diff --git a/desktopRuntime/resources/EPKVersionIdentifier.txt b/desktopRuntime/resources/EPKVersionIdentifier.txt index 50356da8..503c4b5b 100755 --- a/desktopRuntime/resources/EPKVersionIdentifier.txt +++ b/desktopRuntime/resources/EPKVersionIdentifier.txt @@ -1 +1 @@ -u46 \ No newline at end of file +u47 \ No newline at end of file diff --git a/desktopRuntime/resources/assets/eagler/CREDITS.txt b/desktopRuntime/resources/assets/eagler/CREDITS.txt index 1885e21e..654d455d 100755 --- a/desktopRuntime/resources/assets/eagler/CREDITS.txt +++ b/desktopRuntime/resources/assets/eagler/CREDITS.txt @@ -217,6 +217,28 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: High Performance Primitive Collections + Project Author: Carrot Search + Project URL: http://labs.carrotsearch.com/hppc.html + + Used For: Primitive collections library for the client + + * Copyright 2010-2013, Carrot Search s.c., Boznicza 11/56, Poznan, Poland + * + * Licensed 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 + * + * https://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. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: Google Guava Project Author: Google Project URL: https://github.com/google/guava @@ -514,6 +536,45 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: OpenJDK + Project Author: Oracle, IBM + Project URL: https://openjdk.org/projects/jdk/17/ + + Used For: Debloated version of IBM's ICU4J for reordering Arabic and Hebrew text + + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + + * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved + * + * The original version of this source code and documentation is + * copyrighted and owned by IBM. These materials are provided + * under terms of a License Agreement between IBM and Sun. + * This technology is protected by multiple US and International + * patents. This notice and attribution to IBM may not be removed. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Project Name: Java-WebSocket Project Author: Nathan Rajlich (TooTallNate) Project URL: http://tootallnate.github.io/Java-WebSocket diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh index c55d8fef..554b324e 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/accel_particle_forward.fsh @@ -206,6 +206,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = worldPosition4f.xyz - u_dynamicLightArray[i].u_lightPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -215,9 +216,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting(diffuseColor4f.rgb, dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f, materialData3f, metalN, metalK) * u_blockSkySunDynamicLightFac4f.w; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh index 4fbbc84f..c5155b2b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_combine.fsh @@ -68,7 +68,7 @@ void main() { vec4 materialData4f; float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { discard; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh index f544f13c..19de1c08 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/deferred_fog.fsh @@ -52,7 +52,7 @@ void main() { vec4 fragPos4f = vec4(v_position2f, textureLod(u_fogDepthTexture, v_position2f, 0.0).r, 1.0); #ifdef COMPILE_FOG_ATMOSPHERE - if(fragPos4f.z <= 0.0000001) { + if(fragPos4f.z == 0.0) { discard; } #endif diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh index c7549099..3ba9fcf5 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_core.fsh @@ -404,6 +404,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = worldPosition4f.xyz - u_dynamicLightArray[i].u_lightPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -412,9 +413,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting(diffuseColor4f.rgb, dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f, materialData3f, metalN, metalK) * u_blockSkySunDynamicLightFac4f.w; } @@ -451,7 +454,7 @@ void main() { #ifdef COMPILE_FOG_LIGHT_SHAFTS fogBlend4f.rgb *= pow(textureLod(u_lightShaftsTexture, v_positionClip2f * 0.5 + 0.5, 0.0).r * 0.9 + 0.1, 2.25); - fogBlend4f.a = fogBlend4f.a * 0.9 + 0.1; + fogBlend4f.a = fogBlend4f.a * 0.85 + 0.2; #endif break; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh index 7cab95f9..4409765c 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/forward_glass_highlights.fsh @@ -268,6 +268,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = u_dynamicLightArray[i].u_lightPosition4f.xyz - worldPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -275,9 +276,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting_Glass(dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f) * u_blockSkySunDynamicLightFac4f.w; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh index 13d15369..8771c3dd 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/hand_depth_mask.fsh @@ -25,5 +25,5 @@ in vec2 v_position2f; uniform sampler2D u_depthTexture; void main() { - gl_FragDepth = textureLod(u_depthTexture, v_position2f, 0.0).r <= 0.0000001 ? 0.0 : 1.0; + gl_FragDepth = textureLod(u_depthTexture, v_position2f, 0.0).r == 0.0 ? 0.0 : 1.0; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh index e0d71711..41ba1cfc 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/light_shafts_sample.fsh @@ -84,7 +84,7 @@ float shadow(in vec3 coords) { void main() { output1f = 0.0; float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { return; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh index 1fcbd0ae..11a00ec1 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_point.fsh @@ -47,7 +47,7 @@ void main() { vec3 materialData3f; float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { discard; } @@ -59,11 +59,14 @@ void main() { worldSpacePosition = u_inverseViewMatrix4f * worldSpacePosition; vec3 lightDist = (worldSpacePosition.xyz / worldSpacePosition.w) - u_lightPosition3f; vec3 color3f = u_lightColor3f / dot(lightDist, lightDist); + float cm = color3f.r + color3f.g + color3f.b; - if(color3f.r + color3f.g + color3f.b < 0.025) { + if(cm < 0.025) { discard; } + color3f *= ((cm - 0.025) / cm); + vec4 sampleVar4f = textureLod(u_gbufferColorTexture, v_position2f, 0.0); diffuseColor3f.rgb = sampleVar4f.rgb; lightmapCoords2f.x = sampleVar4f.a; diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh index 0659f27c..cc1e1201 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/lighting_sun.fsh @@ -64,6 +64,14 @@ void main() { #endif #endif + float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; + +#ifndef COMPILE_SUN_SHADOW + if(depth == 0.0) { + discard; + } +#endif + vec4 sampleVar4f = textureLod(u_gbufferNormalTexture, v_position2f, 0.0); #ifndef COMPILE_SUN_SHADOW @@ -77,14 +85,6 @@ void main() { normalVector3f.xyz = sampleVar4f.rgb * 2.0 - 1.0; lightmapCoords2f.y = sampleVar4f.a; - float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - -#ifndef COMPILE_SUN_SHADOW - if(depth < 0.00001) { - discard; - } -#endif - sampleVar4f = textureLod(u_gbufferColorTexture, v_position2f, 0.0); diffuseColor3f.rgb = sampleVar4f.rgb; lightmapCoords2f.x = sampleVar4f.a; diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh index 685586f0..69d2416b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_bloom_bright.fsh @@ -39,7 +39,7 @@ void main() { if(inputColor.a > 0.0) { emission = textureLod(u_gbufferMaterialTexture, alignedUV, 0.0).b; }else { - emission = textureLod(u_gbufferDepthTexture, alignedUV, 0.0).r <= 0.0000001 ? 10.0 : 0.0; + emission = textureLod(u_gbufferDepthTexture, alignedUV, 0.0).r == 0.0 ? 10.0 : 0.0; } float f = dot(inputColor.rgb, vec3(0.2126, 0.7152, 0.0722)) * (5.0 + emission * 15.0); if(f > 2.0 + exposure) { diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh index 3064179e..4e6b3d3f 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/post_tonemap.fsh @@ -34,7 +34,7 @@ void main() { float lumaHDR = textureLod(u_framebufferLumaAvgInput, vec2(0.5), 0.0).r; vec3 input3f = textureLod(u_lightingHDRFramebufferTexture, v_position2f, 0.0).rgb; - input3f /= (0.07 + clamp(lumaHDR * 6.0, 0.2, 4.0)); + input3f /= (0.07 + clamp(lumaHDR * 5.0, 0.18, 4.0)); input3f *= u_exposure3f; diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh index 58724b36..dcef9f47 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_mask.fsh @@ -29,9 +29,15 @@ uniform vec2 u_textureCoords02; #endif void main() { -#ifdef COMPILE_NORMAL_ATTRIB - output4f = vec4(v_normal3f * 0.5 + 0.5, 1.0); +#ifdef COMPILE_LIGHTMAP_ATTRIB + float skyLight = v_lightmap2f.y; #else - output4f = vec4(0.0, 1.0, 0.0, 1.0); + float skyLight = u_textureCoords02.y; +#endif + skyLight = 0.004 + skyLight * 0.996; +#ifdef COMPILE_NORMAL_ATTRIB + output4f = vec4(v_normal3f * 0.5 + 0.5, skyLight); +#else + output4f = vec4(0.0, 1.0, 0.0, skyLight); #endif } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh index ce164e02..013820cf 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_noise.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 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 @@ -37,5 +37,5 @@ void main() { sampleC = textureLod(u_noiseTexture, fract(sampleC) * 0.46875 + vec2(0.515625, 0.515625), 0.0).rg; vec2 sampleD = v_position2f + vec2(-0.135, 0.092) * u_waveTimer4f.x + sampleC * 0.1; sampleD = textureLod(u_noiseTexture, fract(sampleD) * 0.46875 + vec2(0.015625, 0.515625), 0.0).rg; - realisticWaterDisplacementOutput1f = dot(vec4(sampleA.r, sampleB.r, sampleC.r, sampleD.r), vec4(0.63, 0.40, 0.035, 0.035)) + dot(vec2(sampleC.g, sampleD.g), vec2(-0.075 * sampleA.g, 0.053 * sampleA.r)); + realisticWaterDisplacementOutput1f = exp((dot(vec4(sampleA.r, sampleB.r, sampleC.r, sampleD.r), vec4(0.63, 0.40, 0.035, 0.035)) + dot(vec2(sampleC.g, sampleD.g), vec2(-0.075 * sampleA.g, 0.053 * sampleA.r))) * 2.0); } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh index 7140a7a1..720e2fa8 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 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 @@ -31,5 +31,5 @@ void main() { float A = textureLod(u_displacementTexture, v_position2f, 0.0).r; float B = textureLod(u_displacementTexture, v_position2f + vec2(u_sampleOffset2f.x, 0.0), 0.0).r; float C = textureLod(u_displacementTexture, v_position2f - vec2(0.0, u_sampleOffset2f.y), 0.0).r; - realisticWaterNormalOutput2f = clamp((vec2(A * A) - vec2(B, C) * vec2(B, C)) * 10.0 + 0.5, vec2(0.0), vec2(1.0)); + realisticWaterNormalOutput2f = clamp((vec2(A * A) - vec2(B, C) * vec2(B, C)) * 0.5 + 0.5, vec2(0.0), vec2(1.0)); } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals_mix.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals_mix.fsh new file mode 100755 index 00000000..e9646ccf --- /dev/null +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_normals_mix.fsh @@ -0,0 +1,35 @@ +#line 2 + +/* + * 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. + * + */ + +precision lowp int; +precision mediump float; +precision mediump sampler2D; + +in vec2 v_position2f; + +layout(location = 0) out vec4 combinedNormalsOutput4f; + +uniform sampler2D u_gbufferNormalsTexture; +uniform sampler2D u_surfaceNormalsTexture; + +void main() { + combinedNormalsOutput4f = textureLod(u_surfaceNormalsTexture, v_position2f, 0.0); + if(combinedNormalsOutput4f.a > 0.0) return; + combinedNormalsOutput4f.rgb = textureLod(u_gbufferNormalsTexture, v_position2f, 0.0).rgb; + combinedNormalsOutput4f.a = 0.0; +} diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh index 900d6868..c39f835b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/realistic_water_render.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 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 @@ -230,16 +230,17 @@ void main() { worldPosition4fOff.xyz += u_wavingBlockOffset3f; vec2 rotatedUV2f = worldPosition4fOff.xz + (block1f == 10.0 ? u_waterWindOffset4f.z * texCoords2f : u_waterWindOffset4f.xy); - rotatedUV2f *= (block1f == 10.0 ? 0.75 : 0.25); + rotatedUV2f *= (block1f == 10.0 ? 0.30 : 0.10); mat3 cf = cotangent_frame(normalVector3f, worldDirection4f.xyz, rotatedUV2f); - vec3 surfaceNormalsMap3f = vec3(textureLod(u_normalMap, rotatedUV2f, 0.0).rg, 0.0); - surfaceNormalsMap3f.xy *= 2.0; - surfaceNormalsMap3f.xy -= 1.0; + vec3 surfaceNormalsMap3f = vec3(textureLod(u_normalMap, rotatedUV2f * 0.68, 0.0).rg - 0.5, 0.0); + surfaceNormalsMap3f.xy += textureLod(u_normalMap, rotatedUV2f, 0.0).rg - 0.5; + surfaceNormalsMap3f.xy += textureLod(u_normalMap, rotatedUV2f * 2.33, 0.0).rg - 0.5; + surfaceNormalsMap3f.xy *= (2.0 / 3.0); vec3 surfaceNormalsMapFlat3f = cf * surfaceNormalsMap3f; - surfaceNormalsMapFlat3f *= 0.1; + surfaceNormalsMapFlat3f *= 0.15; - surfaceNormalsMap3f.z = 8.0; + surfaceNormalsMap3f.z = 7.0; surfaceNormalsMap3f = normalize(surfaceNormalsMap3f); normalVector3f = surfaceNormalsMap3f = cf * surfaceNormalsMap3f; @@ -268,6 +269,18 @@ void main() { vec4 envMapSample4f = textureLod(u_reflectionMap, reflectCoordsR.xy, 0.0); vec4 refractionSample = textureLod(u_refractionMap, reflectCoordsL.xy, 0.0); + if(refractionSample.a == 0.0) { + reflectCoordsL = mat4x3( + u_modelViewProjMat4f_[0].xyw, + u_modelViewProjMat4f_[1].xyw, + u_modelViewProjMat4f_[2].xyw, + u_modelViewProjMat4f_[3].xyw) * worldPosition4f; + reflectCoordsL.xy /= reflectCoordsL.z; + reflectCoordsL.xy *= 0.5; + reflectCoordsL.xy += 0.5; + refractionSample = textureLod(u_refractionMap, reflectCoordsL.xy, 0.0); + } + #ifdef COMPILE_COLOR_ATTRIB refractionSample *= v_color4f * v_color4f * u_color4f * u_color4f; #else @@ -374,6 +387,7 @@ void main() { vec3 dlightDist3f, dlightDir3f, dlightColor3f; int safeLightCount = u_dynamicLightCount1i > 12 ? 0 : u_dynamicLightCount1i; // hate this + float cm; for(int i = 0; i < safeLightCount; ++i) { dlightDist3f = u_dynamicLightArray[i].u_lightPosition4f.xyz - worldPosition4f.xyz; dlightDir3f = normalize(dlightDist3f); @@ -381,9 +395,11 @@ void main() { continue; } dlightColor3f = u_dynamicLightArray[i].u_lightColor4f.rgb / dot(dlightDist3f, dlightDist3f); - if(dlightColor3f.r + dlightColor3f.g + dlightColor3f.b < 0.025) { + cm = dlightColor3f.r + dlightColor3f.g + dlightColor3f.b; + if(cm < 0.025) { continue; } + dlightColor3f *= ((cm - 0.025) / cm); lightColor3f += eaglercraftLighting_Water(diffuseColor4f.rgb, dlightColor3f, -worldDirection4f.xyz, dlightDir3f, normalVector3f) * u_blockSkySunDynamicLightFac4f.w; } @@ -419,7 +435,7 @@ void main() { #ifdef COMPILE_FOG_LIGHT_SHAFTS fogBlend4f.rgb *= pow(textureLod(u_lightShaftsTexture, v_positionClip2f * 0.5 + 0.5, 0.0).r * 0.9 + 0.1, 2.25); - fogBlend4f.a = fogBlend4f.a * 0.9 + 0.1; + fogBlend4f.a = fogBlend4f.a * 0.85 + 0.2; #endif break; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh index 30f9d965..9efb9c5d 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/reproject_ssr.fsh @@ -1,7 +1,7 @@ #line 2 /* - * Copyright (c) 2023 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 @@ -41,72 +41,96 @@ uniform float u_sampleStep1f; uniform vec4 u_pixelAlignment4f; +uniform int u_sampleDelta1i; + #define maxAge 55.0 #define maxSamples 50.0 void main() { vec2 v_position2f2 = (floor(v_position2f * u_pixelAlignment4f.xy) + 0.25) * (2.0 / u_pixelAlignment4f.zw); - reflectionOutput4f = vec4(0.0, 0.0, 0.0, 0.0); - hitVectorOutput4f = vec4(0.0, 0.0, 0.0, 0.0); float fragDepth = textureLod(u_gbufferDepthTexture, v_position2f2, 0.0).r; if(fragDepth < 0.000001) { + reflectionOutput4f = vec4(0.0, 0.0, 0.0, 0.0); + hitVectorOutput4f = vec4(0.0, 0.0, 0.0, 0.0); return; } - vec4 reflectionInput4f = textureLod(u_reprojectionReflectionInput4f, v_position2f, 0.0); - vec4 hitVectorInput4f = textureLod(u_reprojectionHitVectorInput4f, v_position2f, 0.0); - hitVectorInput4f.a += 1.0; - float f = reflectionInput4f.a < 1.0 ? 1.0 : reflectionInput4f.a; - reflectionInput4f.a = hitVectorInput4f.a > maxAge ? f : reflectionInput4f.a; - if(reflectionInput4f.a < 1.0) { - reflectionOutput4f = reflectionInput4f; - hitVectorOutput4f = hitVectorInput4f; - return; + vec4 reflectionBuffer4f = textureLod(u_reprojectionReflectionInput4f, v_position2f, 0.0); + vec4 hitVectorBuffer4f = textureLod(u_reprojectionHitVectorInput4f, v_position2f, 0.0); + vec4 surfaceNormal4f = textureLod(u_gbufferNormalTexture, v_position2f2, 0.0); + surfaceNormal4f.xyz *= 2.0; + surfaceNormal4f.xyz -= 1.0; + + vec4 reflectionInput4f; + vec4 hitVectorInput4f; + float f; + vec4 fragPos4f; + vec4 reflectionNormal4f; + float sampleStepMod; + vec3 sampleOffset3f; + vec3 reflectionSamplePos3f; + float reflectDepthSample; + vec2 sampleFragDepth; + vec4 colorSample; + + for(int itr = 0; itr < u_sampleDelta1i; ++itr) { + reflectionInput4f = reflectionBuffer4f; + hitVectorInput4f = hitVectorBuffer4f; + reflectionBuffer4f = vec4(0.0, 0.0, 0.0, 0.0); + hitVectorBuffer4f = vec4(0.0, 0.0, 0.0, 0.0); + hitVectorInput4f.a += 1.0; + f = reflectionInput4f.a < 1.0 ? 1.0 : reflectionInput4f.a; + reflectionInput4f.a = hitVectorInput4f.a > maxAge ? f : reflectionInput4f.a; + if(reflectionInput4f.a < 1.0) { + reflectionBuffer4f = reflectionInput4f; + hitVectorBuffer4f = hitVectorInput4f; + continue; + } + + fragPos4f = u_inverseProjectionMatrix4f * (vec4(v_position2f2, fragDepth, 1.0) * 2.0 - 1.0); + fragPos4f.xyz /= fragPos4f.w; + fragPos4f.w = 1.0; + reflectionNormal4f.xyz = reflect(normalize(fragPos4f.xyz), surfaceNormal4f.xyz); + reflectionNormal4f.w = 1.0; + sampleStepMod = (reflectionInput4f.a * 0.03 + 0.15 + length(fragPos4f.xyz) * 0.03) * u_sampleStep1f; + sampleOffset3f = reflectionNormal4f.xyz * reflectionInput4f.a * sampleStepMod; + fragPos4f.xyz += sampleOffset3f; + reflectionNormal4f = u_lastProjectionMatrix4f * fragPos4f; + reflectionNormal4f.xyz /= reflectionNormal4f.w; + reflectionNormal4f.w = 1.0; + reflectionSamplePos3f = reflectionNormal4f.xyz; + reflectionSamplePos3f *= 0.5; + reflectionSamplePos3f += 0.5; + reflectionSamplePos3f.xy = (floor(reflectionSamplePos3f.xy * u_pixelAlignment4f.zw) + 0.5) * (0.5 / u_pixelAlignment4f.xy); + + if(clamp(reflectionSamplePos3f.xy, vec2(0.001), vec2(0.999)) != reflectionSamplePos3f.xy) { + continue; + } + + reflectDepthSample = textureLod(u_lastFrameDepthInput, reflectionSamplePos3f.xy, 0.0).r; + sampleFragDepth = u_lastInverseProjMatrix4x2f * vec4(reflectionNormal4f.xy, reflectDepthSample * 2.0 - 1.0, 1.0); + sampleFragDepth.x /= sampleFragDepth.y; + + reflectDepthSample = sampleFragDepth.x - fragPos4f.z; + if(reflectDepthSample < sampleStepMod * 3.0) { + reflectionInput4f.a += 1.0; + reflectionBuffer4f = reflectionInput4f.a >= maxSamples ? vec4(0.0, 0.0, 0.0, 0.0) : reflectionInput4f; + hitVectorBuffer4f = vec4(0.0, 0.0, 0.0, hitVectorInput4f.a); + continue; + } + + if(abs(reflectDepthSample) > sampleStepMod * 6.0) { + continue; + } + + colorSample = textureLod(u_lastFrameColorInput4f, reflectionSamplePos3f.xy, 0.0); + reflectionBuffer4f = vec4(colorSample.rgb, 0.0); + reflectionBuffer4f.g += 0.0005; + hitVectorBuffer4f = vec4(colorSample.a > 0.0 ? sampleOffset3f : vec3(0.0), 0.0); + hitVectorBuffer4f.g += colorSample.a > 0.0 ? 0.0004 : 0.0; } - vec4 fragPos4f = u_inverseProjectionMatrix4f * (vec4(v_position2f2, fragDepth, 1.0) * 2.0 - 1.0); - fragPos4f.xyz /= fragPos4f.w; - fragPos4f.w = 1.0; - vec4 reflectionNormal4f = textureLod(u_gbufferNormalTexture, v_position2f2, 0.0); - reflectionNormal4f.xyz *= 2.0; - reflectionNormal4f.xyz -= 1.0; - reflectionNormal4f.xyz = reflect(normalize(fragPos4f.xyz), reflectionNormal4f.xyz); - reflectionNormal4f.w = 1.0; - float sampleStepMod = (reflectionInput4f.a * 0.03 + 0.15 + length(fragPos4f.xyz) * 0.03) * u_sampleStep1f; - vec3 sampleOffset3f = reflectionNormal4f.xyz * reflectionInput4f.a * sampleStepMod; - fragPos4f.xyz += sampleOffset3f; - reflectionNormal4f = u_lastProjectionMatrix4f * fragPos4f; - reflectionNormal4f.xyz /= reflectionNormal4f.w; - reflectionNormal4f.w = 1.0; - vec3 reflectionSamplePos3f = reflectionNormal4f.xyz; - reflectionSamplePos3f *= 0.5; - reflectionSamplePos3f += 0.5; - reflectionSamplePos3f.xy = (floor(reflectionSamplePos3f.xy * u_pixelAlignment4f.zw) + 0.5) * (0.5 / u_pixelAlignment4f.xy); - - if(clamp(reflectionSamplePos3f.xy, vec2(0.001), vec2(0.999)) != reflectionSamplePos3f.xy) { - return; - } - - float reflectDepthSample = textureLod(u_lastFrameDepthInput, reflectionSamplePos3f.xy, 0.0).r; - vec2 sampleFragDepth = u_lastInverseProjMatrix4x2f * vec4(reflectionNormal4f.xy, reflectDepthSample * 2.0 - 1.0, 1.0); - sampleFragDepth.x /= sampleFragDepth.y; - - reflectDepthSample = sampleFragDepth.x - fragPos4f.z; - if(reflectDepthSample < sampleStepMod * 3.0) { - reflectionInput4f.a += 1.0; - reflectionOutput4f = reflectionInput4f.a >= maxSamples ? vec4(0.0, 0.0, 0.0, 0.0) : reflectionInput4f; - hitVectorOutput4f = vec4(0.0, 0.0, 0.0, hitVectorInput4f.a); - return; - } - - if(abs(reflectDepthSample) > sampleStepMod * 6.0) { - return; - } - - vec4 colorSample = textureLod(u_lastFrameColorInput4f, reflectionSamplePos3f.xy, 0.0); - reflectionOutput4f = vec4(colorSample.rgb, 0.0); - reflectionOutput4f.g += 0.0005; - hitVectorOutput4f = vec4(colorSample.a > 0.0 ? sampleOffset3f : vec3(0.0), 0.0); - hitVectorOutput4f.g += colorSample.a > 0.0 ? 0.0004 : 0.0; + reflectionOutput4f = reflectionBuffer4f; + hitVectorOutput4f = hitVectorBuffer4f; } diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json b/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json index 48660544..d60bfe2b 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/shader_pack_info.json @@ -1,7 +1,7 @@ { "name": "§eHigh Performance PBR", "desc": "Pack made from scratch specifically for this client, designed to give what I call the best balance between quality and performance possible in a browser but obviously that's just my opinion", - "vers": "1.2.2", + "vers": "1.3.0", "author": "lax1dude", "api_vers": 1, "features": [ diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh index a11645ee..834fdba2 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/shadows_sun.fsh @@ -79,7 +79,7 @@ void main() { output1f = 0.0; #endif float depth = textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r; - if(depth < 0.00001) { + if(depth == 0.0) { return; } vec4 normalVector4f = textureLod(u_gbufferNormalTexture, v_position2f, 0.0); diff --git a/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh b/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh index 98b425ce..92a97bd7 100755 --- a/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh +++ b/desktopRuntime/resources/assets/eagler/glsl/deferred/ssao_generate.fsh @@ -54,7 +54,7 @@ vec3(0.716,-0.439,0.543),vec3(-0.400,0.733,0.550)); void main() { vec3 originalClipSpacePos = vec3(v_position2f, textureLod(u_gbufferDepthTexture, v_position2f, 0.0).r); - if(originalClipSpacePos.z <= 0.0000001) { + if(originalClipSpacePos.z == 0.0) { output1f = 1.0; return; } diff --git a/desktopRuntime/resources/assets/eagler/icudt/nfc.nrm b/desktopRuntime/resources/assets/eagler/icudt/nfc.nrm new file mode 100755 index 00000000..45c26085 Binary files /dev/null and b/desktopRuntime/resources/assets/eagler/icudt/nfc.nrm differ diff --git a/desktopRuntime/resources/assets/eagler/icudt/nfkc.nrm b/desktopRuntime/resources/assets/eagler/icudt/nfkc.nrm new file mode 100755 index 00000000..2c0587b6 Binary files /dev/null and b/desktopRuntime/resources/assets/eagler/icudt/nfkc.nrm differ diff --git a/desktopRuntime/resources/assets/eagler/icudt/ubidi.icu b/desktopRuntime/resources/assets/eagler/icudt/ubidi.icu new file mode 100755 index 00000000..bec7b093 Binary files /dev/null and b/desktopRuntime/resources/assets/eagler/icudt/ubidi.icu differ diff --git a/desktopRuntime/resources/assets/eagler/icudt/uprops.icu b/desktopRuntime/resources/assets/eagler/icudt/uprops.icu new file mode 100755 index 00000000..ee08ff5b Binary files /dev/null and b/desktopRuntime/resources/assets/eagler/icudt/uprops.icu differ diff --git a/desktopRuntime/resources/plugin_download.zip b/desktopRuntime/resources/plugin_download.zip index 0db389f5..ccd84bcb 100755 Binary files a/desktopRuntime/resources/plugin_download.zip and b/desktopRuntime/resources/plugin_download.zip differ diff --git a/desktopRuntime/resources/plugin_version.json b/desktopRuntime/resources/plugin_version.json index d5b0c6f2..b758fceb 100755 --- a/desktopRuntime/resources/plugin_version.json +++ b/desktopRuntime/resources/plugin_version.json @@ -1 +1 @@ -{"pluginName":"EaglercraftXBungee","pluginVersion":"1.3.4","pluginButton":"Download \"EaglerXBungee-1.3.4.jar\"","pluginFilename":"EaglerXBungee.zip"} \ No newline at end of file +{"pluginName":"EaglercraftXBungee","pluginVersion":"1.3.5","pluginButton":"Download \"EaglerXBungee-1.3.5.jar\"","pluginFilename":"EaglerXBungee.zip"} \ No newline at end of file diff --git a/desktopRuntime/resources/relay_download.zip b/desktopRuntime/resources/relay_download.zip index 5b5db2c2..00b74aaa 100755 Binary files a/desktopRuntime/resources/relay_download.zip and b/desktopRuntime/resources/relay_download.zip differ diff --git a/src/game/java/net/minecraft/block/Block.java b/src/game/java/net/minecraft/block/Block.java index a5ea75cf..02b3ba96 100755 --- a/src/game/java/net/minecraft/block/Block.java +++ b/src/game/java/net/minecraft/block/Block.java @@ -40,7 +40,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockAir.java b/src/game/java/net/minecraft/block/BlockAir.java index e8cdb61d..e53a7158 100755 --- a/src/game/java/net/minecraft/block/BlockAir.java +++ b/src/game/java/net/minecraft/block/BlockAir.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockAnvil.java b/src/game/java/net/minecraft/block/BlockAnvil.java index 30d6bb33..fb42195a 100755 --- a/src/game/java/net/minecraft/block/BlockAnvil.java +++ b/src/game/java/net/minecraft/block/BlockAnvil.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBanner.java b/src/game/java/net/minecraft/block/BlockBanner.java index e27bcb42..cbdda5d1 100755 --- a/src/game/java/net/minecraft/block/BlockBanner.java +++ b/src/game/java/net/minecraft/block/BlockBanner.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBarrier.java b/src/game/java/net/minecraft/block/BlockBarrier.java index d61bc12c..abae54e4 100755 --- a/src/game/java/net/minecraft/block/BlockBarrier.java +++ b/src/game/java/net/minecraft/block/BlockBarrier.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBasePressurePlate.java b/src/game/java/net/minecraft/block/BlockBasePressurePlate.java index fd83e1f1..6c25ea16 100755 --- a/src/game/java/net/minecraft/block/BlockBasePressurePlate.java +++ b/src/game/java/net/minecraft/block/BlockBasePressurePlate.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBeacon.java b/src/game/java/net/minecraft/block/BlockBeacon.java index d66465b9..b8414d13 100755 --- a/src/game/java/net/minecraft/block/BlockBeacon.java +++ b/src/game/java/net/minecraft/block/BlockBeacon.java @@ -24,7 +24,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBed.java b/src/game/java/net/minecraft/block/BlockBed.java index 52885281..57c2a193 100755 --- a/src/game/java/net/minecraft/block/BlockBed.java +++ b/src/game/java/net/minecraft/block/BlockBed.java @@ -30,7 +30,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBookshelf.java b/src/game/java/net/minecraft/block/BlockBookshelf.java index 2b5f7402..8888a523 100755 --- a/src/game/java/net/minecraft/block/BlockBookshelf.java +++ b/src/game/java/net/minecraft/block/BlockBookshelf.java @@ -14,7 +14,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBreakable.java b/src/game/java/net/minecraft/block/BlockBreakable.java index 32931eaf..3c1d482b 100755 --- a/src/game/java/net/minecraft/block/BlockBreakable.java +++ b/src/game/java/net/minecraft/block/BlockBreakable.java @@ -14,7 +14,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBrewingStand.java b/src/game/java/net/minecraft/block/BlockBrewingStand.java index 2a4d3fae..d2613498 100755 --- a/src/game/java/net/minecraft/block/BlockBrewingStand.java +++ b/src/game/java/net/minecraft/block/BlockBrewingStand.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockBush.java b/src/game/java/net/minecraft/block/BlockBush.java index c8039f27..002f97d3 100755 --- a/src/game/java/net/minecraft/block/BlockBush.java +++ b/src/game/java/net/minecraft/block/BlockBush.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockButton.java b/src/game/java/net/minecraft/block/BlockButton.java index c9776ac9..2eeea02d 100755 --- a/src/game/java/net/minecraft/block/BlockButton.java +++ b/src/game/java/net/minecraft/block/BlockButton.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockButtonStone.java b/src/game/java/net/minecraft/block/BlockButtonStone.java index 767b56a7..b1bb5326 100755 --- a/src/game/java/net/minecraft/block/BlockButtonStone.java +++ b/src/game/java/net/minecraft/block/BlockButtonStone.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockButtonWood.java b/src/game/java/net/minecraft/block/BlockButtonWood.java index 0f282ffd..093d3846 100755 --- a/src/game/java/net/minecraft/block/BlockButtonWood.java +++ b/src/game/java/net/minecraft/block/BlockButtonWood.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCactus.java b/src/game/java/net/minecraft/block/BlockCactus.java index 04681b1a..5a8afeaa 100755 --- a/src/game/java/net/minecraft/block/BlockCactus.java +++ b/src/game/java/net/minecraft/block/BlockCactus.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCake.java b/src/game/java/net/minecraft/block/BlockCake.java index 96e7a444..b4691c9a 100755 --- a/src/game/java/net/minecraft/block/BlockCake.java +++ b/src/game/java/net/minecraft/block/BlockCake.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCarpet.java b/src/game/java/net/minecraft/block/BlockCarpet.java index 41902e35..1c9f8df0 100755 --- a/src/game/java/net/minecraft/block/BlockCarpet.java +++ b/src/game/java/net/minecraft/block/BlockCarpet.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCarrot.java b/src/game/java/net/minecraft/block/BlockCarrot.java index f2c91677..f428a776 100755 --- a/src/game/java/net/minecraft/block/BlockCarrot.java +++ b/src/game/java/net/minecraft/block/BlockCarrot.java @@ -9,7 +9,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCauldron.java b/src/game/java/net/minecraft/block/BlockCauldron.java index 24fde302..12193956 100755 --- a/src/game/java/net/minecraft/block/BlockCauldron.java +++ b/src/game/java/net/minecraft/block/BlockCauldron.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockChest.java b/src/game/java/net/minecraft/block/BlockChest.java index f5e8fdaf..d490fd9f 100755 --- a/src/game/java/net/minecraft/block/BlockChest.java +++ b/src/game/java/net/minecraft/block/BlockChest.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockClay.java b/src/game/java/net/minecraft/block/BlockClay.java index 9eb0f65b..1e917644 100755 --- a/src/game/java/net/minecraft/block/BlockClay.java +++ b/src/game/java/net/minecraft/block/BlockClay.java @@ -14,7 +14,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCocoa.java b/src/game/java/net/minecraft/block/BlockCocoa.java index c789ae94..2da3f87c 100755 --- a/src/game/java/net/minecraft/block/BlockCocoa.java +++ b/src/game/java/net/minecraft/block/BlockCocoa.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockColored.java b/src/game/java/net/minecraft/block/BlockColored.java index 3d414905..7f5c06b0 100755 --- a/src/game/java/net/minecraft/block/BlockColored.java +++ b/src/game/java/net/minecraft/block/BlockColored.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCommandBlock.java b/src/game/java/net/minecraft/block/BlockCommandBlock.java index 9b1de4d0..94832017 100755 --- a/src/game/java/net/minecraft/block/BlockCommandBlock.java +++ b/src/game/java/net/minecraft/block/BlockCommandBlock.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCompressedPowered.java b/src/game/java/net/minecraft/block/BlockCompressedPowered.java index d08ef238..2e2b2942 100755 --- a/src/game/java/net/minecraft/block/BlockCompressedPowered.java +++ b/src/game/java/net/minecraft/block/BlockCompressedPowered.java @@ -13,7 +13,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockContainer.java b/src/game/java/net/minecraft/block/BlockContainer.java index 0525b98f..5efc381d 100755 --- a/src/game/java/net/minecraft/block/BlockContainer.java +++ b/src/game/java/net/minecraft/block/BlockContainer.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockCrops.java b/src/game/java/net/minecraft/block/BlockCrops.java index fed0ab42..5293e37d 100755 --- a/src/game/java/net/minecraft/block/BlockCrops.java +++ b/src/game/java/net/minecraft/block/BlockCrops.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDaylightDetector.java b/src/game/java/net/minecraft/block/BlockDaylightDetector.java index 4b0d8ba0..68c412c8 100755 --- a/src/game/java/net/minecraft/block/BlockDaylightDetector.java +++ b/src/game/java/net/minecraft/block/BlockDaylightDetector.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDeadBush.java b/src/game/java/net/minecraft/block/BlockDeadBush.java index 8727792e..0463683e 100755 --- a/src/game/java/net/minecraft/block/BlockDeadBush.java +++ b/src/game/java/net/minecraft/block/BlockDeadBush.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDirectional.java b/src/game/java/net/minecraft/block/BlockDirectional.java index 78ae0759..cf3a0e94 100755 --- a/src/game/java/net/minecraft/block/BlockDirectional.java +++ b/src/game/java/net/minecraft/block/BlockDirectional.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDirt.java b/src/game/java/net/minecraft/block/BlockDirt.java index f91ae9e7..68b89e1f 100755 --- a/src/game/java/net/minecraft/block/BlockDirt.java +++ b/src/game/java/net/minecraft/block/BlockDirt.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDispenser.java b/src/game/java/net/minecraft/block/BlockDispenser.java index 934f7611..93938698 100755 --- a/src/game/java/net/minecraft/block/BlockDispenser.java +++ b/src/game/java/net/minecraft/block/BlockDispenser.java @@ -35,7 +35,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDoor.java b/src/game/java/net/minecraft/block/BlockDoor.java index 0a6e868e..9a015e8a 100755 --- a/src/game/java/net/minecraft/block/BlockDoor.java +++ b/src/game/java/net/minecraft/block/BlockDoor.java @@ -30,7 +30,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDoublePlant.java b/src/game/java/net/minecraft/block/BlockDoublePlant.java index bce102dd..a4f373ff 100755 --- a/src/game/java/net/minecraft/block/BlockDoublePlant.java +++ b/src/game/java/net/minecraft/block/BlockDoublePlant.java @@ -30,7 +30,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java b/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java index 164300fd..7c0564ba 100755 --- a/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java +++ b/src/game/java/net/minecraft/block/BlockDoubleStoneSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java b/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java index 7a918c33..2e0e0b33 100755 --- a/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java +++ b/src/game/java/net/minecraft/block/BlockDoubleStoneSlabNew.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java b/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java index 1bbbbca9..a2c88187 100755 --- a/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java +++ b/src/game/java/net/minecraft/block/BlockDoubleWoodSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDragonEgg.java b/src/game/java/net/minecraft/block/BlockDragonEgg.java index 6d887490..aa0254cb 100755 --- a/src/game/java/net/minecraft/block/BlockDragonEgg.java +++ b/src/game/java/net/minecraft/block/BlockDragonEgg.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDropper.java b/src/game/java/net/minecraft/block/BlockDropper.java index ce97d6d0..ac97b77f 100755 --- a/src/game/java/net/minecraft/block/BlockDropper.java +++ b/src/game/java/net/minecraft/block/BlockDropper.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockDynamicLiquid.java b/src/game/java/net/minecraft/block/BlockDynamicLiquid.java index c35e2ce6..a07de593 100755 --- a/src/game/java/net/minecraft/block/BlockDynamicLiquid.java +++ b/src/game/java/net/minecraft/block/BlockDynamicLiquid.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockEnchantmentTable.java b/src/game/java/net/minecraft/block/BlockEnchantmentTable.java index 8f89ec4d..7bd76930 100755 --- a/src/game/java/net/minecraft/block/BlockEnchantmentTable.java +++ b/src/game/java/net/minecraft/block/BlockEnchantmentTable.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockEndPortal.java b/src/game/java/net/minecraft/block/BlockEndPortal.java index 9b1d06f5..37cedf33 100755 --- a/src/game/java/net/minecraft/block/BlockEndPortal.java +++ b/src/game/java/net/minecraft/block/BlockEndPortal.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockEndPortalFrame.java b/src/game/java/net/minecraft/block/BlockEndPortalFrame.java index 1955085e..e03c905c 100755 --- a/src/game/java/net/minecraft/block/BlockEndPortalFrame.java +++ b/src/game/java/net/minecraft/block/BlockEndPortalFrame.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockEnderChest.java b/src/game/java/net/minecraft/block/BlockEnderChest.java index 76ca86e5..a292d5ee 100755 --- a/src/game/java/net/minecraft/block/BlockEnderChest.java +++ b/src/game/java/net/minecraft/block/BlockEnderChest.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockEventData.java b/src/game/java/net/minecraft/block/BlockEventData.java index 13a361ed..364ca989 100755 --- a/src/game/java/net/minecraft/block/BlockEventData.java +++ b/src/game/java/net/minecraft/block/BlockEventData.java @@ -8,7 +8,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockFalling.java b/src/game/java/net/minecraft/block/BlockFalling.java index 8f80daa6..4bc4f426 100755 --- a/src/game/java/net/minecraft/block/BlockFalling.java +++ b/src/game/java/net/minecraft/block/BlockFalling.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockFarmland.java b/src/game/java/net/minecraft/block/BlockFarmland.java index 17bf6d1b..d1a224ff 100755 --- a/src/game/java/net/minecraft/block/BlockFarmland.java +++ b/src/game/java/net/minecraft/block/BlockFarmland.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockFence.java b/src/game/java/net/minecraft/block/BlockFence.java index f9b42448..43129759 100755 --- a/src/game/java/net/minecraft/block/BlockFence.java +++ b/src/game/java/net/minecraft/block/BlockFence.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockFenceGate.java b/src/game/java/net/minecraft/block/BlockFenceGate.java index 12f25461..5efc8971 100755 --- a/src/game/java/net/minecraft/block/BlockFenceGate.java +++ b/src/game/java/net/minecraft/block/BlockFenceGate.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockFire.java b/src/game/java/net/minecraft/block/BlockFire.java index 3368218a..0d4f176a 100755 --- a/src/game/java/net/minecraft/block/BlockFire.java +++ b/src/game/java/net/minecraft/block/BlockFire.java @@ -1,9 +1,9 @@ package net.minecraft.block; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.ObjectIntIdentityHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import net.minecraft.block.material.MapColor; import net.minecraft.block.material.Material; @@ -28,7 +28,7 @@ import net.minecraft.world.WorldProviderEnd; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -51,8 +51,8 @@ public class BlockFire extends Block { public static final PropertyBool SOUTH = PropertyBool.create("south"); public static final PropertyBool WEST = PropertyBool.create("west"); public static final PropertyInteger UPPER = PropertyInteger.create("upper", 0, 2); - private final Map encouragements = Maps.newIdentityHashMap(); - private final Map flammabilities = Maps.newIdentityHashMap(); + private final ObjectIntMap encouragements = new ObjectIntIdentityHashMap<>(); + private final ObjectIntMap flammabilities = new ObjectIntIdentityHashMap<>(); /**+ * Get the actual Block state of this Block at the given @@ -132,8 +132,8 @@ public class BlockFire extends Block { } public void setFireInfo(Block blockIn, int encouragement, int flammability) { - this.encouragements.put(blockIn, Integer.valueOf(encouragement)); - this.flammabilities.put(blockIn, Integer.valueOf(flammability)); + this.encouragements.put(blockIn, encouragement); + this.flammabilities.put(blockIn, flammability); } public AxisAlignedBB getCollisionBoundingBox(World var1, BlockPos var2, IBlockState var3) { @@ -226,6 +226,8 @@ public class BlockFire extends Block { } BlockPos blockpos1 = blockpos.add(j, l, k); + if (!world.isBlockLoaded(blockpos1)) + continue; int j1 = this.getNeighborEncouragement(world, blockpos1); if (j1 > 0) { int k1 = (j1 + 40 + world.getDifficulty().getDifficultyId() * 7) / (i + 30); @@ -264,19 +266,20 @@ public class BlockFire extends Block { } private int getFlammability(Block blockIn) { - Integer integer = (Integer) this.flammabilities.get(blockIn); - return integer == null ? 0 : integer.intValue(); + return this.flammabilities.getOrDefault(blockIn, 0); } private int getEncouragement(Block blockIn) { - Integer integer = (Integer) this.encouragements.get(blockIn); - return integer == null ? 0 : integer.intValue(); + return this.encouragements.getOrDefault(blockIn, 0); } private void catchOnFire(World worldIn, BlockPos pos, int chance, EaglercraftRandom random, int age) { - int i = this.getFlammability(worldIn.getBlockState(pos).getBlock()); + IBlockState iblockstate = worldIn.getBlockStateIfLoaded(pos); + if (iblockstate == null) { + return; + } + int i = this.getFlammability(iblockstate.getBlock()); if (random.nextInt(chance) < i) { - IBlockState iblockstate = worldIn.getBlockState(pos); if (random.nextInt(age + 10) < 5 && !worldIn.canLightningStrike(pos)) { int j = age + random.nextInt(5) / 4; if (j > 15) { @@ -315,8 +318,12 @@ public class BlockFire extends Block { int i = 0; EnumFacing[] facings = EnumFacing._VALUES; + BlockPos tmp = new BlockPos(0, 0, 0); for (int j = 0; j < facings.length; ++j) { - i = Math.max(this.getEncouragement(worldIn.getBlockState(pos.offset(facings[j])).getBlock()), i); + IBlockState type = worldIn.getBlockStateIfLoaded(pos.offsetEvenFaster(facings[j], tmp)); + if (type != null) { + i = Math.max(this.getEncouragement(type.getBlock()), i); + } } return i; diff --git a/src/game/java/net/minecraft/block/BlockFlower.java b/src/game/java/net/minecraft/block/BlockFlower.java index d73ba6e4..4ab5a445 100755 --- a/src/game/java/net/minecraft/block/BlockFlower.java +++ b/src/game/java/net/minecraft/block/BlockFlower.java @@ -23,7 +23,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockFlowerPot.java b/src/game/java/net/minecraft/block/BlockFlowerPot.java index 3482ddb3..e334b083 100755 --- a/src/game/java/net/minecraft/block/BlockFlowerPot.java +++ b/src/game/java/net/minecraft/block/BlockFlowerPot.java @@ -31,7 +31,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockFurnace.java b/src/game/java/net/minecraft/block/BlockFurnace.java index 35821986..2f2acba8 100755 --- a/src/game/java/net/minecraft/block/BlockFurnace.java +++ b/src/game/java/net/minecraft/block/BlockFurnace.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockGlass.java b/src/game/java/net/minecraft/block/BlockGlass.java index 2c0cc1ad..5c7d1c1a 100755 --- a/src/game/java/net/minecraft/block/BlockGlass.java +++ b/src/game/java/net/minecraft/block/BlockGlass.java @@ -12,7 +12,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockGlowstone.java b/src/game/java/net/minecraft/block/BlockGlowstone.java index 5de1582b..929a1195 100755 --- a/src/game/java/net/minecraft/block/BlockGlowstone.java +++ b/src/game/java/net/minecraft/block/BlockGlowstone.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockGrass.java b/src/game/java/net/minecraft/block/BlockGrass.java index 77cd8bdd..01860310 100755 --- a/src/game/java/net/minecraft/block/BlockGrass.java +++ b/src/game/java/net/minecraft/block/BlockGrass.java @@ -23,7 +23,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockGravel.java b/src/game/java/net/minecraft/block/BlockGravel.java index 38c30052..cddd6e67 100755 --- a/src/game/java/net/minecraft/block/BlockGravel.java +++ b/src/game/java/net/minecraft/block/BlockGravel.java @@ -13,7 +13,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java b/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java index e0201a27..2eaac83b 100755 --- a/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java +++ b/src/game/java/net/minecraft/block/BlockHalfStoneSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java b/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java index aa0fdbe8..3ef3b78c 100755 --- a/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java +++ b/src/game/java/net/minecraft/block/BlockHalfStoneSlabNew.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java b/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java index 7c0c3703..cc9cf13f 100755 --- a/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java +++ b/src/game/java/net/minecraft/block/BlockHalfWoodSlab.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockHardenedClay.java b/src/game/java/net/minecraft/block/BlockHardenedClay.java index 57915476..a1b28620 100755 --- a/src/game/java/net/minecraft/block/BlockHardenedClay.java +++ b/src/game/java/net/minecraft/block/BlockHardenedClay.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockHay.java b/src/game/java/net/minecraft/block/BlockHay.java index f4f9e8df..7b261fc0 100755 --- a/src/game/java/net/minecraft/block/BlockHay.java +++ b/src/game/java/net/minecraft/block/BlockHay.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockHopper.java b/src/game/java/net/minecraft/block/BlockHopper.java index 4874da92..1ea31179 100755 --- a/src/game/java/net/minecraft/block/BlockHopper.java +++ b/src/game/java/net/minecraft/block/BlockHopper.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockHugeMushroom.java b/src/game/java/net/minecraft/block/BlockHugeMushroom.java index 6ba543e7..ea0a2a4d 100755 --- a/src/game/java/net/minecraft/block/BlockHugeMushroom.java +++ b/src/game/java/net/minecraft/block/BlockHugeMushroom.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockIce.java b/src/game/java/net/minecraft/block/BlockIce.java index b08d495c..fbc65999 100755 --- a/src/game/java/net/minecraft/block/BlockIce.java +++ b/src/game/java/net/minecraft/block/BlockIce.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockJukebox.java b/src/game/java/net/minecraft/block/BlockJukebox.java index d31df2d4..c2776ce3 100755 --- a/src/game/java/net/minecraft/block/BlockJukebox.java +++ b/src/game/java/net/minecraft/block/BlockJukebox.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockLadder.java b/src/game/java/net/minecraft/block/BlockLadder.java index 3a569979..31ac8555 100755 --- a/src/game/java/net/minecraft/block/BlockLadder.java +++ b/src/game/java/net/minecraft/block/BlockLadder.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockLeaves.java b/src/game/java/net/minecraft/block/BlockLeaves.java index dc534462..fd3903e8 100755 --- a/src/game/java/net/minecraft/block/BlockLeaves.java +++ b/src/game/java/net/minecraft/block/BlockLeaves.java @@ -23,7 +23,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockLeavesBase.java b/src/game/java/net/minecraft/block/BlockLeavesBase.java index fa8db7e5..08577d0c 100755 --- a/src/game/java/net/minecraft/block/BlockLeavesBase.java +++ b/src/game/java/net/minecraft/block/BlockLeavesBase.java @@ -11,7 +11,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockLever.java b/src/game/java/net/minecraft/block/BlockLever.java index 4948a666..47213698 100755 --- a/src/game/java/net/minecraft/block/BlockLever.java +++ b/src/game/java/net/minecraft/block/BlockLever.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockLilyPad.java b/src/game/java/net/minecraft/block/BlockLilyPad.java index b5fa49d0..07913621 100755 --- a/src/game/java/net/minecraft/block/BlockLilyPad.java +++ b/src/game/java/net/minecraft/block/BlockLilyPad.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockLiquid.java b/src/game/java/net/minecraft/block/BlockLiquid.java index bc0d1b90..c0acf93b 100755 --- a/src/game/java/net/minecraft/block/BlockLiquid.java +++ b/src/game/java/net/minecraft/block/BlockLiquid.java @@ -27,7 +27,7 @@ import net.minecraft.world.biome.BiomeColorHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockLog.java b/src/game/java/net/minecraft/block/BlockLog.java index acacc000..3b9390b2 100755 --- a/src/game/java/net/minecraft/block/BlockLog.java +++ b/src/game/java/net/minecraft/block/BlockLog.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockMelon.java b/src/game/java/net/minecraft/block/BlockMelon.java index dabba802..93450e89 100755 --- a/src/game/java/net/minecraft/block/BlockMelon.java +++ b/src/game/java/net/minecraft/block/BlockMelon.java @@ -15,7 +15,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockMobSpawner.java b/src/game/java/net/minecraft/block/BlockMobSpawner.java index 4a12be09..d9e8ed5f 100755 --- a/src/game/java/net/minecraft/block/BlockMobSpawner.java +++ b/src/game/java/net/minecraft/block/BlockMobSpawner.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockMushroom.java b/src/game/java/net/minecraft/block/BlockMushroom.java index 95dcb1d0..21496ac0 100755 --- a/src/game/java/net/minecraft/block/BlockMushroom.java +++ b/src/game/java/net/minecraft/block/BlockMushroom.java @@ -14,7 +14,7 @@ import net.minecraft.world.gen.feature.WorldGenBigMushroom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockMycelium.java b/src/game/java/net/minecraft/block/BlockMycelium.java index c2f6a3de..7c622aec 100755 --- a/src/game/java/net/minecraft/block/BlockMycelium.java +++ b/src/game/java/net/minecraft/block/BlockMycelium.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockNetherBrick.java b/src/game/java/net/minecraft/block/BlockNetherBrick.java index 0210337b..5f78c7d0 100755 --- a/src/game/java/net/minecraft/block/BlockNetherBrick.java +++ b/src/game/java/net/minecraft/block/BlockNetherBrick.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockNetherWart.java b/src/game/java/net/minecraft/block/BlockNetherWart.java index bd2df534..24b47098 100755 --- a/src/game/java/net/minecraft/block/BlockNetherWart.java +++ b/src/game/java/net/minecraft/block/BlockNetherWart.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockNetherrack.java b/src/game/java/net/minecraft/block/BlockNetherrack.java index 614c0585..7766eb84 100755 --- a/src/game/java/net/minecraft/block/BlockNetherrack.java +++ b/src/game/java/net/minecraft/block/BlockNetherrack.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockNewLeaf.java b/src/game/java/net/minecraft/block/BlockNewLeaf.java index c39a36c8..40379071 100755 --- a/src/game/java/net/minecraft/block/BlockNewLeaf.java +++ b/src/game/java/net/minecraft/block/BlockNewLeaf.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockNewLog.java b/src/game/java/net/minecraft/block/BlockNewLog.java index 4d46cd92..52b64837 100755 --- a/src/game/java/net/minecraft/block/BlockNewLog.java +++ b/src/game/java/net/minecraft/block/BlockNewLog.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockNote.java b/src/game/java/net/minecraft/block/BlockNote.java index 00886e87..3c6274bc 100755 --- a/src/game/java/net/minecraft/block/BlockNote.java +++ b/src/game/java/net/minecraft/block/BlockNote.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockObsidian.java b/src/game/java/net/minecraft/block/BlockObsidian.java index 8caae1e8..a3ae2f2a 100755 --- a/src/game/java/net/minecraft/block/BlockObsidian.java +++ b/src/game/java/net/minecraft/block/BlockObsidian.java @@ -15,7 +15,7 @@ import net.minecraft.item.Item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockOldLeaf.java b/src/game/java/net/minecraft/block/BlockOldLeaf.java index 3634f38a..a1804c2e 100755 --- a/src/game/java/net/minecraft/block/BlockOldLeaf.java +++ b/src/game/java/net/minecraft/block/BlockOldLeaf.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockOldLog.java b/src/game/java/net/minecraft/block/BlockOldLog.java index 8dbe8c78..448c2fa5 100755 --- a/src/game/java/net/minecraft/block/BlockOldLog.java +++ b/src/game/java/net/minecraft/block/BlockOldLog.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockOre.java b/src/game/java/net/minecraft/block/BlockOre.java index b063d923..a0e444c8 100755 --- a/src/game/java/net/minecraft/block/BlockOre.java +++ b/src/game/java/net/minecraft/block/BlockOre.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPackedIce.java b/src/game/java/net/minecraft/block/BlockPackedIce.java index 257804df..03c4453b 100755 --- a/src/game/java/net/minecraft/block/BlockPackedIce.java +++ b/src/game/java/net/minecraft/block/BlockPackedIce.java @@ -11,7 +11,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPane.java b/src/game/java/net/minecraft/block/BlockPane.java index 404bb875..05afad4a 100755 --- a/src/game/java/net/minecraft/block/BlockPane.java +++ b/src/game/java/net/minecraft/block/BlockPane.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPistonBase.java b/src/game/java/net/minecraft/block/BlockPistonBase.java index 1703ebe2..75791b37 100755 --- a/src/game/java/net/minecraft/block/BlockPistonBase.java +++ b/src/game/java/net/minecraft/block/BlockPistonBase.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPistonExtension.java b/src/game/java/net/minecraft/block/BlockPistonExtension.java index 37ecccee..2e1898aa 100755 --- a/src/game/java/net/minecraft/block/BlockPistonExtension.java +++ b/src/game/java/net/minecraft/block/BlockPistonExtension.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPistonMoving.java b/src/game/java/net/minecraft/block/BlockPistonMoving.java index bdf1f057..73f05661 100755 --- a/src/game/java/net/minecraft/block/BlockPistonMoving.java +++ b/src/game/java/net/minecraft/block/BlockPistonMoving.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPlanks.java b/src/game/java/net/minecraft/block/BlockPlanks.java index ba0109d9..b3fc20d7 100755 --- a/src/game/java/net/minecraft/block/BlockPlanks.java +++ b/src/game/java/net/minecraft/block/BlockPlanks.java @@ -19,7 +19,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPortal.java b/src/game/java/net/minecraft/block/BlockPortal.java index e2e499ab..dedef301 100755 --- a/src/game/java/net/minecraft/block/BlockPortal.java +++ b/src/game/java/net/minecraft/block/BlockPortal.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPotato.java b/src/game/java/net/minecraft/block/BlockPotato.java index b6ebed95..1d004848 100755 --- a/src/game/java/net/minecraft/block/BlockPotato.java +++ b/src/game/java/net/minecraft/block/BlockPotato.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPressurePlate.java b/src/game/java/net/minecraft/block/BlockPressurePlate.java index 0e7f7684..838f0cb8 100755 --- a/src/game/java/net/minecraft/block/BlockPressurePlate.java +++ b/src/game/java/net/minecraft/block/BlockPressurePlate.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java b/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java index 29ed717a..25696ed2 100755 --- a/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java +++ b/src/game/java/net/minecraft/block/BlockPressurePlateWeighted.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPrismarine.java b/src/game/java/net/minecraft/block/BlockPrismarine.java index 9addcbe5..8d6fa7a9 100755 --- a/src/game/java/net/minecraft/block/BlockPrismarine.java +++ b/src/game/java/net/minecraft/block/BlockPrismarine.java @@ -20,7 +20,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockPumpkin.java b/src/game/java/net/minecraft/block/BlockPumpkin.java index 98c8488d..2656e62e 100755 --- a/src/game/java/net/minecraft/block/BlockPumpkin.java +++ b/src/game/java/net/minecraft/block/BlockPumpkin.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockQuartz.java b/src/game/java/net/minecraft/block/BlockQuartz.java index 1685a638..2a447f69 100755 --- a/src/game/java/net/minecraft/block/BlockQuartz.java +++ b/src/game/java/net/minecraft/block/BlockQuartz.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRail.java b/src/game/java/net/minecraft/block/BlockRail.java index 1d5eeb3a..7a3f17a4 100755 --- a/src/game/java/net/minecraft/block/BlockRail.java +++ b/src/game/java/net/minecraft/block/BlockRail.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRailBase.java b/src/game/java/net/minecraft/block/BlockRailBase.java index 8f0884a5..39aba226 100755 --- a/src/game/java/net/minecraft/block/BlockRailBase.java +++ b/src/game/java/net/minecraft/block/BlockRailBase.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRailDetector.java b/src/game/java/net/minecraft/block/BlockRailDetector.java index 61299c96..50bd7964 100755 --- a/src/game/java/net/minecraft/block/BlockRailDetector.java +++ b/src/game/java/net/minecraft/block/BlockRailDetector.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRailPowered.java b/src/game/java/net/minecraft/block/BlockRailPowered.java index d2a136d6..63622ff5 100755 --- a/src/game/java/net/minecraft/block/BlockRailPowered.java +++ b/src/game/java/net/minecraft/block/BlockRailPowered.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedFlower.java b/src/game/java/net/minecraft/block/BlockRedFlower.java index 183fef29..c1b543b1 100755 --- a/src/game/java/net/minecraft/block/BlockRedFlower.java +++ b/src/game/java/net/minecraft/block/BlockRedFlower.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedSandstone.java b/src/game/java/net/minecraft/block/BlockRedSandstone.java index 1d7861a8..9e5c8581 100755 --- a/src/game/java/net/minecraft/block/BlockRedSandstone.java +++ b/src/game/java/net/minecraft/block/BlockRedSandstone.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedstoneComparator.java b/src/game/java/net/minecraft/block/BlockRedstoneComparator.java index 95db0406..b22b30ac 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneComparator.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneComparator.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedstoneDiode.java b/src/game/java/net/minecraft/block/BlockRedstoneDiode.java index 0087315b..c0c88e61 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneDiode.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneDiode.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedstoneLight.java b/src/game/java/net/minecraft/block/BlockRedstoneLight.java index 041eee05..39f318f3 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneLight.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneLight.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedstoneOre.java b/src/game/java/net/minecraft/block/BlockRedstoneOre.java index 0647819d..7eeafe7d 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneOre.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneOre.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java b/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java index 9a2c2253..4521ca13 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneRepeater.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRedstoneTorch.java b/src/game/java/net/minecraft/block/BlockRedstoneTorch.java index 06c751c1..41f95eba 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneTorch.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneTorch.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -119,11 +119,16 @@ public class BlockRedstoneTorch extends BlockTorch { public void updateTick(World world, BlockPos blockpos, IBlockState iblockstate, EaglercraftRandom random) { boolean flag = this.shouldBeOff(world, blockpos, iblockstate); - List list = (List) toggles.get(world); + List list = toggles.get(world); - while (list != null && !list.isEmpty() - && world.getTotalWorldTime() - ((BlockRedstoneTorch.Toggle) list.get(0)).time > 60L) { - list.remove(0); + if (list != null) { + int index = 0; + while (index < list.size() && world.getTotalWorldTime() - list.get(index).time > 60L) { + index++; + } + if (index > 0) { + list.subList(0, index).clear(); + } } if (this.isOn) { diff --git a/src/game/java/net/minecraft/block/BlockRedstoneWire.java b/src/game/java/net/minecraft/block/BlockRedstoneWire.java index f10fcd43..dfda4290 100755 --- a/src/game/java/net/minecraft/block/BlockRedstoneWire.java +++ b/src/game/java/net/minecraft/block/BlockRedstoneWire.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockReed.java b/src/game/java/net/minecraft/block/BlockReed.java index c81df456..93e20669 100755 --- a/src/game/java/net/minecraft/block/BlockReed.java +++ b/src/game/java/net/minecraft/block/BlockReed.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockRotatedPillar.java b/src/game/java/net/minecraft/block/BlockRotatedPillar.java index 3bead051..45dbe586 100755 --- a/src/game/java/net/minecraft/block/BlockRotatedPillar.java +++ b/src/game/java/net/minecraft/block/BlockRotatedPillar.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSand.java b/src/game/java/net/minecraft/block/BlockSand.java index 58e1175d..e8998e8d 100755 --- a/src/game/java/net/minecraft/block/BlockSand.java +++ b/src/game/java/net/minecraft/block/BlockSand.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSandStone.java b/src/game/java/net/minecraft/block/BlockSandStone.java index f5c249f5..a6d92d42 100755 --- a/src/game/java/net/minecraft/block/BlockSandStone.java +++ b/src/game/java/net/minecraft/block/BlockSandStone.java @@ -19,7 +19,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSapling.java b/src/game/java/net/minecraft/block/BlockSapling.java index 5d261c8a..4cd3860d 100755 --- a/src/game/java/net/minecraft/block/BlockSapling.java +++ b/src/game/java/net/minecraft/block/BlockSapling.java @@ -31,7 +31,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSeaLantern.java b/src/game/java/net/minecraft/block/BlockSeaLantern.java index 9ed67660..a831d151 100755 --- a/src/game/java/net/minecraft/block/BlockSeaLantern.java +++ b/src/game/java/net/minecraft/block/BlockSeaLantern.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSign.java b/src/game/java/net/minecraft/block/BlockSign.java index d5498ac7..c7f9c91c 100755 --- a/src/game/java/net/minecraft/block/BlockSign.java +++ b/src/game/java/net/minecraft/block/BlockSign.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSilverfish.java b/src/game/java/net/minecraft/block/BlockSilverfish.java index 75b234be..f37650a1 100755 --- a/src/game/java/net/minecraft/block/BlockSilverfish.java +++ b/src/game/java/net/minecraft/block/BlockSilverfish.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSkull.java b/src/game/java/net/minecraft/block/BlockSkull.java index a0ff2eae..1b589dfe 100755 --- a/src/game/java/net/minecraft/block/BlockSkull.java +++ b/src/game/java/net/minecraft/block/BlockSkull.java @@ -43,7 +43,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSlab.java b/src/game/java/net/minecraft/block/BlockSlab.java index 83220663..0ec9269c 100755 --- a/src/game/java/net/minecraft/block/BlockSlab.java +++ b/src/game/java/net/minecraft/block/BlockSlab.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSlime.java b/src/game/java/net/minecraft/block/BlockSlime.java index 41144bb0..76c0bc76 100755 --- a/src/game/java/net/minecraft/block/BlockSlime.java +++ b/src/game/java/net/minecraft/block/BlockSlime.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSnow.java b/src/game/java/net/minecraft/block/BlockSnow.java index 7bf7fab6..2bbbc327 100755 --- a/src/game/java/net/minecraft/block/BlockSnow.java +++ b/src/game/java/net/minecraft/block/BlockSnow.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSnowBlock.java b/src/game/java/net/minecraft/block/BlockSnowBlock.java index 7cc01215..072436d4 100755 --- a/src/game/java/net/minecraft/block/BlockSnowBlock.java +++ b/src/game/java/net/minecraft/block/BlockSnowBlock.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSoulSand.java b/src/game/java/net/minecraft/block/BlockSoulSand.java index a67f82cf..37a2f4b7 100755 --- a/src/game/java/net/minecraft/block/BlockSoulSand.java +++ b/src/game/java/net/minecraft/block/BlockSoulSand.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSourceImpl.java b/src/game/java/net/minecraft/block/BlockSourceImpl.java index a1603629..559e8207 100755 --- a/src/game/java/net/minecraft/block/BlockSourceImpl.java +++ b/src/game/java/net/minecraft/block/BlockSourceImpl.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockSponge.java b/src/game/java/net/minecraft/block/BlockSponge.java index 51241692..736fdd35 100755 --- a/src/game/java/net/minecraft/block/BlockSponge.java +++ b/src/game/java/net/minecraft/block/BlockSponge.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStainedGlass.java b/src/game/java/net/minecraft/block/BlockStainedGlass.java index f964f980..ff3d9fec 100755 --- a/src/game/java/net/minecraft/block/BlockStainedGlass.java +++ b/src/game/java/net/minecraft/block/BlockStainedGlass.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStainedGlassPane.java b/src/game/java/net/minecraft/block/BlockStainedGlassPane.java index e1db700c..debca6d2 100755 --- a/src/game/java/net/minecraft/block/BlockStainedGlassPane.java +++ b/src/game/java/net/minecraft/block/BlockStainedGlassPane.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStairs.java b/src/game/java/net/minecraft/block/BlockStairs.java index dc1cf48e..d86d0508 100755 --- a/src/game/java/net/minecraft/block/BlockStairs.java +++ b/src/game/java/net/minecraft/block/BlockStairs.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStandingSign.java b/src/game/java/net/minecraft/block/BlockStandingSign.java index 61c303af..5109b157 100755 --- a/src/game/java/net/minecraft/block/BlockStandingSign.java +++ b/src/game/java/net/minecraft/block/BlockStandingSign.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStaticLiquid.java b/src/game/java/net/minecraft/block/BlockStaticLiquid.java index e1d95030..704c3232 100755 --- a/src/game/java/net/minecraft/block/BlockStaticLiquid.java +++ b/src/game/java/net/minecraft/block/BlockStaticLiquid.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStem.java b/src/game/java/net/minecraft/block/BlockStem.java index 2c0f7eed..5a08b34a 100755 --- a/src/game/java/net/minecraft/block/BlockStem.java +++ b/src/game/java/net/minecraft/block/BlockStem.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStone.java b/src/game/java/net/minecraft/block/BlockStone.java index 0978de1e..2f6e56af 100755 --- a/src/game/java/net/minecraft/block/BlockStone.java +++ b/src/game/java/net/minecraft/block/BlockStone.java @@ -22,7 +22,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStoneBrick.java b/src/game/java/net/minecraft/block/BlockStoneBrick.java index 136e9f3c..a29812e6 100755 --- a/src/game/java/net/minecraft/block/BlockStoneBrick.java +++ b/src/game/java/net/minecraft/block/BlockStoneBrick.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStoneSlab.java b/src/game/java/net/minecraft/block/BlockStoneSlab.java index 10a5547e..d0cf124f 100755 --- a/src/game/java/net/minecraft/block/BlockStoneSlab.java +++ b/src/game/java/net/minecraft/block/BlockStoneSlab.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockStoneSlabNew.java b/src/game/java/net/minecraft/block/BlockStoneSlabNew.java index 00c8ad6f..b7f1bccc 100755 --- a/src/game/java/net/minecraft/block/BlockStoneSlabNew.java +++ b/src/game/java/net/minecraft/block/BlockStoneSlabNew.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockTNT.java b/src/game/java/net/minecraft/block/BlockTNT.java index e2088d14..f9fa0528 100755 --- a/src/game/java/net/minecraft/block/BlockTNT.java +++ b/src/game/java/net/minecraft/block/BlockTNT.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockTallGrass.java b/src/game/java/net/minecraft/block/BlockTallGrass.java index 36d77fc6..671d9e49 100755 --- a/src/game/java/net/minecraft/block/BlockTallGrass.java +++ b/src/game/java/net/minecraft/block/BlockTallGrass.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockTorch.java b/src/game/java/net/minecraft/block/BlockTorch.java index 633b2133..94b7c664 100755 --- a/src/game/java/net/minecraft/block/BlockTorch.java +++ b/src/game/java/net/minecraft/block/BlockTorch.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockTrapDoor.java b/src/game/java/net/minecraft/block/BlockTrapDoor.java index 77f4a73f..17d196aa 100755 --- a/src/game/java/net/minecraft/block/BlockTrapDoor.java +++ b/src/game/java/net/minecraft/block/BlockTrapDoor.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockTripWire.java b/src/game/java/net/minecraft/block/BlockTripWire.java index b9eb57b9..0675dbfd 100755 --- a/src/game/java/net/minecraft/block/BlockTripWire.java +++ b/src/game/java/net/minecraft/block/BlockTripWire.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockTripWireHook.java b/src/game/java/net/minecraft/block/BlockTripWireHook.java index dcfa9fe7..07e73e9a 100755 --- a/src/game/java/net/minecraft/block/BlockTripWireHook.java +++ b/src/game/java/net/minecraft/block/BlockTripWireHook.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockVine.java b/src/game/java/net/minecraft/block/BlockVine.java index 179beece..52e28ea6 100755 --- a/src/game/java/net/minecraft/block/BlockVine.java +++ b/src/game/java/net/minecraft/block/BlockVine.java @@ -30,7 +30,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockWall.java b/src/game/java/net/minecraft/block/BlockWall.java index 1e259991..ab1e80f5 100755 --- a/src/game/java/net/minecraft/block/BlockWall.java +++ b/src/game/java/net/minecraft/block/BlockWall.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockWallSign.java b/src/game/java/net/minecraft/block/BlockWallSign.java index e8b456b1..ebb92813 100755 --- a/src/game/java/net/minecraft/block/BlockWallSign.java +++ b/src/game/java/net/minecraft/block/BlockWallSign.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockWeb.java b/src/game/java/net/minecraft/block/BlockWeb.java index 4eeb6b94..b1327155 100755 --- a/src/game/java/net/minecraft/block/BlockWeb.java +++ b/src/game/java/net/minecraft/block/BlockWeb.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockWoodSlab.java b/src/game/java/net/minecraft/block/BlockWoodSlab.java index ade4b630..36adf26a 100755 --- a/src/game/java/net/minecraft/block/BlockWoodSlab.java +++ b/src/game/java/net/minecraft/block/BlockWoodSlab.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockWorkbench.java b/src/game/java/net/minecraft/block/BlockWorkbench.java index 8915cf22..30fdca31 100755 --- a/src/game/java/net/minecraft/block/BlockWorkbench.java +++ b/src/game/java/net/minecraft/block/BlockWorkbench.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/BlockYellowFlower.java b/src/game/java/net/minecraft/block/BlockYellowFlower.java index 16281600..01e6054b 100755 --- a/src/game/java/net/minecraft/block/BlockYellowFlower.java +++ b/src/game/java/net/minecraft/block/BlockYellowFlower.java @@ -6,7 +6,7 @@ package net.minecraft.block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/IGrowable.java b/src/game/java/net/minecraft/block/IGrowable.java index 7bd9898f..83615370 100755 --- a/src/game/java/net/minecraft/block/IGrowable.java +++ b/src/game/java/net/minecraft/block/IGrowable.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/ITileEntityProvider.java b/src/game/java/net/minecraft/block/ITileEntityProvider.java index 84b818d9..3501cebd 100755 --- a/src/game/java/net/minecraft/block/ITileEntityProvider.java +++ b/src/game/java/net/minecraft/block/ITileEntityProvider.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/material/MapColor.java b/src/game/java/net/minecraft/block/material/MapColor.java index c7aebfd0..7700bfe6 100755 --- a/src/game/java/net/minecraft/block/material/MapColor.java +++ b/src/game/java/net/minecraft/block/material/MapColor.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/material/Material.java b/src/game/java/net/minecraft/block/material/Material.java index 65ccc935..8597e516 100755 --- a/src/game/java/net/minecraft/block/material/Material.java +++ b/src/game/java/net/minecraft/block/material/Material.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/material/MaterialLiquid.java b/src/game/java/net/minecraft/block/material/MaterialLiquid.java index 8fd027b0..1352c8fa 100755 --- a/src/game/java/net/minecraft/block/material/MaterialLiquid.java +++ b/src/game/java/net/minecraft/block/material/MaterialLiquid.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/material/MaterialLogic.java b/src/game/java/net/minecraft/block/material/MaterialLogic.java index 79699c8c..92c65c47 100755 --- a/src/game/java/net/minecraft/block/material/MaterialLogic.java +++ b/src/game/java/net/minecraft/block/material/MaterialLogic.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/material/MaterialPortal.java b/src/game/java/net/minecraft/block/material/MaterialPortal.java index 1cad7e2d..9d83b983 100755 --- a/src/game/java/net/minecraft/block/material/MaterialPortal.java +++ b/src/game/java/net/minecraft/block/material/MaterialPortal.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/material/MaterialTransparent.java b/src/game/java/net/minecraft/block/material/MaterialTransparent.java index f58e96c8..5dda0587 100755 --- a/src/game/java/net/minecraft/block/material/MaterialTransparent.java +++ b/src/game/java/net/minecraft/block/material/MaterialTransparent.java @@ -6,7 +6,7 @@ package net.minecraft.block.material; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/properties/IProperty.java b/src/game/java/net/minecraft/block/properties/IProperty.java index fc2abe7d..3dd89864 100755 --- a/src/game/java/net/minecraft/block/properties/IProperty.java +++ b/src/game/java/net/minecraft/block/properties/IProperty.java @@ -8,7 +8,7 @@ import java.util.Collection; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/properties/PropertyBool.java b/src/game/java/net/minecraft/block/properties/PropertyBool.java index 0a983315..a375dc86 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyBool.java +++ b/src/game/java/net/minecraft/block/properties/PropertyBool.java @@ -10,7 +10,7 @@ import com.google.common.collect.ImmutableSet; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/properties/PropertyDirection.java b/src/game/java/net/minecraft/block/properties/PropertyDirection.java index 9cc316eb..84fe198f 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyDirection.java +++ b/src/game/java/net/minecraft/block/properties/PropertyDirection.java @@ -15,7 +15,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/properties/PropertyEnum.java b/src/game/java/net/minecraft/block/properties/PropertyEnum.java index 9f999e29..893fd208 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyEnum.java +++ b/src/game/java/net/minecraft/block/properties/PropertyEnum.java @@ -18,7 +18,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/properties/PropertyHelper.java b/src/game/java/net/minecraft/block/properties/PropertyHelper.java index 3f1c61ab..2518d2c3 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyHelper.java +++ b/src/game/java/net/minecraft/block/properties/PropertyHelper.java @@ -8,7 +8,7 @@ import com.google.common.base.Objects; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/properties/PropertyInteger.java b/src/game/java/net/minecraft/block/properties/PropertyInteger.java index 4d826cc9..67e7fbcb 100755 --- a/src/game/java/net/minecraft/block/properties/PropertyInteger.java +++ b/src/game/java/net/minecraft/block/properties/PropertyInteger.java @@ -12,7 +12,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java b/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java index 3c5dfc2c..69101068 100755 --- a/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java +++ b/src/game/java/net/minecraft/block/state/BlockPistonStructureHelper.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/BlockState.java b/src/game/java/net/minecraft/block/state/BlockState.java index 8f4b42a1..b949ab95 100755 --- a/src/game/java/net/minecraft/block/state/BlockState.java +++ b/src/game/java/net/minecraft/block/state/BlockState.java @@ -32,7 +32,7 @@ import net.minecraft.util.MapPopulator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/BlockStateBase.java b/src/game/java/net/minecraft/block/state/BlockStateBase.java index 87d32356..0ecc915e 100755 --- a/src/game/java/net/minecraft/block/state/BlockStateBase.java +++ b/src/game/java/net/minecraft/block/state/BlockStateBase.java @@ -17,7 +17,7 @@ import net.minecraft.block.properties.IProperty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/BlockWorldState.java b/src/game/java/net/minecraft/block/state/BlockWorldState.java index fdfe5201..48827700 100755 --- a/src/game/java/net/minecraft/block/state/BlockWorldState.java +++ b/src/game/java/net/minecraft/block/state/BlockWorldState.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/IBlockState.java b/src/game/java/net/minecraft/block/state/IBlockState.java index 20cd5850..05df0ed3 100755 --- a/src/game/java/net/minecraft/block/state/IBlockState.java +++ b/src/game/java/net/minecraft/block/state/IBlockState.java @@ -13,7 +13,7 @@ import net.minecraft.block.properties.IProperty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java b/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java index edeb5565..a53638bb 100755 --- a/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java +++ b/src/game/java/net/minecraft/block/state/pattern/BlockHelper.java @@ -11,7 +11,7 @@ import net.minecraft.block.state.IBlockState; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java b/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java index 2bd9330a..af6d68fe 100755 --- a/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java +++ b/src/game/java/net/minecraft/block/state/pattern/BlockPattern.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java b/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java index 48ea7e81..992c1aef 100755 --- a/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java +++ b/src/game/java/net/minecraft/block/state/pattern/BlockStateHelper.java @@ -17,7 +17,7 @@ import net.minecraft.block.state.IBlockState; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java b/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java index bd882033..f3265584 100755 --- a/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java +++ b/src/game/java/net/minecraft/block/state/pattern/FactoryBlockPattern.java @@ -2,16 +2,16 @@ package net.minecraft.block.state.pattern; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import org.apache.commons.lang3.StringUtils; +import com.carrotsearch.hppc.CharObjectHashMap; +import com.carrotsearch.hppc.CharObjectMap; +import com.carrotsearch.hppc.cursors.CharObjectCursor; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import net.minecraft.block.state.BlockWorldState; @@ -21,7 +21,7 @@ import net.minecraft.block.state.BlockWorldState; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -38,12 +38,12 @@ import net.minecraft.block.state.BlockWorldState; public class FactoryBlockPattern { private static final Joiner COMMA_JOIN = Joiner.on(","); private final List depth = Lists.newArrayList(); - private final Map> symbolMap = Maps.newHashMap(); + private final CharObjectMap> symbolMap = new CharObjectHashMap<>(); private int aisleHeight; private int rowWidth; private FactoryBlockPattern() { - this.symbolMap.put(Character.valueOf(' '), Predicates.alwaysTrue()); + this.symbolMap.put(' ', Predicates.alwaysTrue()); } public FactoryBlockPattern aisle(String... aisle) { @@ -68,8 +68,8 @@ public class FactoryBlockPattern { char[] achar = s.toCharArray(); for (int j = 0; j < achar.length; ++j) { char c0 = achar[j]; - if (!this.symbolMap.containsKey(Character.valueOf(c0))) { - this.symbolMap.put(Character.valueOf(c0), null); + if (!this.symbolMap.containsKey(c0)) { + this.symbolMap.put(c0, null); } } } @@ -87,7 +87,7 @@ public class FactoryBlockPattern { } public FactoryBlockPattern where(char symbol, Predicate blockMatcher) { - this.symbolMap.put(Character.valueOf(symbol), blockMatcher); + this.symbolMap.put(symbol, blockMatcher); return this; } @@ -102,8 +102,7 @@ public class FactoryBlockPattern { for (int i = 0; i < this.depth.size(); ++i) { for (int j = 0; j < this.aisleHeight; ++j) { for (int k = 0; k < this.rowWidth; ++k) { - apredicate[i][j][k] = (Predicate) this.symbolMap - .get(Character.valueOf(((String[]) this.depth.get(i))[j].charAt(k))); + apredicate[i][j][k] = this.symbolMap.get(((String[]) this.depth.get(i))[j].charAt(k)); } } } @@ -114,9 +113,9 @@ public class FactoryBlockPattern { private void checkMissingPredicates() { ArrayList arraylist = Lists.newArrayList(); - for (Entry entry : this.symbolMap.entrySet()) { - if (entry.getValue() == null) { - arraylist.add(entry.getKey()); + for (CharObjectCursor> entry : this.symbolMap) { + if (entry.value == null) { + arraylist.add(entry.key); } } diff --git a/src/game/java/net/minecraft/client/ClientBrandRetriever.java b/src/game/java/net/minecraft/client/ClientBrandRetriever.java index 232956c7..05a7dece 100755 --- a/src/game/java/net/minecraft/client/ClientBrandRetriever.java +++ b/src/game/java/net/minecraft/client/ClientBrandRetriever.java @@ -6,7 +6,7 @@ package net.minecraft.client; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/LoadingScreenRenderer.java b/src/game/java/net/minecraft/client/LoadingScreenRenderer.java index 597a5388..11a10df5 100755 --- a/src/game/java/net/minecraft/client/LoadingScreenRenderer.java +++ b/src/game/java/net/minecraft/client/LoadingScreenRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.util.MinecraftError; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/Minecraft.java b/src/game/java/net/minecraft/client/Minecraft.java index 933aff53..1dabd777 100755 --- a/src/game/java/net/minecraft/client/Minecraft.java +++ b/src/game/java/net/minecraft/client/Minecraft.java @@ -206,7 +206,7 @@ import net.minecraft.world.storage.ISaveFormat; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/GuardianSound.java b/src/game/java/net/minecraft/client/audio/GuardianSound.java index b88fd273..16ee7cd9 100755 --- a/src/game/java/net/minecraft/client/audio/GuardianSound.java +++ b/src/game/java/net/minecraft/client/audio/GuardianSound.java @@ -9,7 +9,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/ISound.java b/src/game/java/net/minecraft/client/audio/ISound.java index 5df9e099..21a3a735 100755 --- a/src/game/java/net/minecraft/client/audio/ISound.java +++ b/src/game/java/net/minecraft/client/audio/ISound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java b/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java index bfa4d74d..cba466b7 100755 --- a/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java +++ b/src/game/java/net/minecraft/client/audio/ISoundEventAccessor.java @@ -6,7 +6,7 @@ package net.minecraft.client.audio; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/ITickableSound.java b/src/game/java/net/minecraft/client/audio/ITickableSound.java index 66dc660e..b290ae73 100755 --- a/src/game/java/net/minecraft/client/audio/ITickableSound.java +++ b/src/game/java/net/minecraft/client/audio/ITickableSound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/MovingSound.java b/src/game/java/net/minecraft/client/audio/MovingSound.java index 7b312aeb..2c5ced65 100755 --- a/src/game/java/net/minecraft/client/audio/MovingSound.java +++ b/src/game/java/net/minecraft/client/audio/MovingSound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java b/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java index 5abe13c8..3d970321 100755 --- a/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java +++ b/src/game/java/net/minecraft/client/audio/MovingSoundMinecart.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java b/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java index 876c5625..9a560f2e 100755 --- a/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java +++ b/src/game/java/net/minecraft/client/audio/MovingSoundMinecartRiding.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/MusicTicker.java b/src/game/java/net/minecraft/client/audio/MusicTicker.java index 1f5a8cdf..f377fac1 100755 --- a/src/game/java/net/minecraft/client/audio/MusicTicker.java +++ b/src/game/java/net/minecraft/client/audio/MusicTicker.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/PositionedSound.java b/src/game/java/net/minecraft/client/audio/PositionedSound.java index a6790292..13f2a2e8 100755 --- a/src/game/java/net/minecraft/client/audio/PositionedSound.java +++ b/src/game/java/net/minecraft/client/audio/PositionedSound.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java b/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java index 7814e6ee..1ec00d7d 100755 --- a/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java +++ b/src/game/java/net/minecraft/client/audio/PositionedSoundRecord.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/SoundCategory.java b/src/game/java/net/minecraft/client/audio/SoundCategory.java index d9e22bef..51d637ff 100755 --- a/src/game/java/net/minecraft/client/audio/SoundCategory.java +++ b/src/game/java/net/minecraft/client/audio/SoundCategory.java @@ -2,6 +2,8 @@ package net.minecraft.client.audio; import java.util.Map; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Maps; /**+ @@ -10,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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,7 +33,7 @@ public enum SoundCategory { public static final SoundCategory[] _VALUES = values(); private static final Map NAME_CATEGORY_MAP = Maps.newHashMap(); - private static final Map ID_CATEGORY_MAP = Maps.newHashMap(); + private static final IntObjectMap ID_CATEGORY_MAP = new IntObjectHashMap<>(); private final String categoryName; private final int categoryId; @@ -57,12 +59,12 @@ public enum SoundCategory { for (int i = 0; i < categories.length; ++i) { SoundCategory soundcategory = categories[i]; if (NAME_CATEGORY_MAP.containsKey(soundcategory.getCategoryName()) - || ID_CATEGORY_MAP.containsKey(Integer.valueOf(soundcategory.getCategoryId()))) { + || ID_CATEGORY_MAP.containsKey(soundcategory.getCategoryId())) { throw new Error("Clash in Sound Category ID & Name pools! Cannot insert " + soundcategory); } NAME_CATEGORY_MAP.put(soundcategory.getCategoryName(), soundcategory); - ID_CATEGORY_MAP.put(Integer.valueOf(soundcategory.getCategoryId()), soundcategory); + ID_CATEGORY_MAP.put(soundcategory.getCategoryId(), soundcategory); } } diff --git a/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java b/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java index f23d7e40..1b87f566 100755 --- a/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java +++ b/src/game/java/net/minecraft/client/audio/SoundEventAccessor.java @@ -6,7 +6,7 @@ package net.minecraft.client.audio; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java b/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java index 3911f6a9..08d20016 100755 --- a/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java +++ b/src/game/java/net/minecraft/client/audio/SoundEventAccessorComposite.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/SoundHandler.java b/src/game/java/net/minecraft/client/audio/SoundHandler.java index 445b9d3d..9ec3b9d2 100755 --- a/src/game/java/net/minecraft/client/audio/SoundHandler.java +++ b/src/game/java/net/minecraft/client/audio/SoundHandler.java @@ -31,7 +31,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/SoundList.java b/src/game/java/net/minecraft/client/audio/SoundList.java index 87e26fcd..316f4b8f 100755 --- a/src/game/java/net/minecraft/client/audio/SoundList.java +++ b/src/game/java/net/minecraft/client/audio/SoundList.java @@ -10,7 +10,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/SoundListSerializer.java b/src/game/java/net/minecraft/client/audio/SoundListSerializer.java index 14f37e4f..5855e313 100755 --- a/src/game/java/net/minecraft/client/audio/SoundListSerializer.java +++ b/src/game/java/net/minecraft/client/audio/SoundListSerializer.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeDeserializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java b/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java index 4fd65772..a3787b93 100755 --- a/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java +++ b/src/game/java/net/minecraft/client/audio/SoundPoolEntry.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/audio/SoundRegistry.java b/src/game/java/net/minecraft/client/audio/SoundRegistry.java index 61ee6d30..30bf6325 100755 --- a/src/game/java/net/minecraft/client/audio/SoundRegistry.java +++ b/src/game/java/net/minecraft/client/audio/SoundRegistry.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java b/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java index 4259135c..ac7f50d5 100755 --- a/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java +++ b/src/game/java/net/minecraft/client/entity/AbstractClientPlayer.java @@ -26,7 +26,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java b/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java index f7e668a1..6d58c872 100755 --- a/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java +++ b/src/game/java/net/minecraft/client/entity/EntityOtherPlayerMP.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java b/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java index 9e8f30b1..36d99a89 100755 --- a/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java +++ b/src/game/java/net/minecraft/client/entity/EntityPlayerSP.java @@ -61,7 +61,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/ChatLine.java b/src/game/java/net/minecraft/client/gui/ChatLine.java index 1bd8e16b..d392f40d 100755 --- a/src/game/java/net/minecraft/client/gui/ChatLine.java +++ b/src/game/java/net/minecraft/client/gui/ChatLine.java @@ -10,7 +10,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/FontRenderer.java b/src/game/java/net/minecraft/client/gui/FontRenderer.java index 7ec37e22..5d26062e 100755 --- a/src/game/java/net/minecraft/client/gui/FontRenderer.java +++ b/src/game/java/net/minecraft/client/gui/FontRenderer.java @@ -4,6 +4,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.List; + +import net.lax1dude.eaglercraft.v1_8.EaglerBidiReorder; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.HString; @@ -28,7 +30,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -329,21 +331,6 @@ public class FontRenderer implements IResourceManagerReloadListener { return i; } - /**+ - * Apply Unicode Bidirectional Algorithm to string and return a - * new possibly reordered string for visual rendering. - */ - private String bidiReorder(String parString1) { -// try { -// Bidi bidi = new Bidi((new ArabicShaping(8)).shape(parString1), 127); -// bidi.setReorderingMode(0); -// return bidi.writeReordered(2); -// } catch (ArabicShapingException var3) { -// return parString1; -// } - return parString1; - } - /**+ * Reset all style flag fields in the class to false; called at * the start of string rendering @@ -501,7 +488,7 @@ public class FontRenderer implements IResourceManagerReloadListener { */ private int renderStringAligned(String text, int x, int y, int wrapWidth, int color, boolean parFlag) { if (this.bidiFlag) { - int i = this.getStringWidth(this.bidiReorder(text)); + int i = this.getStringWidth(EaglerBidiReorder.bidiReorder(text)); x = x + wrapWidth - i; } @@ -518,7 +505,7 @@ public class FontRenderer implements IResourceManagerReloadListener { this.posY = y; } else { if (this.bidiFlag) { - text = this.bidiReorder(text); + text = EaglerBidiReorder.bidiReorder(text); } if ((color & -67108864) == 0) { diff --git a/src/game/java/net/minecraft/client/gui/Gui.java b/src/game/java/net/minecraft/client/gui/Gui.java index c2fc356f..bc7f23ea 100755 --- a/src/game/java/net/minecraft/client/gui/Gui.java +++ b/src/game/java/net/minecraft/client/gui/Gui.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiButton.java b/src/game/java/net/minecraft/client/gui/GuiButton.java index 54dc4be0..4f5dc626 100755 --- a/src/game/java/net/minecraft/client/gui/GuiButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiButton.java @@ -16,7 +16,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java b/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java index 850e4468..74c99ff2 100755 --- a/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java +++ b/src/game/java/net/minecraft/client/gui/GuiButtonLanguage.java @@ -11,7 +11,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiChat.java b/src/game/java/net/minecraft/client/gui/GuiChat.java index 48e28fca..19f639fe 100755 --- a/src/game/java/net/minecraft/client/gui/GuiChat.java +++ b/src/game/java/net/minecraft/client/gui/GuiChat.java @@ -31,7 +31,7 @@ import net.minecraft.util.MovingObjectPosition; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java b/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java index 78f9efb3..b9b0344a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java +++ b/src/game/java/net/minecraft/client/gui/GuiCommandBlock.java @@ -17,7 +17,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java b/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java index faa42d05..9bca025b 100755 --- a/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java +++ b/src/game/java/net/minecraft/client/gui/GuiConfirmOpenLink.java @@ -8,7 +8,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiControls.java b/src/game/java/net/minecraft/client/gui/GuiControls.java index da3fb4a7..0e08d1f1 100755 --- a/src/game/java/net/minecraft/client/gui/GuiControls.java +++ b/src/game/java/net/minecraft/client/gui/GuiControls.java @@ -13,7 +13,7 @@ import net.minecraft.client.settings.KeyBinding; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java b/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java index bb66925e..1c571761 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiCreateFlatWorld.java @@ -23,7 +23,7 @@ import net.minecraft.world.gen.FlatLayerInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java b/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java index 16b1b6ec..8f31695a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiCreateWorld.java @@ -18,7 +18,7 @@ import org.apache.commons.lang3.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java b/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java index 4a2d4857..6b58328a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java +++ b/src/game/java/net/minecraft/client/gui/GuiCustomizeSkin.java @@ -9,7 +9,7 @@ import net.minecraft.entity.player.EnumPlayerModelParts; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java b/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java index 5a124068..8b040b97 100755 --- a/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiCustomizeWorldScreen.java @@ -22,7 +22,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiDisconnected.java b/src/game/java/net/minecraft/client/gui/GuiDisconnected.java index b37fa256..05a450a9 100755 --- a/src/game/java/net/minecraft/client/gui/GuiDisconnected.java +++ b/src/game/java/net/minecraft/client/gui/GuiDisconnected.java @@ -15,7 +15,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java b/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java index b530ba0f..45c13dde 100755 --- a/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java +++ b/src/game/java/net/minecraft/client/gui/GuiDownloadTerrain.java @@ -10,7 +10,7 @@ import net.minecraft.network.play.client.C00PacketKeepAlive; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiEnchantment.java b/src/game/java/net/minecraft/client/gui/GuiEnchantment.java index 4475cec3..afc50c42 100755 --- a/src/game/java/net/minecraft/client/gui/GuiEnchantment.java +++ b/src/game/java/net/minecraft/client/gui/GuiEnchantment.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java b/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java index 083a688c..6f1387c3 100755 --- a/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiErrorScreen.java @@ -8,7 +8,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java b/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java index b261f8d9..4a7ea5bb 100755 --- a/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java +++ b/src/game/java/net/minecraft/client/gui/GuiFlatPresets.java @@ -29,7 +29,7 @@ import net.minecraft.world.gen.FlatLayerInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiGameOver.java b/src/game/java/net/minecraft/client/gui/GuiGameOver.java index 73577b52..e8db0d14 100755 --- a/src/game/java/net/minecraft/client/gui/GuiGameOver.java +++ b/src/game/java/net/minecraft/client/gui/GuiGameOver.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiHopper.java b/src/game/java/net/minecraft/client/gui/GuiHopper.java index 263ea609..35ca080d 100755 --- a/src/game/java/net/minecraft/client/gui/GuiHopper.java +++ b/src/game/java/net/minecraft/client/gui/GuiHopper.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiIngame.java b/src/game/java/net/minecraft/client/gui/GuiIngame.java index 89223159..ff09a1b8 100755 --- a/src/game/java/net/minecraft/client/gui/GuiIngame.java +++ b/src/game/java/net/minecraft/client/gui/GuiIngame.java @@ -64,7 +64,7 @@ import net.minecraft.world.border.WorldBorder; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java b/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java index c5bc76d0..cc92c330 100755 --- a/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java +++ b/src/game/java/net/minecraft/client/gui/GuiIngameMenu.java @@ -33,7 +33,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java b/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java index d5c3fba8..755a822d 100755 --- a/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java +++ b/src/game/java/net/minecraft/client/gui/GuiKeyBindingList.java @@ -16,7 +16,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiLabel.java b/src/game/java/net/minecraft/client/gui/GuiLabel.java index 0657b9a9..dd716b60 100755 --- a/src/game/java/net/minecraft/client/gui/GuiLabel.java +++ b/src/game/java/net/minecraft/client/gui/GuiLabel.java @@ -16,7 +16,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiLanguage.java b/src/game/java/net/minecraft/client/gui/GuiLanguage.java index f62de6b6..900b01a3 100755 --- a/src/game/java/net/minecraft/client/gui/GuiLanguage.java +++ b/src/game/java/net/minecraft/client/gui/GuiLanguage.java @@ -18,7 +18,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiListButton.java b/src/game/java/net/minecraft/client/gui/GuiListButton.java index 95680cd0..9ab5543a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiListButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiListButton.java @@ -9,7 +9,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiListExtended.java b/src/game/java/net/minecraft/client/gui/GuiListExtended.java index 83b44ae9..fa5eb56b 100755 --- a/src/game/java/net/minecraft/client/gui/GuiListExtended.java +++ b/src/game/java/net/minecraft/client/gui/GuiListExtended.java @@ -8,7 +8,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java b/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java index 88982a2a..81866484 100755 --- a/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiLockIconButton.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiMainMenu.java b/src/game/java/net/minecraft/client/gui/GuiMainMenu.java index 8a470b81..0c0bfafe 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMainMenu.java +++ b/src/game/java/net/minecraft/client/gui/GuiMainMenu.java @@ -53,7 +53,7 @@ import net.minecraft.world.storage.ISaveFormat; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java b/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java index b07c6c22..7f55854a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiMemoryErrorScreen.java @@ -8,7 +8,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiMerchant.java b/src/game/java/net/minecraft/client/gui/GuiMerchant.java index ce884f7d..1b03052e 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMerchant.java +++ b/src/game/java/net/minecraft/client/gui/GuiMerchant.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java b/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java index d5aeab11..08de930a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java +++ b/src/game/java/net/minecraft/client/gui/GuiMultiplayer.java @@ -33,7 +33,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiNewChat.java b/src/game/java/net/minecraft/client/gui/GuiNewChat.java index 5047cfa6..fc0a47f0 100755 --- a/src/game/java/net/minecraft/client/gui/GuiNewChat.java +++ b/src/game/java/net/minecraft/client/gui/GuiNewChat.java @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiOptionButton.java b/src/game/java/net/minecraft/client/gui/GuiOptionButton.java index 3ea9cbec..3f198fd8 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptionButton.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptionButton.java @@ -8,7 +8,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java b/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java index 0c97f190..00f72699 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptionSlider.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiOptions.java b/src/game/java/net/minecraft/client/gui/GuiOptions.java index fdae3805..41c339cc 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptions.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptions.java @@ -34,7 +34,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java b/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java index 3c674cfd..086fff94 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java +++ b/src/game/java/net/minecraft/client/gui/GuiOptionsRowList.java @@ -14,7 +14,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java b/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java index c06a90bc..0ac88554 100755 --- a/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java +++ b/src/game/java/net/minecraft/client/gui/GuiOverlayDebug.java @@ -5,7 +5,6 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map.Entry; @@ -14,6 +13,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.TimeZone; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.base.Strings; import com.google.common.collect.Lists; @@ -50,7 +50,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -169,28 +169,25 @@ public class GuiOverlayDebug extends Gui { this.fontRenderer.drawStringWithShadow(line, x - lw, y - i, 0xFFFFFF); i += 11; - Iterator potions = mc.thePlayer.getActivePotionEffects().iterator(); - if (potions.hasNext()) { - while (potions.hasNext()) { - i += 11; - PotionEffect e = potions.next(); - int t = e.getDuration() / 20; - int m = t / 60; - int s = t % 60; - int j = e.getAmplifier(); - if (j > 0) { - line = I18n.format(e.getEffectName()) - + (j > 0 ? (" " + EnumChatFormatting.YELLOW + EnumChatFormatting.BOLD - + I18n.format("potion.potency." + j) + EnumChatFormatting.RESET) : "") - + " [" + EnumChatFormatting.YELLOW + HString.format("%02d:%02d", m, s) - + EnumChatFormatting.RESET + "]"; - } else { - line = I18n.format(e.getEffectName()) + " [" + EnumChatFormatting.YELLOW - + HString.format("%02d:%02d", m, s) + EnumChatFormatting.RESET + "]"; - } - lw = fontRenderer.getStringWidth(line); - this.fontRenderer.drawStringWithShadow(line, x - lw, y - i, 0xFFFFFF); + for (ObjectCursor ee : mc.thePlayer.getActivePotionEffects()) { + i += 11; + PotionEffect e = ee.value; + int t = e.getDuration() / 20; + int m = t / 60; + int s = t % 60; + int j = e.getAmplifier(); + if (j > 0) { + line = I18n.format(e.getEffectName()) + + (j > 0 ? (" " + EnumChatFormatting.YELLOW + EnumChatFormatting.BOLD + + I18n.format("potion.potency." + j) + EnumChatFormatting.RESET) : "") + + " [" + EnumChatFormatting.YELLOW + HString.format("%02d:%02d", m, s) + + EnumChatFormatting.RESET + "]"; + } else { + line = I18n.format(e.getEffectName()) + " [" + EnumChatFormatting.YELLOW + + HString.format("%02d:%02d", m, s) + EnumChatFormatting.RESET + "]"; } + lw = fontRenderer.getStringWidth(line); + this.fontRenderer.drawStringWithShadow(line, x - lw, y - i, 0xFFFFFF); } } @@ -435,7 +432,7 @@ public class GuiOverlayDebug extends Gui { long j = EagRuntime.totalMemory(); long k = EagRuntime.freeMemory(); long l = j - k; - arraylist = Lists.newArrayList(new String[] { + arraylist = Lists.newArrayList(new String[] { "Platform: Desktop", HString.format("Java: %s %dbit", new Object[] { System.getProperty("java.version"), Integer.valueOf(this.mc.isJava64bit() ? 64 : 32) }), @@ -450,12 +447,12 @@ public class GuiOverlayDebug extends Gui { EaglercraftGPU.glGetString(7936) }), EaglercraftGPU.glGetString(7937), EaglercraftGPU.glGetString(7938) }); } else { - arraylist = Lists.newArrayList( - new String[] { "Java: TeaVM", "", HString.format("CPU: %s", new Object[] { "eaglercraft" }), "", - HString.format("Display: %dx%d (%s)", - new Object[] { Integer.valueOf(Display.getWidth()), - Integer.valueOf(Display.getHeight()), EaglercraftGPU.glGetString(7936) }), - EaglercraftGPU.glGetString(7937), EaglercraftGPU.glGetString(7938) }); + arraylist = Lists.newArrayList(new String[] { "Platform: " + EagRuntime.getPlatformType().getName(), + "Java: TeaVM", "", HString.format("CPU: %s", new Object[] { "eaglercraft" }), "", + HString.format("Display: %dx%d (%s)", + new Object[] { Integer.valueOf(Display.getWidth()), Integer.valueOf(Display.getHeight()), + EaglercraftGPU.glGetString(7936) }), + EaglercraftGPU.glGetString(7937), EaglercraftGPU.glGetString(7938) }); } if (this.isReducedDebug()) { return arraylist; diff --git a/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java b/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java index 68c937a8..82fbf667 100755 --- a/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java +++ b/src/game/java/net/minecraft/client/gui/GuiPageButtonList.java @@ -2,6 +2,8 @@ package net.minecraft.client.gui; import java.util.List; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -10,7 +12,6 @@ import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction; import net.lax1dude.eaglercraft.v1_8.minecraft.EnumInputEvent; import net.minecraft.client.Minecraft; -import net.minecraft.util.IntHashMap; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -18,7 +19,7 @@ import net.minecraft.util.IntHashMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -34,7 +35,7 @@ import net.minecraft.util.IntHashMap; */ public class GuiPageButtonList extends GuiListExtended { private final List field_178074_u = Lists.newArrayList(); - private final IntHashMap field_178073_v = new IntHashMap(); + private final IntObjectMap field_178073_v = new IntObjectHashMap<>(); private final List field_178072_w = Lists.newArrayList(); private final GuiPageButtonList.GuiListEntry[][] field_178078_x; private int field_178077_y; @@ -65,14 +66,14 @@ public class GuiPageButtonList extends GuiListExtended { GuiPageButtonList.GuiEntry guipagebuttonlist$guientry = new GuiPageButtonList.GuiEntry(gui, gui1); this.field_178074_u.add(guipagebuttonlist$guientry); if (guipagebuttonlist$guilistentry != null && gui != null) { - this.field_178073_v.addKey(guipagebuttonlist$guilistentry.func_178935_b(), gui); + this.field_178073_v.put(guipagebuttonlist$guilistentry.func_178935_b(), gui); if (gui instanceof GuiTextField) { this.field_178072_w.add((GuiTextField) gui); } } if (guipagebuttonlist$guilistentry1 != null && gui1 != null) { - this.field_178073_v.addKey(guipagebuttonlist$guilistentry1.func_178935_b(), gui1); + this.field_178073_v.put(guipagebuttonlist$guilistentry1.func_178935_b(), gui1); if (gui1 instanceof GuiTextField) { this.field_178072_w.add((GuiTextField) gui1); } @@ -89,9 +90,9 @@ public class GuiPageButtonList extends GuiListExtended { GuiPageButtonList.GuiListEntry guipagebuttonlist$guilistentry = this.field_178078_x[this.field_178077_y][i]; GuiPageButtonList.GuiListEntry guipagebuttonlist$guilistentry1 = i < this.field_178078_x[this.field_178077_y].length - 1 ? this.field_178078_x[this.field_178077_y][i + 1] : null; - Gui gui = (Gui) this.field_178073_v.lookup(guipagebuttonlist$guilistentry.func_178935_b()); + Gui gui = this.field_178073_v.get(guipagebuttonlist$guilistentry.func_178935_b()); Gui gui1 = guipagebuttonlist$guilistentry1 != null - ? (Gui) this.field_178073_v.lookup(guipagebuttonlist$guilistentry1.func_178935_b()) + ? this.field_178073_v.get(guipagebuttonlist$guilistentry1.func_178935_b()) : null; GuiPageButtonList.GuiEntry guipagebuttonlist$guientry = new GuiPageButtonList.GuiEntry(gui, gui1); this.field_178074_u.add(guipagebuttonlist$guientry); @@ -136,7 +137,7 @@ public class GuiPageButtonList extends GuiListExtended { } public Gui func_178061_c(int parInt1) { - return (Gui) this.field_178073_v.lookup(parInt1); + return this.field_178073_v.get(parInt1); } private void func_178060_e(int parInt1, int parInt2) { @@ -144,14 +145,14 @@ public class GuiPageButtonList extends GuiListExtended { GuiListEntry[] etr = this.field_178078_x[parInt1]; for (int i = 0; i < etr.length; ++i) { if (etr[i] != null) { - this.func_178066_a((Gui) this.field_178073_v.lookup(etr[i].func_178935_b()), false); + this.func_178066_a(this.field_178073_v.get(etr[i].func_178935_b()), false); } } etr = this.field_178078_x[parInt2]; for (int i = 0; i < etr.length; ++i) { if (etr[i] != null) { - this.func_178066_a((Gui) this.field_178073_v.lookup(etr[i].func_178935_b()), true); + this.func_178066_a(this.field_178073_v.get(etr[i].func_178935_b()), true); } } diff --git a/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java b/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java index 7233bb3d..8318ffb7 100755 --- a/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java +++ b/src/game/java/net/minecraft/client/gui/GuiPlayerTabOverlay.java @@ -30,7 +30,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java b/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java index 7322d165..f6d1c769 100755 --- a/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiRenameWorld.java @@ -14,7 +14,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiRepair.java b/src/game/java/net/minecraft/client/gui/GuiRepair.java index 9167e7c1..310dd47a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiRepair.java +++ b/src/game/java/net/minecraft/client/gui/GuiRepair.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java b/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java index 9ccf60e4..e705c5df 100755 --- a/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java +++ b/src/game/java/net/minecraft/client/gui/GuiResourcePackAvailable.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.ResourcePackListEntry; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java b/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java index cb61085a..843c87ac 100755 --- a/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java +++ b/src/game/java/net/minecraft/client/gui/GuiResourcePackList.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java b/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java index c6f597ec..f9b00918 100755 --- a/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java +++ b/src/game/java/net/minecraft/client/gui/GuiResourcePackSelected.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.ResourcePackListEntry; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiScreen.java b/src/game/java/net/minecraft/client/gui/GuiScreen.java index cb628b88..ac89da4b 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreen.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreen.java @@ -5,14 +5,14 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import net.lax1dude.eaglercraft.v1_8.internal.EnumTouchEvent; import org.apache.commons.lang3.StringUtils; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -60,7 +60,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -574,7 +574,7 @@ public abstract class GuiScreen extends Gui implements GuiYesNoCallback { } - public final Map touchStarts = new HashMap<>(); + public final IntObjectMap touchStarts = new IntObjectHashMap<>(); /** * Handles touch input. diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java b/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java index 91731f51..6474d3e4 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenAddServer.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenBook.java b/src/game/java/net/minecraft/client/gui/GuiScreenBook.java index 1683573b..429048a6 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenBook.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenBook.java @@ -36,7 +36,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java b/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java index 76f9eabc..fb45ab7d 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenCustomizePresets.java @@ -20,7 +20,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java b/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java index 84e12d5c..2376a160 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenOptionsSounds.java @@ -16,7 +16,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java b/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java index 1210ab67..d4bb96e2 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenResourcePacks.java @@ -25,7 +25,7 @@ import net.minecraft.client.resources.ResourcePackRepository; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java b/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java index 57932985..2673291c 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenServerList.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java b/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java index ff72f19b..9508f840 100755 --- a/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java +++ b/src/game/java/net/minecraft/client/gui/GuiScreenWorking.java @@ -8,7 +8,7 @@ import net.minecraft.util.IProgressUpdate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java b/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java index 86860c37..038d8620 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java +++ b/src/game/java/net/minecraft/client/gui/GuiSelectWorld.java @@ -38,7 +38,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.gui.GuiScreenLANInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiSleepMP.java b/src/game/java/net/minecraft/client/gui/GuiSleepMP.java index 0637b535..f8f81484 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSleepMP.java +++ b/src/game/java/net/minecraft/client/gui/GuiSleepMP.java @@ -10,7 +10,7 @@ import net.minecraft.network.play.client.C0BPacketEntityAction; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiSlider.java b/src/game/java/net/minecraft/client/gui/GuiSlider.java index 6f9b26f8..de8625ce 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSlider.java +++ b/src/game/java/net/minecraft/client/gui/GuiSlider.java @@ -10,7 +10,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiSlot.java b/src/game/java/net/minecraft/client/gui/GuiSlot.java index 895f440d..bacc4672 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSlot.java +++ b/src/game/java/net/minecraft/client/gui/GuiSlot.java @@ -22,7 +22,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiSpectator.java b/src/game/java/net/minecraft/client/gui/GuiSpectator.java index 38acffc9..a23e7cfb 100755 --- a/src/game/java/net/minecraft/client/gui/GuiSpectator.java +++ b/src/game/java/net/minecraft/client/gui/GuiSpectator.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiTextField.java b/src/game/java/net/minecraft/client/gui/GuiTextField.java index c691ff14..d6f64278 100755 --- a/src/game/java/net/minecraft/client/gui/GuiTextField.java +++ b/src/game/java/net/minecraft/client/gui/GuiTextField.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java b/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java index 245af26a..7cf6c8e1 100755 --- a/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java +++ b/src/game/java/net/minecraft/client/gui/GuiUtilRenderComponents.java @@ -16,7 +16,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java b/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java index 28688e8f..246f47b4 100755 --- a/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java +++ b/src/game/java/net/minecraft/client/gui/GuiVideoSettings.java @@ -16,7 +16,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiWinGame.java b/src/game/java/net/minecraft/client/gui/GuiWinGame.java index acc158d1..e8cad44a 100755 --- a/src/game/java/net/minecraft/client/gui/GuiWinGame.java +++ b/src/game/java/net/minecraft/client/gui/GuiWinGame.java @@ -30,7 +30,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiYesNo.java b/src/game/java/net/minecraft/client/gui/GuiYesNo.java index 4d061b05..2ee521c6 100755 --- a/src/game/java/net/minecraft/client/gui/GuiYesNo.java +++ b/src/game/java/net/minecraft/client/gui/GuiYesNo.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java b/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java index 9078709b..26500b45 100755 --- a/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java +++ b/src/game/java/net/minecraft/client/gui/GuiYesNoCallback.java @@ -6,7 +6,7 @@ package net.minecraft.client.gui; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/IProgressMeter.java b/src/game/java/net/minecraft/client/gui/IProgressMeter.java index 71b3c73d..10cad525 100755 --- a/src/game/java/net/minecraft/client/gui/IProgressMeter.java +++ b/src/game/java/net/minecraft/client/gui/IProgressMeter.java @@ -6,7 +6,7 @@ package net.minecraft.client.gui; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/MapItemRenderer.java b/src/game/java/net/minecraft/client/gui/MapItemRenderer.java index d70f8245..e8e3ac82 100755 --- a/src/game/java/net/minecraft/client/gui/MapItemRenderer.java +++ b/src/game/java/net/minecraft/client/gui/MapItemRenderer.java @@ -23,7 +23,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/ScaledResolution.java b/src/game/java/net/minecraft/client/gui/ScaledResolution.java index 0fd6bacd..709de89d 100755 --- a/src/game/java/net/minecraft/client/gui/ScaledResolution.java +++ b/src/game/java/net/minecraft/client/gui/ScaledResolution.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java b/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java index 687c959d..c7b4494a 100755 --- a/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java +++ b/src/game/java/net/minecraft/client/gui/ScreenChatOptions.java @@ -10,7 +10,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java b/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java index 68cacb10..9e0f9737 100755 --- a/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java +++ b/src/game/java/net/minecraft/client/gui/ServerListEntryNormal.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/ServerSelectionList.java b/src/game/java/net/minecraft/client/gui/ServerSelectionList.java index 4f834aba..8789ce82 100755 --- a/src/game/java/net/minecraft/client/gui/ServerSelectionList.java +++ b/src/game/java/net/minecraft/client/gui/ServerSelectionList.java @@ -17,7 +17,7 @@ import net.minecraft.client.resources.I18n; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java index 39e43df1..512f7e3c 100755 --- a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java +++ b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievement.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java index 68cbfbb2..a1984d3d 100755 --- a/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java +++ b/src/game/java/net/minecraft/client/gui/achievement/GuiAchievements.java @@ -32,7 +32,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java b/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java index 1927e5b5..4fa23861 100755 --- a/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java +++ b/src/game/java/net/minecraft/client/gui/achievement/GuiStats.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction; @@ -36,7 +37,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -665,7 +666,8 @@ public class GuiStats extends GuiScreen implements IProgressMeter { GuiStats.this.fontRendererObj.FONT_HEIGHT * 4); this.setShowSelectionBox(false); - for (EntityList.EntityEggInfo entitylist$entityegginfo : EntityList.entityEggs.values()) { + for (ObjectCursor entitylist$entityegginfo_ : EntityList.entityEggs.values()) { + EntityList.EntityEggInfo entitylist$entityegginfo = entitylist$entityegginfo_.value; if (GuiStats.this.field_146546_t.readStat(entitylist$entityegginfo.field_151512_d) > 0 || GuiStats.this.field_146546_t.readStat(entitylist$entityegginfo.field_151513_e) > 0) { this.field_148222_l.add(entitylist$entityegginfo); diff --git a/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java b/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java index c49f60ca..679472e6 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java +++ b/src/game/java/net/minecraft/client/gui/inventory/CreativeCrafting.java @@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java b/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java index 309a3133..1f2c09c6 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiBeacon.java @@ -28,7 +28,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java b/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java index def2bf84..e93933fb 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiBrewingStand.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java b/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java index dfffcb58..8284b328 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiChest.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java b/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java index 681f4c43..0142aba0 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiContainer.java @@ -29,7 +29,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java b/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java index 7aeb4517..4af8a5d0 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiContainerCreative.java @@ -3,8 +3,8 @@ package net.minecraft.client.gui.inventory; import java.io.IOException; import java.util.Iterator; import java.util.List; -import java.util.Map; +import com.carrotsearch.hppc.IntIntMap; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.Keyboard; @@ -43,7 +43,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -564,10 +564,9 @@ public class GuiContainerCreative extends InventoryEffectRenderer { this.mc.gameSettings.advancedItemTooltips); CreativeTabs creativetabs = itemstack.getItem().getCreativeTab(); if (creativetabs == null && itemstack.getItem() == Items.enchanted_book) { - Map map = EnchantmentHelper.getEnchantments(itemstack); + IntIntMap map = EnchantmentHelper.getEnchantments(itemstack); if (map.size() == 1) { - Enchantment enchantment = Enchantment - .getEnchantmentById(((Integer) map.keySet().iterator().next()).intValue()); + Enchantment enchantment = Enchantment.getEnchantmentById(map.keys().iterator().next().value); for (int m = 0; m < CreativeTabs.creativeTabArray.length; ++m) { CreativeTabs creativetabs1 = CreativeTabs.creativeTabArray[m]; diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java b/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java index 8dd7603a..36e27a48 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiCrafting.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java b/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java index 0370dd22..6ebee973 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiDispenser.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java b/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java index 9d48a8dc..5faed6c0 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiEditSign.java @@ -24,7 +24,7 @@ import net.minecraft.util.ChatComponentText; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java b/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java index de63db78..a8cdaf47 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiFurnace.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java b/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java index 50a23211..3e65ad32 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiInventory.java @@ -19,7 +19,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java b/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java index 4f9410f2..c6de4586 100755 --- a/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java +++ b/src/game/java/net/minecraft/client/gui/inventory/GuiScreenHorseInventory.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java b/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java index f4652f5a..c226ed43 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java +++ b/src/game/java/net/minecraft/client/gui/spectator/BaseSpectatorGroup.java @@ -15,7 +15,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java index d7141f40..75a402bf 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java +++ b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuObject.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java index 60ea26b9..08800104 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java +++ b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuRecipient.java @@ -6,7 +6,7 @@ package net.minecraft.client.gui.spectator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java index f90dc0d7..1b27baa1 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java +++ b/src/game/java/net/minecraft/client/gui/spectator/ISpectatorMenuView.java @@ -10,7 +10,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java b/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java index f1003e53..583d5bdd 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java +++ b/src/game/java/net/minecraft/client/gui/spectator/PlayerMenuObject.java @@ -14,7 +14,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java b/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java index 80dc37f8..80eb9ea0 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java +++ b/src/game/java/net/minecraft/client/gui/spectator/SpectatorMenu.java @@ -19,7 +19,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java b/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java index 8bbd8c94..b9341a4f 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java +++ b/src/game/java/net/minecraft/client/gui/spectator/categories/SpectatorDetails.java @@ -14,7 +14,7 @@ import net.minecraft.client.gui.spectator.SpectatorMenu; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java index 4e39cef8..5382040d 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java +++ b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToPlayer.java @@ -26,7 +26,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java index 80e38085..d4e6af39 100755 --- a/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java +++ b/src/game/java/net/minecraft/client/gui/spectator/categories/TeleportToTeam.java @@ -25,7 +25,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/main/GameConfiguration.java b/src/game/java/net/minecraft/client/main/GameConfiguration.java index 53ee71d3..13569349 100755 --- a/src/game/java/net/minecraft/client/main/GameConfiguration.java +++ b/src/game/java/net/minecraft/client/main/GameConfiguration.java @@ -8,7 +8,7 @@ import net.minecraft.util.Session; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/main/Main.java b/src/game/java/net/minecraft/client/main/Main.java index a38e704e..8fce2430 100755 --- a/src/game/java/net/minecraft/client/main/Main.java +++ b/src/game/java/net/minecraft/client/main/Main.java @@ -10,7 +10,7 @@ import net.minecraft.util.Session; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelArmorStand.java b/src/game/java/net/minecraft/client/model/ModelArmorStand.java index d2a0cc68..bfb6444d 100755 --- a/src/game/java/net/minecraft/client/model/ModelArmorStand.java +++ b/src/game/java/net/minecraft/client/model/ModelArmorStand.java @@ -10,7 +10,7 @@ import net.minecraft.entity.item.EntityArmorStand; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java b/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java index c5b9d3ec..a36e9b43 100755 --- a/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java +++ b/src/game/java/net/minecraft/client/model/ModelArmorStandArmor.java @@ -9,7 +9,7 @@ import net.minecraft.entity.item.EntityArmorStand; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBanner.java b/src/game/java/net/minecraft/client/model/ModelBanner.java index d17fcd99..425abb06 100755 --- a/src/game/java/net/minecraft/client/model/ModelBanner.java +++ b/src/game/java/net/minecraft/client/model/ModelBanner.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBase.java b/src/game/java/net/minecraft/client/model/ModelBase.java index 61473a1a..76b14c90 100755 --- a/src/game/java/net/minecraft/client/model/ModelBase.java +++ b/src/game/java/net/minecraft/client/model/ModelBase.java @@ -16,7 +16,7 @@ import net.minecraft.entity.EntityLivingBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBat.java b/src/game/java/net/minecraft/client/model/ModelBat.java index 031513bd..42da2010 100755 --- a/src/game/java/net/minecraft/client/model/ModelBat.java +++ b/src/game/java/net/minecraft/client/model/ModelBat.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBiped.java b/src/game/java/net/minecraft/client/model/ModelBiped.java index b3003e0c..53c9de8f 100755 --- a/src/game/java/net/minecraft/client/model/ModelBiped.java +++ b/src/game/java/net/minecraft/client/model/ModelBiped.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBlaze.java b/src/game/java/net/minecraft/client/model/ModelBlaze.java index 172b0adc..1e6a919d 100755 --- a/src/game/java/net/minecraft/client/model/ModelBlaze.java +++ b/src/game/java/net/minecraft/client/model/ModelBlaze.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBoat.java b/src/game/java/net/minecraft/client/model/ModelBoat.java index f0c65508..9a5c59a8 100755 --- a/src/game/java/net/minecraft/client/model/ModelBoat.java +++ b/src/game/java/net/minecraft/client/model/ModelBoat.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBook.java b/src/game/java/net/minecraft/client/model/ModelBook.java index 3b56158b..86e5d92a 100755 --- a/src/game/java/net/minecraft/client/model/ModelBook.java +++ b/src/game/java/net/minecraft/client/model/ModelBook.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelBox.java b/src/game/java/net/minecraft/client/model/ModelBox.java index 903ccd02..ea7d9875 100755 --- a/src/game/java/net/minecraft/client/model/ModelBox.java +++ b/src/game/java/net/minecraft/client/model/ModelBox.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelChest.java b/src/game/java/net/minecraft/client/model/ModelChest.java index 42d3662d..e617fe40 100755 --- a/src/game/java/net/minecraft/client/model/ModelChest.java +++ b/src/game/java/net/minecraft/client/model/ModelChest.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelChicken.java b/src/game/java/net/minecraft/client/model/ModelChicken.java index a564ae22..06daa9e8 100755 --- a/src/game/java/net/minecraft/client/model/ModelChicken.java +++ b/src/game/java/net/minecraft/client/model/ModelChicken.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelCow.java b/src/game/java/net/minecraft/client/model/ModelCow.java index 281d9b11..efa6a65c 100755 --- a/src/game/java/net/minecraft/client/model/ModelCow.java +++ b/src/game/java/net/minecraft/client/model/ModelCow.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelCreeper.java b/src/game/java/net/minecraft/client/model/ModelCreeper.java index 66cf52d1..cb2108b1 100755 --- a/src/game/java/net/minecraft/client/model/ModelCreeper.java +++ b/src/game/java/net/minecraft/client/model/ModelCreeper.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelDragon.java b/src/game/java/net/minecraft/client/model/ModelDragon.java index 23facaf3..186f8934 100755 --- a/src/game/java/net/minecraft/client/model/ModelDragon.java +++ b/src/game/java/net/minecraft/client/model/ModelDragon.java @@ -14,7 +14,7 @@ import net.minecraft.entity.boss.EntityDragon; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java b/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java index 314e7c1b..cbac9e5c 100755 --- a/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java +++ b/src/game/java/net/minecraft/client/model/ModelEnderCrystal.java @@ -9,7 +9,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelEnderMite.java b/src/game/java/net/minecraft/client/model/ModelEnderMite.java index e04b603c..32c1e77e 100755 --- a/src/game/java/net/minecraft/client/model/ModelEnderMite.java +++ b/src/game/java/net/minecraft/client/model/ModelEnderMite.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelEnderman.java b/src/game/java/net/minecraft/client/model/ModelEnderman.java index 8615635f..ff96feb4 100755 --- a/src/game/java/net/minecraft/client/model/ModelEnderman.java +++ b/src/game/java/net/minecraft/client/model/ModelEnderman.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelGhast.java b/src/game/java/net/minecraft/client/model/ModelGhast.java index 7bbd3794..fb7e418b 100755 --- a/src/game/java/net/minecraft/client/model/ModelGhast.java +++ b/src/game/java/net/minecraft/client/model/ModelGhast.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelGuardian.java b/src/game/java/net/minecraft/client/model/ModelGuardian.java index 33c47c23..c787ae87 100755 --- a/src/game/java/net/minecraft/client/model/ModelGuardian.java +++ b/src/game/java/net/minecraft/client/model/ModelGuardian.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelHorse.java b/src/game/java/net/minecraft/client/model/ModelHorse.java index 6de455d2..aae175eb 100755 --- a/src/game/java/net/minecraft/client/model/ModelHorse.java +++ b/src/game/java/net/minecraft/client/model/ModelHorse.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java b/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java index 1edf6f5d..7025e5b6 100755 --- a/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java +++ b/src/game/java/net/minecraft/client/model/ModelHumanoidHead.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelIronGolem.java b/src/game/java/net/minecraft/client/model/ModelIronGolem.java index 5b0ff19b..99e9814f 100755 --- a/src/game/java/net/minecraft/client/model/ModelIronGolem.java +++ b/src/game/java/net/minecraft/client/model/ModelIronGolem.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntityIronGolem; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelLargeChest.java b/src/game/java/net/minecraft/client/model/ModelLargeChest.java index 28f7ad88..609e4a6d 100755 --- a/src/game/java/net/minecraft/client/model/ModelLargeChest.java +++ b/src/game/java/net/minecraft/client/model/ModelLargeChest.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelLeashKnot.java b/src/game/java/net/minecraft/client/model/ModelLeashKnot.java index 93588791..53216a8a 100755 --- a/src/game/java/net/minecraft/client/model/ModelLeashKnot.java +++ b/src/game/java/net/minecraft/client/model/ModelLeashKnot.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelMagmaCube.java b/src/game/java/net/minecraft/client/model/ModelMagmaCube.java index cf58497c..643b6f04 100755 --- a/src/game/java/net/minecraft/client/model/ModelMagmaCube.java +++ b/src/game/java/net/minecraft/client/model/ModelMagmaCube.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntityMagmaCube; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelMinecart.java b/src/game/java/net/minecraft/client/model/ModelMinecart.java index 56bc0c6b..e329736f 100755 --- a/src/game/java/net/minecraft/client/model/ModelMinecart.java +++ b/src/game/java/net/minecraft/client/model/ModelMinecart.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelOcelot.java b/src/game/java/net/minecraft/client/model/ModelOcelot.java index 5a61d64d..7243a093 100755 --- a/src/game/java/net/minecraft/client/model/ModelOcelot.java +++ b/src/game/java/net/minecraft/client/model/ModelOcelot.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelPig.java b/src/game/java/net/minecraft/client/model/ModelPig.java index a2bc7636..0e5fab95 100755 --- a/src/game/java/net/minecraft/client/model/ModelPig.java +++ b/src/game/java/net/minecraft/client/model/ModelPig.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelPlayer.java b/src/game/java/net/minecraft/client/model/ModelPlayer.java index 05114c18..f9e5ec2a 100755 --- a/src/game/java/net/minecraft/client/model/ModelPlayer.java +++ b/src/game/java/net/minecraft/client/model/ModelPlayer.java @@ -11,7 +11,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelQuadruped.java b/src/game/java/net/minecraft/client/model/ModelQuadruped.java index 4547f03f..51f33377 100755 --- a/src/game/java/net/minecraft/client/model/ModelQuadruped.java +++ b/src/game/java/net/minecraft/client/model/ModelQuadruped.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelRabbit.java b/src/game/java/net/minecraft/client/model/ModelRabbit.java index 60ed61f1..210b954b 100755 --- a/src/game/java/net/minecraft/client/model/ModelRabbit.java +++ b/src/game/java/net/minecraft/client/model/ModelRabbit.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelRenderer.java b/src/game/java/net/minecraft/client/model/ModelRenderer.java index 7f9186fa..6e7ab52f 100755 --- a/src/game/java/net/minecraft/client/model/ModelRenderer.java +++ b/src/game/java/net/minecraft/client/model/ModelRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.client.renderer.Tessellator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSheep1.java b/src/game/java/net/minecraft/client/model/ModelSheep1.java index b0c7c196..3525f01b 100755 --- a/src/game/java/net/minecraft/client/model/ModelSheep1.java +++ b/src/game/java/net/minecraft/client/model/ModelSheep1.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntitySheep; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSheep2.java b/src/game/java/net/minecraft/client/model/ModelSheep2.java index 0cf5f3e1..1fede293 100755 --- a/src/game/java/net/minecraft/client/model/ModelSheep2.java +++ b/src/game/java/net/minecraft/client/model/ModelSheep2.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntitySheep; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSign.java b/src/game/java/net/minecraft/client/model/ModelSign.java index e9a0f53e..35404ca5 100755 --- a/src/game/java/net/minecraft/client/model/ModelSign.java +++ b/src/game/java/net/minecraft/client/model/ModelSign.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSilverfish.java b/src/game/java/net/minecraft/client/model/ModelSilverfish.java index fdcd93bc..4c570626 100755 --- a/src/game/java/net/minecraft/client/model/ModelSilverfish.java +++ b/src/game/java/net/minecraft/client/model/ModelSilverfish.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSkeleton.java b/src/game/java/net/minecraft/client/model/ModelSkeleton.java index 8328e837..89fb98e1 100755 --- a/src/game/java/net/minecraft/client/model/ModelSkeleton.java +++ b/src/game/java/net/minecraft/client/model/ModelSkeleton.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntitySkeleton; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java b/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java index 6d148bc3..168aa829 100755 --- a/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java +++ b/src/game/java/net/minecraft/client/model/ModelSkeletonHead.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSlime.java b/src/game/java/net/minecraft/client/model/ModelSlime.java index 85d7e988..6491797b 100755 --- a/src/game/java/net/minecraft/client/model/ModelSlime.java +++ b/src/game/java/net/minecraft/client/model/ModelSlime.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSnowMan.java b/src/game/java/net/minecraft/client/model/ModelSnowMan.java index c48a88dc..0beacea9 100755 --- a/src/game/java/net/minecraft/client/model/ModelSnowMan.java +++ b/src/game/java/net/minecraft/client/model/ModelSnowMan.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSpider.java b/src/game/java/net/minecraft/client/model/ModelSpider.java index b4d26dff..c1818628 100755 --- a/src/game/java/net/minecraft/client/model/ModelSpider.java +++ b/src/game/java/net/minecraft/client/model/ModelSpider.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelSquid.java b/src/game/java/net/minecraft/client/model/ModelSquid.java index c6f52fa9..b75480fe 100755 --- a/src/game/java/net/minecraft/client/model/ModelSquid.java +++ b/src/game/java/net/minecraft/client/model/ModelSquid.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelVillager.java b/src/game/java/net/minecraft/client/model/ModelVillager.java index 4c611ef7..4c204433 100755 --- a/src/game/java/net/minecraft/client/model/ModelVillager.java +++ b/src/game/java/net/minecraft/client/model/ModelVillager.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelWitch.java b/src/game/java/net/minecraft/client/model/ModelWitch.java index a2994663..535077be 100755 --- a/src/game/java/net/minecraft/client/model/ModelWitch.java +++ b/src/game/java/net/minecraft/client/model/ModelWitch.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelWither.java b/src/game/java/net/minecraft/client/model/ModelWither.java index 70ad069c..665942b5 100755 --- a/src/game/java/net/minecraft/client/model/ModelWither.java +++ b/src/game/java/net/minecraft/client/model/ModelWither.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelWolf.java b/src/game/java/net/minecraft/client/model/ModelWolf.java index b128317a..979953c4 100755 --- a/src/game/java/net/minecraft/client/model/ModelWolf.java +++ b/src/game/java/net/minecraft/client/model/ModelWolf.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelZombie.java b/src/game/java/net/minecraft/client/model/ModelZombie.java index 05c3dad9..79bd3002 100755 --- a/src/game/java/net/minecraft/client/model/ModelZombie.java +++ b/src/game/java/net/minecraft/client/model/ModelZombie.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/ModelZombieVillager.java b/src/game/java/net/minecraft/client/model/ModelZombieVillager.java index b52017c8..4ae0b981 100755 --- a/src/game/java/net/minecraft/client/model/ModelZombieVillager.java +++ b/src/game/java/net/minecraft/client/model/ModelZombieVillager.java @@ -9,7 +9,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/PositionTextureVertex.java b/src/game/java/net/minecraft/client/model/PositionTextureVertex.java index 290fcbd7..0dcde044 100755 --- a/src/game/java/net/minecraft/client/model/PositionTextureVertex.java +++ b/src/game/java/net/minecraft/client/model/PositionTextureVertex.java @@ -8,7 +8,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/TextureOffset.java b/src/game/java/net/minecraft/client/model/TextureOffset.java index 0882f274..b97dd54e 100755 --- a/src/game/java/net/minecraft/client/model/TextureOffset.java +++ b/src/game/java/net/minecraft/client/model/TextureOffset.java @@ -6,7 +6,7 @@ package net.minecraft.client.model; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/model/TexturedQuad.java b/src/game/java/net/minecraft/client/model/TexturedQuad.java index e9e14203..a2929a44 100755 --- a/src/game/java/net/minecraft/client/model/TexturedQuad.java +++ b/src/game/java/net/minecraft/client/model/TexturedQuad.java @@ -11,7 +11,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java b/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java index 32c6e90b..0ce9377b 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java +++ b/src/game/java/net/minecraft/client/multiplayer/ChunkProviderClient.java @@ -2,6 +2,8 @@ package net.minecraft.client.multiplayer; import java.util.List; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.EagRuntime; @@ -10,7 +12,6 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.minecraft.entity.EnumCreatureType; import net.minecraft.util.BlockPos; import net.minecraft.util.IProgressUpdate; -import net.minecraft.util.LongHashMap; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; @@ -24,7 +25,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -45,7 +46,7 @@ public class ChunkProviderClient implements IChunkProvider { * The mapping between ChunkCoordinates and Chunks that * ChunkProviderClient maintains. */ - private LongHashMap chunkMapping = new LongHashMap(); + private LongObjectMap chunkMapping = new LongObjectHashMap<>(); /**+ * This may have been intended to be an iterable version of all * currently loaded chunks (MultiplayerChunkCache), with @@ -87,7 +88,7 @@ public class ChunkProviderClient implements IChunkProvider { */ public Chunk loadChunk(int parInt1, int parInt2) { Chunk chunk = new Chunk(this.worldObj, parInt1, parInt2); - this.chunkMapping.add(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2), chunk); + this.chunkMapping.put(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2), chunk); this.chunkListing.add(chunk); chunk.setChunkLoaded(true); return chunk; @@ -99,7 +100,7 @@ public class ChunkProviderClient implements IChunkProvider { * chunk from the map seed and chunk seed */ public Chunk provideChunk(int i, int j) { - Chunk chunk = (Chunk) this.chunkMapping.getValueByKey(ChunkCoordIntPair.chunkXZ2Int(i, j)); + Chunk chunk = this.chunkMapping.get(ChunkCoordIntPair.chunkXZ2Int(i, j)); return chunk == null ? this.blankChunk : chunk; } @@ -160,7 +161,7 @@ public class ChunkProviderClient implements IChunkProvider { * Converts the instance data to a readable string. */ public String makeString() { - return "MultiplayerChunkCache: " + this.chunkMapping.getNumHashElements() + ", " + this.chunkListing.size(); + return "MultiplayerChunkCache: " + this.chunkMapping.size() + ", " + this.chunkListing.size(); } public List getPossibleCreatures(EnumCreatureType var1, BlockPos var2) { diff --git a/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java b/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java index 813c1247..53a0150e 100755 --- a/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java +++ b/src/game/java/net/minecraft/client/multiplayer/GuiConnecting.java @@ -35,7 +35,7 @@ import net.minecraft.util.ChatComponentText; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java b/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java index 73580bfb..223eae8d 100755 --- a/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java +++ b/src/game/java/net/minecraft/client/multiplayer/PlayerControllerMP.java @@ -40,7 +40,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java b/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java index e04405cf..acf4b785 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java +++ b/src/game/java/net/minecraft/client/multiplayer/ServerAddress.java @@ -6,7 +6,7 @@ package net.minecraft.client.multiplayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/multiplayer/ServerData.java b/src/game/java/net/minecraft/client/multiplayer/ServerData.java index 5be03f1f..ade783c4 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ServerData.java +++ b/src/game/java/net/minecraft/client/multiplayer/ServerData.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/multiplayer/ServerList.java b/src/game/java/net/minecraft/client/multiplayer/ServerList.java index 6487e00f..6889ce26 100755 --- a/src/game/java/net/minecraft/client/multiplayer/ServerList.java +++ b/src/game/java/net/minecraft/client/multiplayer/ServerList.java @@ -28,7 +28,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/multiplayer/WorldClient.java b/src/game/java/net/minecraft/client/multiplayer/WorldClient.java index 4eeb770c..377b3f81 100755 --- a/src/game/java/net/minecraft/client/multiplayer/WorldClient.java +++ b/src/game/java/net/minecraft/client/multiplayer/WorldClient.java @@ -4,6 +4,9 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import java.util.Set; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; +import com.carrotsearch.hppc.cursors.LongCursor; import com.google.common.collect.Sets; import net.minecraft.block.Block; @@ -25,7 +28,6 @@ import net.minecraft.util.BlockPos; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.World; import net.minecraft.world.WorldProvider; @@ -42,7 +44,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -72,7 +74,7 @@ public class WorldClient extends World { */ private final Set entitySpawnQueue = Sets.newHashSet(); private final Minecraft mc = Minecraft.getMinecraft(); - private final Set previousActiveChunkSet = Sets.newHashSet(); + private final LongSet previousActiveChunkSet = new LongHashSet(); public WorldClient(NetHandlerPlayClient parNetHandlerPlayClient, WorldSettings parWorldSettings, int parInt1, EnumDifficulty parEnumDifficulty) { @@ -130,20 +132,23 @@ public class WorldClient extends World { protected void updateBlocks() { super.updateBlocks(); - this.previousActiveChunkSet.retainAll(this.activeChunkSet); + this.previousActiveChunkSet.retainAll(this.activeChunkSet::contains); if (this.previousActiveChunkSet.size() == this.activeChunkSet.size()) { this.previousActiveChunkSet.clear(); } int i = 0; - for (ChunkCoordIntPair chunkcoordintpair : this.activeChunkSet) { - if (!this.previousActiveChunkSet.contains(chunkcoordintpair)) { - int j = chunkcoordintpair.chunkXPos * 16; - int k = chunkcoordintpair.chunkZPos * 16; - Chunk chunk = this.getChunkFromChunkCoords(chunkcoordintpair.chunkXPos, chunkcoordintpair.chunkZPos); + for (LongCursor chunkcoordintpair : this.activeChunkSet) { + long l = chunkcoordintpair.value; + if (!this.previousActiveChunkSet.contains(l)) { + int chunkXPos = (int) (l & 4294967295L); + int chunkZPos = (int) (l >>> 32); + int j = chunkXPos * 16; + int k = chunkZPos * 16; + Chunk chunk = this.getChunkFromChunkCoords(chunkXPos, chunkZPos); this.playMoodSoundAndCheckLight(j, k, chunk); - this.previousActiveChunkSet.add(chunkcoordintpair); + this.previousActiveChunkSet.add(l); ++i; if (i >= 10) { return; @@ -229,7 +234,7 @@ public class WorldClient extends World { this.entitySpawnQueue.add(parEntity); } - this.entitiesById.addKey(parInt1, parEntity); + this.entitiesById.put(parInt1, parEntity); } /**+ @@ -237,11 +242,11 @@ public class WorldClient extends World { * exist in this World. */ public Entity getEntityByID(int i) { - return (Entity) (i == this.mc.thePlayer.getEntityId() ? this.mc.thePlayer : super.getEntityByID(i)); + return i == this.mc.thePlayer.getEntityId() ? this.mc.thePlayer : super.getEntityByID(i); } public Entity removeEntityFromWorld(int parInt1) { - Entity entity = (Entity) this.entitiesById.removeObject(parInt1); + Entity entity = this.entitiesById.remove(parInt1); if (entity != null) { this.entityList.remove(entity); this.removeEntity(entity); diff --git a/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java b/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java index 3391ffe9..a96a6ae0 100755 --- a/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java +++ b/src/game/java/net/minecraft/client/network/NetHandlerPlayClient.java @@ -4,12 +4,12 @@ import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import net.lax1dude.eaglercraft.v1_8.ClientUUIDLoadingCache; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import com.carrotsearch.hppc.cursors.ObjectIntCursor; import com.google.common.collect.Maps; import net.lax1dude.eaglercraft.v1_8.netty.Unpooled; @@ -225,7 +225,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -1350,9 +1350,9 @@ public class NetHandlerPlayClient implements INetHandlerPlayClient { public void handleStatistics(S37PacketStatistics packetIn) { boolean flag = false; - for (Entry entry : packetIn.func_148974_c().entrySet()) { - StatBase statbase = (StatBase) entry.getKey(); - int i = ((Integer) entry.getValue()).intValue(); + for (ObjectIntCursor entry : packetIn.func_148974_c()) { + StatBase statbase = entry.key; + int i = entry.value; if (statbase.isAchievement() && i > 0) { if (this.field_147308_k && this.gameController.thePlayer.getStatFileWriter().readStat(statbase) == 0) { Achievement achievement = (Achievement) statbase; diff --git a/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java b/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java index 76af28a4..3fc927a7 100755 --- a/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java +++ b/src/game/java/net/minecraft/client/network/NetworkPlayerInfo.java @@ -16,7 +16,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/Barrier.java b/src/game/java/net/minecraft/client/particle/Barrier.java index 23d6441a..f80f91ff 100755 --- a/src/game/java/net/minecraft/client/particle/Barrier.java +++ b/src/game/java/net/minecraft/client/particle/Barrier.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EffectRenderer.java b/src/game/java/net/minecraft/client/particle/EffectRenderer.java index 66cf1ea1..a22c5081 100755 --- a/src/game/java/net/minecraft/client/particle/EffectRenderer.java +++ b/src/game/java/net/minecraft/client/particle/EffectRenderer.java @@ -4,16 +4,15 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.util.ArrayList; import java.util.List; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.minecraft.AcceleratedEffectRenderer; import net.lax1dude.eaglercraft.v1_8.minecraft.IAcceleratedParticleEngine; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU; import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; import net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer; @@ -44,7 +43,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -70,7 +69,7 @@ public class EffectRenderer { * RNG. */ private EaglercraftRandom rand = new EaglercraftRandom(); - private Map particleTypes = Maps.newHashMap(); + private IntObjectMap particleTypes = new IntObjectHashMap<>(); public static final AcceleratedEffectRenderer vanillaAcceleratedParticleRenderer = new AcceleratedEffectRenderer(); public IAcceleratedParticleEngine acceleratedParticleRenderer = null; @@ -142,7 +141,7 @@ public class EffectRenderer { } public void registerParticle(int id, IParticleFactory particleFactory) { - this.particleTypes.put(Integer.valueOf(id), particleFactory); + this.particleTypes.put(id, particleFactory); } public void emitParticleAtEntity(Entity entityIn, EnumParticleTypes particleTypes) { @@ -154,7 +153,7 @@ public class EffectRenderer { */ public EntityFX spawnEffectParticle(int particleId, double parDouble1, double parDouble2, double parDouble3, double parDouble4, double parDouble5, double parDouble6, int... parArrayOfInt) { - IParticleFactory iparticlefactory = (IParticleFactory) this.particleTypes.get(Integer.valueOf(particleId)); + IParticleFactory iparticlefactory = this.particleTypes.get(particleId); if (iparticlefactory != null) { EntityFX entityfx = iparticlefactory.getEntityFX(particleId, this.worldObj, parDouble1, parDouble2, parDouble3, parDouble4, parDouble5, parDouble6, parArrayOfInt); diff --git a/src/game/java/net/minecraft/client/particle/EntityAuraFX.java b/src/game/java/net/minecraft/client/particle/EntityAuraFX.java index f0d8ee4e..c7a01897 100755 --- a/src/game/java/net/minecraft/client/particle/EntityAuraFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityAuraFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java b/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java index 980c05bd..f2ac74bd 100755 --- a/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityBlockDustFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java b/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java index 9ccd85b7..56a3dd52 100755 --- a/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityBreakingFX.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java b/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java index 7da7f7f2..270b8a36 100755 --- a/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityBubbleFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityCloudFX.java b/src/game/java/net/minecraft/client/particle/EntityCloudFX.java index 45fe1da2..de460929 100755 --- a/src/game/java/net/minecraft/client/particle/EntityCloudFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityCloudFX.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java b/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java index 97505ffb..3ec584e8 100755 --- a/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java +++ b/src/game/java/net/minecraft/client/particle/EntityCrit2FX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityCritFX.java b/src/game/java/net/minecraft/client/particle/EntityCritFX.java index c4a3032f..d91c8a1c 100755 --- a/src/game/java/net/minecraft/client/particle/EntityCritFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityCritFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java b/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java index fb285bce..4297c79a 100755 --- a/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityDiggingFX.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java b/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java index 87ede835..bb26a3e6 100755 --- a/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityDropParticleFX.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java b/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java index 2688d220..e9ea1afd 100755 --- a/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityEnchantmentTableParticleFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java b/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java index 72db7e8b..34073c5f 100755 --- a/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityExplodeFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityFX.java b/src/game/java/net/minecraft/client/particle/EntityFX.java index 0e55c001..1461a537 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFX.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityFirework.java b/src/game/java/net/minecraft/client/particle/EntityFirework.java index f056d5d4..cf34a400 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFirework.java +++ b/src/game/java/net/minecraft/client/particle/EntityFirework.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java b/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java index 306c4f90..0ad582ce 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFishWakeFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityFlameFX.java b/src/game/java/net/minecraft/client/particle/EntityFlameFX.java index 25211987..6c43fe80 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFlameFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFlameFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java b/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java index 47cf71ca..2b67f7b5 100755 --- a/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityFootStepFX.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityHeartFX.java b/src/game/java/net/minecraft/client/particle/EntityHeartFX.java index 36904ba8..0b05425d 100755 --- a/src/game/java/net/minecraft/client/particle/EntityHeartFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityHeartFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java b/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java index da950891..d68e60f6 100755 --- a/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityHugeExplodeFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java b/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java index 5f2a9a09..73556ff9 100755 --- a/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityLargeExplodeFX.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityLavaFX.java b/src/game/java/net/minecraft/client/particle/EntityLavaFX.java index 8609567c..934ea3dd 100755 --- a/src/game/java/net/minecraft/client/particle/EntityLavaFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityLavaFX.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityNoteFX.java b/src/game/java/net/minecraft/client/particle/EntityNoteFX.java index f0c08249..39f56cbc 100755 --- a/src/game/java/net/minecraft/client/particle/EntityNoteFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityNoteFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java b/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java index 7a137b13..7aadb0a2 100755 --- a/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java +++ b/src/game/java/net/minecraft/client/particle/EntityParticleEmitter.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityPickupFX.java b/src/game/java/net/minecraft/client/particle/EntityPickupFX.java index 1ba2ca51..e3a9fee1 100755 --- a/src/game/java/net/minecraft/client/particle/EntityPickupFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityPickupFX.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityPortalFX.java b/src/game/java/net/minecraft/client/particle/EntityPortalFX.java index 2ba4f697..9fdee8a2 100755 --- a/src/game/java/net/minecraft/client/particle/EntityPortalFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityPortalFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityRainFX.java b/src/game/java/net/minecraft/client/particle/EntityRainFX.java index fb7d561b..b3c3f679 100755 --- a/src/game/java/net/minecraft/client/particle/EntityRainFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityRainFX.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntityReddustFX.java b/src/game/java/net/minecraft/client/particle/EntityReddustFX.java index f4c946b1..04c80907 100755 --- a/src/game/java/net/minecraft/client/particle/EntityReddustFX.java +++ b/src/game/java/net/minecraft/client/particle/EntityReddustFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java b/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java index b4469230..e8a56258 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySmokeFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java b/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java index 7ee48ae4..51bf5e4b 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySnowShovelFX.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java b/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java index ced40db3..d108bdaf 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySpellParticleFX.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntitySplashFX.java b/src/game/java/net/minecraft/client/particle/EntitySplashFX.java index b37b558b..099b86b3 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySplashFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySplashFX.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java b/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java index d7ca15ec..9ff82ce6 100755 --- a/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java +++ b/src/game/java/net/minecraft/client/particle/EntitySuspendFX.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/IParticleFactory.java b/src/game/java/net/minecraft/client/particle/IParticleFactory.java index f5c34ccf..61bb595d 100755 --- a/src/game/java/net/minecraft/client/particle/IParticleFactory.java +++ b/src/game/java/net/minecraft/client/particle/IParticleFactory.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/particle/MobAppearance.java b/src/game/java/net/minecraft/client/particle/MobAppearance.java index f41648fe..3ba31f60 100755 --- a/src/game/java/net/minecraft/client/particle/MobAppearance.java +++ b/src/game/java/net/minecraft/client/particle/MobAppearance.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java b/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java index 492bfed5..4dd99c83 100755 --- a/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java +++ b/src/game/java/net/minecraft/client/player/inventory/ContainerLocalMenu.java @@ -1,9 +1,7 @@ package net.minecraft.client.player.inventory; -import java.util.Map; - -import com.google.common.collect.Maps; - +import com.carrotsearch.hppc.IntIntHashMap; +import com.carrotsearch.hppc.IntIntMap; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.Container; @@ -18,7 +16,7 @@ import net.minecraft.world.LockCode; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -34,7 +32,7 @@ import net.minecraft.world.LockCode; */ public class ContainerLocalMenu extends InventoryBasic implements ILockableContainer { private String guiID; - private Map field_174895_b = Maps.newHashMap(); + private IntIntMap field_174895_b = new IntIntHashMap(); public ContainerLocalMenu(String id, IChatComponent title, int slotCount) { super(title, slotCount); @@ -42,13 +40,11 @@ public class ContainerLocalMenu extends InventoryBasic implements ILockableConta } public int getField(int i) { - return this.field_174895_b.containsKey(Integer.valueOf(i)) - ? ((Integer) this.field_174895_b.get(Integer.valueOf(i))).intValue() - : 0; + return this.field_174895_b.getOrDefault(i, 0); } public void setField(int i, int j) { - this.field_174895_b.put(Integer.valueOf(i), Integer.valueOf(j)); + this.field_174895_b.put(i, j); } public int getFieldCount() { diff --git a/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java b/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java index 80798e97..38e07c89 100755 --- a/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java +++ b/src/game/java/net/minecraft/client/player/inventory/LocalBlockIntercommunication.java @@ -12,7 +12,7 @@ import net.minecraft.world.IInteractionObject; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java b/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java index 3dbffbd4..54a36ad5 100755 --- a/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java +++ b/src/game/java/net/minecraft/client/renderer/ActiveRenderInfo.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java b/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java index 4f010ac3..d3bd7963 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/BlockFluidRenderer.java @@ -22,7 +22,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java b/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java index 17e4d2e4..59e28721 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/BlockModelRenderer.java @@ -30,7 +30,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java b/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java index 7fdd1e77..4642280d 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java +++ b/src/game/java/net/minecraft/client/renderer/BlockModelShapes.java @@ -65,7 +65,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java b/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java index 32062476..167028a7 100755 --- a/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java +++ b/src/game/java/net/minecraft/client/renderer/BlockRendererDispatcher.java @@ -23,7 +23,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/ChestRenderer.java b/src/game/java/net/minecraft/client/renderer/ChestRenderer.java index 4a2d4036..ef02766c 100755 --- a/src/game/java/net/minecraft/client/renderer/ChestRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/ChestRenderer.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java b/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java index fe70e7e3..bce02f9c 100755 --- a/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java +++ b/src/game/java/net/minecraft/client/renderer/ChunkRenderContainer.java @@ -18,7 +18,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java b/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java index 10db86d6..94517046 100755 --- a/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java +++ b/src/game/java/net/minecraft/client/renderer/DestroyBlockProgress.java @@ -8,7 +8,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/EntityRenderer.java b/src/game/java/net/minecraft/client/renderer/EntityRenderer.java index 04b40a5a..b1112f72 100755 --- a/src/game/java/net/minecraft/client/renderer/EntityRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/EntityRenderer.java @@ -97,7 +97,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -1928,7 +1928,7 @@ public class EntityRenderer implements IResourceManagerReloadListener { // System.out.println(builder.toString()); float waveTimer = (float) ((EagRuntime.steadyTimeMillis() % 600000l) * 0.001); - DeferredStateManager.setWaterWindOffset(0.0f, 0.0f, waveTimer, waveTimer); + DeferredStateManager.setWaterWindOffset(waveTimer * 0.25f, waveTimer * 0.13f, waveTimer * 1.45f, waveTimer); float blockWaveDistX = (float) (d0 - blockWaveOffsetX); float blockWaveDistY = (float) (d1 - blockWaveOffsetY); @@ -2563,7 +2563,7 @@ public class EntityRenderer implements IResourceManagerReloadListener { + mc.theWorld.getThunderStrength(partialTicks) * 5.0f; ds *= MathHelper.clamp_float(6.0f - DeferredStateManager.getSunHeight() * 17.0f, 1.0f, 3.0f); if (conf.is_rendering_lightShafts) { - ds *= Math.max(2.0f - Math.abs(DeferredStateManager.getSunHeight()) * 5.0f, 1.0f); + ds *= Math.max(2.5f - Math.abs(DeferredStateManager.getSunHeight()) * 5.0f, 2.5f); } DeferredStateManager.enableFogExp(ds, true, 1.0f, 1.0f, 1.0f, 1.0f, ff, ff, ff, 1.0f); } @@ -2661,6 +2661,7 @@ public class EntityRenderer implements IResourceManagerReloadListener { for (int i = 0, l = lst.size(); i < l; ++i) { lst.get(i).draw(ShadersRenderPassFuture.PassType.MAIN); } + DeferredStateManager.forwardCallbackGBuffer.reset(); GlStateManager.matrixMode(GL_PROJECTION); GlStateManager.popMatrix(); GlStateManager.matrixMode(GL_MODELVIEW); diff --git a/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java b/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java index 2717926d..e548cf5a 100755 --- a/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java +++ b/src/game/java/net/minecraft/client/renderer/EnumFaceDirection.java @@ -8,7 +8,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/GLAllocation.java b/src/game/java/net/minecraft/client/renderer/GLAllocation.java index 04ac9489..bbfbfb19 100755 --- a/src/game/java/net/minecraft/client/renderer/GLAllocation.java +++ b/src/game/java/net/minecraft/client/renderer/GLAllocation.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/IImageBuffer.java b/src/game/java/net/minecraft/client/renderer/IImageBuffer.java index b0f39a48..9ef18958 100755 --- a/src/game/java/net/minecraft/client/renderer/IImageBuffer.java +++ b/src/game/java/net/minecraft/client/renderer/IImageBuffer.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ImageData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java b/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java index 971e9ea5..45038ac1 100755 --- a/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java +++ b/src/game/java/net/minecraft/client/renderer/ImageBufferDownload.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ImageData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java b/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java index 34a862dc..217010e5 100755 --- a/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/InventoryEffectRenderer.java @@ -1,6 +1,7 @@ package net.minecraft.client.renderer; -import java.util.Collection; +import com.carrotsearch.hppc.ObjectContainer; +import com.carrotsearch.hppc.cursors.ObjectCursor; import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; import net.minecraft.client.gui.inventory.GuiContainer; @@ -15,7 +16,7 @@ import net.minecraft.potion.PotionEffect; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -76,7 +77,7 @@ public abstract class InventoryEffectRenderer extends GuiContainer { int i = this.guiLeft - 124; int j = this.guiTop; boolean flag = true; - Collection collection = this.mc.thePlayer.getActivePotionEffects(); + ObjectContainer collection = this.mc.thePlayer.getActivePotionEffects(); if (!collection.isEmpty()) { GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableLighting(); @@ -86,7 +87,8 @@ public abstract class InventoryEffectRenderer extends GuiContainer { k = 132 / (collection.size() - 1); } - for (PotionEffect potioneffect : this.mc.thePlayer.getActivePotionEffects()) { + for (ObjectCursor potioneffect_ : collection) { + PotionEffect potioneffect = potioneffect_.value; Potion potion = Potion.potionTypes[potioneffect.getPotionID()]; GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); this.mc.getTextureManager().bindTexture(inventoryBackground); diff --git a/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java b/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java index 525fea0b..78fd4bd2 100755 --- a/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java +++ b/src/game/java/net/minecraft/client/renderer/ItemMeshDefinition.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java b/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java index 7d29771f..82d853e9 100755 --- a/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java +++ b/src/game/java/net/minecraft/client/renderer/ItemModelMesher.java @@ -1,8 +1,9 @@ package net.minecraft.client.renderer; import java.util.Map; -import java.util.Map.Entry; - +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.cursors.IntObjectCursor; import com.google.common.collect.Maps; import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite; @@ -18,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -33,8 +34,8 @@ import net.minecraft.item.ItemStack; * */ public class ItemModelMesher { - private final Map simpleShapes = Maps.newHashMap(); - private final Map simpleShapesCache = Maps.newHashMap(); + private final IntObjectMap simpleShapes = new IntObjectHashMap<>(); + private final IntObjectMap simpleShapesCache = new IntObjectHashMap<>(); private final Map shapers = Maps.newHashMap(); private final ModelManager modelManager; @@ -54,7 +55,7 @@ public class ItemModelMesher { Item item = stack.getItem(); IBakedModel ibakedmodel = this.getItemModel(item, this.getMetadata(stack)); if (ibakedmodel == null) { - ItemMeshDefinition itemmeshdefinition = (ItemMeshDefinition) this.shapers.get(item); + ItemMeshDefinition itemmeshdefinition = this.shapers.get(item); if (itemmeshdefinition != null) { ibakedmodel = this.modelManager.getModel(itemmeshdefinition.getModelLocation(stack)); } @@ -72,7 +73,7 @@ public class ItemModelMesher { } protected IBakedModel getItemModel(Item item, int meta) { - return (IBakedModel) this.simpleShapesCache.get(Integer.valueOf(this.getIndex(item, meta))); + return this.simpleShapesCache.get(this.getIndex(item, meta)); } private int getIndex(Item item, int meta) { @@ -80,8 +81,8 @@ public class ItemModelMesher { } public void register(Item item, int meta, ModelResourceLocation location) { - this.simpleShapes.put(Integer.valueOf(this.getIndex(item, meta)), location); - this.simpleShapesCache.put(Integer.valueOf(this.getIndex(item, meta)), this.modelManager.getModel(location)); + this.simpleShapes.put(this.getIndex(item, meta), location); + this.simpleShapesCache.put(this.getIndex(item, meta), this.modelManager.getModel(location)); } public void register(Item item, ItemMeshDefinition definition) { @@ -95,10 +96,8 @@ public class ItemModelMesher { public void rebuildCache() { this.simpleShapesCache.clear(); - for (Entry entry : this.simpleShapes.entrySet()) { - this.simpleShapesCache.put((Integer) entry.getKey(), - this.modelManager.getModel((ModelResourceLocation) entry.getValue())); + for (IntObjectCursor entry : this.simpleShapes) { + this.simpleShapesCache.put(entry.key, this.modelManager.getModel(entry.value)); } - } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/client/renderer/ItemRenderer.java b/src/game/java/net/minecraft/client/renderer/ItemRenderer.java index 101f61e3..a15f38d8 100755 --- a/src/game/java/net/minecraft/client/renderer/ItemRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/ItemRenderer.java @@ -37,7 +37,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -193,7 +193,7 @@ public class ItemRenderer { this.mc.getTextureManager().bindTexture(RES_MAP_BACKGROUND); Tessellator tessellator = Tessellator.getInstance(); WorldRenderer worldrenderer = tessellator.getWorldRenderer(); - EaglercraftGPU.glNormal3f(0.0F, 0.0F, -1.0F); + EaglercraftGPU.glNormal3f(0.0F, 0.0F, 1.0F); worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); worldrenderer.pos(-7.0D, 135.0D, 0.0D).tex(0.0D, 1.0D).endVertex(); worldrenderer.pos(135.0D, 135.0D, 0.0D).tex(1.0D, 1.0D).endVertex(); diff --git a/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java b/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java index 8736fc03..6141b1a4 100755 --- a/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java +++ b/src/game/java/net/minecraft/client/renderer/RegionRenderCache.java @@ -9,6 +9,7 @@ import net.minecraft.util.BlockPos; import net.minecraft.util.Vec3i; import net.minecraft.world.ChunkCache; import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.chunk.Chunk; /**+ @@ -17,7 +18,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -34,16 +35,19 @@ import net.minecraft.world.chunk.Chunk; public class RegionRenderCache extends ChunkCache { private final IBlockState DEFAULT_STATE = Blocks.air.getDefaultState(); private final BlockPos position; - private int[] combinedLights; - private IBlockState[] blockStates; + private final BlockPos tmpStupid = new BlockPos(); + private static final int[] combinedLights = new int[8000]; + private static final IBlockState[] blockStates = new IBlockState[8000]; + private static final int[] biomeColors = new int[1200]; + private static final int[] biomeColorsBlended = new int[768]; public RegionRenderCache(World worldIn, BlockPos posFromIn, BlockPos posToIn, int subIn) { super(worldIn, posFromIn, posToIn, subIn); this.position = posFromIn.subtract(new Vec3i(subIn, subIn, subIn)); - boolean flag = true; - this.combinedLights = new int[8000]; - Arrays.fill(this.combinedLights, -1); - this.blockStates = new IBlockState[8000]; + Arrays.fill(combinedLights, -1); + Arrays.fill(blockStates, null); + Arrays.fill(biomeColors, 0); + Arrays.fill(biomeColorsBlended, 0); } public TileEntity getTileEntity(BlockPos blockpos) { @@ -54,10 +58,10 @@ public class RegionRenderCache extends ChunkCache { public int getCombinedLight(BlockPos blockpos, int i) { int j = this.getPositionIndex(blockpos); - int k = this.combinedLights[j]; + int k = combinedLights[j]; if (k == -1) { k = super.getCombinedLight(blockpos, i); - this.combinedLights[j] = k; + combinedLights[j] = k; } return k; @@ -65,10 +69,10 @@ public class RegionRenderCache extends ChunkCache { public IBlockState getBlockState(BlockPos blockpos) { int i = this.getPositionIndex(blockpos); - IBlockState iblockstate = this.blockStates[i]; + IBlockState iblockstate = blockStates[i]; if (iblockstate == null) { iblockstate = this.getBlockStateRaw(blockpos); - this.blockStates[i] = iblockstate; + blockStates[i] = iblockstate; } return iblockstate; @@ -79,15 +83,29 @@ public class RegionRenderCache extends ChunkCache { */ public IBlockState getBlockStateFaster(BlockPos blockpos) { int i = this.getPositionIndexFaster(blockpos); - IBlockState iblockstate = this.blockStates[i]; + IBlockState iblockstate = blockStates[i]; if (iblockstate == null) { iblockstate = this.getBlockStateRawFaster(blockpos); - this.blockStates[i] = iblockstate; + blockStates[i] = iblockstate; } return iblockstate; } + /** + * only use with a regular "net.minecraft.util.BlockPos"! + */ + public int getBiomeColorForCoords(BlockPos blockpos, int colorIndex) { + int i = this.getPositionIndex16Faster(blockpos); + i += colorIndex * 256; + int j = biomeColorsBlended[i]; + if (j == 0) { + j = getBiomeColorBlended(blockpos, colorIndex); + biomeColorsBlended[i] = j; + } + return j; + } + private IBlockState getBlockStateRaw(BlockPos pos) { if (pos.getY() >= 0 && pos.getY() < 256) { int i = (pos.getX() >> 4) - this.chunkX; @@ -111,6 +129,59 @@ public class RegionRenderCache extends ChunkCache { } } + private int getBiomeColorBlended(BlockPos blockpos, int colorIndex) { + BlockPos blockpos2 = tmpStupid; + blockpos2.y = blockpos.y; + int rad = 1; + int xmin = blockpos.x - rad; + int zmin = blockpos.z - rad; + int xmax = blockpos.x + rad; + int zmax = blockpos.z + rad; + int r = 0; + int g = 0; + int b = 0; + int rgb; + for (int x = xmin; x <= xmax; ++x) { + for (int z = zmin; z <= zmax; ++z) { + blockpos2.x = x; + blockpos2.z = z; + rgb = getBiomeColorRaw(blockpos2, colorIndex); + r += (rgb >> 16) & 0xFF; + g += (rgb >> 8) & 0xFF; + b += rgb & 0xFF; + } + } + rad = 1 + rad * 2; + rad *= rad; + return 0xFF000000 | ((r / rad) << 16) | ((g / rad) << 8) | (b / rad); + } + + private int getBiomeColorRaw(BlockPos blockpos, int colorIndex) { + int i = getPositionIndex20Faster(blockpos); + i += colorIndex * 400; + int j = biomeColors[i]; + BiomeGenBase biome; + int ii, jj; + if (j == 0) { + if (blockpos.y >= 0 && blockpos.y < 256) { + ii = (blockpos.x >> 4) - this.chunkX; + jj = (blockpos.z >> 4) - this.chunkZ; + biome = this.chunkArray[ii][jj].getBiome(blockpos, worldObj.getWorldChunkManager()); + if (colorIndex == 0) { + j = biome.getGrassColorAtPos(blockpos); + } else if (colorIndex == 1) { + j = biome.getFoliageColorAtPos(blockpos); + } else { + j = biome.waterColorMultiplier; + } + } else { + j = 0xFFFFFFFF; + } + biomeColors[i] = j; + } + return j; + } + private int getPositionIndex(BlockPos parBlockPos) { int i = parBlockPos.getX() - this.position.getX(); int j = parBlockPos.getY() - this.position.getY(); @@ -127,4 +198,19 @@ public class RegionRenderCache extends ChunkCache { int k = parBlockPos.z - this.position.z; return i * 400 + k * 20 + j; } + + /** + * only use with a regular "net.minecraft.util.BlockPos"! + */ + private int getPositionIndex16Faster(BlockPos parBlockPos) { + int i = parBlockPos.x - this.position.x - 2; + int k = parBlockPos.z - this.position.z - 2; + return i * 16 + k; + } + + private int getPositionIndex20Faster(BlockPos parBlockPos) { + int i = parBlockPos.x - this.position.x; + int k = parBlockPos.z - this.position.z; + return i * 20 + k; + } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java b/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java index f758d159..ec3ab628 100755 --- a/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java +++ b/src/game/java/net/minecraft/client/renderer/RegionRenderCacheBuilder.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/RenderGlobal.java b/src/game/java/net/minecraft/client/renderer/RenderGlobal.java index 90e0a698..a6c19d43 100755 --- a/src/game/java/net/minecraft/client/renderer/RenderGlobal.java +++ b/src/game/java/net/minecraft/client/renderer/RenderGlobal.java @@ -104,7 +104,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/RenderHelper.java b/src/game/java/net/minecraft/client/renderer/RenderHelper.java index 2a1800da..47fe4f9b 100755 --- a/src/game/java/net/minecraft/client/renderer/RenderHelper.java +++ b/src/game/java/net/minecraft/client/renderer/RenderHelper.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/RenderList.java b/src/game/java/net/minecraft/client/renderer/RenderList.java index 7d9d4e32..d1376d96 100755 --- a/src/game/java/net/minecraft/client/renderer/RenderList.java +++ b/src/game/java/net/minecraft/client/renderer/RenderList.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/StitcherException.java b/src/game/java/net/minecraft/client/renderer/StitcherException.java index b0f2e444..6d21c8af 100755 --- a/src/game/java/net/minecraft/client/renderer/StitcherException.java +++ b/src/game/java/net/minecraft/client/renderer/StitcherException.java @@ -8,7 +8,7 @@ import net.minecraft.client.renderer.texture.Stitcher; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/Tessellator.java b/src/game/java/net/minecraft/client/renderer/Tessellator.java index 191311c3..6a607576 100755 --- a/src/game/java/net/minecraft/client/renderer/Tessellator.java +++ b/src/game/java/net/minecraft/client/renderer/Tessellator.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.WorldVertexBufferUploader; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/ViewFrustum.java b/src/game/java/net/minecraft/client/renderer/ViewFrustum.java index dcd529ce..bb1f6983 100755 --- a/src/game/java/net/minecraft/client/renderer/ViewFrustum.java +++ b/src/game/java/net/minecraft/client/renderer/ViewFrustum.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java b/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java index d5226146..05aab3ab 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BakedQuad.java @@ -8,7 +8,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java index 498cede9..61d0696f 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockFaceUV.java @@ -12,7 +12,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeDeserializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java index 242db3d4..f156340c 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockPart.java @@ -22,7 +22,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java index c945f20b..c299ef8e 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartFace.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java index 11972b0f..fc2b970a 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BlockPartRotation.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java b/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java index 46d6dc23..9256a2d1 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/BreakingFour.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.minecraft.EaglerTextureAtlasSprite; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java b/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java index 28a1387a..edd2c385 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/FaceBakery.java @@ -18,7 +18,7 @@ import net.minecraft.util.Vec3i; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java b/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java index 2a6e06d0..ef0d8ba5 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java b/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java index 790e8c83..a8d39aa3 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ItemModelGenerator.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java b/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java index dfc10aa1..258e06c7 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java index 5e0f330e..83677fd3 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlock.java @@ -24,7 +24,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java index 2ef74f4d..68f51dac 100755 --- a/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java +++ b/src/game/java/net/minecraft/client/renderer/block/model/ModelBlockDefinition.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java b/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java index ada6e6b9..0dfd2b12 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/BlockStateMapper.java @@ -19,7 +19,7 @@ import net.minecraft.client.resources.model.ModelResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java b/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java index 396d62e3..bb74f3ed 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/DefaultStateMapper.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java b/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java index 0058edae..4e2af2ef 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/IStateMapper.java @@ -12,7 +12,7 @@ import net.minecraft.client.resources.model.ModelResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java index 95148123..ec3c53cc 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMap.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java index 0157f33a..1665c3dd 100755 --- a/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java +++ b/src/game/java/net/minecraft/client/renderer/block/statemap/StateMapperBase.java @@ -16,7 +16,7 @@ import net.minecraft.client.resources.model.ModelResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java b/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java index dab798c2..1250cdd8 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator.java @@ -14,7 +14,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java b/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java index ced087ff..06e6654a 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ChunkRenderWorker.java @@ -15,7 +15,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java b/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java index 19e07b1c..85bb0ff5 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/CompiledChunk.java @@ -16,7 +16,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java b/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java index 3451a15e..0554c0a5 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/IRenderChunkFactory.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java b/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java index ac5180af..5cd218a0 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ListChunkFactory.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java b/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java index 7c85cd3e..23369a00 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/ListedRenderChunk.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java b/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java index fabb56d9..05fb6b6e 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/RenderChunk.java @@ -1,7 +1,5 @@ package net.minecraft.client.renderer.chunk; -import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; - import java.util.EnumMap; import java.util.HashSet; import java.util.Set; @@ -9,7 +7,6 @@ import java.util.Set; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; 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; @@ -36,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -63,7 +60,6 @@ public class RenderChunk { private ChunkCompileTaskGenerator compileTask = null; private final Set field_181056_j = Sets.newHashSet(); private final int index; - private final float[] modelviewMatrix = new float[16]; public AxisAlignedBB boundingBox; private int frameIndex = -1; private boolean needsUpdate = true; @@ -103,8 +99,6 @@ public class RenderChunk { for (int i = 0; i < facings.length; ++i) { this.field_181702_p.put(facings[i], pos.offset(facings[i], 16)); } - - this.initModelviewMatrix(); } public void resortTransparency(float x, float y, float z, ChunkCompileTaskGenerator generator) { @@ -272,21 +266,6 @@ public class RenderChunk { worldRendererIn.finishDrawing(); } - private void initModelviewMatrix() { - GlStateManager.pushMatrix(); - GlStateManager.loadIdentity(); - float f = 1.000001F; - GlStateManager.translate(-8.0F, -8.0F, -8.0F); - GlStateManager.scale(f, f, f); - GlStateManager.translate(8.0F, 8.0F, 8.0F); - GlStateManager.getFloat(GL_MODELVIEW_MATRIX, this.modelviewMatrix); - GlStateManager.popMatrix(); - } - - public void multModelviewMatrix() { - GlStateManager.multMatrix(this.modelviewMatrix); - } - public CompiledChunk getCompiledChunk() { return this.compiledChunk; } diff --git a/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java b/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java index b6a0f00a..22937ea2 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/SetVisibility.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java b/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java index a65bad52..48ccf81e 100755 --- a/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java +++ b/src/game/java/net/minecraft/client/renderer/chunk/VisGraph.java @@ -17,7 +17,7 @@ import net.minecraft.util.IntegerCache; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java index 8a422b55..9f51f9f2 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java +++ b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelper.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.culling; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java index 869ed429..07a48355 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java +++ b/src/game/java/net/minecraft/client/renderer/culling/ClippingHelperImpl.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/culling/Frustum.java b/src/game/java/net/minecraft/client/renderer/culling/Frustum.java index 4677c9a9..af42994d 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/Frustum.java +++ b/src/game/java/net/minecraft/client/renderer/culling/Frustum.java @@ -8,7 +8,7 @@ import net.minecraft.util.AxisAlignedBB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/culling/ICamera.java b/src/game/java/net/minecraft/client/renderer/culling/ICamera.java index 05029c24..b042cbd7 100755 --- a/src/game/java/net/minecraft/client/renderer/culling/ICamera.java +++ b/src/game/java/net/minecraft/client/renderer/culling/ICamera.java @@ -8,7 +8,7 @@ import net.minecraft.util.AxisAlignedBB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java b/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java index e0165299..18fdc2bf 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/entity/ArmorStandRenderer.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/Render.java b/src/game/java/net/minecraft/client/renderer/entity/Render.java index ed72da15..26848e50 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/Render.java +++ b/src/game/java/net/minecraft/client/renderer/entity/Render.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java b/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java index dea483ff..217f6639 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderArrow.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java index de47b45a..52df3d0c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBat.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java index 2e10a1eb..9149a91f 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBiped.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java index 209c1fcf..a9ee2eff 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBlaze.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java b/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java index 3a24dccb..26f95235 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderBoat.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java b/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java index 73714ead..05095356 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderCaveSpider.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java b/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java index 46d64266..edaee657 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderChicken.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java b/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java index 1c8f4fc1..f819782c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderCow.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java b/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java index 80b52ada..2c094400 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderCreeper.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java b/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java index 4b48981d..c0254d76 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderDragon.java @@ -22,7 +22,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java index 774c731d..82468296 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEnderman.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java index 50a75907..73662b36 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEndermite.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java index 23e95203..57d89bf6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEntity.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java b/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java index 4cf405d1..e7464425 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderEntityItem.java @@ -21,7 +21,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java b/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java index 313e2135..5121efdf 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderFallingBlock.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java b/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java index 09113405..9b7b4d6d 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderFireball.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java b/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java index 4476f969..ea77184c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderFish.java @@ -16,7 +16,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java b/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java index 714e6486..64b32362 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderGhast.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java b/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java index bc353b06..f1793129 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderGiantZombie.java @@ -14,7 +14,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java b/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java index 28c29606..085a13ee 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderGuardian.java @@ -22,7 +22,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java b/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java index 64f2384b..6e936509 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderHorse.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java b/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java index 4fb6c90e..2590f782 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderIronGolem.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java b/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java index 715a8d04..ab048805 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderItem.java @@ -73,7 +73,7 @@ import net.minecraft.util.Vec3i; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java b/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java index 06578ecc..f6a6990f 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderLeashKnot.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java b/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java index ad444058..3b178b20 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderLightningBolt.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java b/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java index 5195fd51..46792ee9 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderLiving.java @@ -17,7 +17,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java index 733c248b..e6ba5067 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMagmaCube.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java b/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java index d49ccbd8..d9728eb3 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderManager.java @@ -114,7 +114,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java index bb987826..9e107beb 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecart.java @@ -17,7 +17,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java index 5ea2b6ed..33e04e08 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMinecartMobSpawner.java @@ -11,7 +11,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java b/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java index 91b9487e..7c87baa0 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderMooshroom.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java b/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java index 722b93e9..422fb827 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderOcelot.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java index 0d8ff5c0..ea95fbd2 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPainting.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java index 17ea1f5f..6a139273 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPig.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java index ce297b4a..3c550cde 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPigZombie.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java index 73061c1e..361c75a3 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPlayer.java @@ -27,7 +27,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java b/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java index 9efa9b19..35d99d96 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderPotion.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java b/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java index 83828a57..de20ab22 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderRabbit.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java index 9360c29d..89e4d2d5 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSheep.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java index 7ecfeb8c..ca9f2084 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSilverfish.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java index ade5cd7e..cb35eeee 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSkeleton.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java index b9326119..b4c8056f 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSlime.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java index 61d0228e..a8303f0a 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowMan.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java index 2ae1077d..60c66adc 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSnowball.java @@ -16,7 +16,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java index e8802498..ed2ae946 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSpider.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java b/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java index f780fee8..1e3afed9 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderSquid.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java b/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java index 1eefdb11..eb695065 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderTNTPrimed.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java b/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java index df08610c..a2afd900 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderTntMinecart.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java b/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java index 1482155b..e1b481c8 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderVillager.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java b/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java index d4c38c54..f73750a6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderWitch.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java b/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java index a2a4931a..3f5b28e0 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderWither.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java b/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java index f3af8c0c..0c27ac61 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderWolf.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java b/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java index 5544452b..4cc344ec 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderXPOrb.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java b/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java index e1fdda49..f918ca95 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RenderZombie.java @@ -21,7 +21,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java b/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java index cacb0d73..71428605 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java +++ b/src/game/java/net/minecraft/client/renderer/entity/RendererLivingEntity.java @@ -43,7 +43,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java index 3cb54455..46f5c1f6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArmorBase.java @@ -26,7 +26,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java index a6c48669..8d0d446c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerArrow.java @@ -16,7 +16,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java index bab4fe4d..a0d5435c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerBipedArmor.java @@ -9,7 +9,7 @@ import net.minecraft.client.renderer.entity.RendererLivingEntity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java index 24acabc9..55dfb413 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCape.java @@ -13,7 +13,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java index 52e1510e..577d04dc 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCreeperCharge.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java index 1a616226..6aa00026 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerCustomHead.java @@ -27,7 +27,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java index 7edf020b..356f379c 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerDeadmau5Head.java @@ -11,7 +11,7 @@ import net.minecraft.client.renderer.entity.RenderPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java index f00d8d56..c7aee0e1 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonDeath.java @@ -22,7 +22,7 @@ import net.minecraft.entity.boss.EntityDragon; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java index ae56bc41..7c538352 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEnderDragonEyes.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java index 133b6de7..e8414030 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerEndermanEyes.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java index 85c14647..a382ef83 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldBlock.java @@ -21,7 +21,7 @@ import net.minecraft.util.EnumWorldBlockLayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java index 8df94a04..85245270 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItem.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java index 2b283ae6..813733e2 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerHeldItemWitch.java @@ -18,7 +18,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java index 8e4c629b..4653f01b 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerIronGolemFlower.java @@ -16,7 +16,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java index 1d49dce4..d980f7ba 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerMooshroomMushroom.java @@ -18,7 +18,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java index 00877da6..f42b6e0e 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerRenderer.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLivingBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java index fe3defbb..384c8acb 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSaddle.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java index 825c189b..346125ad 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSheepWool.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java index 0bb0646e..1f5ec4cb 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSlimeGel.java @@ -19,7 +19,7 @@ import net.minecraft.entity.monster.EntitySlime; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java index b788ae51..703f215a 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSnowmanHead.java @@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java index bb96111c..20c792e4 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerSpiderEyes.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java index ea6e95e2..c66463a8 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerVillagerArmor.java @@ -9,7 +9,7 @@ import net.minecraft.client.renderer.entity.RendererLivingEntity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java index dcb06c0b..04aad8d6 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWitherAura.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java index 0ee0cdff..4d11cebf 100755 --- a/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java +++ b/src/game/java/net/minecraft/client/renderer/entity/layers/LayerWolfCollar.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java b/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java index bbf818cf..b07aab46 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/AbstractTexture.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java b/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java index eef82db1..aa9a0da0 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/DynamicTexture.java @@ -11,7 +11,7 @@ import net.minecraft.client.resources.IResourceManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java b/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java index 7a98366f..4be3a614 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java +++ b/src/game/java/net/minecraft/client/renderer/texture/IIconCreator.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.texture; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java b/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java index 66738f02..342a6983 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java +++ b/src/game/java/net/minecraft/client/renderer/texture/ITextureObject.java @@ -10,7 +10,7 @@ import net.minecraft.client.resources.IResourceManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/ITickable.java b/src/game/java/net/minecraft/client/renderer/texture/ITickable.java index 1840a624..d1c1de71 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/ITickable.java +++ b/src/game/java/net/minecraft/client/renderer/texture/ITickable.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.texture; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java b/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java index eb59abe4..0eabefbb 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java +++ b/src/game/java/net/minecraft/client/renderer/texture/ITickableTextureObject.java @@ -6,7 +6,7 @@ package net.minecraft.client.renderer.texture; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java b/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java index be9d2f67..c9666579 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/LayeredColorMaskTexture.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java b/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java index 03cfed5f..43c503a2 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/LayeredTexture.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java b/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java index 0ff7d758..ff0bd25b 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java +++ b/src/game/java/net/minecraft/client/renderer/texture/SimpleTexture.java @@ -17,7 +17,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java b/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java index 020bc49a..217b2cfe 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java +++ b/src/game/java/net/minecraft/client/renderer/texture/Stitcher.java @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java b/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java index 9e9392f3..e5eda268 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureClock.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java b/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java index 3b7efc67..3f9c109c 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureCompass.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java b/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java index f0558b58..91ef08aa 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureManager.java @@ -8,6 +8,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -30,7 +32,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -48,7 +50,7 @@ public class TextureManager implements ITickable, IResourceManagerReloadListener private static final Logger logger = LogManager.getLogger(); private final Map mapTextureObjects = Maps.newHashMap(); private final List listTickables = Lists.newArrayList(); - private final Map mapTextureCounters = Maps.newHashMap(); + private final ObjectIntMap mapTextureCounters = new ObjectIntHashMap<>(); private IResourceManager theResourceManager; public TextureManager(IResourceManager resourceManager) { @@ -131,13 +133,7 @@ public class TextureManager implements ITickable, IResourceManagerReloadListener } public ResourceLocation getDynamicTextureLocation(String name, DynamicTexture texture) { - Integer integer = (Integer) this.mapTextureCounters.get(name); - if (integer == null) { - integer = Integer.valueOf(1); - } else { - integer = Integer.valueOf(integer.intValue() + 1); - } - + int integer = this.mapTextureCounters.getOrDefault(name, 0) + 1; this.mapTextureCounters.put(name, integer); ResourceLocation resourcelocation = new ResourceLocation( HString.format("dynamic/%s_%d", new Object[] { name, integer })); diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java b/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java index 19973cc7..1466ea0a 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureMap.java @@ -5,12 +5,13 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.io.IOException; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.IntIndexedContainer; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -44,7 +45,7 @@ import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -234,7 +235,7 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec TextureMetadataSection texturemetadatasection = (TextureMetadataSection) iresource .getMetadata("texture"); if (texturemetadatasection != null) { - List list = texturemetadatasection.getListMipmaps(); + IntIndexedContainer list = texturemetadatasection.getListMipmaps(); if (!list.isEmpty()) { int l = abufferedimageColor[0].width; int i1 = abufferedimageColor[0].height; @@ -243,11 +244,8 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec "Unable to load extra miplevels, source-texture is not power of two"); } } - - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - int i2 = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : list) { + int i2 = cur.value; if (i2 > 0 && i2 < abufferedimageColor.length - 1 && abufferedimageColor[i2] == null) { ResourceLocation resourcelocation2 = this.completeResourceLocation(resourcelocation, i2); @@ -319,7 +317,7 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec TextureMetadataSection texturemetadatasection = (TextureMetadataSection) iresource .getMetadata("texture"); if (texturemetadatasection != null) { - List list = texturemetadatasection.getListMipmaps(); + IntIndexedContainer list = texturemetadatasection.getListMipmaps(); if (!list.isEmpty()) { int l = abufferedimage[0].width; int i1 = abufferedimage[0].height; @@ -329,10 +327,8 @@ public class TextureMap extends AbstractTexture implements ITickableTextureObjec } } - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - int i2 = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : list) { + int i2 = cur.value; if (i2 > 0 && i2 < abufferedimage.length - 1 && abufferedimage[i2] == null) { ResourceLocation resourcelocation2 = this.completeResourceLocation(resourcelocation, i2); diff --git a/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java b/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java index 8e868dd5..4be47c19 100755 --- a/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java +++ b/src/game/java/net/minecraft/client/renderer/texture/TextureUtil.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java b/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java index 72069d6e..ad04c683 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/RenderEnderCrystal.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java b/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java index 5d1a2434..137db759 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/RenderItemFrame.java @@ -37,7 +37,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java b/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java index 82e0af2e..b6990e46 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/RenderWitherSkull.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java index 7b704605..5e42bb63 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBannerRenderer.java @@ -25,7 +25,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java index d945d73c..383bf15d 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityBeaconRenderer.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java index 6b11a955..d393f474 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityChestRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java index a098c427..6eea8653 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnchantmentTableRenderer.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java index d19d81d0..c4f80d5e 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEndPortalRenderer.java @@ -23,7 +23,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java index 467f2b75..17f214ec 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityEnderChestRenderer.java @@ -13,7 +13,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java index 3bc92571..6baeb7da 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityItemStackRenderer.java @@ -22,7 +22,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java index 98242adf..46a985c4 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityMobSpawnerRenderer.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.TileEntityMobSpawner; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java index c891262a..f60d6517 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityPistonRenderer.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java index 438d17c2..5b6d7f53 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java index 205111fe..c745ed14 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySignRenderer.java @@ -26,7 +26,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java index 23d6c009..cf1880d4 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySkullRenderer.java @@ -20,7 +20,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java index 946bc215..b8444099 100755 --- a/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java +++ b/src/game/java/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java b/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java index f95aea21..4be8b2ac 100755 --- a/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java +++ b/src/game/java/net/minecraft/client/renderer/vertex/DefaultVertexFormats.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.VertexFormat; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java b/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java index 2ff47ce0..67897f0d 100755 --- a/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java +++ b/src/game/java/net/minecraft/client/resources/AbstractResourcePack.java @@ -24,7 +24,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java b/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java index 0a3b5850..da2c3d0d 100755 --- a/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java +++ b/src/game/java/net/minecraft/client/resources/DefaultPlayerSkin.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java b/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java index 4a884832..962fb26c 100755 --- a/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java +++ b/src/game/java/net/minecraft/client/resources/DefaultResourcePack.java @@ -20,7 +20,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java b/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java index 2de67bd8..1aeb0e9e 100755 --- a/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/FallbackResourceManager.java @@ -20,7 +20,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java b/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java index 65e12538..f602ffff 100755 --- a/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java +++ b/src/game/java/net/minecraft/client/resources/FoliageColorReloadListener.java @@ -12,7 +12,7 @@ import net.minecraft.world.ColorizerFoliage; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java b/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java index 2cc8e524..2b4ce918 100755 --- a/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java +++ b/src/game/java/net/minecraft/client/resources/GrassColorReloadListener.java @@ -12,7 +12,7 @@ import net.minecraft.world.ColorizerGrass; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/I18n.java b/src/game/java/net/minecraft/client/resources/I18n.java index b47df8ef..47946269 100755 --- a/src/game/java/net/minecraft/client/resources/I18n.java +++ b/src/game/java/net/minecraft/client/resources/I18n.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java b/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java index 5f3deb6f..27360d19 100755 --- a/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/IReloadableResourceManager.java @@ -8,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/IResource.java b/src/game/java/net/minecraft/client/resources/IResource.java index 25d7684d..ebd696ed 100755 --- a/src/game/java/net/minecraft/client/resources/IResource.java +++ b/src/game/java/net/minecraft/client/resources/IResource.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/IResourceManager.java b/src/game/java/net/minecraft/client/resources/IResourceManager.java index 64ba7840..ccee41cc 100755 --- a/src/game/java/net/minecraft/client/resources/IResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/IResourceManager.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java b/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java index bb3ca265..fdbd2bb5 100755 --- a/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java +++ b/src/game/java/net/minecraft/client/resources/IResourceManagerReloadListener.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/IResourcePack.java b/src/game/java/net/minecraft/client/resources/IResourcePack.java index fde05118..3d877940 100755 --- a/src/game/java/net/minecraft/client/resources/IResourcePack.java +++ b/src/game/java/net/minecraft/client/resources/IResourcePack.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/Language.java b/src/game/java/net/minecraft/client/resources/Language.java index a2a2c9be..276f53ff 100755 --- a/src/game/java/net/minecraft/client/resources/Language.java +++ b/src/game/java/net/minecraft/client/resources/Language.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/LanguageManager.java b/src/game/java/net/minecraft/client/resources/LanguageManager.java index 83eb33cc..59a34d61 100755 --- a/src/game/java/net/minecraft/client/resources/LanguageManager.java +++ b/src/game/java/net/minecraft/client/resources/LanguageManager.java @@ -22,7 +22,7 @@ import net.minecraft.util.StringTranslate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/Locale.java b/src/game/java/net/minecraft/client/resources/Locale.java index bfef9b0e..318898a6 100755 --- a/src/game/java/net/minecraft/client/resources/Locale.java +++ b/src/game/java/net/minecraft/client/resources/Locale.java @@ -25,7 +25,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java b/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java index 5ced15e8..de878f0a 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackFileNotFoundException.java @@ -11,7 +11,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java b/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java index e7d6dc98..b92ad177 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackListEntry.java @@ -22,7 +22,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java index 8adf9e3a..253c884e 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryDefault.java @@ -19,7 +19,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java index 9399baff..ca10cca5 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackListEntryFound.java @@ -8,7 +8,7 @@ import net.minecraft.client.gui.GuiScreenResourcePacks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java b/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java index f8ce9f78..2950561f 100755 --- a/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java +++ b/src/game/java/net/minecraft/client/resources/ResourcePackRepository.java @@ -30,7 +30,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java b/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java index ff4e31ea..a73d8438 100755 --- a/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java +++ b/src/game/java/net/minecraft/client/resources/SimpleReloadableResourceManager.java @@ -24,7 +24,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/SimpleResource.java b/src/game/java/net/minecraft/client/resources/SimpleResource.java index 451f2221..1860a51a 100755 --- a/src/game/java/net/minecraft/client/resources/SimpleResource.java +++ b/src/game/java/net/minecraft/client/resources/SimpleResource.java @@ -21,7 +21,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java b/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java index fb714c76..2442b421 100755 --- a/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java +++ b/src/game/java/net/minecraft/client/resources/data/AnimationFrame.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java index cfddc0a6..42824d66 100755 --- a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSection.java @@ -1,10 +1,8 @@ package net.minecraft.client.resources.data; -import java.util.HashSet; import java.util.List; -import java.util.Set; - -import com.google.common.collect.Sets; +import com.carrotsearch.hppc.IntHashSet; +import com.carrotsearch.hppc.IntSet; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -12,7 +10,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -79,11 +77,11 @@ public class AnimationMetadataSection implements IMetadataSection { return ((AnimationFrame) this.animationFrames.get(parInt1)).getFrameIndex(); } - public Set getFrameIndexSet() { - HashSet hashset = Sets.newHashSet(); + public IntSet getFrameIndexSet() { + IntHashSet hashset = new IntHashSet(); for (int i = 0, l = this.animationFrames.size(); i < l; ++i) { - hashset.add(Integer.valueOf(this.animationFrames.get(i).getFrameIndex())); + hashset.add(this.animationFrames.get(i).getFrameIndex()); } return hashset; diff --git a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java index b171ff5e..20247d2e 100755 --- a/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/AnimationMetadataSectionSerializer.java @@ -17,7 +17,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeSerializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java index 466f8b6b..2a4fd52f 100755 --- a/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/BaseMetadataSectionSerializer.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java index 4b0d095f..2ece17d7 100755 --- a/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/FontMetadataSection.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java index d7c3504e..19944281 100755 --- a/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/FontMetadataSectionSerializer.java @@ -10,7 +10,7 @@ import org.json.JSONObject; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java index 96517805..93d24b86 100755 --- a/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/IMetadataSection.java @@ -6,7 +6,7 @@ package net.minecraft.client.resources.data; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java index 00e83560..fad00128 100755 --- a/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/IMetadataSectionSerializer.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeDeserializer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java b/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java index 44c93031..510da561 100755 --- a/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/IMetadataSerializer.java @@ -12,7 +12,7 @@ import net.minecraft.util.RegistrySimple; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java index 460f7fd7..1c490b94 100755 --- a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSection.java @@ -10,7 +10,7 @@ import net.minecraft.client.resources.Language; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java index e926da6d..cc9d855e 100755 --- a/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/LanguageMetadataSectionSerializer.java @@ -15,7 +15,7 @@ import net.minecraft.client.resources.Language; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java index 3601d8f6..0dbf8e61 100755 --- a/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/PackMetadataSection.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java index b7f1904e..b9308764 100755 --- a/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/PackMetadataSectionSerializer.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java index 1dd12aed..14980924 100755 --- a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java +++ b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSection.java @@ -1,7 +1,6 @@ package net.minecraft.client.resources.data; -import java.util.Collections; -import java.util.List; +import com.carrotsearch.hppc.IntIndexedContainer; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -9,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -26,9 +25,9 @@ import java.util.List; public class TextureMetadataSection implements IMetadataSection { private final boolean textureBlur; private final boolean textureClamp; - private final List listMipmaps; + private final IntIndexedContainer listMipmaps; - public TextureMetadataSection(boolean parFlag, boolean parFlag2, List parList) { + public TextureMetadataSection(boolean parFlag, boolean parFlag2, IntIndexedContainer parList) { this.textureBlur = parFlag; this.textureClamp = parFlag2; this.listMipmaps = parList; @@ -42,7 +41,7 @@ public class TextureMetadataSection implements IMetadataSection { return this.textureClamp; } - public List getListMipmaps() { - return Collections.unmodifiableList(this.listMipmaps); + public IntIndexedContainer getListMipmaps() { + return listMipmaps; } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java index 92bc8f83..22a0a1b3 100755 --- a/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java +++ b/src/game/java/net/minecraft/client/resources/data/TextureMetadataSectionSerializer.java @@ -1,12 +1,10 @@ package net.minecraft.client.resources.data; -import java.util.ArrayList; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import com.google.common.collect.Lists; +import com.carrotsearch.hppc.IntArrayList; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -14,7 +12,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -32,7 +30,7 @@ public class TextureMetadataSectionSerializer extends BaseMetadataSectionSeriali public TextureMetadataSection deserialize(JSONObject jsonobject) throws JSONException { boolean flag = jsonobject.optBoolean("blur", false); boolean flag1 = jsonobject.optBoolean("clamp", false); - ArrayList arraylist = Lists.newArrayList(); + IntArrayList arraylist = new IntArrayList(); if (jsonobject.has("mipmaps")) { try { JSONArray jsonarray = jsonobject.getJSONArray("mipmaps"); diff --git a/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java b/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java index 6570ab46..3b4b5b37 100755 --- a/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java +++ b/src/game/java/net/minecraft/client/resources/model/BuiltInModel.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/model/IBakedModel.java b/src/game/java/net/minecraft/client/resources/model/IBakedModel.java index ebb29ee6..8f244e2d 100755 --- a/src/game/java/net/minecraft/client/resources/model/IBakedModel.java +++ b/src/game/java/net/minecraft/client/resources/model/IBakedModel.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/model/ModelBakery.java b/src/game/java/net/minecraft/client/resources/model/ModelBakery.java index 7c4e6197..a59bf8b4 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelBakery.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelBakery.java @@ -54,7 +54,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -421,17 +421,17 @@ public class ModelBakery { if (deferred) { ModelBlock currentBlockModel = modelblock; ResourceLocation currentResourceLocation = modelblockdefinition$variant.getModelLocation(); - Integer blockId = null; + int blockId = -1; do { - blockId = BlockVertexIDs.modelToID.get(currentResourceLocation.toString()); - if (blockId != null) { + blockId = BlockVertexIDs.modelToID.getOrDefault(currentResourceLocation.toString(), -1); + if (blockId != -1) { break; } currentResourceLocation = currentBlockModel.getParentLocation(); currentBlockModel = models.get(currentResourceLocation); } while (currentBlockModel != null); - if (blockId != null) { - VertexMarkerState.markId = blockId.intValue(); + if (blockId != -1) { + VertexMarkerState.markId = blockId; try { weightedbakedmodel$builder.add( this.bakeModel(modelblock, modelblockdefinition$variant.getRotation(), diff --git a/src/game/java/net/minecraft/client/resources/model/ModelManager.java b/src/game/java/net/minecraft/client/resources/model/ModelManager.java index 74e87de4..470e5c79 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelManager.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelManager.java @@ -12,7 +12,7 @@ import net.minecraft.util.IRegistry; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java b/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java index a5dc21f5..ca64c1dc 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelResourceLocation.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/model/ModelRotation.java b/src/game/java/net/minecraft/client/resources/model/ModelRotation.java index 79425357..0b9c36b3 100755 --- a/src/game/java/net/minecraft/client/resources/model/ModelRotation.java +++ b/src/game/java/net/minecraft/client/resources/model/ModelRotation.java @@ -1,8 +1,7 @@ package net.minecraft.client.resources.model; -import java.util.Map; - -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.lax1dude.eaglercraft.v1_8.vector.Matrix4f; import net.lax1dude.eaglercraft.v1_8.vector.Vector3f; @@ -15,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -34,7 +33,7 @@ public enum ModelRotation { X90_Y270(90, 270), X180_Y0(180, 0), X180_Y90(180, 90), X180_Y180(180, 180), X180_Y270(180, 270), X270_Y0(270, 0), X270_Y90(270, 90), X270_Y180(270, 180), X270_Y270(270, 270); - private static final Map mapRotations = Maps.newHashMap(); + private static final IntObjectMap mapRotations = new IntObjectHashMap<>(); private final int combinedXY; private final Matrix4f matrix4d; private final int quartersX; @@ -98,14 +97,14 @@ public enum ModelRotation { } public static ModelRotation getModelRotation(int parInt1, int parInt2) { - return (ModelRotation) mapRotations.get(Integer - .valueOf(combineXY(MathHelper.normalizeAngle(parInt1, 360), MathHelper.normalizeAngle(parInt2, 360)))); + return mapRotations + .get(combineXY(MathHelper.normalizeAngle(parInt1, 360), MathHelper.normalizeAngle(parInt2, 360))); } static { ModelRotation[] lst = values(); for (int i = 0; i < lst.length; ++i) { - mapRotations.put(Integer.valueOf(lst[i].combinedXY), lst[i]); + mapRotations.put(lst[i].combinedXY, lst[i]); } } diff --git a/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java b/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java index f1dafc25..1c5b85de 100755 --- a/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java +++ b/src/game/java/net/minecraft/client/resources/model/SimpleBakedModel.java @@ -17,7 +17,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java b/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java index d90772a0..a6557de5 100755 --- a/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java +++ b/src/game/java/net/minecraft/client/resources/model/WeightedBakedModel.java @@ -18,7 +18,7 @@ import net.minecraft.util.WeightedRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/settings/GameSettings.java b/src/game/java/net/minecraft/client/settings/GameSettings.java index c3f4b971..e4114851 100755 --- a/src/game/java/net/minecraft/client/settings/GameSettings.java +++ b/src/game/java/net/minecraft/client/settings/GameSettings.java @@ -44,6 +44,7 @@ import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EnumPlayerModelParts; import net.minecraft.network.play.client.C15PacketClientSettings; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.MathHelper; import net.minecraft.world.EnumDifficulty; @@ -53,7 +54,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -660,6 +661,11 @@ public class GameSettings { * 100.0F) + "%") : "yee"))))))))))))); + } else if (EagRuntime.getPlatformType() != EnumPlatformType.DESKTOP + && parOptions == GameSettings.Options.EAGLER_VSYNC) { + boolean flag = this.getOptionOrdinalValue(parOptions); + return flag ? s + I18n.format("options.on", new Object[0]) + : EnumChatFormatting.RED + s + I18n.format("options.off", new Object[0]); } else if (parOptions.getEnumBoolean()) { boolean flag = this.getOptionOrdinalValue(parOptions); return flag ? s + I18n.format("options.on", new Object[0]) : s + I18n.format("options.off", new Object[0]); diff --git a/src/game/java/net/minecraft/client/settings/KeyBinding.java b/src/game/java/net/minecraft/client/settings/KeyBinding.java index e4b476ad..3c261635 100755 --- a/src/game/java/net/minecraft/client/settings/KeyBinding.java +++ b/src/game/java/net/minecraft/client/settings/KeyBinding.java @@ -3,11 +3,12 @@ package net.minecraft.client.settings; import java.util.List; import java.util.Set; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import net.minecraft.client.resources.I18n; -import net.minecraft.util.IntHashMap; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -15,7 +16,7 @@ import net.minecraft.util.IntHashMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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,7 +32,7 @@ import net.minecraft.util.IntHashMap; */ public class KeyBinding implements Comparable { private static final List keybindArray = Lists.newArrayList(); - private static final IntHashMap hash = new IntHashMap(); + private static final IntObjectMap hash = new IntObjectHashMap<>(); private static final Set keybindSet = Sets.newHashSet(); private final String keyDescription; private final int keyCodeDefault; @@ -42,7 +43,7 @@ public class KeyBinding implements Comparable { public static void onTick(int keyCode) { if (keyCode != 0) { - KeyBinding keybinding = (KeyBinding) hash.lookup(keyCode); + KeyBinding keybinding = hash.get(keyCode); if (keybinding != null) { ++keybinding.pressTime; } @@ -52,7 +53,7 @@ public class KeyBinding implements Comparable { public static void setKeyBindState(int keyCode, boolean pressed) { if (keyCode != 0) { - KeyBinding keybinding = (KeyBinding) hash.lookup(keyCode); + KeyBinding keybinding = hash.get(keyCode); if (keybinding != null) { keybinding.pressed = pressed; } @@ -68,11 +69,11 @@ public class KeyBinding implements Comparable { } public static void resetKeyBindingArrayAndHash() { - hash.clearMap(); + hash.clear(); for (int i = 0, l = keybindArray.size(); i < l; ++i) { KeyBinding keybinding = keybindArray.get(i); - hash.addKey(keybinding.keyCode, keybinding); + hash.put(keybinding.keyCode, keybinding); } } @@ -87,7 +88,7 @@ public class KeyBinding implements Comparable { this.keyCodeDefault = keyCode; this.keyCategory = category; keybindArray.add(this); - hash.addKey(keyCode, this); + hash.put(keyCode, this); keybindSet.add(category); } diff --git a/src/game/java/net/minecraft/client/stream/IStream.java b/src/game/java/net/minecraft/client/stream/IStream.java index cb9b3cf3..f8b4122b 100755 --- a/src/game/java/net/minecraft/client/stream/IStream.java +++ b/src/game/java/net/minecraft/client/stream/IStream.java @@ -6,7 +6,7 @@ package net.minecraft.client.stream; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/util/JsonBlendingMode.java b/src/game/java/net/minecraft/client/util/JsonBlendingMode.java index 45446e91..2330416d 100755 --- a/src/game/java/net/minecraft/client/util/JsonBlendingMode.java +++ b/src/game/java/net/minecraft/client/util/JsonBlendingMode.java @@ -11,7 +11,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/client/util/JsonException.java b/src/game/java/net/minecraft/client/util/JsonException.java index 03f871da..7f149d4f 100755 --- a/src/game/java/net/minecraft/client/util/JsonException.java +++ b/src/game/java/net/minecraft/client/util/JsonException.java @@ -14,7 +14,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandBase.java b/src/game/java/net/minecraft/command/CommandBase.java index b5667f82..f5579f29 100755 --- a/src/game/java/net/minecraft/command/CommandBase.java +++ b/src/game/java/net/minecraft/command/CommandBase.java @@ -1,5 +1,7 @@ package net.minecraft.command; +import com.carrotsearch.hppc.ObjectContainer; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.base.Functions; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -27,7 +29,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -597,6 +599,27 @@ public abstract class CommandBase implements ICommand { return arraylist; } + /**+ + * Returns a List of strings (chosen from the given strings) + * which the last word in the given string array is a + * beginning-match for. (Tab completion). + */ + public static List getListOfStringsMatchingLastWord(String[] parArrayOfString, + ObjectContainer parCollection) { + String s = parArrayOfString[parArrayOfString.length - 1]; + ArrayList arraylist = Lists.newArrayList(); + if (!parCollection.isEmpty()) { + for (ObjectCursor s1_ : parCollection) { + String s1 = s1_.value; + if (doesStringStartWith(s, s1)) { + arraylist.add(s1); + } + } + } + + return arraylist; + } + /**+ * Return whether the specified command parameter index is a * username parameter. diff --git a/src/game/java/net/minecraft/command/CommandBlockData.java b/src/game/java/net/minecraft/command/CommandBlockData.java index be0350df..386db7b9 100755 --- a/src/game/java/net/minecraft/command/CommandBlockData.java +++ b/src/game/java/net/minecraft/command/CommandBlockData.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandClearInventory.java b/src/game/java/net/minecraft/command/CommandClearInventory.java index 82bb4e86..e22eda55 100755 --- a/src/game/java/net/minecraft/command/CommandClearInventory.java +++ b/src/game/java/net/minecraft/command/CommandClearInventory.java @@ -16,7 +16,7 @@ import net.minecraft.util.ChatComponentTranslation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandClone.java b/src/game/java/net/minecraft/command/CommandClone.java index ddcaf082..355eeae8 100755 --- a/src/game/java/net/minecraft/command/CommandClone.java +++ b/src/game/java/net/minecraft/command/CommandClone.java @@ -21,7 +21,7 @@ import net.minecraft.world.gen.structure.StructureBoundingBox; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandCompare.java b/src/game/java/net/minecraft/command/CommandCompare.java index 2245b012..5bfb46ac 100755 --- a/src/game/java/net/minecraft/command/CommandCompare.java +++ b/src/game/java/net/minecraft/command/CommandCompare.java @@ -15,7 +15,7 @@ import net.minecraft.world.gen.structure.StructureBoundingBox; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandDefaultGameMode.java b/src/game/java/net/minecraft/command/CommandDefaultGameMode.java index fd750883..80a90fa9 100755 --- a/src/game/java/net/minecraft/command/CommandDefaultGameMode.java +++ b/src/game/java/net/minecraft/command/CommandDefaultGameMode.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandDifficulty.java b/src/game/java/net/minecraft/command/CommandDifficulty.java index f9027b5c..f9ffadc9 100755 --- a/src/game/java/net/minecraft/command/CommandDifficulty.java +++ b/src/game/java/net/minecraft/command/CommandDifficulty.java @@ -12,7 +12,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandEffect.java b/src/game/java/net/minecraft/command/CommandEffect.java index 80b70d48..aa72ee39 100755 --- a/src/game/java/net/minecraft/command/CommandEffect.java +++ b/src/game/java/net/minecraft/command/CommandEffect.java @@ -14,7 +14,7 @@ import net.minecraft.util.ChatComponentTranslation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandEnchant.java b/src/game/java/net/minecraft/command/CommandEnchant.java index 81fff5b8..d60100a7 100755 --- a/src/game/java/net/minecraft/command/CommandEnchant.java +++ b/src/game/java/net/minecraft/command/CommandEnchant.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandEntityData.java b/src/game/java/net/minecraft/command/CommandEntityData.java index 1c3c2147..c7412eaa 100755 --- a/src/game/java/net/minecraft/command/CommandEntityData.java +++ b/src/game/java/net/minecraft/command/CommandEntityData.java @@ -12,7 +12,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandException.java b/src/game/java/net/minecraft/command/CommandException.java index e9bcc37f..5d2281b8 100755 --- a/src/game/java/net/minecraft/command/CommandException.java +++ b/src/game/java/net/minecraft/command/CommandException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandExecuteAt.java b/src/game/java/net/minecraft/command/CommandExecuteAt.java index 850798ef..eb115166 100755 --- a/src/game/java/net/minecraft/command/CommandExecuteAt.java +++ b/src/game/java/net/minecraft/command/CommandExecuteAt.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandFill.java b/src/game/java/net/minecraft/command/CommandFill.java index 6efd36ae..b82a12da 100755 --- a/src/game/java/net/minecraft/command/CommandFill.java +++ b/src/game/java/net/minecraft/command/CommandFill.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandGameMode.java b/src/game/java/net/minecraft/command/CommandGameMode.java index 9d6048b9..36a750fe 100755 --- a/src/game/java/net/minecraft/command/CommandGameMode.java +++ b/src/game/java/net/minecraft/command/CommandGameMode.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandGameRule.java b/src/game/java/net/minecraft/command/CommandGameRule.java index f7168cf2..d1961004 100755 --- a/src/game/java/net/minecraft/command/CommandGameRule.java +++ b/src/game/java/net/minecraft/command/CommandGameRule.java @@ -14,7 +14,7 @@ import net.minecraft.world.GameRules; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandGive.java b/src/game/java/net/minecraft/command/CommandGive.java index dbc00870..c9c79ebf 100755 --- a/src/game/java/net/minecraft/command/CommandGive.java +++ b/src/game/java/net/minecraft/command/CommandGive.java @@ -16,7 +16,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandHandler.java b/src/game/java/net/minecraft/command/CommandHandler.java index 948192b6..6687b1be 100755 --- a/src/game/java/net/minecraft/command/CommandHandler.java +++ b/src/game/java/net/minecraft/command/CommandHandler.java @@ -21,7 +21,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandHelp.java b/src/game/java/net/minecraft/command/CommandHelp.java index 98d6d0b6..9825ef06 100755 --- a/src/game/java/net/minecraft/command/CommandHelp.java +++ b/src/game/java/net/minecraft/command/CommandHelp.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandKill.java b/src/game/java/net/minecraft/command/CommandKill.java index da568c36..33ba063e 100755 --- a/src/game/java/net/minecraft/command/CommandKill.java +++ b/src/game/java/net/minecraft/command/CommandKill.java @@ -12,7 +12,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandNotFoundException.java b/src/game/java/net/minecraft/command/CommandNotFoundException.java index b9b5ac80..13eafb09 100755 --- a/src/game/java/net/minecraft/command/CommandNotFoundException.java +++ b/src/game/java/net/minecraft/command/CommandNotFoundException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandParticle.java b/src/game/java/net/minecraft/command/CommandParticle.java index 9e7d3ad1..022784dc 100755 --- a/src/game/java/net/minecraft/command/CommandParticle.java +++ b/src/game/java/net/minecraft/command/CommandParticle.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandPlaySound.java b/src/game/java/net/minecraft/command/CommandPlaySound.java index fbee124b..b4263586 100755 --- a/src/game/java/net/minecraft/command/CommandPlaySound.java +++ b/src/game/java/net/minecraft/command/CommandPlaySound.java @@ -13,7 +13,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandReplaceItem.java b/src/game/java/net/minecraft/command/CommandReplaceItem.java index d174b70b..6a0a3356 100755 --- a/src/game/java/net/minecraft/command/CommandReplaceItem.java +++ b/src/game/java/net/minecraft/command/CommandReplaceItem.java @@ -1,8 +1,10 @@ package net.minecraft.command; -import com.google.common.collect.Maps; import java.util.List; -import java.util.Map; + +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; + import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; @@ -23,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -39,7 +41,7 @@ import net.minecraft.world.World; */ public class CommandReplaceItem extends CommandBase { - private static final Map SHORTCUTS = Maps.newHashMap(); + private static final ObjectIntMap SHORTCUTS = new ObjectIntHashMap<>(); /**+ * Gets the name of the command @@ -169,7 +171,7 @@ public class CommandReplaceItem extends CommandBase { if (!SHORTCUTS.containsKey(shortcut)) { throw new CommandException("commands.generic.parameter.invalid", new Object[] { shortcut }); } else { - return ((Integer) SHORTCUTS.get(shortcut)).intValue(); + return SHORTCUTS.get(shortcut); } } @@ -189,7 +191,7 @@ public class CommandReplaceItem extends CommandBase { ? null : getListOfStringsMatchingLastWord(astring, Item.itemRegistry.getKeys())) - : getListOfStringsMatchingLastWord(astring, SHORTCUTS.keySet())))); + : getListOfStringsMatchingLastWord(astring, SHORTCUTS.keys())))); } protected String[] getUsernames() { @@ -206,36 +208,36 @@ public class CommandReplaceItem extends CommandBase { static { for (int i = 0; i < 54; ++i) { - SHORTCUTS.put("slot.container." + i, Integer.valueOf(i)); + SHORTCUTS.put("slot.container." + i, i); } for (int j = 0; j < 9; ++j) { - SHORTCUTS.put("slot.hotbar." + j, Integer.valueOf(j)); + SHORTCUTS.put("slot.hotbar." + j, j); } for (int k = 0; k < 27; ++k) { - SHORTCUTS.put("slot.inventory." + k, Integer.valueOf(9 + k)); + SHORTCUTS.put("slot.inventory." + k, 9 + k); } for (int l = 0; l < 27; ++l) { - SHORTCUTS.put("slot.enderchest." + l, Integer.valueOf(200 + l)); + SHORTCUTS.put("slot.enderchest." + l, 200 + l); } for (int i1 = 0; i1 < 8; ++i1) { - SHORTCUTS.put("slot.villager." + i1, Integer.valueOf(300 + i1)); + SHORTCUTS.put("slot.villager." + i1, 300 + i1); } for (int j1 = 0; j1 < 15; ++j1) { - SHORTCUTS.put("slot.horse." + j1, Integer.valueOf(500 + j1)); + SHORTCUTS.put("slot.horse." + j1, 500 + j1); } - SHORTCUTS.put("slot.weapon", Integer.valueOf(99)); - SHORTCUTS.put("slot.armor.head", Integer.valueOf(103)); - SHORTCUTS.put("slot.armor.chest", Integer.valueOf(102)); - SHORTCUTS.put("slot.armor.legs", Integer.valueOf(101)); - SHORTCUTS.put("slot.armor.feet", Integer.valueOf(100)); - SHORTCUTS.put("slot.horse.saddle", Integer.valueOf(400)); - SHORTCUTS.put("slot.horse.armor", Integer.valueOf(401)); - SHORTCUTS.put("slot.horse.chest", Integer.valueOf(499)); + SHORTCUTS.put("slot.weapon", 99); + SHORTCUTS.put("slot.armor.head", 103); + SHORTCUTS.put("slot.armor.chest", 102); + SHORTCUTS.put("slot.armor.legs", 101); + SHORTCUTS.put("slot.armor.feet", 100); + SHORTCUTS.put("slot.horse.saddle", 400); + SHORTCUTS.put("slot.horse.armor", 401); + SHORTCUTS.put("slot.horse.chest", 499); } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/command/CommandResultStats.java b/src/game/java/net/minecraft/command/CommandResultStats.java index eba2055d..71cb3fa9 100755 --- a/src/game/java/net/minecraft/command/CommandResultStats.java +++ b/src/game/java/net/minecraft/command/CommandResultStats.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandServerKick.java b/src/game/java/net/minecraft/command/CommandServerKick.java index 3fb50f0a..9970da21 100755 --- a/src/game/java/net/minecraft/command/CommandServerKick.java +++ b/src/game/java/net/minecraft/command/CommandServerKick.java @@ -12,7 +12,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java b/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java index 3bcf8d3e..434edb5d 100755 --- a/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java +++ b/src/game/java/net/minecraft/command/CommandSetPlayerTimeout.java @@ -8,7 +8,7 @@ import net.minecraft.server.MinecraftServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java b/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java index 148a71db..d16ff0c6 100755 --- a/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java +++ b/src/game/java/net/minecraft/command/CommandSetSpawnpoint.java @@ -11,7 +11,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandShowSeed.java b/src/game/java/net/minecraft/command/CommandShowSeed.java index 24726888..7947ac73 100755 --- a/src/game/java/net/minecraft/command/CommandShowSeed.java +++ b/src/game/java/net/minecraft/command/CommandShowSeed.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandSpreadPlayers.java b/src/game/java/net/minecraft/command/CommandSpreadPlayers.java index d2099eda..437a1139 100755 --- a/src/game/java/net/minecraft/command/CommandSpreadPlayers.java +++ b/src/game/java/net/minecraft/command/CommandSpreadPlayers.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandStats.java b/src/game/java/net/minecraft/command/CommandStats.java index 2f73bb5d..fdd1b1f1 100755 --- a/src/game/java/net/minecraft/command/CommandStats.java +++ b/src/game/java/net/minecraft/command/CommandStats.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandTime.java b/src/game/java/net/minecraft/command/CommandTime.java index b0ebb08b..3e3b2d2f 100755 --- a/src/game/java/net/minecraft/command/CommandTime.java +++ b/src/game/java/net/minecraft/command/CommandTime.java @@ -11,7 +11,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandTitle.java b/src/game/java/net/minecraft/command/CommandTitle.java index e4bf88cc..937c5b2e 100755 --- a/src/game/java/net/minecraft/command/CommandTitle.java +++ b/src/game/java/net/minecraft/command/CommandTitle.java @@ -20,7 +20,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandToggleDownfall.java b/src/game/java/net/minecraft/command/CommandToggleDownfall.java index f3da57db..6928b969 100755 --- a/src/game/java/net/minecraft/command/CommandToggleDownfall.java +++ b/src/game/java/net/minecraft/command/CommandToggleDownfall.java @@ -9,7 +9,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandTrigger.java b/src/game/java/net/minecraft/command/CommandTrigger.java index e5ec1677..ca461816 100755 --- a/src/game/java/net/minecraft/command/CommandTrigger.java +++ b/src/game/java/net/minecraft/command/CommandTrigger.java @@ -18,7 +18,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandWeather.java b/src/game/java/net/minecraft/command/CommandWeather.java index 2d617d5a..0a1a8c2a 100755 --- a/src/game/java/net/minecraft/command/CommandWeather.java +++ b/src/game/java/net/minecraft/command/CommandWeather.java @@ -14,7 +14,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandWorldBorder.java b/src/game/java/net/minecraft/command/CommandWorldBorder.java index 6bedbd2c..cfa907b3 100755 --- a/src/game/java/net/minecraft/command/CommandWorldBorder.java +++ b/src/game/java/net/minecraft/command/CommandWorldBorder.java @@ -15,7 +15,7 @@ import net.minecraft.world.border.WorldBorder; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/CommandXP.java b/src/game/java/net/minecraft/command/CommandXP.java index 59b6f2be..08c735bb 100755 --- a/src/game/java/net/minecraft/command/CommandXP.java +++ b/src/game/java/net/minecraft/command/CommandXP.java @@ -11,7 +11,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/EntityNotFoundException.java b/src/game/java/net/minecraft/command/EntityNotFoundException.java index 6863f319..48c40452 100755 --- a/src/game/java/net/minecraft/command/EntityNotFoundException.java +++ b/src/game/java/net/minecraft/command/EntityNotFoundException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/IAdminCommand.java b/src/game/java/net/minecraft/command/IAdminCommand.java index 2773a97d..b6816689 100755 --- a/src/game/java/net/minecraft/command/IAdminCommand.java +++ b/src/game/java/net/minecraft/command/IAdminCommand.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/ICommand.java b/src/game/java/net/minecraft/command/ICommand.java index b1bc237b..e23f3d84 100755 --- a/src/game/java/net/minecraft/command/ICommand.java +++ b/src/game/java/net/minecraft/command/ICommand.java @@ -9,7 +9,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/ICommandManager.java b/src/game/java/net/minecraft/command/ICommandManager.java index 41c77a3d..fca2a4c0 100755 --- a/src/game/java/net/minecraft/command/ICommandManager.java +++ b/src/game/java/net/minecraft/command/ICommandManager.java @@ -10,7 +10,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/ICommandSender.java b/src/game/java/net/minecraft/command/ICommandSender.java index 52758558..31efa535 100755 --- a/src/game/java/net/minecraft/command/ICommandSender.java +++ b/src/game/java/net/minecraft/command/ICommandSender.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/NumberInvalidException.java b/src/game/java/net/minecraft/command/NumberInvalidException.java index ee182d53..5c9eb55b 100755 --- a/src/game/java/net/minecraft/command/NumberInvalidException.java +++ b/src/game/java/net/minecraft/command/NumberInvalidException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/PlayerNotFoundException.java b/src/game/java/net/minecraft/command/PlayerNotFoundException.java index 9f1ee593..b87368ef 100755 --- a/src/game/java/net/minecraft/command/PlayerNotFoundException.java +++ b/src/game/java/net/minecraft/command/PlayerNotFoundException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/PlayerSelector.java b/src/game/java/net/minecraft/command/PlayerSelector.java index c5c6aa70..99d5d7ab 100755 --- a/src/game/java/net/minecraft/command/PlayerSelector.java +++ b/src/game/java/net/minecraft/command/PlayerSelector.java @@ -42,7 +42,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/ServerCommandManager.java b/src/game/java/net/minecraft/command/ServerCommandManager.java index 29497253..734c0103 100755 --- a/src/game/java/net/minecraft/command/ServerCommandManager.java +++ b/src/game/java/net/minecraft/command/ServerCommandManager.java @@ -29,7 +29,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.ClientCommandDummy; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/SyntaxErrorException.java b/src/game/java/net/minecraft/command/SyntaxErrorException.java index d965d327..7d5228ff 100755 --- a/src/game/java/net/minecraft/command/SyntaxErrorException.java +++ b/src/game/java/net/minecraft/command/SyntaxErrorException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/WrongUsageException.java b/src/game/java/net/minecraft/command/WrongUsageException.java index e8d1e90a..2f34ce2c 100755 --- a/src/game/java/net/minecraft/command/WrongUsageException.java +++ b/src/game/java/net/minecraft/command/WrongUsageException.java @@ -6,7 +6,7 @@ package net.minecraft.command; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandAchievement.java b/src/game/java/net/minecraft/command/server/CommandAchievement.java index 34ce6fdc..95e9eece 100755 --- a/src/game/java/net/minecraft/command/server/CommandAchievement.java +++ b/src/game/java/net/minecraft/command/server/CommandAchievement.java @@ -23,7 +23,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandBlockLogic.java b/src/game/java/net/minecraft/command/server/CommandBlockLogic.java index 46bf6ae3..c8dee050 100755 --- a/src/game/java/net/minecraft/command/server/CommandBlockLogic.java +++ b/src/game/java/net/minecraft/command/server/CommandBlockLogic.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandBroadcast.java b/src/game/java/net/minecraft/command/server/CommandBroadcast.java index d54f349d..34224f71 100755 --- a/src/game/java/net/minecraft/command/server/CommandBroadcast.java +++ b/src/game/java/net/minecraft/command/server/CommandBroadcast.java @@ -18,7 +18,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandEmote.java b/src/game/java/net/minecraft/command/server/CommandEmote.java index 6d55a2da..d363028e 100755 --- a/src/game/java/net/minecraft/command/server/CommandEmote.java +++ b/src/game/java/net/minecraft/command/server/CommandEmote.java @@ -19,7 +19,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandListPlayers.java b/src/game/java/net/minecraft/command/server/CommandListPlayers.java index 177cb579..6d8f1c64 100755 --- a/src/game/java/net/minecraft/command/server/CommandListPlayers.java +++ b/src/game/java/net/minecraft/command/server/CommandListPlayers.java @@ -14,7 +14,7 @@ import net.minecraft.util.ChatComponentTranslation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandMessage.java b/src/game/java/net/minecraft/command/server/CommandMessage.java index a7b1ef71..b2860e27 100755 --- a/src/game/java/net/minecraft/command/server/CommandMessage.java +++ b/src/game/java/net/minecraft/command/server/CommandMessage.java @@ -23,7 +23,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandMessageRaw.java b/src/game/java/net/minecraft/command/server/CommandMessageRaw.java index e7ed145b..6650400b 100755 --- a/src/game/java/net/minecraft/command/server/CommandMessageRaw.java +++ b/src/game/java/net/minecraft/command/server/CommandMessageRaw.java @@ -22,7 +22,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandScoreboard.java b/src/game/java/net/minecraft/command/server/CommandScoreboard.java index 8f6edd13..8c948698 100755 --- a/src/game/java/net/minecraft/command/server/CommandScoreboard.java +++ b/src/game/java/net/minecraft/command/server/CommandScoreboard.java @@ -39,7 +39,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandSetBlock.java b/src/game/java/net/minecraft/command/server/CommandSetBlock.java index 92c0b993..a0f0097d 100755 --- a/src/game/java/net/minecraft/command/server/CommandSetBlock.java +++ b/src/game/java/net/minecraft/command/server/CommandSetBlock.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java b/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java index da5864b1..a6fef594 100755 --- a/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java +++ b/src/game/java/net/minecraft/command/server/CommandSetDefaultSpawnpoint.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandSummon.java b/src/game/java/net/minecraft/command/server/CommandSummon.java index 63ec8d0d..1dcbc8d7 100755 --- a/src/game/java/net/minecraft/command/server/CommandSummon.java +++ b/src/game/java/net/minecraft/command/server/CommandSummon.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandTeleport.java b/src/game/java/net/minecraft/command/server/CommandTeleport.java index 154d68d6..57b73cd3 100755 --- a/src/game/java/net/minecraft/command/server/CommandTeleport.java +++ b/src/game/java/net/minecraft/command/server/CommandTeleport.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandTestFor.java b/src/game/java/net/minecraft/command/server/CommandTestFor.java index bfa56ba5..c7ca7307 100755 --- a/src/game/java/net/minecraft/command/server/CommandTestFor.java +++ b/src/game/java/net/minecraft/command/server/CommandTestFor.java @@ -19,7 +19,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/command/server/CommandTestForBlock.java b/src/game/java/net/minecraft/command/server/CommandTestForBlock.java index e8cc4086..67132b3f 100755 --- a/src/game/java/net/minecraft/command/server/CommandTestForBlock.java +++ b/src/game/java/net/minecraft/command/server/CommandTestForBlock.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/crash/CrashReport.java b/src/game/java/net/minecraft/crash/CrashReport.java index d455dee2..6d2e24b8 100755 --- a/src/game/java/net/minecraft/crash/CrashReport.java +++ b/src/game/java/net/minecraft/crash/CrashReport.java @@ -20,7 +20,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/crash/CrashReportCategory.java b/src/game/java/net/minecraft/crash/CrashReportCategory.java index 598c0bc0..4e79d445 100755 --- a/src/game/java/net/minecraft/crash/CrashReportCategory.java +++ b/src/game/java/net/minecraft/crash/CrashReportCategory.java @@ -17,7 +17,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/creativetab/CreativeTabs.java b/src/game/java/net/minecraft/creativetab/CreativeTabs.java index 08b76d67..267c3ce5 100755 --- a/src/game/java/net/minecraft/creativetab/CreativeTabs.java +++ b/src/game/java/net/minecraft/creativetab/CreativeTabs.java @@ -17,7 +17,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java b/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java index fdbcd211..e35b22c9 100755 --- a/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java +++ b/src/game/java/net/minecraft/dispenser/BehaviorDefaultDispenseItem.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java b/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java index e28eb33b..e1743be4 100755 --- a/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java +++ b/src/game/java/net/minecraft/dispenser/BehaviorProjectileDispense.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java b/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java index 1f69c682..e729edaf 100755 --- a/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java +++ b/src/game/java/net/minecraft/dispenser/IBehaviorDispenseItem.java @@ -8,7 +8,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/IBlockSource.java b/src/game/java/net/minecraft/dispenser/IBlockSource.java index 817c3837..068acadf 100755 --- a/src/game/java/net/minecraft/dispenser/IBlockSource.java +++ b/src/game/java/net/minecraft/dispenser/IBlockSource.java @@ -9,7 +9,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/ILocatableSource.java b/src/game/java/net/minecraft/dispenser/ILocatableSource.java index 9717651f..ad9b7acd 100755 --- a/src/game/java/net/minecraft/dispenser/ILocatableSource.java +++ b/src/game/java/net/minecraft/dispenser/ILocatableSource.java @@ -6,7 +6,7 @@ package net.minecraft.dispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/ILocation.java b/src/game/java/net/minecraft/dispenser/ILocation.java index 7d6dc6ca..6c2fb863 100755 --- a/src/game/java/net/minecraft/dispenser/ILocation.java +++ b/src/game/java/net/minecraft/dispenser/ILocation.java @@ -8,7 +8,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/IPosition.java b/src/game/java/net/minecraft/dispenser/IPosition.java index b39c1bd3..32bd7e4f 100755 --- a/src/game/java/net/minecraft/dispenser/IPosition.java +++ b/src/game/java/net/minecraft/dispenser/IPosition.java @@ -6,7 +6,7 @@ package net.minecraft.dispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/dispenser/PositionImpl.java b/src/game/java/net/minecraft/dispenser/PositionImpl.java index 7a8938bb..8070d180 100755 --- a/src/game/java/net/minecraft/dispenser/PositionImpl.java +++ b/src/game/java/net/minecraft/dispenser/PositionImpl.java @@ -6,7 +6,7 @@ package net.minecraft.dispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/Enchantment.java b/src/game/java/net/minecraft/enchantment/Enchantment.java index ae13abf6..f5b47357 100755 --- a/src/game/java/net/minecraft/enchantment/Enchantment.java +++ b/src/game/java/net/minecraft/enchantment/Enchantment.java @@ -21,7 +21,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java index fa1650fa..fb7241e0 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowDamage.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java index 1b091d34..5d4ed315 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowFire.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java index ac172c77..6676c8f0 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowInfinite.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java b/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java index bfd20396..cac1166f 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentArrowKnockback.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java b/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java index e7c5be49..5dd6c65e 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentDamage.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentData.java b/src/game/java/net/minecraft/enchantment/EnchantmentData.java index 04b92d60..c0fdb509 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentData.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentData.java @@ -8,7 +8,7 @@ import net.minecraft.util.WeightedRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java b/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java index 6d8bed94..3cf80a39 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentDigging.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java b/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java index 7d7ec62a..803c5e1f 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentDurability.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java b/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java index ec6d5f8c..b3fe0aa9 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentFireAspect.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java b/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java index 87d24190..58e3bfa9 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentFishingSpeed.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java b/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java index de7b02ae..0fa7db08 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentHelper.java @@ -3,11 +3,13 @@ package net.minecraft.enchantment; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; +import com.carrotsearch.hppc.IntIntHashMap; +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -29,7 +31,7 @@ import net.minecraft.util.WeightedRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -85,15 +87,18 @@ public class EnchantmentHelper { } } - public static Map getEnchantments(ItemStack stack) { - LinkedHashMap linkedhashmap = Maps.newLinkedHashMap(); + /**+ + * Return the enchantments for the specified stack. + */ + public static IntIntMap getEnchantments(ItemStack stack) { + IntIntHashMap linkedhashmap = new IntIntHashMap(); NBTTagList nbttaglist = stack.getItem() == Items.enchanted_book ? Items.enchanted_book.getEnchantments(stack) : stack.getEnchantmentTagList(); if (nbttaglist != null) { for (int i = 0; i < nbttaglist.tagCount(); ++i) { short short1 = nbttaglist.getCompoundTagAt(i).getShort("id"); short short2 = nbttaglist.getCompoundTagAt(i).getShort("lvl"); - linkedhashmap.put(Integer.valueOf(short1), Integer.valueOf(short2)); + linkedhashmap.put(short1, short2); } } @@ -103,12 +108,11 @@ public class EnchantmentHelper { /**+ * Set the enchantments for the specified stack. */ - public static void setEnchantments(Map enchMap, ItemStack stack) { + public static void setEnchantments(IntIntMap enchMap, ItemStack stack) { NBTTagList nbttaglist = new NBTTagList(); - Iterator iterator = enchMap.keySet().iterator(); - while (iterator.hasNext()) { - int i = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : enchMap.keys()) { + int i = cur.value; Enchantment enchantment = Enchantment.getEnchantmentById(i); if (enchantment != null) { NBTTagCompound nbttagcompound = new NBTTagCompound(); diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java b/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java index 66a175db..090779f6 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentKnockback.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java b/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java index d46f0017..e7a2c32c 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentLootBonus.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java b/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java index 3cc270fb..14cc90e5 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentOxygen.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java b/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java index 12637e07..4dfcd8ca 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentProtection.java @@ -11,7 +11,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java b/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java index 8f35b0fd..6dacc5db 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentThorns.java @@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java b/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java index 366de53a..cb7945c0 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentUntouching.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java index 17cd2d7d..c2e7d65f 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWalker.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java index ac6c7891..4aed4407 100755 --- a/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java +++ b/src/game/java/net/minecraft/enchantment/EnchantmentWaterWorker.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java b/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java index 7b986407..b2e7f162 100755 --- a/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java +++ b/src/game/java/net/minecraft/enchantment/EnumEnchantmentType.java @@ -13,7 +13,7 @@ import net.minecraft.item.ItemTool; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/DataWatcher.java b/src/game/java/net/minecraft/entity/DataWatcher.java index efa552a4..cfd09ac0 100755 --- a/src/game/java/net/minecraft/entity/DataWatcher.java +++ b/src/game/java/net/minecraft/entity/DataWatcher.java @@ -3,12 +3,15 @@ package net.minecraft.entity; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Map; import org.apache.commons.lang3.ObjectUtils; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; @@ -24,7 +27,7 @@ import net.minecraft.util.Rotations; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -45,8 +48,8 @@ public class DataWatcher { * objects */ private boolean isBlank = true; - private static final Map, Integer> dataTypes = Maps.newHashMap(); - private final Map watchedObjects = Maps.newHashMap(); + private static final ObjectIntMap> dataTypes = new ObjectIntHashMap<>(); + private final IntObjectMap watchedObjects = new IntObjectHashMap<>(); private boolean objectChanged; public DataWatcher(Entity owner) { @@ -54,17 +57,17 @@ public class DataWatcher { } public void addObject(int id, T object) { - Integer integer = (Integer) dataTypes.get(object.getClass()); - if (integer == null) { + int integer = dataTypes.getOrDefault(object.getClass(), -1); + if (integer == -1) { throw new IllegalArgumentException("Unknown data type: " + object.getClass()); } else if (id > 31) { throw new IllegalArgumentException("Data value id is too big with " + id + "! (Max is " + 31 + ")"); - } else if (this.watchedObjects.containsKey(Integer.valueOf(id))) { + } else if (this.watchedObjects.containsKey(id)) { throw new IllegalArgumentException("Duplicate id value for " + id + "!"); } else { - DataWatcher.WatchableObject datawatcher$watchableobject = new DataWatcher.WatchableObject( - integer.intValue(), id, object); - this.watchedObjects.put(Integer.valueOf(id), datawatcher$watchableobject); + DataWatcher.WatchableObject datawatcher$watchableobject = new DataWatcher.WatchableObject(integer, id, + object); + this.watchedObjects.put(id, datawatcher$watchableobject); this.isBlank = false; } } @@ -76,7 +79,7 @@ public class DataWatcher { public void addObjectByDataType(int id, int type) { DataWatcher.WatchableObject datawatcher$watchableobject = new DataWatcher.WatchableObject(type, id, (Object) null); - this.watchedObjects.put(Integer.valueOf(id), datawatcher$watchableobject); + this.watchedObjects.put(id, datawatcher$watchableobject); this.isBlank = false; } @@ -122,7 +125,7 @@ public class DataWatcher { private DataWatcher.WatchableObject getWatchedObject(int id) { DataWatcher.WatchableObject datawatcher$watchableobject; try { - datawatcher$watchableobject = (DataWatcher.WatchableObject) this.watchedObjects.get(Integer.valueOf(id)); + datawatcher$watchableobject = (DataWatcher.WatchableObject) this.watchedObjects.get(id); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting synched entity data"); CrashReportCategory crashreportcategory = crashreport.makeCategory("Synched entity data"); @@ -178,7 +181,9 @@ public class DataWatcher { public List getChanged() { ArrayList arraylist = null; if (this.objectChanged) { - for (DataWatcher.WatchableObject datawatcher$watchableobject : this.watchedObjects.values()) { + for (ObjectCursor datawatcher$watchableobject_ : this.watchedObjects + .values()) { + DataWatcher.WatchableObject datawatcher$watchableobject = datawatcher$watchableobject_.value; if (datawatcher$watchableobject.isWatched()) { datawatcher$watchableobject.setWatched(false); if (arraylist == null) { @@ -195,8 +200,8 @@ public class DataWatcher { } public void writeTo(PacketBuffer buffer) throws IOException { - for (DataWatcher.WatchableObject datawatcher$watchableobject : this.watchedObjects.values()) { - writeWatchableObjectToPacketBuffer(buffer, datawatcher$watchableobject); + for (ObjectCursor datawatcher$watchableobject : this.watchedObjects.values()) { + writeWatchableObjectToPacketBuffer(buffer, datawatcher$watchableobject.value); } buffer.writeByte(127); } @@ -204,12 +209,12 @@ public class DataWatcher { public List getAllWatched() { ArrayList arraylist = null; - for (DataWatcher.WatchableObject datawatcher$watchableobject : this.watchedObjects.values()) { + for (ObjectCursor datawatcher$watchableobject : this.watchedObjects.values()) { if (arraylist == null) { arraylist = Lists.newArrayList(); } - arraylist.add(datawatcher$watchableobject); + arraylist.add(datawatcher$watchableobject.value); } return arraylist; @@ -319,7 +324,7 @@ public class DataWatcher { for (int i = 0, l = parList.size(); i < l; ++i) { DataWatcher.WatchableObject datawatcher$watchableobject = parList.get(i); DataWatcher.WatchableObject datawatcher$watchableobject1 = (DataWatcher.WatchableObject) this.watchedObjects - .get(Integer.valueOf(datawatcher$watchableobject.getDataValueId())); + .get(datawatcher$watchableobject.getDataValueId()); if (datawatcher$watchableobject1 != null) { datawatcher$watchableobject1.setObject(datawatcher$watchableobject.getObject()); this.owner.onDataWatcherUpdate(datawatcher$watchableobject.getDataValueId()); @@ -338,14 +343,14 @@ public class DataWatcher { } static { - dataTypes.put(Byte.class, Integer.valueOf(0)); - dataTypes.put(Short.class, Integer.valueOf(1)); - dataTypes.put(Integer.class, Integer.valueOf(2)); - dataTypes.put(Float.class, Integer.valueOf(3)); - dataTypes.put(String.class, Integer.valueOf(4)); - dataTypes.put(ItemStack.class, Integer.valueOf(5)); - dataTypes.put(BlockPos.class, Integer.valueOf(6)); - dataTypes.put(Rotations.class, Integer.valueOf(7)); + dataTypes.put(Byte.class, 0); + dataTypes.put(Short.class, 1); + dataTypes.put(Integer.class, 2); + dataTypes.put(Float.class, 3); + dataTypes.put(String.class, 4); + dataTypes.put(ItemStack.class, 5); + dataTypes.put(BlockPos.class, 6); + dataTypes.put(Rotations.class, 7); } public static class WatchableObject { diff --git a/src/game/java/net/minecraft/entity/Entity.java b/src/game/java/net/minecraft/entity/Entity.java index 7f425102..bf3ddbe2 100755 --- a/src/game/java/net/minecraft/entity/Entity.java +++ b/src/game/java/net/minecraft/entity/Entity.java @@ -61,7 +61,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityAgeable.java b/src/game/java/net/minecraft/entity/EntityAgeable.java index e29afbf8..0d3f4d06 100755 --- a/src/game/java/net/minecraft/entity/EntityAgeable.java +++ b/src/game/java/net/minecraft/entity/EntityAgeable.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityBodyHelper.java b/src/game/java/net/minecraft/entity/EntityBodyHelper.java index b09daf83..d5d26198 100755 --- a/src/game/java/net/minecraft/entity/EntityBodyHelper.java +++ b/src/game/java/net/minecraft/entity/EntityBodyHelper.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityCreature.java b/src/game/java/net/minecraft/entity/EntityCreature.java index 1531d327..1e3b0fff 100755 --- a/src/game/java/net/minecraft/entity/EntityCreature.java +++ b/src/game/java/net/minecraft/entity/EntityCreature.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityFlying.java b/src/game/java/net/minecraft/entity/EntityFlying.java index e924667c..86e2fbaf 100755 --- a/src/game/java/net/minecraft/entity/EntityFlying.java +++ b/src/game/java/net/minecraft/entity/EntityFlying.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityHanging.java b/src/game/java/net/minecraft/entity/EntityHanging.java index ab3cee45..15cc291d 100755 --- a/src/game/java/net/minecraft/entity/EntityHanging.java +++ b/src/game/java/net/minecraft/entity/EntityHanging.java @@ -20,7 +20,7 @@ import org.apache.commons.lang3.Validate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityLeashKnot.java b/src/game/java/net/minecraft/entity/EntityLeashKnot.java index fcff343b..7bf9f3e3 100755 --- a/src/game/java/net/minecraft/entity/EntityLeashKnot.java +++ b/src/game/java/net/minecraft/entity/EntityLeashKnot.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityList.java b/src/game/java/net/minecraft/entity/EntityList.java index 8e92fb0d..a5009a02 100755 --- a/src/game/java/net/minecraft/entity/EntityList.java +++ b/src/game/java/net/minecraft/entity/EntityList.java @@ -5,6 +5,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -86,7 +90,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -106,13 +110,19 @@ public class EntityList { private static final Map> stringToConstructorMapping = Maps .newHashMap(); private static final Map, String> classToStringMapping = Maps.newHashMap(); - private static final Map> idToClassMapping = Maps.newHashMap(); - private static final Map> idToConstructorMapping = Maps.newHashMap(); - private static final Map, Integer> classToIDMapping = Maps.newHashMap(); + private static final IntObjectMap> idToClassMapping = new IntObjectHashMap<>(); + private static final IntObjectMap> idToConstructorMapping = new IntObjectHashMap<>(); + private static final ObjectIntMap> classToIDMapping = new ObjectIntHashMap<>(); private static final Map, EntityConstructor> classToConstructorMapping = Maps .newHashMap(); - private static final Map stringToIDMapping = Maps.newHashMap(); - public static final Map entityEggs = Maps.newLinkedHashMap(); + /**+ + * provides a mapping between a string and an entity ID + */ + private static final ObjectIntMap stringToIDMapping = new ObjectIntHashMap<>(); + /**+ + * This is a HashMap of the Creative Entity Eggs/Spawners. + */ + public static final IntObjectMap entityEggs = new IntObjectHashMap<>(); /**+ * adds a mapping between Entity classes and both a string @@ -122,7 +132,7 @@ public class EntityList { EntityConstructor entityConstructor, String entityName, int id) { if (stringToClassMapping.containsKey(entityName)) { throw new IllegalArgumentException("ID is already registered: " + entityName); - } else if (idToClassMapping.containsKey(Integer.valueOf(id))) { + } else if (idToClassMapping.containsKey(id)) { throw new IllegalArgumentException("ID is already registered: " + id); } else if (id == 0) { throw new IllegalArgumentException("Cannot register to reserved id: " + id); @@ -132,11 +142,11 @@ public class EntityList { stringToClassMapping.put(entityName, entityClass); stringToConstructorMapping.put(entityName, entityConstructor); classToStringMapping.put(entityClass, entityName); - idToClassMapping.put(Integer.valueOf(id), entityClass); - idToConstructorMapping.put(Integer.valueOf(id), entityConstructor); - classToIDMapping.put(entityClass, Integer.valueOf(id)); + idToClassMapping.put(id, entityClass); + idToConstructorMapping.put(id, entityConstructor); + classToIDMapping.put(entityClass, id); classToConstructorMapping.put(entityClass, entityConstructor); - stringToIDMapping.put(entityName, Integer.valueOf(id)); + stringToIDMapping.put(entityName, id); } } @@ -148,7 +158,7 @@ public class EntityList { EntityConstructor entityConstructor, String entityName, int entityID, int baseColor, int spotColor) { addMapping(entityClass, entityConstructor, entityName, entityID); - entityEggs.put(Integer.valueOf(entityID), new EntityList.EntityEggInfo(entityID, baseColor, spotColor)); + entityEggs.put(entityID, new EntityList.EntityEggInfo(entityID, baseColor, spotColor)); } /**+ @@ -248,31 +258,31 @@ public class EntityList { * gets the entityID of a specific entity */ public static int getEntityID(Entity entityIn) { - Integer integer = (Integer) classToIDMapping.get(entityIn.getClass()); - return integer == null ? 0 : integer.intValue(); + int integer = classToIDMapping.getOrDefault(entityIn.getClass(), -1); + return integer == -1 ? 0 : integer; } public static Class getClassFromID(int entityID) { - return (Class) idToClassMapping.get(Integer.valueOf(entityID)); + return idToClassMapping.get(entityID); } public static EntityConstructor getConstructorFromID(int entityID) { - return idToConstructorMapping.get(Integer.valueOf(entityID)); + return idToConstructorMapping.get(entityID); } /**+ * Gets the string representation of a specific entity. */ public static String getEntityString(Entity entityIn) { - return (String) classToStringMapping.get(entityIn.getClass()); + return classToStringMapping.get(entityIn.getClass()); } /**+ * Returns the ID assigned to it's string representation */ public static int getIDFromString(String entityName) { - Integer integer = (Integer) stringToIDMapping.get(entityName); - return integer == null ? 90 : integer.intValue(); + int integer = stringToIDMapping.getOrDefault(entityName, -1); + return integer == -1 ? 90 : integer; } /**+ @@ -280,7 +290,7 @@ public class EntityList { * classToStringMapping */ public static String getStringFromID(int entityID) { - return (String) classToStringMapping.get(getClassFromID(entityID)); + return classToStringMapping.get(getClassFromID(entityID)); } public static void func_151514_a() { diff --git a/src/game/java/net/minecraft/entity/EntityLiving.java b/src/game/java/net/minecraft/entity/EntityLiving.java index d4647ee1..c77ecffe 100755 --- a/src/game/java/net/minecraft/entity/EntityLiving.java +++ b/src/game/java/net/minecraft/entity/EntityLiving.java @@ -44,7 +44,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityLivingBase.java b/src/game/java/net/minecraft/entity/EntityLivingBase.java index b97a83b4..8988067f 100755 --- a/src/game/java/net/minecraft/entity/EntityLivingBase.java +++ b/src/game/java/net/minecraft/entity/EntityLivingBase.java @@ -1,13 +1,14 @@ package net.minecraft.entity; +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.google.common.base.Predicate; import com.google.common.base.Predicates; -import com.google.common.collect.Maps; - -import java.util.Collection; -import java.util.Iterator; import java.util.List; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.minecraft.block.Block; @@ -59,7 +60,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -80,7 +81,7 @@ public abstract class EntityLivingBase extends Entity { sprintingSpeedBoostModifierUUID, "Sprinting speed boost", 0.30000001192092896D, 2)).setSaved(false); private BaseAttributeMap attributeMap; private final CombatTracker _combatTracker = new CombatTracker(this); - private final Map activePotionsMap = Maps.newHashMap(); + private final IntObjectMap activePotionsMap = new IntObjectHashMap<>(); /**+ * The equipment this mob was previously wearing, used for * syncing. @@ -448,8 +449,8 @@ public abstract class EntityLivingBase extends Entity { if (!this.activePotionsMap.isEmpty()) { NBTTagList nbttaglist = new NBTTagList(); - for (PotionEffect potioneffect : this.activePotionsMap.values()) { - nbttaglist.appendTag(potioneffect.writeCustomPotionEffectToNBT(new NBTTagCompound())); + for (ObjectCursor potioneffect : this.activePotionsMap.values()) { + nbttaglist.appendTag(potioneffect.value.writeCustomPotionEffectToNBT(new NBTTagCompound())); } nbttagcompound.setTag("ActiveEffects", nbttaglist); @@ -474,7 +475,7 @@ public abstract class EntityLivingBase extends Entity { NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); PotionEffect potioneffect = PotionEffect.readCustomPotionEffectFromNBT(nbttagcompound1); if (potioneffect != null) { - this.activePotionsMap.put(Integer.valueOf(potioneffect.getPotionID()), potioneffect); + this.activePotionsMap.put(potioneffect.getPotionID(), potioneffect); } } } @@ -498,14 +499,16 @@ public abstract class EntityLivingBase extends Entity { } protected void updatePotionEffects() { - Iterator iterator = this.activePotionsMap.keySet().iterator(); + IntArrayList deadPotionEffects = null; - while (iterator.hasNext()) { - Integer integer = (Integer) iterator.next(); - PotionEffect potioneffect = (PotionEffect) this.activePotionsMap.get(integer); + for (IntObjectCursor cur : this.activePotionsMap) { + int integer = cur.key; + PotionEffect potioneffect = cur.value; if (!potioneffect.onUpdate(this)) { if (!this.worldObj.isRemote) { - iterator.remove(); + if (deadPotionEffects == null) + deadPotionEffects = new IntArrayList(4); + deadPotionEffects.add(integer); this.onFinishedPotionEffect(potioneffect); } } else if (potioneffect.getDuration() % 600 == 0) { @@ -513,6 +516,10 @@ public abstract class EntityLivingBase extends Entity { } } + if (deadPotionEffects != null) { + this.activePotionsMap.removeAll(deadPotionEffects); + } + if (this.potionsNeedUpdate) { if (!this.worldObj.isRemote) { this.updatePotionMetadata(); @@ -558,9 +565,9 @@ public abstract class EntityLivingBase extends Entity { this.resetPotionEffectMetadata(); this.setInvisible(false); } else { - int i = PotionHelper.calcPotionLiquidColor(this.activePotionsMap.values()); - this.dataWatcher.updateObject(8, - Byte.valueOf((byte) (PotionHelper.getAreAmbient(this.activePotionsMap.values()) ? 1 : 0))); + ObjectContainer cc = this.activePotionsMap.values(); + int i = PotionHelper.calcPotionLiquidColor(cc); + this.dataWatcher.updateObject(8, Byte.valueOf((byte) (PotionHelper.getAreAmbient(cc) ? 1 : 0))); this.dataWatcher.updateObject(7, Integer.valueOf(i)); this.setInvisible(this.isPotionActive(Potion.invisibility.id)); } @@ -576,29 +583,28 @@ public abstract class EntityLivingBase extends Entity { } public void clearActivePotions() { - Iterator iterator = this.activePotionsMap.keySet().iterator(); - - while (iterator.hasNext()) { - Integer integer = (Integer) iterator.next(); - PotionEffect potioneffect = (PotionEffect) this.activePotionsMap.get(integer); + for (ObjectCursor cur : activePotionsMap.values()) { + PotionEffect potioneffect = cur.value; if (!this.worldObj.isRemote) { - iterator.remove(); this.onFinishedPotionEffect(potioneffect); } } + if (!this.worldObj.isRemote) { + activePotionsMap.clear(); + } } - public Collection getActivePotionEffects() { + public ObjectContainer getActivePotionEffects() { return this.activePotionsMap.values(); } public boolean isPotionActive(int potionId) { - return this.activePotionsMap.containsKey(Integer.valueOf(potionId)); + return this.activePotionsMap.containsKey(potionId); } public boolean isPotionActive(Potion potionIn) { - return this.activePotionsMap.containsKey(Integer.valueOf(potionIn.id)); + return this.activePotionsMap.containsKey(potionIn.id); } /**+ @@ -606,7 +612,7 @@ public abstract class EntityLivingBase extends Entity { * active, null otherwise. */ public PotionEffect getActivePotionEffect(Potion potionIn) { - return (PotionEffect) this.activePotionsMap.get(Integer.valueOf(potionIn.id)); + return this.activePotionsMap.get(potionIn.id); } /**+ @@ -614,13 +620,11 @@ public abstract class EntityLivingBase extends Entity { */ public void addPotionEffect(PotionEffect potioneffectIn) { if (this.isPotionApplicable(potioneffectIn)) { - if (this.activePotionsMap.containsKey(Integer.valueOf(potioneffectIn.getPotionID()))) { - ((PotionEffect) this.activePotionsMap.get(Integer.valueOf(potioneffectIn.getPotionID()))) - .combine(potioneffectIn); - this.onChangedPotionEffect( - (PotionEffect) this.activePotionsMap.get(Integer.valueOf(potioneffectIn.getPotionID())), true); + if (this.activePotionsMap.containsKey(potioneffectIn.getPotionID())) { + this.activePotionsMap.get(potioneffectIn.getPotionID()).combine(potioneffectIn); + this.onChangedPotionEffect(this.activePotionsMap.get(potioneffectIn.getPotionID()), true); } else { - this.activePotionsMap.put(Integer.valueOf(potioneffectIn.getPotionID()), potioneffectIn); + this.activePotionsMap.put(potioneffectIn.getPotionID(), potioneffectIn); this.onNewPotionEffect(potioneffectIn); } @@ -649,14 +653,14 @@ public abstract class EntityLivingBase extends Entity { * Remove the speified potion effect from this entity. */ public void removePotionEffectClient(int potionId) { - this.activePotionsMap.remove(Integer.valueOf(potionId)); + this.activePotionsMap.remove(potionId); } /**+ * Remove the specified potion effect from this entity. */ public void removePotionEffect(int potionId) { - PotionEffect potioneffect = (PotionEffect) this.activePotionsMap.remove(Integer.valueOf(potionId)); + PotionEffect potioneffect = this.activePotionsMap.remove(potionId); if (potioneffect != null) { this.onFinishedPotionEffect(potioneffect); } diff --git a/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java b/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java index 51bae457..d6c2dba0 100755 --- a/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java +++ b/src/game/java/net/minecraft/entity/EntityMinecartCommandBlock.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java b/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java index 8a59a7a4..ba70a210 100755 --- a/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java +++ b/src/game/java/net/minecraft/entity/EntitySpawnPlacementRegistry.java @@ -43,7 +43,7 @@ import net.minecraft.entity.passive.EntityWolf; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EntityTracker.java b/src/game/java/net/minecraft/entity/EntityTracker.java index f4d0cc62..a153d491 100755 --- a/src/game/java/net/minecraft/entity/EntityTracker.java +++ b/src/game/java/net/minecraft/entity/EntityTracker.java @@ -1,5 +1,7 @@ package net.minecraft.entity; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.ArrayList; @@ -33,7 +35,6 @@ import net.minecraft.entity.projectile.EntityPotion; import net.minecraft.entity.projectile.EntitySmallFireball; import net.minecraft.entity.projectile.EntitySnowball; import net.minecraft.network.Packet; -import net.minecraft.util.IntHashMap; import net.minecraft.util.ReportedException; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; @@ -46,7 +47,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -71,7 +72,7 @@ public class EntityTracker { /**+ * Used for identity lookup of tracked entities. */ - private IntHashMap trackedEntityHashTable = new IntHashMap(); + private IntObjectMap trackedEntityHashTable = new IntObjectHashMap<>(); private int maxTrackingDistanceThreshold; public EntityTracker(WorldServer theWorldIn) { @@ -80,6 +81,10 @@ public class EntityTracker { .getEntityViewDistance(); } + public void updateMaxTrackingThreshold(int dist) { + maxTrackingDistanceThreshold = dist; + } + public void trackEntity(Entity parEntity) { if (parEntity instanceof EntityPlayerMP) { this.trackEntity(parEntity, 512, 2); @@ -87,7 +92,7 @@ public class EntityTracker { for (EntityTrackerEntry entitytrackerentry : this.trackedEntities) { if (entitytrackerentry.trackedEntity != entityplayermp) { - entitytrackerentry.updatePlayerEntity(entityplayermp); + entitytrackerentry.updatePlayerEntity(entityplayermp, maxTrackingDistanceThreshold); } } } else if (parEntity instanceof EntityFishHook) { @@ -154,20 +159,16 @@ public class EntityTracker { */ public void addEntityToTracker(Entity entityIn, int trackingRange, final int updateFrequency, boolean sendVelocityUpdates) { - if (trackingRange > this.maxTrackingDistanceThreshold) { - trackingRange = this.maxTrackingDistanceThreshold; - } - try { - if (this.trackedEntityHashTable.containsItem(entityIn.getEntityId())) { + if (this.trackedEntityHashTable.containsKey(entityIn.getEntityId())) { throw new IllegalStateException("Entity is already tracked!"); } EntityTrackerEntry entitytrackerentry = new EntityTrackerEntry(entityIn, trackingRange, updateFrequency, sendVelocityUpdates); this.trackedEntities.add(entitytrackerentry); - this.trackedEntityHashTable.addKey(entityIn.getEntityId(), entitytrackerentry); - entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities); + this.trackedEntityHashTable.put(entityIn.getEntityId(), entitytrackerentry); + entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities, maxTrackingDistanceThreshold); } catch (Throwable throwable) { CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Adding entity to track"); CrashReportCategory crashreportcategory = crashreport.makeCategory("Entity To Track"); @@ -184,7 +185,7 @@ public class EntityTracker { }); entityIn.addEntityCrashInfo(crashreportcategory); CrashReportCategory crashreportcategory1 = crashreport.makeCategory("Entity That Is Already Tracked"); - ((EntityTrackerEntry) this.trackedEntityHashTable.lookup(entityIn.getEntityId())).trackedEntity + this.trackedEntityHashTable.get(entityIn.getEntityId()).trackedEntity .addEntityCrashInfo(crashreportcategory1); try { @@ -205,8 +206,7 @@ public class EntityTracker { } } - EntityTrackerEntry entitytrackerentry1 = (EntityTrackerEntry) this.trackedEntityHashTable - .removeObject(entityIn.getEntityId()); + EntityTrackerEntry entitytrackerentry1 = this.trackedEntityHashTable.remove(entityIn.getEntityId()); if (entitytrackerentry1 != null) { this.trackedEntities.remove(entitytrackerentry1); entitytrackerentry1.sendDestroyEntityPacketToTrackedPlayers(); @@ -218,7 +218,7 @@ public class EntityTracker { ArrayList arraylist = Lists.newArrayList(); for (EntityTrackerEntry entitytrackerentry : this.trackedEntities) { - entitytrackerentry.updatePlayerList(this.theWorld.playerEntities); + entitytrackerentry.updatePlayerList(this.theWorld.playerEntities, maxTrackingDistanceThreshold); if (entitytrackerentry.playerEntitiesUpdated && entitytrackerentry.trackedEntity instanceof EntityPlayerMP) { arraylist.add((EntityPlayerMP) entitytrackerentry.trackedEntity); @@ -230,7 +230,7 @@ public class EntityTracker { for (EntityTrackerEntry entitytrackerentry1 : this.trackedEntities) { if (entitytrackerentry1.trackedEntity != entityplayermp) { - entitytrackerentry1.updatePlayerEntity(entityplayermp); + entitytrackerentry1.updatePlayerEntity(entityplayermp, maxTrackingDistanceThreshold); } } } @@ -240,17 +240,16 @@ public class EntityTracker { public void func_180245_a(EntityPlayerMP parEntityPlayerMP) { for (EntityTrackerEntry entitytrackerentry : this.trackedEntities) { if (entitytrackerentry.trackedEntity == parEntityPlayerMP) { - entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities); + entitytrackerentry.updatePlayerEntities(this.theWorld.playerEntities, maxTrackingDistanceThreshold); } else { - entitytrackerentry.updatePlayerEntity(parEntityPlayerMP); + entitytrackerentry.updatePlayerEntity(parEntityPlayerMP, maxTrackingDistanceThreshold); } } } public void sendToAllTrackingEntity(Entity entityIn, Packet parPacket) { - EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntityHashTable - .lookup(entityIn.getEntityId()); + EntityTrackerEntry entitytrackerentry = this.trackedEntityHashTable.get(entityIn.getEntityId()); if (entitytrackerentry != null) { entitytrackerentry.sendPacketToTrackedPlayers(parPacket); } @@ -258,8 +257,7 @@ public class EntityTracker { } public void func_151248_b(Entity entityIn, Packet parPacket) { - EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) this.trackedEntityHashTable - .lookup(entityIn.getEntityId()); + EntityTrackerEntry entitytrackerentry = this.trackedEntityHashTable.get(entityIn.getEntityId()); if (entitytrackerentry != null) { entitytrackerentry.func_151261_b(parPacket); } @@ -278,7 +276,7 @@ public class EntityTracker { if (entitytrackerentry.trackedEntity != parEntityPlayerMP && entitytrackerentry.trackedEntity.chunkCoordX == parChunk.xPosition && entitytrackerentry.trackedEntity.chunkCoordZ == parChunk.zPosition) { - entitytrackerentry.updatePlayerEntity(parEntityPlayerMP); + entitytrackerentry.updatePlayerEntity(parEntityPlayerMP, maxTrackingDistanceThreshold); } } diff --git a/src/game/java/net/minecraft/entity/EntityTrackerEntry.java b/src/game/java/net/minecraft/entity/EntityTrackerEntry.java index dd7e2cc2..33b37247 100755 --- a/src/game/java/net/minecraft/entity/EntityTrackerEntry.java +++ b/src/game/java/net/minecraft/entity/EntityTrackerEntry.java @@ -1,5 +1,6 @@ package net.minecraft.entity; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Sets; import java.util.Collection; import java.util.List; @@ -65,7 +66,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -135,7 +136,7 @@ public class EntityTrackerEntry { return this.trackedEntity.getEntityId(); } - public void updatePlayerList(List parList) { + public void updatePlayerList(List parList, int trackingDistanceMax) { this.playerEntitiesUpdated = false; if (!this.firstUpdateDone || this.trackedEntity.getDistanceSq(this.lastTrackedEntityPosX, this.lastTrackedEntityPosY, this.lastTrackedEntityPosZ) > 16.0D) { @@ -144,7 +145,7 @@ public class EntityTrackerEntry { this.lastTrackedEntityPosZ = this.trackedEntity.posZ; this.firstUpdateDone = true; this.playerEntitiesUpdated = true; - this.updatePlayerEntities(parList); + this.updatePlayerEntities(parList, trackingDistanceMax); } if (this.field_85178_v != this.trackedEntity.ridingEntity @@ -341,9 +342,9 @@ public class EntityTrackerEntry { } - public void updatePlayerEntity(EntityPlayerMP playerMP) { + public void updatePlayerEntity(EntityPlayerMP playerMP, int trackingDistanceMax) { if (playerMP != this.trackedEntity) { - if (this.func_180233_c(playerMP)) { + if (this.func_180233_c(playerMP, trackingDistanceMax)) { if (!this.trackingPlayers.contains(playerMP) && (this.isPlayerWatchingThisChunk(playerMP) || this.trackedEntity.forceSpawn)) { this.trackingPlayers.add(playerMP); @@ -408,12 +409,17 @@ public class EntityTrackerEntry { } } + this.lastHeadMotion = MathHelper + .floor_float(this.trackedEntity.getRotationYawHead() * 256.0F / 360.0F); + playerMP.playerNetServerHandler + .sendPacket(new S19PacketEntityHeadLook(this.trackedEntity, (byte) lastHeadMotion)); + if (this.trackedEntity instanceof EntityLivingBase) { EntityLivingBase entitylivingbase = (EntityLivingBase) this.trackedEntity; - for (PotionEffect potioneffect : entitylivingbase.getActivePotionEffects()) { + for (ObjectCursor potioneffect : entitylivingbase.getActivePotionEffects()) { playerMP.playerNetServerHandler.sendPacket( - new S1DPacketEntityEffect(this.trackedEntity.getEntityId(), potioneffect)); + new S1DPacketEntityEffect(this.trackedEntity.getEntityId(), potioneffect.value)); } } } @@ -425,11 +431,11 @@ public class EntityTrackerEntry { } } - public boolean func_180233_c(EntityPlayerMP playerMP) { + public boolean func_180233_c(EntityPlayerMP playerMP, int trackingDistanceMax) { + int i = trackingDistanceThreshold > trackingDistanceMax ? trackingDistanceMax : trackingDistanceThreshold; double d0 = playerMP.posX - (double) (this.encodedPosX / 32); double d1 = playerMP.posZ - (double) (this.encodedPosZ / 32); - return d0 >= (double) (-this.trackingDistanceThreshold) && d0 <= (double) this.trackingDistanceThreshold - && d1 >= (double) (-this.trackingDistanceThreshold) && d1 <= (double) this.trackingDistanceThreshold + return d0 >= (double) (-i) && d0 <= (double) i && d1 >= (double) (-i) && d1 <= (double) i && this.trackedEntity.isSpectatedByPlayer(playerMP); } @@ -438,9 +444,9 @@ public class EntityTrackerEntry { this.trackedEntity.chunkCoordX, this.trackedEntity.chunkCoordZ); } - public void updatePlayerEntities(List parList) { + public void updatePlayerEntities(List parList, int trackingDistanceMax) { for (int i = 0; i < parList.size(); ++i) { - this.updatePlayerEntity((EntityPlayerMP) parList.get(i)); + this.updatePlayerEntity((EntityPlayerMP) parList.get(i), trackingDistanceMax); } } diff --git a/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java b/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java index 16d86954..d223cfec 100755 --- a/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java +++ b/src/game/java/net/minecraft/entity/EnumCreatureAttribute.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/EnumCreatureType.java b/src/game/java/net/minecraft/entity/EnumCreatureType.java index 37f92b69..02d17815 100755 --- a/src/game/java/net/minecraft/entity/EnumCreatureType.java +++ b/src/game/java/net/minecraft/entity/EnumCreatureType.java @@ -13,7 +13,7 @@ import net.minecraft.entity.passive.IAnimals; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/IEntityLivingData.java b/src/game/java/net/minecraft/entity/IEntityLivingData.java index e3996e76..5777e28c 100755 --- a/src/game/java/net/minecraft/entity/IEntityLivingData.java +++ b/src/game/java/net/minecraft/entity/IEntityLivingData.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/IEntityMultiPart.java b/src/game/java/net/minecraft/entity/IEntityMultiPart.java index 98f6450c..1b4e90c8 100755 --- a/src/game/java/net/minecraft/entity/IEntityMultiPart.java +++ b/src/game/java/net/minecraft/entity/IEntityMultiPart.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/IEntityOwnable.java b/src/game/java/net/minecraft/entity/IEntityOwnable.java index 33d5e5c9..53de9986 100755 --- a/src/game/java/net/minecraft/entity/IEntityOwnable.java +++ b/src/game/java/net/minecraft/entity/IEntityOwnable.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/IMerchant.java b/src/game/java/net/minecraft/entity/IMerchant.java index 06572465..7fb2fd39 100755 --- a/src/game/java/net/minecraft/entity/IMerchant.java +++ b/src/game/java/net/minecraft/entity/IMerchant.java @@ -12,7 +12,7 @@ import net.minecraft.village.MerchantRecipeList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/INpc.java b/src/game/java/net/minecraft/entity/INpc.java index 48f64e07..42541f0b 100755 --- a/src/game/java/net/minecraft/entity/INpc.java +++ b/src/game/java/net/minecraft/entity/INpc.java @@ -8,7 +8,7 @@ import net.minecraft.entity.passive.IAnimals; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/IProjectile.java b/src/game/java/net/minecraft/entity/IProjectile.java index d5253c33..36ef7045 100755 --- a/src/game/java/net/minecraft/entity/IProjectile.java +++ b/src/game/java/net/minecraft/entity/IProjectile.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/IRangedAttackMob.java b/src/game/java/net/minecraft/entity/IRangedAttackMob.java index 32f8d215..1a6533bb 100755 --- a/src/game/java/net/minecraft/entity/IRangedAttackMob.java +++ b/src/game/java/net/minecraft/entity/IRangedAttackMob.java @@ -6,7 +6,7 @@ package net.minecraft.entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/NpcMerchant.java b/src/game/java/net/minecraft/entity/NpcMerchant.java index f3405bcd..0bea600d 100755 --- a/src/game/java/net/minecraft/entity/NpcMerchant.java +++ b/src/game/java/net/minecraft/entity/NpcMerchant.java @@ -14,7 +14,7 @@ import net.minecraft.village.MerchantRecipeList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java b/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java index 8271e78a..f7faed50 100755 --- a/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java +++ b/src/game/java/net/minecraft/entity/SharedMonsterAttributes.java @@ -19,7 +19,7 @@ import net.minecraft.nbt.NBTTagList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java b/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java index f23ac1d5..91257053 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIArrowAttack.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java b/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java index 97a8b0ea..b1f4e28a 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIAttackOnCollide.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java b/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java index 67950828..cdb4665b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIAvoidEntity.java @@ -16,7 +16,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIBase.java b/src/game/java/net/minecraft/entity/ai/EntityAIBase.java index d9f6c2c5..5c478093 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIBase.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIBase.java @@ -6,7 +6,7 @@ package net.minecraft.entity.ai; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java b/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java index df94cc69..56188a19 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIBeg.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java b/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java index 80ba3a65..5ebba8ed 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIBreakDoor.java @@ -11,7 +11,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java index 1e128497..73e07c25 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIControlledByPlayer.java @@ -19,7 +19,7 @@ import net.minecraft.world.pathfinder.WalkNodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java b/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java index d9f01f16..a72daef1 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAICreeperSwell.java @@ -9,7 +9,7 @@ import net.minecraft.entity.monster.EntityCreeper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java b/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java index adb084f2..da0e4396 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIDefendVillage.java @@ -11,7 +11,7 @@ import net.minecraft.village.Village; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java b/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java index a5c72684..0e749ece 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIDoorInteract.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java b/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java index 0bf054c5..1b788577 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIEatGrass.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java index 3b8dc468..6d2a6a53 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearest.java @@ -18,7 +18,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java index b43b52f7..9d7ff921 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFindEntityNearestPlayer.java @@ -21,7 +21,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java b/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java index b0c51b14..184ba855 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFleeSun.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java b/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java index b4e6877b..2cabd798 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFollowGolem.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntityVillager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java b/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java index 07f06604..242d8569 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFollowOwner.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java b/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java index 7b990e05..2dfe6858 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIFollowParent.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityAnimal; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java b/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java index d6bb164d..29bada5f 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIHarvestFarmland.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java index 2498cb7b..9ea86428 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIHurtByTarget.java @@ -12,7 +12,7 @@ import net.minecraft.util.AxisAlignedBB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java index 695cdd83..f965a743 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILeapAtTarget.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java index ed60bde1..02465619 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILookAtTradePlayer.java @@ -9,7 +9,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java b/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java index d68ab45b..8a8c4d8e 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILookAtVillager.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityVillager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java b/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java index 6ffd0511..528df41f 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAILookIdle.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMate.java b/src/game/java/net/minecraft/entity/ai/EntityAIMate.java index 8b85b0e5..94bc9b2e 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMate.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMate.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java index b55d695d..8d4da2d9 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveIndoors.java @@ -12,7 +12,7 @@ import net.minecraft.village.VillageDoorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java index 1fe2dc9b..842e2aad 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveThroughVillage.java @@ -17,7 +17,7 @@ import net.minecraft.village.VillageDoorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java index 5c4555bd..10e9ec62 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveToBlock.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java index 5060779c..4a0749b6 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsRestriction.java @@ -10,7 +10,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java index 7687d5c0..66df2221 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIMoveTowardsTarget.java @@ -10,7 +10,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java index 1dc84c63..0238cb5b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAINearestAttackableTarget.java @@ -17,7 +17,7 @@ import net.minecraft.util.EntitySelectors; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java index 59e1707f..6e9d8154 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotAttack.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java index 0fb7cd76..1be6bef6 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOcelotSit.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java b/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java index af197f04..9c172ce5 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOpenDoor.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java index 5bd52e9d..a8edf950 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtByTarget.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java index d4887688..0d85205c 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIOwnerHurtTarget.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java b/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java index 5c48292c..9e832e96 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIPanic.java @@ -9,7 +9,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java b/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java index e85cbbea..5f69f619 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIPlay.java @@ -11,7 +11,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java index abf27574..d08b1e41 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictOpenDoor.java @@ -12,7 +12,7 @@ import net.minecraft.village.VillageDoorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java index a1ea8d29..71ed47f5 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIRestrictSun.java @@ -9,7 +9,7 @@ import net.minecraft.pathfinding.PathNavigateGround; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java b/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java index 51d594dc..d1f59917 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIRunAroundLikeCrazy.java @@ -11,7 +11,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAISit.java b/src/game/java/net/minecraft/entity/ai/EntityAISit.java index 0a8cdfc9..5c8ca4af 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAISit.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAISit.java @@ -9,7 +9,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java b/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java index 59640d89..79a39b28 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAISwimming.java @@ -9,7 +9,7 @@ import net.minecraft.pathfinding.PathNavigateGround; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITarget.java b/src/game/java/net/minecraft/entity/ai/EntityAITarget.java index 99a647d1..110af459 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITarget.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITarget.java @@ -21,7 +21,7 @@ import org.apache.commons.lang3.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java b/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java index 123b8f93..615da1c3 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITargetNonTamed.java @@ -10,7 +10,7 @@ import net.minecraft.entity.passive.EntityTameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITasks.java b/src/game/java/net/minecraft/entity/ai/EntityAITasks.java index ceb0f232..389843e2 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITasks.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITasks.java @@ -12,7 +12,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITempt.java b/src/game/java/net/minecraft/entity/ai/EntityAITempt.java index 4401858d..517c049c 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITempt.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITempt.java @@ -12,7 +12,7 @@ import net.minecraft.pathfinding.PathNavigateGround; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java b/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java index bc98b8f2..191641d5 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAITradePlayer.java @@ -10,7 +10,7 @@ import net.minecraft.inventory.Container; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java index 350edb36..5c1b14e2 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerInteract.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java index ea4622a4..11ea8b6b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIVillagerMate.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIWander.java b/src/game/java/net/minecraft/entity/ai/EntityAIWander.java index 83b2f3fe..a351b3a6 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIWander.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIWander.java @@ -9,7 +9,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java index 74e79dc5..befbc597 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest.java @@ -10,7 +10,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java index 6f716971..ed5f042b 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java +++ b/src/game/java/net/minecraft/entity/ai/EntityAIWatchClosest2.java @@ -9,7 +9,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java b/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java index 69f8d637..9e364aca 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java +++ b/src/game/java/net/minecraft/entity/ai/EntityJumpHelper.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java b/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java index 23cbbee6..ae07e749 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java +++ b/src/game/java/net/minecraft/entity/ai/EntityLookHelper.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java b/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java index 53b72e30..63099b73 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java +++ b/src/game/java/net/minecraft/entity/ai/EntityMinecartMobSpawner.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java b/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java index 3aaa53db..a05c12b2 100755 --- a/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java +++ b/src/game/java/net/minecraft/entity/ai/EntityMoveHelper.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/EntitySenses.java b/src/game/java/net/minecraft/entity/ai/EntitySenses.java index df71fe85..e4052b07 100755 --- a/src/game/java/net/minecraft/entity/ai/EntitySenses.java +++ b/src/game/java/net/minecraft/entity/ai/EntitySenses.java @@ -11,7 +11,7 @@ import net.minecraft.entity.EntityLiving; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java b/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java index 0caab242..660e918d 100755 --- a/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java +++ b/src/game/java/net/minecraft/entity/ai/RandomPositionGenerator.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java b/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java index 1354318e..0a5ccc13 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/AttributeModifier.java @@ -13,7 +13,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java index e1c1ca80..a0ca26f7 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttribute.java @@ -6,7 +6,7 @@ package net.minecraft.entity.ai.attributes; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java index 4bd85ac5..32b3d6c6 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/BaseAttributeMap.java @@ -16,7 +16,7 @@ import net.minecraft.server.management.LowerStringMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java b/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java index dc97bd0c..bfd6e322 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/IAttribute.java @@ -6,7 +6,7 @@ package net.minecraft.entity.ai.attributes; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java b/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java index f6db33c0..24af7de4 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/IAttributeInstance.java @@ -9,7 +9,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java b/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java index a14e3d0b..bcf11df5 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java @@ -7,6 +7,8 @@ import java.util.Map; import java.util.Set; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -17,7 +19,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -34,7 +36,7 @@ import com.google.common.collect.Sets; public class ModifiableAttributeInstance implements IAttributeInstance { private final BaseAttributeMap attributeMap; private final IAttribute genericAttribute; - private final Map> mapByOperation = Maps.newHashMap(); + private final IntObjectMap> mapByOperation = new IntObjectHashMap<>(); private final Map> mapByName = Maps.newHashMap(); private final Map mapByUUID = Maps.newHashMap(); private double baseValue; @@ -47,7 +49,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { this.baseValue = genericAttributeIn.getDefaultValue(); for (int i = 0; i < 3; ++i) { - this.mapByOperation.put(Integer.valueOf(i), Sets.newHashSet()); + this.mapByOperation.put(i, Sets.newHashSet()); } } @@ -71,7 +73,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { } public Collection getModifiersByOperation(int i) { - return (Collection) this.mapByOperation.get(Integer.valueOf(i)); + return this.mapByOperation.get(i); } public Collection func_111122_c() { @@ -105,7 +107,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { this.mapByName.put(attributemodifier.getName(), object); } - ((Set) this.mapByOperation.get(Integer.valueOf(attributemodifier.getOperation()))).add(attributemodifier); + ((Set) this.mapByOperation.get(attributemodifier.getOperation())).add(attributemodifier); ((Set) object).add(attributemodifier); this.mapByUUID.put(attributemodifier.getID(), attributemodifier); this.flagForUpdate(); @@ -119,7 +121,7 @@ public class ModifiableAttributeInstance implements IAttributeInstance { public void removeModifier(AttributeModifier attributemodifier) { for (int i = 0; i < 3; ++i) { - Set set = (Set) this.mapByOperation.get(Integer.valueOf(i)); + Set set = (Set) this.mapByOperation.get(i); set.remove(attributemodifier); } diff --git a/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java b/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java index 7a9d4a88..ad2d8f70 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/RangedAttribute.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java b/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java index 1d4e627f..2fd95192 100755 --- a/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java +++ b/src/game/java/net/minecraft/entity/ai/attributes/ServersideAttributeMap.java @@ -13,7 +13,7 @@ import net.minecraft.server.management.LowerStringMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/boss/BossStatus.java b/src/game/java/net/minecraft/entity/boss/BossStatus.java index 4883624d..1e1be893 100755 --- a/src/game/java/net/minecraft/entity/boss/BossStatus.java +++ b/src/game/java/net/minecraft/entity/boss/BossStatus.java @@ -6,7 +6,7 @@ package net.minecraft.entity.boss; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/boss/EntityDragon.java b/src/game/java/net/minecraft/entity/boss/EntityDragon.java index d2bbe1cf..d5dcd8ef 100755 --- a/src/game/java/net/minecraft/entity/boss/EntityDragon.java +++ b/src/game/java/net/minecraft/entity/boss/EntityDragon.java @@ -34,7 +34,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java b/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java index 0d9569df..a489e975 100755 --- a/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java +++ b/src/game/java/net/minecraft/entity/boss/EntityDragonPart.java @@ -11,7 +11,7 @@ import net.minecraft.util.DamageSource; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/boss/EntityWither.java b/src/game/java/net/minecraft/entity/boss/EntityWither.java index b24e3149..ab882fd4 100755 --- a/src/game/java/net/minecraft/entity/boss/EntityWither.java +++ b/src/game/java/net/minecraft/entity/boss/EntityWither.java @@ -43,7 +43,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java b/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java index 0fce6f54..f1b4f6b0 100755 --- a/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java +++ b/src/game/java/net/minecraft/entity/boss/IBossDisplayData.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java b/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java index 26869962..6cc0887c 100755 --- a/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java +++ b/src/game/java/net/minecraft/entity/effect/EntityLightningBolt.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java b/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java index 2b9fe4e3..e5e50aa5 100755 --- a/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java +++ b/src/game/java/net/minecraft/entity/effect/EntityWeatherEffect.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityArmorStand.java b/src/game/java/net/minecraft/entity/item/EntityArmorStand.java index d122a794..eb9334cc 100755 --- a/src/game/java/net/minecraft/entity/item/EntityArmorStand.java +++ b/src/game/java/net/minecraft/entity/item/EntityArmorStand.java @@ -29,7 +29,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityBoat.java b/src/game/java/net/minecraft/entity/item/EntityBoat.java index 8b0aedcc..4fa4b450 100755 --- a/src/game/java/net/minecraft/entity/item/EntityBoat.java +++ b/src/game/java/net/minecraft/entity/item/EntityBoat.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java b/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java index 1029905c..7911887b 100755 --- a/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java +++ b/src/game/java/net/minecraft/entity/item/EntityEnderCrystal.java @@ -15,7 +15,7 @@ import net.minecraft.world.WorldProviderEnd; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityEnderEye.java b/src/game/java/net/minecraft/entity/item/EntityEnderEye.java index 9f689eff..6f731780 100755 --- a/src/game/java/net/minecraft/entity/item/EntityEnderEye.java +++ b/src/game/java/net/minecraft/entity/item/EntityEnderEye.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java b/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java index 8f572957..f3f8186b 100755 --- a/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java +++ b/src/game/java/net/minecraft/entity/item/EntityEnderPearl.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityExpBottle.java b/src/game/java/net/minecraft/entity/item/EntityExpBottle.java index 27216a15..cdb4c9c9 100755 --- a/src/game/java/net/minecraft/entity/item/EntityExpBottle.java +++ b/src/game/java/net/minecraft/entity/item/EntityExpBottle.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java b/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java index 6aab3283..0b9c754b 100755 --- a/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java +++ b/src/game/java/net/minecraft/entity/item/EntityFallingBlock.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java b/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java index e8c9a7d3..ea5796f5 100755 --- a/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java +++ b/src/game/java/net/minecraft/entity/item/EntityFireworkRocket.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityItem.java b/src/game/java/net/minecraft/entity/item/EntityItem.java index df3b79ce..5d1c290e 100755 --- a/src/game/java/net/minecraft/entity/item/EntityItem.java +++ b/src/game/java/net/minecraft/entity/item/EntityItem.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityItemFrame.java b/src/game/java/net/minecraft/entity/item/EntityItemFrame.java index 421e55f4..bce5fa76 100755 --- a/src/game/java/net/minecraft/entity/item/EntityItemFrame.java +++ b/src/game/java/net/minecraft/entity/item/EntityItemFrame.java @@ -22,7 +22,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecart.java b/src/game/java/net/minecraft/entity/item/EntityMinecart.java index 168e5bb6..ccc31536 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecart.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecart.java @@ -1,10 +1,8 @@ package net.minecraft.entity.item; import java.util.List; -import java.util.Map; - -import com.google.common.collect.Maps; - +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.minecraft.block.Block; import net.minecraft.block.BlockRailBase; import net.minecraft.block.BlockRailPowered; @@ -39,7 +37,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -990,7 +988,7 @@ public abstract class EntityMinecart extends Entity implements IWorldNameable { TNT(3, "MinecartTNT"), SPAWNER(4, "MinecartSpawner"), HOPPER(5, "MinecartHopper"), COMMAND_BLOCK(6, "MinecartCommandBlock"); - private static final Map ID_LOOKUP = Maps.newHashMap(); + private static final IntObjectMap ID_LOOKUP = new IntObjectHashMap<>(); private final int networkID; private final String name; @@ -1012,15 +1010,14 @@ public abstract class EntityMinecart extends Entity implements IWorldNameable { } public static EntityMinecart.EnumMinecartType byNetworkID(int id) { - EntityMinecart.EnumMinecartType entityminecart$enumminecarttype = (EntityMinecart.EnumMinecartType) ID_LOOKUP - .get(Integer.valueOf(id)); + EntityMinecart.EnumMinecartType entityminecart$enumminecarttype = ID_LOOKUP.get(id); return entityminecart$enumminecarttype == null ? RIDEABLE : entityminecart$enumminecarttype; } static { EntityMinecart.EnumMinecartType[] types = values(); for (int i = 0; i < types.length; ++i) { - ID_LOOKUP.put(Integer.valueOf(types[i].getNetworkID()), types[i]); + ID_LOOKUP.put(types[i].getNetworkID(), types[i]); } } diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java b/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java index 9d79b40b..32448212 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartChest.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java b/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java index 7cb5e49e..b30736bb 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartContainer.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java b/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java index f4491813..28810172 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartEmpty.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java b/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java index 3a7f833d..726e320d 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartFurnace.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java b/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java index db14dd10..a3edb719 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartHopper.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java b/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java index a508cdad..41963ceb 100755 --- a/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java +++ b/src/game/java/net/minecraft/entity/item/EntityMinecartTNT.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityPainting.java b/src/game/java/net/minecraft/entity/item/EntityPainting.java index 8dd0942a..3e724c5a 100755 --- a/src/game/java/net/minecraft/entity/item/EntityPainting.java +++ b/src/game/java/net/minecraft/entity/item/EntityPainting.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java b/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java index 22a78418..924dace2 100755 --- a/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java +++ b/src/game/java/net/minecraft/entity/item/EntityTNTPrimed.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/item/EntityXPOrb.java b/src/game/java/net/minecraft/entity/item/EntityXPOrb.java index 1fac03a5..8673ffc9 100755 --- a/src/game/java/net/minecraft/entity/item/EntityXPOrb.java +++ b/src/game/java/net/minecraft/entity/item/EntityXPOrb.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityBlaze.java b/src/game/java/net/minecraft/entity/monster/EntityBlaze.java index 009c40c0..5c28f784 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityBlaze.java +++ b/src/game/java/net/minecraft/entity/monster/EntityBlaze.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java b/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java index 58ec93dd..99c8e176 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java +++ b/src/game/java/net/minecraft/entity/monster/EntityCaveSpider.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityCreeper.java b/src/game/java/net/minecraft/entity/monster/EntityCreeper.java index c949c5ac..24b7a55a 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityCreeper.java +++ b/src/game/java/net/minecraft/entity/monster/EntityCreeper.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityEnderman.java b/src/game/java/net/minecraft/entity/monster/EntityEnderman.java index 01a37163..d16be41d 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityEnderman.java +++ b/src/game/java/net/minecraft/entity/monster/EntityEnderman.java @@ -45,7 +45,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -511,7 +511,10 @@ public class EntityEnderman extends EntityMob { int j = MathHelper.floor_double(this.enderman.posY + random.nextDouble() * 2.0D); int k = MathHelper.floor_double(this.enderman.posZ - 1.0D + random.nextDouble() * 2.0D); BlockPos blockpos = new BlockPos(i, j, k); - Block block = world.getBlockState(blockpos).getBlock(); + IBlockState iblockstate = world.getBlockState(blockpos); + if (iblockstate == null) + return; + Block block = iblockstate.getBlock(); Block block1 = world.getBlockState(blockpos.down()).getBlock(); if (this.func_179474_a(world, blockpos, this.enderman.getHeldBlockState().getBlock(), block, block1)) { world.setBlockState(blockpos, this.enderman.getHeldBlockState(), 3); @@ -548,7 +551,9 @@ public class EntityEnderman extends EntityMob { int j = MathHelper.floor_double(this.enderman.posY + random.nextDouble() * 3.0D); int k = MathHelper.floor_double(this.enderman.posZ - 2.0D + random.nextDouble() * 4.0D); BlockPos blockpos = new BlockPos(i, j, k); - IBlockState iblockstate = world.getBlockState(blockpos); + IBlockState iblockstate = world.getBlockStateIfLoaded(blockpos); + if (iblockstate == null) + return; Block block = iblockstate.getBlock(); if (EntityEnderman.carriableBlocks.contains(block)) { this.enderman.setHeldBlockState(iblockstate); diff --git a/src/game/java/net/minecraft/entity/monster/EntityEndermite.java b/src/game/java/net/minecraft/entity/monster/EntityEndermite.java index 7c5f74dc..bb962b79 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityEndermite.java +++ b/src/game/java/net/minecraft/entity/monster/EntityEndermite.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityGhast.java b/src/game/java/net/minecraft/entity/monster/EntityGhast.java index b1e6cb34..3f4dffaa 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGhast.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGhast.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java b/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java index 5f6f5538..32c49559 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGiantZombie.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityGolem.java b/src/game/java/net/minecraft/entity/monster/EntityGolem.java index cce18c88..cc0f51f1 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGolem.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGolem.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityGuardian.java b/src/game/java/net/minecraft/entity/monster/EntityGuardian.java index 1f5ec875..bf36c0af 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityGuardian.java +++ b/src/game/java/net/minecraft/entity/monster/EntityGuardian.java @@ -45,7 +45,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java b/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java index 0248e3cf..be606c40 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java +++ b/src/game/java/net/minecraft/entity/monster/EntityIronGolem.java @@ -40,7 +40,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java b/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java index ace061a2..717c494c 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java +++ b/src/game/java/net/minecraft/entity/monster/EntityMagmaCube.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityMob.java b/src/game/java/net/minecraft/entity/monster/EntityMob.java index 337fd02e..49b14cf1 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityMob.java +++ b/src/game/java/net/minecraft/entity/monster/EntityMob.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java b/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java index 60d4d112..484e7a3e 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java +++ b/src/game/java/net/minecraft/entity/monster/EntityPigZombie.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java b/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java index a6d22b3f..aedb4607 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySilverfish.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java b/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java index 7821bc79..96cb576e 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySkeleton.java @@ -45,7 +45,7 @@ import net.minecraft.world.WorldProviderHell; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntitySlime.java b/src/game/java/net/minecraft/entity/monster/EntitySlime.java index 0c948298..d72447da 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySlime.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySlime.java @@ -31,7 +31,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntitySnowman.java b/src/game/java/net/minecraft/entity/monster/EntitySnowman.java index 28c22eb2..0fa9a4f3 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySnowman.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySnowman.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntitySpider.java b/src/game/java/net/minecraft/entity/monster/EntitySpider.java index f84df437..d3516fe1 100755 --- a/src/game/java/net/minecraft/entity/monster/EntitySpider.java +++ b/src/game/java/net/minecraft/entity/monster/EntitySpider.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityWitch.java b/src/game/java/net/minecraft/entity/monster/EntityWitch.java index f708fc28..9d7922b3 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityWitch.java +++ b/src/game/java/net/minecraft/entity/monster/EntityWitch.java @@ -33,7 +33,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/EntityZombie.java b/src/game/java/net/minecraft/entity/monster/EntityZombie.java index b4bf2cff..7864563d 100755 --- a/src/game/java/net/minecraft/entity/monster/EntityZombie.java +++ b/src/game/java/net/minecraft/entity/monster/EntityZombie.java @@ -49,7 +49,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/monster/IMob.java b/src/game/java/net/minecraft/entity/monster/IMob.java index 638a5fed..a40cc7a2 100755 --- a/src/game/java/net/minecraft/entity/monster/IMob.java +++ b/src/game/java/net/minecraft/entity/monster/IMob.java @@ -11,7 +11,7 @@ import net.minecraft.entity.passive.IAnimals; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java b/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java index e5da0fda..b8d630cd 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java +++ b/src/game/java/net/minecraft/entity/passive/EntityAmbientCreature.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityAnimal.java b/src/game/java/net/minecraft/entity/passive/EntityAnimal.java index 848e7c78..3d07d4f6 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityAnimal.java +++ b/src/game/java/net/minecraft/entity/passive/EntityAnimal.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityBat.java b/src/game/java/net/minecraft/entity/passive/EntityBat.java index a1571b0d..7e64ca9f 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityBat.java +++ b/src/game/java/net/minecraft/entity/passive/EntityBat.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityChicken.java b/src/game/java/net/minecraft/entity/passive/EntityChicken.java index 5ab6f74f..3f39df51 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityChicken.java +++ b/src/game/java/net/minecraft/entity/passive/EntityChicken.java @@ -27,7 +27,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityCow.java b/src/game/java/net/minecraft/entity/passive/EntityCow.java index cdfac514..97dc0d47 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityCow.java +++ b/src/game/java/net/minecraft/entity/passive/EntityCow.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityHorse.java b/src/game/java/net/minecraft/entity/passive/EntityHorse.java index 44fde571..ec752796 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityHorse.java +++ b/src/game/java/net/minecraft/entity/passive/EntityHorse.java @@ -49,7 +49,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java b/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java index 6e126596..e84ffc7f 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java +++ b/src/game/java/net/minecraft/entity/passive/EntityMooshroom.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityOcelot.java b/src/game/java/net/minecraft/entity/passive/EntityOcelot.java index 6cc07c7c..6d91c2a3 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityOcelot.java +++ b/src/game/java/net/minecraft/entity/passive/EntityOcelot.java @@ -37,7 +37,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityPig.java b/src/game/java/net/minecraft/entity/passive/EntityPig.java index c39faf05..c66314ae 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityPig.java +++ b/src/game/java/net/minecraft/entity/passive/EntityPig.java @@ -30,7 +30,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityRabbit.java b/src/game/java/net/minecraft/entity/passive/EntityRabbit.java index ca1bd665..b80583e9 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityRabbit.java +++ b/src/game/java/net/minecraft/entity/passive/EntityRabbit.java @@ -44,7 +44,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntitySheep.java b/src/game/java/net/minecraft/entity/passive/EntitySheep.java index e23cd759..a94e8b1b 100755 --- a/src/game/java/net/minecraft/entity/passive/EntitySheep.java +++ b/src/game/java/net/minecraft/entity/passive/EntitySheep.java @@ -39,7 +39,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntitySquid.java b/src/game/java/net/minecraft/entity/passive/EntitySquid.java index 9a2fd179..1d774f34 100755 --- a/src/game/java/net/minecraft/entity/passive/EntitySquid.java +++ b/src/game/java/net/minecraft/entity/passive/EntitySquid.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityTameable.java b/src/game/java/net/minecraft/entity/passive/EntityTameable.java index f9998a09..14a96812 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityTameable.java +++ b/src/game/java/net/minecraft/entity/passive/EntityTameable.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityVillager.java b/src/game/java/net/minecraft/entity/passive/EntityVillager.java index e4978e3f..411f8667 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityVillager.java +++ b/src/game/java/net/minecraft/entity/passive/EntityVillager.java @@ -57,7 +57,6 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.IChatComponent; import net.minecraft.util.MathHelper; -import net.minecraft.util.Tuple; import net.minecraft.village.MerchantRecipe; import net.minecraft.village.MerchantRecipeList; import net.minecraft.village.Village; @@ -70,7 +69,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -1109,16 +1108,25 @@ public class EntityVillager extends EntityAgeable implements IMerchant, INpc { } } - static class PriceInfo extends Tuple { + static class PriceInfo { + private int a; + private int b; + public PriceInfo(int parInt1, int parInt2) { - super(Integer.valueOf(parInt1), Integer.valueOf(parInt2)); + this.a = parInt1; + this.b = parInt2; + } + + public int getFirst() { + return this.a; + } + + public int getSecond() { + return this.b; } public int getPrice(EaglercraftRandom rand) { - return ((Integer) this.getFirst()).intValue() >= ((Integer) this.getSecond()).intValue() - ? ((Integer) this.getFirst()).intValue() - : ((Integer) this.getFirst()).intValue() + rand.nextInt( - ((Integer) this.getSecond()).intValue() - ((Integer) this.getFirst()).intValue() + 1); + return (a >= b) ? a : a + rand.nextInt(b - a + 1); } } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java b/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java index f79eb45e..fb235304 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java +++ b/src/game/java/net/minecraft/entity/passive/EntityWaterMob.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/EntityWolf.java b/src/game/java/net/minecraft/entity/passive/EntityWolf.java index 0beb8979..379595c8 100755 --- a/src/game/java/net/minecraft/entity/passive/EntityWolf.java +++ b/src/game/java/net/minecraft/entity/passive/EntityWolf.java @@ -44,7 +44,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/passive/IAnimals.java b/src/game/java/net/minecraft/entity/passive/IAnimals.java index b14daacd..e16bf5af 100755 --- a/src/game/java/net/minecraft/entity/passive/IAnimals.java +++ b/src/game/java/net/minecraft/entity/passive/IAnimals.java @@ -6,7 +6,7 @@ package net.minecraft.entity.passive; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/player/EntityPlayer.java b/src/game/java/net/minecraft/entity/player/EntityPlayer.java index a1941f56..4db1a4cb 100755 --- a/src/game/java/net/minecraft/entity/player/EntityPlayer.java +++ b/src/game/java/net/minecraft/entity/player/EntityPlayer.java @@ -83,7 +83,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java b/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java index 2bb2b37d..dca4d0ac 100755 --- a/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java +++ b/src/game/java/net/minecraft/entity/player/EntityPlayerMP.java @@ -1,5 +1,11 @@ package net.minecraft.entity.player; +import com.carrotsearch.hppc.IntArrayDeque; +import com.carrotsearch.hppc.IntDeque; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.cursors.LongCursor; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile; @@ -87,7 +93,6 @@ import net.minecraft.util.JsonSerializableSet; import net.minecraft.util.MathHelper; import net.minecraft.util.ReportedException; import net.minecraft.village.MerchantRecipeList; -import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.IInteractionObject; import net.minecraft.world.ILockableContainer; import net.minecraft.world.WorldServer; @@ -105,7 +110,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -131,11 +136,11 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { /**+ * LinkedList that holds the loaded chunks. */ - public final List loadedChunks = Lists.newLinkedList(); + public final LongSet loadedChunks = new LongHashSet(); /**+ * entities added to this list will be packet29'd to the player */ - private final List destroyedItemsNetCache = Lists.newLinkedList(); + private final IntDeque destroyedItemsNetCache = new IntArrayDeque(); private final StatisticsFile statsFile; /**+ * the total health of the player, includes actual health and @@ -287,56 +292,49 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { while (!this.destroyedItemsNetCache.isEmpty()) { int i = Math.min(this.destroyedItemsNetCache.size(), Integer.MAX_VALUE); int[] aint = new int[i]; - Iterator iterator = this.destroyedItemsNetCache.iterator(); int j = 0; - while (iterator.hasNext() && j < i) { - aint[j++] = ((Integer) iterator.next()).intValue(); - iterator.remove(); + while (!destroyedItemsNetCache.isEmpty() && j < i) { + aint[j++] = destroyedItemsNetCache.removeFirst(); } this.playerNetServerHandler.sendPacket(new S13PacketDestroyEntities(aint)); } if (!this.loadedChunks.isEmpty()) { - ArrayList arraylist = Lists.newArrayList(); - Iterator iterator1 = this.loadedChunks.iterator(); - ArrayList arraylist1 = Lists.newArrayList(); + ArrayList arraylist = Lists.newArrayList(); + Iterator iterator1 = this.loadedChunks.iterator(); + ArrayList arraylist1 = Lists.newArrayList(); while (iterator1.hasNext() && arraylist.size() < 10) { - ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator1.next(); - if (chunkcoordintpair != null) { - if (this.worldObj.isBlockLoaded( - new BlockPos(chunkcoordintpair.chunkXPos << 4, 0, chunkcoordintpair.chunkZPos << 4))) { - Chunk chunk = this.worldObj.getChunkFromChunkCoords(chunkcoordintpair.chunkXPos, - chunkcoordintpair.chunkZPos); - if (chunk.isPopulated()) { - arraylist.add(chunk); - arraylist1.addAll(((WorldServer) this.worldObj).getTileEntitiesIn( - chunkcoordintpair.chunkXPos * 16, 0, chunkcoordintpair.chunkZPos * 16, - chunkcoordintpair.chunkXPos * 16 + 16, 256, chunkcoordintpair.chunkZPos * 16 + 16)); - iterator1.remove(); - } + long l = iterator1.next().value; + int chunkXPos = (int) (l & 4294967295L); + int chunkZPos = (int) (l >>> 32); + if (this.worldObj.isBlockLoaded(new BlockPos(chunkXPos << 4, 0, chunkZPos << 4))) { + Chunk chunk = this.worldObj.getChunkFromChunkCoords(chunkXPos, chunkZPos); + if (chunk.isPopulated()) { + arraylist.add(chunk); + arraylist1.addAll(((WorldServer) this.worldObj).getTileEntitiesIn(chunkXPos * 16, 0, + chunkZPos * 16, chunkXPos * 16 + 16, 256, chunkZPos * 16 + 16)); } - } else { - iterator1.remove(); } } if (!arraylist.isEmpty()) { if (arraylist.size() == 1) { - this.playerNetServerHandler - .sendPacket(new S21PacketChunkData((Chunk) arraylist.get(0), true, '\uffff')); + this.playerNetServerHandler.sendPacket(new S21PacketChunkData(arraylist.get(0), true, '\uffff')); } else { this.playerNetServerHandler.sendPacket(new S26PacketMapChunkBulk(arraylist)); } for (int i = 0, l = arraylist1.size(); i < l; ++i) { - this.sendTileEntityUpdate((TileEntity) arraylist1.get(i)); + this.sendTileEntityUpdate(arraylist1.get(i)); } for (int i = 0, l = arraylist.size(); i < l; ++i) { - this.getServerForPlayer().getEntityTracker().func_85172_a(this, (Chunk) arraylist.get(i)); + Chunk c = arraylist.get(i); + this.getServerForPlayer().getEntityTracker().func_85172_a(this, c); + this.loadedChunks.removeAll(c.getChunkCoordLong()); } } } @@ -940,7 +938,9 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { this.lastExperience = -1; this.lastHealth = -1.0F; this.lastFoodLevel = -1; - this.destroyedItemsNetCache.addAll(((EntityPlayerMP) oldPlayer).destroyedItemsNetCache); + for (IntCursor cur : ((EntityPlayerMP) oldPlayer).destroyedItemsNetCache) { + destroyedItemsNetCache.addLast(cur.value); + } } protected void onNewPotionEffect(PotionEffect id) { @@ -1086,7 +1086,7 @@ public class EntityPlayerMP extends EntityPlayer implements ICrafting { if (parEntity instanceof EntityPlayer) { this.playerNetServerHandler.sendPacket(new S13PacketDestroyEntities(new int[] { parEntity.getEntityId() })); } else { - this.destroyedItemsNetCache.add(Integer.valueOf(parEntity.getEntityId())); + this.destroyedItemsNetCache.addLast(parEntity.getEntityId()); } } diff --git a/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java b/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java index dafb46b2..8eebc196 100755 --- a/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java +++ b/src/game/java/net/minecraft/entity/player/EnumPlayerModelParts.java @@ -9,7 +9,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/player/InventoryPlayer.java b/src/game/java/net/minecraft/entity/player/InventoryPlayer.java index 3603b56e..30e6571f 100755 --- a/src/game/java/net/minecraft/entity/player/InventoryPlayer.java +++ b/src/game/java/net/minecraft/entity/player/InventoryPlayer.java @@ -23,7 +23,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java b/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java index 7a22ea6a..93af2a77 100755 --- a/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java +++ b/src/game/java/net/minecraft/entity/player/PlayerCapabilities.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityArrow.java b/src/game/java/net/minecraft/entity/projectile/EntityArrow.java index a43a38c2..24024b22 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityArrow.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityArrow.java @@ -31,7 +31,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityEgg.java b/src/game/java/net/minecraft/entity/projectile/EntityEgg.java index aa9af05e..c056494e 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityEgg.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityEgg.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityFireball.java b/src/game/java/net/minecraft/entity/projectile/EntityFireball.java index 1a5bc51c..b74f19d3 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityFireball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityFireball.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java b/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java index 19557e4b..0c3e2f11 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityFishHook.java @@ -35,7 +35,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java b/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java index abe2d8c3..04736a3f 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityLargeFireball.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityPotion.java b/src/game/java/net/minecraft/entity/projectile/EntityPotion.java index 80c601c1..d687283c 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityPotion.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityPotion.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java b/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java index 0daf2fc7..86049cb1 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntitySmallFireball.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java b/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java index a2dc92ff..63bd2727 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java +++ b/src/game/java/net/minecraft/entity/projectile/EntitySnowball.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java b/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java index 12e09a3e..d9173b27 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityThrowable.java @@ -25,7 +25,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java b/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java index 28adba76..d80d425b 100755 --- a/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java +++ b/src/game/java/net/minecraft/entity/projectile/EntityWitherSkull.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/event/ClickEvent.java b/src/game/java/net/minecraft/event/ClickEvent.java index 652af505..5a33f67c 100755 --- a/src/game/java/net/minecraft/event/ClickEvent.java +++ b/src/game/java/net/minecraft/event/ClickEvent.java @@ -10,7 +10,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/event/HoverEvent.java b/src/game/java/net/minecraft/event/HoverEvent.java index 70b2fc14..a40d5c33 100755 --- a/src/game/java/net/minecraft/event/HoverEvent.java +++ b/src/game/java/net/minecraft/event/HoverEvent.java @@ -12,7 +12,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/init/Blocks.java b/src/game/java/net/minecraft/init/Blocks.java index 2c7aa7f7..8610d994 100755 --- a/src/game/java/net/minecraft/init/Blocks.java +++ b/src/game/java/net/minecraft/init/Blocks.java @@ -40,7 +40,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/init/Bootstrap.java b/src/game/java/net/minecraft/init/Bootstrap.java index 00f51c08..9f3ae2b2 100755 --- a/src/game/java/net/minecraft/init/Bootstrap.java +++ b/src/game/java/net/minecraft/init/Bootstrap.java @@ -64,7 +64,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/init/Items.java b/src/game/java/net/minecraft/init/Items.java index 393c72ef..b5fcb864 100755 --- a/src/game/java/net/minecraft/init/Items.java +++ b/src/game/java/net/minecraft/init/Items.java @@ -18,7 +18,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/AnimalChest.java b/src/game/java/net/minecraft/inventory/AnimalChest.java index 8a665142..c2ffc54f 100755 --- a/src/game/java/net/minecraft/inventory/AnimalChest.java +++ b/src/game/java/net/minecraft/inventory/AnimalChest.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/Container.java b/src/game/java/net/minecraft/inventory/Container.java index 7f1019ad..45c33204 100755 --- a/src/game/java/net/minecraft/inventory/Container.java +++ b/src/game/java/net/minecraft/inventory/Container.java @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerBeacon.java b/src/game/java/net/minecraft/inventory/ContainerBeacon.java index c392b12a..83fcbb5a 100755 --- a/src/game/java/net/minecraft/inventory/ContainerBeacon.java +++ b/src/game/java/net/minecraft/inventory/ContainerBeacon.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java b/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java index 0a27e509..259e3ca8 100755 --- a/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java +++ b/src/game/java/net/minecraft/inventory/ContainerBrewingStand.java @@ -12,7 +12,7 @@ import net.minecraft.stats.AchievementList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerChest.java b/src/game/java/net/minecraft/inventory/ContainerChest.java index 7ca236a3..93ad7be4 100755 --- a/src/game/java/net/minecraft/inventory/ContainerChest.java +++ b/src/game/java/net/minecraft/inventory/ContainerChest.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerDispenser.java b/src/game/java/net/minecraft/inventory/ContainerDispenser.java index 4f191a00..49458c4e 100755 --- a/src/game/java/net/minecraft/inventory/ContainerDispenser.java +++ b/src/game/java/net/minecraft/inventory/ContainerDispenser.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerEnchantment.java b/src/game/java/net/minecraft/inventory/ContainerEnchantment.java index bf182d0b..828e6c37 100755 --- a/src/game/java/net/minecraft/inventory/ContainerEnchantment.java +++ b/src/game/java/net/minecraft/inventory/ContainerEnchantment.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerFurnace.java b/src/game/java/net/minecraft/inventory/ContainerFurnace.java index a023a86d..b3c826f0 100755 --- a/src/game/java/net/minecraft/inventory/ContainerFurnace.java +++ b/src/game/java/net/minecraft/inventory/ContainerFurnace.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.TileEntityFurnace; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerHopper.java b/src/game/java/net/minecraft/inventory/ContainerHopper.java index 930b84bb..738b0673 100755 --- a/src/game/java/net/minecraft/inventory/ContainerHopper.java +++ b/src/game/java/net/minecraft/inventory/ContainerHopper.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java b/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java index a06e0a02..44d883e0 100755 --- a/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java +++ b/src/game/java/net/minecraft/inventory/ContainerHorseInventory.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerMerchant.java b/src/game/java/net/minecraft/inventory/ContainerMerchant.java index 93a71f25..c05c65e4 100755 --- a/src/game/java/net/minecraft/inventory/ContainerMerchant.java +++ b/src/game/java/net/minecraft/inventory/ContainerMerchant.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerPlayer.java b/src/game/java/net/minecraft/inventory/ContainerPlayer.java index abe951b6..0cb1ba5b 100755 --- a/src/game/java/net/minecraft/inventory/ContainerPlayer.java +++ b/src/game/java/net/minecraft/inventory/ContainerPlayer.java @@ -15,7 +15,7 @@ import net.minecraft.item.crafting.CraftingManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ContainerRepair.java b/src/game/java/net/minecraft/inventory/ContainerRepair.java index 62fe6843..54721966 100755 --- a/src/game/java/net/minecraft/inventory/ContainerRepair.java +++ b/src/game/java/net/minecraft/inventory/ContainerRepair.java @@ -1,7 +1,5 @@ package net.minecraft.inventory; -import java.util.Iterator; -import java.util.Map; import net.minecraft.block.BlockAnvil; import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.Enchantment; @@ -14,6 +12,11 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.BlockPos; import net.minecraft.world.World; import org.apache.commons.lang3.StringUtils; + +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.cursors.IntCursor; +import com.carrotsearch.hppc.cursors.IntIntCursor; + import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; @@ -23,7 +26,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -162,7 +165,7 @@ public class ContainerRepair extends Container { } else { ItemStack itemstack1 = itemstack.copy(); ItemStack itemstack2 = this.inputSlots.getStackInSlot(1); - Map map = EnchantmentHelper.getEnchantments(itemstack1); + IntIntMap map = EnchantmentHelper.getEnchantments(itemstack1); boolean flag7 = false; j = j + itemstack.getRepairCost() + (itemstack2 == null ? 0 : itemstack2.getRepairCost()); this.materialCost = 0; @@ -210,17 +213,14 @@ public class ContainerRepair extends Container { } } - Map map1 = EnchantmentHelper.getEnchantments(itemstack2); - Iterator iterator1 = map1.keySet().iterator(); + IntIntMap map1 = EnchantmentHelper.getEnchantments(itemstack2); - while (iterator1.hasNext()) { - int i3 = ((Integer) iterator1.next()).intValue(); + for (IntIntCursor cur : map1) { + int i3 = cur.key; Enchantment enchantment = Enchantment.getEnchantmentById(i3); if (enchantment != null) { - int k3 = map.containsKey(Integer.valueOf(i3)) - ? ((Integer) map.get(Integer.valueOf(i3))).intValue() - : 0; - int l1 = ((Integer) map1.get(Integer.valueOf(i3))).intValue(); + int k3 = map.getOrDefault(i3, 0); + int l1 = cur.value; int i4; if (k3 == l1) { ++l1; @@ -236,10 +236,8 @@ public class ContainerRepair extends Container { flag8 = true; } - Iterator iterator = map.keySet().iterator(); - - while (iterator.hasNext()) { - int i2 = ((Integer) iterator.next()).intValue(); + for (IntCursor curr : map.keys()) { + int i2 = curr.value; if (i2 != i3 && !enchantment.canApplyTogether(Enchantment.getEnchantmentById(i2))) { flag8 = false; ++i; @@ -251,7 +249,7 @@ public class ContainerRepair extends Container { l1 = enchantment.getMaxLevel(); } - map.put(Integer.valueOf(i3), Integer.valueOf(l1)); + map.put(i3, l1); int l3 = 0; switch (enchantment.getWeight()) { case 1: diff --git a/src/game/java/net/minecraft/inventory/ContainerWorkbench.java b/src/game/java/net/minecraft/inventory/ContainerWorkbench.java index 2959bb26..3145b52e 100755 --- a/src/game/java/net/minecraft/inventory/ContainerWorkbench.java +++ b/src/game/java/net/minecraft/inventory/ContainerWorkbench.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ICrafting.java b/src/game/java/net/minecraft/inventory/ICrafting.java index 7fa10887..98567a59 100755 --- a/src/game/java/net/minecraft/inventory/ICrafting.java +++ b/src/game/java/net/minecraft/inventory/ICrafting.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/IInvBasic.java b/src/game/java/net/minecraft/inventory/IInvBasic.java index 35cc4276..e3fa816e 100755 --- a/src/game/java/net/minecraft/inventory/IInvBasic.java +++ b/src/game/java/net/minecraft/inventory/IInvBasic.java @@ -6,7 +6,7 @@ package net.minecraft.inventory; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/IInventory.java b/src/game/java/net/minecraft/inventory/IInventory.java index 1f126130..fa074d37 100755 --- a/src/game/java/net/minecraft/inventory/IInventory.java +++ b/src/game/java/net/minecraft/inventory/IInventory.java @@ -10,7 +10,7 @@ import net.minecraft.world.IWorldNameable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/ISidedInventory.java b/src/game/java/net/minecraft/inventory/ISidedInventory.java index 7ee51421..cbdf74b3 100755 --- a/src/game/java/net/minecraft/inventory/ISidedInventory.java +++ b/src/game/java/net/minecraft/inventory/ISidedInventory.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/InventoryBasic.java b/src/game/java/net/minecraft/inventory/InventoryBasic.java index 3fb2f412..b2b6ee89 100755 --- a/src/game/java/net/minecraft/inventory/InventoryBasic.java +++ b/src/game/java/net/minecraft/inventory/InventoryBasic.java @@ -16,7 +16,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/InventoryCraftResult.java b/src/game/java/net/minecraft/inventory/InventoryCraftResult.java index 31ac5df8..b1c045d4 100755 --- a/src/game/java/net/minecraft/inventory/InventoryCraftResult.java +++ b/src/game/java/net/minecraft/inventory/InventoryCraftResult.java @@ -12,7 +12,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/InventoryCrafting.java b/src/game/java/net/minecraft/inventory/InventoryCrafting.java index c6530349..77bea52f 100755 --- a/src/game/java/net/minecraft/inventory/InventoryCrafting.java +++ b/src/game/java/net/minecraft/inventory/InventoryCrafting.java @@ -12,7 +12,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/InventoryEnderChest.java b/src/game/java/net/minecraft/inventory/InventoryEnderChest.java index 5b714224..035aeea2 100755 --- a/src/game/java/net/minecraft/inventory/InventoryEnderChest.java +++ b/src/game/java/net/minecraft/inventory/InventoryEnderChest.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.TileEntityEnderChest; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/InventoryHelper.java b/src/game/java/net/minecraft/inventory/InventoryHelper.java index fe80d18b..d1e36bce 100755 --- a/src/game/java/net/minecraft/inventory/InventoryHelper.java +++ b/src/game/java/net/minecraft/inventory/InventoryHelper.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/InventoryLargeChest.java b/src/game/java/net/minecraft/inventory/InventoryLargeChest.java index 5874609d..18a6ba32 100755 --- a/src/game/java/net/minecraft/inventory/InventoryLargeChest.java +++ b/src/game/java/net/minecraft/inventory/InventoryLargeChest.java @@ -15,7 +15,7 @@ import net.minecraft.world.LockCode; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/InventoryMerchant.java b/src/game/java/net/minecraft/inventory/InventoryMerchant.java index 0a69fa28..fc772f4f 100755 --- a/src/game/java/net/minecraft/inventory/InventoryMerchant.java +++ b/src/game/java/net/minecraft/inventory/InventoryMerchant.java @@ -15,7 +15,7 @@ import net.minecraft.village.MerchantRecipeList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/Slot.java b/src/game/java/net/minecraft/inventory/Slot.java index aa0aa00a..1f4d3030 100755 --- a/src/game/java/net/minecraft/inventory/Slot.java +++ b/src/game/java/net/minecraft/inventory/Slot.java @@ -9,7 +9,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/SlotCrafting.java b/src/game/java/net/minecraft/inventory/SlotCrafting.java index 6bea63f9..a139cea7 100755 --- a/src/game/java/net/minecraft/inventory/SlotCrafting.java +++ b/src/game/java/net/minecraft/inventory/SlotCrafting.java @@ -17,7 +17,7 @@ import net.minecraft.stats.AchievementList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java b/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java index 822e37cf..79e7d752 100755 --- a/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java +++ b/src/game/java/net/minecraft/inventory/SlotFurnaceFuel.java @@ -10,7 +10,7 @@ import net.minecraft.tileentity.TileEntityFurnace; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java b/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java index e8561208..48094918 100755 --- a/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java +++ b/src/game/java/net/minecraft/inventory/SlotFurnaceOutput.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/inventory/SlotMerchantResult.java b/src/game/java/net/minecraft/inventory/SlotMerchantResult.java index af69b41f..e9ed4dff 100755 --- a/src/game/java/net/minecraft/inventory/SlotMerchantResult.java +++ b/src/game/java/net/minecraft/inventory/SlotMerchantResult.java @@ -12,7 +12,7 @@ import net.minecraft.village.MerchantRecipe; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/EnumAction.java b/src/game/java/net/minecraft/item/EnumAction.java index 787ebec3..f2c2c71a 100755 --- a/src/game/java/net/minecraft/item/EnumAction.java +++ b/src/game/java/net/minecraft/item/EnumAction.java @@ -6,7 +6,7 @@ package net.minecraft.item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/EnumDyeColor.java b/src/game/java/net/minecraft/item/EnumDyeColor.java index 322082f3..94cb7bb3 100755 --- a/src/game/java/net/minecraft/item/EnumDyeColor.java +++ b/src/game/java/net/minecraft/item/EnumDyeColor.java @@ -10,7 +10,7 @@ import net.minecraft.util.IStringSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/EnumRarity.java b/src/game/java/net/minecraft/item/EnumRarity.java index f503cbd4..00803cd3 100755 --- a/src/game/java/net/minecraft/item/EnumRarity.java +++ b/src/game/java/net/minecraft/item/EnumRarity.java @@ -8,7 +8,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/Item.java b/src/game/java/net/minecraft/item/Item.java index 15f73165..80d0b25a 100755 --- a/src/game/java/net/minecraft/item/Item.java +++ b/src/game/java/net/minecraft/item/Item.java @@ -52,7 +52,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemAnvilBlock.java b/src/game/java/net/minecraft/item/ItemAnvilBlock.java index 6a0b5fab..cea0ecb7 100755 --- a/src/game/java/net/minecraft/item/ItemAnvilBlock.java +++ b/src/game/java/net/minecraft/item/ItemAnvilBlock.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemAppleGold.java b/src/game/java/net/minecraft/item/ItemAppleGold.java index 68b91c44..b3860021 100755 --- a/src/game/java/net/minecraft/item/ItemAppleGold.java +++ b/src/game/java/net/minecraft/item/ItemAppleGold.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemArmor.java b/src/game/java/net/minecraft/item/ItemArmor.java index a2fb46c9..f9877643 100755 --- a/src/game/java/net/minecraft/item/ItemArmor.java +++ b/src/game/java/net/minecraft/item/ItemArmor.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemArmorStand.java b/src/game/java/net/minecraft/item/ItemArmorStand.java index 22d8342a..2fbc0c66 100755 --- a/src/game/java/net/minecraft/item/ItemArmorStand.java +++ b/src/game/java/net/minecraft/item/ItemArmorStand.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemAxe.java b/src/game/java/net/minecraft/item/ItemAxe.java index 08c39c9c..0e08bcff 100755 --- a/src/game/java/net/minecraft/item/ItemAxe.java +++ b/src/game/java/net/minecraft/item/ItemAxe.java @@ -14,7 +14,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBanner.java b/src/game/java/net/minecraft/item/ItemBanner.java index 06ab518e..9ee5a9ed 100755 --- a/src/game/java/net/minecraft/item/ItemBanner.java +++ b/src/game/java/net/minecraft/item/ItemBanner.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBed.java b/src/game/java/net/minecraft/item/ItemBed.java index 991e1eb2..f550803f 100755 --- a/src/game/java/net/minecraft/item/ItemBed.java +++ b/src/game/java/net/minecraft/item/ItemBed.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBlock.java b/src/game/java/net/minecraft/item/ItemBlock.java index c6411ee0..d4370628 100755 --- a/src/game/java/net/minecraft/item/ItemBlock.java +++ b/src/game/java/net/minecraft/item/ItemBlock.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBoat.java b/src/game/java/net/minecraft/item/ItemBoat.java index d71c7084..5671a329 100755 --- a/src/game/java/net/minecraft/item/ItemBoat.java +++ b/src/game/java/net/minecraft/item/ItemBoat.java @@ -21,7 +21,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBook.java b/src/game/java/net/minecraft/item/ItemBook.java index b2ce15a3..5b4a1a67 100755 --- a/src/game/java/net/minecraft/item/ItemBook.java +++ b/src/game/java/net/minecraft/item/ItemBook.java @@ -6,7 +6,7 @@ package net.minecraft.item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBow.java b/src/game/java/net/minecraft/item/ItemBow.java index b6e9a142..96edb844 100755 --- a/src/game/java/net/minecraft/item/ItemBow.java +++ b/src/game/java/net/minecraft/item/ItemBow.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBucket.java b/src/game/java/net/minecraft/item/ItemBucket.java index 20690290..82a55620 100755 --- a/src/game/java/net/minecraft/item/ItemBucket.java +++ b/src/game/java/net/minecraft/item/ItemBucket.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemBucketMilk.java b/src/game/java/net/minecraft/item/ItemBucketMilk.java index 79247e16..6f2f2ae5 100755 --- a/src/game/java/net/minecraft/item/ItemBucketMilk.java +++ b/src/game/java/net/minecraft/item/ItemBucketMilk.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java b/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java index 30873bf0..cc88be0d 100755 --- a/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java +++ b/src/game/java/net/minecraft/item/ItemCarrotOnAStick.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemCloth.java b/src/game/java/net/minecraft/item/ItemCloth.java index e70b5f70..9c5f982c 100755 --- a/src/game/java/net/minecraft/item/ItemCloth.java +++ b/src/game/java/net/minecraft/item/ItemCloth.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemCoal.java b/src/game/java/net/minecraft/item/ItemCoal.java index fce3b2e4..005f5fdb 100755 --- a/src/game/java/net/minecraft/item/ItemCoal.java +++ b/src/game/java/net/minecraft/item/ItemCoal.java @@ -10,7 +10,7 @@ import net.minecraft.creativetab.CreativeTabs; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemColored.java b/src/game/java/net/minecraft/item/ItemColored.java index 750fb31b..d2dc1848 100755 --- a/src/game/java/net/minecraft/item/ItemColored.java +++ b/src/game/java/net/minecraft/item/ItemColored.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemDoor.java b/src/game/java/net/minecraft/item/ItemDoor.java index 9e641a1c..07c445c4 100755 --- a/src/game/java/net/minecraft/item/ItemDoor.java +++ b/src/game/java/net/minecraft/item/ItemDoor.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemDoublePlant.java b/src/game/java/net/minecraft/item/ItemDoublePlant.java index 7ab3cc4e..d7dcd8d4 100755 --- a/src/game/java/net/minecraft/item/ItemDoublePlant.java +++ b/src/game/java/net/minecraft/item/ItemDoublePlant.java @@ -12,7 +12,7 @@ import net.minecraft.world.ColorizerGrass; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemDye.java b/src/game/java/net/minecraft/item/ItemDye.java index 9d7054e5..2339a64e 100755 --- a/src/game/java/net/minecraft/item/ItemDye.java +++ b/src/game/java/net/minecraft/item/ItemDye.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemEditableBook.java b/src/game/java/net/minecraft/item/ItemEditableBook.java index b36a50bc..0ec5ef35 100755 --- a/src/game/java/net/minecraft/item/ItemEditableBook.java +++ b/src/game/java/net/minecraft/item/ItemEditableBook.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemEgg.java b/src/game/java/net/minecraft/item/ItemEgg.java index c4644a7b..e11b31d1 100755 --- a/src/game/java/net/minecraft/item/ItemEgg.java +++ b/src/game/java/net/minecraft/item/ItemEgg.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemEmptyMap.java b/src/game/java/net/minecraft/item/ItemEmptyMap.java index 31db0284..b8ab220a 100755 --- a/src/game/java/net/minecraft/item/ItemEmptyMap.java +++ b/src/game/java/net/minecraft/item/ItemEmptyMap.java @@ -13,7 +13,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemEnchantedBook.java b/src/game/java/net/minecraft/item/ItemEnchantedBook.java index 2fae3e0b..4a978880 100755 --- a/src/game/java/net/minecraft/item/ItemEnchantedBook.java +++ b/src/game/java/net/minecraft/item/ItemEnchantedBook.java @@ -18,7 +18,7 @@ import net.minecraft.util.WeightedRandomChestContent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemEnderEye.java b/src/game/java/net/minecraft/item/ItemEnderEye.java index caf2d753..1deee295 100755 --- a/src/game/java/net/minecraft/item/ItemEnderEye.java +++ b/src/game/java/net/minecraft/item/ItemEnderEye.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemEnderPearl.java b/src/game/java/net/minecraft/item/ItemEnderPearl.java index db9b2688..3fd2a7ca 100755 --- a/src/game/java/net/minecraft/item/ItemEnderPearl.java +++ b/src/game/java/net/minecraft/item/ItemEnderPearl.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemExpBottle.java b/src/game/java/net/minecraft/item/ItemExpBottle.java index 1c03ac28..bfacc3f3 100755 --- a/src/game/java/net/minecraft/item/ItemExpBottle.java +++ b/src/game/java/net/minecraft/item/ItemExpBottle.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemFireball.java b/src/game/java/net/minecraft/item/ItemFireball.java index d4830404..7dc866ac 100755 --- a/src/game/java/net/minecraft/item/ItemFireball.java +++ b/src/game/java/net/minecraft/item/ItemFireball.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemFirework.java b/src/game/java/net/minecraft/item/ItemFirework.java index bf68ec4b..f6d24d9a 100755 --- a/src/game/java/net/minecraft/item/ItemFirework.java +++ b/src/game/java/net/minecraft/item/ItemFirework.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemFireworkCharge.java b/src/game/java/net/minecraft/item/ItemFireworkCharge.java index 94bf912a..d6799278 100755 --- a/src/game/java/net/minecraft/item/ItemFireworkCharge.java +++ b/src/game/java/net/minecraft/item/ItemFireworkCharge.java @@ -14,7 +14,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemFishFood.java b/src/game/java/net/minecraft/item/ItemFishFood.java index 073a2aa6..b43e8593 100755 --- a/src/game/java/net/minecraft/item/ItemFishFood.java +++ b/src/game/java/net/minecraft/item/ItemFishFood.java @@ -1,9 +1,9 @@ package net.minecraft.item; import java.util.List; -import java.util.Map; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -99,7 +99,7 @@ public class ItemFishFood extends ItemFood { COD(0, "cod", 2, 0.1F, 5, 0.6F), SALMON(1, "salmon", 2, 0.1F, 6, 0.8F), CLOWNFISH(2, "clownfish", 1, 0.1F), PUFFERFISH(3, "pufferfish", 1, 0.1F); - private static final Map META_LOOKUP = Maps.newHashMap(); + private static final IntObjectMap META_LOOKUP = new IntObjectHashMap<>(); private final int meta; private final String unlocalizedName; private final int uncookedHealAmount; @@ -163,8 +163,7 @@ public class ItemFishFood extends ItemFood { } public static ItemFishFood.FishType byMetadata(int meta) { - ItemFishFood.FishType itemfishfood$fishtype = (ItemFishFood.FishType) META_LOOKUP - .get(Integer.valueOf(meta)); + ItemFishFood.FishType itemfishfood$fishtype = META_LOOKUP.get(meta); return itemfishfood$fishtype == null ? COD : itemfishfood$fishtype; } @@ -175,7 +174,7 @@ public class ItemFishFood extends ItemFood { static { ItemFishFood.FishType[] types = values(); for (int i = 0; i < types.length; ++i) { - META_LOOKUP.put(Integer.valueOf(types[i].getMetadata()), types[i]); + META_LOOKUP.put(types[i].getMetadata(), types[i]); } } diff --git a/src/game/java/net/minecraft/item/ItemFishingRod.java b/src/game/java/net/minecraft/item/ItemFishingRod.java index 90892851..8478a744 100755 --- a/src/game/java/net/minecraft/item/ItemFishingRod.java +++ b/src/game/java/net/minecraft/item/ItemFishingRod.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemFlintAndSteel.java b/src/game/java/net/minecraft/item/ItemFlintAndSteel.java index 09116cb6..fecfc831 100755 --- a/src/game/java/net/minecraft/item/ItemFlintAndSteel.java +++ b/src/game/java/net/minecraft/item/ItemFlintAndSteel.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemFood.java b/src/game/java/net/minecraft/item/ItemFood.java index f99eaf7b..5c62482d 100755 --- a/src/game/java/net/minecraft/item/ItemFood.java +++ b/src/game/java/net/minecraft/item/ItemFood.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemGlassBottle.java b/src/game/java/net/minecraft/item/ItemGlassBottle.java index ff35eff9..78d9d2a2 100755 --- a/src/game/java/net/minecraft/item/ItemGlassBottle.java +++ b/src/game/java/net/minecraft/item/ItemGlassBottle.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemHangingEntity.java b/src/game/java/net/minecraft/item/ItemHangingEntity.java index bf94339f..50021c71 100755 --- a/src/game/java/net/minecraft/item/ItemHangingEntity.java +++ b/src/game/java/net/minecraft/item/ItemHangingEntity.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemHoe.java b/src/game/java/net/minecraft/item/ItemHoe.java index 87d9af89..607d291f 100755 --- a/src/game/java/net/minecraft/item/ItemHoe.java +++ b/src/game/java/net/minecraft/item/ItemHoe.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemLead.java b/src/game/java/net/minecraft/item/ItemLead.java index b82c5230..b830db6d 100755 --- a/src/game/java/net/minecraft/item/ItemLead.java +++ b/src/game/java/net/minecraft/item/ItemLead.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemLeaves.java b/src/game/java/net/minecraft/item/ItemLeaves.java index 9bf4508d..28f27732 100755 --- a/src/game/java/net/minecraft/item/ItemLeaves.java +++ b/src/game/java/net/minecraft/item/ItemLeaves.java @@ -8,7 +8,7 @@ import net.minecraft.block.BlockLeaves; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemLilyPad.java b/src/game/java/net/minecraft/item/ItemLilyPad.java index 4410eddc..574d6cdf 100755 --- a/src/game/java/net/minecraft/item/ItemLilyPad.java +++ b/src/game/java/net/minecraft/item/ItemLilyPad.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemMap.java b/src/game/java/net/minecraft/item/ItemMap.java index fa3a7a12..84c84561 100755 --- a/src/game/java/net/minecraft/item/ItemMap.java +++ b/src/game/java/net/minecraft/item/ItemMap.java @@ -28,7 +28,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemMapBase.java b/src/game/java/net/minecraft/item/ItemMapBase.java index 52e2f61c..3dbaee81 100755 --- a/src/game/java/net/minecraft/item/ItemMapBase.java +++ b/src/game/java/net/minecraft/item/ItemMapBase.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemMinecart.java b/src/game/java/net/minecraft/item/ItemMinecart.java index 2047d9cf..54e7449b 100755 --- a/src/game/java/net/minecraft/item/ItemMinecart.java +++ b/src/game/java/net/minecraft/item/ItemMinecart.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemMonsterPlacer.java b/src/game/java/net/minecraft/item/ItemMonsterPlacer.java index 4862159f..dfb5059d 100755 --- a/src/game/java/net/minecraft/item/ItemMonsterPlacer.java +++ b/src/game/java/net/minecraft/item/ItemMonsterPlacer.java @@ -1,6 +1,9 @@ package net.minecraft.item; import java.util.List; + +import com.carrotsearch.hppc.cursors.ObjectCursor; + import net.minecraft.block.BlockFence; import net.minecraft.block.BlockLiquid; import net.minecraft.block.state.IBlockState; @@ -29,7 +32,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -195,8 +198,8 @@ public class ItemMonsterPlacer extends Item { * (eg: dye returns 16 items) */ public void getSubItems(Item item, CreativeTabs var2, List list) { - for (EntityList.EntityEggInfo entitylist$entityegginfo : EntityList.entityEggs.values()) { - list.add(new ItemStack(item, 1, entitylist$entityegginfo.spawnedID)); + for (ObjectCursor entitylist$entityegginfo : EntityList.entityEggs.values()) { + list.add(new ItemStack(item, 1, entitylist$entityegginfo.value.spawnedID)); } } diff --git a/src/game/java/net/minecraft/item/ItemMultiTexture.java b/src/game/java/net/minecraft/item/ItemMultiTexture.java index e4ef15f8..aa10a669 100755 --- a/src/game/java/net/minecraft/item/ItemMultiTexture.java +++ b/src/game/java/net/minecraft/item/ItemMultiTexture.java @@ -10,7 +10,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemNameTag.java b/src/game/java/net/minecraft/item/ItemNameTag.java index 0c1969ff..ce58fd4b 100755 --- a/src/game/java/net/minecraft/item/ItemNameTag.java +++ b/src/game/java/net/minecraft/item/ItemNameTag.java @@ -11,7 +11,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemPickaxe.java b/src/game/java/net/minecraft/item/ItemPickaxe.java index 08b3cb45..62c034e0 100755 --- a/src/game/java/net/minecraft/item/ItemPickaxe.java +++ b/src/game/java/net/minecraft/item/ItemPickaxe.java @@ -14,7 +14,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemPiston.java b/src/game/java/net/minecraft/item/ItemPiston.java index 6187cefc..e59cd2d3 100755 --- a/src/game/java/net/minecraft/item/ItemPiston.java +++ b/src/game/java/net/minecraft/item/ItemPiston.java @@ -8,7 +8,7 @@ import net.minecraft.block.Block; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemPotion.java b/src/game/java/net/minecraft/item/ItemPotion.java index 05b4f03f..e6e134ee 100755 --- a/src/game/java/net/minecraft/item/ItemPotion.java +++ b/src/game/java/net/minecraft/item/ItemPotion.java @@ -1,15 +1,18 @@ package net.minecraft.item; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.ai.attributes.AttributeModifier; @@ -33,7 +36,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -48,8 +51,13 @@ import net.minecraft.world.World; * */ public class ItemPotion extends Item { - private Map> effectCache = Maps.newHashMap(); - private static final Map, Integer> SUB_ITEMS_CACHE = Maps.newLinkedHashMap(); + /**+ + * Contains a map from integers to the list of potion effects + * that potions with that damage value confer (to prevent + * recalculating it). + */ + private IntObjectMap> effectCache = new IntObjectHashMap<>(); + private static final ObjectIntMap> SUB_ITEMS_CACHE = new ObjectIntHashMap<>(); public ItemPotion() { this.setMaxStackSize(1); @@ -77,10 +85,10 @@ public class ItemPotion extends Item { return arraylist; } else { - List list = (List) this.effectCache.get(Integer.valueOf(stack.getMetadata())); + List list = this.effectCache.get(stack.getMetadata()); if (list == null) { list = PotionHelper.getPotionEffects(stack.getMetadata(), false); - this.effectCache.put(Integer.valueOf(stack.getMetadata()), list); + this.effectCache.put(stack.getMetadata(), list); } return list; @@ -92,10 +100,10 @@ public class ItemPotion extends Item { * value. */ public List getEffects(int meta) { - List list = (List) this.effectCache.get(Integer.valueOf(meta)); + List list = this.effectCache.get(meta); if (list == null) { list = PotionHelper.getPotionEffects(meta, false); - this.effectCache.put(Integer.valueOf(meta), list); + this.effectCache.put(meta, list); } return list; @@ -332,18 +340,15 @@ public class ItemPotion extends Item { List list = PotionHelper.getPotionEffects(i1, false); if (list != null && !list.isEmpty()) { - SUB_ITEMS_CACHE.put(list, Integer.valueOf(i1)); + SUB_ITEMS_CACHE.put(list, i1); } } } } } - Iterator iterator = SUB_ITEMS_CACHE.values().iterator(); - - while (iterator.hasNext()) { - int j1 = ((Integer) iterator.next()).intValue(); - subItems.add(new ItemStack(itemIn, 1, j1)); + for (IntCursor cur : SUB_ITEMS_CACHE.values()) { + subItems.add(new ItemStack(itemIn, 1, cur.value)); } } diff --git a/src/game/java/net/minecraft/item/ItemRecord.java b/src/game/java/net/minecraft/item/ItemRecord.java index cf269441..f97fbb6e 100755 --- a/src/game/java/net/minecraft/item/ItemRecord.java +++ b/src/game/java/net/minecraft/item/ItemRecord.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemRedstone.java b/src/game/java/net/minecraft/item/ItemRedstone.java index c1d6a1c6..40e0fae7 100755 --- a/src/game/java/net/minecraft/item/ItemRedstone.java +++ b/src/game/java/net/minecraft/item/ItemRedstone.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemReed.java b/src/game/java/net/minecraft/item/ItemReed.java index 6da64a94..d6a002dc 100755 --- a/src/game/java/net/minecraft/item/ItemReed.java +++ b/src/game/java/net/minecraft/item/ItemReed.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSaddle.java b/src/game/java/net/minecraft/item/ItemSaddle.java index e55b3f3d..6c327383 100755 --- a/src/game/java/net/minecraft/item/ItemSaddle.java +++ b/src/game/java/net/minecraft/item/ItemSaddle.java @@ -11,7 +11,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSeedFood.java b/src/game/java/net/minecraft/item/ItemSeedFood.java index f815487b..bd8c4260 100755 --- a/src/game/java/net/minecraft/item/ItemSeedFood.java +++ b/src/game/java/net/minecraft/item/ItemSeedFood.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSeeds.java b/src/game/java/net/minecraft/item/ItemSeeds.java index a6c70e31..de10bda7 100755 --- a/src/game/java/net/minecraft/item/ItemSeeds.java +++ b/src/game/java/net/minecraft/item/ItemSeeds.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemShears.java b/src/game/java/net/minecraft/item/ItemShears.java index f5f154fb..69a9e8e6 100755 --- a/src/game/java/net/minecraft/item/ItemShears.java +++ b/src/game/java/net/minecraft/item/ItemShears.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSign.java b/src/game/java/net/minecraft/item/ItemSign.java index 3056f68a..c8138b64 100755 --- a/src/game/java/net/minecraft/item/ItemSign.java +++ b/src/game/java/net/minecraft/item/ItemSign.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSimpleFoiled.java b/src/game/java/net/minecraft/item/ItemSimpleFoiled.java index 337b804f..34c20e5b 100755 --- a/src/game/java/net/minecraft/item/ItemSimpleFoiled.java +++ b/src/game/java/net/minecraft/item/ItemSimpleFoiled.java @@ -6,7 +6,7 @@ package net.minecraft.item; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSkull.java b/src/game/java/net/minecraft/item/ItemSkull.java index 9c7b9f84..b53c1f30 100755 --- a/src/game/java/net/minecraft/item/ItemSkull.java +++ b/src/game/java/net/minecraft/item/ItemSkull.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSlab.java b/src/game/java/net/minecraft/item/ItemSlab.java index c218aeaa..a3ee35b2 100755 --- a/src/game/java/net/minecraft/item/ItemSlab.java +++ b/src/game/java/net/minecraft/item/ItemSlab.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSnow.java b/src/game/java/net/minecraft/item/ItemSnow.java index 2ca8cc47..f32575f6 100755 --- a/src/game/java/net/minecraft/item/ItemSnow.java +++ b/src/game/java/net/minecraft/item/ItemSnow.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSnowball.java b/src/game/java/net/minecraft/item/ItemSnowball.java index ff344c64..4ca3730f 100755 --- a/src/game/java/net/minecraft/item/ItemSnowball.java +++ b/src/game/java/net/minecraft/item/ItemSnowball.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSoup.java b/src/game/java/net/minecraft/item/ItemSoup.java index 81f01a99..591990e9 100755 --- a/src/game/java/net/minecraft/item/ItemSoup.java +++ b/src/game/java/net/minecraft/item/ItemSoup.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSpade.java b/src/game/java/net/minecraft/item/ItemSpade.java index 490ba7ae..4fdff6e8 100755 --- a/src/game/java/net/minecraft/item/ItemSpade.java +++ b/src/game/java/net/minecraft/item/ItemSpade.java @@ -13,7 +13,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemStack.java b/src/game/java/net/minecraft/item/ItemStack.java index d88d161e..41e4ec63 100755 --- a/src/game/java/net/minecraft/item/ItemStack.java +++ b/src/game/java/net/minecraft/item/ItemStack.java @@ -47,7 +47,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemSword.java b/src/game/java/net/minecraft/item/ItemSword.java index b6df2591..e74c5e14 100755 --- a/src/game/java/net/minecraft/item/ItemSword.java +++ b/src/game/java/net/minecraft/item/ItemSword.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemTool.java b/src/game/java/net/minecraft/item/ItemTool.java index ba81ebf4..612b3174 100755 --- a/src/game/java/net/minecraft/item/ItemTool.java +++ b/src/game/java/net/minecraft/item/ItemTool.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/ItemWritableBook.java b/src/game/java/net/minecraft/item/ItemWritableBook.java index af13fb3b..e59ff446 100755 --- a/src/game/java/net/minecraft/item/ItemWritableBook.java +++ b/src/game/java/net/minecraft/item/ItemWritableBook.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/CraftingManager.java b/src/game/java/net/minecraft/item/crafting/CraftingManager.java index 14055512..9a9f8484 100755 --- a/src/game/java/net/minecraft/item/crafting/CraftingManager.java +++ b/src/game/java/net/minecraft/item/crafting/CraftingManager.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java b/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java index 17439ca0..c305fd5b 100755 --- a/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java +++ b/src/game/java/net/minecraft/item/crafting/FurnaceRecipes.java @@ -3,6 +3,9 @@ package net.minecraft.item.crafting; import java.util.Map; import java.util.Map.Entry; +import com.carrotsearch.hppc.ObjectFloatHashMap; +import com.carrotsearch.hppc.ObjectFloatMap; +import com.carrotsearch.hppc.cursors.ObjectFloatCursor; import com.google.common.collect.Maps; import net.minecraft.block.Block; @@ -20,7 +23,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -37,7 +40,11 @@ import net.minecraft.item.ItemStack; public class FurnaceRecipes { private static FurnaceRecipes smeltingBase; private Map smeltingList = Maps.newHashMap(); - private Map experienceList = Maps.newHashMap(); + /**+ + * A list which contains how many experience points each recipe + * output will give. + */ + private ObjectFloatMap experienceList = new ObjectFloatHashMap<>(); /**+ * Returns an instance of FurnaceRecipes. @@ -110,7 +117,7 @@ public class FurnaceRecipes { */ public void addSmeltingRecipe(ItemStack input, ItemStack stack, float experience) { this.smeltingList.put(input, stack); - this.experienceList.put(stack, Float.valueOf(experience)); + this.experienceList.put(stack, experience); } /**+ @@ -140,9 +147,9 @@ public class FurnaceRecipes { } public float getSmeltingExperience(ItemStack stack) { - for (Entry entry : this.experienceList.entrySet()) { - if (this.compareItemStacks(stack, (ItemStack) entry.getKey())) { - return ((Float) entry.getValue()).floatValue(); + for (ObjectFloatCursor entry : this.experienceList) { + if (this.compareItemStacks(stack, entry.key)) { + return entry.value; } } diff --git a/src/game/java/net/minecraft/item/crafting/IRecipe.java b/src/game/java/net/minecraft/item/crafting/IRecipe.java index 7ba88803..c8bf80e9 100755 --- a/src/game/java/net/minecraft/item/crafting/IRecipe.java +++ b/src/game/java/net/minecraft/item/crafting/IRecipe.java @@ -10,7 +10,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java b/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java index 49988652..08d0c889 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java +++ b/src/game/java/net/minecraft/item/crafting/RecipeBookCloning.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java b/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java index 81dea9b5..2015e043 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java +++ b/src/game/java/net/minecraft/item/crafting/RecipeFireworks.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java b/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java index b20045b7..fa50c951 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java +++ b/src/game/java/net/minecraft/item/crafting/RecipeRepairItem.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesArmor.java b/src/game/java/net/minecraft/item/crafting/RecipesArmor.java index f42ac617..c794e7af 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesArmor.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesArmor.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java b/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java index d2247fba..6fa7fcbb 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesArmorDyes.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesBanners.java b/src/game/java/net/minecraft/item/crafting/RecipesBanners.java index d8e00de0..344c80ec 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesBanners.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesBanners.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java b/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java index c40e60f1..223b677c 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesCrafting.java @@ -21,7 +21,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesDyes.java b/src/game/java/net/minecraft/item/crafting/RecipesDyes.java index a208dd5e..307e73c5 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesDyes.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesDyes.java @@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesFood.java b/src/game/java/net/minecraft/item/crafting/RecipesFood.java index 0a56418a..4a4b124b 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesFood.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesFood.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesIngots.java b/src/game/java/net/minecraft/item/crafting/RecipesIngots.java index b406b860..f36a27a5 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesIngots.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesIngots.java @@ -12,7 +12,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java b/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java index 75a475c3..a212ab33 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesMapCloning.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java b/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java index 65b0f57f..0e7451fc 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesMapExtending.java @@ -13,7 +13,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesTools.java b/src/game/java/net/minecraft/item/crafting/RecipesTools.java index a78b53c0..988b8d34 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesTools.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesTools.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java b/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java index 3302c338..eec823ed 100755 --- a/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java +++ b/src/game/java/net/minecraft/item/crafting/RecipesWeapons.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java b/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java index e1be923f..ca753d11 100755 --- a/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java +++ b/src/game/java/net/minecraft/item/crafting/ShapedRecipes.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java b/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java index e085b0b3..c7b7a089 100755 --- a/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java +++ b/src/game/java/net/minecraft/item/crafting/ShapelessRecipes.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/CompressedStreamTools.java b/src/game/java/net/minecraft/nbt/CompressedStreamTools.java index 1ba84a0e..298595a4 100755 --- a/src/game/java/net/minecraft/nbt/CompressedStreamTools.java +++ b/src/game/java/net/minecraft/nbt/CompressedStreamTools.java @@ -21,7 +21,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/JsonToNBT.java b/src/game/java/net/minecraft/nbt/JsonToNBT.java index a4efcd63..712e9f20 100755 --- a/src/game/java/net/minecraft/nbt/JsonToNBT.java +++ b/src/game/java/net/minecraft/nbt/JsonToNBT.java @@ -16,7 +16,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTBase.java b/src/game/java/net/minecraft/nbt/NBTBase.java index f3c59fef..6d6c7e7c 100755 --- a/src/game/java/net/minecraft/nbt/NBTBase.java +++ b/src/game/java/net/minecraft/nbt/NBTBase.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTException.java b/src/game/java/net/minecraft/nbt/NBTException.java index 7ea34529..77e527b6 100755 --- a/src/game/java/net/minecraft/nbt/NBTException.java +++ b/src/game/java/net/minecraft/nbt/NBTException.java @@ -6,7 +6,7 @@ package net.minecraft.nbt; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTSizeTracker.java b/src/game/java/net/minecraft/nbt/NBTSizeTracker.java index 14feda88..7f2e0c8a 100755 --- a/src/game/java/net/minecraft/nbt/NBTSizeTracker.java +++ b/src/game/java/net/minecraft/nbt/NBTSizeTracker.java @@ -6,7 +6,7 @@ package net.minecraft.nbt; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagByte.java b/src/game/java/net/minecraft/nbt/NBTTagByte.java index 40ca4064..30d107fe 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagByte.java +++ b/src/game/java/net/minecraft/nbt/NBTTagByte.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagByteArray.java b/src/game/java/net/minecraft/nbt/NBTTagByteArray.java index 63738bf5..f1fae8ae 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagByteArray.java +++ b/src/game/java/net/minecraft/nbt/NBTTagByteArray.java @@ -11,7 +11,7 @@ import java.util.Arrays; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagCompound.java b/src/game/java/net/minecraft/nbt/NBTTagCompound.java index 87fed617..5c12daac 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagCompound.java +++ b/src/game/java/net/minecraft/nbt/NBTTagCompound.java @@ -20,7 +20,7 @@ import net.minecraft.util.ReportedException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagDouble.java b/src/game/java/net/minecraft/nbt/NBTTagDouble.java index 711b8f4e..c6d73d44 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagDouble.java +++ b/src/game/java/net/minecraft/nbt/NBTTagDouble.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagEnd.java b/src/game/java/net/minecraft/nbt/NBTTagEnd.java index 555a32aa..607418f4 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagEnd.java +++ b/src/game/java/net/minecraft/nbt/NBTTagEnd.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagFloat.java b/src/game/java/net/minecraft/nbt/NBTTagFloat.java index 68284e1d..1e4c0cfb 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagFloat.java +++ b/src/game/java/net/minecraft/nbt/NBTTagFloat.java @@ -12,7 +12,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagInt.java b/src/game/java/net/minecraft/nbt/NBTTagInt.java index e63ede6d..62a11c8f 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagInt.java +++ b/src/game/java/net/minecraft/nbt/NBTTagInt.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagIntArray.java b/src/game/java/net/minecraft/nbt/NBTTagIntArray.java index 8432ba50..6fa27750 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagIntArray.java +++ b/src/game/java/net/minecraft/nbt/NBTTagIntArray.java @@ -11,7 +11,7 @@ import java.util.Arrays; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagList.java b/src/game/java/net/minecraft/nbt/NBTTagList.java index b3853d04..a578f758 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagList.java +++ b/src/game/java/net/minecraft/nbt/NBTTagList.java @@ -16,7 +16,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagLong.java b/src/game/java/net/minecraft/nbt/NBTTagLong.java index 6ebe6233..cc2accf6 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagLong.java +++ b/src/game/java/net/minecraft/nbt/NBTTagLong.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagShort.java b/src/game/java/net/minecraft/nbt/NBTTagShort.java index 34dd3300..ec531aba 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagShort.java +++ b/src/game/java/net/minecraft/nbt/NBTTagShort.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTTagString.java b/src/game/java/net/minecraft/nbt/NBTTagString.java index 5d4fb080..9107d9ad 100755 --- a/src/game/java/net/minecraft/nbt/NBTTagString.java +++ b/src/game/java/net/minecraft/nbt/NBTTagString.java @@ -10,7 +10,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/nbt/NBTUtil.java b/src/game/java/net/minecraft/nbt/NBTUtil.java index ba1d1d77..b513935d 100755 --- a/src/game/java/net/minecraft/nbt/NBTUtil.java +++ b/src/game/java/net/minecraft/nbt/NBTUtil.java @@ -15,7 +15,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/EnumConnectionState.java b/src/game/java/net/minecraft/network/EnumConnectionState.java index 1c0b4a17..23b651f7 100755 --- a/src/game/java/net/minecraft/network/EnumConnectionState.java +++ b/src/game/java/net/minecraft/network/EnumConnectionState.java @@ -117,7 +117,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/EnumPacketDirection.java b/src/game/java/net/minecraft/network/EnumPacketDirection.java index a31334f7..3863cf23 100755 --- a/src/game/java/net/minecraft/network/EnumPacketDirection.java +++ b/src/game/java/net/minecraft/network/EnumPacketDirection.java @@ -6,7 +6,7 @@ package net.minecraft.network; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/INetHandler.java b/src/game/java/net/minecraft/network/INetHandler.java index 604541c4..fa393751 100755 --- a/src/game/java/net/minecraft/network/INetHandler.java +++ b/src/game/java/net/minecraft/network/INetHandler.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/NetHandlerPlayServer.java b/src/game/java/net/minecraft/network/NetHandlerPlayServer.java index c1a3a064..b1005872 100755 --- a/src/game/java/net/minecraft/network/NetHandlerPlayServer.java +++ b/src/game/java/net/minecraft/network/NetHandlerPlayServer.java @@ -1,5 +1,7 @@ package net.minecraft.network; +import com.carrotsearch.hppc.IntShortHashMap; +import com.carrotsearch.hppc.IntShortMap; import com.google.common.collect.Lists; import com.google.common.primitives.Doubles; import com.google.common.primitives.Floats; @@ -88,7 +90,6 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.EnumFacing; import net.minecraft.util.IChatComponent; import net.minecraft.util.ITickable; -import net.minecraft.util.IntHashMap; import net.minecraft.util.ReportedException; import net.minecraft.world.WorldServer; import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager; @@ -105,7 +106,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -134,7 +135,7 @@ public class NetHandlerPlayServer implements INetHandlerPlayServer, ITickable { private long lastSentPingPacket; private int chatSpamThresholdCount; private int itemDropThreshold; - private IntHashMap field_147372_n = new IntHashMap(); + private IntShortMap field_147372_n = new IntShortHashMap(); private double lastPosX; private double lastPosY; private double lastPosZ; @@ -928,8 +929,8 @@ public class NetHandlerPlayServer implements INetHandlerPlayServer, ITickable { this.playerEntity.updateHeldItem(); this.playerEntity.isChangingQuantityOnly = false; } else { - this.field_147372_n.addKey(this.playerEntity.openContainer.windowId, - Short.valueOf(c0epacketclickwindow.getActionNumber())); + this.field_147372_n.put(this.playerEntity.openContainer.windowId, + c0epacketclickwindow.getActionNumber()); this.playerEntity.playerNetServerHandler.sendPacket(new S32PacketConfirmTransaction( c0epacketclickwindow.getWindowId(), c0epacketclickwindow.getActionNumber(), false)); this.playerEntity.openContainer.setCanCraft(this.playerEntity, false); @@ -1019,14 +1020,14 @@ public class NetHandlerPlayServer implements INetHandlerPlayServer, ITickable { * player's ability to manipulate the container contents */ public void processConfirmTransaction(C0FPacketConfirmTransaction c0fpacketconfirmtransaction) { - Short oshort = (Short) this.field_147372_n.lookup(this.playerEntity.openContainer.windowId); - if (oshort != null && c0fpacketconfirmtransaction.getUid() == oshort.shortValue() - && this.playerEntity.openContainer.windowId == c0fpacketconfirmtransaction.getWindowId() + int windowId = this.playerEntity.openContainer.windowId; + if (this.field_147372_n.containsKey(windowId) + && c0fpacketconfirmtransaction.getUid() == this.field_147372_n.get(windowId) + && windowId == c0fpacketconfirmtransaction.getWindowId() && !this.playerEntity.openContainer.getCanCraft(this.playerEntity) && !this.playerEntity.isSpectator()) { this.playerEntity.openContainer.setCanCraft(this.playerEntity, true); } - } public void processUpdateSign(C12PacketUpdateSign c12packetupdatesign) { diff --git a/src/game/java/net/minecraft/network/Packet.java b/src/game/java/net/minecraft/network/Packet.java index 13bcf6ea..131cd2c6 100755 --- a/src/game/java/net/minecraft/network/Packet.java +++ b/src/game/java/net/minecraft/network/Packet.java @@ -8,7 +8,7 @@ import java.io.IOException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/PacketBuffer.java b/src/game/java/net/minecraft/network/PacketBuffer.java index 2a151308..a7d35846 100755 --- a/src/game/java/net/minecraft/network/PacketBuffer.java +++ b/src/game/java/net/minecraft/network/PacketBuffer.java @@ -30,7 +30,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/ServerStatusResponse.java b/src/game/java/net/minecraft/network/ServerStatusResponse.java index 38f2ad12..39b19781 100755 --- a/src/game/java/net/minecraft/network/ServerStatusResponse.java +++ b/src/game/java/net/minecraft/network/ServerStatusResponse.java @@ -16,7 +16,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java b/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java index 0bde65df..59593efd 100755 --- a/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java +++ b/src/game/java/net/minecraft/network/handshake/INetHandlerHandshakeServer.java @@ -9,7 +9,7 @@ import net.minecraft.network.handshake.client.C00Handshake; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java b/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java index 8d430b01..7b443998 100755 --- a/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java +++ b/src/game/java/net/minecraft/network/handshake/client/C00Handshake.java @@ -13,7 +13,7 @@ import net.minecraft.network.handshake.INetHandlerHandshakeServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java b/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java index ae351a07..ce48fe1f 100755 --- a/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java +++ b/src/game/java/net/minecraft/network/login/INetHandlerLoginClient.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.server.S03PacketEnableCompression; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java b/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java index d0662d03..229642e3 100755 --- a/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java +++ b/src/game/java/net/minecraft/network/login/INetHandlerLoginServer.java @@ -10,7 +10,7 @@ import net.minecraft.network.login.client.C01PacketEncryptionResponse; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java b/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java index c2674ba2..08ea7ee7 100755 --- a/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java +++ b/src/game/java/net/minecraft/network/login/client/C00PacketLoginStart.java @@ -13,7 +13,7 @@ import net.minecraft.network.login.INetHandlerLoginServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java b/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java index fb8603e9..a6136398 100755 --- a/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java +++ b/src/game/java/net/minecraft/network/login/client/C01PacketEncryptionResponse.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.INetHandlerLoginServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java b/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java index 3a0b6077..be4d1e43 100755 --- a/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java +++ b/src/game/java/net/minecraft/network/login/server/S00PacketDisconnect.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java b/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java index b54a96a1..3db2bacb 100755 --- a/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java +++ b/src/game/java/net/minecraft/network/login/server/S01PacketEncryptionRequest.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.INetHandlerLoginClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java b/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java index da521262..83189444 100755 --- a/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java +++ b/src/game/java/net/minecraft/network/login/server/S02PacketLoginSuccess.java @@ -14,7 +14,7 @@ import net.minecraft.network.login.INetHandlerLoginClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java b/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java index 8326206a..737ae33b 100755 --- a/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java +++ b/src/game/java/net/minecraft/network/login/server/S03PacketEnableCompression.java @@ -12,7 +12,7 @@ import net.minecraft.network.login.INetHandlerLoginClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java b/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java index 9e9a19d9..ea688c47 100755 --- a/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java +++ b/src/game/java/net/minecraft/network/play/INetHandlerPlayClient.java @@ -79,7 +79,7 @@ import net.minecraft.network.play.server.S49PacketUpdateEntityNBT; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java b/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java index d6a4b5bc..2ed788b6 100755 --- a/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java +++ b/src/game/java/net/minecraft/network/play/INetHandlerPlayServer.java @@ -31,7 +31,7 @@ import net.minecraft.network.play.client.C19PacketResourcePackStatus; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java b/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java index 92d6baae..ea7ef33c 100755 --- a/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java +++ b/src/game/java/net/minecraft/network/play/client/C00PacketKeepAlive.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java b/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java index 99f29fda..8fd8c4ec 100755 --- a/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java +++ b/src/game/java/net/minecraft/network/play/client/C01PacketChatMessage.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java b/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java index 815ed7cc..ce046bc6 100755 --- a/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java +++ b/src/game/java/net/minecraft/network/play/client/C02PacketUseEntity.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java b/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java index 0b5cbf7c..fd010126 100755 --- a/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java +++ b/src/game/java/net/minecraft/network/play/client/C03PacketPlayer.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java b/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java index 268f3407..d1cd7309 100755 --- a/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java +++ b/src/game/java/net/minecraft/network/play/client/C07PacketPlayerDigging.java @@ -14,7 +14,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java b/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java index 178c71c2..410ca004 100755 --- a/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java +++ b/src/game/java/net/minecraft/network/play/client/C08PacketPlayerBlockPlacement.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java b/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java index dce72c76..efbf45ef 100755 --- a/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java +++ b/src/game/java/net/minecraft/network/play/client/C09PacketHeldItemChange.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java b/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java index 88ff6ea9..c5a08581 100755 --- a/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java +++ b/src/game/java/net/minecraft/network/play/client/C0APacketAnimation.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java b/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java index e7cce2a0..db46b39f 100755 --- a/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java +++ b/src/game/java/net/minecraft/network/play/client/C0BPacketEntityAction.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java b/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java index a9af9a67..3a046db8 100755 --- a/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java +++ b/src/game/java/net/minecraft/network/play/client/C0CPacketInput.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java b/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java index 2ebfeef7..55fb554e 100755 --- a/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java +++ b/src/game/java/net/minecraft/network/play/client/C0DPacketCloseWindow.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java b/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java index df1a9019..365299f7 100755 --- a/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java +++ b/src/game/java/net/minecraft/network/play/client/C0EPacketClickWindow.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java b/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java index 33515cf1..64ab6a7b 100755 --- a/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java +++ b/src/game/java/net/minecraft/network/play/client/C0FPacketConfirmTransaction.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java b/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java index a33d3b64..7642226a 100755 --- a/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java +++ b/src/game/java/net/minecraft/network/play/client/C10PacketCreativeInventoryAction.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java b/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java index f2ae5f3f..69a282de 100755 --- a/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java +++ b/src/game/java/net/minecraft/network/play/client/C11PacketEnchantItem.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java b/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java index 1c984cc6..8563b373 100755 --- a/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java +++ b/src/game/java/net/minecraft/network/play/client/C12PacketUpdateSign.java @@ -14,7 +14,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java b/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java index 0e249763..557492f9 100755 --- a/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java +++ b/src/game/java/net/minecraft/network/play/client/C13PacketPlayerAbilities.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java b/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java index 90712ee0..0605e5b7 100755 --- a/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java +++ b/src/game/java/net/minecraft/network/play/client/C14PacketTabComplete.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java b/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java index 933e6f77..86890d53 100755 --- a/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java +++ b/src/game/java/net/minecraft/network/play/client/C15PacketClientSettings.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java b/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java index 5cc4658a..81fdd1ed 100755 --- a/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java +++ b/src/game/java/net/minecraft/network/play/client/C16PacketClientStatus.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java b/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java index 20589d05..18852ad1 100755 --- a/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java +++ b/src/game/java/net/minecraft/network/play/client/C17PacketCustomPayload.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java b/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java index c3b95a42..6c0410ed 100755 --- a/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java +++ b/src/game/java/net/minecraft/network/play/client/C18PacketSpectate.java @@ -14,7 +14,7 @@ import net.minecraft.world.WorldServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java b/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java index d0103f94..a18a134c 100755 --- a/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java +++ b/src/game/java/net/minecraft/network/play/client/C19PacketResourcePackStatus.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java b/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java index 1870cdba..a3ed1088 100755 --- a/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java +++ b/src/game/java/net/minecraft/network/play/server/S00PacketKeepAlive.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java b/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java index 1b366b09..65dd6459 100755 --- a/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java +++ b/src/game/java/net/minecraft/network/play/server/S01PacketJoinGame.java @@ -15,7 +15,7 @@ import net.minecraft.world.WorldType; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S02PacketChat.java b/src/game/java/net/minecraft/network/play/server/S02PacketChat.java index 262eef6f..8aba9dde 100755 --- a/src/game/java/net/minecraft/network/play/server/S02PacketChat.java +++ b/src/game/java/net/minecraft/network/play/server/S02PacketChat.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java b/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java index 80dd7fc5..4d2ea84a 100755 --- a/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java +++ b/src/game/java/net/minecraft/network/play/server/S03PacketTimeUpdate.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java b/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java index 7fb92d65..d34df912 100755 --- a/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java +++ b/src/game/java/net/minecraft/network/play/server/S04PacketEntityEquipment.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java b/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java index 6315718e..cf70ffb4 100755 --- a/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java +++ b/src/game/java/net/minecraft/network/play/server/S05PacketSpawnPosition.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java b/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java index 3818bc3e..3eaf465f 100755 --- a/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java +++ b/src/game/java/net/minecraft/network/play/server/S06PacketUpdateHealth.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java b/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java index 3fb5f615..48097b47 100755 --- a/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java +++ b/src/game/java/net/minecraft/network/play/server/S07PacketRespawn.java @@ -15,7 +15,7 @@ import net.minecraft.world.WorldType; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java b/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java index 7f8701c8..dbc4c632 100755 --- a/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java +++ b/src/game/java/net/minecraft/network/play/server/S08PacketPlayerPosLook.java @@ -14,7 +14,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java b/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java index 560e3da0..e36801d0 100755 --- a/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java +++ b/src/game/java/net/minecraft/network/play/server/S09PacketHeldItemChange.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java b/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java index 757ce11b..b1f0727d 100755 --- a/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java +++ b/src/game/java/net/minecraft/network/play/server/S0APacketUseBed.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java b/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java index 426b15ed..b4b993a4 100755 --- a/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java +++ b/src/game/java/net/minecraft/network/play/server/S0BPacketAnimation.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java b/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java index 1fb5008c..9b7b6c5d 100755 --- a/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java +++ b/src/game/java/net/minecraft/network/play/server/S0CPacketSpawnPlayer.java @@ -19,7 +19,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java b/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java index 4b463258..b31a1f7b 100755 --- a/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java +++ b/src/game/java/net/minecraft/network/play/server/S0DPacketCollectItem.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java b/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java index 35d82274..a278cd76 100755 --- a/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java +++ b/src/game/java/net/minecraft/network/play/server/S0EPacketSpawnObject.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java b/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java index 73f3fee5..64d41fc1 100755 --- a/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java +++ b/src/game/java/net/minecraft/network/play/server/S0FPacketSpawnMob.java @@ -17,7 +17,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java b/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java index 430ccec0..3f51f69b 100755 --- a/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java +++ b/src/game/java/net/minecraft/network/play/server/S10PacketSpawnPainting.java @@ -15,7 +15,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java b/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java index e22b387b..f41d2170 100755 --- a/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java +++ b/src/game/java/net/minecraft/network/play/server/S11PacketSpawnExperienceOrb.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java b/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java index c3fbc630..ee56af6d 100755 --- a/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java +++ b/src/game/java/net/minecraft/network/play/server/S12PacketEntityVelocity.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java b/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java index e038cb99..0ae5e329 100755 --- a/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java +++ b/src/game/java/net/minecraft/network/play/server/S13PacketDestroyEntities.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java b/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java index 9ed2dcb3..077c3235 100755 --- a/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java +++ b/src/game/java/net/minecraft/network/play/server/S14PacketEntity.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java b/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java index e873c91e..00888838 100755 --- a/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java +++ b/src/game/java/net/minecraft/network/play/server/S18PacketEntityTeleport.java @@ -14,7 +14,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java b/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java index d1adefc5..94e2ad61 100755 --- a/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java +++ b/src/game/java/net/minecraft/network/play/server/S19PacketEntityHeadLook.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java b/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java index 6dd331f6..e598059c 100755 --- a/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java +++ b/src/game/java/net/minecraft/network/play/server/S19PacketEntityStatus.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java b/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java index c2e8636c..af1c31f7 100755 --- a/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java +++ b/src/game/java/net/minecraft/network/play/server/S1BPacketEntityAttach.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java b/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java index 79984f18..34b5ce86 100755 --- a/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java +++ b/src/game/java/net/minecraft/network/play/server/S1CPacketEntityMetadata.java @@ -14,7 +14,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java b/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java index fd3f9e07..d1a33b62 100755 --- a/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S1DPacketEntityEffect.java @@ -13,7 +13,7 @@ import net.minecraft.potion.PotionEffect; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java b/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java index e3d5e989..3f769314 100755 --- a/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S1EPacketRemoveEntityEffect.java @@ -13,7 +13,7 @@ import net.minecraft.potion.PotionEffect; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java b/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java index e398627e..aae8c968 100755 --- a/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java +++ b/src/game/java/net/minecraft/network/play/server/S1FPacketSetExperience.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java b/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java index 65e9cf80..efe5df6a 100755 --- a/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java +++ b/src/game/java/net/minecraft/network/play/server/S20PacketEntityProperties.java @@ -20,7 +20,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java b/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java index 202ecd34..5b8578ea 100755 --- a/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java +++ b/src/game/java/net/minecraft/network/play/server/S21PacketChunkData.java @@ -17,7 +17,7 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java b/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java index 85612f06..7ef56493 100755 --- a/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java +++ b/src/game/java/net/minecraft/network/play/server/S22PacketMultiBlockChange.java @@ -17,7 +17,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java b/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java index ee2e4346..181a53d2 100755 --- a/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java +++ b/src/game/java/net/minecraft/network/play/server/S23PacketBlockChange.java @@ -16,7 +16,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java b/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java index 5effada3..cdfd9d03 100755 --- a/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java +++ b/src/game/java/net/minecraft/network/play/server/S24PacketBlockAction.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java b/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java index c436f516..a443595b 100755 --- a/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java +++ b/src/game/java/net/minecraft/network/play/server/S25PacketBlockBreakAnim.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java b/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java index 3da9332a..36b9eed6 100755 --- a/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java +++ b/src/game/java/net/minecraft/network/play/server/S26PacketMapChunkBulk.java @@ -14,7 +14,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java b/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java index 5957af7c..34b17201 100755 --- a/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java +++ b/src/game/java/net/minecraft/network/play/server/S27PacketExplosion.java @@ -17,7 +17,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java b/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java index b22379bd..f8e02f5c 100755 --- a/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S28PacketEffect.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java b/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java index 563b8235..7caa9281 100755 --- a/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java +++ b/src/game/java/net/minecraft/network/play/server/S29PacketSoundEffect.java @@ -15,7 +15,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java b/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java index d6e3ab44..c32af4ea 100755 --- a/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java +++ b/src/game/java/net/minecraft/network/play/server/S2APacketParticles.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumParticleTypes; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java b/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java index 1a0235aa..869664a2 100755 --- a/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java +++ b/src/game/java/net/minecraft/network/play/server/S2BPacketChangeGameState.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java b/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java index e1838b4a..a2b10fe1 100755 --- a/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java +++ b/src/game/java/net/minecraft/network/play/server/S2CPacketSpawnGlobalEntity.java @@ -15,7 +15,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java b/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java index df7f4584..25f15d8a 100755 --- a/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java +++ b/src/game/java/net/minecraft/network/play/server/S2DPacketOpenWindow.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java b/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java index 4a584608..d8a97602 100755 --- a/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java +++ b/src/game/java/net/minecraft/network/play/server/S2EPacketCloseWindow.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java b/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java index 65917702..35fa5bd2 100755 --- a/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java +++ b/src/game/java/net/minecraft/network/play/server/S2FPacketSetSlot.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java b/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java index a75fe45d..b60ce29d 100755 --- a/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java +++ b/src/game/java/net/minecraft/network/play/server/S30PacketWindowItems.java @@ -14,7 +14,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java b/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java index fb7a14ee..0c06ca26 100755 --- a/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java +++ b/src/game/java/net/minecraft/network/play/server/S31PacketWindowProperty.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java b/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java index 230538b3..f340d3d4 100755 --- a/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java +++ b/src/game/java/net/minecraft/network/play/server/S32PacketConfirmTransaction.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java b/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java index 79678ce8..80e3a79d 100755 --- a/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java +++ b/src/game/java/net/minecraft/network/play/server/S33PacketUpdateSign.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java b/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java index bbdfb8f0..a60f14d2 100755 --- a/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java +++ b/src/game/java/net/minecraft/network/play/server/S34PacketMaps.java @@ -15,7 +15,7 @@ import net.minecraft.world.storage.MapData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java b/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java index db1ab324..bfda1323 100755 --- a/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java +++ b/src/game/java/net/minecraft/network/play/server/S35PacketUpdateTileEntity.java @@ -14,7 +14,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java b/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java index 8511cd0c..7b45e5b0 100755 --- a/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java +++ b/src/game/java/net/minecraft/network/play/server/S36PacketSignEditorOpen.java @@ -13,7 +13,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java b/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java index cc0512a4..ca2bfe06 100755 --- a/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java +++ b/src/game/java/net/minecraft/network/play/server/S37PacketStatistics.java @@ -1,10 +1,10 @@ package net.minecraft.network.play.server; import java.io.IOException; -import java.util.Map; -import java.util.Map.Entry; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; +import com.carrotsearch.hppc.cursors.ObjectIntCursor; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; @@ -18,7 +18,7 @@ import net.minecraft.stats.StatList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -33,12 +33,12 @@ import net.minecraft.stats.StatList; * */ public class S37PacketStatistics implements Packet { - private Map field_148976_a; + private ObjectIntMap field_148976_a; public S37PacketStatistics() { } - public S37PacketStatistics(Map parMap) { + public S37PacketStatistics(ObjectIntMap parMap) { this.field_148976_a = parMap; } @@ -54,13 +54,13 @@ public class S37PacketStatistics implements Packet { */ public void readPacketData(PacketBuffer parPacketBuffer) throws IOException { int i = parPacketBuffer.readVarIntFromBuffer(); - this.field_148976_a = Maps.newHashMap(); + this.field_148976_a = new ObjectIntHashMap<>(); for (int j = 0; j < i; ++j) { StatBase statbase = StatList.getOneShotStat(parPacketBuffer.readStringFromBuffer(32767)); int k = parPacketBuffer.readVarIntFromBuffer(); if (statbase != null) { - this.field_148976_a.put(statbase, Integer.valueOf(k)); + this.field_148976_a.put(statbase, k); } } @@ -72,14 +72,14 @@ public class S37PacketStatistics implements Packet { public void writePacketData(PacketBuffer parPacketBuffer) throws IOException { parPacketBuffer.writeVarIntToBuffer(this.field_148976_a.size()); - for (Entry entry : this.field_148976_a.entrySet()) { - parPacketBuffer.writeString(((StatBase) entry.getKey()).statId); - parPacketBuffer.writeVarIntToBuffer(((Integer) entry.getValue()).intValue()); + for (ObjectIntCursor entry : this.field_148976_a) { + parPacketBuffer.writeString(entry.key.statId); + parPacketBuffer.writeVarIntToBuffer(entry.value); } } - public Map func_148974_c() { + public ObjectIntMap func_148974_c() { return this.field_148976_a; } } \ No newline at end of file diff --git a/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java b/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java index 64767a3f..33cdcaf2 100755 --- a/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java +++ b/src/game/java/net/minecraft/network/play/server/S38PacketPlayerListItem.java @@ -19,7 +19,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java b/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java index 81f63b49..f173d655 100755 --- a/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java +++ b/src/game/java/net/minecraft/network/play/server/S39PacketPlayerAbilities.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java b/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java index ef4ed229..45289bbd 100755 --- a/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java +++ b/src/game/java/net/minecraft/network/play/server/S3APacketTabComplete.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java b/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java index c8e2ff10..5036b0e0 100755 --- a/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java +++ b/src/game/java/net/minecraft/network/play/server/S3BPacketScoreboardObjective.java @@ -14,7 +14,7 @@ import net.minecraft.scoreboard.ScoreObjective; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java b/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java index fec4cbca..c46081e9 100755 --- a/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java +++ b/src/game/java/net/minecraft/network/play/server/S3CPacketUpdateScore.java @@ -14,7 +14,7 @@ import net.minecraft.scoreboard.ScoreObjective; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java b/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java index 116d4a59..824a4838 100755 --- a/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java +++ b/src/game/java/net/minecraft/network/play/server/S3DPacketDisplayScoreboard.java @@ -13,7 +13,7 @@ import net.minecraft.scoreboard.ScoreObjective; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java b/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java index b4623d4b..05b486e7 100755 --- a/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java +++ b/src/game/java/net/minecraft/network/play/server/S3EPacketTeams.java @@ -17,7 +17,7 @@ import net.minecraft.scoreboard.Team; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java b/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java index 86ce71ac..b29edac3 100755 --- a/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java +++ b/src/game/java/net/minecraft/network/play/server/S3FPacketCustomPayload.java @@ -13,7 +13,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java b/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java index d3d7b7b7..428f97ee 100755 --- a/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java +++ b/src/game/java/net/minecraft/network/play/server/S40PacketDisconnect.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java b/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java index 45dceca3..ea08b508 100755 --- a/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java +++ b/src/game/java/net/minecraft/network/play/server/S41PacketServerDifficulty.java @@ -13,7 +13,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java b/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java index 9d534fc8..7f9b0b03 100755 --- a/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java +++ b/src/game/java/net/minecraft/network/play/server/S42PacketCombatEvent.java @@ -14,7 +14,7 @@ import net.minecraft.util.CombatTracker; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java b/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java index ce25ffd7..528de395 100755 --- a/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java +++ b/src/game/java/net/minecraft/network/play/server/S43PacketCamera.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java b/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java index bca409d9..97622c78 100755 --- a/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java +++ b/src/game/java/net/minecraft/network/play/server/S44PacketWorldBorder.java @@ -13,7 +13,7 @@ import net.minecraft.world.border.WorldBorder; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java b/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java index aef2749a..57fe6d0a 100755 --- a/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java +++ b/src/game/java/net/minecraft/network/play/server/S45PacketTitle.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java b/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java index 247e978c..27e20f49 100755 --- a/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java +++ b/src/game/java/net/minecraft/network/play/server/S46PacketSetCompressionLevel.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java b/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java index 888c18fd..048f46ff 100755 --- a/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java +++ b/src/game/java/net/minecraft/network/play/server/S47PacketPlayerListHeaderFooter.java @@ -13,7 +13,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java b/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java index 56b20fed..59b9f0cd 100755 --- a/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java +++ b/src/game/java/net/minecraft/network/play/server/S48PacketResourcePackSend.java @@ -12,7 +12,7 @@ import net.minecraft.network.play.INetHandlerPlayClient; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java b/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java index b8c1b361..3deb3479 100755 --- a/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java +++ b/src/game/java/net/minecraft/network/play/server/S49PacketUpdateEntityNBT.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/pathfinding/Path.java b/src/game/java/net/minecraft/pathfinding/Path.java index 9d1c49c5..4f8eadff 100755 --- a/src/game/java/net/minecraft/pathfinding/Path.java +++ b/src/game/java/net/minecraft/pathfinding/Path.java @@ -6,7 +6,7 @@ package net.minecraft.pathfinding; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/pathfinding/PathEntity.java b/src/game/java/net/minecraft/pathfinding/PathEntity.java index ea31ba58..8e8e41a2 100755 --- a/src/game/java/net/minecraft/pathfinding/PathEntity.java +++ b/src/game/java/net/minecraft/pathfinding/PathEntity.java @@ -9,7 +9,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/pathfinding/PathFinder.java b/src/game/java/net/minecraft/pathfinding/PathFinder.java index 9e81fb81..5079c720 100755 --- a/src/game/java/net/minecraft/pathfinding/PathFinder.java +++ b/src/game/java/net/minecraft/pathfinding/PathFinder.java @@ -11,7 +11,7 @@ import net.minecraft.world.pathfinder.NodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigate.java b/src/game/java/net/minecraft/pathfinding/PathNavigate.java index de3f7eed..359ec826 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigate.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigate.java @@ -5,6 +5,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.IAttributeInstance; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.MathHelper; @@ -18,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -40,6 +41,8 @@ public abstract class PathNavigate { private final IAttributeInstance pathSearchRange; private int totalTicks; private int ticksAtLastPos; + private int lastFailure = 0; + private int pathfindFailures = 0; /**+ * Coordinates of the entity's position last time a check was * done (part of monitoring getting 'stuck') @@ -134,8 +137,23 @@ public abstract class PathNavigate { * successful. Args : entity, speed */ public boolean tryMoveToEntityLiving(Entity entityIn, double speedIn) { + int i = -1; + if (this.pathfindFailures > 10 && this.currentPath == null + && (i = (int) (MinecraftServer.getCurrentTimeMillis() / 50l)) < this.lastFailure + 40) { + return false; + } + PathEntity pathentity = this.getPathToEntityLiving(entityIn); - return pathentity != null ? this.setPath(pathentity, speedIn) : false; + + if (pathentity != null && this.setPath(pathentity, speedIn)) { + this.lastFailure = 0; + this.pathfindFailures = 0; + return true; + } else { + this.pathfindFailures++; + this.lastFailure = i == -1 ? (int) (MinecraftServer.getCurrentTimeMillis() / 50l) : i; + return false; + } } /**+ @@ -273,6 +291,8 @@ public abstract class PathNavigate { * sets active PathEntity to null */ public void clearPathEntity() { + this.pathfindFailures = 0; + this.lastFailure = 0; this.currentPath = null; } diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java b/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java index 8cd3c4b7..26b91f82 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigateClimber.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java b/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java index 005c9df7..5e1d8cfc 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigateGround.java @@ -18,7 +18,7 @@ import net.minecraft.world.pathfinder.WalkNodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java b/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java index f96182fd..cbdf9984 100755 --- a/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java +++ b/src/game/java/net/minecraft/pathfinding/PathNavigateSwimmer.java @@ -12,7 +12,7 @@ import net.minecraft.world.pathfinder.SwimNodeProcessor; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/pathfinding/PathPoint.java b/src/game/java/net/minecraft/pathfinding/PathPoint.java index 9cf4234b..806ad93d 100755 --- a/src/game/java/net/minecraft/pathfinding/PathPoint.java +++ b/src/game/java/net/minecraft/pathfinding/PathPoint.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/potion/Potion.java b/src/game/java/net/minecraft/potion/Potion.java index c94a062e..2857a139 100755 --- a/src/game/java/net/minecraft/potion/Potion.java +++ b/src/game/java/net/minecraft/potion/Potion.java @@ -25,7 +25,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/potion/PotionAbsorption.java b/src/game/java/net/minecraft/potion/PotionAbsorption.java index 787b416f..c6563eb9 100755 --- a/src/game/java/net/minecraft/potion/PotionAbsorption.java +++ b/src/game/java/net/minecraft/potion/PotionAbsorption.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/potion/PotionAttackDamage.java b/src/game/java/net/minecraft/potion/PotionAttackDamage.java index 37f6c30f..e0e24a9d 100755 --- a/src/game/java/net/minecraft/potion/PotionAttackDamage.java +++ b/src/game/java/net/minecraft/potion/PotionAttackDamage.java @@ -9,7 +9,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/potion/PotionEffect.java b/src/game/java/net/minecraft/potion/PotionEffect.java index abba81b4..6b3d0540 100755 --- a/src/game/java/net/minecraft/potion/PotionEffect.java +++ b/src/game/java/net/minecraft/potion/PotionEffect.java @@ -11,7 +11,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/potion/PotionHealth.java b/src/game/java/net/minecraft/potion/PotionHealth.java index 86587959..74ede3f6 100755 --- a/src/game/java/net/minecraft/potion/PotionHealth.java +++ b/src/game/java/net/minecraft/potion/PotionHealth.java @@ -8,7 +8,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/potion/PotionHealthBoost.java b/src/game/java/net/minecraft/potion/PotionHealthBoost.java index d477727e..2a60dc80 100755 --- a/src/game/java/net/minecraft/potion/PotionHealthBoost.java +++ b/src/game/java/net/minecraft/potion/PotionHealthBoost.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/potion/PotionHelper.java b/src/game/java/net/minecraft/potion/PotionHelper.java index a49a36fc..7b513a86 100755 --- a/src/game/java/net/minecraft/potion/PotionHelper.java +++ b/src/game/java/net/minecraft/potion/PotionHelper.java @@ -3,12 +3,14 @@ package net.minecraft.potion; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; +import com.carrotsearch.hppc.IntIntHashMap; +import com.carrotsearch.hppc.IntIntMap; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.ObjectContainer; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import net.minecraft.util.IntegerCache; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -16,7 +18,7 @@ import net.minecraft.util.IntegerCache; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -45,9 +47,9 @@ public class PotionHelper { public static final String goldenCarrotEffect = "-0+1+2-3+13&4-4"; public static final String pufferfishEffect = "+0-1+2+3+13&4-4"; public static final String rabbitFootEffect = "+0+1-2+3&4-4+13"; - private static final Map potionRequirements = Maps.newHashMap(); - private static final Map potionAmplifiers = Maps.newHashMap(); - private static final Map DATAVALUE_COLORS = Maps.newHashMap(); + private static final IntObjectMap potionRequirements = new IntObjectHashMap<>(); + private static final IntObjectMap potionAmplifiers = new IntObjectHashMap<>(); + private static final IntIntMap DATAVALUE_COLORS = new IntIntHashMap(); /**+ * An array of possible potion prefix names, as translation IDs. */ @@ -133,6 +135,45 @@ public class PotionHelper { } } + /**+ + * Given a {@link Collection}<{@link PotionEffect}> will return + * an Integer color. + */ + public static int calcPotionLiquidColor(ObjectContainer parCollection) { + int i = 3694022; + if (parCollection != null && !parCollection.isEmpty()) { + float f = 0.0F; + float f1 = 0.0F; + float f2 = 0.0F; + float f3 = 0.0F; + + for (ObjectCursor potioneffect_ : parCollection) { + PotionEffect potioneffect = potioneffect_.value; + if (potioneffect.getIsShowParticles()) { + int j = Potion.potionTypes[potioneffect.getPotionID()].getLiquidColor(); + + for (int k = 0; k <= potioneffect.getAmplifier(); ++k) { + f += (float) (j >> 16 & 255) / 255.0F; + f1 += (float) (j >> 8 & 255) / 255.0F; + f2 += (float) (j >> 0 & 255) / 255.0F; + ++f3; + } + } + } + + if (f3 == 0.0F) { + return 0; + } else { + f = f / f3 * 255.0F; + f1 = f1 / f3 * 255.0F; + f2 = f2 / f3 * 255.0F; + return (int) f << 16 | (int) f1 << 8 | (int) f2; + } + } else { + return i; + } + } + /**+ * Check whether a {@link Collection}<{@link PotionEffect}> are * all ambient. @@ -147,18 +188,32 @@ public class PotionHelper { return true; } + /**+ + * Check whether a {@link Collection}<{@link PotionEffect}> are + * all ambient. + */ + public static boolean getAreAmbient(ObjectContainer potionEffects) { + for (ObjectCursor potioneffect : potionEffects) { + if (!potioneffect.value.getIsAmbient()) { + return false; + } + } + + return true; + } + /**+ * Given a potion data value, get the associated liquid color * (optionally bypassing the cache) */ public static int getLiquidColor(int dataValue, boolean bypassCache) { - Integer integer = IntegerCache.func_181756_a(dataValue); if (!bypassCache) { - if (DATAVALUE_COLORS.containsKey(integer)) { - return ((Integer) DATAVALUE_COLORS.get(integer)).intValue(); + int i = DATAVALUE_COLORS.getOrDefault(dataValue, -1); + if (i != -1) { + return i; } else { - int i = calcPotionLiquidColor(getPotionEffects(integer.intValue(), false)); - DATAVALUE_COLORS.put(integer, Integer.valueOf(i)); + i = calcPotionLiquidColor(getPotionEffects(dataValue, false)); + DATAVALUE_COLORS.put(dataValue, i); return i; } } else { @@ -166,7 +221,7 @@ public class PotionHelper { * Given a {@link Collection}<{@link PotionEffect}> will return * an Integer color. */ - return calcPotionLiquidColor(getPotionEffects(integer.intValue(), true)); + return calcPotionLiquidColor(getPotionEffects(dataValue, true)); } } @@ -349,12 +404,12 @@ public class PotionHelper { for (int k = 0; k < Potion.potionTypes.length; ++k) { Potion potion = Potion.potionTypes[k]; if (potion != null && (!potion.isUsable() || parFlag)) { - String s = (String) potionRequirements.get(Integer.valueOf(potion.getId())); + String s = potionRequirements.get(potion.getId()); if (s != null) { int i = parsePotionEffects(s, 0, s.length(), parInt1); if (i > 0) { int j = 0; - String s1 = (String) potionAmplifiers.get(Integer.valueOf(potion.getId())); + String s1 = potionAmplifiers.get(potion.getId()); if (s1 != null) { j = parsePotionEffects(s1, 0, s1.length(), parInt1); if (j < 0) { diff --git a/src/game/java/net/minecraft/scoreboard/GoalColor.java b/src/game/java/net/minecraft/scoreboard/GoalColor.java index c1494f46..3d7b041f 100755 --- a/src/game/java/net/minecraft/scoreboard/GoalColor.java +++ b/src/game/java/net/minecraft/scoreboard/GoalColor.java @@ -11,7 +11,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java b/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java index 66b33754..4a1eb3a7 100755 --- a/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java +++ b/src/game/java/net/minecraft/scoreboard/IScoreObjectiveCriteria.java @@ -14,7 +14,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/Score.java b/src/game/java/net/minecraft/scoreboard/Score.java index 17eb6861..053b0a05 100755 --- a/src/game/java/net/minecraft/scoreboard/Score.java +++ b/src/game/java/net/minecraft/scoreboard/Score.java @@ -11,7 +11,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java b/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java index 46627e0d..087531f4 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreDummyCriteria.java @@ -10,7 +10,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java b/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java index 177ff284..0ef3ca6d 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreHealthCriteria.java @@ -11,7 +11,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/ScoreObjective.java b/src/game/java/net/minecraft/scoreboard/ScoreObjective.java index da13e85e..e35ff501 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreObjective.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreObjective.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java b/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java index 164b71a0..a18d1e80 100755 --- a/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java +++ b/src/game/java/net/minecraft/scoreboard/ScorePlayerTeam.java @@ -13,7 +13,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/Scoreboard.java b/src/game/java/net/minecraft/scoreboard/Scoreboard.java index 22aa0994..e6562ae0 100755 --- a/src/game/java/net/minecraft/scoreboard/Scoreboard.java +++ b/src/game/java/net/minecraft/scoreboard/Scoreboard.java @@ -19,7 +19,7 @@ import net.minecraft.util.EnumChatFormatting; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java b/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java index 99ccc5f6..cb03c4c5 100755 --- a/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java +++ b/src/game/java/net/minecraft/scoreboard/ScoreboardSaveData.java @@ -14,7 +14,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java b/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java index 0c3d779f..17d021ec 100755 --- a/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java +++ b/src/game/java/net/minecraft/scoreboard/ServerScoreboard.java @@ -20,7 +20,7 @@ import net.minecraft.server.MinecraftServer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/scoreboard/Team.java b/src/game/java/net/minecraft/scoreboard/Team.java index 13a6775c..61044903 100755 --- a/src/game/java/net/minecraft/scoreboard/Team.java +++ b/src/game/java/net/minecraft/scoreboard/Team.java @@ -11,7 +11,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/server/MinecraftServer.java b/src/game/java/net/minecraft/server/MinecraftServer.java index db5cee0c..631a6dec 100755 --- a/src/game/java/net/minecraft/server/MinecraftServer.java +++ b/src/game/java/net/minecraft/server/MinecraftServer.java @@ -55,7 +55,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/server/management/ItemInWorldManager.java b/src/game/java/net/minecraft/server/management/ItemInWorldManager.java index 8a4060d7..efe34faa 100755 --- a/src/game/java/net/minecraft/server/management/ItemInWorldManager.java +++ b/src/game/java/net/minecraft/server/management/ItemInWorldManager.java @@ -26,7 +26,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/server/management/LowerStringMap.java b/src/game/java/net/minecraft/server/management/LowerStringMap.java index bdde0f92..7b4e29d2 100755 --- a/src/game/java/net/minecraft/server/management/LowerStringMap.java +++ b/src/game/java/net/minecraft/server/management/LowerStringMap.java @@ -12,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/server/management/PlayerManager.java b/src/game/java/net/minecraft/server/management/PlayerManager.java index 447cee71..8257a5fb 100755 --- a/src/game/java/net/minecraft/server/management/PlayerManager.java +++ b/src/game/java/net/minecraft/server/management/PlayerManager.java @@ -1,7 +1,10 @@ package net.minecraft.server.management; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; +import com.carrotsearch.hppc.LongSet; import com.google.common.collect.Lists; -import java.util.ArrayList; import java.util.List; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.network.Packet; @@ -10,7 +13,6 @@ import net.minecraft.network.play.server.S22PacketMultiBlockChange; import net.minecraft.network.play.server.S23PacketBlockChange; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.BlockPos; -import net.minecraft.util.LongHashMap; import net.minecraft.util.MathHelper; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.WorldProvider; @@ -25,7 +27,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -49,7 +51,7 @@ public class PlayerManager { /**+ * the hash of all playerInstances created */ - private final LongHashMap playerInstances = new LongHashMap(); + private final LongObjectMap playerInstances = new LongObjectHashMap<>(); /**+ * the playerInstances(chunks) that need to be updated */ @@ -112,7 +114,7 @@ public class PlayerManager { public boolean hasPlayerInstance(int chunkX, int chunkZ) { long i = (long) chunkX + 2147483647L | (long) chunkZ + 2147483647L << 32; - return this.playerInstances.getValueByKey(i) != null; + return this.playerInstances.get(i) != null; } /**+ @@ -121,11 +123,10 @@ public class PlayerManager { */ private PlayerManager.PlayerInstance getPlayerInstance(int chunkX, int chunkZ, boolean createIfAbsent) { long i = (long) chunkX + 2147483647L | (long) chunkZ + 2147483647L << 32; - PlayerManager.PlayerInstance playermanager$playerinstance = (PlayerManager.PlayerInstance) this.playerInstances - .getValueByKey(i); + PlayerManager.PlayerInstance playermanager$playerinstance = this.playerInstances.get(i); if (playermanager$playerinstance == null && createIfAbsent) { playermanager$playerinstance = new PlayerManager.PlayerInstance(chunkX, chunkZ); - this.playerInstances.add(i, playermanager$playerinstance); + this.playerInstances.put(i, playermanager$playerinstance); this.playerInstanceList.add(playermanager$playerinstance); } @@ -167,14 +168,14 @@ public class PlayerManager { * that are not in viewing range of the player. */ public void filterChunkLoadQueue(EntityPlayerMP player) { - ArrayList arraylist = Lists.newArrayList(player.loadedChunks); + LongSet arraylist = new LongHashSet(player.loadedChunks); int i = 0; int j = this.playerViewRadius; int k = (int) player.posX >> 4; int l = (int) player.posZ >> 4; int i1 = 0; int j1 = 0; - ChunkCoordIntPair chunkcoordintpair = this.getPlayerInstance(k, l, true).chunkCoords; + long chunkcoordintpair = this.getPlayerInstance(k, l, true).chunkCoordsHash; player.loadedChunks.clear(); if (arraylist.contains(chunkcoordintpair)) { player.loadedChunks.add(chunkcoordintpair); @@ -187,7 +188,7 @@ public class PlayerManager { for (int i2 = 0; i2 < k1; ++i2) { i1 += aint[0]; j1 += aint[1]; - chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoords; + chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoordsHash; if (arraylist.contains(chunkcoordintpair)) { player.loadedChunks.add(chunkcoordintpair); } @@ -200,7 +201,7 @@ public class PlayerManager { for (int j2 = 0; j2 < j * 2; ++j2) { i1 += this.xzDirectionsConst[i][0]; j1 += this.xzDirectionsConst[i][1]; - chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoords; + chunkcoordintpair = this.getPlayerInstance(k + i1, l + j1, true).chunkCoordsHash; if (arraylist.contains(chunkcoordintpair)) { player.loadedChunks.add(chunkcoordintpair); } @@ -282,7 +283,7 @@ public class PlayerManager { PlayerManager.PlayerInstance playermanager$playerinstance = this.getPlayerInstance(chunkX, chunkZ, false); return playermanager$playerinstance != null && playermanager$playerinstance.playersWatchingChunk.contains(player) - && !player.loadedChunks.contains(playermanager$playerinstance.chunkCoords); + && !player.loadedChunks.contains(playermanager$playerinstance.chunkCoordsHash); } public void setPlayerViewRadius(int radius) { @@ -330,6 +331,7 @@ public class PlayerManager { class PlayerInstance { private final List playersWatchingChunk = Lists.newArrayList(); private final ChunkCoordIntPair chunkCoords; + private final long chunkCoordsHash; private short[] locationOfBlockChange = new short[64]; private int numBlocksToUpdate; private int flagsYAreasToUpdate; @@ -337,6 +339,7 @@ public class PlayerManager { public PlayerInstance(int chunkX, int chunkZ) { this.chunkCoords = new ChunkCoordIntPair(chunkX, chunkZ); + this.chunkCoordsHash = ChunkCoordIntPair.chunkXZ2Int(chunkX, chunkZ); PlayerManager.this.getWorldServer().theChunkProviderServer.loadChunk(chunkX, chunkZ); } @@ -355,7 +358,7 @@ public class PlayerManager { } this.playersWatchingChunk.add(player); - player.loadedChunks.add(this.chunkCoords); + player.loadedChunks.add(this.chunkCoordsHash); } } @@ -371,7 +374,7 @@ public class PlayerManager { } this.playersWatchingChunk.remove(player); - player.loadedChunks.remove(this.chunkCoords); + player.loadedChunks.removeAll(this.chunkCoordsHash); if (this.playersWatchingChunk.isEmpty()) { long i = (long) this.chunkCoords.chunkXPos + 2147483647L | (long) this.chunkCoords.chunkZPos + 2147483647L << 32; @@ -423,7 +426,7 @@ public class PlayerManager { public void sendToAllPlayersWatchingChunk(Packet thePacket) { for (int i = 0; i < this.playersWatchingChunk.size(); ++i) { EntityPlayerMP entityplayermp = (EntityPlayerMP) this.playersWatchingChunk.get(i); - if (!entityplayermp.loadedChunks.contains(this.chunkCoords)) { + if (!entityplayermp.loadedChunks.contains(this.chunkCoordsHash)) { entityplayermp.playerNetServerHandler.sendPacket(thePacket); } } diff --git a/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java b/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java index adabb031..e929b97a 100755 --- a/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java +++ b/src/game/java/net/minecraft/server/management/ServerConfigurationManager.java @@ -1,5 +1,6 @@ package net.minecraft.server.management; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -77,7 +78,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -175,8 +176,8 @@ public abstract class ServerConfigurationManager { playerIn.loadResourcePack(this.mcServer.getResourcePackUrl(), this.mcServer.getResourcePackHash()); } - for (PotionEffect potioneffect : playerIn.getActivePotionEffects()) { - nethandlerplayserver.sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect)); + for (ObjectCursor potioneffect : playerIn.getActivePotionEffects()) { + nethandlerplayserver.sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect.value)); } playerIn.addSelfToInternalCraftingInventory(); @@ -513,8 +514,9 @@ public abstract class ServerConfigurationManager { this.updateTimeAndWeatherForPlayer(playerIn, worldserver1); this.syncPlayerInventory(playerIn); - for (PotionEffect potioneffect : playerIn.getActivePotionEffects()) { - playerIn.playerNetServerHandler.sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect)); + for (ObjectCursor potioneffect : playerIn.getActivePotionEffects()) { + playerIn.playerNetServerHandler + .sendPacket(new S1DPacketEntityEffect(playerIn.getEntityId(), potioneffect.value)); } } @@ -890,12 +892,14 @@ public abstract class ServerConfigurationManager { public void setViewDistance(int distance) { this.viewDistance = distance; + int entityViewDist = getEntityViewDistance(); if (this.mcServer.worldServers != null) { WorldServer[] srv = this.mcServer.worldServers; for (int i = 0; i < srv.length; ++i) { WorldServer worldserver = srv[i]; if (worldserver != null) { worldserver.getPlayerManager().setPlayerViewRadius(distance); + worldserver.getEntityTracker().updateMaxTrackingThreshold(entityViewDist); } } } diff --git a/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java b/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java index 774ff124..46fd2c1e 100755 --- a/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java +++ b/src/game/java/net/minecraft/server/network/NetHandlerLoginServer.java @@ -34,7 +34,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/Achievement.java b/src/game/java/net/minecraft/stats/Achievement.java index 4ac5c242..95ccb162 100755 --- a/src/game/java/net/minecraft/stats/Achievement.java +++ b/src/game/java/net/minecraft/stats/Achievement.java @@ -17,7 +17,7 @@ import net.minecraft.util.StatCollector; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/AchievementList.java b/src/game/java/net/minecraft/stats/AchievementList.java index 9d5f5e99..df706f16 100755 --- a/src/game/java/net/minecraft/stats/AchievementList.java +++ b/src/game/java/net/minecraft/stats/AchievementList.java @@ -15,7 +15,7 @@ import net.minecraft.util.JsonSerializableSet; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/IStatStringFormat.java b/src/game/java/net/minecraft/stats/IStatStringFormat.java index 7e0e58c3..5076c272 100755 --- a/src/game/java/net/minecraft/stats/IStatStringFormat.java +++ b/src/game/java/net/minecraft/stats/IStatStringFormat.java @@ -6,7 +6,7 @@ package net.minecraft.stats; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/IStatType.java b/src/game/java/net/minecraft/stats/IStatType.java index f5f79e48..3a062b43 100755 --- a/src/game/java/net/minecraft/stats/IStatType.java +++ b/src/game/java/net/minecraft/stats/IStatType.java @@ -6,7 +6,7 @@ package net.minecraft.stats; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/ObjectiveStat.java b/src/game/java/net/minecraft/stats/ObjectiveStat.java index 71c6f2ec..009e36c5 100755 --- a/src/game/java/net/minecraft/stats/ObjectiveStat.java +++ b/src/game/java/net/minecraft/stats/ObjectiveStat.java @@ -8,7 +8,7 @@ import net.minecraft.scoreboard.ScoreDummyCriteria; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/StatBase.java b/src/game/java/net/minecraft/stats/StatBase.java index ea5b82fa..c6bfcae5 100755 --- a/src/game/java/net/minecraft/stats/StatBase.java +++ b/src/game/java/net/minecraft/stats/StatBase.java @@ -18,7 +18,7 @@ import net.minecraft.util.IJsonSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/StatBasic.java b/src/game/java/net/minecraft/stats/StatBasic.java index fcd3ae81..b8762a03 100755 --- a/src/game/java/net/minecraft/stats/StatBasic.java +++ b/src/game/java/net/minecraft/stats/StatBasic.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/StatCrafting.java b/src/game/java/net/minecraft/stats/StatCrafting.java index 949617d1..29853f29 100755 --- a/src/game/java/net/minecraft/stats/StatCrafting.java +++ b/src/game/java/net/minecraft/stats/StatCrafting.java @@ -10,7 +10,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/StatFileWriter.java b/src/game/java/net/minecraft/stats/StatFileWriter.java index 6254facb..d1ad8779 100755 --- a/src/game/java/net/minecraft/stats/StatFileWriter.java +++ b/src/game/java/net/minecraft/stats/StatFileWriter.java @@ -14,7 +14,7 @@ import net.minecraft.util.TupleIntJsonSerializable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/StatList.java b/src/game/java/net/minecraft/stats/StatList.java index c04e8bfc..cd27105e 100755 --- a/src/game/java/net/minecraft/stats/StatList.java +++ b/src/game/java/net/minecraft/stats/StatList.java @@ -26,7 +26,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/stats/StatisticsFile.java b/src/game/java/net/minecraft/stats/StatisticsFile.java index e5164ffa..2de7f2af 100755 --- a/src/game/java/net/minecraft/stats/StatisticsFile.java +++ b/src/game/java/net/minecraft/stats/StatisticsFile.java @@ -1,5 +1,7 @@ package net.minecraft.stats; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.HashMap; @@ -27,7 +29,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -187,12 +189,12 @@ public class StatisticsFile extends StatFileWriter { public void func_150876_a(EntityPlayerMP parEntityPlayerMP) { int i = this.mcServer.getTickCounter(); - HashMap hashmap = Maps.newHashMap(); + ObjectIntMap hashmap = new ObjectIntHashMap<>(); if (this.field_150886_g || i - this.field_150885_f > 300) { this.field_150885_f = i; for (StatBase statbase : this.func_150878_c()) { - hashmap.put(statbase, Integer.valueOf(this.readStat(statbase))); + hashmap.put(statbase, this.readStat(statbase)); } } @@ -200,12 +202,12 @@ public class StatisticsFile extends StatFileWriter { } public void sendAchievements(EntityPlayerMP player) { - HashMap hashmap = Maps.newHashMap(); + ObjectIntMap hashmap = new ObjectIntHashMap<>(); for (int i = 0, l = AchievementList.achievementList.size(); i < l; ++i) { Achievement achievement = AchievementList.achievementList.get(i); if (this.hasAchievementUnlocked(achievement)) { - hashmap.put(achievement, Integer.valueOf(this.readStat(achievement))); + hashmap.put(achievement, this.readStat(achievement)); this.field_150888_e.remove(achievement); } } diff --git a/src/game/java/net/minecraft/tileentity/IHopper.java b/src/game/java/net/minecraft/tileentity/IHopper.java index ed95f3cc..19277dc1 100755 --- a/src/game/java/net/minecraft/tileentity/IHopper.java +++ b/src/game/java/net/minecraft/tileentity/IHopper.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java b/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java index 90d88e36..52835e13 100755 --- a/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java +++ b/src/game/java/net/minecraft/tileentity/MobSpawnerBaseLogic.java @@ -26,7 +26,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntity.java b/src/game/java/net/minecraft/tileentity/TileEntity.java index de99e46f..5cda6cc0 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntity.java +++ b/src/game/java/net/minecraft/tileentity/TileEntity.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityBanner.java b/src/game/java/net/minecraft/tileentity/TileEntityBanner.java index 8f676e1e..ea3fb7f4 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityBanner.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityBanner.java @@ -21,7 +21,7 @@ import net.minecraft.network.play.server.S35PacketUpdateTileEntity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java b/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java index 2dab48a1..5d4158c7 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityBeacon.java @@ -33,7 +33,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java b/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java index 14f7c87f..1979cca9 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityBrewingStand.java @@ -25,7 +25,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityChest.java b/src/game/java/net/minecraft/tileentity/TileEntityChest.java index 60ddfcf8..e03a4254 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityChest.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityChest.java @@ -24,7 +24,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java b/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java index 02690217..64adc1c7 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityCommandBlock.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityComparator.java b/src/game/java/net/minecraft/tileentity/TileEntityComparator.java index 0d8dc626..ba7abd96 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityComparator.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityComparator.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java b/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java index 7a36af3e..1641451b 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityDaylightDetector.java @@ -9,7 +9,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java b/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java index 69dd8956..6c015b4c 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityDispenser.java @@ -17,7 +17,7 @@ import net.minecraft.nbt.NBTTagList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityDropper.java b/src/game/java/net/minecraft/tileentity/TileEntityDropper.java index ec46a26c..f6d368e4 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityDropper.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityDropper.java @@ -6,7 +6,7 @@ package net.minecraft.tileentity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java b/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java index 17cc7f9e..7ccc8a7b 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityEnchantmentTable.java @@ -20,7 +20,7 @@ import net.minecraft.world.IInteractionObject; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java b/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java index 7f221329..7b83b486 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityEndPortal.java @@ -6,7 +6,7 @@ package net.minecraft.tileentity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java b/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java index f424b073..37bf6f8e 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityEnderChest.java @@ -10,7 +10,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java b/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java index 15e2a6d3..e7401dee 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityFlowerPot.java @@ -12,7 +12,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java b/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java index 10d37bb2..57c2742f 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityFurnace.java @@ -31,7 +31,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityHopper.java b/src/game/java/net/minecraft/tileentity/TileEntityHopper.java index d98136ea..6353c0f2 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityHopper.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityHopper.java @@ -29,7 +29,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityLockable.java b/src/game/java/net/minecraft/tileentity/TileEntityLockable.java index bd0bec24..03ec46df 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityLockable.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityLockable.java @@ -14,7 +14,7 @@ import net.minecraft.world.LockCode; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java b/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java index 9ec237d8..b50b2bc9 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityMobSpawner.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityNote.java b/src/game/java/net/minecraft/tileentity/TileEntityNote.java index bd69787b..1646f56c 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityNote.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityNote.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntityPiston.java b/src/game/java/net/minecraft/tileentity/TileEntityPiston.java index bd64be81..d9c9f1e4 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntityPiston.java +++ b/src/game/java/net/minecraft/tileentity/TileEntityPiston.java @@ -19,7 +19,7 @@ import net.minecraft.util.ITickable; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntitySign.java b/src/game/java/net/minecraft/tileentity/TileEntitySign.java index cc54715f..2ef0198c 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntitySign.java +++ b/src/game/java/net/minecraft/tileentity/TileEntitySign.java @@ -28,7 +28,7 @@ import org.json.JSONException; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/tileentity/TileEntitySkull.java b/src/game/java/net/minecraft/tileentity/TileEntitySkull.java index 89c04c21..bae6f047 100755 --- a/src/game/java/net/minecraft/tileentity/TileEntitySkull.java +++ b/src/game/java/net/minecraft/tileentity/TileEntitySkull.java @@ -15,7 +15,7 @@ import net.minecraft.util.StringUtils; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/AxisAlignedBB.java b/src/game/java/net/minecraft/util/AxisAlignedBB.java index 06935453..ee775582 100755 --- a/src/game/java/net/minecraft/util/AxisAlignedBB.java +++ b/src/game/java/net/minecraft/util/AxisAlignedBB.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/BlockPos.java b/src/game/java/net/minecraft/util/BlockPos.java index becd0c73..9018f7e4 100755 --- a/src/game/java/net/minecraft/util/BlockPos.java +++ b/src/game/java/net/minecraft/util/BlockPos.java @@ -12,7 +12,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Cartesian.java b/src/game/java/net/minecraft/util/Cartesian.java index 2320f280..2727e17f 100755 --- a/src/game/java/net/minecraft/util/Cartesian.java +++ b/src/game/java/net/minecraft/util/Cartesian.java @@ -19,7 +19,7 @@ import com.google.common.collect.UnmodifiableIterator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatAllowedCharacters.java b/src/game/java/net/minecraft/util/ChatAllowedCharacters.java index f1d282bc..be1416f3 100755 --- a/src/game/java/net/minecraft/util/ChatAllowedCharacters.java +++ b/src/game/java/net/minecraft/util/ChatAllowedCharacters.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatComponentProcessor.java b/src/game/java/net/minecraft/util/ChatComponentProcessor.java index 232a3248..848a3ad9 100755 --- a/src/game/java/net/minecraft/util/ChatComponentProcessor.java +++ b/src/game/java/net/minecraft/util/ChatComponentProcessor.java @@ -14,7 +14,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatComponentScore.java b/src/game/java/net/minecraft/util/ChatComponentScore.java index b7dd9125..4dcc9dee 100755 --- a/src/game/java/net/minecraft/util/ChatComponentScore.java +++ b/src/game/java/net/minecraft/util/ChatComponentScore.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatComponentSelector.java b/src/game/java/net/minecraft/util/ChatComponentSelector.java index d665f0c9..92a58e1a 100755 --- a/src/game/java/net/minecraft/util/ChatComponentSelector.java +++ b/src/game/java/net/minecraft/util/ChatComponentSelector.java @@ -8,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatComponentStyle.java b/src/game/java/net/minecraft/util/ChatComponentStyle.java index b7a53dba..0ba3b4a8 100755 --- a/src/game/java/net/minecraft/util/ChatComponentStyle.java +++ b/src/game/java/net/minecraft/util/ChatComponentStyle.java @@ -13,7 +13,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatComponentText.java b/src/game/java/net/minecraft/util/ChatComponentText.java index 2fc6115a..a4ac0998 100755 --- a/src/game/java/net/minecraft/util/ChatComponentText.java +++ b/src/game/java/net/minecraft/util/ChatComponentText.java @@ -8,7 +8,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatComponentTranslation.java b/src/game/java/net/minecraft/util/ChatComponentTranslation.java index aeda3e09..840da12b 100755 --- a/src/game/java/net/minecraft/util/ChatComponentTranslation.java +++ b/src/game/java/net/minecraft/util/ChatComponentTranslation.java @@ -18,7 +18,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java b/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java index c8143f24..95708431 100755 --- a/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java +++ b/src/game/java/net/minecraft/util/ChatComponentTranslationFormatException.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ChatStyle.java b/src/game/java/net/minecraft/util/ChatStyle.java index 386fbe15..7009b48f 100755 --- a/src/game/java/net/minecraft/util/ChatStyle.java +++ b/src/game/java/net/minecraft/util/ChatStyle.java @@ -14,7 +14,7 @@ import net.minecraft.event.HoverEvent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java b/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java index 70c1a2f3..7916525e 100755 --- a/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java +++ b/src/game/java/net/minecraft/util/ClassInheritanceMultiMap.java @@ -17,7 +17,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/CombatEntry.java b/src/game/java/net/minecraft/util/CombatEntry.java index 3b2037f4..93ec982c 100755 --- a/src/game/java/net/minecraft/util/CombatEntry.java +++ b/src/game/java/net/minecraft/util/CombatEntry.java @@ -8,7 +8,7 @@ import net.minecraft.entity.EntityLivingBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/CombatTracker.java b/src/game/java/net/minecraft/util/CombatTracker.java index dab0c76a..90a2e9a9 100755 --- a/src/game/java/net/minecraft/util/CombatTracker.java +++ b/src/game/java/net/minecraft/util/CombatTracker.java @@ -17,7 +17,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/DamageSource.java b/src/game/java/net/minecraft/util/DamageSource.java index 7094f605..f7371ff2 100755 --- a/src/game/java/net/minecraft/util/DamageSource.java +++ b/src/game/java/net/minecraft/util/DamageSource.java @@ -13,7 +13,7 @@ import net.minecraft.world.Explosion; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/EnchantmentNameParts.java b/src/game/java/net/minecraft/util/EnchantmentNameParts.java index 02631043..98d9c8ce 100755 --- a/src/game/java/net/minecraft/util/EnchantmentNameParts.java +++ b/src/game/java/net/minecraft/util/EnchantmentNameParts.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/EntityDamageSource.java b/src/game/java/net/minecraft/util/EntityDamageSource.java index 7cfd8506..4f148b5a 100755 --- a/src/game/java/net/minecraft/util/EntityDamageSource.java +++ b/src/game/java/net/minecraft/util/EntityDamageSource.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java b/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java index 968cc011..1b7ba2f7 100755 --- a/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java +++ b/src/game/java/net/minecraft/util/EntityDamageSourceIndirect.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/EntitySelectors.java b/src/game/java/net/minecraft/util/EntitySelectors.java index 0bfd26dc..0d18d67a 100755 --- a/src/game/java/net/minecraft/util/EntitySelectors.java +++ b/src/game/java/net/minecraft/util/EntitySelectors.java @@ -16,7 +16,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/EnumChatFormatting.java b/src/game/java/net/minecraft/util/EnumChatFormatting.java index a35843e6..37ee9da3 100755 --- a/src/game/java/net/minecraft/util/EnumChatFormatting.java +++ b/src/game/java/net/minecraft/util/EnumChatFormatting.java @@ -14,7 +14,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/EnumFacing.java b/src/game/java/net/minecraft/util/EnumFacing.java index 7d19e70e..20fd18e5 100755 --- a/src/game/java/net/minecraft/util/EnumFacing.java +++ b/src/game/java/net/minecraft/util/EnumFacing.java @@ -14,7 +14,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/EnumParticleTypes.java b/src/game/java/net/minecraft/util/EnumParticleTypes.java index b834b408..eac53302 100755 --- a/src/game/java/net/minecraft/util/EnumParticleTypes.java +++ b/src/game/java/net/minecraft/util/EnumParticleTypes.java @@ -1,10 +1,10 @@ package net.minecraft.util; import java.util.ArrayList; -import java.util.Map; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -12,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -49,7 +49,7 @@ public enum EnumParticleTypes { private final int particleID; private final boolean shouldIgnoreRange; private final int argumentCount; - private static final Map PARTICLES = Maps.newHashMap(); + private static final IntObjectMap PARTICLES = new IntObjectHashMap<>(); private static final String[] PARTICLE_NAMES; private EnumParticleTypes(String particleNameIn, int particleIDIn, boolean parFlag, int argumentCountIn) { @@ -91,7 +91,7 @@ public enum EnumParticleTypes { * Gets the relative EnumParticleTypes by id. */ public static EnumParticleTypes getParticleFromId(int particleId) { - return (EnumParticleTypes) PARTICLES.get(Integer.valueOf(particleId)); + return PARTICLES.get(Integer.valueOf(particleId)); } static { diff --git a/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java b/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java index 306ae0e3..2472a9cc 100755 --- a/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java +++ b/src/game/java/net/minecraft/util/EnumWorldBlockLayer.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/FoodStats.java b/src/game/java/net/minecraft/util/FoodStats.java index 06beb9d2..423f49f8 100755 --- a/src/game/java/net/minecraft/util/FoodStats.java +++ b/src/game/java/net/minecraft/util/FoodStats.java @@ -12,7 +12,7 @@ import net.minecraft.world.EnumDifficulty; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/FrameTimer.java b/src/game/java/net/minecraft/util/FrameTimer.java index 6dd30ef9..8b137e2b 100755 --- a/src/game/java/net/minecraft/util/FrameTimer.java +++ b/src/game/java/net/minecraft/util/FrameTimer.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IChatComponent.java b/src/game/java/net/minecraft/util/IChatComponent.java index 6bfdc531..d540c226 100755 --- a/src/game/java/net/minecraft/util/IChatComponent.java +++ b/src/game/java/net/minecraft/util/IChatComponent.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.json.JSONTypeProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IJsonSerializable.java b/src/game/java/net/minecraft/util/IJsonSerializable.java index 8324b776..c45a70e8 100755 --- a/src/game/java/net/minecraft/util/IJsonSerializable.java +++ b/src/game/java/net/minecraft/util/IJsonSerializable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IObjectIntIterable.java b/src/game/java/net/minecraft/util/IObjectIntIterable.java index 62f2bcd6..c1562b35 100755 --- a/src/game/java/net/minecraft/util/IObjectIntIterable.java +++ b/src/game/java/net/minecraft/util/IObjectIntIterable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IProgressUpdate.java b/src/game/java/net/minecraft/util/IProgressUpdate.java index 015fa8cd..48e80df6 100755 --- a/src/game/java/net/minecraft/util/IProgressUpdate.java +++ b/src/game/java/net/minecraft/util/IProgressUpdate.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IRegistry.java b/src/game/java/net/minecraft/util/IRegistry.java index bf239037..175be0e7 100755 --- a/src/game/java/net/minecraft/util/IRegistry.java +++ b/src/game/java/net/minecraft/util/IRegistry.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IStringSerializable.java b/src/game/java/net/minecraft/util/IStringSerializable.java index 7301c90b..a024ce61 100755 --- a/src/game/java/net/minecraft/util/IStringSerializable.java +++ b/src/game/java/net/minecraft/util/IStringSerializable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IThreadListener.java b/src/game/java/net/minecraft/util/IThreadListener.java index 1bac31bf..8d634d6c 100755 --- a/src/game/java/net/minecraft/util/IThreadListener.java +++ b/src/game/java/net/minecraft/util/IThreadListener.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ITickable.java b/src/game/java/net/minecraft/util/ITickable.java index f2c757d3..cbb0db01 100755 --- a/src/game/java/net/minecraft/util/ITickable.java +++ b/src/game/java/net/minecraft/util/ITickable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/IntHashMap.java b/src/game/java/net/minecraft/util/IntHashMap.java deleted file mode 100755 index 83e4f72c..00000000 --- a/src/game/java/net/minecraft/util/IntHashMap.java +++ /dev/null @@ -1,265 +0,0 @@ -package net.minecraft.util; - -/**+ - * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. - * - * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" - * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team - * - * EaglercraftX 1.8 patch files (c) 2022-2024 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. - * - */ -public class IntHashMap { - /**+ - * An array of HashEntries representing the heads of hash slot - * lists - */ - private transient IntHashMap.Entry[] slots = new IntHashMap.Entry[16]; - private transient int count; - /**+ - * The grow threshold - */ - private int threshold = 12; - /**+ - * The scale factor used to determine when to grow the table - */ - private final float growFactor = 0.75F; - - /**+ - * Makes the passed in integer suitable for hashing by a number - * of shifts - */ - private static int computeHash(int integer) { - integer = integer ^ integer >>> 20 ^ integer >>> 12; - return integer ^ integer >>> 7 ^ integer >>> 4; - } - - /**+ - * Computes the index of the slot for the hash and slot count - * passed in. - */ - private static int getSlotIndex(int hash, int slotCount) { - return hash & slotCount - 1; - } - - /**+ - * Returns the object associated to a key - */ - public V lookup(int parInt1) { - int i = computeHash(parInt1); - - for (IntHashMap.Entry inthashmap$entry = this.slots[getSlotIndex(i, - this.slots.length)]; inthashmap$entry != null; inthashmap$entry = inthashmap$entry.nextEntry) { - if (inthashmap$entry.hashEntry == parInt1) { - return (V) inthashmap$entry.valueEntry; - } - } - - return (V) null; - } - - /**+ - * Returns true if this hash table contains the specified item. - */ - public boolean containsItem(int parInt1) { - return this.lookupEntry(parInt1) != null; - } - - /**+ - * Returns the internal entry for a key - */ - final IntHashMap.Entry lookupEntry(int parInt1) { - int i = computeHash(parInt1); - - for (IntHashMap.Entry inthashmap$entry = this.slots[getSlotIndex(i, - this.slots.length)]; inthashmap$entry != null; inthashmap$entry = inthashmap$entry.nextEntry) { - if (inthashmap$entry.hashEntry == parInt1) { - return inthashmap$entry; - } - } - - return null; - } - - /**+ - * Adds a key and associated value to this map - */ - public void addKey(int parInt1, V parObject) { - int i = computeHash(parInt1); - int j = getSlotIndex(i, this.slots.length); - - for (IntHashMap.Entry inthashmap$entry = this.slots[j]; inthashmap$entry != null; inthashmap$entry = inthashmap$entry.nextEntry) { - if (inthashmap$entry.hashEntry == parInt1) { - inthashmap$entry.valueEntry = parObject; - return; - } - } - - this.insert(i, parInt1, parObject, j); - } - - /**+ - * Increases the number of hash slots - */ - private void grow(int parInt1) { - IntHashMap.Entry[] ainthashmap$entry = this.slots; - int i = ainthashmap$entry.length; - if (i == 1073741824) { - this.threshold = Integer.MAX_VALUE; - } else { - IntHashMap.Entry[] ainthashmap$entry1 = new IntHashMap.Entry[parInt1]; - this.copyTo(ainthashmap$entry1); - this.slots = ainthashmap$entry1; - this.threshold = (int) ((float) parInt1 * this.growFactor); - } - } - - /**+ - * Copies the hash slots to a new array - */ - private void copyTo(IntHashMap.Entry[] parArrayOfEntry) { - IntHashMap.Entry[] ainthashmap$entry = this.slots; - int i = parArrayOfEntry.length; - - for (int j = 0; j < ainthashmap$entry.length; ++j) { - IntHashMap.Entry inthashmap$entry = ainthashmap$entry[j]; - if (inthashmap$entry != null) { - ainthashmap$entry[j] = null; - - while (true) { - IntHashMap.Entry inthashmap$entry1 = inthashmap$entry.nextEntry; - int k = getSlotIndex(inthashmap$entry.slotHash, i); - inthashmap$entry.nextEntry = parArrayOfEntry[k]; - parArrayOfEntry[k] = inthashmap$entry; - inthashmap$entry = inthashmap$entry1; - if (inthashmap$entry1 == null) { - break; - } - } - } - } - - } - - /**+ - * Removes the specified object from the map and returns it - */ - public V removeObject(int parInt1) { - IntHashMap.Entry inthashmap$entry = this.removeEntry(parInt1); - return (V) (inthashmap$entry == null ? null : inthashmap$entry.valueEntry); - } - - /**+ - * Removes the specified entry from the map and returns it - */ - final IntHashMap.Entry removeEntry(int parInt1) { - int i = computeHash(parInt1); - int j = getSlotIndex(i, this.slots.length); - IntHashMap.Entry inthashmap$entry = this.slots[j]; - - IntHashMap.Entry inthashmap$entry1; - IntHashMap.Entry inthashmap$entry2; - for (inthashmap$entry1 = inthashmap$entry; inthashmap$entry1 != null; inthashmap$entry1 = inthashmap$entry2) { - inthashmap$entry2 = inthashmap$entry1.nextEntry; - if (inthashmap$entry1.hashEntry == parInt1) { - --this.count; - if (inthashmap$entry == inthashmap$entry1) { - this.slots[j] = inthashmap$entry2; - } else { - inthashmap$entry.nextEntry = inthashmap$entry2; - } - - return inthashmap$entry1; - } - - inthashmap$entry = inthashmap$entry1; - } - - return inthashmap$entry1; - } - - /**+ - * Removes all entries from the map - */ - public void clearMap() { - IntHashMap.Entry[] ainthashmap$entry = this.slots; - - for (int i = 0; i < ainthashmap$entry.length; ++i) { - ainthashmap$entry[i] = null; - } - - this.count = 0; - } - - /**+ - * Adds an object to a slot - */ - private void insert(int parInt1, int parInt2, V parObject, int parInt3) { - IntHashMap.Entry inthashmap$entry = this.slots[parInt3]; - this.slots[parInt3] = new IntHashMap.Entry(parInt1, parInt2, parObject, inthashmap$entry); - if (this.count++ >= this.threshold) { - this.grow(2 * this.slots.length); - } - - } - - static class Entry { - final int hashEntry; - V valueEntry; - IntHashMap.Entry nextEntry; - final int slotHash; - - Entry(int parInt1, int parInt2, V parObject, IntHashMap.Entry parEntry) { - this.valueEntry = parObject; - this.nextEntry = parEntry; - this.hashEntry = parInt2; - this.slotHash = parInt1; - } - - public final int getHash() { - return this.hashEntry; - } - - public final V getValue() { - return this.valueEntry; - } - - public final boolean equals(Object object) { - if (!(object instanceof IntHashMap.Entry)) { - return false; - } else { - IntHashMap.Entry inthashmap$entry = (IntHashMap.Entry) object; - Integer integer = Integer.valueOf(this.getHash()); - Integer integer1 = Integer.valueOf(inthashmap$entry.getHash()); - if (integer == integer1 || integer != null && integer.equals(integer1)) { - Object object1 = this.getValue(); - Object object2 = inthashmap$entry.getValue(); - if (object1 == object2 || object1 != null && object1.equals(object2)) { - return true; - } - } - - return false; - } - } - - public final int hashCode() { - return IntHashMap.computeHash(this.hashEntry); - } - - public final String toString() { - return this.getHash() + "=" + this.getValue(); - } - } -} \ No newline at end of file diff --git a/src/game/java/net/minecraft/util/IntegerCache.java b/src/game/java/net/minecraft/util/IntegerCache.java index f052720c..332c727e 100755 --- a/src/game/java/net/minecraft/util/IntegerCache.java +++ b/src/game/java/net/minecraft/util/IntegerCache.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/JsonSerializableSet.java b/src/game/java/net/minecraft/util/JsonSerializableSet.java index f06f4ea3..ecfdd0d4 100755 --- a/src/game/java/net/minecraft/util/JsonSerializableSet.java +++ b/src/game/java/net/minecraft/util/JsonSerializableSet.java @@ -13,7 +13,7 @@ import com.google.common.collect.Sets; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/LazyLoadBase.java b/src/game/java/net/minecraft/util/LazyLoadBase.java index 8382aef8..f448fbd8 100755 --- a/src/game/java/net/minecraft/util/LazyLoadBase.java +++ b/src/game/java/net/minecraft/util/LazyLoadBase.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/LoggingPrintStream.java b/src/game/java/net/minecraft/util/LoggingPrintStream.java index 8e564736..04077d98 100755 --- a/src/game/java/net/minecraft/util/LoggingPrintStream.java +++ b/src/game/java/net/minecraft/util/LoggingPrintStream.java @@ -13,7 +13,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/LongHashMap.java b/src/game/java/net/minecraft/util/LongHashMap.java deleted file mode 100755 index 74abb5a3..00000000 --- a/src/game/java/net/minecraft/util/LongHashMap.java +++ /dev/null @@ -1,269 +0,0 @@ -package net.minecraft.util; - -/**+ - * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. - * - * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" - * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team - * - * EaglercraftX 1.8 patch files (c) 2022-2024 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. - * - */ -public class LongHashMap { - /**+ - * the array of all elements in the hash - */ - private transient LongHashMap.Entry[] hashArray = new LongHashMap.Entry[4096]; - private transient int numHashElements; - private int mask; - /**+ - * the maximum amount of elements in the hash (probably 3/4 the - * size due to meh hashing function) - */ - private int capacity = 3072; - /**+ - * percent of the hasharray that can be used without hash - * colliding probably - */ - private final float percentUseable = 0.75F; - private transient volatile int modCount; - - public LongHashMap() { - this.mask = this.hashArray.length - 1; - } - - /**+ - * returns the hashed key given the original key - */ - private static int getHashedKey(long originalKey) { - /**+ - * the hash function - */ - return hash((int) (originalKey ^ originalKey >>> 32)); - } - - /**+ - * the hash function - */ - private static int hash(int integer) { - integer = integer ^ integer >>> 20 ^ integer >>> 12; - return integer ^ integer >>> 7 ^ integer >>> 4; - } - - /**+ - * gets the index in the hash given the array length and the - * hashed key - */ - private static int getHashIndex(int parInt1, int parInt2) { - return parInt1 & parInt2; - } - - public int getNumHashElements() { - return this.numHashElements; - } - - /**+ - * get the value from the map given the key - */ - public V getValueByKey(long parLong1) { - int i = getHashedKey(parLong1); - - for (LongHashMap.Entry longhashmap$entry = this.hashArray[getHashIndex(i, - this.mask)]; longhashmap$entry != null; longhashmap$entry = longhashmap$entry.nextEntry) { - if (longhashmap$entry.key == parLong1) { - return (V) longhashmap$entry.value; - } - } - - return (V) null; - } - - public boolean containsItem(long parLong1) { - return this.getEntry(parLong1) != null; - } - - final LongHashMap.Entry getEntry(long parLong1) { - int i = getHashedKey(parLong1); - - for (LongHashMap.Entry longhashmap$entry = this.hashArray[getHashIndex(i, - this.mask)]; longhashmap$entry != null; longhashmap$entry = longhashmap$entry.nextEntry) { - if (longhashmap$entry.key == parLong1) { - return longhashmap$entry; - } - } - - return null; - } - - /**+ - * Add a key-value pair. - */ - public void add(long parLong1, V parObject) { - int i = getHashedKey(parLong1); - int j = getHashIndex(i, this.mask); - - for (LongHashMap.Entry longhashmap$entry = this.hashArray[j]; longhashmap$entry != null; longhashmap$entry = longhashmap$entry.nextEntry) { - if (longhashmap$entry.key == parLong1) { - longhashmap$entry.value = parObject; - return; - } - } - - ++this.modCount; - this.createKey(i, parLong1, parObject, j); - } - - /**+ - * resizes the table - */ - private void resizeTable(int parInt1) { - LongHashMap.Entry[] alonghashmap$entry = this.hashArray; - int i = alonghashmap$entry.length; - if (i == 1073741824) { - this.capacity = Integer.MAX_VALUE; - } else { - LongHashMap.Entry[] alonghashmap$entry1 = new LongHashMap.Entry[parInt1]; - this.copyHashTableTo(alonghashmap$entry1); - this.hashArray = alonghashmap$entry1; - this.mask = this.hashArray.length - 1; - this.capacity = (int) ((float) parInt1 * this.percentUseable); - } - } - - /**+ - * copies the hash table to the specified array - */ - private void copyHashTableTo(LongHashMap.Entry[] parArrayOfEntry) { - LongHashMap.Entry[] alonghashmap$entry = this.hashArray; - int i = parArrayOfEntry.length; - - for (int j = 0; j < alonghashmap$entry.length; ++j) { - LongHashMap.Entry longhashmap$entry = alonghashmap$entry[j]; - if (longhashmap$entry != null) { - alonghashmap$entry[j] = null; - - while (true) { - LongHashMap.Entry longhashmap$entry1 = longhashmap$entry.nextEntry; - int k = getHashIndex(longhashmap$entry.hash, i - 1); - longhashmap$entry.nextEntry = parArrayOfEntry[k]; - parArrayOfEntry[k] = longhashmap$entry; - longhashmap$entry = longhashmap$entry1; - if (longhashmap$entry1 == null) { - break; - } - } - } - } - - } - - /**+ - * calls the removeKey method and returns removed object - */ - public V remove(long parLong1) { - LongHashMap.Entry longhashmap$entry = this.removeKey(parLong1); - return (V) (longhashmap$entry == null ? null : longhashmap$entry.value); - } - - /**+ - * removes the key from the hash linked list - */ - final LongHashMap.Entry removeKey(long parLong1) { - int i = getHashedKey(parLong1); - int j = getHashIndex(i, this.mask); - LongHashMap.Entry longhashmap$entry = this.hashArray[j]; - - LongHashMap.Entry longhashmap$entry1; - LongHashMap.Entry longhashmap$entry2; - for (longhashmap$entry1 = longhashmap$entry; longhashmap$entry1 != null; longhashmap$entry1 = longhashmap$entry2) { - longhashmap$entry2 = longhashmap$entry1.nextEntry; - if (longhashmap$entry1.key == parLong1) { - ++this.modCount; - --this.numHashElements; - if (longhashmap$entry == longhashmap$entry1) { - this.hashArray[j] = longhashmap$entry2; - } else { - longhashmap$entry.nextEntry = longhashmap$entry2; - } - - return longhashmap$entry1; - } - - longhashmap$entry = longhashmap$entry1; - } - - return longhashmap$entry1; - } - - /**+ - * creates the key in the hash table - */ - private void createKey(int parInt1, long parLong1, V parObject, int parInt2) { - LongHashMap.Entry longhashmap$entry = this.hashArray[parInt2]; - this.hashArray[parInt2] = new LongHashMap.Entry(parInt1, parLong1, parObject, longhashmap$entry); - if (this.numHashElements++ >= this.capacity) { - this.resizeTable(2 * this.hashArray.length); - } - - } - - static class Entry { - final long key; - V value; - LongHashMap.Entry nextEntry; - final int hash; - - Entry(int parInt1, long parLong1, V parObject, LongHashMap.Entry parEntry) { - this.value = parObject; - this.nextEntry = parEntry; - this.key = parLong1; - this.hash = parInt1; - } - - public final long getKey() { - return this.key; - } - - public final V getValue() { - return this.value; - } - - public final boolean equals(Object object) { - if (!(object instanceof LongHashMap.Entry)) { - return false; - } else { - LongHashMap.Entry longhashmap$entry = (LongHashMap.Entry) object; - Long olong = Long.valueOf(this.getKey()); - Long olong1 = Long.valueOf(longhashmap$entry.getKey()); - if (olong == olong1 || olong != null && olong.equals(olong1)) { - Object object1 = this.getValue(); - Object object2 = longhashmap$entry.getValue(); - if (object1 == object2 || object1 != null && object1.equals(object2)) { - return true; - } - } - - return false; - } - } - - public final int hashCode() { - return LongHashMap.getHashedKey(this.key); - } - - public final String toString() { - return this.getKey() + "=" + this.getValue(); - } - } -} \ No newline at end of file diff --git a/src/game/java/net/minecraft/util/MapPopulator.java b/src/game/java/net/minecraft/util/MapPopulator.java index 6803e8f0..1293f6ab 100755 --- a/src/game/java/net/minecraft/util/MapPopulator.java +++ b/src/game/java/net/minecraft/util/MapPopulator.java @@ -12,7 +12,7 @@ import com.google.common.collect.Maps; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/MathHelper.java b/src/game/java/net/minecraft/util/MathHelper.java index a3ec1c3f..c9c4fd1b 100755 --- a/src/game/java/net/minecraft/util/MathHelper.java +++ b/src/game/java/net/minecraft/util/MathHelper.java @@ -9,7 +9,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Matrix4f.java b/src/game/java/net/minecraft/util/Matrix4f.java index 405202fb..339d9e5b 100755 --- a/src/game/java/net/minecraft/util/Matrix4f.java +++ b/src/game/java/net/minecraft/util/Matrix4f.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/MinecraftError.java b/src/game/java/net/minecraft/util/MinecraftError.java index 3d49afa8..f96d8013 100755 --- a/src/game/java/net/minecraft/util/MinecraftError.java +++ b/src/game/java/net/minecraft/util/MinecraftError.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/MouseFilter.java b/src/game/java/net/minecraft/util/MouseFilter.java index 28f1bd4b..64d6b8d8 100755 --- a/src/game/java/net/minecraft/util/MouseFilter.java +++ b/src/game/java/net/minecraft/util/MouseFilter.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/MouseHelper.java b/src/game/java/net/minecraft/util/MouseHelper.java index 100efb19..344b1254 100755 --- a/src/game/java/net/minecraft/util/MouseHelper.java +++ b/src/game/java/net/minecraft/util/MouseHelper.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.PointerInputAbstraction; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/MovementInput.java b/src/game/java/net/minecraft/util/MovementInput.java index 08c83ae3..bcecc4c4 100755 --- a/src/game/java/net/minecraft/util/MovementInput.java +++ b/src/game/java/net/minecraft/util/MovementInput.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/MovementInputFromOptions.java b/src/game/java/net/minecraft/util/MovementInputFromOptions.java index 2b044060..02c40fd1 100755 --- a/src/game/java/net/minecraft/util/MovementInputFromOptions.java +++ b/src/game/java/net/minecraft/util/MovementInputFromOptions.java @@ -10,7 +10,7 @@ import net.minecraft.client.settings.GameSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/MovingObjectPosition.java b/src/game/java/net/minecraft/util/MovingObjectPosition.java index fac1f0bb..e39ddf37 100755 --- a/src/game/java/net/minecraft/util/MovingObjectPosition.java +++ b/src/game/java/net/minecraft/util/MovingObjectPosition.java @@ -8,7 +8,7 @@ import net.minecraft.entity.Entity; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java b/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java index 6f025bc4..1c80bffb 100755 --- a/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java +++ b/src/game/java/net/minecraft/util/ObjectIntIdentityMap.java @@ -1,9 +1,9 @@ package net.minecraft.util; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import com.carrotsearch.hppc.ObjectIntIdentityHashMap; import com.google.common.base.Predicates; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; @@ -14,7 +14,7 @@ import com.google.common.collect.Lists; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -29,11 +29,11 @@ import com.google.common.collect.Lists; * */ public class ObjectIntIdentityMap implements IObjectIntIterable { - private final IdentityHashMap identityMap = new IdentityHashMap(512); + private final ObjectIntIdentityHashMap identityMap = new ObjectIntIdentityHashMap<>(512); private final List objectList = Lists.newArrayList(); public void put(T key, int value) { - this.identityMap.put(key, Integer.valueOf(value)); + this.identityMap.put(key, value); while (this.objectList.size() <= value) { this.objectList.add((T) null); @@ -43,8 +43,7 @@ public class ObjectIntIdentityMap implements IObjectIntIterable { } public int get(T key) { - Integer integer = (Integer) this.identityMap.get(key); - return integer == null ? -1 : integer.intValue(); + return this.identityMap.getOrDefault(key, -1); } public final T getByValue(int value) { diff --git a/src/game/java/net/minecraft/util/RegistryDefaulted.java b/src/game/java/net/minecraft/util/RegistryDefaulted.java index 120f8648..985b14f6 100755 --- a/src/game/java/net/minecraft/util/RegistryDefaulted.java +++ b/src/game/java/net/minecraft/util/RegistryDefaulted.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/RegistryNamespaced.java b/src/game/java/net/minecraft/util/RegistryNamespaced.java index 20387cc0..1bb5b93f 100755 --- a/src/game/java/net/minecraft/util/RegistryNamespaced.java +++ b/src/game/java/net/minecraft/util/RegistryNamespaced.java @@ -12,7 +12,7 @@ import com.google.common.collect.HashBiMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java b/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java index 807a1a25..6bd61b4c 100755 --- a/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java +++ b/src/game/java/net/minecraft/util/RegistryNamespacedDefaultedByKey.java @@ -8,7 +8,7 @@ import org.apache.commons.lang3.Validate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/RegistrySimple.java b/src/game/java/net/minecraft/util/RegistrySimple.java index ffc6eee4..55ec8f80 100755 --- a/src/game/java/net/minecraft/util/RegistrySimple.java +++ b/src/game/java/net/minecraft/util/RegistrySimple.java @@ -18,7 +18,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ReportedException.java b/src/game/java/net/minecraft/util/ReportedException.java index 72282263..c4a79f54 100755 --- a/src/game/java/net/minecraft/util/ReportedException.java +++ b/src/game/java/net/minecraft/util/ReportedException.java @@ -8,7 +8,7 @@ import net.minecraft.crash.CrashReport; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ResourceLocation.java b/src/game/java/net/minecraft/util/ResourceLocation.java index 95be5a8e..ce5c0eaf 100755 --- a/src/game/java/net/minecraft/util/ResourceLocation.java +++ b/src/game/java/net/minecraft/util/ResourceLocation.java @@ -8,7 +8,7 @@ import org.apache.commons.lang3.Validate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Rotations.java b/src/game/java/net/minecraft/util/Rotations.java index 7592fe39..b0c6e4f9 100755 --- a/src/game/java/net/minecraft/util/Rotations.java +++ b/src/game/java/net/minecraft/util/Rotations.java @@ -9,7 +9,7 @@ import net.minecraft.nbt.NBTTagList; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/ScreenShotHelper.java b/src/game/java/net/minecraft/util/ScreenShotHelper.java index b0e2192b..8ecf587b 100755 --- a/src/game/java/net/minecraft/util/ScreenShotHelper.java +++ b/src/game/java/net/minecraft/util/ScreenShotHelper.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Session.java b/src/game/java/net/minecraft/util/Session.java index 97437379..25d0714c 100755 --- a/src/game/java/net/minecraft/util/Session.java +++ b/src/game/java/net/minecraft/util/Session.java @@ -12,7 +12,7 @@ import net.minecraft.entity.player.EntityPlayer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/StatCollector.java b/src/game/java/net/minecraft/util/StatCollector.java index 80066a3a..7f486b9f 100755 --- a/src/game/java/net/minecraft/util/StatCollector.java +++ b/src/game/java/net/minecraft/util/StatCollector.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/StringTranslate.java b/src/game/java/net/minecraft/util/StringTranslate.java index ae34f3db..f7865e92 100755 --- a/src/game/java/net/minecraft/util/StringTranslate.java +++ b/src/game/java/net/minecraft/util/StringTranslate.java @@ -25,7 +25,7 @@ import java.util.regex.Pattern; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/StringUtils.java b/src/game/java/net/minecraft/util/StringUtils.java index cb02416b..0f0b3017 100755 --- a/src/game/java/net/minecraft/util/StringUtils.java +++ b/src/game/java/net/minecraft/util/StringUtils.java @@ -8,7 +8,7 @@ import java.util.regex.Pattern; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Timer.java b/src/game/java/net/minecraft/util/Timer.java index 721001ec..0e40ca1b 100755 --- a/src/game/java/net/minecraft/util/Timer.java +++ b/src/game/java/net/minecraft/util/Timer.java @@ -9,7 +9,7 @@ import net.minecraft.client.Minecraft; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Tuple.java b/src/game/java/net/minecraft/util/Tuple.java index 8255d615..f427d6ed 100755 --- a/src/game/java/net/minecraft/util/Tuple.java +++ b/src/game/java/net/minecraft/util/Tuple.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java b/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java index db108384..9df39eb3 100755 --- a/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java +++ b/src/game/java/net/minecraft/util/TupleIntJsonSerializable.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Util.java b/src/game/java/net/minecraft/util/Util.java index 8c49abff..78a0d41b 100755 --- a/src/game/java/net/minecraft/util/Util.java +++ b/src/game/java/net/minecraft/util/Util.java @@ -11,7 +11,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Vec3.java b/src/game/java/net/minecraft/util/Vec3.java index 0884af77..9d78e572 100755 --- a/src/game/java/net/minecraft/util/Vec3.java +++ b/src/game/java/net/minecraft/util/Vec3.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Vec3i.java b/src/game/java/net/minecraft/util/Vec3i.java index e59af467..c4a18aa2 100755 --- a/src/game/java/net/minecraft/util/Vec3i.java +++ b/src/game/java/net/minecraft/util/Vec3i.java @@ -8,7 +8,7 @@ import com.google.common.base.Objects; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Vec4b.java b/src/game/java/net/minecraft/util/Vec4b.java index 4ea4b0be..a9018d37 100755 --- a/src/game/java/net/minecraft/util/Vec4b.java +++ b/src/game/java/net/minecraft/util/Vec4b.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/Vector3d.java b/src/game/java/net/minecraft/util/Vector3d.java index 5ad69583..ba4dea9f 100755 --- a/src/game/java/net/minecraft/util/Vector3d.java +++ b/src/game/java/net/minecraft/util/Vector3d.java @@ -6,7 +6,7 @@ package net.minecraft.util; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/WeightedRandom.java b/src/game/java/net/minecraft/util/WeightedRandom.java index 4a483c75..6b7a4e81 100755 --- a/src/game/java/net/minecraft/util/WeightedRandom.java +++ b/src/game/java/net/minecraft/util/WeightedRandom.java @@ -9,7 +9,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/WeightedRandomChestContent.java b/src/game/java/net/minecraft/util/WeightedRandomChestContent.java index f0157336..8a5c0a2b 100755 --- a/src/game/java/net/minecraft/util/WeightedRandomChestContent.java +++ b/src/game/java/net/minecraft/util/WeightedRandomChestContent.java @@ -18,7 +18,7 @@ import net.minecraft.tileentity.TileEntityDispenser; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/util/WeightedRandomFishable.java b/src/game/java/net/minecraft/util/WeightedRandomFishable.java index fbf8d066..f9233c12 100755 --- a/src/game/java/net/minecraft/util/WeightedRandomFishable.java +++ b/src/game/java/net/minecraft/util/WeightedRandomFishable.java @@ -11,7 +11,7 @@ import net.minecraft.item.ItemStack; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/village/MerchantRecipe.java b/src/game/java/net/minecraft/village/MerchantRecipe.java index 632fe203..b0495161 100755 --- a/src/game/java/net/minecraft/village/MerchantRecipe.java +++ b/src/game/java/net/minecraft/village/MerchantRecipe.java @@ -10,7 +10,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/village/MerchantRecipeList.java b/src/game/java/net/minecraft/village/MerchantRecipeList.java index de043f27..b9d9cc46 100755 --- a/src/game/java/net/minecraft/village/MerchantRecipeList.java +++ b/src/game/java/net/minecraft/village/MerchantRecipeList.java @@ -15,7 +15,7 @@ import net.minecraft.network.PacketBuffer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/village/Village.java b/src/game/java/net/minecraft/village/Village.java index f1b2a993..19b244d1 100755 --- a/src/game/java/net/minecraft/village/Village.java +++ b/src/game/java/net/minecraft/village/Village.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -70,6 +70,28 @@ public class Village { this.worldObj = worldIn; } + private BlockPos[] positions = null; + + private void calculateNewCheckPositions() { + if (this.center == null || this.center.equals(BlockPos.ORIGIN)) { + this.positions = null; + } else { + this.positions = new BlockPos[] { this.center.add(-this.villageRadius, 0, -this.villageRadius), + this.center.add(-this.villageRadius, 0, this.villageRadius), + this.center.add(this.villageRadius, 0, -this.villageRadius), + this.center.add(this.villageRadius, 0, this.villageRadius), this.center }; + } + } + + public boolean isVillageAreaLoaded() { + for (int i = 0; this.positions != null && i < this.positions.length; i++) { + if (this.worldObj.isBlockLoaded(this.positions[i])) { + return true; + } + } + return false; + } + public void setWorld(World worldIn) { this.worldObj = worldIn; } @@ -78,6 +100,9 @@ public class Village { * Called periodically by VillageCollection */ public void tick(int parInt1) { + if (!isVillageAreaLoaded()) { + return; + } this.tickCounter = parInt1; this.removeDeadAndOutOfRangeDoors(); this.removeDeadAndOldAgressors(); @@ -379,6 +404,8 @@ public class Village { this.villageRadius = Math.max(32, (int) Math.sqrt((double) j) + 1); } + + calculateNewCheckPositions(); } /**+ @@ -443,6 +470,7 @@ public class Village { } } + calculateNewCheckPositions(); } /**+ diff --git a/src/game/java/net/minecraft/village/VillageCollection.java b/src/game/java/net/minecraft/village/VillageCollection.java index a1a4ffde..bfdea854 100755 --- a/src/game/java/net/minecraft/village/VillageCollection.java +++ b/src/game/java/net/minecraft/village/VillageCollection.java @@ -20,7 +20,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/village/VillageDoorInfo.java b/src/game/java/net/minecraft/village/VillageDoorInfo.java index 227e5591..3e4dc41f 100755 --- a/src/game/java/net/minecraft/village/VillageDoorInfo.java +++ b/src/game/java/net/minecraft/village/VillageDoorInfo.java @@ -9,7 +9,7 @@ import net.minecraft.util.EnumFacing; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/village/VillageSiege.java b/src/game/java/net/minecraft/village/VillageSiege.java index 2e2f24b7..a31742e1 100755 --- a/src/game/java/net/minecraft/village/VillageSiege.java +++ b/src/game/java/net/minecraft/village/VillageSiege.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/ChunkCache.java b/src/game/java/net/minecraft/world/ChunkCache.java index 5a63d5c3..59758d59 100755 --- a/src/game/java/net/minecraft/world/ChunkCache.java +++ b/src/game/java/net/minecraft/world/ChunkCache.java @@ -15,7 +15,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -104,6 +104,10 @@ public class ChunkCache implements IBlockAccess { return this.worldObj.getBiomeGenForCoords(blockpos); } + public int getBiomeColorForCoords(BlockPos var1, int index) { + return this.worldObj.getBiomeColorForCoords(var1, index); + } + private int getLightForExt(EnumSkyBlock pos, BlockPos parBlockPos) { if (pos == EnumSkyBlock.SKY && this.worldObj.provider.getHasNoSky()) { return Chunk.getNoSkyLightValue(); diff --git a/src/game/java/net/minecraft/world/ChunkCoordIntPair.java b/src/game/java/net/minecraft/world/ChunkCoordIntPair.java index e91a216d..93eac70e 100755 --- a/src/game/java/net/minecraft/world/ChunkCoordIntPair.java +++ b/src/game/java/net/minecraft/world/ChunkCoordIntPair.java @@ -8,7 +8,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/ColorizerFoliage.java b/src/game/java/net/minecraft/world/ColorizerFoliage.java index dd6f0a97..13f96a8a 100755 --- a/src/game/java/net/minecraft/world/ColorizerFoliage.java +++ b/src/game/java/net/minecraft/world/ColorizerFoliage.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/ColorizerGrass.java b/src/game/java/net/minecraft/world/ColorizerGrass.java index 3b9d2683..3ec82cb6 100755 --- a/src/game/java/net/minecraft/world/ColorizerGrass.java +++ b/src/game/java/net/minecraft/world/ColorizerGrass.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/DifficultyInstance.java b/src/game/java/net/minecraft/world/DifficultyInstance.java index 38abeb79..8d5d2788 100755 --- a/src/game/java/net/minecraft/world/DifficultyInstance.java +++ b/src/game/java/net/minecraft/world/DifficultyInstance.java @@ -8,7 +8,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/EnumDifficulty.java b/src/game/java/net/minecraft/world/EnumDifficulty.java index b228976e..5d9f68a8 100755 --- a/src/game/java/net/minecraft/world/EnumDifficulty.java +++ b/src/game/java/net/minecraft/world/EnumDifficulty.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/EnumSkyBlock.java b/src/game/java/net/minecraft/world/EnumSkyBlock.java index 7ec4f164..bb95262d 100755 --- a/src/game/java/net/minecraft/world/EnumSkyBlock.java +++ b/src/game/java/net/minecraft/world/EnumSkyBlock.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/Explosion.java b/src/game/java/net/minecraft/world/Explosion.java index 9322a866..a3659323 100755 --- a/src/game/java/net/minecraft/world/Explosion.java +++ b/src/game/java/net/minecraft/world/Explosion.java @@ -32,7 +32,7 @@ import net.minecraft.util.Vec3; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/GameRules.java b/src/game/java/net/minecraft/world/GameRules.java index cf5f9dab..9f195305 100755 --- a/src/game/java/net/minecraft/world/GameRules.java +++ b/src/game/java/net/minecraft/world/GameRules.java @@ -11,7 +11,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/IBlockAccess.java b/src/game/java/net/minecraft/world/IBlockAccess.java index 3adf278d..67add182 100755 --- a/src/game/java/net/minecraft/world/IBlockAccess.java +++ b/src/game/java/net/minecraft/world/IBlockAccess.java @@ -12,7 +12,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -43,6 +43,8 @@ public interface IBlockAccess { BiomeGenBase getBiomeGenForCoords(BlockPos var1); + int getBiomeColorForCoords(BlockPos var1, int index); + /**+ * set by !chunk.getAreLevelsEmpty */ diff --git a/src/game/java/net/minecraft/world/IInteractionObject.java b/src/game/java/net/minecraft/world/IInteractionObject.java index e1f0250c..3f4cfab8 100755 --- a/src/game/java/net/minecraft/world/IInteractionObject.java +++ b/src/game/java/net/minecraft/world/IInteractionObject.java @@ -10,7 +10,7 @@ import net.minecraft.inventory.Container; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/ILockableContainer.java b/src/game/java/net/minecraft/world/ILockableContainer.java index 051f62c4..222ca632 100755 --- a/src/game/java/net/minecraft/world/ILockableContainer.java +++ b/src/game/java/net/minecraft/world/ILockableContainer.java @@ -8,7 +8,7 @@ import net.minecraft.inventory.IInventory; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/IWorldAccess.java b/src/game/java/net/minecraft/world/IWorldAccess.java index 056e1cf8..c3bb1fc2 100755 --- a/src/game/java/net/minecraft/world/IWorldAccess.java +++ b/src/game/java/net/minecraft/world/IWorldAccess.java @@ -10,7 +10,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/IWorldNameable.java b/src/game/java/net/minecraft/world/IWorldNameable.java index e5e62b5b..027117b0 100755 --- a/src/game/java/net/minecraft/world/IWorldNameable.java +++ b/src/game/java/net/minecraft/world/IWorldNameable.java @@ -8,7 +8,7 @@ import net.minecraft.util.IChatComponent; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/LockCode.java b/src/game/java/net/minecraft/world/LockCode.java index c201f41a..17c18037 100755 --- a/src/game/java/net/minecraft/world/LockCode.java +++ b/src/game/java/net/minecraft/world/LockCode.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/NextTickListEntry.java b/src/game/java/net/minecraft/world/NextTickListEntry.java index b96ede2b..bda9bb3c 100755 --- a/src/game/java/net/minecraft/world/NextTickListEntry.java +++ b/src/game/java/net/minecraft/world/NextTickListEntry.java @@ -9,7 +9,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/SpawnerAnimals.java b/src/game/java/net/minecraft/world/SpawnerAnimals.java index 635e6f18..1625ec7e 100755 --- a/src/game/java/net/minecraft/world/SpawnerAnimals.java +++ b/src/game/java/net/minecraft/world/SpawnerAnimals.java @@ -1,12 +1,12 @@ package net.minecraft.world; -import com.google.common.collect.Sets; - +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; +import com.carrotsearch.hppc.cursors.LongCursor; import java.util.List; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import java.util.Set; import net.minecraft.block.Block; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; @@ -27,7 +27,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -46,7 +46,7 @@ public final class SpawnerAnimals { /**+ * The 17x17 area around the player where mobs can spawn */ - private final Set eligibleChunksForSpawning = Sets.newHashSet(); + private final LongSet eligibleChunksForSpawning = new LongHashSet(); /**+ * adds all chunks within the spawn radius of the players to @@ -67,15 +67,16 @@ public final class SpawnerAnimals { if (!entityplayer.isSpectator()) { int j = MathHelper.floor_double(entityplayer.posX / 16.0D); int k = MathHelper.floor_double(entityplayer.posZ / 16.0D); - byte b0 = 8; + byte b0 = (byte) spawnHostileMobs.getMinecraftServer().getConfigurationManager().getViewDistance(); for (int l = -b0; l <= b0; ++l) { for (int i1 = -b0; i1 <= b0; ++i1) { boolean flag = l == -b0 || l == b0 || i1 == -b0 || i1 == b0; - ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(l + j, i1 + k); + int cx = l + j; + int cz = i1 + k; + long chunkcoordintpair = ChunkCoordIntPair.chunkXZ2Int(cx, cz); if (!this.eligibleChunksForSpawning.contains(chunkcoordintpair) - && spawnHostileMobs.theChunkProviderServer.chunkExists(chunkcoordintpair.chunkXPos, - chunkcoordintpair.chunkZPos)) { + && spawnHostileMobs.theChunkProviderServer.chunkExists(cx, cz)) { ++i; if (!flag && spawnHostileMobs.getWorldBorder().contains(chunkcoordintpair)) { this.eligibleChunksForSpawning.add(chunkcoordintpair); @@ -98,9 +99,11 @@ public final class SpawnerAnimals { int l3 = spawnHostileMobs.countEntities(enumcreaturetype.getCreatureClass()); int i4 = enumcreaturetype.getMaxNumberOfCreature() * i / MOB_COUNT_DIV; if (l3 <= i4) { - label374: for (ChunkCoordIntPair chunkcoordintpair1 : this.eligibleChunksForSpawning) { - BlockPos blockpos = getRandomChunkPosition(spawnHostileMobs, chunkcoordintpair1.chunkXPos, - chunkcoordintpair1.chunkZPos); + label374: for (LongCursor chunkcoordintpair1 : this.eligibleChunksForSpawning) { + long chunkcoordintpair1l = chunkcoordintpair1.value; + int chunkXPos = (int) (chunkcoordintpair1l & 4294967295L); + int chunkZPos = (int) (chunkcoordintpair1l >>> 32); + BlockPos blockpos = getRandomChunkPosition(spawnHostileMobs, chunkXPos, chunkZPos); int j1 = blockpos.getX(); int k1 = blockpos.getY(); int l1 = blockpos.getZ(); diff --git a/src/game/java/net/minecraft/world/Teleporter.java b/src/game/java/net/minecraft/world/Teleporter.java index 6e9b256d..6fc9a9c7 100755 --- a/src/game/java/net/minecraft/world/Teleporter.java +++ b/src/game/java/net/minecraft/world/Teleporter.java @@ -1,8 +1,9 @@ package net.minecraft.world; -import com.google.common.collect.Lists; -import java.util.Iterator; -import java.util.List; +import com.carrotsearch.hppc.LongArrayList; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; + import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.minecraft.block.BlockPortal; import net.minecraft.block.state.IBlockState; @@ -11,7 +12,6 @@ import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; -import net.minecraft.util.LongHashMap; import net.minecraft.util.MathHelper; /**+ @@ -20,7 +20,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -41,12 +41,12 @@ public class Teleporter { * Stores successful portal placement locations for rapid * lookup. */ - private final LongHashMap destinationCoordinateCache = new LongHashMap(); + private final LongObjectMap destinationCoordinateCache = new LongObjectHashMap<>(); /**+ * A list of valid keys for the destinationCoordainteCache. * These are based on the X & Z of the players initial location. */ - private final List destinationCoordinateKeys = Lists.newArrayList(); + private final LongArrayList destinationCoordinateKeys = new LongArrayList(); public Teleporter(WorldServer worldIn) { this.worldServerInstance = worldIn; @@ -92,9 +92,8 @@ public class Teleporter { boolean flag1 = true; Object object = BlockPos.ORIGIN; long k = ChunkCoordIntPair.chunkXZ2Int(i, j); - if (this.destinationCoordinateCache.containsItem(k)) { - Teleporter.PortalPosition teleporter$portalposition = (Teleporter.PortalPosition) this.destinationCoordinateCache - .getValueByKey(k); + if (this.destinationCoordinateCache.containsKey(k)) { + Teleporter.PortalPosition teleporter$portalposition = this.destinationCoordinateCache.get(k); d0 = 0.0D; object = teleporter$portalposition; teleporter$portalposition.lastUpdateTime = this.worldServerInstance.getTotalWorldTime(); @@ -128,7 +127,7 @@ public class Teleporter { if (d0 >= 0.0D) { if (flag1) { - this.destinationCoordinateCache.add(k, + this.destinationCoordinateCache.put(k, new Teleporter.PortalPosition((BlockPos) object, this.worldServerInstance.getTotalWorldTime())); this.destinationCoordinateKeys.add(Long.valueOf(k)); } @@ -374,16 +373,14 @@ public class Teleporter { */ public void removeStalePortalLocations(long worldTime) { if (worldTime % 100L == 0L) { - Iterator iterator = this.destinationCoordinateKeys.iterator(); long i = worldTime - 300L; - while (iterator.hasNext()) { - Long olong = (Long) iterator.next(); - Teleporter.PortalPosition teleporter$portalposition = (Teleporter.PortalPosition) this.destinationCoordinateCache - .getValueByKey(olong.longValue()); + for (int j = 0; j < destinationCoordinateKeys.size(); ++j) { + long olong = destinationCoordinateKeys.get(j); + Teleporter.PortalPosition teleporter$portalposition = this.destinationCoordinateCache.get(olong); if (teleporter$portalposition == null || teleporter$portalposition.lastUpdateTime < i) { - iterator.remove(); - this.destinationCoordinateCache.remove(olong.longValue()); + destinationCoordinateKeys.removeAt(j--); + this.destinationCoordinateCache.remove(olong); } } } diff --git a/src/game/java/net/minecraft/world/World.java b/src/game/java/net/minecraft/world/World.java index adb5d6d0..ab3f7e5e 100755 --- a/src/game/java/net/minecraft/world/World.java +++ b/src/game/java/net/minecraft/world/World.java @@ -1,5 +1,9 @@ package net.minecraft.world; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongSet; import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -9,9 +13,9 @@ import java.util.Calendar; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Set; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import java.util.Set; import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.lax1dude.eaglercraft.v1_8.HString; @@ -42,12 +46,12 @@ import net.minecraft.util.EntitySelectors; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ITickable; -import net.minecraft.util.IntHashMap; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.ReportedException; import net.minecraft.util.Vec3; import net.minecraft.village.VillageCollection; +import net.minecraft.world.biome.BiomeColorHelper; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.biome.WorldChunkManager; import net.minecraft.world.border.WorldBorder; @@ -64,7 +68,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -89,8 +93,8 @@ public abstract class World implements IBlockAccess { /**+ * A list of the loaded tile entities in the world */ - public final List loadedTileEntityList = Lists.newArrayList(); - public final List tickableTileEntities = Lists.newArrayList(); + public final Set loadedTileEntityList = Sets.newIdentityHashSet(); + public final Set tickableTileEntities = Sets.newIdentityHashSet(); private final List addedTileEntityList = Lists.newArrayList(); private final List tileEntitiesToBeRemoved = Lists.newArrayList(); /**+ @@ -101,7 +105,7 @@ public abstract class World implements IBlockAccess { * a list of all the lightning entities */ public final List weatherEffects = Lists.newArrayList(); - protected final IntHashMap entitiesById = new IntHashMap(); + protected final IntObjectMap entitiesById = new IntObjectHashMap<>(); private long cloudColour = 16777215L; private int skylightSubtracted; /**+ @@ -138,7 +142,7 @@ public abstract class World implements IBlockAccess { /**+ * populated by chunks that are within 9 chunks of any player */ - protected Set activeChunkSet = Sets.newHashSet(); + protected LongSet activeChunkSet = new LongHashSet(); private int ambientTickCountdown; protected boolean spawnHostileMobs; protected boolean spawnPeacefulMobs; @@ -185,6 +189,10 @@ public abstract class World implements IBlockAccess { } } + public int getBiomeColorForCoords(BlockPos var1, int index) { + return BiomeColorHelper.getBiomeColorForCoordsOld(this, var1, index); + } + public WorldChunkManager getWorldChunkManager() { return this.provider.getWorldChunkManager(); } @@ -232,11 +240,11 @@ public abstract class World implements IBlockAccess { } public boolean isBlockLoaded(BlockPos pos) { - return this.isBlockLoaded(pos, true); + return !this.isValid(pos) ? false : this.isChunkLoaded(pos.x >> 4, pos.z >> 4, true); } public boolean isBlockLoaded(BlockPos pos, boolean allowEmpty) { - return !this.isValid(pos) ? false : this.isChunkLoaded(pos.getX() >> 4, pos.getZ() >> 4, allowEmpty); + return !this.isValid(pos) ? false : this.isChunkLoaded(pos.x >> 4, pos.z >> 4, allowEmpty); } public boolean isAreaLoaded(BlockPos center, int radius) { @@ -290,7 +298,13 @@ public abstract class World implements IBlockAccess { } public Chunk getChunkFromBlockCoords(BlockPos pos) { - return this.getChunkFromChunkCoords(pos.getX() >> 4, pos.getZ() >> 4); + return this.chunkProvider.provideChunk(pos.x >> 4, pos.z >> 4); + } + + public Chunk getChunkFromBlockCoordsIfLoaded(BlockPos pos) { + int x = pos.x >> 4; + int z = pos.z >> 4; + return this.chunkProvider.chunkExists(x, z) ? this.chunkProvider.provideChunk(x, z) : null; } /**+ @@ -301,6 +315,10 @@ public abstract class World implements IBlockAccess { return this.chunkProvider.provideChunk(chunkX, chunkZ); } + public Chunk getChunkFromChunkCoordsIfLoaded(int chunkX, int chunkZ) { + return this.chunkProvider.chunkExists(chunkX, chunkZ) ? this.chunkProvider.provideChunk(chunkX, chunkZ) : null; + } + /**+ * Convenience method to update the block on both the client and * server @@ -701,6 +719,15 @@ public abstract class World implements IBlockAccess { } } + public IBlockState getBlockStateIfLoaded(BlockPos pos) { + if (!this.isValid(pos)) { + return Blocks.air.getDefaultState(); + } else { + Chunk chunk = this.getChunkFromBlockCoordsIfLoaded(pos); + return chunk != null ? chunk.getBlockState(pos) : null; + } + } + /**+ * Checks whether its daytime by seeing if the light subtracted * from the skylight is less than 4 @@ -737,7 +764,9 @@ public abstract class World implements IBlockAccess { int i1 = MathHelper.floor_double(vec31.yCoord); int j1 = MathHelper.floor_double(vec31.zCoord); BlockPos blockpos = new BlockPos(l, i1, j1); - IBlockState iblockstate = this.getBlockState(blockpos); + IBlockState iblockstate = this.getBlockStateIfLoaded(blockpos); + if (iblockstate == null) + return null; Block block = iblockstate.getBlock(); if ((!ignoreBlockWithoutBoundingBox || block.getCollisionBoundingBox(this, blockpos, iblockstate) != null) @@ -836,7 +865,9 @@ public abstract class World implements IBlockAccess { i1 = MathHelper.floor_double(vec31.yCoord) - (enumfacing == EnumFacing.UP ? 1 : 0); j1 = MathHelper.floor_double(vec31.zCoord) - (enumfacing == EnumFacing.SOUTH ? 1 : 0); blockpos = new BlockPos(l, i1, j1); - IBlockState iblockstate1 = this.getBlockState(blockpos); + IBlockState iblockstate1 = this.getBlockStateIfLoaded(blockpos); + if (iblockstate1 == null) + return null; Block block1 = iblockstate1.getBlock(); if (!ignoreBlockWithoutBoundingBox || block1.getCollisionBoundingBox(this, blockpos, iblockstate1) != null) { @@ -2122,11 +2153,13 @@ public abstract class World implements IBlockAccess { EntityPlayer entityplayer = (EntityPlayer) this.playerEntities.get(i); int j = MathHelper.floor_double(entityplayer.posX / 16.0D); int k = MathHelper.floor_double(entityplayer.posZ / 16.0D); - int l = this.getRenderDistanceChunks(); + int l = this.getRenderDistanceChunks() - 1; + if (l < 1) + l = 1; for (int i1 = -l; i1 <= l; ++i1) { for (int j1 = -l; j1 <= l; ++j1) { - this.activeChunkSet.add(new ChunkCoordIntPair(i1 + j, j1 + k)); + this.activeChunkSet.add(ChunkCoordIntPair.chunkXZ2Int(i1 + j, j1 + k)); } } } @@ -2452,9 +2485,9 @@ public abstract class World implements IBlockAccess { for (int i1 = i; i1 <= j; ++i1) { for (int j1 = k; j1 <= l; ++j1) { - if (this.isChunkLoaded(i1, j1, true)) { - this.getChunkFromChunkCoords(i1, j1).getEntitiesWithinAABBForEntity(entityIn, boundingBox, - arraylist, predicate); + Chunk chunk = this.getChunkFromChunkCoordsIfLoaded(i1, j1); + if (chunk != null) { + chunk.getEntitiesWithinAABBForEntity(entityIn, boundingBox, arraylist, predicate); } } } @@ -2536,7 +2569,7 @@ public abstract class World implements IBlockAccess { * exist in this World. */ public Entity getEntityByID(int id) { - return (Entity) this.entitiesById.lookup(id); + return this.entitiesById.get(id); } /**+ diff --git a/src/game/java/net/minecraft/world/WorldManager.java b/src/game/java/net/minecraft/world/WorldManager.java index 490bb120..4b665fa0 100755 --- a/src/game/java/net/minecraft/world/WorldManager.java +++ b/src/game/java/net/minecraft/world/WorldManager.java @@ -15,7 +15,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldProvider.java b/src/game/java/net/minecraft/world/WorldProvider.java index c4387c58..919bf6ca 100755 --- a/src/game/java/net/minecraft/world/WorldProvider.java +++ b/src/game/java/net/minecraft/world/WorldProvider.java @@ -20,7 +20,7 @@ import net.minecraft.world.gen.FlatGeneratorInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldProviderEnd.java b/src/game/java/net/minecraft/world/WorldProviderEnd.java index c94ca0b1..9dfd7731 100755 --- a/src/game/java/net/minecraft/world/WorldProviderEnd.java +++ b/src/game/java/net/minecraft/world/WorldProviderEnd.java @@ -14,7 +14,7 @@ import net.minecraft.world.gen.ChunkProviderEnd; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldProviderHell.java b/src/game/java/net/minecraft/world/WorldProviderHell.java index b1de94cf..5b1e8876 100755 --- a/src/game/java/net/minecraft/world/WorldProviderHell.java +++ b/src/game/java/net/minecraft/world/WorldProviderHell.java @@ -13,7 +13,7 @@ import net.minecraft.world.gen.ChunkProviderHell; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldProviderSurface.java b/src/game/java/net/minecraft/world/WorldProviderSurface.java index a037c28b..e36e3256 100755 --- a/src/game/java/net/minecraft/world/WorldProviderSurface.java +++ b/src/game/java/net/minecraft/world/WorldProviderSurface.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldSavedData.java b/src/game/java/net/minecraft/world/WorldSavedData.java index 87007e50..edbab757 100755 --- a/src/game/java/net/minecraft/world/WorldSavedData.java +++ b/src/game/java/net/minecraft/world/WorldSavedData.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldServer.java b/src/game/java/net/minecraft/world/WorldServer.java index 34381f42..d207d5a0 100755 --- a/src/game/java/net/minecraft/world/WorldServer.java +++ b/src/game/java/net/minecraft/world/WorldServer.java @@ -1,5 +1,6 @@ package net.minecraft.world; +import com.carrotsearch.hppc.cursors.LongCursor; import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -75,7 +76,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -319,19 +320,22 @@ public class WorldServer extends World implements IThreadListener { protected void updateBlocks() { super.updateBlocks(); if (this.worldInfo.getTerrainType() == WorldType.DEBUG_WORLD) { - for (ChunkCoordIntPair chunkcoordintpair1 : this.activeChunkSet) { - this.getChunkFromChunkCoords(chunkcoordintpair1.chunkXPos, chunkcoordintpair1.chunkZPos) - .func_150804_b(false); + for (LongCursor chunkcoordintpair1 : this.activeChunkSet) { + long l = chunkcoordintpair1.value; + this.getChunkFromChunkCoords((int) (l & 4294967295L), (int) (l >>> 32)).func_150804_b(false); } } else { int i = 0; int j = 0; - for (ChunkCoordIntPair chunkcoordintpair : this.activeChunkSet) { - int k = chunkcoordintpair.chunkXPos * 16; - int l = chunkcoordintpair.chunkZPos * 16; - Chunk chunk = this.getChunkFromChunkCoords(chunkcoordintpair.chunkXPos, chunkcoordintpair.chunkZPos); + for (LongCursor chunkcoordintpair : this.activeChunkSet) { + long ll = chunkcoordintpair.value; + int chunkXPos = (int) (ll & 4294967295L); + int chunkZPos = (int) (ll >>> 32); + int k = chunkXPos * 16; + int l = chunkZPos * 16; + Chunk chunk = this.getChunkFromChunkCoords(chunkXPos, chunkZPos); this.playMoodSoundAndCheckLight(k, l, chunk); chunk.func_150804_b(false); if (this.rand.nextInt(100000) == 0 && this.isRaining() && this.isThundering()) { @@ -635,14 +639,22 @@ public class WorldServer extends World implements IThreadListener { * coordinates */ public List getTileEntitiesIn(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - ArrayList arraylist = Lists.newArrayList(); + ArrayList arraylist = Lists.newArrayList(); - for (int i = 0; i < this.loadedTileEntityList.size(); ++i) { - TileEntity tileentity = (TileEntity) this.loadedTileEntityList.get(i); - BlockPos blockpos = tileentity.getPos(); - if (blockpos.getX() >= minX && blockpos.getY() >= minY && blockpos.getZ() >= minZ && blockpos.getX() < maxX - && blockpos.getY() < maxY && blockpos.getZ() < maxZ) { - arraylist.add(tileentity); + for (int chunkX = (minX >> 4); chunkX <= ((maxX - 1) >> 4); chunkX++) { + for (int chunkZ = (minZ >> 4); chunkZ <= ((maxZ - 1) >> 4); chunkZ++) { + Chunk chunk = getChunkFromChunkCoords(chunkX, chunkZ); + if (chunk == null) { + continue; + } + + for (TileEntity tileentity : chunk.getTileEntityMap().values()) { + BlockPos pos = tileentity.getPos(); + if ((pos.x >= minX) && (pos.y >= minY) && (pos.z >= minZ) && (pos.x < maxX) && (pos.y < maxY) + && (pos.z < maxZ)) { + arraylist.add(tileentity); + } + } } } @@ -819,12 +831,12 @@ public class WorldServer extends World implements IThreadListener { protected void onEntityAdded(Entity entity) { super.onEntityAdded(entity); - this.entitiesById.addKey(entity.getEntityId(), entity); + this.entitiesById.put(entity.getEntityId(), entity); this.entitiesByUuid.put(entity.getUniqueID(), entity); Entity[] aentity = entity.getParts(); if (aentity != null) { for (int i = 0; i < aentity.length; ++i) { - this.entitiesById.addKey(aentity[i].getEntityId(), aentity[i]); + this.entitiesById.put(aentity[i].getEntityId(), aentity[i]); } } @@ -832,12 +844,12 @@ public class WorldServer extends World implements IThreadListener { protected void onEntityRemoved(Entity entity) { super.onEntityRemoved(entity); - this.entitiesById.removeObject(entity.getEntityId()); + this.entitiesById.remove(entity.getEntityId()); this.entitiesByUuid.remove(entity.getUniqueID()); Entity[] aentity = entity.getParts(); if (aentity != null) { for (int i = 0; i < aentity.length; ++i) { - this.entitiesById.removeObject(aentity[i].getEntityId()); + this.entitiesById.remove(aentity[i].getEntityId()); } } diff --git a/src/game/java/net/minecraft/world/WorldServerMulti.java b/src/game/java/net/minecraft/world/WorldServerMulti.java index a7bb01c6..9732f64c 100755 --- a/src/game/java/net/minecraft/world/WorldServerMulti.java +++ b/src/game/java/net/minecraft/world/WorldServerMulti.java @@ -13,7 +13,7 @@ import net.minecraft.world.storage.ISaveHandler; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldSettings.java b/src/game/java/net/minecraft/world/WorldSettings.java index 9f46d5f5..bd45ab7c 100755 --- a/src/game/java/net/minecraft/world/WorldSettings.java +++ b/src/game/java/net/minecraft/world/WorldSettings.java @@ -9,7 +9,7 @@ import net.minecraft.world.storage.WorldInfo; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/WorldType.java b/src/game/java/net/minecraft/world/WorldType.java index 96efd5fd..ac0801f1 100755 --- a/src/game/java/net/minecraft/world/WorldType.java +++ b/src/game/java/net/minecraft/world/WorldType.java @@ -6,7 +6,7 @@ package net.minecraft.world; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeCache.java b/src/game/java/net/minecraft/world/biome/BiomeCache.java index c76f95c7..aaf48303 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeCache.java +++ b/src/game/java/net/minecraft/world/biome/BiomeCache.java @@ -1,9 +1,10 @@ package net.minecraft.world.biome; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; import com.google.common.collect.Lists; import java.util.List; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.LongHashMap; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. @@ -11,7 +12,7 @@ import net.minecraft.util.LongHashMap; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -32,7 +33,7 @@ public class BiomeCache { * The map of keys to BiomeCacheBlocks. Keys are based on the * chunk x, z coordinates as (x | z << 32). */ - private LongHashMap cacheMap = new LongHashMap(); + private LongObjectMap cacheMap = new LongObjectHashMap<>(); /**+ * The list of cached BiomeCacheBlocks */ @@ -49,10 +50,10 @@ public class BiomeCache { x = x >> 4; z = z >> 4; long i = (long) x & 4294967295L | ((long) z & 4294967295L) << 32; - BiomeCache.Block biomecache$block = (BiomeCache.Block) this.cacheMap.getValueByKey(i); + BiomeCache.Block biomecache$block = this.cacheMap.get(i); if (biomecache$block == null) { biomecache$block = new BiomeCache.Block(x, z); - this.cacheMap.add(i, biomecache$block); + this.cacheMap.put(i, biomecache$block); this.cache.add(biomecache$block); } @@ -76,7 +77,7 @@ public class BiomeCache { this.lastCleanupTime = i; for (int k = 0; k < this.cache.size(); ++k) { - BiomeCache.Block biomecache$block = (BiomeCache.Block) this.cache.get(k); + BiomeCache.Block biomecache$block = this.cache.get(k); long l = i - biomecache$block.lastAccessTime; if (l > 30000L || l < 0L) { this.cache.remove(k--); diff --git a/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java b/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java index 98f3da1e..e78d6954 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java +++ b/src/game/java/net/minecraft/world/biome/BiomeColorHelper.java @@ -9,7 +9,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -24,6 +24,7 @@ import net.minecraft.world.IBlockAccess; * */ public class BiomeColorHelper { + private static final BiomeColorHelper.ColorResolver field_180291_a = new BiomeColorHelper.ColorResolver() { public int getColorAtPos(BiomeGenBase blockPosition, BlockPos parBlockPos) { return blockPosition.getGrassColorAtPos(parBlockPos); @@ -59,15 +60,25 @@ public class BiomeColorHelper { } public static int getGrassColorAtPos(IBlockAccess parIBlockAccess, BlockPos parBlockPos) { - return func_180285_a(parIBlockAccess, parBlockPos, field_180291_a); + return parIBlockAccess.getBiomeColorForCoords(parBlockPos, 0); } public static int getFoliageColorAtPos(IBlockAccess parIBlockAccess, BlockPos parBlockPos) { - return func_180285_a(parIBlockAccess, parBlockPos, field_180289_b); + return parIBlockAccess.getBiomeColorForCoords(parBlockPos, 1); } public static int getWaterColorAtPos(IBlockAccess parIBlockAccess, BlockPos parBlockPos) { - return func_180285_a(parIBlockAccess, parBlockPos, field_180290_c); + return parIBlockAccess.getBiomeColorForCoords(parBlockPos, 2); + } + + public static int getBiomeColorForCoordsOld(IBlockAccess parIBlockAccess, BlockPos parBlockPos, int index) { + if (index == 0) { + return func_180285_a(parIBlockAccess, parBlockPos, field_180291_a); + } else if (index == 1) { + return func_180285_a(parIBlockAccess, parBlockPos, field_180289_b); + } else { + return func_180285_a(parIBlockAccess, parBlockPos, field_180290_c); + } } interface ColorResolver { diff --git a/src/game/java/net/minecraft/world/biome/BiomeDecorator.java b/src/game/java/net/minecraft/world/biome/BiomeDecorator.java index f0559d20..42e85489 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeDecorator.java +++ b/src/game/java/net/minecraft/world/biome/BiomeDecorator.java @@ -29,7 +29,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java b/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java index c59f376f..258cb27e 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java +++ b/src/game/java/net/minecraft/world/biome/BiomeEndDecorator.java @@ -11,7 +11,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenBase.java b/src/game/java/net/minecraft/world/biome/BiomeGenBase.java index 833a9aee..a615bebc 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenBase.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenBase.java @@ -55,7 +55,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java b/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java index 8522c1e7..de1a13df 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenBeach.java @@ -8,7 +8,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java b/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java index 5ec89e51..e9b9f9e3 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenDesert.java @@ -12,7 +12,7 @@ import net.minecraft.world.gen.feature.WorldGenDesertWells; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java b/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java index ab1ac3a8..feb29ccd 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenEnd.java @@ -9,7 +9,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenForest.java b/src/game/java/net/minecraft/world/biome/BiomeGenForest.java index b0e0e930..a1041520 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenForest.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenForest.java @@ -18,7 +18,7 @@ import net.minecraft.world.gen.feature.WorldGenForest; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenHell.java b/src/game/java/net/minecraft/world/biome/BiomeGenHell.java index d20356dc..6ebdd880 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenHell.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenHell.java @@ -10,7 +10,7 @@ import net.minecraft.entity.monster.EntityPigZombie; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenHills.java b/src/game/java/net/minecraft/world/biome/BiomeGenHills.java index d00be348..8eb3236a 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenHills.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenHills.java @@ -17,7 +17,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java b/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java index f11b4f7a..23b5f6fe 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenJungle.java @@ -27,7 +27,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java b/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java index bbc62066..4d4d342a 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenMesa.java @@ -21,7 +21,7 @@ import net.minecraft.world.gen.feature.WorldGenAbstractTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java b/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java index fdb2948d..08133b8b 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenMushroomIsland.java @@ -9,7 +9,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java b/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java index b28ec805..ede1c2fd 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenMutated.java @@ -15,7 +15,7 @@ import net.minecraft.world.gen.feature.WorldGenAbstractTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java b/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java index f79946e8..934bf461 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenOcean.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java b/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java index 39ac214f..b23993a7 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenPlains.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java b/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java index c84304e5..be88812e 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenRiver.java @@ -6,7 +6,7 @@ package net.minecraft.world.biome; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java b/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java index b3710882..0628040d 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenSavanna.java @@ -17,7 +17,7 @@ import net.minecraft.world.gen.feature.WorldGenSavannaTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java b/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java index cb00192b..08b114f2 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenSnow.java @@ -15,7 +15,7 @@ import net.minecraft.world.gen.feature.WorldGenTaiga2; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java b/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java index fc310bf7..fcfd09bd 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenStoneBeach.java @@ -8,7 +8,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java b/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java index 81abc93a..80cd6d46 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenSwamp.java @@ -16,7 +16,7 @@ import net.minecraft.world.gen.feature.WorldGenAbstractTree; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java b/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java index 25aa05f1..a14d2bb5 100755 --- a/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java +++ b/src/game/java/net/minecraft/world/biome/BiomeGenTaiga.java @@ -23,7 +23,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/biome/WorldChunkManager.java b/src/game/java/net/minecraft/world/biome/WorldChunkManager.java index 09044925..b68c603c 100755 --- a/src/game/java/net/minecraft/world/biome/WorldChunkManager.java +++ b/src/game/java/net/minecraft/world/biome/WorldChunkManager.java @@ -18,7 +18,7 @@ import net.minecraft.world.gen.layer.IntCache; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -85,6 +85,13 @@ public class WorldChunkManager { return this.biomeCache.func_180284_a(pos.getX(), pos.getZ(), biomeGenBaseIn); } + /**+ + * Returns the biome generator + */ + public BiomeGenBase getBiomeGenerator(int x, int z, BiomeGenBase biomeGenBaseIn) { + return this.biomeCache.func_180284_a(x, z, biomeGenBaseIn); + } + /**+ * Returns a list of rainfall values for the specified blocks. * Args: listToReuse, x, z, width, length. diff --git a/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java b/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java index fe68f7ae..d968fa68 100755 --- a/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java +++ b/src/game/java/net/minecraft/world/biome/WorldChunkManagerHell.java @@ -11,7 +11,7 @@ import net.minecraft.util.BlockPos; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/border/EnumBorderStatus.java b/src/game/java/net/minecraft/world/border/EnumBorderStatus.java index 639c7438..150fcfaf 100755 --- a/src/game/java/net/minecraft/world/border/EnumBorderStatus.java +++ b/src/game/java/net/minecraft/world/border/EnumBorderStatus.java @@ -6,7 +6,7 @@ package net.minecraft.world.border; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/border/IBorderListener.java b/src/game/java/net/minecraft/world/border/IBorderListener.java index 854515f5..15239bee 100755 --- a/src/game/java/net/minecraft/world/border/IBorderListener.java +++ b/src/game/java/net/minecraft/world/border/IBorderListener.java @@ -6,7 +6,7 @@ package net.minecraft.world.border; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/border/WorldBorder.java b/src/game/java/net/minecraft/world/border/WorldBorder.java index d3608516..967e83eb 100755 --- a/src/game/java/net/minecraft/world/border/WorldBorder.java +++ b/src/game/java/net/minecraft/world/border/WorldBorder.java @@ -16,7 +16,7 @@ import net.minecraft.world.ChunkCoordIntPair; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -63,6 +63,13 @@ public class WorldBorder { && (double) range.getZEnd() > this.minZ() && (double) range.getZStart() < this.maxZ(); } + public boolean contains(long range) { + int chunkXPos = (int) (range & 4294967295L); + int chunkZPos = (int) (range >>> 32); + return (double) ((chunkXPos << 4) + 15) > this.minX() && (double) (chunkXPos << 4) < this.maxX() + && (double) ((chunkZPos << 4) + 15) > this.minZ() && (double) (chunkZPos << 4) < this.maxZ(); + } + public boolean contains(AxisAlignedBB bb) { return bb.maxX > this.minX() && bb.minX < this.maxX() && bb.maxZ > this.minZ() && bb.minZ < this.maxZ(); } diff --git a/src/game/java/net/minecraft/world/chunk/Chunk.java b/src/game/java/net/minecraft/world/chunk/Chunk.java index 48001678..97cd2d78 100755 --- a/src/game/java/net/minecraft/world/chunk/Chunk.java +++ b/src/game/java/net/minecraft/world/chunk/Chunk.java @@ -8,15 +8,11 @@ import java.util.List; import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; -import java.util.concurrent.Callable; - import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; import net.minecraft.block.Block; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; -import net.minecraft.crash.CrashReport; -import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; @@ -25,7 +21,6 @@ import net.minecraft.util.BlockPos; import net.minecraft.util.ClassInheritanceMultiMap; import net.minecraft.util.EnumFacing; import net.minecraft.util.MathHelper; -import net.minecraft.util.ReportedException; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; @@ -42,7 +37,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -80,6 +75,7 @@ public class Chunk { private long inhabitedTime; private int queuedLightChecks; private List tileEntityPosQueue; + private final ChunkCoordIntPair coordsCache; public Chunk(World worldIn, int x, int z) { this.storageArrays = new ExtendedBlockStorage[16]; @@ -94,6 +90,7 @@ public class Chunk { this.xPosition = x; this.zPosition = z; this.heightMap = new int[256]; + this.coordsCache = new ChunkCoordIntPair(x, z); for (int i = 0; i < this.entityLists.length; ++i) { this.entityLists[i] = new ClassInheritanceMultiMap(Entity.class); @@ -135,7 +132,7 @@ public class Chunk { } public int getHeight(BlockPos pos) { - return this.getHeightValue(pos.getX() & 15, pos.getZ() & 15); + return this.getHeightValue(pos.x & 15, pos.z & 15); } /**+ @@ -179,7 +176,7 @@ public class Chunk { this.precipitationHeightMap[j + (k << 4)] = -999; for (int l = i + 16; l > 0; --l) { - Block block = this.getBlock0(j, l - 1, k); + Block block = this.getBlock(j, l - 1, k); if (block.getLightOpacity() != 0) { this.heightMap[k << 4 | j] = l; if (l < this.heightMapMinimum) { @@ -422,112 +419,46 @@ public class Chunk { } private int getBlockLightOpacity(int x, int y, int z) { - return this.getBlock0(x, y, z).getLightOpacity(); + return this.getBlock(x, y, z).getLightOpacity(); } - /**+ - * Returns the block corresponding to the given coordinates - * inside a chunk. - */ - private Block getBlock0(int x, int y, int z) { - Block block = Blocks.air; + public Block getBlock(int x, int y, int z) { if (y >= 0 && y >> 4 < this.storageArrays.length) { ExtendedBlockStorage extendedblockstorage = this.storageArrays[y >> 4]; if (extendedblockstorage != null) { - try { - block = extendedblockstorage.getBlockByExtId(x, y & 15, z); - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block"); - throw new ReportedException(crashreport); - } + return extendedblockstorage.getBlockByExtId(x, y & 15, z); } } - return block; + return Blocks.air; } - public Block getBlock(final int x, final int y, final int z) { - try { - return this.getBlock0(x & 15, y, z & 15); - } catch (ReportedException reportedexception) { - CrashReportCategory crashreportcategory = reportedexception.getCrashReport() - .makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo( - new BlockPos(Chunk.this.xPosition * 16 + x, y, Chunk.this.zPosition * 16 + z)); - } - }); - throw reportedexception; + public Block getBlock(final BlockPos pos) { + if (pos.y >= 0 && pos.y >> 4 < this.storageArrays.length) { + ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.y >> 4]; + if (extendedblockstorage != null) { + int j = pos.x & 15; + int k = pos.y & 15; + int i = pos.z & 15; + return extendedblockstorage.getBlockByExtId(j, k, i); + } } - } - public Block getBlock(final BlockPos blockpos) { - try { - return this.getBlock0(blockpos.getX() & 15, blockpos.getY(), blockpos.getZ() & 15); - } catch (ReportedException reportedexception) { - CrashReportCategory crashreportcategory = reportedexception.getCrashReport() - .makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo(blockpos); - } - }); - throw reportedexception; - } + return Blocks.air; } public IBlockState getBlockState(final BlockPos pos) { - try { - if (pos.getY() >= 0 && pos.getY() >> 4 < this.storageArrays.length) { - ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.getY() >> 4]; - if (extendedblockstorage != null) { - int j = pos.getX() & 15; - int k = pos.getY() & 15; - int i = pos.getZ() & 15; - return extendedblockstorage.get(j, k, i); - } + if (pos.y >= 0 && pos.y >> 4 < this.storageArrays.length) { + ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.y >> 4]; + if (extendedblockstorage != null) { + int j = pos.x & 15; + int k = pos.y & 15; + int i = pos.z & 15; + return extendedblockstorage.get(j, k, i); } - - return Blocks.air.getDefaultState(); - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block state"); - CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo(pos); - } - }); - throw new ReportedException(crashreport); } - } - /** - * only use with a regular "net.minecraft.util.BlockPos"! - */ - public IBlockState getBlockStateFaster(final BlockPos pos) { - try { - if (pos.y >= 0 && pos.y >> 4 < this.storageArrays.length) { - ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.getY() >> 4]; - if (extendedblockstorage != null) { - int j = pos.x & 15; - int k = pos.y & 15; - int i = pos.z & 15; - return extendedblockstorage.get(j, k, i); - } - } - - return Blocks.air.getDefaultState(); - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block state"); - CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being got"); - crashreportcategory.addCrashSectionCallable("Location", new Callable() { - public String call() throws Exception { - return CrashReportCategory.getCoordinateInfo(pos); - } - }); - throw new ReportedException(crashreport); - } + return Blocks.air.getDefaultState(); } /**+ @@ -552,9 +483,9 @@ public class Chunk { } public IBlockState setBlockState(BlockPos pos, IBlockState state) { - int i = pos.getX() & 15; - int j = pos.getY(); - int k = pos.getZ() & 15; + int i = pos.x & 15; + int j = pos.y; + int k = pos.z & 15; int l = k << 4 | i; if (j >= this.precipitationHeightMap[l] - 1) { this.precipitationHeightMap[l] = -999; @@ -641,9 +572,9 @@ public class Chunk { } public int getLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos) { - int i = blockpos.getX() & 15; - int j = blockpos.getY(); - int k = blockpos.getZ() & 15; + int i = blockpos.x & 15; + int j = blockpos.y; + int k = blockpos.z & 15; ExtendedBlockStorage extendedblockstorage = this.storageArrays[j >> 4]; return extendedblockstorage == null ? (this.canSeeSky(blockpos) ? enumskyblock.defaultLightValue : getNoSkyLightValue()) @@ -655,9 +586,9 @@ public class Chunk { } public void setLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos, int i) { - int j = blockpos.getX() & 15; - int k = blockpos.getY(); - int l = blockpos.getZ() & 15; + int j = blockpos.x & 15; + int k = blockpos.y; + int l = blockpos.z & 15; ExtendedBlockStorage extendedblockstorage = this.storageArrays[k >> 4]; if (extendedblockstorage == null) { extendedblockstorage = this.storageArrays[k >> 4] = new ExtendedBlockStorage(k >> 4 << 4, @@ -677,9 +608,9 @@ public class Chunk { } public int getLightSubtracted(BlockPos blockpos, int i) { - int j = blockpos.getX() & 15; - int k = blockpos.getY(); - int l = blockpos.getZ() & 15; + int j = blockpos.x & 15; + int k = blockpos.y; + int l = blockpos.z & 15; ExtendedBlockStorage extendedblockstorage = this.storageArrays[k >> 4]; if (extendedblockstorage == null) { return !this.worldObj.provider.getHasNoSky() && i < EnumSkyBlock.SKY.defaultLightValue @@ -754,9 +685,9 @@ public class Chunk { } public boolean canSeeSky(BlockPos blockpos) { - int i = blockpos.getX() & 15; - int j = blockpos.getY(); - int k = blockpos.getZ() & 15; + int i = blockpos.x & 15; + int j = blockpos.y; + int k = blockpos.z & 15; return j >= this.heightMap[k << 4 | i]; } @@ -1038,7 +969,11 @@ public class Chunk { * Gets a ChunkCoordIntPair representing the Chunk's position. */ public ChunkCoordIntPair getChunkCoordIntPair() { - return new ChunkCoordIntPair(this.xPosition, this.zPosition); + return coordsCache; + } + + public long getChunkCoordLong() { + return ChunkCoordIntPair.chunkXZ2Int(this.xPosition, this.zPosition); } /**+ diff --git a/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java b/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java index 2cd601c7..f3504c18 100755 --- a/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java +++ b/src/game/java/net/minecraft/world/chunk/ChunkPrimer.java @@ -10,7 +10,7 @@ import net.minecraft.init.Blocks; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/EmptyChunk.java b/src/game/java/net/minecraft/world/chunk/EmptyChunk.java index 38240a1c..27789caa 100755 --- a/src/game/java/net/minecraft/world/chunk/EmptyChunk.java +++ b/src/game/java/net/minecraft/world/chunk/EmptyChunk.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/IChunkProvider.java b/src/game/java/net/minecraft/world/chunk/IChunkProvider.java index 12658c9d..c8996632 100755 --- a/src/game/java/net/minecraft/world/chunk/IChunkProvider.java +++ b/src/game/java/net/minecraft/world/chunk/IChunkProvider.java @@ -14,7 +14,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/NibbleArray.java b/src/game/java/net/minecraft/world/chunk/NibbleArray.java index ad7d4bf2..14f6436a 100755 --- a/src/game/java/net/minecraft/world/chunk/NibbleArray.java +++ b/src/game/java/net/minecraft/world/chunk/NibbleArray.java @@ -6,7 +6,7 @@ package net.minecraft.world.chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -55,18 +55,14 @@ public class NibbleArray { } public int getFromIndex(int index) { - int i = this.getNibbleIndex(index); - return this.isLowerNibble(index) ? this.data[i] & 15 : this.data[i] >> 4 & 15; + int shift = (index & 1) << 2; + return data[index >> 1] >> shift & 15; } public void setIndex(int index, int value) { - int i = this.getNibbleIndex(index); - if (this.isLowerNibble(index)) { - this.data[i] = (byte) (this.data[i] & 240 | value & 15); - } else { - this.data[i] = (byte) (this.data[i] & 15 | (value & 15) << 4); - } - + int i = index >> 1; + int shift = (index & 1) << 2; + data[i] = (byte) (data[i] & ~(15 << shift) | (value & 15) << shift); } private boolean isLowerNibble(int index) { diff --git a/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java b/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java index da9e46d1..76ddd377 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/AnvilChunkLoader.java @@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java b/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java index c0425e64..69e333d4 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/ChunkLoader.java @@ -13,7 +13,7 @@ import net.minecraft.world.chunk.NibbleArray; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java b/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java index 23a407af..591dece4 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java +++ b/src/game/java/net/minecraft/world/chunk/storage/ExtendedBlockStorage.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.NibbleArray; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java b/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java index 91d4512e..094c05a0 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/IChunkLoader.java @@ -10,7 +10,7 @@ import net.minecraft.world.chunk.Chunk; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java b/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java index f2b8d13f..f6f7f427 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java +++ b/src/game/java/net/minecraft/world/chunk/storage/NibbleArrayReader.java @@ -6,7 +6,7 @@ package net.minecraft.world.chunk.storage; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java b/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java index 6fcfcbe4..92223e59 100755 --- a/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java +++ b/src/game/java/net/minecraft/world/chunk/storage/RegionFile.java @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.export.RandomAccessMemoryFile; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/demo/DemoWorldManager.java b/src/game/java/net/minecraft/world/demo/DemoWorldManager.java index d6e0825f..bbd60234 100755 --- a/src/game/java/net/minecraft/world/demo/DemoWorldManager.java +++ b/src/game/java/net/minecraft/world/demo/DemoWorldManager.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/demo/DemoWorldServer.java b/src/game/java/net/minecraft/world/demo/DemoWorldServer.java index 8f0d7bc8..55a22a3b 100755 --- a/src/game/java/net/minecraft/world/demo/DemoWorldServer.java +++ b/src/game/java/net/minecraft/world/demo/DemoWorldServer.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java b/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java index 941fed1f..9c5da316 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderDebug.java @@ -21,7 +21,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java b/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java index a6f4cebd..bbd6ed6b 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderEnd.java @@ -22,7 +22,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java b/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java index 78ae5159..4198ee95 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderFlat.java @@ -30,7 +30,7 @@ import net.minecraft.world.gen.structure.StructureOceanMonument; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java b/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java index e3efc969..350fabb1 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderGenerate.java @@ -31,7 +31,7 @@ import net.minecraft.world.gen.structure.StructureOceanMonument; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java b/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java index 5fb958af..64309ec5 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderHell.java @@ -31,7 +31,7 @@ import net.minecraft.world.gen.structure.MapGenNetherBridge; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java b/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java index b0f95101..81c74345 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderServer.java @@ -1,19 +1,19 @@ package net.minecraft.world.gen; +import com.carrotsearch.hppc.LongHashSet; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; +import com.carrotsearch.hppc.LongSet; import com.google.common.collect.Lists; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer; import net.minecraft.entity.EnumCreatureType; import net.minecraft.util.BlockPos; import net.minecraft.util.IProgressUpdate; -import net.minecraft.util.LongHashMap; import net.minecraft.util.ReportedException; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; @@ -33,7 +33,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -49,7 +49,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; */ public class ChunkProviderServer implements IChunkProvider { private static final Logger logger = LogManager.getLogger(); - private Set droppedChunksSet = Collections.newSetFromMap(new ConcurrentHashMap()); + private LongSet droppedChunksSet = new LongHashSet(); private Chunk dummyChunk; private IChunkProvider serverChunkGenerator; private IChunkLoader chunkLoader; @@ -61,13 +61,13 @@ public class ChunkProviderServer implements IChunkProvider { /**+ * map of chunk Id's to Chunk instances */ - private LongHashMap id2ChunkMap = new LongHashMap(); + private LongObjectMap id2ChunkMap = new LongObjectHashMap<>(); private List loadedChunks = Lists.newLinkedList(); private WorldServer worldObj; public ChunkProviderServer(WorldServer parWorldServer, IChunkLoader parIChunkLoader, IChunkProvider parIChunkProvider) { - this.dummyChunk = new EmptyChunk(parWorldServer, 0, 0); + this.dummyChunk = new EmptyChunk(parWorldServer, Integer.MIN_VALUE, Integer.MIN_VALUE); this.worldObj = parWorldServer; this.chunkLoader = parIChunkLoader; this.serverChunkGenerator = parIChunkProvider; @@ -77,7 +77,7 @@ public class ChunkProviderServer implements IChunkProvider { * Checks to see if a chunk exists at x, z */ public boolean chunkExists(int i, int j) { - return this.id2ChunkMap.containsItem(ChunkCoordIntPair.chunkXZ2Int(i, j)); + return this.id2ChunkMap.containsKey(ChunkCoordIntPair.chunkXZ2Int(i, j)); } public List func_152380_a() { @@ -87,10 +87,10 @@ public class ChunkProviderServer implements IChunkProvider { public void dropChunk(int parInt1, int parInt2) { if (this.worldObj.provider.canRespawnHere()) { if (!this.worldObj.isSpawnChunk(parInt1, parInt2)) { - this.droppedChunksSet.add(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2))); + this.droppedChunksSet.add(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2)); } } else { - this.droppedChunksSet.add(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2))); + this.droppedChunksSet.add(ChunkCoordIntPair.chunkXZ2Int(parInt1, parInt2)); } } @@ -110,8 +110,8 @@ public class ChunkProviderServer implements IChunkProvider { */ public Chunk loadChunk(int i, int j) { long k = ChunkCoordIntPair.chunkXZ2Int(i, j); - this.droppedChunksSet.remove(Long.valueOf(k)); - Chunk chunk = (Chunk) this.id2ChunkMap.getValueByKey(k); + this.droppedChunksSet.removeAll(k); + Chunk chunk = this.id2ChunkMap.get(k); if (chunk == null) { chunk = this.loadChunkFromFile(i, j); if (chunk == null) { @@ -136,7 +136,7 @@ public class ChunkProviderServer implements IChunkProvider { ++EaglerMinecraftServer.counterChunkRead; } - this.id2ChunkMap.add(k, chunk); + this.id2ChunkMap.put(k, chunk); this.loadedChunks.add(chunk); chunk.onChunkLoad(); chunk.populateChunk(this, this, i, j); @@ -151,7 +151,7 @@ public class ChunkProviderServer implements IChunkProvider { * chunk from the map seed and chunk seed */ public Chunk provideChunk(int i, int j) { - Chunk chunk = (Chunk) this.id2ChunkMap.getValueByKey(ChunkCoordIntPair.chunkXZ2Int(i, j)); + Chunk chunk = this.id2ChunkMap.get(ChunkCoordIntPair.chunkXZ2Int(i, j)); return chunk == null ? (!this.worldObj.isFindingSpawnPoint() && !this.chunkLoadOverride ? this.dummyChunk : this.loadChunk(i, j)) : chunk; } @@ -276,17 +276,17 @@ public class ChunkProviderServer implements IChunkProvider { if (!this.worldObj.disableLevelSaving) { for (int i = 0; i < 100; ++i) { if (!this.droppedChunksSet.isEmpty()) { - Long olong = (Long) this.droppedChunksSet.iterator().next(); - Chunk chunk = (Chunk) this.id2ChunkMap.getValueByKey(olong.longValue()); + long olong = this.droppedChunksSet.iterator().next().value; + Chunk chunk = this.id2ChunkMap.get(olong); if (chunk != null) { chunk.onChunkUnload(); this.saveChunkData(chunk); this.saveChunkExtraData(chunk); - this.id2ChunkMap.remove(olong.longValue()); + this.id2ChunkMap.remove(olong); this.loadedChunks.remove(chunk); } - this.droppedChunksSet.remove(olong); + this.droppedChunksSet.removeAll(olong); } } @@ -309,7 +309,7 @@ public class ChunkProviderServer implements IChunkProvider { * Converts the instance data to a readable string. */ public String makeString() { - return "ServerChunkCache: " + this.id2ChunkMap.getNumHashElements() + " Drop: " + this.droppedChunksSet.size(); + return "ServerChunkCache: " + this.id2ChunkMap.size() + " Drop: " + this.droppedChunksSet.size(); } public List getPossibleCreatures(EnumCreatureType enumcreaturetype, @@ -322,7 +322,7 @@ public class ChunkProviderServer implements IChunkProvider { } public int getLoadedChunkCount() { - return this.id2ChunkMap.getNumHashElements(); + return this.id2ChunkMap.size(); } public void recreateStructures(Chunk var1, int var2, int var3) { diff --git a/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java b/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java index 54405d70..04c5b5ff 100755 --- a/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java +++ b/src/game/java/net/minecraft/world/gen/ChunkProviderSettings.java @@ -13,7 +13,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java b/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java index 70b21653..bc7d1e46 100755 --- a/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java +++ b/src/game/java/net/minecraft/world/gen/FlatGeneratorInfo.java @@ -21,7 +21,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java b/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java index 1c4480ab..5a2625d5 100755 --- a/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java +++ b/src/game/java/net/minecraft/world/gen/FlatLayerInfo.java @@ -10,7 +10,7 @@ import net.minecraft.util.ResourceLocation; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java b/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java index 666d8e75..04bd069b 100755 --- a/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java +++ b/src/game/java/net/minecraft/world/gen/GeneratorBushFeature.java @@ -12,7 +12,7 @@ import net.minecraft.world.gen.feature.WorldGenerator; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/MapGenBase.java b/src/game/java/net/minecraft/world/gen/MapGenBase.java index e679535e..54eecf13 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenBase.java +++ b/src/game/java/net/minecraft/world/gen/MapGenBase.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.IChunkProvider; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/MapGenCaves.java b/src/game/java/net/minecraft/world/gen/MapGenCaves.java index ca518b16..ddd839dc 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenCaves.java +++ b/src/game/java/net/minecraft/world/gen/MapGenCaves.java @@ -17,7 +17,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java b/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java index b6f46f9b..8830812f 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java +++ b/src/game/java/net/minecraft/world/gen/MapGenCavesHell.java @@ -13,7 +13,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/MapGenRavine.java b/src/game/java/net/minecraft/world/gen/MapGenRavine.java index 734a3e0d..da6ce462 100755 --- a/src/game/java/net/minecraft/world/gen/MapGenRavine.java +++ b/src/game/java/net/minecraft/world/gen/MapGenRavine.java @@ -14,7 +14,7 @@ import net.minecraft.world.chunk.ChunkPrimer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/NoiseGenerator.java b/src/game/java/net/minecraft/world/gen/NoiseGenerator.java index d438bf8d..4be4ad83 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGenerator.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGenerator.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java index 23f2d407..ed2ad167 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorImproved.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java index 7bdc242b..1917fce5 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorOctaves.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java index 61e52a4a..add8cf84 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorPerlin.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java b/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java index 06558833..1095db27 100755 --- a/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java +++ b/src/game/java/net/minecraft/world/gen/NoiseGeneratorSimplex.java @@ -8,7 +8,7 @@ import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java index dec881fb..c8ea53d6 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenAbstractTree.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java index d273980d..4140c864 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigMushroom.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java index 45ab3c4b..817027c1 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenBigTree.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java index 7ba4d736..067aa8f8 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenBlockBlob.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java index c4ef67af..27330ae1 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenCactus.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java index c513608b..58bb36b8 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenCanopyTree.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java index 1309eaac..76c95e2b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenClay.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java index 3d89e615..102de7f1 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDeadBush.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java index 062dd653..c489dd6c 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDesertWells.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java index 0d38a512..ead297e9 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDoublePlant.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java index 79dc5951..68e488ce 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenDungeons.java @@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java index 64a3e328..fa9263ed 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenFire.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java index 45512f27..a4991b2b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenFlowers.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java index 0723d7d2..697a6aad 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenForest.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java index 7e049887..74b1bdc0 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone1.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java index 017e5d79..e63676fe 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenGlowStone2.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java index 8b7041cb..e7c8d2e3 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenHellLava.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java index 092e7684..2f8b54af 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenHugeTrees.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java index deb6fce3..b180e6bd 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenIcePath.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java index e1695bf5..c9c0537c 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenIceSpike.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java index 783b82fd..f8fe0123 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenLakes.java @@ -15,7 +15,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java index 499987a3..7accf062 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenLiquids.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java index abe8f9c5..e4ea968e 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaJungle.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java index 596d3ec1..d6fd7903 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMegaPineTree.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java index 09ba60b7..4585db25 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMelon.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java index 7947f97c..46e7a866 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenMinable.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java index d54191a8..6be28ad4 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenPumpkin.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java index 78d9c43c..9e471432 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenReed.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java index 3b473d8c..025498fd 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSand.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java index 492087bf..6420fa26 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSavannaTree.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java index a735b8fd..425d2e7d 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenShrub.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java index 77aeacde..bbd8b06e 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSpikes.java @@ -13,7 +13,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java index c1d56e1c..6197efbe 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenSwamp.java @@ -19,7 +19,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java index 64d37a14..e411affe 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga1.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java index c8aaabe0..32832c0b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTaiga2.java @@ -18,7 +18,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java index 8b382c75..285938fb 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTallGrass.java @@ -15,7 +15,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java index 859d696d..2c45a979 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenTrees.java @@ -22,7 +22,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java index 5271b372..27fc982b 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenVines.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java index d7d3a3df..fb9728ca 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenWaterlily.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java b/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java index e208a144..b97dfde2 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGenerator.java @@ -11,7 +11,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java b/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java index 4cda84b3..8366b633 100755 --- a/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java +++ b/src/game/java/net/minecraft/world/gen/feature/WorldGeneratorBonusChest.java @@ -17,7 +17,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayer.java b/src/game/java/net/minecraft/world/gen/layer/GenLayer.java index d8a92a5f..17581f12 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayer.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayer.java @@ -1,6 +1,8 @@ package net.minecraft.world.gen.layer; import java.util.concurrent.Callable; + +import net.lax1dude.eaglercraft.v1_8.sp.server.GenLayerEaglerRivers; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.util.ReportedException; @@ -14,7 +16,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -29,7 +31,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * */ public abstract class GenLayer { - private long worldGenSeed; + protected long worldGenSeed; protected GenLayer parent; private long chunkSeed; protected long baseSeed; @@ -76,8 +78,9 @@ public abstract class GenLayer { GenLayer genlayerhills = new GenLayerHills(1000L, genlayerbiomeedge, genlayer1); GenLayer genlayer3 = GenLayerZoom.magnify(1000L, genlayerriverinit, 2); genlayer3 = GenLayerZoom.magnify(1000L, genlayer3, j); - GenLayerRiver genlayerriver = new GenLayerRiver(1L, genlayer3); - GenLayerSmooth genlayersmooth = new GenLayerSmooth(1000L, genlayerriver); + GenLayer genlayerriver = new GenLayerRiver(1L, genlayer3); + genlayerriver = new GenLayerSmooth(1000L, genlayerriver); + genlayerriver = new GenLayerEaglerRivers(69L, genlayerriver); genlayerhills = new GenLayerRareBiome(1001L, genlayerhills); for (int k = 0; k < i; ++k) { @@ -92,7 +95,7 @@ public abstract class GenLayer { } GenLayerSmooth genlayersmooth1 = new GenLayerSmooth(1000L, genlayerhills); - GenLayerRiverMix genlayerrivermix = new GenLayerRiverMix(100L, genlayersmooth1, genlayersmooth); + GenLayerRiverMix genlayerrivermix = new GenLayerRiverMix(100L, genlayersmooth1, genlayerriver); GenLayerVoronoiZoom genlayervoronoizoom = new GenLayerVoronoiZoom(10L, genlayerrivermix); genlayerrivermix.initWorldGenSeed(seed); genlayervoronoizoom.initWorldGenSeed(seed); diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java index a2f8ae22..95266e84 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddIsland.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java index e5b5e6fa..26086de0 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddMushroomIsland.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java index 60db8b48..eb8d6828 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerAddSnow.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java index bfa8bc50..29957780 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiome.java @@ -10,7 +10,7 @@ import net.minecraft.world.gen.ChunkProviderSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java index 24f1701b..d357b3df 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerBiomeEdge.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java index dabf0af3..ca196445 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerDeepOcean.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java index 928d51e2..7cd165e0 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerEdge.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java index 2c52d911..10760ce8 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerFuzzyZoom.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java index eece564a..aa8a4234 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerHills.java @@ -10,7 +10,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java index 8477c75b..3e177e0c 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerIsland.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java index 1bf70291..f28d030d 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRareBiome.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java index 2870d6b8..2ccec44d 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRemoveTooMuchOcean.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java index 2e262c41..a83524e7 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiver.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java index a7b466d8..81ef52b5 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverInit.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java index 5801f529..5cf4381a 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerRiverMix.java @@ -8,7 +8,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java index a3363cc6..b4c9768e 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerShore.java @@ -10,7 +10,7 @@ import net.minecraft.world.biome.BiomeGenMesa; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java index afbd8b93..b538547c 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerSmooth.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java index e52bc819..95261989 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerVoronoiZoom.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java b/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java index bd7538e8..37ed52c1 100755 --- a/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java +++ b/src/game/java/net/minecraft/world/gen/layer/GenLayerZoom.java @@ -6,7 +6,7 @@ package net.minecraft.world.gen.layer; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/layer/IntCache.java b/src/game/java/net/minecraft/world/gen/layer/IntCache.java index e17ed582..4d586011 100755 --- a/src/game/java/net/minecraft/world/gen/layer/IntCache.java +++ b/src/game/java/net/minecraft/world/gen/layer/IntCache.java @@ -9,7 +9,7 @@ import java.util.List; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java b/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java index 16be0f68..0cbb9a9f 100755 --- a/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/ComponentScatteredFeaturePieces.java @@ -28,7 +28,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java b/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java index b7592307..d6efd264 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenMineshaft.java @@ -10,7 +10,7 @@ import net.minecraft.util.MathHelper; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java b/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java index 35397246..e0d308f5 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenNetherBridge.java @@ -16,7 +16,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java b/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java index 059991ae..fb33e100 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenScatteredFeature.java @@ -18,7 +18,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java index a2eb064b..b03d13f9 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStronghold.java @@ -18,7 +18,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java index 0a61ee7d..3881f097 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStructure.java @@ -1,10 +1,11 @@ package net.minecraft.world.gen.structure; -import com.google.common.collect.Maps; +import com.carrotsearch.hppc.LongObjectHashMap; +import com.carrotsearch.hppc.LongObjectMap; +import com.carrotsearch.hppc.cursors.ObjectCursor; import java.util.Iterator; import java.util.List; -import java.util.Map; import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom; import net.lax1dude.eaglercraft.v1_8.HString; @@ -26,7 +27,7 @@ import net.minecraft.world.gen.MapGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -42,7 +43,13 @@ import net.minecraft.world.gen.MapGenBase; */ public abstract class MapGenStructure extends MapGenBase { private MapGenStructureData structureData; - protected Map structureMap = Maps.newHashMap(); + /**+ + * Used to store a list of all structures that have been + * recursively generated. Used so that during recursive + * generation, the structure generator can avoid generating + * structures that intersect ones that have already been placed. + */ + protected LongObjectMap structureMap = new LongObjectHashMap<>(); public abstract String getStructureName(); @@ -60,13 +67,13 @@ public abstract class MapGenStructure extends MapGenBase { protected final void recursiveGenerate(World world, final int i, final int j, int var4, int var5, ChunkPrimer var6) { this.func_143027_a(world); - if (!this.structureMap.containsKey(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(i, j)))) { + if (!this.structureMap.containsKey(ChunkCoordIntPair.chunkXZ2Int(i, j))) { this.rand.nextInt(); try { if (this.canSpawnStructureAtCoords(i, j)) { StructureStart structurestart = this.getStructureStart(i, j); - this.structureMap.put(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(i, j)), structurestart); + this.structureMap.put(ChunkCoordIntPair.chunkXZ2Int(i, j), structurestart); this.func_143026_a(i, j, structurestart); } @@ -102,7 +109,8 @@ public abstract class MapGenStructure extends MapGenBase { int j = (chunkCoord.chunkZPos << 4) + 8; boolean flag = false; - for (StructureStart structurestart : this.structureMap.values()) { + for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure() && structurestart.func_175788_a(chunkCoord) && structurestart.getBoundingBox().intersectsWith(i, j, i + 15, j + 15)) { structurestart.generateStructure(worldIn, randomIn, new StructureBoundingBox(i, j, i + 15, j + 15)); @@ -121,7 +129,8 @@ public abstract class MapGenStructure extends MapGenBase { } protected StructureStart func_175797_c(BlockPos pos) { - label24: for (StructureStart structurestart : this.structureMap.values()) { + label24: for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure() && structurestart.getBoundingBox().isVecInside(pos)) { Iterator iterator = structurestart.getComponents().iterator(); @@ -146,7 +155,8 @@ public abstract class MapGenStructure extends MapGenBase { public boolean func_175796_a(World worldIn, BlockPos pos) { this.func_143027_a(worldIn); - for (StructureStart structurestart : this.structureMap.values()) { + for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure() && structurestart.getBoundingBox().isVecInside(pos)) { return true; } @@ -168,7 +178,8 @@ public abstract class MapGenStructure extends MapGenBase { double d0 = Double.MAX_VALUE; BlockPos blockpos = null; - for (StructureStart structurestart : this.structureMap.values()) { + for (ObjectCursor structurestart_ : this.structureMap.values()) { + StructureStart structurestart = structurestart_.value; if (structurestart.isSizeableStructure()) { StructureComponent structurecomponent = (StructureComponent) structurestart.getComponents().get(0); BlockPos blockpos1 = structurecomponent.getBoundingBoxCenter(); @@ -232,8 +243,7 @@ public abstract class MapGenStructure extends MapGenBase { StructureStart structurestart = MapGenStructureIO.getStructureStart(nbttagcompound1, worldIn); if (structurestart != null) { - this.structureMap.put(Long.valueOf(ChunkCoordIntPair.chunkXZ2Int(i, j)), - structurestart); + this.structureMap.put(ChunkCoordIntPair.chunkXZ2Int(i, j), structurestart); } } } diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java index 07e3b0c0..7a9205ff 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureData.java @@ -9,7 +9,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java index 12659c5f..5942ec41 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenStructureIO.java @@ -15,7 +15,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java b/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java index a9b07f01..fe394887 100755 --- a/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java +++ b/src/game/java/net/minecraft/world/gen/structure/MapGenVillage.java @@ -16,7 +16,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java b/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java index eb14fc20..77bb79a3 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureBoundingBox.java @@ -12,7 +12,7 @@ import net.minecraft.util.Vec3i; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java b/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java index 325d5030..9cf6f40b 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureComponent.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java index 24464acf..0dbf62b7 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftPieces.java @@ -25,7 +25,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java index 13fcb8a0..c8392664 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureMineshaftStart.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java index 28767af6..8399ffd3 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureNetherBridgePieces.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java index 9f93fb34..cc2eb8d8 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonument.java @@ -24,7 +24,7 @@ import net.minecraft.world.biome.BiomeGenBase; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java index 87807c63..e4e4fbd3 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureOceanMonumentPieces.java @@ -24,7 +24,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureStart.java b/src/game/java/net/minecraft/world/gen/structure/StructureStart.java index fedaef13..0ff00970 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureStart.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureStart.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java index 5cb75ce8..03acba33 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureStrongholdPieces.java @@ -23,7 +23,7 @@ import net.minecraft.world.World; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java b/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java index cdce5674..327c8c4b 100755 --- a/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java +++ b/src/game/java/net/minecraft/world/gen/structure/StructureVillagePieces.java @@ -32,7 +32,7 @@ import net.minecraft.world.biome.WorldChunkManager; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java b/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java index 9b595c9c..55bf429d 100755 --- a/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java +++ b/src/game/java/net/minecraft/world/pathfinder/NodeProcessor.java @@ -1,8 +1,10 @@ package net.minecraft.world.pathfinder; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; + import net.minecraft.entity.Entity; import net.minecraft.pathfinding.PathPoint; -import net.minecraft.util.IntHashMap; import net.minecraft.util.MathHelper; import net.minecraft.world.IBlockAccess; @@ -12,7 +14,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 @@ -28,14 +30,14 @@ import net.minecraft.world.IBlockAccess; */ public abstract class NodeProcessor { protected IBlockAccess blockaccess; - protected IntHashMap pointMap = new IntHashMap(); + protected IntObjectMap pointMap = new IntObjectHashMap<>(); protected int entitySizeX; protected int entitySizeY; protected int entitySizeZ; public void initProcessor(IBlockAccess iblockaccessIn, Entity entityIn) { this.blockaccess = iblockaccessIn; - this.pointMap.clearMap(); + this.pointMap.clear(); this.entitySizeX = MathHelper.floor_float(entityIn.width + 1.0F); this.entitySizeY = MathHelper.floor_float(entityIn.height + 1.0F); this.entitySizeZ = MathHelper.floor_float(entityIn.width + 1.0F); @@ -57,10 +59,10 @@ public abstract class NodeProcessor { */ protected PathPoint openPoint(int x, int y, int z) { int i = PathPoint.makeHash(x, y, z); - PathPoint pathpoint = (PathPoint) this.pointMap.lookup(i); + PathPoint pathpoint = this.pointMap.get(i); if (pathpoint == null) { pathpoint = new PathPoint(x, y, z); - this.pointMap.addKey(i, pathpoint); + this.pointMap.put(i, pathpoint); } return pathpoint; diff --git a/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java b/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java index 913f9c77..03811bdf 100755 --- a/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java +++ b/src/game/java/net/minecraft/world/pathfinder/SwimNodeProcessor.java @@ -15,7 +15,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java b/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java index d8844366..d546e9e2 100755 --- a/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java +++ b/src/game/java/net/minecraft/world/pathfinder/WalkNodeProcessor.java @@ -20,7 +20,7 @@ import net.minecraft.world.IBlockAccess; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java b/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java index 24e50ae1..9359d1fd 100755 --- a/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java +++ b/src/game/java/net/minecraft/world/storage/DerivedWorldInfo.java @@ -13,7 +13,7 @@ import net.minecraft.world.WorldType; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/IPlayerFileData.java b/src/game/java/net/minecraft/world/storage/IPlayerFileData.java index 2524c797..fc5addff 100755 --- a/src/game/java/net/minecraft/world/storage/IPlayerFileData.java +++ b/src/game/java/net/minecraft/world/storage/IPlayerFileData.java @@ -9,7 +9,7 @@ import net.minecraft.nbt.NBTTagCompound; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/ISaveFormat.java b/src/game/java/net/minecraft/world/storage/ISaveFormat.java index b0fff086..73669896 100755 --- a/src/game/java/net/minecraft/world/storage/ISaveFormat.java +++ b/src/game/java/net/minecraft/world/storage/ISaveFormat.java @@ -9,7 +9,7 @@ import net.minecraft.util.IProgressUpdate; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/ISaveHandler.java b/src/game/java/net/minecraft/world/storage/ISaveHandler.java index 75d5711a..de7f8f62 100755 --- a/src/game/java/net/minecraft/world/storage/ISaveHandler.java +++ b/src/game/java/net/minecraft/world/storage/ISaveHandler.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.storage.IChunkLoader; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/MapData.java b/src/game/java/net/minecraft/world/storage/MapData.java index 8d82a623..1816043f 100755 --- a/src/game/java/net/minecraft/world/storage/MapData.java +++ b/src/game/java/net/minecraft/world/storage/MapData.java @@ -25,7 +25,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/MapStorage.java b/src/game/java/net/minecraft/world/storage/MapStorage.java index 0e9cf019..33c4597f 100755 --- a/src/game/java/net/minecraft/world/storage/MapStorage.java +++ b/src/game/java/net/minecraft/world/storage/MapStorage.java @@ -27,7 +27,7 @@ import net.minecraft.world.gen.structure.MapGenStructureData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java b/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java index 78e8b55e..57c7a794 100755 --- a/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java +++ b/src/game/java/net/minecraft/world/storage/SaveDataMemoryStorage.java @@ -8,7 +8,7 @@ import net.minecraft.world.WorldSavedData; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java b/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java index ace4cbbc..9bbb152a 100755 --- a/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java +++ b/src/game/java/net/minecraft/world/storage/SaveFormatComparator.java @@ -9,7 +9,7 @@ import net.minecraft.world.WorldSettings; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/SaveFormatOld.java b/src/game/java/net/minecraft/world/storage/SaveFormatOld.java index 24739d32..b01f4cb3 100755 --- a/src/game/java/net/minecraft/world/storage/SaveFormatOld.java +++ b/src/game/java/net/minecraft/world/storage/SaveFormatOld.java @@ -22,7 +22,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/SaveHandler.java b/src/game/java/net/minecraft/world/storage/SaveHandler.java index 84bbcc2f..8db99dc3 100755 --- a/src/game/java/net/minecraft/world/storage/SaveHandler.java +++ b/src/game/java/net/minecraft/world/storage/SaveHandler.java @@ -21,7 +21,7 @@ import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java b/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java index 3a5e2da4..2d2a2c85 100755 --- a/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java +++ b/src/game/java/net/minecraft/world/storage/SaveHandlerMP.java @@ -11,7 +11,7 @@ import net.minecraft.world.chunk.storage.IChunkLoader; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/game/java/net/minecraft/world/storage/WorldInfo.java b/src/game/java/net/minecraft/world/storage/WorldInfo.java index 69e5ad65..2fd64fcd 100755 --- a/src/game/java/net/minecraft/world/storage/WorldInfo.java +++ b/src/game/java/net/minecraft/world/storage/WorldInfo.java @@ -17,7 +17,7 @@ import net.lax1dude.eaglercraft.v1_8.HString; * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * - * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. + * EaglercraftX 1.8 patch files (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 diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java index 7fbabe91..cf074821 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java @@ -18,9 +18,12 @@ import java.util.Date; import java.util.List; import java.util.Random; import java.util.function.Consumer; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; import javax.imageio.ImageIO; @@ -556,6 +559,16 @@ public class PlatformRuntime { return new DeflaterOutputStream(os); } + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Deflater df = new Deflater(); + df.setInput(input, inputOff, inputLen); + df.finish(); + int i = df.deflate(output, outputOff, outputLen); + df.end(); + return i; + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return new GZIPOutputStream(os); } @@ -564,6 +577,21 @@ public class PlatformRuntime { return new InflaterInputStream(is); } + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Inflater df = new Inflater(); + int i; + try { + df.setInput(input, inputOff, inputLen); + i = df.inflate(output, outputOff, outputLen); + }catch(DataFormatException ex) { + throw new IOException("Failed to inflate!", ex); + }finally { + df.end(); + } + return i; + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return new GZIPInputStream(is); } diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java index 4d2a0877..ff1cf320 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLByteBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * 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 @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLByteBuffer implements ByteBuffer { +public class EaglerLWJGLByteBuffer extends ByteBuffer { final long address; final boolean original; diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java index 55fcf8a3..f839dbfb 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLFloatBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * 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 @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLFloatBuffer implements FloatBuffer { +public class EaglerLWJGLFloatBuffer extends FloatBuffer { final long address; final boolean original; diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java index c52534fa..392f7a17 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLIntBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * 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 @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLIntBuffer implements IntBuffer { +public class EaglerLWJGLIntBuffer extends IntBuffer { final long address; final boolean original; diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java index 094153da..c77a0ce5 100755 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerLWJGLShortBuffer.java @@ -4,7 +4,7 @@ import net.lax1dude.unsafememcpy.UnsafeMemcpy; import net.lax1dude.unsafememcpy.UnsafeUtils; /** - * 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 @@ -18,7 +18,7 @@ import net.lax1dude.unsafememcpy.UnsafeUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerLWJGLShortBuffer implements ShortBuffer { +public class EaglerLWJGLShortBuffer extends ShortBuffer { final long address; final boolean original; diff --git a/src/main/java/com/carrotsearch/hppc/AbstractByteCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractByteCollection.java new file mode 100755 index 00000000..ed184354 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractByteCollection.java @@ -0,0 +1,51 @@ +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/src/main/java/com/carrotsearch/hppc/AbstractCharCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractCharCollection.java new file mode 100755 index 00000000..5ecdbb55 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractCharCollection.java @@ -0,0 +1,51 @@ +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/src/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java new file mode 100755 index 00000000..2bb296ff --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractDoubleCollection.java @@ -0,0 +1,51 @@ +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/src/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java new file mode 100755 index 00000000..089086f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractFloatCollection.java @@ -0,0 +1,51 @@ +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/src/main/java/com/carrotsearch/hppc/AbstractIntCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractIntCollection.java new file mode 100755 index 00000000..e9ae748d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractIntCollection.java @@ -0,0 +1,50 @@ +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/src/main/java/com/carrotsearch/hppc/AbstractIterator.java b/src/main/java/com/carrotsearch/hppc/AbstractIterator.java new file mode 100755 index 00000000..78951402 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractIterator.java @@ -0,0 +1,71 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/AbstractLongCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractLongCollection.java new file mode 100755 index 00000000..914bc36e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractLongCollection.java @@ -0,0 +1,51 @@ +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/src/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java new file mode 100755 index 00000000..1a841f62 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractObjectCollection.java @@ -0,0 +1,66 @@ +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/src/main/java/com/carrotsearch/hppc/AbstractShortCollection.java b/src/main/java/com/carrotsearch/hppc/AbstractShortCollection.java new file mode 100755 index 00000000..e78dbe11 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/AbstractShortCollection.java @@ -0,0 +1,51 @@ +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/src/main/java/com/carrotsearch/hppc/Accountable.java b/src/main/java/com/carrotsearch/hppc/Accountable.java new file mode 100755 index 00000000..44aefc9b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Accountable.java @@ -0,0 +1,31 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java b/src/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java new file mode 100755 index 00000000..b541c56f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ArraySizingStrategy.java @@ -0,0 +1,27 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/BitMixer.java b/src/main/java/com/carrotsearch/hppc/BitMixer.java new file mode 100755 index 00000000..136c12f9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitMixer.java @@ -0,0 +1,120 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/BitSet.java b/src/main/java/com/carrotsearch/hppc/BitSet.java new file mode 100755 index 00000000..7f8a94bc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitSet.java @@ -0,0 +1,952 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/BitSetIterator.java b/src/main/java/com/carrotsearch/hppc/BitSetIterator.java new file mode 100755 index 00000000..35aa3e06 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitSetIterator.java @@ -0,0 +1,356 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/BitUtil.java b/src/main/java/com/carrotsearch/hppc/BitUtil.java new file mode 100755 index 00000000..61a628d5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BitUtil.java @@ -0,0 +1,98 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java b/src/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java new file mode 100755 index 00000000..14c5a9ab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BoundedProportionalArraySizingStrategy.java @@ -0,0 +1,115 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/BufferAllocationException.java b/src/main/java/com/carrotsearch/hppc/BufferAllocationException.java new file mode 100755 index 00000000..f09ef3c8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/BufferAllocationException.java @@ -0,0 +1,41 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/ByteArrayDeque.java b/src/main/java/com/carrotsearch/hppc/ByteArrayDeque.java new file mode 100755 index 00000000..b9c809c1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteArrayDeque.java @@ -0,0 +1,776 @@ +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/src/main/java/com/carrotsearch/hppc/ByteArrayList.java b/src/main/java/com/carrotsearch/hppc/ByteArrayList.java new file mode 100755 index 00000000..836c6b9d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteArrayList.java @@ -0,0 +1,579 @@ +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/src/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java new file mode 100755 index 00000000..0a39142a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/ByteCollection.java b/src/main/java/com/carrotsearch/hppc/ByteCollection.java new file mode 100755 index 00000000..2e89418e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/ByteContainer.java b/src/main/java/com/carrotsearch/hppc/ByteContainer.java new file mode 100755 index 00000000..19edc86b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteContainer.java @@ -0,0 +1,76 @@ +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/src/main/java/com/carrotsearch/hppc/ByteDeque.java b/src/main/java/com/carrotsearch/hppc/ByteDeque.java new file mode 100755 index 00000000..3b8dd7fe --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java new file mode 100755 index 00000000..f70fb895 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteIndexedContainer.java @@ -0,0 +1,91 @@ +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/src/main/java/com/carrotsearch/hppc/ByteLookupContainer.java b/src/main/java/com/carrotsearch/hppc/ByteLookupContainer.java new file mode 100755 index 00000000..ac41bc0b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/ByteStack.java b/src/main/java/com/carrotsearch/hppc/ByteStack.java new file mode 100755 index 00000000..0cf32432 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ByteStack.java @@ -0,0 +1,137 @@ +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/src/main/java/com/carrotsearch/hppc/CharArrayDeque.java b/src/main/java/com/carrotsearch/hppc/CharArrayDeque.java new file mode 100755 index 00000000..e8aeb6a4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharArrayDeque.java @@ -0,0 +1,776 @@ +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/src/main/java/com/carrotsearch/hppc/CharArrayList.java b/src/main/java/com/carrotsearch/hppc/CharArrayList.java new file mode 100755 index 00000000..90837d31 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharArrayList.java @@ -0,0 +1,579 @@ +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/src/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java new file mode 100755 index 00000000..7bd17436 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java new file mode 100755 index 00000000..a69b4beb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharByteAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharByteHashMap.java b/src/main/java/com/carrotsearch/hppc/CharByteHashMap.java new file mode 100755 index 00000000..93dd3c8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharByteHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/CharByteMap.java b/src/main/java/com/carrotsearch/hppc/CharByteMap.java new file mode 100755 index 00000000..dcb4ef54 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharByteMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java new file mode 100755 index 00000000..b7334bbc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCharAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharCharHashMap.java b/src/main/java/com/carrotsearch/hppc/CharCharHashMap.java new file mode 100755 index 00000000..509c1a2c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCharHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/CharCharMap.java b/src/main/java/com/carrotsearch/hppc/CharCharMap.java new file mode 100755 index 00000000..c3690bba --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCharMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/CharCollection.java b/src/main/java/com/carrotsearch/hppc/CharCollection.java new file mode 100755 index 00000000..4cc8517b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/CharContainer.java b/src/main/java/com/carrotsearch/hppc/CharContainer.java new file mode 100755 index 00000000..5977583b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharContainer.java @@ -0,0 +1,76 @@ +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/src/main/java/com/carrotsearch/hppc/CharDeque.java b/src/main/java/com/carrotsearch/hppc/CharDeque.java new file mode 100755 index 00000000..34ff5c92 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java new file mode 100755 index 00000000..2d898f2c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java new file mode 100755 index 00000000..0a68bfaf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDoubleHashMap.java @@ -0,0 +1,1082 @@ +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/src/main/java/com/carrotsearch/hppc/CharDoubleMap.java b/src/main/java/com/carrotsearch/hppc/CharDoubleMap.java new file mode 100755 index 00000000..2ba6e41b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharDoubleMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java new file mode 100755 index 00000000..10069a39 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/CharFloatHashMap.java new file mode 100755 index 00000000..0f4d6d8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharFloatHashMap.java @@ -0,0 +1,1081 @@ +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/src/main/java/com/carrotsearch/hppc/CharFloatMap.java b/src/main/java/com/carrotsearch/hppc/CharFloatMap.java new file mode 100755 index 00000000..4bf7569f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharFloatMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/CharHashSet.java b/src/main/java/com/carrotsearch/hppc/CharHashSet.java new file mode 100755 index 00000000..58ad8f26 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharHashSet.java @@ -0,0 +1,787 @@ +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/src/main/java/com/carrotsearch/hppc/CharIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/CharIndexedContainer.java new file mode 100755 index 00000000..96824521 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIndexedContainer.java @@ -0,0 +1,91 @@ +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/src/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java new file mode 100755 index 00000000..08c5d64a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIntAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharIntHashMap.java b/src/main/java/com/carrotsearch/hppc/CharIntHashMap.java new file mode 100755 index 00000000..aff7e50d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIntHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/CharIntMap.java b/src/main/java/com/carrotsearch/hppc/CharIntMap.java new file mode 100755 index 00000000..8c2f24e0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharIntMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java new file mode 100755 index 00000000..7999c340 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLongAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharLongHashMap.java b/src/main/java/com/carrotsearch/hppc/CharLongHashMap.java new file mode 100755 index 00000000..e1bea344 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLongHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/CharLongMap.java b/src/main/java/com/carrotsearch/hppc/CharLongMap.java new file mode 100755 index 00000000..fcbda2b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLongMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/CharLookupContainer.java b/src/main/java/com/carrotsearch/hppc/CharLookupContainer.java new file mode 100755 index 00000000..3e2fd0a4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java new file mode 100755 index 00000000..806efa68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/CharObjectHashMap.java new file mode 100755 index 00000000..a9d9a0d5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharObjectHashMap.java @@ -0,0 +1,1050 @@ +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/src/main/java/com/carrotsearch/hppc/CharObjectMap.java b/src/main/java/com/carrotsearch/hppc/CharObjectMap.java new file mode 100755 index 00000000..6a1004df --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharObjectMap.java @@ -0,0 +1,181 @@ +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/src/main/java/com/carrotsearch/hppc/CharSet.java b/src/main/java/com/carrotsearch/hppc/CharSet.java new file mode 100755 index 00000000..a9740eac --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharSet.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java new file mode 100755 index 00000000..66f6c444 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharShortAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/CharShortHashMap.java b/src/main/java/com/carrotsearch/hppc/CharShortHashMap.java new file mode 100755 index 00000000..686281c6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharShortHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/CharShortMap.java b/src/main/java/com/carrotsearch/hppc/CharShortMap.java new file mode 100755 index 00000000..e5b0deeb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharShortMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/CharStack.java b/src/main/java/com/carrotsearch/hppc/CharStack.java new file mode 100755 index 00000000..fb7a5947 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/CharStack.java @@ -0,0 +1,137 @@ +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/src/main/java/com/carrotsearch/hppc/Containers.java b/src/main/java/com/carrotsearch/hppc/Containers.java new file mode 100755 index 00000000..edd41b7c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Containers.java @@ -0,0 +1,68 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java b/src/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java new file mode 100755 index 00000000..7561da28 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleArrayDeque.java @@ -0,0 +1,776 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleArrayList.java b/src/main/java/com/carrotsearch/hppc/DoubleArrayList.java new file mode 100755 index 00000000..a0a8bbdd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleArrayList.java @@ -0,0 +1,586 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java new file mode 100755 index 00000000..f708c7a9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleCollection.java b/src/main/java/com/carrotsearch/hppc/DoubleCollection.java new file mode 100755 index 00000000..e1c4f96a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleContainer.java b/src/main/java/com/carrotsearch/hppc/DoubleContainer.java new file mode 100755 index 00000000..b5719fd5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleContainer.java @@ -0,0 +1,76 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleDeque.java b/src/main/java/com/carrotsearch/hppc/DoubleDeque.java new file mode 100755 index 00000000..423026ec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java new file mode 100755 index 00000000..faf6b27c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleIndexedContainer.java @@ -0,0 +1,93 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java b/src/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java new file mode 100755 index 00000000..c27e6b4b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/DoublePgmIndex.java b/src/main/java/com/carrotsearch/hppc/DoublePgmIndex.java new file mode 100755 index 00000000..ee5ac213 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoublePgmIndex.java @@ -0,0 +1,600 @@ +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/src/main/java/com/carrotsearch/hppc/DoubleStack.java b/src/main/java/com/carrotsearch/hppc/DoubleStack.java new file mode 100755 index 00000000..bf0a2219 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/DoubleStack.java @@ -0,0 +1,137 @@ +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/src/main/java/com/carrotsearch/hppc/FloatArrayDeque.java b/src/main/java/com/carrotsearch/hppc/FloatArrayDeque.java new file mode 100755 index 00000000..e3d29082 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatArrayDeque.java @@ -0,0 +1,776 @@ +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/src/main/java/com/carrotsearch/hppc/FloatArrayList.java b/src/main/java/com/carrotsearch/hppc/FloatArrayList.java new file mode 100755 index 00000000..0b82dc2a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatArrayList.java @@ -0,0 +1,579 @@ +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/src/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java new file mode 100755 index 00000000..d0c471c3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/FloatCollection.java b/src/main/java/com/carrotsearch/hppc/FloatCollection.java new file mode 100755 index 00000000..491fab8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/FloatContainer.java b/src/main/java/com/carrotsearch/hppc/FloatContainer.java new file mode 100755 index 00000000..83b952bf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatContainer.java @@ -0,0 +1,76 @@ +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/src/main/java/com/carrotsearch/hppc/FloatDeque.java b/src/main/java/com/carrotsearch/hppc/FloatDeque.java new file mode 100755 index 00000000..240f3298 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java new file mode 100755 index 00000000..f7beda6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatIndexedContainer.java @@ -0,0 +1,91 @@ +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/src/main/java/com/carrotsearch/hppc/FloatLookupContainer.java b/src/main/java/com/carrotsearch/hppc/FloatLookupContainer.java new file mode 100755 index 00000000..558f763b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/FloatPgmIndex.java b/src/main/java/com/carrotsearch/hppc/FloatPgmIndex.java new file mode 100755 index 00000000..e14cb073 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatPgmIndex.java @@ -0,0 +1,600 @@ +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/src/main/java/com/carrotsearch/hppc/FloatStack.java b/src/main/java/com/carrotsearch/hppc/FloatStack.java new file mode 100755 index 00000000..d2377178 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/FloatStack.java @@ -0,0 +1,137 @@ +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/src/main/java/com/carrotsearch/hppc/Generated.java b/src/main/java/com/carrotsearch/hppc/Generated.java new file mode 100755 index 00000000..dd8c66d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Generated.java @@ -0,0 +1,37 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/HashContainers.java b/src/main/java/com/carrotsearch/hppc/HashContainers.java new file mode 100755 index 00000000..7f4be809 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/HashContainers.java @@ -0,0 +1,112 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/IntArrayDeque.java b/src/main/java/com/carrotsearch/hppc/IntArrayDeque.java new file mode 100755 index 00000000..06983d90 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntArrayDeque.java @@ -0,0 +1,776 @@ +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/src/main/java/com/carrotsearch/hppc/IntArrayList.java b/src/main/java/com/carrotsearch/hppc/IntArrayList.java new file mode 100755 index 00000000..6029be09 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntArrayList.java @@ -0,0 +1,586 @@ +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/src/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java new file mode 100755 index 00000000..dddbbfc3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java new file mode 100755 index 00000000..474cc041 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntByteAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntByteHashMap.java b/src/main/java/com/carrotsearch/hppc/IntByteHashMap.java new file mode 100755 index 00000000..2e69d807 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntByteHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/IntByteMap.java b/src/main/java/com/carrotsearch/hppc/IntByteMap.java new file mode 100755 index 00000000..06ce8aa8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntByteMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java new file mode 100755 index 00000000..adf2f6b1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCharAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntCharHashMap.java b/src/main/java/com/carrotsearch/hppc/IntCharHashMap.java new file mode 100755 index 00000000..f3bc23a9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCharHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/IntCharMap.java b/src/main/java/com/carrotsearch/hppc/IntCharMap.java new file mode 100755 index 00000000..dd06fe44 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCharMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/IntCollection.java b/src/main/java/com/carrotsearch/hppc/IntCollection.java new file mode 100755 index 00000000..16ae39bf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/IntContainer.java b/src/main/java/com/carrotsearch/hppc/IntContainer.java new file mode 100755 index 00000000..fd8c1b3a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntContainer.java @@ -0,0 +1,76 @@ +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/src/main/java/com/carrotsearch/hppc/IntDeque.java b/src/main/java/com/carrotsearch/hppc/IntDeque.java new file mode 100755 index 00000000..e7981ad5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java new file mode 100755 index 00000000..b447931f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java new file mode 100755 index 00000000..d070d0f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDoubleHashMap.java @@ -0,0 +1,1082 @@ +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/src/main/java/com/carrotsearch/hppc/IntDoubleMap.java b/src/main/java/com/carrotsearch/hppc/IntDoubleMap.java new file mode 100755 index 00000000..03691ffa --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntDoubleMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java new file mode 100755 index 00000000..50a4b963 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/IntFloatHashMap.java new file mode 100755 index 00000000..f7a3a4f5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntFloatHashMap.java @@ -0,0 +1,1081 @@ +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/src/main/java/com/carrotsearch/hppc/IntFloatMap.java b/src/main/java/com/carrotsearch/hppc/IntFloatMap.java new file mode 100755 index 00000000..4a1e2c9b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntFloatMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/IntHashSet.java b/src/main/java/com/carrotsearch/hppc/IntHashSet.java new file mode 100755 index 00000000..f6aae01d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntHashSet.java @@ -0,0 +1,787 @@ +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/src/main/java/com/carrotsearch/hppc/IntIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/IntIndexedContainer.java new file mode 100755 index 00000000..0eb076ea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIndexedContainer.java @@ -0,0 +1,93 @@ +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/src/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java new file mode 100755 index 00000000..fdb8772a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIntAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntIntHashMap.java b/src/main/java/com/carrotsearch/hppc/IntIntHashMap.java new file mode 100755 index 00000000..5380245c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIntHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/IntIntMap.java b/src/main/java/com/carrotsearch/hppc/IntIntMap.java new file mode 100755 index 00000000..29097ecf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntIntMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java new file mode 100755 index 00000000..37f3887c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLongAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntLongHashMap.java b/src/main/java/com/carrotsearch/hppc/IntLongHashMap.java new file mode 100755 index 00000000..8a595142 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLongHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/IntLongMap.java b/src/main/java/com/carrotsearch/hppc/IntLongMap.java new file mode 100755 index 00000000..debb6908 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLongMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/IntLookupContainer.java b/src/main/java/com/carrotsearch/hppc/IntLookupContainer.java new file mode 100755 index 00000000..7eee508f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java new file mode 100755 index 00000000..7be49222 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/IntObjectHashMap.java new file mode 100755 index 00000000..8fb8f64f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntObjectHashMap.java @@ -0,0 +1,1050 @@ +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/src/main/java/com/carrotsearch/hppc/IntObjectMap.java b/src/main/java/com/carrotsearch/hppc/IntObjectMap.java new file mode 100755 index 00000000..86c778c7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntObjectMap.java @@ -0,0 +1,181 @@ +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/src/main/java/com/carrotsearch/hppc/IntPgmIndex.java b/src/main/java/com/carrotsearch/hppc/IntPgmIndex.java new file mode 100755 index 00000000..da7dd0d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntPgmIndex.java @@ -0,0 +1,600 @@ +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/src/main/java/com/carrotsearch/hppc/IntSet.java b/src/main/java/com/carrotsearch/hppc/IntSet.java new file mode 100755 index 00000000..500b376e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntSet.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java new file mode 100755 index 00000000..918efde7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntShortAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/IntShortHashMap.java b/src/main/java/com/carrotsearch/hppc/IntShortHashMap.java new file mode 100755 index 00000000..c36b0fe2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntShortHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/IntShortMap.java b/src/main/java/com/carrotsearch/hppc/IntShortMap.java new file mode 100755 index 00000000..b0a5813a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntShortMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/IntStack.java b/src/main/java/com/carrotsearch/hppc/IntStack.java new file mode 100755 index 00000000..cd65ff61 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/IntStack.java @@ -0,0 +1,137 @@ +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/src/main/java/com/carrotsearch/hppc/LongArrayDeque.java b/src/main/java/com/carrotsearch/hppc/LongArrayDeque.java new file mode 100755 index 00000000..8065aafd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongArrayDeque.java @@ -0,0 +1,776 @@ +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/src/main/java/com/carrotsearch/hppc/LongArrayList.java b/src/main/java/com/carrotsearch/hppc/LongArrayList.java new file mode 100755 index 00000000..ea99bfeb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongArrayList.java @@ -0,0 +1,586 @@ +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/src/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java new file mode 100755 index 00000000..1c9e0af9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java new file mode 100755 index 00000000..b3e17bfa --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongByteAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongByteHashMap.java b/src/main/java/com/carrotsearch/hppc/LongByteHashMap.java new file mode 100755 index 00000000..eeaf5028 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongByteHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/LongByteMap.java b/src/main/java/com/carrotsearch/hppc/LongByteMap.java new file mode 100755 index 00000000..1291678d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongByteMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java new file mode 100755 index 00000000..9188f4e5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCharAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongCharHashMap.java b/src/main/java/com/carrotsearch/hppc/LongCharHashMap.java new file mode 100755 index 00000000..c5262ab9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCharHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/LongCharMap.java b/src/main/java/com/carrotsearch/hppc/LongCharMap.java new file mode 100755 index 00000000..fbc9d681 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCharMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/LongCollection.java b/src/main/java/com/carrotsearch/hppc/LongCollection.java new file mode 100755 index 00000000..65869b85 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/LongContainer.java b/src/main/java/com/carrotsearch/hppc/LongContainer.java new file mode 100755 index 00000000..cc10b05a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongContainer.java @@ -0,0 +1,76 @@ +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/src/main/java/com/carrotsearch/hppc/LongDeque.java b/src/main/java/com/carrotsearch/hppc/LongDeque.java new file mode 100755 index 00000000..a2a202b9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java new file mode 100755 index 00000000..f0ec0558 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java new file mode 100755 index 00000000..2df0b5ab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDoubleHashMap.java @@ -0,0 +1,1082 @@ +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/src/main/java/com/carrotsearch/hppc/LongDoubleMap.java b/src/main/java/com/carrotsearch/hppc/LongDoubleMap.java new file mode 100755 index 00000000..7c83d309 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongDoubleMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java new file mode 100755 index 00000000..80cc2da1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/LongFloatHashMap.java new file mode 100755 index 00000000..bc0d5f2d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongFloatHashMap.java @@ -0,0 +1,1081 @@ +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/src/main/java/com/carrotsearch/hppc/LongFloatMap.java b/src/main/java/com/carrotsearch/hppc/LongFloatMap.java new file mode 100755 index 00000000..dc4cf199 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongFloatMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/LongHashSet.java b/src/main/java/com/carrotsearch/hppc/LongHashSet.java new file mode 100755 index 00000000..8957939d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongHashSet.java @@ -0,0 +1,787 @@ +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/src/main/java/com/carrotsearch/hppc/LongIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/LongIndexedContainer.java new file mode 100755 index 00000000..ba0c78a2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIndexedContainer.java @@ -0,0 +1,93 @@ +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/src/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java new file mode 100755 index 00000000..97467873 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIntAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongIntHashMap.java b/src/main/java/com/carrotsearch/hppc/LongIntHashMap.java new file mode 100755 index 00000000..de4d34b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIntHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/LongIntMap.java b/src/main/java/com/carrotsearch/hppc/LongIntMap.java new file mode 100755 index 00000000..6fb8c866 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongIntMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java new file mode 100755 index 00000000..24be1a2e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLongAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongLongHashMap.java b/src/main/java/com/carrotsearch/hppc/LongLongHashMap.java new file mode 100755 index 00000000..c1937803 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLongHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/LongLongMap.java b/src/main/java/com/carrotsearch/hppc/LongLongMap.java new file mode 100755 index 00000000..3ea093c9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLongMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/LongLookupContainer.java b/src/main/java/com/carrotsearch/hppc/LongLookupContainer.java new file mode 100755 index 00000000..70a99942 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java new file mode 100755 index 00000000..9e805ffc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/LongObjectHashMap.java new file mode 100755 index 00000000..e8647afd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongObjectHashMap.java @@ -0,0 +1,1050 @@ +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/src/main/java/com/carrotsearch/hppc/LongObjectMap.java b/src/main/java/com/carrotsearch/hppc/LongObjectMap.java new file mode 100755 index 00000000..712d01a5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongObjectMap.java @@ -0,0 +1,181 @@ +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/src/main/java/com/carrotsearch/hppc/LongPgmIndex.java b/src/main/java/com/carrotsearch/hppc/LongPgmIndex.java new file mode 100755 index 00000000..dc80b159 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongPgmIndex.java @@ -0,0 +1,600 @@ +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/src/main/java/com/carrotsearch/hppc/LongSet.java b/src/main/java/com/carrotsearch/hppc/LongSet.java new file mode 100755 index 00000000..69a3144a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongSet.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java new file mode 100755 index 00000000..e9f9f677 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongShortAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/LongShortHashMap.java b/src/main/java/com/carrotsearch/hppc/LongShortHashMap.java new file mode 100755 index 00000000..cf9a34c8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongShortHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/LongShortMap.java b/src/main/java/com/carrotsearch/hppc/LongShortMap.java new file mode 100755 index 00000000..3ef50522 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongShortMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/LongStack.java b/src/main/java/com/carrotsearch/hppc/LongStack.java new file mode 100755 index 00000000..6d5f15ff --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/LongStack.java @@ -0,0 +1,137 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java b/src/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java new file mode 100755 index 00000000..a25261f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectArrayDeque.java @@ -0,0 +1,786 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectArrayList.java b/src/main/java/com/carrotsearch/hppc/ObjectArrayList.java new file mode 100755 index 00000000..e11da848 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectArrayList.java @@ -0,0 +1,604 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java new file mode 100755 index 00000000..c7a988f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java new file mode 100755 index 00000000..a5904161 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java new file mode 100755 index 00000000..4de468b8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteHashMap.java @@ -0,0 +1,1089 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java new file mode 100755 index 00000000..f9567cdd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteIdentityHashMap.java @@ -0,0 +1,71 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectByteMap.java b/src/main/java/com/carrotsearch/hppc/ObjectByteMap.java new file mode 100755 index 00000000..9b4ac38a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectByteMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java new file mode 100755 index 00000000..fc06ba23 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java new file mode 100755 index 00000000..b71d892c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharHashMap.java @@ -0,0 +1,1089 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java new file mode 100755 index 00000000..d373e7f0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharIdentityHashMap.java @@ -0,0 +1,71 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectCharMap.java b/src/main/java/com/carrotsearch/hppc/ObjectCharMap.java new file mode 100755 index 00000000..ab636b51 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCharMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectCollection.java b/src/main/java/com/carrotsearch/hppc/ObjectCollection.java new file mode 100755 index 00000000..447e46de --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectContainer.java new file mode 100755 index 00000000..6e8cd488 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectContainer.java @@ -0,0 +1,85 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectDeque.java b/src/main/java/com/carrotsearch/hppc/ObjectDeque.java new file mode 100755 index 00000000..2e6f62f3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java new file mode 100755 index 00000000..0eb15e2a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleAssociativeContainer.java @@ -0,0 +1,106 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java new file mode 100755 index 00000000..bf3240c7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleHashMap.java @@ -0,0 +1,1091 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java new file mode 100755 index 00000000..b034adf4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleIdentityHashMap.java @@ -0,0 +1,71 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java b/src/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java new file mode 100755 index 00000000..595fc978 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectDoubleMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java new file mode 100755 index 00000000..a7448b25 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java new file mode 100755 index 00000000..2dc4c98e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatHashMap.java @@ -0,0 +1,1090 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java new file mode 100755 index 00000000..cfb63d0c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatIdentityHashMap.java @@ -0,0 +1,71 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectFloatMap.java b/src/main/java/com/carrotsearch/hppc/ObjectFloatMap.java new file mode 100755 index 00000000..8feee948 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectFloatMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectHashSet.java b/src/main/java/com/carrotsearch/hppc/ObjectHashSet.java new file mode 100755 index 00000000..1a37b23e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectHashSet.java @@ -0,0 +1,797 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java b/src/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java new file mode 100755 index 00000000..4efb528d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIdentityHashSet.java @@ -0,0 +1,66 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java new file mode 100755 index 00000000..37ce1fc4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIndexedContainer.java @@ -0,0 +1,93 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java new file mode 100755 index 00000000..13f68440 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java new file mode 100755 index 00000000..47e49998 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntHashMap.java @@ -0,0 +1,1089 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java new file mode 100755 index 00000000..b471a1a7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntIdentityHashMap.java @@ -0,0 +1,71 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectIntMap.java b/src/main/java/com/carrotsearch/hppc/ObjectIntMap.java new file mode 100755 index 00000000..5f87f0f6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectIntMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java new file mode 100755 index 00000000..3d78e376 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java new file mode 100755 index 00000000..1688a68d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongHashMap.java @@ -0,0 +1,1089 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java new file mode 100755 index 00000000..886d6742 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongIdentityHashMap.java @@ -0,0 +1,71 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectLongMap.java b/src/main/java/com/carrotsearch/hppc/ObjectLongMap.java new file mode 100755 index 00000000..4cab9639 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLongMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java new file mode 100755 index 00000000..ee0982c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java new file mode 100755 index 00000000..551388ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectAssociativeContainer.java @@ -0,0 +1,106 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java new file mode 100755 index 00000000..855027cd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectHashMap.java @@ -0,0 +1,1059 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java new file mode 100755 index 00000000..c726faa1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectIdentityHashMap.java @@ -0,0 +1,91 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectObjectMap.java b/src/main/java/com/carrotsearch/hppc/ObjectObjectMap.java new file mode 100755 index 00000000..c1316b06 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectObjectMap.java @@ -0,0 +1,183 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectSet.java b/src/main/java/com/carrotsearch/hppc/ObjectSet.java new file mode 100755 index 00000000..24355d4d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectSet.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java new file mode 100755 index 00000000..a5c46c27 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java new file mode 100755 index 00000000..9d492a11 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortHashMap.java @@ -0,0 +1,1089 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java b/src/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java new file mode 100755 index 00000000..c5c04c28 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortIdentityHashMap.java @@ -0,0 +1,71 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectShortMap.java b/src/main/java/com/carrotsearch/hppc/ObjectShortMap.java new file mode 100755 index 00000000..df88b9e2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectShortMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ObjectStack.java b/src/main/java/com/carrotsearch/hppc/ObjectStack.java new file mode 100755 index 00000000..d768be98 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ObjectStack.java @@ -0,0 +1,145 @@ +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/src/main/java/com/carrotsearch/hppc/PgmIndexUtil.java b/src/main/java/com/carrotsearch/hppc/PgmIndexUtil.java new file mode 100755 index 00000000..9793ab2b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/PgmIndexUtil.java @@ -0,0 +1,122 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/PlaModel.java b/src/main/java/com/carrotsearch/hppc/PlaModel.java new file mode 100755 index 00000000..49317404 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/PlaModel.java @@ -0,0 +1,414 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/Preallocable.java b/src/main/java/com/carrotsearch/hppc/Preallocable.java new file mode 100755 index 00000000..1251bcb9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/Preallocable.java @@ -0,0 +1,21 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/RamUsageEstimator.java b/src/main/java/com/carrotsearch/hppc/RamUsageEstimator.java new file mode 100755 index 00000000..907ea2e9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/RamUsageEstimator.java @@ -0,0 +1,162 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/ShortArrayDeque.java b/src/main/java/com/carrotsearch/hppc/ShortArrayDeque.java new file mode 100755 index 00000000..9c1cf824 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortArrayDeque.java @@ -0,0 +1,776 @@ +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/src/main/java/com/carrotsearch/hppc/ShortArrayList.java b/src/main/java/com/carrotsearch/hppc/ShortArrayList.java new file mode 100755 index 00000000..cae87388 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortArrayList.java @@ -0,0 +1,579 @@ +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/src/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java b/src/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java new file mode 100755 index 00000000..ce873652 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortBufferVisualizer.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java new file mode 100755 index 00000000..27f4953d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortByteAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortByteHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortByteHashMap.java new file mode 100755 index 00000000..049da077 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortByteHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/ShortByteMap.java b/src/main/java/com/carrotsearch/hppc/ShortByteMap.java new file mode 100755 index 00000000..dfe9a67a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortByteMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java new file mode 100755 index 00000000..3ab6c85d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCharAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortCharHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortCharHashMap.java new file mode 100755 index 00000000..cb29c12e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCharHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/ShortCharMap.java b/src/main/java/com/carrotsearch/hppc/ShortCharMap.java new file mode 100755 index 00000000..17bd928b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCharMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ShortCollection.java b/src/main/java/com/carrotsearch/hppc/ShortCollection.java new file mode 100755 index 00000000..372dfca5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortCollection.java @@ -0,0 +1,64 @@ +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/src/main/java/com/carrotsearch/hppc/ShortContainer.java b/src/main/java/com/carrotsearch/hppc/ShortContainer.java new file mode 100755 index 00000000..f425a1fe --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortContainer.java @@ -0,0 +1,76 @@ +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/src/main/java/com/carrotsearch/hppc/ShortDeque.java b/src/main/java/com/carrotsearch/hppc/ShortDeque.java new file mode 100755 index 00000000..244b6a6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDeque.java @@ -0,0 +1,77 @@ +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/src/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java new file mode 100755 index 00000000..0155b8a3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDoubleAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java new file mode 100755 index 00000000..4bf50582 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDoubleHashMap.java @@ -0,0 +1,1082 @@ +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/src/main/java/com/carrotsearch/hppc/ShortDoubleMap.java b/src/main/java/com/carrotsearch/hppc/ShortDoubleMap.java new file mode 100755 index 00000000..8d3ac5f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortDoubleMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java new file mode 100755 index 00000000..f6a2bf72 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortFloatAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java new file mode 100755 index 00000000..9383ebab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortFloatHashMap.java @@ -0,0 +1,1081 @@ +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/src/main/java/com/carrotsearch/hppc/ShortFloatMap.java b/src/main/java/com/carrotsearch/hppc/ShortFloatMap.java new file mode 100755 index 00000000..d09dac18 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortFloatMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ShortHashSet.java b/src/main/java/com/carrotsearch/hppc/ShortHashSet.java new file mode 100755 index 00000000..f2f35006 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortHashSet.java @@ -0,0 +1,787 @@ +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/src/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java b/src/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java new file mode 100755 index 00000000..fc7a41cf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIndexedContainer.java @@ -0,0 +1,91 @@ +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/src/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java new file mode 100755 index 00000000..07b4a19b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIntAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortIntHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortIntHashMap.java new file mode 100755 index 00000000..07bea9e2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIntHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/ShortIntMap.java b/src/main/java/com/carrotsearch/hppc/ShortIntMap.java new file mode 100755 index 00000000..78f19f42 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortIntMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java new file mode 100755 index 00000000..32375150 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLongAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortLongHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortLongHashMap.java new file mode 100755 index 00000000..2fe676e5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLongHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/ShortLongMap.java b/src/main/java/com/carrotsearch/hppc/ShortLongMap.java new file mode 100755 index 00000000..682a924f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLongMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ShortLookupContainer.java b/src/main/java/com/carrotsearch/hppc/ShortLookupContainer.java new file mode 100755 index 00000000..c049ef8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortLookupContainer.java @@ -0,0 +1,12 @@ +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/src/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java new file mode 100755 index 00000000..0c3b670b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortObjectAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java new file mode 100755 index 00000000..6b8a20b0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortObjectHashMap.java @@ -0,0 +1,1050 @@ +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/src/main/java/com/carrotsearch/hppc/ShortObjectMap.java b/src/main/java/com/carrotsearch/hppc/ShortObjectMap.java new file mode 100755 index 00000000..732c57e7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortObjectMap.java @@ -0,0 +1,181 @@ +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/src/main/java/com/carrotsearch/hppc/ShortSet.java b/src/main/java/com/carrotsearch/hppc/ShortSet.java new file mode 100755 index 00000000..f87250b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortSet.java @@ -0,0 +1,33 @@ +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/src/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java b/src/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java new file mode 100755 index 00000000..e1adb957 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortShortAssociativeContainer.java @@ -0,0 +1,105 @@ +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/src/main/java/com/carrotsearch/hppc/ShortShortHashMap.java b/src/main/java/com/carrotsearch/hppc/ShortShortHashMap.java new file mode 100755 index 00000000..589b23c3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortShortHashMap.java @@ -0,0 +1,1080 @@ +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/src/main/java/com/carrotsearch/hppc/ShortShortMap.java b/src/main/java/com/carrotsearch/hppc/ShortShortMap.java new file mode 100755 index 00000000..d90c602e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortShortMap.java @@ -0,0 +1,205 @@ +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/src/main/java/com/carrotsearch/hppc/ShortStack.java b/src/main/java/com/carrotsearch/hppc/ShortStack.java new file mode 100755 index 00000000..2c972c32 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/ShortStack.java @@ -0,0 +1,137 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java new file mode 100755 index 00000000..4e0da79c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharByteHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java new file mode 100755 index 00000000..e5f5017d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharCharHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java new file mode 100755 index 00000000..0d54399c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharDoubleHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java new file mode 100755 index 00000000..90c227ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharFloatHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java new file mode 100755 index 00000000..dde200f4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharIntHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java new file mode 100755 index 00000000..76ec360d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharLongHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java new file mode 100755 index 00000000..b4eef4b9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharObjectHashMap.java @@ -0,0 +1,435 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java new file mode 100755 index 00000000..8097e0c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationCharShortHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java new file mode 100755 index 00000000..ff9ca502 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntByteHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java new file mode 100755 index 00000000..c9190720 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntCharHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java new file mode 100755 index 00000000..107abe8f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntDoubleHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java new file mode 100755 index 00000000..ff98b064 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntFloatHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java new file mode 100755 index 00000000..8cb4c22c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntIntHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java new file mode 100755 index 00000000..bbbfb306 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntLongHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java new file mode 100755 index 00000000..cd8591ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntObjectHashMap.java @@ -0,0 +1,435 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java new file mode 100755 index 00000000..243bf989 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationIntShortHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java new file mode 100755 index 00000000..46b063f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongByteHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java new file mode 100755 index 00000000..c4daf3d0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongCharHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java new file mode 100755 index 00000000..bbd41530 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongDoubleHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java new file mode 100755 index 00000000..2a8e61d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongFloatHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java new file mode 100755 index 00000000..77620aa9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongIntHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java new file mode 100755 index 00000000..605189b3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongLongHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java new file mode 100755 index 00000000..b7f64fe4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongObjectHashMap.java @@ -0,0 +1,435 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java new file mode 100755 index 00000000..63de5c26 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationLongShortHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java new file mode 100755 index 00000000..011ace2f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectByteHashMap.java @@ -0,0 +1,447 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java new file mode 100755 index 00000000..37f0f25a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectCharHashMap.java @@ -0,0 +1,447 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java new file mode 100755 index 00000000..f593fe6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectDoubleHashMap.java @@ -0,0 +1,447 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java new file mode 100755 index 00000000..4781dd42 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectFloatHashMap.java @@ -0,0 +1,447 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java new file mode 100755 index 00000000..84b1aad2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectIntHashMap.java @@ -0,0 +1,447 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java new file mode 100755 index 00000000..f353773c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectLongHashMap.java @@ -0,0 +1,447 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java new file mode 100755 index 00000000..d1c881be --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectObjectHashMap.java @@ -0,0 +1,440 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java new file mode 100755 index 00000000..69e7bd7e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationObjectShortHashMap.java @@ -0,0 +1,447 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java new file mode 100755 index 00000000..478d3dec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortByteHashMap.java @@ -0,0 +1,442 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java new file mode 100755 index 00000000..3f4ad7df --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortCharHashMap.java @@ -0,0 +1,442 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java new file mode 100755 index 00000000..a9ae3265 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortDoubleHashMap.java @@ -0,0 +1,443 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java new file mode 100755 index 00000000..bad3ad03 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortFloatHashMap.java @@ -0,0 +1,442 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java new file mode 100755 index 00000000..501b0a07 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortIntHashMap.java @@ -0,0 +1,441 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java new file mode 100755 index 00000000..5aae2e1f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortLongHashMap.java @@ -0,0 +1,442 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java new file mode 100755 index 00000000..989690ae --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortObjectHashMap.java @@ -0,0 +1,436 @@ +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/src/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java b/src/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java new file mode 100755 index 00000000..d7266230 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/SortedIterationShortShortHashMap.java @@ -0,0 +1,442 @@ +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/src/main/java/com/carrotsearch/hppc/XorShift128P.java b/src/main/java/com/carrotsearch/hppc/XorShift128P.java new file mode 100755 index 00000000..e9db0a0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/XorShift128P.java @@ -0,0 +1,67 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java new file mode 100755 index 00000000..734e028b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java new file mode 100755 index 00000000..6682edd4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java new file mode 100755 index 00000000..0ff9f381 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteComparator.java @@ -0,0 +1,11 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java new file mode 100755 index 00000000..84b6105f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java new file mode 100755 index 00000000..a54901d6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java new file mode 100755 index 00000000..e2fed664 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java new file mode 100755 index 00000000..5684a8bc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java new file mode 100755 index 00000000..fc1c19a8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java new file mode 100755 index 00000000..154a2167 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ByteShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java new file mode 100755 index 00000000..807f0e0c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java new file mode 100755 index 00000000..0f790620 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharComparator.java new file mode 100755 index 00000000..acedac68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharComparator.java @@ -0,0 +1,11 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java new file mode 100755 index 00000000..486620ca --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java new file mode 100755 index 00000000..47bc5950 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java new file mode 100755 index 00000000..c2a225d4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java new file mode 100755 index 00000000..390998ec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java new file mode 100755 index 00000000..fdab147d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java new file mode 100755 index 00000000..91ba9976 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/CharShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java new file mode 100755 index 00000000..60fae03f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java new file mode 100755 index 00000000..ec215c93 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java new file mode 100755 index 00000000..193b5f90 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleComparator.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java new file mode 100755 index 00000000..20ba2dcc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java new file mode 100755 index 00000000..50aca950 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java new file mode 100755 index 00000000..afd12514 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java new file mode 100755 index 00000000..a843ec6a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java new file mode 100755 index 00000000..9d654aab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java new file mode 100755 index 00000000..4b463161 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/DoubleShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java new file mode 100755 index 00000000..298f94b0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java new file mode 100755 index 00000000..a2af271b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java new file mode 100755 index 00000000..8831a3bc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatComparator.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java new file mode 100755 index 00000000..26cfcb64 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java new file mode 100755 index 00000000..8fc373bb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java new file mode 100755 index 00000000..86199e53 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java new file mode 100755 index 00000000..7dcc9e44 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java new file mode 100755 index 00000000..f1e9cd64 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java new file mode 100755 index 00000000..baac7d4f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/FloatShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java new file mode 100755 index 00000000..fe34ad58 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java new file mode 100755 index 00000000..b682c529 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntComparator.java new file mode 100755 index 00000000..3501d91a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntComparator.java @@ -0,0 +1,11 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java new file mode 100755 index 00000000..5d6580d9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java new file mode 100755 index 00000000..6cb79069 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java new file mode 100755 index 00000000..fe4214fc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java new file mode 100755 index 00000000..620a6978 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java new file mode 100755 index 00000000..8fbbb04c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java new file mode 100755 index 00000000..5657bdb0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/IntShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java new file mode 100755 index 00000000..326d0f1c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java new file mode 100755 index 00000000..7c2267f5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongComparator.java new file mode 100755 index 00000000..d090607c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongComparator.java @@ -0,0 +1,11 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java new file mode 100755 index 00000000..25f39e20 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java new file mode 100755 index 00000000..dde992f6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java new file mode 100755 index 00000000..de63af1d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java new file mode 100755 index 00000000..9b0822d8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java new file mode 100755 index 00000000..42fd64ba --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java new file mode 100755 index 00000000..b6377dd2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/LongShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java new file mode 100755 index 00000000..54d86da0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java new file mode 100755 index 00000000..0c8f42dc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java new file mode 100755 index 00000000..1ec17275 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java new file mode 100755 index 00000000..1c289f20 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java new file mode 100755 index 00000000..fe143279 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java new file mode 100755 index 00000000..e031f4ea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java new file mode 100755 index 00000000..ed5a2d68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java new file mode 100755 index 00000000..c545a557 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ObjectShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java new file mode 100755 index 00000000..b372f942 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortByteComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java new file mode 100755 index 00000000..82b9b0a3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortCharComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java new file mode 100755 index 00000000..b935f60b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortComparator.java @@ -0,0 +1,11 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java new file mode 100755 index 00000000..37c2a7b5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortDoubleComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java new file mode 100755 index 00000000..15eec4a8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortFloatComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java new file mode 100755 index 00000000..9d5ad1fe --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortIntComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java new file mode 100755 index 00000000..9e394e1a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortLongComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java new file mode 100755 index 00000000..6d1715f3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortObjectComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java b/src/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java new file mode 100755 index 00000000..ccd78621 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/comparators/ShortShortComparator.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java new file mode 100755 index 00000000..e0b695dd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ByteCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java new file mode 100755 index 00000000..9e36f8f1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharByteCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java new file mode 100755 index 00000000..079a2682 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharCharCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharCursor.java new file mode 100755 index 00000000..20a0ec58 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java new file mode 100755 index 00000000..5cdcd581 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharDoubleCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java new file mode 100755 index 00000000..109f0ae3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharFloatCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java new file mode 100755 index 00000000..b706f1f4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharIntCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java new file mode 100755 index 00000000..1d5259ff --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharLongCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java new file mode 100755 index 00000000..fa98d620 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharObjectCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java new file mode 100755 index 00000000..d6407c80 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/CharShortCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java new file mode 100755 index 00000000..cc4f42c9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/DoubleCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java new file mode 100755 index 00000000..417f27eb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/FloatCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java new file mode 100755 index 00000000..b0dede73 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntByteCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java new file mode 100755 index 00000000..d49fd001 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntCharCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntCursor.java new file mode 100755 index 00000000..8fd34781 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java new file mode 100755 index 00000000..03e56888 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntDoubleCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java new file mode 100755 index 00000000..0cbc76e1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntFloatCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java new file mode 100755 index 00000000..c02ea79e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntIntCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java new file mode 100755 index 00000000..299ad712 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntLongCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java new file mode 100755 index 00000000..673a06d1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntObjectCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java new file mode 100755 index 00000000..7f72eba4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/IntShortCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java new file mode 100755 index 00000000..74cdbd90 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongByteCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java new file mode 100755 index 00000000..800389a1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongCharCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongCursor.java new file mode 100755 index 00000000..53da311c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java new file mode 100755 index 00000000..ed4ceef2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongDoubleCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java new file mode 100755 index 00000000..0ff3ebb7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongFloatCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java new file mode 100755 index 00000000..202d409a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongIntCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java new file mode 100755 index 00000000..824852f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongLongCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java new file mode 100755 index 00000000..26f413c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongObjectCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java new file mode 100755 index 00000000..5d82d4e5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/LongShortCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java new file mode 100755 index 00000000..380b48af --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectByteCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java new file mode 100755 index 00000000..1e4df4fc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCharCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java new file mode 100755 index 00000000..9f3ef5c0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java new file mode 100755 index 00000000..edc16aea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectDoubleCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java new file mode 100755 index 00000000..767777e4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectFloatCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java new file mode 100755 index 00000000..b83b3672 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectIntCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java new file mode 100755 index 00000000..4eba0b0b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectLongCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java new file mode 100755 index 00000000..85514da4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectObjectCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java new file mode 100755 index 00000000..30f6fa60 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ObjectShortCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java new file mode 100755 index 00000000..1a2bd555 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortByteCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java new file mode 100755 index 00000000..120fd566 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortCharCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java new file mode 100755 index 00000000..37117970 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortCursor.java @@ -0,0 +1,19 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java new file mode 100755 index 00000000..f4b2d389 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortDoubleCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java new file mode 100755 index 00000000..8a605078 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortFloatCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java new file mode 100755 index 00000000..997a6792 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortIntCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java new file mode 100755 index 00000000..576e7f0e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortLongCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java new file mode 100755 index 00000000..485514f6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortObjectCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java b/src/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java new file mode 100755 index 00000000..5fa724eb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/cursors/ShortShortCursor.java @@ -0,0 +1,23 @@ +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/src/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java b/src/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java new file mode 100755 index 00000000..c746e0f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/internals/SuppressForbidden.java @@ -0,0 +1,20 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java new file mode 100755 index 00000000..d3819903 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java new file mode 100755 index 00000000..7e1877cc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java new file mode 100755 index 00000000..598b185b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java new file mode 100755 index 00000000..0a7dde15 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java new file mode 100755 index 00000000..8b523f51 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java new file mode 100755 index 00000000..bff16b84 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java new file mode 100755 index 00000000..322f132b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java new file mode 100755 index 00000000..16c023b1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/BytePredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java new file mode 100755 index 00000000..975073f7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ByteShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java new file mode 100755 index 00000000..1bd258e4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java new file mode 100755 index 00000000..b2142e99 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java new file mode 100755 index 00000000..d7409d75 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java new file mode 100755 index 00000000..d2e3c890 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java new file mode 100755 index 00000000..e68d9dac --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java new file mode 100755 index 00000000..de3ed2dc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java new file mode 100755 index 00000000..c85875e6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java new file mode 100755 index 00000000..efe6e9dc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharPredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java new file mode 100755 index 00000000..54d462c2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/CharShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java new file mode 100755 index 00000000..1ab1d41c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java new file mode 100755 index 00000000..ac7f394e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java new file mode 100755 index 00000000..d3e39487 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java new file mode 100755 index 00000000..1a0343d8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java new file mode 100755 index 00000000..a1a135be --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java new file mode 100755 index 00000000..2014b2a1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java new file mode 100755 index 00000000..290912f9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java new file mode 100755 index 00000000..57227e9f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoublePredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java new file mode 100755 index 00000000..6ee48dbf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/DoubleShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java new file mode 100755 index 00000000..07a763b5 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java new file mode 100755 index 00000000..a14461d7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java new file mode 100755 index 00000000..8c8dda0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java new file mode 100755 index 00000000..fae9df7a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java new file mode 100755 index 00000000..dd37320b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java new file mode 100755 index 00000000..ed1232a7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java new file mode 100755 index 00000000..a74dca85 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java new file mode 100755 index 00000000..eb728862 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatPredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java new file mode 100755 index 00000000..1a61beb0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/FloatShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java new file mode 100755 index 00000000..3bfa0aac --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java new file mode 100755 index 00000000..c262f415 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java new file mode 100755 index 00000000..3ec64db1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java new file mode 100755 index 00000000..449b5f0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java new file mode 100755 index 00000000..384d33cd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java new file mode 100755 index 00000000..f3d4811b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java new file mode 100755 index 00000000..5a8063a8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java new file mode 100755 index 00000000..77d1c38f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntPredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java new file mode 100755 index 00000000..443642d7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/IntShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java new file mode 100755 index 00000000..dce65d8e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java new file mode 100755 index 00000000..f2974d72 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java new file mode 100755 index 00000000..34947e08 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java new file mode 100755 index 00000000..c0bf1e54 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java new file mode 100755 index 00000000..a31d293a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java new file mode 100755 index 00000000..45315193 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java new file mode 100755 index 00000000..fef9bbc3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java new file mode 100755 index 00000000..52f0b87a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongPredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java new file mode 100755 index 00000000..5621fd73 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/LongShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java new file mode 100755 index 00000000..57657903 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java new file mode 100755 index 00000000..2c108dbb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java new file mode 100755 index 00000000..e8d4ff50 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java new file mode 100755 index 00000000..166d0c56 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java new file mode 100755 index 00000000..d683332c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java new file mode 100755 index 00000000..bd97d954 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java new file mode 100755 index 00000000..6970aa65 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java new file mode 100755 index 00000000..c9426651 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectPredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java new file mode 100755 index 00000000..2049fabf --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ObjectShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java new file mode 100755 index 00000000..86305fa4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortBytePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java new file mode 100755 index 00000000..14a726ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortCharPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java new file mode 100755 index 00000000..1fdd8733 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortDoublePredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java new file mode 100755 index 00000000..4a55b962 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortFloatPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java new file mode 100755 index 00000000..039c59ab --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortIntPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java new file mode 100755 index 00000000..7036942c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortLongPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java new file mode 100755 index 00000000..1b4bf8b7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortObjectPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java new file mode 100755 index 00000000..40fa91c8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortPredicate.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java b/src/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java new file mode 100755 index 00000000..51d7b0a7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/predicates/ShortShortPredicate.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java new file mode 100755 index 00000000..bd4a18ef --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java new file mode 100755 index 00000000..6b4c5dea --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java new file mode 100755 index 00000000..3269170a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java new file mode 100755 index 00000000..011427e7 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java new file mode 100755 index 00000000..aca3dc2f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java new file mode 100755 index 00000000..01e9239e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java new file mode 100755 index 00000000..8d954b0d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java new file mode 100755 index 00000000..9959f0d1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java new file mode 100755 index 00000000..83e34cc9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ByteShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java new file mode 100755 index 00000000..58fa2d40 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java new file mode 100755 index 00000000..2cd5d298 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java new file mode 100755 index 00000000..091e5c9d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java new file mode 100755 index 00000000..73b54532 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java new file mode 100755 index 00000000..8118508d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java new file mode 100755 index 00000000..9657edd1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java new file mode 100755 index 00000000..145e6f7d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java new file mode 100755 index 00000000..2bd7e5d3 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java new file mode 100755 index 00000000..50b2584f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/CharShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java new file mode 100755 index 00000000..70adadf6 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java new file mode 100755 index 00000000..101e0d99 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java new file mode 100755 index 00000000..9ba2012c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java new file mode 100755 index 00000000..3dabb0c9 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java new file mode 100755 index 00000000..be62b25a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java new file mode 100755 index 00000000..a648e97a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java new file mode 100755 index 00000000..5973dd22 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java new file mode 100755 index 00000000..c23a5617 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java new file mode 100755 index 00000000..aea0b9ec --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/DoubleShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java new file mode 100755 index 00000000..df914d43 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java new file mode 100755 index 00000000..8d54dba1 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java new file mode 100755 index 00000000..e398c47f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java new file mode 100755 index 00000000..00cfa5b4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java new file mode 100755 index 00000000..f09f375d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java new file mode 100755 index 00000000..ee7e3d89 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java new file mode 100755 index 00000000..3e23e199 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java new file mode 100755 index 00000000..17543434 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java new file mode 100755 index 00000000..9ae0b7f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/FloatShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java new file mode 100755 index 00000000..2232f85a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java new file mode 100755 index 00000000..f5f1d509 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java new file mode 100755 index 00000000..1fca14bb --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java new file mode 100755 index 00000000..8c91a104 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java new file mode 100755 index 00000000..b870c6b8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java new file mode 100755 index 00000000..741858f0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java new file mode 100755 index 00000000..575a1f2a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java new file mode 100755 index 00000000..4fab32fd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java new file mode 100755 index 00000000..c3bac031 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/IntShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java new file mode 100755 index 00000000..670af78b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java new file mode 100755 index 00000000..5ca456d0 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java new file mode 100755 index 00000000..2aaa2c3d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java new file mode 100755 index 00000000..6b88a579 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java new file mode 100755 index 00000000..297f3878 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java new file mode 100755 index 00000000..f9f1fba4 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java new file mode 100755 index 00000000..2e0a8f86 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java new file mode 100755 index 00000000..9397055f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java new file mode 100755 index 00000000..2ad0865a --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/LongShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java new file mode 100755 index 00000000..85d69130 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java new file mode 100755 index 00000000..3393875f --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java new file mode 100755 index 00000000..4d9345d2 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java new file mode 100755 index 00000000..237c2863 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java new file mode 100755 index 00000000..11bb001c --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java new file mode 100755 index 00000000..9aec4cdd --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java new file mode 100755 index 00000000..382d76f8 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java new file mode 100755 index 00000000..cb0f00fc --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java new file mode 100755 index 00000000..871cac43 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ObjectShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java new file mode 100755 index 00000000..a9b86f29 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortByteProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java new file mode 100755 index 00000000..2ebbb819 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortCharProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java new file mode 100755 index 00000000..ada12e27 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortDoubleProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java new file mode 100755 index 00000000..a99af694 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortFloatProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java new file mode 100755 index 00000000..e633c55d --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortIntProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java new file mode 100755 index 00000000..99275f7e --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortLongProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java new file mode 100755 index 00000000..5ab91d02 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortObjectProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java new file mode 100755 index 00000000..d3482c7b --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortProcedure.java @@ -0,0 +1,7 @@ +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/src/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java b/src/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java new file mode 100755 index 00000000..05873e51 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/procedures/ShortShortProcedure.java @@ -0,0 +1,9 @@ +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/src/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java b/src/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java new file mode 100755 index 00000000..2d4722ed --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/sorting/IndirectSort.java @@ -0,0 +1,133 @@ +/* + * 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/src/main/java/com/carrotsearch/hppc/sorting/QuickSort.java b/src/main/java/com/carrotsearch/hppc/sorting/QuickSort.java new file mode 100755 index 00000000..b547dc68 --- /dev/null +++ b/src/main/java/com/carrotsearch/hppc/sorting/QuickSort.java @@ -0,0 +1,181 @@ +/* + * 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/src/main/java/jdk_internal/bidi/Annotation.java b/src/main/java/jdk_internal/bidi/Annotation.java new file mode 100755 index 00000000..b0b6ed71 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/Annotation.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +/** + * An Annotation object is used as a wrapper for a text attribute value if the + * attribute has annotation characteristics. These characteristics are: + *

    + *
  • The text range that the attribute is applied to is critical to the + * semantics of the range. That means, the attribute cannot be applied to + * subranges of the text range that it applies to, and, if two adjacent text + * ranges have the same value for this attribute, the attribute still cannot be + * applied to the combined range as a whole with this value. + *
  • The attribute or its value usually do no longer apply if the underlying + * text is changed. + *
+ * + * An example is grammatical information attached to a sentence: For the + * previous sentence, you can say that "an example" is the subject, but you + * cannot say the same about "an", "example", or "exam". When the text is + * changed, the grammatical information typically becomes invalid. Another + * example is Japanese reading information (yomi). + * + *

+ * Wrapping the attribute value into an Annotation object guarantees that + * adjacent text runs don't get merged even if the attribute values are equal, + * and indicates to text containers that the attribute should be discarded if + * the underlying text is modified. + * + * @see AttributedCharacterIterator + * @since 1.2 + */ + +public class Annotation { + + /** + * Constructs an annotation record with the given value, which may be null. + * + * @param value the value of the attribute + */ + public Annotation(Object value) { + this.value = value; + } + + /** + * Returns the value of the attribute, which may be null. + * + * @return the value of the attribute + */ + public Object getValue() { + return value; + } + + /** + * Returns the String representation of this Annotation. + * + * @return the {@code String} representation of this {@code Annotation} + */ + public String toString() { + return getClass().getName() + "[value=" + value + "]"; + } + + private Object value; + +}; diff --git a/src/main/java/jdk_internal/bidi/AttributedCharacterIterator.java b/src/main/java/jdk_internal/bidi/AttributedCharacterIterator.java new file mode 100755 index 00000000..00223d36 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/AttributedCharacterIterator.java @@ -0,0 +1,299 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import java.io.InvalidObjectException; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * An {@code AttributedCharacterIterator} allows iteration through both text and + * related attribute information. + * + *

+ * An attribute is a key/value pair, identified by the key. No two attributes on + * a given character can have the same key. + * + *

+ * The values for an attribute are immutable, or must not be mutated by clients + * or storage. They are always passed by reference, and not cloned. + * + *

+ * A run with respect to an attribute is a maximum text range for + * which: + *

    + *
  • the attribute is undefined or {@code null} for the entire range, or + *
  • the attribute value is defined and has the same non-{@code null} value + * for the entire range. + *
+ * + *

+ * A run with respect to a set of attributes is a maximum text range + * for which this condition is met for each member attribute. + * + *

+ * When getting a run with no explicit attributes specified (i.e., calling + * {@link #getRunStart()} and {@link #getRunLimit()}), any contiguous text + * segments having the same attributes (the same set of attribute/value pairs) + * are treated as separate runs if the attributes have been given to those text + * segments separately. + * + *

+ * The returned indexes are limited to the range of the iterator. + * + *

+ * The returned attribute information is limited to runs that contain the + * current character. + * + *

+ * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} + * and its subclasses, such as {@link java.awt.font.TextAttribute}. + * + * @see AttributedCharacterIterator.Attribute + * @see java.awt.font.TextAttribute + * @see AttributedString + * @see Annotation + * @since 1.2 + */ + +public interface AttributedCharacterIterator extends CharacterIterator { + + /** + * Defines attribute keys that are used to identify text attributes. These keys + * are used in {@code AttributedCharacterIterator} and {@code AttributedString}. + * + * @see AttributedCharacterIterator + * @see AttributedString + * @since 1.2 + */ + + public static class Attribute implements Serializable { + + /** + * The name of this {@code Attribute}. The name is used primarily by + * {@code readResolve} to look up the corresponding predefined instance when + * deserializing an instance. + * + * @serial + */ + private String name; + + // table of all instances in this class, used by readResolve + private static final Map instanceMap = new HashMap<>(7); + + /** + * Constructs an {@code Attribute} with the given name. + * + * @param name the name of {@code Attribute} + */ + protected Attribute(String name) { + this.name = name; + if (this.getClass() == Attribute.class) { + instanceMap.put(name, this); + } + } + + /** + * Compares two objects for equality. This version only returns true for + * {@code x.equals(y)} if {@code x} and {@code y} refer to the same object, and + * guarantees this for all subclasses. + */ + public final boolean equals(Object obj) { + return super.equals(obj); + } + + /** + * Returns a hash code value for the object. This version is identical to the + * one in {@code Object}, but is also final. + */ + public final int hashCode() { + return super.hashCode(); + } + + /** + * Returns a string representation of the object. This version returns the + * concatenation of class name, {@code "("}, a name identifying the attribute + * and {@code ")"}. + */ + public String toString() { + return getClass().getName() + "(" + name + ")"; + } + + /** + * Returns the name of the attribute. + * + * @return the name of {@code Attribute} + */ + protected String getName() { + return name; + } + + /** + * Resolves instances being deserialized to the predefined constants. + * + * @return the resolved {@code Attribute} object + * @throws InvalidObjectException if the object to resolve is not an instance of + * {@code Attribute} + */ + protected Object readResolve() throws InvalidObjectException { + if (this.getClass() != Attribute.class) { + throw new InvalidObjectException("subclass didn't correctly implement readResolve"); + } + + Attribute instance = instanceMap.get(getName()); + if (instance != null) { + return instance; + } else { + throw new InvalidObjectException("unknown attribute name"); + } + } + + /** + * Attribute key for the language of some text. + *

+ * Values are instances of {@link java.util.Locale Locale}. + * + * @see java.util.Locale + */ + public static final Attribute LANGUAGE = new Attribute("language"); + + /** + * Attribute key for the reading of some text. In languages where the written + * form and the pronunciation of a word are only loosely related (such as + * Japanese), it is often necessary to store the reading (pronunciation) along + * with the written form. + *

+ * Values are instances of {@link Annotation} holding instances of + * {@link String}. + * + * @see Annotation + * @see java.lang.String + */ + public static final Attribute READING = new Attribute("reading"); + + /** + * Attribute key for input method segments. Input methods often break up text + * into segments, which usually correspond to words. + *

+ * Values are instances of {@link Annotation} holding a {@code null} reference. + * + * @see Annotation + */ + public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment"); + + // make sure the serial version doesn't change between compiler versions + private static final long serialVersionUID = -9142742483513960612L; + + }; + + /** + * Returns the index of the first character of the run with respect to all + * attributes containing the current character. + * + *

+ * Any contiguous text segments having the same attributes (the same set of + * attribute/value pairs) are treated as separate runs if the attributes have + * been given to those text segments separately. + * + * @return the index of the first character of the run + */ + public int getRunStart(); + + /** + * Returns the index of the first character of the run with respect to the given + * {@code attribute} containing the current character. + * + * @param attribute the desired attribute. + * @return the index of the first character of the run + */ + public int getRunStart(Attribute attribute); + + /** + * Returns the index of the first character of the run with respect to the given + * {@code attributes} containing the current character. + * + * @param attributes a set of the desired attributes. + * @return the index of the first character of the run + */ + public int getRunStart(Set attributes); + + /** + * Returns the index of the first character following the run with respect to + * all attributes containing the current character. + * + *

+ * Any contiguous text segments having the same attributes (the same set of + * attribute/value pairs) are treated as separate runs if the attributes have + * been given to those text segments separately. + * + * @return the index of the first character following the run + */ + public int getRunLimit(); + + /** + * Returns the index of the first character following the run with respect to + * the given {@code attribute} containing the current character. + * + * @param attribute the desired attribute + * @return the index of the first character following the run + */ + public int getRunLimit(Attribute attribute); + + /** + * Returns the index of the first character following the run with respect to + * the given {@code attributes} containing the current character. + * + * @param attributes a set of the desired attributes + * @return the index of the first character following the run + */ + public int getRunLimit(Set attributes); + + /** + * Returns a map with the attributes defined on the current character. + * + * @return a map with the attributes defined on the current character + */ + public Map getAttributes(); + + /** + * Returns the value of the named {@code attribute} for the current character. + * Returns {@code null} if the {@code attribute} is not defined. + * + * @param attribute the desired attribute + * @return the value of the named {@code attribute} or {@code null} + */ + public Object getAttribute(Attribute attribute); + + /** + * Returns the keys of all attributes defined on the iterator's text range. The + * set is empty if no attributes are defined. + * + * @return the keys of all attributes + */ + public Set getAllAttributeKeys(); +}; diff --git a/src/main/java/jdk_internal/bidi/AttributedString.java b/src/main/java/jdk_internal/bidi/AttributedString.java new file mode 100755 index 00000000..cdabbc70 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/AttributedString.java @@ -0,0 +1,1109 @@ +/* + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import java.util.*; + +import jdk_internal.bidi.AttributedCharacterIterator.Attribute; + +/** + * An AttributedString holds text and related attribute information. It may be + * used as the actual data storage in some cases where a text reader wants to + * access attributed text through the AttributedCharacterIterator interface. + * + *

+ * An attribute is a key/value pair, identified by the key. No two attributes on + * a given character can have the same key. + * + *

+ * The values for an attribute are immutable, or must not be mutated by clients + * or storage. They are always passed by reference, and not cloned. + * + * @see AttributedCharacterIterator + * @see Annotation + * @since 1.2 + */ + +public class AttributedString { + // field holding the text + String text; + + // Fields holding run attribute information. + // Run attributes are organized by run. + // Arrays are always of equal lengths (the current capacity). + // Since there are no vectors of int, we have to use arrays. + private static final int INITIAL_CAPACITY = 10; + int runCount; // actual number of runs, <= current capacity + int[] runStarts; // start index for each run + Vector[] runAttributes; // vector of attribute keys for each run + Vector[] runAttributeValues; // parallel vector of attribute values for each run + + /** + * Constructs an AttributedString instance with the given + * AttributedCharacterIterators. + * + * @param iterators AttributedCharacterIterators to construct AttributedString + * from. + * @throws NullPointerException if iterators is null + */ + AttributedString(AttributedCharacterIterator[] iterators) { + if (iterators == null) { + throw new NullPointerException("Iterators must not be null"); + } + if (iterators.length == 0) { + text = ""; + } else { + // Build the String contents + StringBuffer buffer = new StringBuffer(); + for (int counter = 0; counter < iterators.length; counter++) { + appendContents(buffer, iterators[counter]); + } + + text = buffer.toString(); + + if (!text.isEmpty()) { + // Determine the runs, creating a new run when the attributes + // differ. + int offset = 0; + Map last = null; + + for (int counter = 0; counter < iterators.length; counter++) { + AttributedCharacterIterator iterator = iterators[counter]; + int start = iterator.getBeginIndex(); + int end = iterator.getEndIndex(); + int index = start; + + while (index < end) { + iterator.setIndex(index); + + Map attrs = iterator.getAttributes(); + + if (mapsDiffer(last, attrs)) { + setAttributes(attrs, index - start + offset); + } + last = attrs; + index = iterator.getRunLimit(); + } + offset += (end - start); + } + } + } + } + + /** + * Constructs an AttributedString instance with the given text. + * + * @param text The text for this attributed string. + * @throws NullPointerException if {@code text} is null. + */ + public AttributedString(String text) { + if (text == null) { + throw new NullPointerException(); + } + this.text = text; + } + + /** + * Constructs an AttributedString instance with the given text and attributes. + * + * @param text The text for this attributed string. + * @param attributes The attributes that apply to the entire string. + * @throws NullPointerException if {@code text} or {@code attributes} is + * null. + * @throws IllegalArgumentException if the text has length 0 and the attributes + * parameter is not an empty Map (attributes + * cannot be applied to a 0-length range). + */ + public AttributedString(String text, Map attributes) { + if (text == null || attributes == null) { + throw new NullPointerException(); + } + this.text = text; + + if (text.isEmpty()) { + if (attributes.isEmpty()) + return; + throw new IllegalArgumentException("Can't add attribute to 0-length text"); + } + + int attributeCount = attributes.size(); + if (attributeCount > 0) { + createRunAttributeDataVectors(); + Vector newRunAttributes = new Vector<>(attributeCount); + Vector newRunAttributeValues = new Vector<>(attributeCount); + runAttributes[0] = newRunAttributes; + runAttributeValues[0] = newRunAttributeValues; + + Iterator> iterator = attributes.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + newRunAttributes.addElement(entry.getKey()); + newRunAttributeValues.addElement(entry.getValue()); + } + } + } + + /** + * Constructs an AttributedString instance with the given attributed text + * represented by AttributedCharacterIterator. + * + * @param text The text for this attributed string. + * @throws NullPointerException if {@code text} is null. + */ + public AttributedString(AttributedCharacterIterator text) { + // If performance is critical, this constructor should be + // implemented here rather than invoking the constructor for a + // subrange. We can avoid some range checking in the loops. + this(text, text.getBeginIndex(), text.getEndIndex(), null); + } + + /** + * Constructs an AttributedString instance with the subrange of the given + * attributed text represented by AttributedCharacterIterator. If the given + * range produces an empty text, all attributes will be discarded. Note that any + * attributes wrapped by an Annotation object are discarded for a subrange of + * the original attribute range. + * + * @param text The text for this attributed string. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @throws NullPointerException if {@code text} is null. + * @throws IllegalArgumentException if the subrange given by beginIndex and + * endIndex is out of the text range. + * @see java.text.Annotation + */ + public AttributedString(AttributedCharacterIterator text, int beginIndex, int endIndex) { + this(text, beginIndex, endIndex, null); + } + + /** + * Constructs an AttributedString instance with the subrange of the given + * attributed text represented by AttributedCharacterIterator. Only attributes + * that match the given attributes will be incorporated into the instance. If + * the given range produces an empty text, all attributes will be discarded. + * Note that any attributes wrapped by an Annotation object are discarded for a + * subrange of the original attribute range. + * + * @param text The text for this attributed string. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @param attributes Specifies attributes to be extracted from the text. If null + * is specified, all available attributes will be used. + * @throws NullPointerException if {@code text} is null. + * @throws IllegalArgumentException if the subrange given by beginIndex and + * endIndex is out of the text range. + * @see java.text.Annotation + */ + public AttributedString(AttributedCharacterIterator text, int beginIndex, int endIndex, Attribute[] attributes) { + if (text == null) { + throw new NullPointerException(); + } + + // Validate the given subrange + int textBeginIndex = text.getBeginIndex(); + int textEndIndex = text.getEndIndex(); + if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex) + throw new IllegalArgumentException("Invalid substring range"); + + // Copy the given string + StringBuilder textBuilder = new StringBuilder(); + text.setIndex(beginIndex); + for (char c = text.current(); text.getIndex() < endIndex; c = text.next()) + textBuilder.append(c); + this.text = textBuilder.toString(); + + if (beginIndex == endIndex) + return; + + // Select attribute keys to be taken care of + HashSet keys = new HashSet<>(); + if (attributes == null) { + keys.addAll(text.getAllAttributeKeys()); + } else { + for (int i = 0; i < attributes.length; i++) + keys.add(attributes[i]); + keys.retainAll(text.getAllAttributeKeys()); + } + if (keys.isEmpty()) + return; + + // Get and set attribute runs for each attribute name. Need to + // scan from the top of the text so that we can discard any + // Annotation that is no longer applied to a subset text segment. + Iterator itr = keys.iterator(); + while (itr.hasNext()) { + Attribute attributeKey = itr.next(); + text.setIndex(textBeginIndex); + while (text.getIndex() < endIndex) { + int start = text.getRunStart(attributeKey); + int limit = text.getRunLimit(attributeKey); + Object value = text.getAttribute(attributeKey); + + if (value != null) { + if (value instanceof Annotation) { + if (start >= beginIndex && limit <= endIndex) { + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex); + } else { + if (limit > endIndex) + break; + } + } else { + // if the run is beyond the given (subset) range, we + // don't need to process further. + if (start >= endIndex) + break; + if (limit > beginIndex) { + // attribute is applied to any subrange + if (start < beginIndex) + start = beginIndex; + if (limit > endIndex) + limit = endIndex; + if (start != limit) { + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex); + } + } + } + } + text.setIndex(limit); + } + } + } + + /** + * Adds an attribute to the entire string. + * + * @param attribute the attribute key + * @param value the value of the attribute; may be null + * @throws NullPointerException if {@code attribute} is null. + * @throws IllegalArgumentException if the AttributedString has length 0 + * (attributes cannot be applied to a 0-length + * range). + */ + public void addAttribute(Attribute attribute, Object value) { + + if (attribute == null) { + throw new NullPointerException(); + } + + int len = length(); + if (len == 0) { + throw new IllegalArgumentException("Can't add attribute to 0-length text"); + } + + addAttributeImpl(attribute, value, 0, len); + } + + /** + * Adds an attribute to a subrange of the string. + * + * @param attribute the attribute key + * @param value The value of the attribute. May be null. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @throws NullPointerException if {@code attribute} is null. + * @throws IllegalArgumentException if beginIndex is less than 0, endIndex is + * greater than the length of the string, or + * beginIndex and endIndex together don't + * define a non-empty subrange of the string. + */ + public void addAttribute(Attribute attribute, Object value, int beginIndex, int endIndex) { + + if (attribute == null) { + throw new NullPointerException(); + } + + if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) { + throw new IllegalArgumentException("Invalid substring range"); + } + + addAttributeImpl(attribute, value, beginIndex, endIndex); + } + + /** + * Adds a set of attributes to a subrange of the string. + * + * @param attributes The attributes to be added to the string. + * @param beginIndex Index of the first character of the range. + * @param endIndex Index of the character following the last character of the + * range. + * @throws NullPointerException if {@code attributes} is null. + * @throws IllegalArgumentException if beginIndex is less than 0, endIndex is + * greater than the length of the string, or + * beginIndex and endIndex together don't + * define a non-empty subrange of the string + * and the attributes parameter is not an empty + * Map. + */ + public void addAttributes(Map attributes, int beginIndex, int endIndex) { + if (attributes == null) { + throw new NullPointerException(); + } + + if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) { + throw new IllegalArgumentException("Invalid substring range"); + } + if (beginIndex == endIndex) { + if (attributes.isEmpty()) + return; + throw new IllegalArgumentException("Can't add attribute to 0-length text"); + } + + // make sure we have run attribute data vectors + if (runCount == 0) { + createRunAttributeDataVectors(); + } + + // break up runs if necessary + int beginRunIndex = ensureRunBreak(beginIndex); + int endRunIndex = ensureRunBreak(endIndex); + + Iterator> iterator = attributes.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + addAttributeRunData(entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex); + } + } + + private synchronized void addAttributeImpl(Attribute attribute, Object value, int beginIndex, int endIndex) { + + // make sure we have run attribute data vectors + if (runCount == 0) { + createRunAttributeDataVectors(); + } + + // break up runs if necessary + int beginRunIndex = ensureRunBreak(beginIndex); + int endRunIndex = ensureRunBreak(endIndex); + + addAttributeRunData(attribute, value, beginRunIndex, endRunIndex); + } + + private final void createRunAttributeDataVectors() { + // use temporary variables so things remain consistent in case of an exception + int[] newRunStarts = new int[INITIAL_CAPACITY]; + + @SuppressWarnings("unchecked") + Vector[] newRunAttributes = (Vector[]) new Vector[INITIAL_CAPACITY]; + + @SuppressWarnings("unchecked") + Vector[] newRunAttributeValues = (Vector[]) new Vector[INITIAL_CAPACITY]; + + runStarts = newRunStarts; + runAttributes = newRunAttributes; + runAttributeValues = newRunAttributeValues; + runCount = 1; // assume initial run starting at index 0 + } + + // ensure there's a run break at offset, return the index of the run + private final int ensureRunBreak(int offset) { + return ensureRunBreak(offset, true); + } + + /** + * Ensures there is a run break at offset, returning the index of the run. If + * this results in splitting a run, two things can happen: + *
    + *
  • If copyAttrs is true, the attributes from the existing run will be placed + * in both of the newly created runs. + *
  • If copyAttrs is false, the attributes from the existing run will NOT be + * copied to the run to the right (>= offset) of the break, but will exist on + * the run to the left (< offset). + *
+ */ + private final int ensureRunBreak(int offset, boolean copyAttrs) { + if (offset == length()) { + return runCount; + } + + // search for the run index where this offset should be + int runIndex = 0; + while (runIndex < runCount && runStarts[runIndex] < offset) { + runIndex++; + } + + // if the offset is at a run start already, we're done + if (runIndex < runCount && runStarts[runIndex] == offset) { + return runIndex; + } + + // we'll have to break up a run + // first, make sure we have enough space in our arrays + int currentCapacity = runStarts.length; + if (runCount == currentCapacity) { + // We need to resize - we grow capacity by 25%. + int newCapacity = currentCapacity + (currentCapacity >> 2); + + // use temporary variables so things remain consistent in case of an exception + int[] newRunStarts = Arrays.copyOf(runStarts, newCapacity); + Vector[] newRunAttributes = Arrays.copyOf(runAttributes, newCapacity); + Vector[] newRunAttributeValues = Arrays.copyOf(runAttributeValues, newCapacity); + + runStarts = newRunStarts; + runAttributes = newRunAttributes; + runAttributeValues = newRunAttributeValues; + } + + // make copies of the attribute information of the old run that the new one used + // to be part of + // use temporary variables so things remain consistent in case of an exception + Vector newRunAttributes = null; + Vector newRunAttributeValues = null; + + if (copyAttrs) { + Vector oldRunAttributes = runAttributes[runIndex - 1]; + Vector oldRunAttributeValues = runAttributeValues[runIndex - 1]; + if (oldRunAttributes != null) { + newRunAttributes = new Vector<>(oldRunAttributes); + } + if (oldRunAttributeValues != null) { + newRunAttributeValues = new Vector<>(oldRunAttributeValues); + } + } + + // now actually break up the run + runCount++; + for (int i = runCount - 1; i > runIndex; i--) { + runStarts[i] = runStarts[i - 1]; + runAttributes[i] = runAttributes[i - 1]; + runAttributeValues[i] = runAttributeValues[i - 1]; + } + runStarts[runIndex] = offset; + runAttributes[runIndex] = newRunAttributes; + runAttributeValues[runIndex] = newRunAttributeValues; + + return runIndex; + } + + // add the attribute attribute/value to all runs where beginRunIndex <= runIndex + // < endRunIndex + private void addAttributeRunData(Attribute attribute, Object value, int beginRunIndex, int endRunIndex) { + + for (int i = beginRunIndex; i < endRunIndex; i++) { + int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet + if (runAttributes[i] == null) { + Vector newRunAttributes = new Vector<>(); + Vector newRunAttributeValues = new Vector<>(); + runAttributes[i] = newRunAttributes; + runAttributeValues[i] = newRunAttributeValues; + } else { + // check whether we have an entry already + keyValueIndex = runAttributes[i].indexOf(attribute); + } + + if (keyValueIndex == -1) { + // create new entry + int oldSize = runAttributes[i].size(); + runAttributes[i].addElement(attribute); + try { + runAttributeValues[i].addElement(value); + } catch (Exception e) { + runAttributes[i].setSize(oldSize); + runAttributeValues[i].setSize(oldSize); + } + } else { + // update existing entry + runAttributeValues[i].set(keyValueIndex, value); + } + } + } + + /** + * Creates an AttributedCharacterIterator instance that provides access to the + * entire contents of this string. + * + * @return An iterator providing access to the text and its attributes. + */ + public AttributedCharacterIterator getIterator() { + return getIterator(null, 0, length()); + } + + /** + * Creates an AttributedCharacterIterator instance that provides access to + * selected contents of this string. Information about attributes not listed in + * attributes that the implementor may have need not be made accessible through + * the iterator. If the list is null, all available attribute information should + * be made accessible. + * + * @param attributes a list of attributes that the client is interested in + * @return an iterator providing access to the entire text and its selected + * attributes + */ + public AttributedCharacterIterator getIterator(Attribute[] attributes) { + return getIterator(attributes, 0, length()); + } + + /** + * Creates an AttributedCharacterIterator instance that provides access to + * selected contents of this string. Information about attributes not listed in + * attributes that the implementor may have need not be made accessible through + * the iterator. If the list is null, all available attribute information should + * be made accessible. + * + * @param attributes a list of attributes that the client is interested in + * @param beginIndex the index of the first character + * @param endIndex the index of the character following the last character + * @return an iterator providing access to the text and its attributes + * @throws IllegalArgumentException if beginIndex is less than 0, endIndex is + * greater than the length of the string, or + * beginIndex is greater than endIndex. + */ + public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) { + return new AttributedStringIterator(attributes, beginIndex, endIndex); + } + + // all (with the exception of length) reading operations are private, + // since AttributedString instances are accessed through iterators. + + // length is package private so that CharacterIteratorFieldDelegate can + // access it without creating an AttributedCharacterIterator. + int length() { + return text.length(); + } + + private char charAt(int index) { + return text.charAt(index); + } + + private synchronized Object getAttribute(Attribute attribute, int runIndex) { + Vector currentRunAttributes = runAttributes[runIndex]; + Vector currentRunAttributeValues = runAttributeValues[runIndex]; + if (currentRunAttributes == null) { + return null; + } + int attributeIndex = currentRunAttributes.indexOf(attribute); + if (attributeIndex != -1) { + return currentRunAttributeValues.elementAt(attributeIndex); + } else { + return null; + } + } + + // gets an attribute value, but returns an annotation only if it's range does + // not extend outside the range beginIndex..endIndex + private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) { + Object value = getAttribute(attribute, runIndex); + if (value instanceof Annotation) { + // need to check whether the annotation's range extends outside the iterator's + // range + if (beginIndex > 0) { + int currIndex = runIndex; + int runStart = runStarts[currIndex]; + while (runStart >= beginIndex && valuesMatch(value, getAttribute(attribute, currIndex - 1))) { + currIndex--; + runStart = runStarts[currIndex]; + } + if (runStart < beginIndex) { + // annotation's range starts before iterator's range + return null; + } + } + int textLength = length(); + if (endIndex < textLength) { + int currIndex = runIndex; + int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; + while (runLimit <= endIndex && valuesMatch(value, getAttribute(attribute, currIndex + 1))) { + currIndex++; + runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; + } + if (runLimit > endIndex) { + // annotation's range ends after iterator's range + return null; + } + } + // annotation's range is subrange of iterator's range, + // so we can return the value + } + return value; + } + + // returns whether all specified attributes have equal values in the runs with + // the given indices + private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) { + Iterator iterator = attributes.iterator(); + while (iterator.hasNext()) { + Attribute key = iterator.next(); + if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) { + return false; + } + } + return true; + } + + // returns whether the two objects are either both null or equal + private static final boolean valuesMatch(Object value1, Object value2) { + if (value1 == null) { + return value2 == null; + } else { + return value1.equals(value2); + } + } + + /** + * Appends the contents of the CharacterIterator iterator into the StringBuffer + * buf. + */ + private final void appendContents(StringBuffer buf, CharacterIterator iterator) { + int index = iterator.getBeginIndex(); + int end = iterator.getEndIndex(); + + while (index < end) { + iterator.setIndex(index++); + buf.append(iterator.current()); + } + } + + /** + * Sets the attributes for the range from offset to the next run break + * (typically the end of the text) to the ones specified in attrs. This is only + * meant to be called from the constructor! + */ + private void setAttributes(Map attrs, int offset) { + if (runCount == 0) { + createRunAttributeDataVectors(); + } + + int index = ensureRunBreak(offset, false); + int size; + + if (attrs != null && (size = attrs.size()) > 0) { + Vector runAttrs = new Vector<>(size); + Vector runValues = new Vector<>(size); + Iterator> iterator = attrs.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + + runAttrs.add(entry.getKey()); + runValues.add(entry.getValue()); + } + runAttributes[index] = runAttrs; + runAttributeValues[index] = runValues; + } + } + + /** + * Returns true if the attributes specified in last and attrs differ. + */ + private static boolean mapsDiffer(Map last, Map attrs) { + if (last == null) { + return (attrs != null && attrs.size() > 0); + } + return (!last.equals(attrs)); + } + + // the iterator class associated with this string class + + private final class AttributedStringIterator implements AttributedCharacterIterator { + + // note on synchronization: + // we don't synchronize on the iterator, assuming that an iterator is only used + // in one thread. + // we do synchronize access to the AttributedString however, since it's more + // likely to be shared between threads. + + // start and end index for our iteration + private int beginIndex; + private int endIndex; + + // attributes that our client is interested in + private Attribute[] relevantAttributes; + + // the current index for our iteration + // invariant: beginIndex <= currentIndex <= endIndex + private int currentIndex; + + // information about the run that includes currentIndex + private int currentRunIndex; + private int currentRunStart; + private int currentRunLimit; + + // constructor + AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) { + + if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) { + throw new IllegalArgumentException("Invalid substring range"); + } + + this.beginIndex = beginIndex; + this.endIndex = endIndex; + this.currentIndex = beginIndex; + updateRunInfo(); + if (attributes != null) { + relevantAttributes = attributes.clone(); + } + } + + // Object methods. See documentation in that class. + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof AttributedStringIterator)) { + return false; + } + + AttributedStringIterator that = (AttributedStringIterator) obj; + + if (AttributedString.this != that.getString()) + return false; + if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex) + return false; + return true; + } + + public int hashCode() { + return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex; + } + + public Object clone() { + try { + AttributedStringIterator other = (AttributedStringIterator) super.clone(); + return other; + } catch (CloneNotSupportedException e) { + throw new InternalError(e); + } + } + + // CharacterIterator methods. See documentation in that interface. + + public char first() { + return internalSetIndex(beginIndex); + } + + public char last() { + if (endIndex == beginIndex) { + return internalSetIndex(endIndex); + } else { + return internalSetIndex(endIndex - 1); + } + } + + public char current() { + if (currentIndex == endIndex) { + return DONE; + } else { + return charAt(currentIndex); + } + } + + public char next() { + if (currentIndex < endIndex) { + return internalSetIndex(currentIndex + 1); + } else { + return DONE; + } + } + + public char previous() { + if (currentIndex > beginIndex) { + return internalSetIndex(currentIndex - 1); + } else { + return DONE; + } + } + + public char setIndex(int position) { + if (position < beginIndex || position > endIndex) + throw new IllegalArgumentException("Invalid index"); + return internalSetIndex(position); + } + + public int getBeginIndex() { + return beginIndex; + } + + public int getEndIndex() { + return endIndex; + } + + public int getIndex() { + return currentIndex; + } + + // AttributedCharacterIterator methods. See documentation in that interface. + + public int getRunStart() { + return currentRunStart; + } + + public int getRunStart(Attribute attribute) { + if (currentRunStart == beginIndex || currentRunIndex == -1) { + return currentRunStart; + } else { + Object value = getAttribute(attribute); + int runStart = currentRunStart; + int runIndex = currentRunIndex; + while (runStart > beginIndex + && valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) { + runIndex--; + runStart = runStarts[runIndex]; + } + if (runStart < beginIndex) { + runStart = beginIndex; + } + return runStart; + } + } + + public int getRunStart(Set attributes) { + if (currentRunStart == beginIndex || currentRunIndex == -1) { + return currentRunStart; + } else { + int runStart = currentRunStart; + int runIndex = currentRunIndex; + while (runStart > beginIndex + && AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) { + runIndex--; + runStart = runStarts[runIndex]; + } + if (runStart < beginIndex) { + runStart = beginIndex; + } + return runStart; + } + } + + public int getRunLimit() { + return currentRunLimit; + } + + public int getRunLimit(Attribute attribute) { + if (currentRunLimit == endIndex || currentRunIndex == -1) { + return currentRunLimit; + } else { + Object value = getAttribute(attribute); + int runLimit = currentRunLimit; + int runIndex = currentRunIndex; + while (runLimit < endIndex + && valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) { + runIndex++; + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex; + } + if (runLimit > endIndex) { + runLimit = endIndex; + } + return runLimit; + } + } + + public int getRunLimit(Set attributes) { + if (currentRunLimit == endIndex || currentRunIndex == -1) { + return currentRunLimit; + } else { + int runLimit = currentRunLimit; + int runIndex = currentRunIndex; + while (runLimit < endIndex + && AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) { + runIndex++; + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex; + } + if (runLimit > endIndex) { + runLimit = endIndex; + } + return runLimit; + } + } + + public Map getAttributes() { + if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) { + // ??? would be nice to return null, but current spec doesn't allow it + // returning Hashtable saves AttributeMap from dealing with emptiness + return new Hashtable<>(); + } + return new AttributeMap(currentRunIndex, beginIndex, endIndex); + } + + public Set getAllAttributeKeys() { + // ??? This should screen out attribute keys that aren't relevant to the client + if (runAttributes == null) { + // ??? would be nice to return null, but current spec doesn't allow it + // returning HashSet saves us from dealing with emptiness + return new HashSet<>(); + } + synchronized (AttributedString.this) { + // ??? should try to create this only once, then update if necessary, + // and give callers read-only view + Set keys = new HashSet<>(); + int i = 0; + while (i < runCount) { + if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) { + Vector currentRunAttributes = runAttributes[i]; + if (currentRunAttributes != null) { + int j = currentRunAttributes.size(); + while (j-- > 0) { + keys.add(currentRunAttributes.get(j)); + } + } + } + i++; + } + return keys; + } + } + + public Object getAttribute(Attribute attribute) { + int runIndex = currentRunIndex; + if (runIndex < 0) { + return null; + } + return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex); + } + + // internally used methods + + private AttributedString getString() { + return AttributedString.this; + } + + // set the current index, update information about the current run if necessary, + // return the character at the current index + private char internalSetIndex(int position) { + currentIndex = position; + if (position < currentRunStart || position >= currentRunLimit) { + updateRunInfo(); + } + if (currentIndex == endIndex) { + return DONE; + } else { + return charAt(position); + } + } + + // update the information about the current run + private void updateRunInfo() { + if (currentIndex == endIndex) { + currentRunStart = currentRunLimit = endIndex; + currentRunIndex = -1; + } else { + synchronized (AttributedString.this) { + int runIndex = -1; + while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex) + runIndex++; + currentRunIndex = runIndex; + if (runIndex >= 0) { + currentRunStart = runStarts[runIndex]; + if (currentRunStart < beginIndex) + currentRunStart = beginIndex; + } else { + currentRunStart = beginIndex; + } + if (runIndex < runCount - 1) { + currentRunLimit = runStarts[runIndex + 1]; + if (currentRunLimit > endIndex) + currentRunLimit = endIndex; + } else { + currentRunLimit = endIndex; + } + } + } + } + + } + + // the map class associated with this string class, giving access to the + // attributes of one run + + private final class AttributeMap extends AbstractMap { + + int runIndex; + int beginIndex; + int endIndex; + + AttributeMap(int runIndex, int beginIndex, int endIndex) { + this.runIndex = runIndex; + this.beginIndex = beginIndex; + this.endIndex = endIndex; + } + + public Set> entrySet() { + HashSet> set = new HashSet<>(); + synchronized (AttributedString.this) { + int size = runAttributes[runIndex].size(); + for (int i = 0; i < size; i++) { + Attribute key = runAttributes[runIndex].get(i); + Object value = runAttributeValues[runIndex].get(i); + if (value instanceof Annotation) { + value = AttributedString.this.getAttributeCheckRange(key, runIndex, beginIndex, endIndex); + if (value == null) { + continue; + } + } + + Map.Entry entry = new AttributeEntry(key, value); + set.add(entry); + } + } + return set; + } + + public Object get(Object key) { + return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex); + } + } +} + +class AttributeEntry implements Map.Entry { + + private Attribute key; + private Object value; + + AttributeEntry(Attribute key, Object value) { + this.key = key; + this.value = value; + } + + public boolean equals(Object o) { + if (!(o instanceof AttributeEntry)) { + return false; + } + AttributeEntry other = (AttributeEntry) o; + return other.key.equals(key) && Objects.equals(other.value, value); + } + + public Attribute getKey() { + return key; + } + + public Object getValue() { + return value; + } + + public Object setValue(Object newValue) { + throw new UnsupportedOperationException(); + } + + public int hashCode() { + return key.hashCode() ^ (value == null ? 0 : value.hashCode()); + } + + public String toString() { + return key.toString() + "=" + value.toString(); + } +} diff --git a/src/main/java/jdk_internal/bidi/Bidi.java b/src/main/java/jdk_internal/bidi/Bidi.java new file mode 100755 index 00000000..8c698bea --- /dev/null +++ b/src/main/java/jdk_internal/bidi/Bidi.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved + * + * The original version of this source code and documentation is + * copyrighted and owned by IBM. These materials are provided + * under terms of a License Agreement between IBM and Sun. + * This technology is protected by multiple US and International + * patents. This notice and attribution to IBM may not be removed. + */ + +package jdk_internal.bidi; + +import jdk_internal.bidi.icu.text.BidiBase; + +/** + * This class implements the Unicode Bidirectional Algorithm. + *

+ * A Bidi object provides information on the bidirectional reordering of the + * text used to create it. This is required, for example, to properly display + * Arabic or Hebrew text. These languages are inherently mixed directional, as + * they order numbers from left-to-right while ordering most other text from + * right-to-left. + *

+ * Once created, a Bidi object can be queried to see if the text it represents + * is all left-to-right or all right-to-left. Such objects are very lightweight + * and this text is relatively easy to process. + *

+ * If there are multiple runs of text, information about the runs can be + * accessed by indexing to get the start, limit, and level of a run. The level + * represents both the direction and the 'nesting level' of a directional run. + * Odd levels are right-to-left, while even levels are left-to-right. So for + * example level 0 represents left-to-right text, while level 1 represents + * right-to-left text, and level 2 represents left-to-right text embedded in a + * right-to-left run. + * + * @since 1.4 + */ +public final class Bidi { + + /** Constant indicating base direction is left-to-right. */ + public static final int DIRECTION_LEFT_TO_RIGHT = 0; + + /** Constant indicating base direction is right-to-left. */ + public static final int DIRECTION_RIGHT_TO_LEFT = 1; + + /** + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, the base direction + * is left-to-right. + */ + public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2; + + /** + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, the base direction + * is right-to-left. + */ + public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1; + + private BidiBase bidiBase; + + /** + * Create Bidi from the given paragraph of text and base direction. + * + * @param paragraph a paragraph of text + * @param flags a collection of flags that control the algorithm. The + * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, + * DIRECTION_RIGHT_TO_LEFT, DIRECTION_DEFAULT_LEFT_TO_RIGHT, + * and DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are + * reserved. + */ + public Bidi(String paragraph, int flags) { + if (paragraph == null) { + throw new IllegalArgumentException("paragraph is null"); + } + + bidiBase = new BidiBase(paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags); + } + + /** + * Create Bidi from the given paragraph of text. + *

+ * The RUN_DIRECTION attribute in the text, if present, determines the base + * direction (left-to-right or right-to-left). If not present, the base + * direction is computes using the Unicode Bidirectional Algorithm, defaulting + * to left-to-right if there are no strong directional characters in the text. + * This attribute, if present, must be applied to all the text in the paragraph. + *

+ * The BIDI_EMBEDDING attribute in the text, if present, represents embedding + * level information. Negative values from -1 to -62 indicate overrides at the + * absolute value of the level. Positive values from 1 to 62 indicate + * embeddings. Where values are zero or not defined, the base embedding level as + * determined by the base direction is assumed. + *

+ * The NUMERIC_SHAPING attribute in the text, if present, converts European + * digits to other decimal digits before running the bidi algorithm. This + * attribute, if present, must be applied to all the text in the paragraph. + * + * @param paragraph a paragraph of text with optional character and paragraph + * attribute information + * + * @see java.awt.font.TextAttribute#BIDI_EMBEDDING + * @see java.awt.font.TextAttribute#NUMERIC_SHAPING + * @see java.awt.font.TextAttribute#RUN_DIRECTION + */ + public Bidi(AttributedCharacterIterator paragraph) { + if (paragraph == null) { + throw new IllegalArgumentException("paragraph is null"); + } + + bidiBase = new BidiBase(0, 0); + bidiBase.setPara(paragraph); + } + + /** + * Create Bidi from the given text, embedding, and direction information. The + * embeddings array may be null. If present, the values represent embedding + * level information. Negative values from -1 to -61 indicate overrides at the + * absolute value of the level. Positive values from 1 to 61 indicate + * embeddings. Where values are zero, the base embedding level as determined by + * the base direction is assumed. + * + * @param text an array containing the paragraph of text to process. + * @param textStart the index into the text array of the start of the + * paragraph. + * @param embeddings an array containing embedding values for each + * character in the paragraph. This can be null, in which + * case it is assumed that there is no external embedding + * information. + * @param embStart the index into the embedding array of the start of the + * paragraph. + * @param paragraphLength the length of the paragraph in the text and embeddings + * arrays. + * @param flags a collection of flags that control the algorithm. The + * algorithm understands the flags + * DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT, + * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and + * DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are + * reserved. + */ + public Bidi(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) { + if (text == null) { + throw new IllegalArgumentException("text is null"); + } + if (paragraphLength < 0) { + throw new IllegalArgumentException("bad length: " + paragraphLength); + } + if (textStart < 0 || paragraphLength > text.length - textStart) { + throw new IllegalArgumentException( + "bad range: " + textStart + " length: " + paragraphLength + " for text of length: " + text.length); + } + if (embeddings != null && (embStart < 0 || paragraphLength > embeddings.length - embStart)) { + throw new IllegalArgumentException("bad range: " + embStart + " length: " + paragraphLength + + " for embeddings of length: " + text.length); + } + + bidiBase = new BidiBase(text, textStart, embeddings, embStart, paragraphLength, flags); + } + + /** + * Create a Bidi object representing the bidi information on a line of text + * within the paragraph represented by the current Bidi. This call is not + * required if the entire paragraph fits on one line. + * + * @param lineStart the offset from the start of the paragraph to the start of + * the line. + * @param lineLimit the offset from the start of the paragraph to the limit of + * the line. + * @return a {@code Bidi} object + */ + public Bidi createLineBidi(int lineStart, int lineLimit) { + AttributedString astr = new AttributedString(""); + Bidi newBidi = new Bidi(astr.getIterator()); + + return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase, lineStart, lineLimit); + } + + /** + * Return true if the line is not left-to-right or right-to-left. This means it + * either has mixed runs of left-to-right and right-to-left text, or the base + * direction differs from the direction of the only run of text. + * + * @return true if the line is not left-to-right or right-to-left. + */ + public boolean isMixed() { + return bidiBase.isMixed(); + } + + /** + * Return true if the line is all left-to-right text and the base direction is + * left-to-right. + * + * @return true if the line is all left-to-right text and the base direction is + * left-to-right + */ + public boolean isLeftToRight() { + return bidiBase.isLeftToRight(); + } + + /** + * Return true if the line is all right-to-left text, and the base direction is + * right-to-left. + * + * @return true if the line is all right-to-left text, and the base direction is + * right-to-left + */ + public boolean isRightToLeft() { + return bidiBase.isRightToLeft(); + } + + /** + * Return the length of text in the line. + * + * @return the length of text in the line + */ + public int getLength() { + return bidiBase.getLength(); + } + + /** + * Return true if the base direction is left-to-right. + * + * @return true if the base direction is left-to-right + */ + public boolean baseIsLeftToRight() { + return bidiBase.baseIsLeftToRight(); + } + + /** + * Return the base level (0 if left-to-right, 1 if right-to-left). + * + * @return the base level + */ + public int getBaseLevel() { + return bidiBase.getParaLevel(); + } + + /** + * Return the resolved level of the character at offset. If offset is + * {@literal <} 0 or ≥ the length of the line, return the base direction + * level. + * + * @param offset the index of the character for which to return the level + * @return the resolved level of the character at offset + */ + public int getLevelAt(int offset) { + return bidiBase.getLevelAt(offset); + } + + /** + * Return the number of level runs. + * + * @return the number of level runs + */ + public int getRunCount() { + return bidiBase.countRuns(); + } + + /** + * Return the level of the nth logical run in this line. + * + * @param run the index of the run, between 0 and {@code getRunCount()} + * @return the level of the run + */ + public int getRunLevel(int run) { + return bidiBase.getRunLevel(run); + } + + /** + * Return the index of the character at the start of the nth logical run in this + * line, as an offset from the start of the line. + * + * @param run the index of the run, between 0 and {@code getRunCount()} + * @return the start of the run + */ + public int getRunStart(int run) { + return bidiBase.getRunStart(run); + } + + /** + * Return the index of the character past the end of the nth logical run in this + * line, as an offset from the start of the line. For example, this will return + * the length of the line for the last run on the line. + * + * @param run the index of the run, between 0 and {@code getRunCount()} + * @return limit the limit of the run + */ + public int getRunLimit(int run) { + return bidiBase.getRunLimit(run); + } + + /** + * Return true if the specified text requires bidi analysis. If this returns + * false, the text will display left-to-right. Clients can then avoid + * constructing a Bidi object. Text in the Arabic Presentation Forms area of + * Unicode is presumed to already be shaped and ordered for display, and so will + * not cause this function to return true. + * + * @param text the text containing the characters to test + * @param start the start of the range of characters to test + * @param limit the limit of the range of characters to test + * @return true if the range of characters requires bidi analysis + */ + public static boolean requiresBidi(char[] text, int start, int limit) { + return BidiBase.requiresBidi(text, start, limit); + } + + /** + * Reorder the objects in the array into visual order based on their levels. + * This is a utility function to use when you have a collection of objects + * representing runs of text in logical order, each run containing text at a + * single level. The elements at {@code index} from {@code objectStart} up to + * {@code objectStart + count} in the objects array will be reordered into + * visual order assuming each run of text has the level indicated by the + * corresponding element in the levels array (at + * {@code index - objectStart + levelStart}). + * + * @param levels an array representing the bidi level of each object + * @param levelStart the start position in the levels array + * @param objects the array of objects to be reordered into visual order + * @param objectStart the start position in the objects array + * @param count the number of objects to reorder + */ + public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) { + BidiBase.reorderVisually(levels, levelStart, objects, objectStart, count); + } + + /** + * Display the bidi internal state, used in debugging. + */ + public String toString() { + return bidiBase.toString(); + } + +} diff --git a/src/main/java/jdk_internal/bidi/CharacterIterator.java b/src/main/java/jdk_internal/bidi/CharacterIterator.java new file mode 100755 index 00000000..68312844 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/CharacterIterator.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved + * + * The original version of this source code and documentation + * is copyrighted and owned by Taligent, Inc., a wholly-owned + * subsidiary of IBM. These materials are provided under terms + * of a License Agreement between Taligent and Sun. This technology + * is protected by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + * + */ + +package jdk_internal.bidi; + +/** + * This interface defines a protocol for bidirectional iteration over text. The + * iterator iterates over a bounded sequence of characters. Characters are + * indexed with values beginning with the value returned by getBeginIndex() and + * continuing through the value returned by getEndIndex()-1. + *

+ * Iterators maintain a current character index, whose valid range is from + * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to + * allow handling of zero-length text ranges and for historical reasons. The + * current index can be retrieved by calling getIndex() and set directly by + * calling setIndex(), first(), and last(). + *

+ * The methods previous() and next() are used for iteration. They return DONE if + * they would move outside the range from getBeginIndex() to getEndIndex() -1, + * signaling that the iterator has reached the end of the sequence. DONE is also + * returned by other methods to indicate that the current index is outside this + * range. + * + *

+ * Examples: + *

+ * + * Traverse the text from start to finish + * + *

{@code
+ * public void traverseForward(CharacterIterator iter) {
+ * 	for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
+ * 		processChar(c);
+ * 	}
+ * }
+ * }
+ * + * Traverse the text backwards, from end to start + * + *
{@code
+ * public void traverseBackward(CharacterIterator iter) {
+ * 	for (char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
+ * 		processChar(c);
+ * 	}
+ * }
+ * }
+ * + * Traverse both forward and backward from a given position in the text. Calls + * to notBoundary() in this example represents some additional stopping + * criteria. + * + *
{@code
+ * public void traverseOut(CharacterIterator iter, int pos) {
+ * 	for (char c = iter.setIndex(pos); c != CharacterIterator.DONE && notBoundary(c); c = iter.next()) {
+ * 	}
+ * 	int end = iter.getIndex();
+ * 	for (char c = iter.setIndex(pos); c != CharacterIterator.DONE && notBoundary(c); c = iter.previous()) {
+ * 	}
+ * 	int start = iter.getIndex();
+ * 	processSection(start, end);
+ * }
+ * }
+ * + * @since 1.1 + * @see StringCharacterIterator + * @see AttributedCharacterIterator + */ + +public interface CharacterIterator extends Cloneable { + + /** + * Constant that is returned when the iterator has reached either the end or the + * beginning of the text. The value is '\\uFFFF', the "not a character" value + * which should not occur in any valid Unicode string. + */ + public static final char DONE = '\uFFFF'; + + /** + * Sets the position to getBeginIndex() and returns the character at that + * position. + * + * @return the first character in the text, or DONE if the text is empty + * @see #getBeginIndex() + */ + public char first(); + + /** + * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty) and + * returns the character at that position. + * + * @return the last character in the text, or DONE if the text is empty + * @see #getEndIndex() + */ + public char last(); + + /** + * Gets the character at the current position (as returned by getIndex()). + * + * @return the character at the current position or DONE if the current position + * is off the end of the text. + * @see #getIndex() + */ + public char current(); + + /** + * Increments the iterator's index by one and returns the character at the new + * index. If the resulting index is greater or equal to getEndIndex(), the + * current index is reset to getEndIndex() and a value of DONE is returned. + * + * @return the character at the new position or DONE if the new position is off + * the end of the text range. + */ + public char next(); + + /** + * Decrements the iterator's index by one and returns the character at the new + * index. If the current index is getBeginIndex(), the index remains at + * getBeginIndex() and a value of DONE is returned. + * + * @return the character at the new position or DONE if the current position is + * equal to getBeginIndex(). + */ + public char previous(); + + /** + * Sets the position to the specified position in the text and returns that + * character. + * + * @param position the position within the text. Valid values range from + * getBeginIndex() to getEndIndex(). An IllegalArgumentException + * is thrown if an invalid value is supplied. + * @return the character at the specified position or DONE if the specified + * position is equal to getEndIndex() + */ + public char setIndex(int position); + + /** + * Returns the start index of the text. + * + * @return the index at which the text begins. + */ + public int getBeginIndex(); + + /** + * Returns the end index of the text. This index is the index of the first + * character following the end of the text. + * + * @return the index after the last character in the text + */ + public int getEndIndex(); + + /** + * Returns the current index. + * + * @return the current index. + */ + public int getIndex(); + + /** + * Create a copy of this iterator + * + * @return A copy of this + */ + public Object clone(); + +} diff --git a/src/main/java/jdk_internal/bidi/Normalizer.java b/src/main/java/jdk_internal/bidi/Normalizer.java new file mode 100755 index 00000000..8029bd38 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/Normalizer.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi; + +import jdk_internal.bidi.icu.text.NormalizerBase; + +/** + * This class provides the method {@code normalize} which transforms Unicode + * text into an equivalent composed or decomposed form, allowing for easier + * sorting and searching of text. The {@code normalize} method supports the + * standard normalization forms described in + * Unicode Standard Annex #15 + * — Unicode Normalization Forms. + *

+ * Characters with accents or other adornments can be encoded in several + * different ways in Unicode. For example, take the character A-acute. In + * Unicode, this can be encoded as a single character (the "composed" form): + * + *

+ *      U+00C1    LATIN CAPITAL LETTER A WITH ACUTE
+ * 
+ * + * or as two separate characters (the "decomposed" form): + * + *
+ *      U+0041    LATIN CAPITAL LETTER A
+ *      U+0301    COMBINING ACUTE ACCENT
+ * 
+ * + * To a user of your program, however, both of these sequences should be treated + * as the same "user-level" character "A with acute accent". When you are + * searching or comparing text, you must ensure that these two sequences are + * treated as equivalent. In addition, you must handle characters with more than + * one accent. Sometimes the order of a character's combining accents is + * significant, while in other cases accent sequences in different orders are + * really equivalent. + *

+ * Similarly, the string "ffi" can be encoded as three separate letters: + * + *

+ *      U+0066    LATIN SMALL LETTER F
+ *      U+0066    LATIN SMALL LETTER F
+ *      U+0069    LATIN SMALL LETTER I
+ * 
+ * + * or as the single character + * + *
+ *      U+FB03    LATIN SMALL LIGATURE FFI
+ * 
+ * + * The ffi ligature is not a distinct semantic character, and strictly speaking + * it shouldn't be in Unicode at all, but it was included for compatibility with + * existing character sets that already provided it. The Unicode standard + * identifies such characters by giving them "compatibility" decompositions into + * the corresponding semantic characters. When sorting and searching, you will + * often want to use these mappings. + *

+ * The {@code normalize} method helps solve these problems by transforming text + * into the canonical composed and decomposed forms as shown in the first + * example above. In addition, you can have it perform compatibility + * decompositions so that you can treat compatibility characters the same as + * their equivalents. Finally, the {@code normalize} method rearranges accents + * into the proper canonical order, so that you do not have to worry about + * accent rearrangement on your own. + *

+ * The W3C generally recommends to exchange texts in NFC. Note also that most + * legacy character encodings use only precomposed forms and often do not encode + * any combining marks by themselves. For conversion to such character encodings + * the Unicode text needs to be normalized to NFC. For more usage examples, see + * the Unicode Standard Annex. + * + * @since 1.6 + */ +public final class Normalizer { + + private Normalizer() { + }; + + /** + * This enum provides constants of the four Unicode normalization forms that are + * described in Unicode + * Standard Annex #15 — Unicode Normalization Forms and two methods to + * access them. + * + * @since 1.6 + */ + public static enum Form { + + /** + * Canonical decomposition. + */ + NFD, + + /** + * Canonical decomposition, followed by canonical composition. + */ + NFC, + + /** + * Compatibility decomposition. + */ + NFKD, + + /** + * Compatibility decomposition, followed by canonical composition. + */ + NFKC + } + + /** + * Normalize a sequence of char values. The sequence will be normalized + * according to the specified normalization form. + * + * @param src The sequence of char values to normalize. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @return The normalized String + * @throws NullPointerException If {@code src} or {@code form} is null. + */ + public static String normalize(CharSequence src, Form form) { + return NormalizerBase.normalize(src.toString(), form); + } + + /** + * Determines if the given sequence of char values is normalized. + * + * @param src The sequence of char values to be checked. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @return true if the sequence of char values is normalized; false otherwise. + * @throws NullPointerException If {@code src} or {@code form} is null. + */ + public static boolean isNormalized(CharSequence src, Form form) { + return NormalizerBase.isNormalized(src.toString(), form); + } +} diff --git a/src/main/java/jdk_internal/bidi/NumericShaper.java b/src/main/java/jdk_internal/bidi/NumericShaper.java new file mode 100755 index 00000000..a3f5f803 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/NumericShaper.java @@ -0,0 +1,1351 @@ +/* + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.Set; + +/** + * The {@code NumericShaper} class is used to convert Latin-1 (European) digits + * to other Unicode decimal digits. Users of this class will primarily be people + * who wish to present data using national digit shapes, but find it more + * convenient to represent the data internally using Latin-1 (European) digits. + * This does not interpret the deprecated numeric shape selector character + * (U+206E). + *

+ * Instances of {@code NumericShaper} are typically applied as attributes to + * text with the {@link TextAttribute#NUMERIC_SHAPING NUMERIC_SHAPING} attribute + * of the {@code TextAttribute} class. For example, this code snippet causes a + * {@code TextLayout} to shape European digits to Arabic in an Arabic + * context:
+ *

+ * + *
+ * Map map = new HashMap();
+ * map.put(TextAttribute.NUMERIC_SHAPING,
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC));
+ * FontRenderContext frc = ...;
+ * TextLayout layout = new TextLayout(text, map, frc);
+ * layout.draw(g2d, x, y);
+ * 
+ * + *

+ * It is also possible to perform numeric shaping explicitly using instances of + * {@code NumericShaper}, as this code snippet demonstrates:
+ *
+ * + *
+ * char[] text = ...;
+ * // shape all EUROPEAN digits (except zero) to ARABIC digits
+ * NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
+ * shaper.shape(text, start, count);
+ *
+ * // shape European digits to ARABIC digits if preceding text is Arabic, or
+ * // shape European digits to TAMIL digits if preceding text is Tamil, or
+ * // leave European digits alone if there is no preceding text, or
+ * // preceding text is neither Arabic nor Tamil
+ * NumericShaper shaper =
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+ *                                         NumericShaper.TAMIL,
+ *                                       NumericShaper.EUROPEAN);
+ * shaper.shape(text, start, count);
+ * 
+ * + *
+ * + *

+ * Bit mask- and enum-based Unicode ranges + *

+ * + *

+ * This class supports two different programming interfaces to represent Unicode + * ranges for script-specific digits: bit mask-based ones, such as + * {@link #ARABIC NumericShaper.ARABIC}, and enum-based ones, such as + * {@link NumericShaper.Range#ARABIC}. Multiple ranges can be specified by ORing + * bit mask-based constants, such as:

+ * + *
+ * NumericShaper.ARABIC | NumericShaper.TAMIL
+ * 
+ * + *
or creating a {@code Set} with the {@link NumericShaper.Range} + * constants, such as:
+ * + *
+ * EnumSet.of(NumericShaper.Range.ARABIC, NumericShaper.Range.TAMIL)
+ * 
+ * + *
The enum-based ranges are a super set of the bit mask-based + * ones. + * + *

+ * If the two interfaces are mixed (including serialization), Unicode range + * values are mapped to their counterparts where such mapping is possible, such + * as {@code NumericShaper.Range.ARABIC} from/to {@code NumericShaper.ARABIC}. + * If any unmappable range values are specified, such as + * {@code NumericShaper.Range.BALINESE}, those ranges are ignored. + * + *

+ * Decimal Digits Precedence + *

+ * + *

+ * A Unicode range may have more than one set of decimal digits. If multiple + * decimal digits sets are specified for the same Unicode range, one of the sets + * will take precedence as follows. + * + * + * + * + * + * + * + * + * + * + * + *
NumericShaper constants precedence
Unicode Range + * {@code NumericShaper} Constants + * Precedence
Arabic + * {@link NumericShaper#ARABIC NumericShaper.ARABIC}
+ * {@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC} + *
{@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC} + *
{@link NumericShaper.Range#ARABIC}
+ * {@link NumericShaper.Range#EASTERN_ARABIC} + *
{@link NumericShaper.Range#EASTERN_ARABIC}
Tai Tham + * {@link NumericShaper.Range#TAI_THAM_HORA}
+ * {@link NumericShaper.Range#TAI_THAM_THAM} + *
{@link NumericShaper.Range#TAI_THAM_THAM}
+ * + * @since 1.4 + */ +public final class NumericShaper implements java.io.Serializable { + + /** + * A {@code NumericShaper.Range} represents a Unicode range of a script having + * its own decimal digits. For example, the {@link NumericShaper.Range#THAI} + * range has the Thai digits, THAI DIGIT ZERO (U+0E50) to THAI DIGIT NINE + * (U+0E59). + * + *

+ * The {@code Range} enum replaces the traditional bit mask-based values (e.g., + * {@link NumericShaper#ARABIC}), and supports more Unicode ranges than the bit + * mask-based ones. For example, the following code using the bit mask: + *

+ * + *
+	 * NumericShaper.getContextualShaper(NumericShaper.ARABIC | NumericShaper.TAMIL, NumericShaper.EUROPEAN);
+	 * 
+ * + *
can be written using this enum as:
+ * + *
+	 * NumericShaper.getContextualShaper(EnumSet.of(NumericShaper.Range.ARABIC, NumericShaper.Range.TAMIL),
+	 * 		NumericShaper.Range.EUROPEAN);
+	 * 
+ * + *
+ * + * @since 1.7 + */ + public static enum Range { + // The order of EUROPEAN to MOGOLIAN must be consistent + // with the bitmask-based constants. + /** + * The Latin (European) range with the Latin (ASCII) digits. + */ + EUROPEAN('\u0030', '\u0000', '\u0300'), + /** + * The Arabic range with the Arabic-Indic digits. + */ + ARABIC('\u0660', '\u0600', '\u0780'), + /** + * The Arabic range with the Eastern Arabic-Indic digits. + */ + EASTERN_ARABIC('\u06f0', '\u0600', '\u0780'), + /** + * The Devanagari range with the Devanagari digits. + */ + DEVANAGARI('\u0966', '\u0900', '\u0980'), + /** + * The Bengali range with the Bengali digits. + */ + BENGALI('\u09e6', '\u0980', '\u0a00'), + /** + * The Gurmukhi range with the Gurmukhi digits. + */ + GURMUKHI('\u0a66', '\u0a00', '\u0a80'), + /** + * The Gujarati range with the Gujarati digits. + */ + GUJARATI('\u0ae6', '\u0b00', '\u0b80'), + /** + * The Oriya range with the Oriya digits. + */ + ORIYA('\u0b66', '\u0b00', '\u0b80'), + /** + * The Tamil range with the Tamil digits. + */ + TAMIL('\u0be6', '\u0b80', '\u0c00'), + /** + * The Telugu range with the Telugu digits. + */ + TELUGU('\u0c66', '\u0c00', '\u0c80'), + /** + * The Kannada range with the Kannada digits. + */ + KANNADA('\u0ce6', '\u0c80', '\u0d00'), + /** + * The Malayalam range with the Malayalam digits. + */ + MALAYALAM('\u0d66', '\u0d00', '\u0d80'), + /** + * The Thai range with the Thai digits. + */ + THAI('\u0e50', '\u0e00', '\u0e80'), + /** + * The Lao range with the Lao digits. + */ + LAO('\u0ed0', '\u0e80', '\u0f00'), + /** + * The Tibetan range with the Tibetan digits. + */ + TIBETAN('\u0f20', '\u0f00', '\u1000'), + /** + * The Myanmar range with the Myanmar digits. + */ + MYANMAR('\u1040', '\u1000', '\u1080'), + /** + * The Ethiopic range with the Ethiopic digits. Ethiopic does not have a decimal + * digit 0 so Latin (European) 0 is used. + */ + ETHIOPIC('\u1369', '\u1200', '\u1380') { + @Override + char getNumericBase() { + return 1; + } + }, + /** + * The Khmer range with the Khmer digits. + */ + KHMER('\u17e0', '\u1780', '\u1800'), + /** + * The Mongolian range with the Mongolian digits. + */ + MONGOLIAN('\u1810', '\u1800', '\u1900'), + // The order of EUROPEAN to MOGOLIAN must be consistent + // with the bitmask-based constants. + + /** + * The N'Ko range with the N'Ko digits. + */ + NKO('\u07c0', '\u07c0', '\u0800'), + /** + * The Myanmar range with the Myanmar Shan digits. + */ + MYANMAR_SHAN('\u1090', '\u1000', '\u10a0'), + /** + * The Limbu range with the Limbu digits. + */ + LIMBU('\u1946', '\u1900', '\u1950'), + /** + * The New Tai Lue range with the New Tai Lue digits. + */ + NEW_TAI_LUE('\u19d0', '\u1980', '\u19e0'), + /** + * The Balinese range with the Balinese digits. + */ + BALINESE('\u1b50', '\u1b00', '\u1b80'), + /** + * The Sundanese range with the Sundanese digits. + */ + SUNDANESE('\u1bb0', '\u1b80', '\u1bc0'), + /** + * The Lepcha range with the Lepcha digits. + */ + LEPCHA('\u1c40', '\u1c00', '\u1c50'), + /** + * The Ol Chiki range with the Ol Chiki digits. + */ + OL_CHIKI('\u1c50', '\u1c50', '\u1c80'), + /** + * The Vai range with the Vai digits. + */ + VAI('\ua620', '\ua500', '\ua640'), + /** + * The Saurashtra range with the Saurashtra digits. + */ + SAURASHTRA('\ua8d0', '\ua880', '\ua8e0'), + /** + * The Kayah Li range with the Kayah Li digits. + */ + KAYAH_LI('\ua900', '\ua900', '\ua930'), + /** + * The Cham range with the Cham digits. + */ + CHAM('\uaa50', '\uaa00', '\uaa60'), + /** + * The Tai Tham Hora range with the Tai Tham Hora digits. + */ + TAI_THAM_HORA('\u1a80', '\u1a20', '\u1ab0'), + /** + * The Tai Tham Tham range with the Tai Tham Tham digits. + */ + TAI_THAM_THAM('\u1a90', '\u1a20', '\u1ab0'), + /** + * The Javanese range with the Javanese digits. + */ + JAVANESE('\ua9d0', '\ua980', '\ua9e0'), + /** + * The Meetei Mayek range with the Meetei Mayek digits. + */ + MEETEI_MAYEK('\uabf0', '\uabc0', '\uac00'), + /** + * The Sinhala range with the Sinhala digits. + * + * @since 9 + */ + SINHALA('\u0de6', '\u0d80', '\u0e00'), + /** + * The Myanmar Extended-B range with the Myanmar Tai Laing digits. + * + * @since 9 + */ + MYANMAR_TAI_LAING('\ua9f0', '\ua9e0', '\uaa00'); + + private static int toRangeIndex(Range script) { + int index = script.ordinal(); + return index < NUM_KEYS ? index : -1; + } + + private static Range indexToRange(int index) { + return index < NUM_KEYS ? Range.values()[index] : null; + } + + private static int toRangeMask(Set ranges) { + int m = 0; + for (Range range : ranges) { + int index = range.ordinal(); + if (index < NUM_KEYS) { + m |= 1 << index; + } + } + return m; + } + + private static Set maskToRangeSet(int mask) { + Set set = EnumSet.noneOf(Range.class); + Range[] a = Range.values(); + for (int i = 0; i < NUM_KEYS; i++) { + if ((mask & (1 << i)) != 0) { + set.add(a[i]); + } + } + return set; + } + + // base character of range digits + private final int base; + // Unicode range + private final int start, // inclusive + end; // exclusive + + private Range(int base, int start, int end) { + this.base = base - ('0' + getNumericBase()); + this.start = start; + this.end = end; + } + + private int getDigitBase() { + return base; + } + + char getNumericBase() { + return 0; + } + + private boolean inRange(int c) { + return start <= c && c < end; + } + } + + /** index of context for contextual shaping - values range from 0 to 18 */ + private int key; + + /** + * flag indicating whether to shape contextually (high bit) and which digit + * ranges to shape (bits 0-18) + */ + private int mask; + + /** + * The context {@code Range} for contextual shaping or the {@code + * Range} for non-contextual shaping. {@code null} for the bit mask-based API. + * + * @since 1.7 + */ + private Range shapingRange; + + /** + * {@code Set} indicating which Unicode ranges to shape. {@code null} for + * the bit mask-based API. + */ + private transient Set rangeSet; + + /** + * rangeSet.toArray() value. Sorted by Range.base when the number of elements is + * greater than BSEARCH_THRESHOLD. + */ + private transient Range[] rangeArray; + + /** + * If more than BSEARCH_THRESHOLD ranges are specified, binary search is used. + */ + private static final int BSEARCH_THRESHOLD = 3; + + /** + * Use serialVersionUID from JDK 1.7 for interoperability. + */ + private static final long serialVersionUID = -8022764705923730308L; + + /** + * Identifies the Latin-1 (European) and extended range, and Latin-1 (European) + * decimal base. + */ + public static final int EUROPEAN = 1 << 0; + + /** Identifies the ARABIC range and decimal base. */ + public static final int ARABIC = 1 << 1; + + /** Identifies the ARABIC range and ARABIC_EXTENDED decimal base. */ + public static final int EASTERN_ARABIC = 1 << 2; + + /** Identifies the DEVANAGARI range and decimal base. */ + public static final int DEVANAGARI = 1 << 3; + + /** Identifies the BENGALI range and decimal base. */ + public static final int BENGALI = 1 << 4; + + /** Identifies the GURMUKHI range and decimal base. */ + public static final int GURMUKHI = 1 << 5; + + /** Identifies the GUJARATI range and decimal base. */ + public static final int GUJARATI = 1 << 6; + + /** Identifies the ORIYA range and decimal base. */ + public static final int ORIYA = 1 << 7; + + /** Identifies the TAMIL range and decimal base. */ + // TAMIL DIGIT ZERO was added in Unicode 4.1 + public static final int TAMIL = 1 << 8; + + /** Identifies the TELUGU range and decimal base. */ + public static final int TELUGU = 1 << 9; + + /** Identifies the KANNADA range and decimal base. */ + public static final int KANNADA = 1 << 10; + + /** Identifies the MALAYALAM range and decimal base. */ + public static final int MALAYALAM = 1 << 11; + + /** Identifies the THAI range and decimal base. */ + public static final int THAI = 1 << 12; + + /** Identifies the LAO range and decimal base. */ + public static final int LAO = 1 << 13; + + /** Identifies the TIBETAN range and decimal base. */ + public static final int TIBETAN = 1 << 14; + + /** Identifies the MYANMAR range and decimal base. */ + public static final int MYANMAR = 1 << 15; + + /** Identifies the ETHIOPIC range and decimal base. */ + public static final int ETHIOPIC = 1 << 16; + + /** Identifies the KHMER range and decimal base. */ + public static final int KHMER = 1 << 17; + + /** Identifies the MONGOLIAN range and decimal base. */ + public static final int MONGOLIAN = 1 << 18; + + /** + * Identifies all ranges, for full contextual shaping. + * + *

+ * This constant specifies all of the bit mask-based ranges. Use + * {@code EnumSet.allOf(NumericShaper.Range.class)} to specify all of the + * enum-based ranges. + */ + public static final int ALL_RANGES = 0x0007ffff; + + private static final int EUROPEAN_KEY = 0; + private static final int ARABIC_KEY = 1; + private static final int EASTERN_ARABIC_KEY = 2; + private static final int DEVANAGARI_KEY = 3; + private static final int BENGALI_KEY = 4; + private static final int GURMUKHI_KEY = 5; + private static final int GUJARATI_KEY = 6; + private static final int ORIYA_KEY = 7; + private static final int TAMIL_KEY = 8; + private static final int TELUGU_KEY = 9; + private static final int KANNADA_KEY = 10; + private static final int MALAYALAM_KEY = 11; + private static final int THAI_KEY = 12; + private static final int LAO_KEY = 13; + private static final int TIBETAN_KEY = 14; + private static final int MYANMAR_KEY = 15; + private static final int ETHIOPIC_KEY = 16; + private static final int KHMER_KEY = 17; + private static final int MONGOLIAN_KEY = 18; + + private static final int NUM_KEYS = MONGOLIAN_KEY + 1; // fixed + + private static final int CONTEXTUAL_MASK = 1 << 31; + + private static final char[] bases = { '\u0030' - '\u0030', // EUROPEAN + '\u0660' - '\u0030', // ARABIC-INDIC + '\u06f0' - '\u0030', // EXTENDED ARABIC-INDIC (EASTERN_ARABIC) + '\u0966' - '\u0030', // DEVANAGARI + '\u09e6' - '\u0030', // BENGALI + '\u0a66' - '\u0030', // GURMUKHI + '\u0ae6' - '\u0030', // GUJARATI + '\u0b66' - '\u0030', // ORIYA + '\u0be6' - '\u0030', // TAMIL - zero was added in Unicode 4.1 + '\u0c66' - '\u0030', // TELUGU + '\u0ce6' - '\u0030', // KANNADA + '\u0d66' - '\u0030', // MALAYALAM + '\u0e50' - '\u0030', // THAI + '\u0ed0' - '\u0030', // LAO + '\u0f20' - '\u0030', // TIBETAN + '\u1040' - '\u0030', // MYANMAR + '\u1369' - '\u0031', // ETHIOPIC - no zero + '\u17e0' - '\u0030', // KHMER + '\u1810' - '\u0030', // MONGOLIAN + }; + + // some ranges adjoin or overlap, rethink if we want to do a binary search on + // this + + private static final char[] contexts = { '\u0000', '\u0300', // 'EUROPEAN' (really latin-1 and extended) + '\u0600', '\u0780', // ARABIC + '\u0600', '\u0780', // EASTERN_ARABIC -- note overlap with arabic + '\u0900', '\u0980', // DEVANAGARI + '\u0980', '\u0a00', // BENGALI + '\u0a00', '\u0a80', // GURMUKHI + '\u0a80', '\u0b00', // GUJARATI + '\u0b00', '\u0b80', // ORIYA + '\u0b80', '\u0c00', // TAMIL + '\u0c00', '\u0c80', // TELUGU + '\u0c80', '\u0d00', // KANNADA + '\u0d00', '\u0d80', // MALAYALAM + '\u0e00', '\u0e80', // THAI + '\u0e80', '\u0f00', // LAO + '\u0f00', '\u1000', // TIBETAN + '\u1000', '\u1080', // MYANMAR + '\u1200', '\u1380', // ETHIOPIC - note missing zero + '\u1780', '\u1800', // KHMER + '\u1800', '\u1900', // MONGOLIAN + '\uffff', }; + + // assume most characters are near each other so probing the cache is + // infrequent, + // and a linear probe is ok. + + private static int ctCache = 0; + private static int ctCacheLimit = contexts.length - 2; + + // warning, synchronize access to this as it modifies state + private static int getContextKey(char c) { + if (c < contexts[ctCache]) { + while (ctCache > 0 && c < contexts[ctCache]) + --ctCache; + } else if (c >= contexts[ctCache + 1]) { + while (ctCache < ctCacheLimit && c >= contexts[ctCache + 1]) + ++ctCache; + } + + // if we're not in a known range, then return EUROPEAN as the range key + return (ctCache & 0x1) == 0 ? (ctCache / 2) : EUROPEAN_KEY; + } + + // cache for the NumericShaper.Range version + private transient volatile Range currentRange = Range.EUROPEAN; + + private Range rangeForCodePoint(final int codepoint) { + if (currentRange.inRange(codepoint)) { + return currentRange; + } + + final Range[] ranges = rangeArray; + if (ranges.length > BSEARCH_THRESHOLD) { + int lo = 0; + int hi = ranges.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + Range range = ranges[mid]; + if (codepoint < range.start) { + hi = mid - 1; + } else if (codepoint >= range.end) { + lo = mid + 1; + } else { + currentRange = range; + return range; + } + } + } else { + for (int i = 0; i < ranges.length; i++) { + if (ranges[i].inRange(codepoint)) { + return ranges[i]; + } + } + } + return Range.EUROPEAN; + } + + /* + * A range table of strong directional characters (types L, R, AL). Even (left) + * indexes are starts of ranges of non-strong-directional (or undefined) + * characters, odd (right) indexes are starts of ranges of strong directional + * characters. + */ + private static int[] strongTable = { 0x0000, 0x0041, 0x005b, 0x0061, 0x007b, 0x00aa, 0x00ab, 0x00b5, 0x00b6, 0x00ba, + 0x00bb, 0x00c0, 0x00d7, 0x00d8, 0x00f7, 0x00f8, 0x02b9, 0x02bb, 0x02c2, 0x02d0, 0x02d2, 0x02e0, 0x02e5, + 0x02ee, 0x02ef, 0x0370, 0x0374, 0x0376, 0x0378, 0x037a, 0x037e, 0x037f, 0x0380, 0x0386, 0x0387, 0x0388, + 0x038b, 0x038c, 0x038d, 0x038e, 0x03a2, 0x03a3, 0x03f6, 0x03f7, 0x0483, 0x048a, 0x0530, 0x0531, 0x0557, + 0x0559, 0x058a, 0x0590, 0x0591, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c3, 0x05c4, 0x05c6, 0x05c7, 0x05c8, + 0x0600, 0x0608, 0x0609, 0x060b, 0x060c, 0x060d, 0x060e, 0x061b, 0x064b, 0x066d, 0x0670, 0x0671, 0x06d6, + 0x06e5, 0x06e7, 0x06ee, 0x06f0, 0x06fa, 0x0711, 0x0712, 0x0730, 0x074b, 0x07a6, 0x07b1, 0x07eb, 0x07f4, + 0x07f6, 0x07fa, 0x07fd, 0x07fe, 0x0816, 0x081a, 0x081b, 0x0824, 0x0825, 0x0828, 0x0829, 0x082e, 0x0859, + 0x085c, 0x08e3, 0x0903, 0x093a, 0x093b, 0x093c, 0x093d, 0x0941, 0x0949, 0x094d, 0x094e, 0x0951, 0x0958, + 0x0962, 0x0964, 0x0981, 0x0982, 0x0984, 0x0985, 0x098d, 0x098f, 0x0991, 0x0993, 0x09a9, 0x09aa, 0x09b1, + 0x09b2, 0x09b3, 0x09b6, 0x09ba, 0x09bd, 0x09c1, 0x09c7, 0x09c9, 0x09cb, 0x09cd, 0x09ce, 0x09cf, 0x09d7, + 0x09d8, 0x09dc, 0x09de, 0x09df, 0x09e2, 0x09e6, 0x09f2, 0x09f4, 0x09fb, 0x09fc, 0x09fe, 0x0a03, 0x0a04, + 0x0a05, 0x0a0b, 0x0a0f, 0x0a11, 0x0a13, 0x0a29, 0x0a2a, 0x0a31, 0x0a32, 0x0a34, 0x0a35, 0x0a37, 0x0a38, + 0x0a3a, 0x0a3e, 0x0a41, 0x0a59, 0x0a5d, 0x0a5e, 0x0a5f, 0x0a66, 0x0a70, 0x0a72, 0x0a75, 0x0a76, 0x0a73, + 0x0a83, 0x0a84, 0x0a85, 0x0a8e, 0x0a8f, 0x0a92, 0x0a93, 0x0aa9, 0x0aaa, 0x0ab1, 0x0ab2, 0x0ab4, 0x0ab5, + 0x0aba, 0x0abd, 0x0ac1, 0x0ac9, 0x0aca, 0x0acb, 0x0acd, 0x0ad0, 0x0ad1, 0x0ae0, 0x0ae2, 0x0ae6, 0x0af1, + 0x0af9, 0x0afa, 0x0b02, 0x0b04, 0x0b05, 0x0b0d, 0x0b0f, 0x0b11, 0x0b13, 0x0b29, 0x0b2a, 0x0b31, 0x0b32, + 0x0b34, 0x0b35, 0x0b3a, 0x0b3d, 0x0b3f, 0x0b40, 0x0b41, 0x0b47, 0x0b49, 0x0b4b, 0x0b4d, 0x0b57, 0x0b58, + 0x0b5c, 0x0b5e, 0x0b5f, 0x0b62, 0x0b66, 0x0b78, 0x0b83, 0x0b84, 0x0b85, 0x0b8b, 0x0b8e, 0x0b91, 0x0b92, + 0x0b96, 0x0b99, 0x0b9b, 0x0b9c, 0x0b9d, 0x0b9e, 0x0ba0, 0x0ba3, 0x0ba5, 0x0ba8, 0x0bab, 0x0bae, 0x0bba, + 0x0bbe, 0x0bc0, 0x0bc1, 0x0bc3, 0x0bc6, 0x0bc9, 0x0bca, 0x0bcd, 0x0bd0, 0x0bd1, 0x0bd7, 0x0bd8, 0x0be6, + 0x0bf3, 0x0c01, 0x0c04, 0x0c05, 0x0c0d, 0x0c0e, 0x0c11, 0x0c12, 0x0c29, 0x0c2a, 0x0c3a, 0x0c3d, 0x0c3e, + 0x0c41, 0x0c45, 0x0c58, 0x0c5b, 0x0c60, 0x0c62, 0x0c66, 0x0c70, 0x0c7f, 0x0c81, 0x0c82, 0x0c8d, 0x0c8e, + 0x0c91, 0x0c92, 0x0ca9, 0x0caa, 0x0cb4, 0x0cb5, 0x0cba, 0x0cbd, 0x0cc5, 0x0cc6, 0x0cc9, 0x0cca, 0x0ccc, + 0x0cd5, 0x0cd7, 0x0cde, 0x0cdf, 0x0ce0, 0x0ce2, 0x0ce6, 0x0cf0, 0x0cf1, 0x0cf3, 0x0d02, 0x0d04, 0x0d05, + 0x0d0d, 0x0d0e, 0x0d11, 0x0d12, 0x0d3b, 0x0d3d, 0x0d41, 0x0d46, 0x0d49, 0x0d4a, 0x0d4d, 0x0d4e, 0x0d62, + 0x0d66, 0x0d80, 0x0d82, 0x0d84, 0x0d85, 0x0d97, 0x0d9a, 0x0db2, 0x0db3, 0x0dbc, 0x0dbd, 0x0dbe, 0x0dc0, + 0x0dc7, 0x0dcf, 0x0dd2, 0x0dd8, 0x0de0, 0x0de6, 0x0df0, 0x0df2, 0x0df5, 0x0e01, 0x0e31, 0x0e32, 0x0e34, + 0x0e40, 0x0e47, 0x0e4f, 0x0e5c, 0x0e81, 0x0e83, 0x0e84, 0x0e85, 0x0e87, 0x0e89, 0x0e8a, 0x0e8b, 0x0e8d, + 0x0e8e, 0x0e94, 0x0e98, 0x0e99, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea5, 0x0ea6, 0x0ea7, 0x0ea8, 0x0eaa, 0x0eac, + 0x0ead, 0x0eb1, 0x0eb2, 0x0eb4, 0x0ebd, 0x0ebe, 0x0ec0, 0x0ec5, 0x0ec6, 0x0ec7, 0x0ed0, 0x0eda, 0x0edc, + 0x0ee0, 0x0f00, 0x0f18, 0x0f1a, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3e, 0x0f48, 0x0f49, 0x0f6d, + 0x0f7f, 0x0f80, 0x0f85, 0x0f86, 0x0f88, 0x0f8d, 0x0fbe, 0x0fc6, 0x0fc7, 0x0fcd, 0x0fce, 0x0fdb, 0x1000, + 0x102d, 0x1031, 0x1032, 0x1038, 0x1039, 0x103b, 0x103d, 0x103f, 0x1058, 0x105a, 0x105e, 0x1061, 0x1071, + 0x1075, 0x1082, 0x1083, 0x1085, 0x1087, 0x108d, 0x108e, 0x109d, 0x109e, 0x10c6, 0x10c7, 0x10c8, 0x10cd, + 0x10ce, 0x10d0, 0x1249, 0x124a, 0x124e, 0x1250, 0x1257, 0x1258, 0x1259, 0x125a, 0x125e, 0x1260, 0x1289, + 0x128a, 0x128e, 0x1290, 0x12b1, 0x12b2, 0x12b6, 0x12b8, 0x12bf, 0x12c0, 0x12c1, 0x12c2, 0x12c6, 0x12c8, + 0x12d7, 0x12d8, 0x1311, 0x1312, 0x1316, 0x1318, 0x135b, 0x1360, 0x137d, 0x1380, 0x1390, 0x13a0, 0x13f6, + 0x13f8, 0x13fe, 0x1401, 0x1680, 0x1681, 0x169b, 0x16a0, 0x16f9, 0x1700, 0x170d, 0x170e, 0x1712, 0x1720, + 0x1732, 0x1735, 0x1737, 0x1740, 0x1752, 0x1760, 0x176d, 0x176e, 0x1771, 0x1780, 0x17b4, 0x17b6, 0x17b7, + 0x17be, 0x17c6, 0x17c7, 0x17c9, 0x17d4, 0x17db, 0x17dc, 0x17dd, 0x17e0, 0x17ea, 0x1810, 0x181a, 0x1820, + 0x1879, 0x1884, 0x1885, 0x1887, 0x18a9, 0x18aa, 0x18ab, 0x18b0, 0x18f6, 0x1900, 0x191f, 0x1923, 0x1927, + 0x1929, 0x192c, 0x1930, 0x1932, 0x1933, 0x1939, 0x1946, 0x196e, 0x1970, 0x1975, 0x1980, 0x19ac, 0x19b0, + 0x19ca, 0x19d0, 0x19db, 0x1a00, 0x1a17, 0x1a19, 0x1a1b, 0x1a1e, 0x1a56, 0x1a57, 0x1a58, 0x1a61, 0x1a62, + 0x1a63, 0x1a65, 0x1a6d, 0x1a73, 0x1a80, 0x1a8a, 0x1a90, 0x1a9a, 0x1aa0, 0x1aae, 0x1b04, 0x1b34, 0x1b35, + 0x1b36, 0x1b3b, 0x1b3c, 0x1b3d, 0x1b42, 0x1b43, 0x1b4c, 0x1b50, 0x1b6b, 0x1b74, 0x1b7d, 0x1b82, 0x1ba2, + 0x1ba6, 0x1ba8, 0x1baa, 0x1bab, 0x1bae, 0x1be6, 0x1be7, 0x1be8, 0x1bea, 0x1bed, 0x1bee, 0x1bef, 0x1bf2, + 0x1bf4, 0x1bfc, 0x1c2c, 0x1c34, 0x1c36, 0x1c3b, 0x1c4a, 0x1c4d, 0x1c89, 0x1c90, 0x1cbb, 0x1cbd, 0x1cc8, + 0x1cd3, 0x1cd4, 0x1ce1, 0x1ce2, 0x1ce9, 0x1ced, 0x1cee, 0x1cf4, 0x1cf5, 0x1cf8, 0x1d00, 0x1dc0, 0x1e00, + 0x1f16, 0x1f18, 0x1f1e, 0x1f20, 0x1f46, 0x1f48, 0x1f4e, 0x1f50, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, 0x1f5c, + 0x1f5d, 0x1f5e, 0x1f5f, 0x1f7e, 0x1f80, 0x1fb5, 0x1fb6, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, 0x1fc5, 0x1fc6, + 0x1fcd, 0x1fd0, 0x1fd4, 0x1fd6, 0x1fdc, 0x1fe0, 0x1fed, 0x1ff2, 0x1ff5, 0x1ff6, 0x1ffd, 0x200e, 0x2010, + 0x2071, 0x2072, 0x207f, 0x2080, 0x2090, 0x209d, 0x2102, 0x2103, 0x2107, 0x2108, 0x210a, 0x2114, 0x2115, + 0x2116, 0x2119, 0x211e, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212a, 0x212e, 0x212f, 0x213a, + 0x213c, 0x2140, 0x2145, 0x214a, 0x214e, 0x2150, 0x2160, 0x2189, 0x2336, 0x237b, 0x2395, 0x2396, 0x249c, + 0x24ea, 0x26ac, 0x26ad, 0x2800, 0x2900, 0x2c00, 0x2c2f, 0x2c30, 0x2c5f, 0x2c60, 0x2ce5, 0x2ceb, 0x2cef, + 0x2cf2, 0x2cf4, 0x2d00, 0x2d26, 0x2d27, 0x2d28, 0x2d2d, 0x2d2e, 0x2d30, 0x2d68, 0x2d6f, 0x2d71, 0x2d80, + 0x2d97, 0x2da0, 0x2da7, 0x2da8, 0x2daf, 0x2db0, 0x2db7, 0x2db8, 0x2dbf, 0x2dc0, 0x2dc7, 0x2dc8, 0x2dcf, + 0x2dd0, 0x2dd7, 0x2dd8, 0x2ddf, 0x3005, 0x3008, 0x3021, 0x302a, 0x302e, 0x3030, 0x3031, 0x3036, 0x3038, + 0x303d, 0x3041, 0x3097, 0x309d, 0x30a0, 0x30a1, 0x30fb, 0x30fc, 0x3100, 0x3105, 0x3130, 0x3131, 0x318f, + 0x3190, 0x31bb, 0x31f0, 0x321d, 0x3220, 0x3250, 0x3260, 0x327c, 0x327f, 0x32b1, 0x32c0, 0x32cc, 0x32d0, + 0x32ff, 0x3300, 0x3377, 0x337b, 0x33de, 0x33e0, 0x33ff, 0x3400, 0x4db6, 0x4e00, 0x9ff0, 0xa000, 0xa48d, + 0xa4d0, 0xa60d, 0xa610, 0xa62c, 0xa640, 0xa66f, 0xa680, 0xa69e, 0xa6a0, 0xa6f0, 0xa6f2, 0xa6f8, 0xa722, + 0xa788, 0xa789, 0xa7ba, 0xa7f7, 0xa802, 0xa803, 0xa806, 0xa807, 0xa80b, 0xa80c, 0xa825, 0xa827, 0xa828, + 0xa830, 0xa838, 0xa840, 0xa874, 0xa880, 0xa8c4, 0xa8ce, 0xa8da, 0xa8f2, 0xa8ff, 0xa900, 0xa926, 0xa92e, + 0xa947, 0xa952, 0xa954, 0xa95f, 0xa97d, 0xa983, 0xa9b3, 0xa9b4, 0xa9b6, 0xa9ba, 0xa9bc, 0xa9bd, 0xa9ce, + 0xa9cf, 0xa9da, 0xa9de, 0xa9e5, 0xa9e6, 0xa9ff, 0xaa00, 0xaa29, 0xaa2f, 0xaa31, 0xaa33, 0xaa35, 0xaa40, + 0xaa43, 0xaa44, 0xaa4c, 0xaa4d, 0xaa4e, 0xaa50, 0xaa5a, 0xaa5c, 0xaa7c, 0xaa7d, 0xaab0, 0xaab1, 0xaab2, + 0xaab5, 0xaab7, 0xaab9, 0xaabe, 0xaac0, 0xaac1, 0xaac2, 0xaac3, 0xaadb, 0xaaec, 0xaaee, 0xaaf6, 0xab01, + 0xab07, 0xab09, 0xab0f, 0xab11, 0xab17, 0xab20, 0xab27, 0xab28, 0xab2f, 0xab30, 0xab66, 0xab70, 0xabe5, + 0xabe6, 0xabe8, 0xabe9, 0xabed, 0xabf0, 0xabfa, 0xac00, 0xd7a4, 0xd7b0, 0xd7c7, 0xd7cb, 0xd7fc, 0xe000, + 0xfa6e, 0xfa70, 0xfada, 0xfb00, 0xfb07, 0xfb13, 0xfb18, 0xfb1d, 0xfb1e, 0xfb1f, 0xfb29, 0xfb2a, 0xfd3e, + 0xfd40, 0xfdd0, 0xfdf0, 0xfdfd, 0xfdfe, 0xfe00, 0xfe70, 0xfeff, 0xff21, 0xff3b, 0xff41, 0xff5b, 0xff66, + 0xffbf, 0xffc2, 0xffc8, 0xffca, 0xffd0, 0xffd2, 0xffd8, 0xffda, 0xffdd, 0x10000, 0x1000c, 0x1000d, 0x10027, + 0x10028, 0x1003b, 0x1003c, 0x1003e, 0x1003f, 0x1004e, 0x10050, 0x1005e, 0x10080, 0x100fb, 0x10100, 0x10101, + 0x10102, 0x10103, 0x10107, 0x10134, 0x10137, 0x10140, 0x1018d, 0x1018f, 0x101d0, 0x101fd, 0x10280, 0x1029d, + 0x102a0, 0x102d1, 0x10300, 0x10324, 0x1032d, 0x1034b, 0x10350, 0x10376, 0x10380, 0x1039e, 0x1039f, 0x103c4, + 0x103c8, 0x103d6, 0x10400, 0x1049e, 0x104a0, 0x104aa, 0x104d3, 0x104d4, 0x104d8, 0x104fc, 0x10500, 0x10528, + 0x10530, 0x10564, 0x1056f, 0x10570, 0x10600, 0x10737, 0x10740, 0x10756, 0x10760, 0x10768, 0x10800, 0x1091f, + 0x10920, 0x10a01, 0x10a04, 0x10a05, 0x10a07, 0x10a0c, 0x10a10, 0x10a38, 0x10a3b, 0x10a3f, 0x10a40, 0x10ae5, + 0x10ae7, 0x10b39, 0x10b40, 0x10d00, 0x10d40, 0x10e60, 0x10e7f, 0x10f30, 0x10f70, 0x11001, 0x11002, 0x11038, + 0x11047, 0x1104e, 0x11066, 0x11070, 0x11082, 0x110b3, 0x110b7, 0x110b9, 0x110bb, 0x110c2, 0x110cd, 0x110ce, + 0x110d0, 0x110e9, 0x110f0, 0x110fa, 0x11103, 0x11127, 0x1112c, 0x1112d, 0x11136, 0x11147, 0x11150, 0x11173, + 0x11174, 0x11177, 0x11182, 0x111b6, 0x111bf, 0x111c9, 0x111cd, 0x111ce, 0x111d0, 0x111e0, 0x111e1, 0x111f5, + 0x11200, 0x11212, 0x11213, 0x1122f, 0x11232, 0x11234, 0x11235, 0x11236, 0x11238, 0x1123e, 0x11280, 0x11287, + 0x11288, 0x11289, 0x1128a, 0x1128e, 0x1128f, 0x1129e, 0x1129f, 0x112aa, 0x112b0, 0x112df, 0x112e0, 0x112e3, + 0x112f0, 0x112fa, 0x11302, 0x11304, 0x11305, 0x1130d, 0x1130f, 0x11311, 0x11313, 0x11329, 0x1132a, 0x11331, + 0x11332, 0x11334, 0x11335, 0x1133a, 0x1133d, 0x11340, 0x11341, 0x11345, 0x11347, 0x11349, 0x1134b, 0x1134e, + 0x11350, 0x11351, 0x11357, 0x11358, 0x1135d, 0x11364, 0x11400, 0x11438, 0x11440, 0x11442, 0x11445, 0x11446, + 0x11447, 0x1145a, 0x1145b, 0x1145c, 0x1145d, 0x1145e, 0x11480, 0x114b3, 0x114b9, 0x114ba, 0x114bb, 0x114bf, + 0x114c1, 0x114c2, 0x114c4, 0x114c8, 0x114d0, 0x114da, 0x11580, 0x115b2, 0x115b8, 0x115bc, 0x115be, 0x115bf, + 0x115c1, 0x115dc, 0x11600, 0x11633, 0x1163b, 0x1163d, 0x1163e, 0x1163f, 0x11641, 0x11645, 0x11650, 0x1165a, + 0x11680, 0x116ab, 0x116ac, 0x116ad, 0x116ae, 0x116b0, 0x116b6, 0x116b7, 0x116c0, 0x116ca, 0x11700, 0x1171b, + 0x11720, 0x11722, 0x11726, 0x11727, 0x11730, 0x1182f, 0x11838, 0x11839, 0x1183b, 0x1183c, 0x118a0, 0x118f3, + 0x118ff, 0x11900, 0x11a00, 0x11a01, 0x11a07, 0x11a09, 0x11a0b, 0x11a33, 0x11a3a, 0x11a3b, 0x11a3f, 0x11a47, + 0x11a50, 0x11a51, 0x11a57, 0x11a59, 0x11a5c, 0x11a84, 0x11a86, 0x11a8a, 0x11a97, 0x11a98, 0x11a9a, 0x11aa3, + 0x11ac0, 0x11af9, 0x11c00, 0x11c09, 0x11c0a, 0x11c30, 0x11c3e, 0x11c46, 0x11c50, 0x11c6d, 0x11c70, 0x11c90, + 0x11ca9, 0x11caa, 0x11cb1, 0x11cb2, 0x11cb4, 0x11cb5, 0x11d00, 0x11d07, 0x11d08, 0x11d0a, 0x11d0b, 0x11d31, + 0x11d46, 0x11d47, 0x11d50, 0x11d5a, 0x11d60, 0x11d66, 0x11d67, 0x11d69, 0x11d6a, 0x11d8f, 0x11d93, 0x11d95, + 0x11d96, 0x11d97, 0x11d98, 0x11d99, 0x11da0, 0x11daa, 0x11ee0, 0x11ef3, 0x11ef5, 0x11ef9, 0x12000, 0x1239a, + 0x12400, 0x1246f, 0x12470, 0x12475, 0x12480, 0x12544, 0x13000, 0x1342f, 0x14400, 0x14647, 0x16800, 0x16a39, + 0x16a40, 0x16a5f, 0x16a60, 0x16a6a, 0x16a6e, 0x16a70, 0x16ad0, 0x16aee, 0x16af5, 0x16af6, 0x16b00, 0x16b30, + 0x16b37, 0x16b46, 0x16b50, 0x16b5a, 0x16b5b, 0x16b62, 0x16b63, 0x16b78, 0x16b7d, 0x16b90, 0x16e40, 0x16e9b, + 0x16f00, 0x16f45, 0x16f50, 0x16f7f, 0x16f93, 0x16fa0, 0x16fe0, 0x16fe2, 0x17000, 0x187f2, 0x18800, 0x18af3, + 0x1b000, 0x1b11f, 0x1b170, 0x1b2fc, 0x1bc00, 0x1bc6b, 0x1bc70, 0x1bc7d, 0x1bc80, 0x1bc89, 0x1bc90, 0x1bc9a, + 0x1bc9c, 0x1bc9d, 0x1bc9f, 0x1bca0, 0x1d000, 0x1d0f6, 0x1d100, 0x1d127, 0x1d129, 0x1d167, 0x1d16a, 0x1d173, + 0x1d183, 0x1d185, 0x1d18c, 0x1d1aa, 0x1d1ae, 0x1d1e9, 0x1d2e0, 0x1d2f4, 0x1d360, 0x1d379, 0x1d400, 0x1d455, + 0x1d456, 0x1d49d, 0x1d49e, 0x1d4a0, 0x1d4a2, 0x1d4a3, 0x1d4a5, 0x1d4a7, 0x1d4a9, 0x1d4ad, 0x1d4ae, 0x1d4ba, + 0x1d4bb, 0x1d4bc, 0x1d4bd, 0x1d4c4, 0x1d4c5, 0x1d506, 0x1d507, 0x1d50b, 0x1d50d, 0x1d515, 0x1d516, 0x1d51d, + 0x1d51e, 0x1d53a, 0x1d53b, 0x1d53f, 0x1d540, 0x1d545, 0x1d546, 0x1d547, 0x1d54a, 0x1d551, 0x1d552, 0x1d6a6, + 0x1d6a8, 0x1d6db, 0x1d6dc, 0x1d715, 0x1d716, 0x1d74f, 0x1d750, 0x1d789, 0x1d78a, 0x1d7c3, 0x1d7c4, 0x1d7cc, + 0x1d800, 0x1da00, 0x1da37, 0x1da3b, 0x1da6d, 0x1da75, 0x1da76, 0x1da84, 0x1da85, 0x1da8c, 0x1e800, 0x1e8d0, + 0x1e8d7, 0x1e944, 0x1e94b, 0x1ec70, 0x1ecc0, 0x1ee00, 0x1ef00, 0x1f000, 0x1f110, 0x1f12f, 0x1f130, 0x1f16a, + 0x1f170, 0x1f1ad, 0x1f1e6, 0x1f203, 0x1f210, 0x1f23c, 0x1f240, 0x1f249, 0x1f250, 0x1f252, 0x20000, 0x2a6d7, + 0x2a700, 0x2b735, 0x2b740, 0x2b81e, 0x2b820, 0x2cea2, 0x2ceb0, 0x2ebe1, 0x2f800, 0x2fa1e, 0xf0000, 0xffffe, + 0x100000, 0x10fffe, 0x10ffff // sentinel + }; + + // use a binary search with a cache + + private transient volatile int stCache = 0; + + private boolean isStrongDirectional(char c) { + int cachedIndex = stCache; + if (c < strongTable[cachedIndex]) { + cachedIndex = search(c, strongTable, 0, cachedIndex); + } else if (c >= strongTable[cachedIndex + 1]) { + cachedIndex = search(c, strongTable, cachedIndex + 1, strongTable.length - cachedIndex - 1); + } + boolean val = (cachedIndex & 0x1) == 1; + stCache = cachedIndex; + return val; + } + + private static int getKeyFromMask(int mask) { + int key = 0; + while (key < NUM_KEYS && ((mask & (1 << key)) == 0)) { + ++key; + } + if (key == NUM_KEYS || ((mask & ~(1 << key)) != 0)) { + throw new IllegalArgumentException("invalid shaper: " + Integer.toHexString(mask)); + } + return key; + } + + /** + * Returns a shaper for the provided unicode range. All Latin-1 (EUROPEAN) + * digits are converted to the corresponding decimal unicode digits. + * + * @param singleRange the specified Unicode range + * @return a non-contextual numeric shaper + * @throws IllegalArgumentException if the range is not a single range + */ + public static NumericShaper getShaper(int singleRange) { + int key = getKeyFromMask(singleRange); + return new NumericShaper(key, singleRange); + } + + /** + * Returns a shaper for the provided Unicode range. All Latin-1 (EUROPEAN) + * digits are converted to the corresponding decimal digits of the specified + * Unicode range. + * + * @param singleRange the Unicode range given by a {@link NumericShaper.Range} + * constant. + * @return a non-contextual {@code NumericShaper}. + * @throws NullPointerException if {@code singleRange} is {@code null} + * @since 1.7 + */ + public static NumericShaper getShaper(Range singleRange) { + return new NumericShaper(singleRange, EnumSet.of(singleRange)); + } + + /** + * Returns a contextual shaper for the provided unicode range(s). Latin-1 + * (EUROPEAN) digits are converted to the decimal digits corresponding to the + * range of the preceding text, if the range is one of the provided ranges. + * Multiple ranges are represented by or-ing the values together, such as, + * {@code NumericShaper.ARABIC | NumericShaper.THAI}. The shaper assumes + * EUROPEAN as the starting context, that is, if EUROPEAN digits are encountered + * before any strong directional text in the string, the context is presumed to + * be EUROPEAN, and so the digits will not shape. + * + * @param ranges the specified Unicode ranges + * @return a shaper for the specified ranges + */ + public static NumericShaper getContextualShaper(int ranges) { + ranges |= CONTEXTUAL_MASK; + return new NumericShaper(EUROPEAN_KEY, ranges); + } + + /** + * Returns a contextual shaper for the provided Unicode range(s). The Latin-1 + * (EUROPEAN) digits are converted to the decimal digits corresponding to the + * range of the preceding text, if the range is one of the provided ranges. + * + *

+ * The shaper assumes EUROPEAN as the starting context, that is, if EUROPEAN + * digits are encountered before any strong directional text in the string, the + * context is presumed to be EUROPEAN, and so the digits will not shape. + * + * @param ranges the specified Unicode ranges + * @return a contextual shaper for the specified ranges + * @throws NullPointerException if {@code ranges} is {@code null}. + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges) { + NumericShaper shaper = new NumericShaper(Range.EUROPEAN, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + + /** + * Returns a contextual shaper for the provided unicode range(s). Latin-1 + * (EUROPEAN) digits will be converted to the decimal digits corresponding to + * the range of the preceding text, if the range is one of the provided ranges. + * Multiple ranges are represented by or-ing the values together, for example, + * {@code NumericShaper.ARABIC | NumericShaper.THAI}. The shaper uses + * defaultContext as the starting context. + * + * @param ranges the specified Unicode ranges + * @param defaultContext the starting context, such as + * {@code NumericShaper.EUROPEAN} + * @return a shaper for the specified Unicode ranges. + * @throws IllegalArgumentException if the specified {@code defaultContext} is + * not a single valid range. + */ + public static NumericShaper getContextualShaper(int ranges, int defaultContext) { + int key = getKeyFromMask(defaultContext); + ranges |= CONTEXTUAL_MASK; + return new NumericShaper(key, ranges); + } + + /** + * Returns a contextual shaper for the provided Unicode range(s). The Latin-1 + * (EUROPEAN) digits will be converted to the decimal digits corresponding to + * the range of the preceding text, if the range is one of the provided ranges. + * The shaper uses {@code + * defaultContext} as the starting context. + * + * @param ranges the specified Unicode ranges + * @param defaultContext the starting context, such as + * {@code NumericShaper.Range.EUROPEAN} + * @return a contextual shaper for the specified Unicode ranges. + * @throws NullPointerException if {@code ranges} or {@code defaultContext} is + * {@code null} + * @since 1.7 + */ + public static NumericShaper getContextualShaper(Set ranges, Range defaultContext) { + if (defaultContext == null) { + throw new NullPointerException(); + } + NumericShaper shaper = new NumericShaper(defaultContext, ranges); + shaper.mask = CONTEXTUAL_MASK; + return shaper; + } + + /** + * Private constructor. + */ + private NumericShaper(int key, int mask) { + this.key = key; + this.mask = mask; + } + + private NumericShaper(Range defaultContext, Set ranges) { + shapingRange = defaultContext; + rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null. + + // Give precedence to EASTERN_ARABIC if both ARABIC and + // EASTERN_ARABIC are specified. + if (rangeSet.contains(Range.EASTERN_ARABIC) && rangeSet.contains(Range.ARABIC)) { + rangeSet.remove(Range.ARABIC); + } + + // As well as the above case, give precedence to TAI_THAM_THAM if both + // TAI_THAM_HORA and TAI_THAM_THAM are specified. + if (rangeSet.contains(Range.TAI_THAM_THAM) && rangeSet.contains(Range.TAI_THAM_HORA)) { + rangeSet.remove(Range.TAI_THAM_HORA); + } + + rangeArray = rangeSet.toArray(new Range[rangeSet.size()]); + if (rangeArray.length > BSEARCH_THRESHOLD) { + // sort rangeArray for binary search + Arrays.sort(rangeArray, new Comparator() { + public int compare(Range s1, Range s2) { + return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1; + } + }); + } + } + + /** + * Converts the digits in the text that occur between start and start + count. + * + * @param text an array of characters to convert + * @param start the index into {@code text} to start converting + * @param count the number of characters in {@code text} to convert + * @throws IndexOutOfBoundsException if start or start + count is out of bounds + * @throws NullPointerException if text is null + */ + public void shape(char[] text, int start, int count) { + checkParams(text, start, count); + if (isContextual()) { + if (rangeSet == null) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } + } else { + shapeNonContextually(text, start, count); + } + } + + /** + * Converts the digits in the text that occur between start and start + count, + * using the provided context. Context is ignored if the shaper is not a + * contextual shaper. + * + * @param text an array of characters + * @param start the index into {@code text} to start converting + * @param count the number of characters in {@code text} to convert + * @param context the context to which to convert the characters, such as + * {@code NumericShaper.EUROPEAN} + * @throws IndexOutOfBoundsException if start or start + count is out of bounds + * @throws NullPointerException if text is null + * @throws IllegalArgumentException if this is a contextual shaper and the + * specified {@code context} is not a single + * valid range. + */ + public void shape(char[] text, int start, int count, int context) { + checkParams(text, start, count); + if (isContextual()) { + int ctxKey = getKeyFromMask(context); + if (rangeSet == null) { + shapeContextually(text, start, count, ctxKey); + } else { + shapeContextually(text, start, count, Range.values()[ctxKey]); + } + } else { + shapeNonContextually(text, start, count); + } + } + + /** + * Converts the digits in the text that occur between {@code + * start} and {@code start + count}, using the provided {@code + * context}. {@code Context} is ignored if the shaper is not a contextual + * shaper. + * + * @param text a {@code char} array + * @param start the index into {@code text} to start converting + * @param count the number of {@code char}s in {@code text} to convert + * @param context the context to which to convert the characters, such as + * {@code NumericShaper.Range.EUROPEAN} + * @throws IndexOutOfBoundsException if {@code start} or {@code start + count} + * is out of bounds + * @throws NullPointerException if {@code text} or {@code context} is null + * @since 1.7 + */ + public void shape(char[] text, int start, int count, Range context) { + checkParams(text, start, count); + if (context == null) { + throw new NullPointerException("context is null"); + } + + if (isContextual()) { + if (rangeSet != null) { + shapeContextually(text, start, count, context); + } else { + int key = Range.toRangeIndex(context); + if (key >= 0) { + shapeContextually(text, start, count, key); + } else { + shapeContextually(text, start, count, shapingRange); + } + } + } else { + shapeNonContextually(text, start, count); + } + } + + private void checkParams(char[] text, int start, int count) { + if (text == null) { + throw new NullPointerException("text is null"); + } + if ((start < 0) || (start > text.length) || ((start + count) < 0) || ((start + count) > text.length)) { + throw new IndexOutOfBoundsException("bad start or count for text of length " + text.length); + } + } + + /** + * Returns a {@code boolean} indicating whether or not this shaper shapes + * contextually. + * + * @return {@code true} if this shaper is contextual; {@code false} otherwise. + */ + public boolean isContextual() { + return (mask & CONTEXTUAL_MASK) != 0; + } + + /** + * Returns an {@code int} that ORs together the values for all the ranges that + * will be shaped. + *

+ * For example, to check if a shaper shapes to Arabic, you would use the + * following:

+ * {@code if ((shaper.getRanges() & shaper.ARABIC) != 0) { ... } + *
+ * + *

+ * Note that this method supports only the bit mask-based ranges. Call + * {@link #getRangeSet()} for the enum-based ranges. + * + * @return the values for all the ranges to be shaped. + */ + public int getRanges() { + return mask & ~CONTEXTUAL_MASK; + } + + /** + * Returns a {@code Set} representing all the Unicode ranges in this + * {@code NumericShaper} that will be shaped. + * + * @return all the Unicode ranges to be shaped. + * @since 1.7 + */ + public Set getRangeSet() { + if (rangeSet != null) { + return EnumSet.copyOf(rangeSet); + } + return Range.maskToRangeSet(mask); + } + + /** + * Perform non-contextual shaping. + */ + private void shapeNonContextually(char[] text, int start, int count) { + int base; + char minDigit = '0'; + if (shapingRange != null) { + base = shapingRange.getDigitBase(); + minDigit += shapingRange.getNumericBase(); + } else { + base = bases[key]; + if (key == ETHIOPIC_KEY) { + minDigit++; // Ethiopic doesn't use decimal zero + } + } + for (int i = start, e = start + count; i < e; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '\u0039') { + text[i] = (char) (c + base); + } + } + } + + /** + * Perform contextual shaping. Synchronized to protect caches used in + * getContextKey. + */ + private synchronized void shapeContextually(char[] text, int start, int count, int ctxKey) { + + // if we don't support this context, then don't shape + if ((mask & (1 << ctxKey)) == 0) { + ctxKey = EUROPEAN_KEY; + } + int lastkey = ctxKey; + + int base = bases[ctxKey]; + char minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero + + synchronized (NumericShaper.class) { + for (int i = start, e = start + count; i < e; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '\u0039') { + text[i] = (char) (c + base); + } + + if (isStrongDirectional(c)) { + int newkey = getContextKey(c); + if (newkey != lastkey) { + lastkey = newkey; + + ctxKey = newkey; + if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { + ctxKey = EASTERN_ARABIC_KEY; + } else if (((mask & ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { + ctxKey = ARABIC_KEY; + } else if ((mask & (1 << ctxKey)) == 0) { + ctxKey = EUROPEAN_KEY; + } + + base = bases[ctxKey]; + + minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero + } + } + } + } + } + + private void shapeContextually(char[] text, int start, int count, Range ctxKey) { + // if we don't support the specified context, then don't shape. + if (ctxKey == null || !rangeSet.contains(ctxKey)) { + ctxKey = Range.EUROPEAN; + } + + Range lastKey = ctxKey; + int base = ctxKey.getDigitBase(); + char minDigit = (char) ('0' + ctxKey.getNumericBase()); + final int end = start + count; + for (int i = start; i < end; ++i) { + char c = text[i]; + if (c >= minDigit && c <= '9') { + text[i] = (char) (c + base); + continue; + } + if (isStrongDirectional(c)) { + ctxKey = rangeForCodePoint(c); + if (ctxKey != lastKey) { + lastKey = ctxKey; + base = ctxKey.getDigitBase(); + minDigit = (char) ('0' + ctxKey.getNumericBase()); + } + } + } + } + + /** + * Returns a hash code for this shaper. + * + * @return this shaper's hash code. + * @see java.lang.Object#hashCode + */ + public int hashCode() { + int hash = mask; + if (rangeSet != null) { + // Use the CONTEXTUAL_MASK bit only for the enum-based + // NumericShaper. A deserialized NumericShaper might have + // bit masks. + hash &= CONTEXTUAL_MASK; + hash ^= rangeSet.hashCode(); + } + return hash; + } + + /** + * Returns {@code true} if the specified object is an instance of + * {@code NumericShaper} and shapes identically to this one, regardless of the + * range representations, the bit mask or the enum. For example, the following + * code produces {@code "true"}.

+ * + *
+	 * NumericShaper ns1 = NumericShaper.getShaper(NumericShaper.ARABIC);
+	 * NumericShaper ns2 = NumericShaper.getShaper(NumericShaper.Range.ARABIC);
+	 * System.out.println(ns1.equals(ns2));
+	 * 
+ * + *
+ * + * @param o the specified object to compare to this {@code NumericShaper} + * @return {@code true} if {@code o} is an instance of {@code NumericShaper} and + * shapes in the same way; {@code false} otherwise. + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) { + if (o != null) { + try { + NumericShaper rhs = (NumericShaper) o; + if (rangeSet != null) { + if (rhs.rangeSet != null) { + return isContextual() == rhs.isContextual() && rangeSet.equals(rhs.rangeSet) + && shapingRange == rhs.shapingRange; + } + return isContextual() == rhs.isContextual() && rangeSet.equals(Range.maskToRangeSet(rhs.mask)) + && shapingRange == Range.indexToRange(rhs.key); + } else if (rhs.rangeSet != null) { + Set rset = Range.maskToRangeSet(mask); + Range srange = Range.indexToRange(key); + return isContextual() == rhs.isContextual() && rset.equals(rhs.rangeSet) + && srange == rhs.shapingRange; + } + return rhs.mask == mask && rhs.key == key; + } catch (ClassCastException e) { + } + } + return false; + } + + /** + * Returns a {@code String} that describes this shaper. This method is used for + * debugging purposes only. + * + * @return a {@code String} describing this shaper. + */ + public String toString() { + StringBuilder buf = new StringBuilder(super.toString()); + + buf.append("[contextual:").append(isContextual()); + + String[] keyNames = null; + if (isContextual()) { + buf.append(", context:"); + buf.append(shapingRange == null ? Range.values()[key] : shapingRange); + } + + if (rangeSet == null) { + buf.append(", range(s): "); + boolean first = true; + for (int i = 0; i < NUM_KEYS; ++i) { + if ((mask & (1 << i)) != 0) { + if (first) { + first = false; + } else { + buf.append(", "); + } + buf.append(Range.values()[i]); + } + } + } else { + buf.append(", range set: ").append(rangeSet); + } + buf.append(']'); + + return buf.toString(); + } + + /** + * Returns the index of the high bit in value (assuming le, actually power of 2 + * >= value). value must be positive. + */ + private static int getHighBit(int value) { + if (value <= 0) { + return -32; + } + + int bit = 0; + + if (value >= 1 << 16) { + value >>= 16; + bit += 16; + } + + if (value >= 1 << 8) { + value >>= 8; + bit += 8; + } + + if (value >= 1 << 4) { + value >>= 4; + bit += 4; + } + + if (value >= 1 << 2) { + value >>= 2; + bit += 2; + } + + if (value >= 1 << 1) { + bit += 1; + } + + return bit; + } + + /** + * fast binary search over subrange of array. + */ + private static int search(int value, int[] array, int start, int length) { + int power = 1 << getHighBit(length); + int extra = length - power; + int probe = power; + int index = start; + + if (value >= array[index + extra]) { + index += extra; + } + + while (probe > 1) { + probe >>= 1; + + if (value >= array[index + probe]) { + index += probe; + } + } + + return index; + } + + /** + * Converts the {@code NumericShaper.Range} enum-based parameters, if any, to + * the bit mask-based counterparts and writes this object to the {@code stream}. + * Any enum constants that have no bit mask-based counterparts are ignored in + * the conversion. + * + * @param stream the output stream to write to + * @throws IOException if an I/O error occurs while writing to {@code stream} + * @since 1.7 + */ + private void writeObject(ObjectOutputStream stream) throws IOException { + if (shapingRange != null) { + int index = Range.toRangeIndex(shapingRange); + if (index >= 0) { + key = index; + } + } + if (rangeSet != null) { + mask |= Range.toRangeMask(rangeSet); + } + stream.defaultWriteObject(); + } +} diff --git a/src/main/java/jdk_internal/bidi/ParseException.java b/src/main/java/jdk_internal/bidi/ParseException.java new file mode 100755 index 00000000..3d3e9d09 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/ParseException.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved + * + * The original version of this source code and documentation is copyrighted + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These + * materials are provided under terms of a License Agreement between Taligent + * and Sun. This technology is protected by multiple US and International + * patents. This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + * + */ + +package jdk_internal.bidi; + +/** + * Signals that an error has been reached unexpectedly while parsing. + * + * @see java.lang.Exception + * @see java.text.Format + * @see java.text.FieldPosition + * @author Mark Davis + * @since 1.1 + */ +public class ParseException extends Exception { + + private static final long serialVersionUID = 2703218443322787634L; + + /** + * Constructs a ParseException with the specified detail message and offset. A + * detail message is a String that describes this particular exception. + * + * @param s the detail message + * @param errorOffset the position where the error is found while parsing. + */ + public ParseException(String s, int errorOffset) { + super(s); + this.errorOffset = errorOffset; + } + + /** + * Returns the position where the error was found. + * + * @return the position where the error was found + */ + public int getErrorOffset() { + return errorOffset; + } + + // ============ privates ============ + /** + * The zero-based character offset into the string being parsed at which the + * error was found during parsing. + * + * @serial + */ + private int errorOffset; +} diff --git a/src/main/java/jdk_internal/bidi/SunNormalizer.java b/src/main/java/jdk_internal/bidi/SunNormalizer.java new file mode 100755 index 00000000..d1f57bca --- /dev/null +++ b/src/main/java/jdk_internal/bidi/SunNormalizer.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk_internal.bidi; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.NormalizerBase; + +/** + * This Normalizer is for Unicode 3.2 support for IDNA only. Developers should + * not use this class. + * + * @since 1.6 + */ +public final class SunNormalizer { + + private SunNormalizer() { + }; + + /** + * Option to select Unicode 3.2 (without corrigendum 4 corrections) for + * normalization. + */ + public static final int UNICODE_3_2 = NormalizerBase.UNICODE_3_2_0_ORIGINAL; + + /** + * Normalize a sequence of char values. The sequence will be normalized + * according to the specified normalization from. + * + * @param src The sequence of char values to normalize. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @param option The normalization option; + * {@link sun.text.Normalizer#UNICODE_3_2} + * @return The normalized String + * @throws NullPointerException If src or form is + * null. + */ + public static String normalize(CharSequence src, Normalizer.Form form, int option) { + return NormalizerBase.normalize(src.toString(), form, option); + }; + + /** + * Determines if the given sequence of char values is normalized. + * + * @param src The sequence of char values to be checked. + * @param form The normalization form; one of + * {@link java.text.Normalizer.Form#NFC}, + * {@link java.text.Normalizer.Form#NFD}, + * {@link java.text.Normalizer.Form#NFKC}, + * {@link java.text.Normalizer.Form#NFKD} + * @param option The normalization option; + * {@link sun.text.Normalizer#UNICODE_3_2} + * @return true if the sequence of char values is normalized; false otherwise. + * @throws NullPointerException If src or form is + * null. + */ + public static boolean isNormalized(CharSequence src, Normalizer.Form form, int option) { + return NormalizerBase.isNormalized(src.toString(), form, option); + } + + /** + * Returns the combining class of the given character + * + * @param ch character to retrieve combining class of + * @return combining class of the given character + */ + public static final int getCombiningClass(int ch) { + return UCharacter.getCombiningClass(ch); + } +} diff --git a/src/main/java/jdk_internal/bidi/TextAttribute.java b/src/main/java/jdk_internal/bidi/TextAttribute.java new file mode 100755 index 00000000..003e85b7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/TextAttribute.java @@ -0,0 +1,1065 @@ +/* + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved + * + * The original version of this source code and documentation is + * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary + * of IBM. These materials are provided under terms of a License + * Agreement between Taligent and Sun. This technology is protected + * by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + * + */ + +package jdk_internal.bidi; + +import java.io.InvalidObjectException; +import java.util.HashMap; +import java.util.Map; + +import jdk_internal.bidi.AttributedCharacterIterator.Attribute; + +/** + * The {@code TextAttribute} class defines attribute keys and attribute values + * used for text rendering. + *

+ * {@code TextAttribute} instances are used as attribute keys to identify + * attributes in {@link java.awt.Font Font}, {@link java.awt.font.TextLayout + * TextLayout}, {@link java.text.AttributedCharacterIterator + * AttributedCharacterIterator}, and other classes handling text attributes. + * Other constants defined in this class can be used as attribute values. + *

+ * For each text attribute, the documentation provides: + *

    + *
  • the type of its value, + *
  • the relevant predefined constants, if any + *
  • the default effect if the attribute is absent + *
  • the valid values if there are limitations + *
  • a description of the effect. + *
+ * + *

Values

+ *
    + *
  • The values of attributes must always be immutable. + *
  • Where value limitations are given, any value outside of that set is + * reserved for future use; the value will be treated as the default. + *
  • The value {@code null} is treated the same as the default value and + * results in the default behavior. + *
  • If the value is not of the proper type, the attribute will be ignored. + *
  • The identity of the value does not matter, only the actual value. For + * example, {@code TextAttribute.WEIGHT_BOLD} and {@code Float.valueOf(2.0f)} + * indicate the same {@code WEIGHT}. + *
  • Attribute values of type {@code Number} (used for {@code WEIGHT}, + * {@code WIDTH}, {@code POSTURE}, {@code SIZE}, {@code JUSTIFICATION}, and + * {@code TRACKING}) can vary along their natural range and are not restricted + * to the predefined constants. {@code Number.floatValue()} is used to get the + * actual value from the {@code Number}. + *
  • The values for {@code WEIGHT}, {@code WIDTH}, and {@code POSTURE} are + * interpolated by the system, which can select the 'nearest available' font or + * use other techniques to approximate the user's request. + * + *
+ * + *

Summary of attributes

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Key, value type, principal constants, and default value behavior of + * all TextAttributes
Key + * Value Type + * Principal Constants + * Default Value
{@link #FAMILY} + * String + * See Font {@link java.awt.Font#DIALOG DIALOG}, + * {@link java.awt.Font#DIALOG_INPUT DIALOG_INPUT},
+ * {@link java.awt.Font#SERIF SERIF}, {@link java.awt.Font#SANS_SERIF + * SANS_SERIF}, and {@link java.awt.Font#MONOSPACED MONOSPACED}. + *
"Default" (use platform default) + *
{@link #WEIGHT} + * Number + * WEIGHT_REGULAR, WEIGHT_BOLD + * WEIGHT_REGULAR + *
{@link #WIDTH} + * Number + * WIDTH_CONDENSED, WIDTH_REGULAR,
+ * WIDTH_EXTENDED + *
WIDTH_REGULAR + *
{@link #POSTURE} + * Number + * POSTURE_REGULAR, POSTURE_OBLIQUE + * POSTURE_REGULAR + *
{@link #SIZE} + * Number + * none + * 12.0 + *
{@link #TRANSFORM} + * {@link TransformAttribute} + * See TransformAttribute {@link TransformAttribute#IDENTITY IDENTITY} + * TransformAttribute.IDENTITY + *
{@link #SUPERSCRIPT} + * Integer + * SUPERSCRIPT_SUPER, SUPERSCRIPT_SUB + * 0 (use the standard glyphs and metrics) + *
{@link #FONT} + * {@link java.awt.Font} + * none + * null (do not override font resolution) + *
{@link #CHAR_REPLACEMENT} + * {@link GraphicAttribute} + * none + * null (draw text using font glyphs) + *
{@link #FOREGROUND} + * {@link java.awt.Paint} + * none + * null (use current graphics paint) + *
{@link #BACKGROUND} + * {@link java.awt.Paint} + * none + * null (do not render background) + *
{@link #UNDERLINE} + * Integer + * UNDERLINE_ON + * -1 (do not render underline) + *
{@link #STRIKETHROUGH} + * Boolean + * STRIKETHROUGH_ON + * false (do not render strikethrough) + *
{@link #RUN_DIRECTION} + * Boolean + * RUN_DIRECTION_LTR
+ * RUN_DIRECTION_RTL + *
null (use {@link java.text.Bidi} standard default) + *
{@link #BIDI_EMBEDDING} + * Integer + * none + * 0 (use base line direction) + *
{@link #JUSTIFICATION} + * Number + * JUSTIFICATION_FULL + * JUSTIFICATION_FULL + *
{@link #INPUT_METHOD_HIGHLIGHT} + * {@link java.awt.im.InputMethodHighlight},
+ * {@link java.text.Annotation} + *
(see class) + * null (do not apply input highlighting) + *
{@link #INPUT_METHOD_UNDERLINE} + * Integer + * UNDERLINE_LOW_ONE_PIXEL,
+ * UNDERLINE_LOW_TWO_PIXEL + *
-1 (do not render underline) + *
{@link #SWAP_COLORS} + * Boolean + * SWAP_COLORS_ON + * false (do not swap colors) + *
{@link #NUMERIC_SHAPING} + * {@link java.awt.font.NumericShaper} + * none + * null (do not shape digits) + *
{@link #KERNING} + * Integer + * KERNING_ON + * 0 (do not request kerning) + *
{@link #LIGATURES} + * Integer + * LIGATURES_ON + * 0 (do not form optional ligatures) + *
{@link #TRACKING} + * Number + * TRACKING_LOOSE, TRACKING_TIGHT + * 0 (do not add tracking) + *
+ * + * @see java.awt.Font + * @see java.awt.font.TextLayout + * @see java.text.AttributedCharacterIterator + */ +public final class TextAttribute extends Attribute { + + // table of all instances in this class, used by readResolve + private static final Map instanceMap = new HashMap(29); + + /** + * Constructs a {@code TextAttribute} with the specified name. + * + * @param name the attribute name to assign to this {@code TextAttribute} + */ + protected TextAttribute(String name) { + super(name); + if (this.getClass() == TextAttribute.class) { + instanceMap.put(name, this); + } + } + + /** + * Resolves instances being deserialized to the predefined constants. + */ + protected Object readResolve() throws InvalidObjectException { + if (this.getClass() != TextAttribute.class) { + throw new InvalidObjectException("subclass didn't correctly implement readResolve"); + } + + TextAttribute instance = instanceMap.get(getName()); + if (instance != null) { + return instance; + } else { + throw new InvalidObjectException("unknown attribute name"); + } + } + + /** + * Use serialVersionUID from JDK 1.2 for interoperability. 1.2 will throw an + * InvalidObjectException if ever asked to deserialize INPUT_METHOD_UNDERLINE. + * This shouldn't happen in real life. + */ + private static final long serialVersionUID = 7744112784117861702L; + + // + // For use with Font. + // + + /** + * Attribute key for the font name. Values are instances of + * {@code String}. The default value is {@code "Default"}, which causes + * the platform default font family to be used. + * + *

+ * The {@code Font} class defines constants for the logical font names + * {@link java.awt.Font#DIALOG DIALOG}, {@link java.awt.Font#DIALOG_INPUT + * DIALOG_INPUT}, {@link java.awt.Font#SANS_SERIF SANS_SERIF}, + * {@link java.awt.Font#SERIF SERIF}, and {@link java.awt.Font#MONOSPACED + * MONOSPACED}. + * + *

+ * This defines the value passed as {@code name} to the {@code Font} + * constructor. Both logical and physical font names are allowed. If a font with + * the requested name is not found, the default font is used. + * + *

+ * Note: This attribute is unfortunately misnamed, as it specifies the + * face name and not just the family. Thus values such as "Lucida Sans Bold" + * will select that face if it exists. Note, though, that if the requested face + * does not exist, the default will be used with regular weight. The + * "Bold" in the name is part of the face name, not a separate request that the + * font's weight be bold. + *

+ */ + public static final TextAttribute FAMILY = new TextAttribute("family"); + + /** + * Attribute key for the weight of a font. Values are instances of + * {@code Number}. The default value is {@code WEIGHT_REGULAR}. + * + *

+ * Several constant values are provided, see {@link #WEIGHT_EXTRA_LIGHT}, + * {@link #WEIGHT_LIGHT}, {@link #WEIGHT_DEMILIGHT}, {@link #WEIGHT_REGULAR}, + * {@link #WEIGHT_SEMIBOLD}, {@link #WEIGHT_MEDIUM}, {@link #WEIGHT_DEMIBOLD}, + * {@link #WEIGHT_BOLD}, {@link #WEIGHT_HEAVY}, {@link #WEIGHT_EXTRABOLD}, and + * {@link #WEIGHT_ULTRABOLD}. The value {@code WEIGHT_BOLD} corresponds to the + * style value {@code Font.BOLD} as passed to the {@code Font} constructor. + * + *

+ * The value is roughly the ratio of the stem width to that of the regular + * weight. + * + *

+ * The system can interpolate the provided value. + */ + public static final TextAttribute WEIGHT = new TextAttribute("weight"); + + /** + * The lightest predefined weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_EXTRA_LIGHT = Float.valueOf(0.5f); + + /** + * The standard light weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_LIGHT = Float.valueOf(0.75f); + + /** + * An intermediate weight between {@code WEIGHT_LIGHT} and + * {@code WEIGHT_STANDARD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_DEMILIGHT = Float.valueOf(0.875f); + + /** + * The standard weight. This is the default value for {@code WEIGHT}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_REGULAR = Float.valueOf(1.0f); + + /** + * A moderately heavier weight than {@code WEIGHT_REGULAR}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_SEMIBOLD = Float.valueOf(1.25f); + + /** + * An intermediate weight between {@code WEIGHT_REGULAR} and + * {@code WEIGHT_BOLD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_MEDIUM = Float.valueOf(1.5f); + + /** + * A moderately lighter weight than {@code WEIGHT_BOLD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_DEMIBOLD = Float.valueOf(1.75f); + + /** + * The standard bold weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_BOLD = Float.valueOf(2.0f); + + /** + * A moderately heavier weight than {@code WEIGHT_BOLD}. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_HEAVY = Float.valueOf(2.25f); + + /** + * An extra heavy weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_EXTRABOLD = Float.valueOf(2.5f); + + /** + * The heaviest predefined weight. + * + * @see #WEIGHT + */ + public static final Float WEIGHT_ULTRABOLD = Float.valueOf(2.75f); + + /** + * Attribute key for the width of a font. Values are instances of + * {@code Number}. The default value is {@code WIDTH_REGULAR}. + * + *

+ * Several constant values are provided, see {@link #WIDTH_CONDENSED}, + * {@link #WIDTH_SEMI_CONDENSED}, {@link #WIDTH_REGULAR}, + * {@link #WIDTH_SEMI_EXTENDED}, {@link #WIDTH_EXTENDED}. + * + *

+ * The value is roughly the ratio of the advance width to that of the regular + * width. + * + *

+ * The system can interpolate the provided value. + */ + public static final TextAttribute WIDTH = new TextAttribute("width"); + + /** + * The most condensed predefined width. + * + * @see #WIDTH + */ + public static final Float WIDTH_CONDENSED = Float.valueOf(0.75f); + + /** + * A moderately condensed width. + * + * @see #WIDTH + */ + public static final Float WIDTH_SEMI_CONDENSED = Float.valueOf(0.875f); + + /** + * The standard width. This is the default value for {@code WIDTH}. + * + * @see #WIDTH + */ + public static final Float WIDTH_REGULAR = Float.valueOf(1.0f); + + /** + * A moderately extended width. + * + * @see #WIDTH + */ + public static final Float WIDTH_SEMI_EXTENDED = Float.valueOf(1.25f); + + /** + * The most extended predefined width. + * + * @see #WIDTH + */ + public static final Float WIDTH_EXTENDED = Float.valueOf(1.5f); + + /** + * Attribute key for the posture of a font. Values are instances of + * {@code Number}. The default value is {@code POSTURE_REGULAR}. + * + *

+ * Two constant values are provided, {@link #POSTURE_REGULAR} and + * {@link #POSTURE_OBLIQUE}. The value {@code POSTURE_OBLIQUE} corresponds to + * the style value {@code Font.ITALIC} as passed to the {@code Font} + * constructor. + * + *

+ * The value is roughly the slope of the stems of the font, expressed as the run + * over the rise. Positive values lean right. + * + *

+ * The system can interpolate the provided value. + * + *

+ * This will affect the font's italic angle as returned by + * {@code Font.getItalicAngle}. + * + * @see java.awt.Font#getItalicAngle() + */ + public static final TextAttribute POSTURE = new TextAttribute("posture"); + + /** + * The standard posture, upright. This is the default value for {@code POSTURE}. + * + * @see #POSTURE + */ + public static final Float POSTURE_REGULAR = Float.valueOf(0.0f); + + /** + * The standard italic posture. + * + * @see #POSTURE + */ + public static final Float POSTURE_OBLIQUE = Float.valueOf(0.20f); + + /** + * Attribute key for the font size. Values are instances of + * {@code Number}. The default value is 12pt. + * + *

+ * This corresponds to the {@code size} parameter to the {@code Font} + * constructor. + * + *

+ * Very large or small sizes will impact rendering performance, and the + * rendering system might not render text at these sizes. Negative sizes are + * illegal and result in the default size. + * + *

+ * Note that the appearance and metrics of a 12pt font with a 2x transform might + * be different than that of a 24 point font with no transform. + */ + public static final TextAttribute SIZE = new TextAttribute("size"); + + /** + * Attribute key for the transform of a font. Values are instances of + * {@code TransformAttribute}. The default value is + * {@code TransformAttribute.IDENTITY}. + * + *

+ * The {@code TransformAttribute} class defines the constant + * {@link TransformAttribute#IDENTITY IDENTITY}. + * + *

+ * This corresponds to the transform passed to + * {@code Font.deriveFont(AffineTransform)}. Since that transform is mutable and + * {@code TextAttribute} values must not be, the {@code TransformAttribute} + * wrapper class is used. + * + *

+ * The primary intent is to support scaling and skewing, though other effects + * are possible. + *

+ * + *

+ * Some transforms will cause the baseline to be rotated and/or shifted. The + * text and the baseline are transformed together so that the text follows the + * new baseline. For example, with text on a horizontal baseline, the new + * baseline follows the direction of the unit x vector passed through the + * transform. Text metrics are measured against this new baseline. So, for + * example, with other things being equal, text rendered with a rotated + * TRANSFORM and an unrotated TRANSFORM will measure as having the same ascent, + * descent, and advance. + *

+ * + *

+ * In styled text, the baselines for each such run are aligned one after the + * other to potentially create a non-linear baseline for the entire run of text. + * For more information, see {@link TextLayout#getLayoutPath}. + *

+ * + * @see TransformAttribute + * @see java.awt.geom.AffineTransform + */ + public static final TextAttribute TRANSFORM = new TextAttribute("transform"); + + /** + * Attribute key for superscripting and subscripting. Values are instances of + * {@code Integer}. The default value is 0, which means that no + * superscript or subscript is used. + * + *

+ * Two constant values are provided, see {@link #SUPERSCRIPT_SUPER} and + * {@link #SUPERSCRIPT_SUB}. These have the values 1 and -1 respectively. Values + * of greater magnitude define greater levels of superscript or subscripting, + * for example, 2 corresponds to super-superscript, 3 to + * super-super-superscript, and similarly for negative values and subscript, up + * to a level of 7 (or -7). Values beyond this range are reserved; behavior is + * platform-dependent. + * + *

+ * {@code SUPERSCRIPT} can impact the ascent and descent of a font. The ascent + * and descent can never become negative, however. + */ + public static final TextAttribute SUPERSCRIPT = new TextAttribute("superscript"); + + /** + * Standard superscript. + * + * @see #SUPERSCRIPT + */ + public static final Integer SUPERSCRIPT_SUPER = Integer.valueOf(1); + + /** + * Standard subscript. + * + * @see #SUPERSCRIPT + */ + public static final Integer SUPERSCRIPT_SUB = Integer.valueOf(-1); + + /** + * Attribute key used to provide the font to use to render text. Values are + * instances of {@link java.awt.Font}. The default value is null, indicating + * that normal resolution of a {@code Font} from attributes should be performed. + * + *

+ * {@code TextLayout} and {@code AttributedCharacterIterator} work in terms of + * {@code Maps} of {@code TextAttributes}. Normally, all the attributes are + * examined and used to select and configure a {@code Font} instance. If a + * {@code FONT} attribute is present, though, its associated {@code Font} will + * be used. This provides a way for users to override the resolution of font + * attributes into a {@code Font}, or force use of a particular {@code Font} + * instance. This also allows users to specify subclasses of {@code Font} in + * cases where a {@code Font} can be subclassed. + * + *

+ * {@code FONT} is used for special situations where clients already have a + * {@code Font} instance but still need to use {@code Map}-based APIs. + * Typically, there will be no other attributes in the {@code Map} except the + * {@code FONT} attribute. With {@code Map}-based APIs the common case is to + * specify all attributes individually, so {@code FONT} is not needed or + * desirable. + * + *

+ * However, if both {@code FONT} and other attributes are present in the + * {@code Map}, the rendering system will merge the attributes defined in the + * {@code Font} with the additional attributes. This merging process classifies + * {@code TextAttributes} into two groups. One group, the 'primary' group, is + * considered fundamental to the selection and metric behavior of a font. These + * attributes are {@code FAMILY}, {@code WEIGHT}, {@code WIDTH}, + * {@code POSTURE}, {@code SIZE}, {@code TRANSFORM}, {@code SUPERSCRIPT}, and + * {@code TRACKING}. The other group, the 'secondary' group, consists of all + * other defined attributes, with the exception of {@code FONT} itself. + * + *

+ * To generate the new {@code Map}, first the {@code Font} is obtained from the + * {@code FONT} attribute, and all of its attributes extracted into a + * new {@code Map}. Then only the secondary attributes from the + * original {@code Map} are added to those in the new {@code Map}. Thus the + * values of primary attributes come solely from the {@code Font}, and the + * values of secondary attributes originate with the {@code Font} but can be + * overridden by other values in the {@code Map}. + * + *

+ * Note:{@code Font's Map}-based constructor and {@code deriveFont} + * methods do not process the {@code FONT} attribute, as these are used to + * create new {@code Font} objects. Instead, {@link java.awt.Font#getFont(Map) + * Font.getFont(Map)} should be used to handle the {@code FONT} attribute. + * + * @see java.awt.Font + */ + public static final TextAttribute FONT = new TextAttribute("font"); + + /** + * Attribute key for a user-defined glyph to display in lieu of the font's + * standard glyph for a character. Values are instances of GraphicAttribute. The + * default value is null, indicating that the standard glyphs provided by the + * font should be used. + * + *

+ * This attribute is used to reserve space for a graphic or other component + * embedded in a line of text. It is required for correct positioning of + * 'inline' components within a line when bidirectional reordering (see + * {@link java.text.Bidi}) is performed. Each character (Unicode code point) + * will be rendered using the provided GraphicAttribute. Typically, the + * characters to which this attribute is applied should be + * \uFFFC. + * + *

+ * The GraphicAttribute determines the logical and visual bounds of the text; + * the actual Font values are ignored. + * + * @see GraphicAttribute + */ + public static final TextAttribute CHAR_REPLACEMENT = new TextAttribute("char_replacement"); + + // + // Adornments added to text. + // + + /** + * Attribute key for the paint used to render the text. Values are instances of + * {@code Paint}. The default value is null, indicating that the + * {@code Paint} set on the {@code Graphics2D} at the time of rendering is used. + * + *

+ * Glyphs will be rendered using this {@code Paint} regardless of the + * {@code Paint} value set on the {@code Graphics} (but see + * {@link #SWAP_COLORS}). + * + * @see java.awt.Paint + * @see #SWAP_COLORS + */ + public static final TextAttribute FOREGROUND = new TextAttribute("foreground"); + + /** + * Attribute key for the paint used to render the background of the text. Values + * are instances of {@code Paint}. The default value is null, indicating + * that the background should not be rendered. + * + *

+ * The logical bounds of the text will be filled using this {@code Paint}, and + * then the text will be rendered on top of it (but see {@link #SWAP_COLORS}). + * + *

+ * The visual bounds of the text is extended to include the logical bounds, if + * necessary. The outline is not affected. + * + * @see java.awt.Paint + * @see #SWAP_COLORS + */ + public static final TextAttribute BACKGROUND = new TextAttribute("background"); + + /** + * Attribute key for underline. Values are instances of {@code Integer}. + * The default value is -1, which means no underline. + * + *

+ * The constant value {@link #UNDERLINE_ON} is provided. + * + *

+ * The underline affects both the visual bounds and the outline of the text. + */ + public static final TextAttribute UNDERLINE = new TextAttribute("underline"); + + /** + * Standard underline. + * + * @see #UNDERLINE + */ + public static final Integer UNDERLINE_ON = Integer.valueOf(0); + + /** + * Attribute key for strikethrough. Values are instances of + * {@code Boolean}. The default value is {@code false}, which means no + * strikethrough. + * + *

+ * The constant value {@link #STRIKETHROUGH_ON} is provided. + * + *

+ * The strikethrough affects both the visual bounds and the outline of the text. + */ + public static final TextAttribute STRIKETHROUGH = new TextAttribute("strikethrough"); + + /** + * A single strikethrough. + * + * @see #STRIKETHROUGH + */ + public static final Boolean STRIKETHROUGH_ON = Boolean.TRUE; + + // + // Attributes use to control layout of text on a line. + // + + /** + * Attribute key for the run direction of the line. Values are instances of + * {@code Boolean}. The default value is null, which indicates that the + * standard Bidi algorithm for determining run direction should be used with the + * value {@link java.text.Bidi#DIRECTION_DEFAULT_LEFT_TO_RIGHT}. + * + *

+ * The constants {@link #RUN_DIRECTION_RTL} and {@link #RUN_DIRECTION_LTR} are + * provided. + * + *

+ * This determines the value passed to the {@link java.text.Bidi} constructor to + * select the primary direction of the text in the paragraph. + * + *

+ * Note: This attribute should have the same value for all the text in + * a paragraph, otherwise the behavior is undetermined. + * + * @see java.text.Bidi + */ + public static final TextAttribute RUN_DIRECTION = new TextAttribute("run_direction"); + + /** + * Left-to-right run direction. + * + * @see #RUN_DIRECTION + */ + public static final Boolean RUN_DIRECTION_LTR = Boolean.FALSE; + + /** + * Right-to-left run direction. + * + * @see #RUN_DIRECTION + */ + public static final Boolean RUN_DIRECTION_RTL = Boolean.TRUE; + + /** + * Attribute key for the embedding level of the text. Values are instances of + * {@code Integer}. The default value is {@code null}, indicating that + * the Bidirectional algorithm should run without explicit embeddings. + * + *

+ * Positive values 1 through 61 are embedding levels, negative values + * -1 through -61 are override levels. The value 0 means that the base + * line direction is used. These levels are passed in the embedding levels array + * to the {@link java.text.Bidi} constructor. + * + *

+ * Note: When this attribute is present anywhere in a paragraph, then + * any Unicode bidi control characters (RLO, LRO, RLE, LRE, and PDF) in the + * paragraph are disregarded, and runs of text where this attribute is not + * present are treated as though it were present and had the value 0. + * + * @see java.text.Bidi + */ + public static final TextAttribute BIDI_EMBEDDING = new TextAttribute("bidi_embedding"); + + /** + * Attribute key for the justification of a paragraph. Values are instances of + * {@code Number}. The default value is 1, indicating that justification + * should use the full width provided. Values are pinned to the range [0..1]. + * + *

+ * The constants {@link #JUSTIFICATION_FULL} and {@link #JUSTIFICATION_NONE} are + * provided. + * + *

+ * Specifies the fraction of the extra space to use when justification is + * requested on a {@code TextLayout}. For example, if the line is 50 points wide + * and it is requested to justify to 70 points, a value of 0.75 will pad to use + * three-quarters of the remaining space, or 15 points, so that the resulting + * line will be 65 points in length. + * + *

+ * Note: This should have the same value for all the text in a + * paragraph, otherwise the behavior is undetermined. + * + * @see TextLayout#getJustifiedLayout + */ + public static final TextAttribute JUSTIFICATION = new TextAttribute("justification"); + + /** + * Justify the line to the full requested width. This is the default value for + * {@code JUSTIFICATION}. + * + * @see #JUSTIFICATION + */ + public static final Float JUSTIFICATION_FULL = Float.valueOf(1.0f); + + /** + * Do not allow the line to be justified. + * + * @see #JUSTIFICATION + */ + public static final Float JUSTIFICATION_NONE = Float.valueOf(0.0f); + + // + // For use by input method. + // + + /** + * Attribute key for input method highlight styles. + * + *

+ * Values are instances of {@link java.awt.im.InputMethodHighlight} or + * {@link java.text.Annotation}. The default value is {@code null}, which means + * that input method styles should not be applied before rendering. + * + *

+ * If adjacent runs of text with the same {@code InputMethodHighlight} need to + * be rendered separately, the {@code InputMethodHighlights} should be wrapped + * in {@code Annotation} instances. + * + *

+ * Input method highlights are used while text is being composed by an input + * method. Text editing components should retain them even if they generally + * only deal with unstyled text, and make them available to the drawing + * routines. + * + * @see java.awt.Font + * @see java.awt.im.InputMethodHighlight + * @see java.text.Annotation + */ + public static final TextAttribute INPUT_METHOD_HIGHLIGHT = new TextAttribute("input method highlight"); + + /** + * Attribute key for input method underlines. Values are instances of + * {@code Integer}. The default value is {@code -1}, which means no + * underline. + * + *

+ * Several constant values are provided, see {@link #UNDERLINE_LOW_ONE_PIXEL}, + * {@link #UNDERLINE_LOW_TWO_PIXEL}, {@link #UNDERLINE_LOW_DOTTED}, + * {@link #UNDERLINE_LOW_GRAY}, and {@link #UNDERLINE_LOW_DASHED}. + * + *

+ * This may be used in conjunction with {@link #UNDERLINE} if desired. The + * primary purpose is for use by input methods. Other use of these underlines + * for simple ornamentation might confuse users. + * + *

+ * The input method underline affects both the visual bounds and the outline of + * the text. + * + * @since 1.3 + */ + public static final TextAttribute INPUT_METHOD_UNDERLINE = new TextAttribute("input method underline"); + + /** + * Single pixel solid low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_ONE_PIXEL = Integer.valueOf(1); + + /** + * Double pixel solid low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_TWO_PIXEL = Integer.valueOf(2); + + /** + * Single pixel dotted low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_DOTTED = Integer.valueOf(3); + + /** + * Double pixel gray low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_GRAY = Integer.valueOf(4); + + /** + * Single pixel dashed low underline. + * + * @see #INPUT_METHOD_UNDERLINE + * @since 1.3 + */ + public static final Integer UNDERLINE_LOW_DASHED = Integer.valueOf(5); + + /** + * Attribute key for swapping foreground and background {@code Paints}. Values + * are instances of {@code Boolean}. The default value is {@code false}, + * which means do not swap colors. + * + *

+ * The constant value {@link #SWAP_COLORS_ON} is defined. + * + *

+ * If the {@link #FOREGROUND} attribute is set, its {@code Paint} will be used + * as the background, otherwise the {@code Paint} currently on the + * {@code Graphics} will be used. If the {@link #BACKGROUND} attribute is set, + * its {@code Paint} will be used as the foreground, otherwise the system will + * find a contrasting color to the (resolved) background so that the text will + * be visible. + * + * @see #FOREGROUND + * @see #BACKGROUND + */ + public static final TextAttribute SWAP_COLORS = new TextAttribute("swap_colors"); + + /** + * Swap foreground and background. + * + * @see #SWAP_COLORS + * @since 1.3 + */ + public static final Boolean SWAP_COLORS_ON = Boolean.TRUE; + + /** + * Attribute key for converting ASCII decimal digits to other decimal ranges. + * Values are instances of {@link NumericShaper}. The default is {@code null}, + * which means do not perform numeric shaping. + * + *

+ * When a numeric shaper is defined, the text is first processed by the shaper + * before any other analysis of the text is performed. + * + *

+ * Note: This should have the same value for all the text in the + * paragraph, otherwise the behavior is undetermined. + * + * @see NumericShaper + * @since 1.4 + */ + public static final TextAttribute NUMERIC_SHAPING = new TextAttribute("numeric_shaping"); + + /** + * Attribute key to request kerning. Values are instances of + * {@code Integer}. The default value is {@code 0}, which does not + * request kerning. + * + *

+ * The constant value {@link #KERNING_ON} is provided. + * + *

+ * The default advances of single characters are not appropriate for some + * character sequences, for example "To" or "AWAY". Without kerning the adjacent + * characters appear to be separated by too much space. Kerning causes selected + * sequences of characters to be spaced differently for a more pleasing visual + * appearance. + * + * @since 1.6 + */ + public static final TextAttribute KERNING = new TextAttribute("kerning"); + + /** + * Request standard kerning. + * + * @see #KERNING + * @since 1.6 + */ + public static final Integer KERNING_ON = Integer.valueOf(1); + + /** + * Attribute key for enabling optional ligatures. Values are instances of + * {@code Integer}. The default value is {@code 0}, which means do not + * use optional ligatures. + * + *

+ * The constant value {@link #LIGATURES_ON} is defined. + * + *

+ * Ligatures required by the writing system are always enabled. + * + * @since 1.6 + */ + public static final TextAttribute LIGATURES = new TextAttribute("ligatures"); + + /** + * Request standard optional ligatures. + * + * @see #LIGATURES + * @since 1.6 + */ + public static final Integer LIGATURES_ON = Integer.valueOf(1); + + /** + * Attribute key to control tracking. Values are instances of + * {@code Number}. The default value is {@code 0}, which means no + * additional tracking. + * + *

+ * The constant values {@link #TRACKING_TIGHT} and {@link #TRACKING_LOOSE} are + * provided. + * + *

+ * The tracking value is multiplied by the font point size and passed through + * the font transform to determine an additional amount to add to the advance of + * each glyph cluster. Positive tracking values will inhibit formation of + * optional ligatures. Tracking values are typically between {@code -0.1} and + * {@code 0.3}; values outside this range are generally not desirable. + * + * @since 1.6 + */ + public static final TextAttribute TRACKING = new TextAttribute("tracking"); + + /** + * Perform tight tracking. + * + * @see #TRACKING + * @since 1.6 + */ + public static final Float TRACKING_TIGHT = Float.valueOf(-.04f); + + /** + * Perform loose tracking. + * + * @see #TRACKING + * @since 1.6 + */ + public static final Float TRACKING_LOOSE = Float.valueOf(.04f); +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/BMPSet.java b/src/main/java/jdk_internal/bidi/icu/impl/BMPSet.java new file mode 100755 index 00000000..c7a9999d --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/BMPSet.java @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import jdk_internal.bidi.icu.text.UnicodeSet.SpanCondition; +import jdk_internal.bidi.icu.util.OutputInt; + +/** + * Helper class for frozen UnicodeSets, implements contains() and span() + * optimized for BMP code points. + * + * Latin-1: Look up bytes. 2-byte characters: Bits organized vertically. 3-byte + * characters: Use zero/one/mixed data per 64-block in U+0000..U+FFFF, with + * mixed for illegal ranges. Supplementary characters: Call contains() on the + * parent set. + */ +public final class BMPSet { + + /** + * One boolean ('true' or 'false') per Latin-1 character. + */ + private boolean[] latin1Contains; + + /** + * One bit per code point from U+0000..U+07FF. The bits are organized + * vertically; consecutive code points correspond to the same bit positions in + * consecutive table words. With code point parts lead=c{10..6} trail=c{5..0} it + * is set.contains(c)==(table7FF[trail] bit lead) + * + * Bits for 0..7F (non-shortest forms) are set to the result of contains(FFFD) + * for faster validity checking at runtime. + */ + private int[] table7FF; + + /** + * One bit per 64 BMP code points. The bits are organized vertically; + * consecutive 64-code point blocks correspond to the same bit position in + * consecutive table words. With code point parts lead=c{15..12} t1=c{11..6} + * test bits (lead+16) and lead in bmpBlockBits[t1]. If the upper bit is 0, then + * the lower bit indicates if contains(c) for all code points in the 64-block. + * If the upper bit is 1, then the block is mixed and set.contains(c) must be + * called. + * + * Bits for 0..7FF (non-shortest forms) and D800..DFFF are set to the result of + * contains(FFFD) for faster validity checking at runtime. + */ + private int[] bmpBlockBits; + + /** + * Inversion list indexes for restricted binary searches in findCodePoint(), + * from findCodePoint(U+0800, U+1000, U+2000, .., U+F000, U+10000). U+0800 is + * the first 3-byte-UTF-8 code point. Code points below U+0800 are always looked + * up in the bit tables. The last pair of indexes is for finding supplementary + * code points. + */ + private int[] list4kStarts; + + /** + * The inversion list of the parent set, for the slower contains() + * implementation for mixed BMP blocks and for supplementary code points. The + * list is terminated with list[listLength-1]=0x110000. + */ + private final int[] list; + private final int listLength; // length used; list may be longer to minimize reallocs + + public BMPSet(final int[] parentList, int parentListLength) { + list = parentList; + listLength = parentListLength; + latin1Contains = new boolean[0x100]; + table7FF = new int[64]; + bmpBlockBits = new int[64]; + list4kStarts = new int[18]; + + /* + * Set the list indexes for binary searches for U+0800, U+1000, U+2000, .., + * U+F000, U+10000. U+0800 is the first 3-byte-UTF-8 code point. Lower code + * points are looked up in the bit tables. The last pair of indexes is for + * finding supplementary code points. + */ + list4kStarts[0] = findCodePoint(0x800, 0, listLength - 1); + int i; + for (i = 1; i <= 0x10; ++i) { + list4kStarts[i] = findCodePoint(i << 12, list4kStarts[i - 1], listLength - 1); + } + list4kStarts[0x11] = listLength - 1; + + initBits(); + } + + public boolean contains(int c) { + if (c <= 0xff) { + return (latin1Contains[c]); + } else if (c <= 0x7ff) { + return ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0); + } else if (c < 0xd800 || (c >= 0xe000 && c <= 0xffff)) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + return (0 != twoBits); + } else { + // Look up the code point in its 4k block of code points. + return containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1]); + } + } else if (c <= 0x10ffff) { + // surrogate or supplementary code point + return containsSlow(c, list4kStarts[0xd], list4kStarts[0x11]); + } else { + // Out-of-range code points get false, consistent with long-standing + // behavior of UnicodeSet.contains(c). + return false; + } + } + + /** + * Span the initial substring for which each character c has + * spanCondition==contains(c). It must be spanCondition==0 or 1. + * + * @param start The start index + * @param outCount If not null: Receives the number of code points in the span. + * @return the limit (exclusive end) of the span + * + * NOTE: to reduce the overhead of function call to contains(c), it is + * manually inlined here. Check for sufficient length for trail unit for + * each surrogate pair. Handle single surrogates as surrogate code + * points as usual in ICU. + */ + public final int span(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + char c, c2; + int i = start; + int limit = s.length(); + int numSupplementary = 0; + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 + || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } else { + // span not + while (i < limit) { + c = s.charAt(i); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || c >= 0xdc00 || (i + 1) == limit || (c2 = s.charAt(i + 1)) < 0xdc00 + || c2 >= 0xe000) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + ++numSupplementary; + ++i; + } + ++i; + } + } + if (outCount != null) { + int spanLength = i - start; + outCount.value = spanLength - numSupplementary; // number of code points + } + return i; + } + + /** + * Symmetrical with span(). Span the trailing substring for which each character + * c has spanCondition==contains(c). It must be s.length >= limit and + * spanCondition==0 or 1. + * + * @return The string index which starts the span (i.e. inclusive). + */ + public final int spanBack(CharSequence s, int limit, SpanCondition spanCondition) { + char c, c2; + + if (SpanCondition.NOT_CONTAINED != spanCondition) { + // span + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (!latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) == 0) { + break; + } + } else if (c < 0xd800 || c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 + || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits == 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (!containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (!containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } else { + // span not + for (;;) { + c = s.charAt(--limit); + if (c <= 0xff) { + if (latin1Contains[c]) { + break; + } + } else if (c <= 0x7ff) { + if ((table7FF[c & 0x3f] & (1 << (c >> 6))) != 0) { + break; + } + } else if (c < 0xd800 || c < 0xdc00 || 0 == limit || (c2 = s.charAt(limit - 1)) < 0xd800 + || c2 >= 0xdc00) { + int lead = c >> 12; + int twoBits = (bmpBlockBits[(c >> 6) & 0x3f] >> lead) & 0x10001; + if (twoBits <= 1) { + // All 64 code points with the same bits 15..6 + // are either in the set or not. + if (twoBits != 0) { + break; + } + } else { + // Look up the code point in its 4k block of code points. + if (containsSlow(c, list4kStarts[lead], list4kStarts[lead + 1])) { + break; + } + } + } else { + // surrogate pair + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + if (containsSlow(supplementary, list4kStarts[0x10], list4kStarts[0x11])) { + break; + } + --limit; + } + if (0 == limit) { + return 0; + } + } + } + return limit + 1; + } + + /** + * Set bits in a bit rectangle in "vertical" bit organization. + * start> 6; // Named for UTF-8 2-byte lead byte with upper 5 bits. + int trail = start & 0x3f; // Named for UTF-8 2-byte trail byte with lower 6 bits. + + // Set one bit indicating an all-one block. + int bits = 1 << lead; + if ((start + 1) == limit) { // Single-character shortcut. + table[trail] |= bits; + return; + } + + int limitLead = limit >> 6; + int limitTrail = limit & 0x3f; + + if (lead == limitLead) { + // Partial vertical bit column. + while (trail < limitTrail) { + table[trail++] |= bits; + } + } else { + // Partial vertical bit column, + // followed by a bit rectangle, + // followed by another partial vertical bit column. + if (trail > 0) { + do { + table[trail++] |= bits; + } while (trail < 64); + ++lead; + } + if (lead < limitLead) { + bits = ~((1 << lead) - 1); + if (limitLead < 0x20) { + bits &= (1 << limitLead) - 1; + } + for (trail = 0; trail < 64; ++trail) { + table[trail] |= bits; + } + } + // limit<=0x800. If limit==0x800 then limitLead=32 and limitTrail=0. + // In that case, bits=1<= 0x100) { + break; + } + do { + latin1Contains[start++] = true; + } while (start < limit && start < 0x100); + } while (limit <= 0x100); + + // Set table7FF[]. + while (start < 0x800) { + set32x64Bits(table7FF, start, limit <= 0x800 ? limit : 0x800); + if (limit > 0x800) { + start = 0x800; + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + + // Set bmpBlockBits[]. + int minStart = 0x800; + while (start < 0x10000) { + if (limit > 0x10000) { + limit = 0x10000; + } + + if (start < minStart) { + start = minStart; + } + if (start < limit) { // Else: Another range entirely in a known mixed-value block. + if (0 != (start & 0x3f)) { + // Mixed-value block of 64 code points. + start >>= 6; + bmpBlockBits[start & 0x3f] |= 0x10001 << (start >> 6); + start = (start + 1) << 6; // Round up to the next block boundary. + minStart = start; // Ignore further ranges in this block. + } + if (start < limit) { + if (start < (limit & ~0x3f)) { + // Multiple all-ones blocks of 64 code points each. + set32x64Bits(bmpBlockBits, start >> 6, limit >> 6); + } + + if (0 != (limit & 0x3f)) { + // Mixed-value block of 64 code points. + limit >>= 6; + bmpBlockBits[limit & 0x3f] |= 0x10001 << (limit >> 6); + limit = (limit + 1) << 6; // Round up to the next block boundary. + minStart = limit; // Ignore further ranges in this block. + } + } + } + + if (limit == 0x10000) { + break; + } + + start = list[listIndex++]; + if (listIndex < listLength) { + limit = list[listIndex++]; + } else { + limit = 0x110000; + } + } + } + + /** + * Same as UnicodeSet.findCodePoint(int c) except that the binary search is + * restricted for finding code points in a certain range. + * + * For restricting the search for finding in the range start..end, pass in + * lo=findCodePoint(start) and hi=findCodePoint(end) with 0<=lo<=hi= hi || c >= list[hi - 1]) + return hi; + // invariant: c >= list[lo] + // invariant: c < list[hi] + for (;;) { + int i = (lo + hi) >>> 1; + if (i == lo) { + break; // Found! + } else if (c < list[i]) { + hi = i; + } else { + lo = i; + } + } + return hi; + } + + private final boolean containsSlow(int c, int lo, int hi) { + return (0 != (findCodePoint(c, lo, hi) & 1)); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/CharTrie.java b/src/main/java/jdk_internal/bidi/icu/impl/CharTrie.java new file mode 100755 index 00000000..aab129b7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/CharTrie.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.InputStream; + +import jdk_internal.bidi.icu.text.UTF16; + +import java.io.IOException; + +/** + * Trie implementation which stores data in char, 16 bits. + * + * @author synwee + * @see com.ibm.icu.impl.Trie + * @since release 2.1, Jan 01 2002 + */ + +// note that i need to handle the block calculations later, since chartrie +// in icu4c uses the same index array. +public class CharTrie extends Trie { + // public constructors --------------------------------------------- + + /** + *

+ * Creates a new Trie with the settings for the trie data. + *

+ *

+ * Unserialize the 32-bit-aligned input stream and use the data for the trie. + *

+ * + * @param inputStream file input stream to a ICU data file, containing the + * trie + * @param dataManipulate object which provides methods to parse the char data + * @throws IOException thrown when data reading fails + * @draft 2.1 + */ + public CharTrie(InputStream inputStream, DataManipulate dataManipulate) throws IOException { + super(inputStream, dataManipulate); + + if (!isCharTrie()) { + throw new IllegalArgumentException("Data given does not belong to a char trie."); + } + } + + // public methods -------------------------------------------------- + + /** + * Gets the value associated with the codepoint. If no value is associated with + * the codepoint, a default value will be returned. + * + * @param ch codepoint + * @return offset to data + */ + public final char getCodePointValue(int ch) { + int offset; + + // fastpath for U+0000..U+D7FF + if (0 <= ch && ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // copy of getRawOffset() + offset = (m_index_[ch >> INDEX_STAGE_1_SHIFT_] << INDEX_STAGE_2_SHIFT_) + (ch & INDEX_STAGE_3_MASK_); + return m_data_[offset]; + } + + // handle U+D800..U+10FFFF + offset = getCodePointOffset(ch); + + // return -1 if there is an error, in this case we return the default + // value: m_initialValue_ + return (offset >= 0) ? m_data_[offset] : m_initialValue_; + } + + /** + * Gets the value to the data which this lead surrogate character points to. + * Returned data may contain folding offset information for the next trailing + * surrogate character. This method does not guarantee correct results for trail + * surrogates. + * + * @param ch lead surrogate character + * @return data value + */ + public final char getLeadValue(char ch) { + return m_data_[getLeadOffset(ch)]; + } + + // protected methods ----------------------------------------------- + + /** + *

+ * Parses the input stream and stores its trie content into a index and data + * array + *

+ * + * @param inputStream data input stream containing trie data + * @exception IOException thrown when data reading fails + */ + protected final void unserialize(InputStream inputStream) throws IOException { + DataInputStream input = new DataInputStream(inputStream); + int indexDataLength = m_dataOffset_ + m_dataLength_; + m_index_ = new char[indexDataLength]; + for (int i = 0; i < indexDataLength; i++) { + m_index_[i] = input.readChar(); + } + m_data_ = m_index_; + m_initialValue_ = m_data_[m_dataOffset_]; + } + + /** + * Gets the offset to the data which the surrogate pair points to. + * + * @param lead lead surrogate + * @param trail trailing surrogate + * @return offset to data + * @draft 2.1 + */ + protected final int getSurrogateOffset(char lead, char trail) { + if (m_dataManipulate_ == null) { + throw new NullPointerException("The field DataManipulate in this Trie is null"); + } + + // get fold position for the next trail surrogate + int offset = m_dataManipulate_.getFoldingOffset(getLeadValue(lead)); + + // get the real data from the folded lead/trail units + if (offset > 0) { + return getRawOffset(offset, (char) (trail & SURROGATE_MASK_)); + } + + // return -1 if there is an error, in this case we return the default + // value: m_initialValue_ + return -1; + } + + // private data members -------------------------------------------- + + /** + * Default value + */ + private char m_initialValue_; + /** + * Array of char data + */ + private char m_data_[]; +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/CharacterIteratorWrapper.java b/src/main/java/jdk_internal/bidi/icu/impl/CharacterIteratorWrapper.java new file mode 100755 index 00000000..7d6fcede --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/CharacterIteratorWrapper.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import jdk_internal.bidi.CharacterIterator; +import jdk_internal.bidi.icu.text.UCharacterIterator; + +/** + * This class is a wrapper around CharacterIterator and implements the + * UCharacterIterator protocol + * + * @author ram + */ + +public class CharacterIteratorWrapper extends UCharacterIterator { + + private CharacterIterator iterator; + + public CharacterIteratorWrapper(CharacterIterator iter) { + if (iter == null) { + throw new IllegalArgumentException(); + } + iterator = iter; + } + + /** + * @see UCharacterIterator#current() + */ + public int current() { + int c = iterator.current(); + if (c == CharacterIterator.DONE) { + return DONE; + } + return c; + } + + /** + * @see UCharacterIterator#getLength() + */ + public int getLength() { + return (iterator.getEndIndex() - iterator.getBeginIndex()); + } + + /** + * @see UCharacterIterator#getIndex() + */ + public int getIndex() { + return iterator.getIndex(); + } + + /** + * @see UCharacterIterator#next() + */ + public int next() { + int i = iterator.current(); + iterator.next(); + if (i == CharacterIterator.DONE) { + return DONE; + } + return i; + } + + /** + * @see UCharacterIterator#previous() + */ + public int previous() { + int i = iterator.previous(); + if (i == CharacterIterator.DONE) { + return DONE; + } + return i; + } + + /** + * @see UCharacterIterator#setIndex(int) + */ + public void setIndex(int index) { + iterator.setIndex(index); + } + + /** + * @see UCharacterIterator#getText(char[]) + */ + public int getText(char[] fillIn, int offset) { + int length = iterator.getEndIndex() - iterator.getBeginIndex(); + int currentIndex = iterator.getIndex(); + if (offset < 0 || offset + length > fillIn.length) { + throw new IndexOutOfBoundsException(Integer.toString(length)); + } + + for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator.next()) { + fillIn[offset++] = ch; + } + iterator.setIndex(currentIndex); + + return length; + } + + /** + * Creates a clone of this iterator. Clones the underlying character iterator. + * + * @see UCharacterIterator#clone() + */ + public Object clone() { + try { + CharacterIteratorWrapper result = (CharacterIteratorWrapper) super.clone(); + result.iterator = (CharacterIterator) this.iterator.clone(); + return result; + } catch (CloneNotSupportedException e) { + return null; // only invoked if bad underlying character iterator + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/ICUBinary.java b/src/main/java/jdk_internal/bidi/icu/impl/ICUBinary.java new file mode 100755 index 00000000..dbbe0b39 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/ICUBinary.java @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +import jdk_internal.bidi.icu.util.VersionInfo; +import net.lax1dude.eaglercraft.v1_8.EagRuntime; + +public final class ICUBinary { + + private static final class IsAcceptable implements Authenticate { + @Override + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 1; + } + } + + // public inner interface ------------------------------------------------ + + /** + * Special interface for data authentication + */ + public static interface Authenticate { + /** + * Method used in ICUBinary.readHeader() to provide data format authentication. + * + * @param version version of the current data + * @return true if dataformat is an acceptable version, false otherwise + */ + public boolean isDataVersionAcceptable(byte version[]); + } + + // public methods -------------------------------------------------------- + + /** + * Loads an ICU binary data file and returns it as a ByteBuffer. The buffer + * contents is normally read-only, but its position etc. can be modified. + * + * @param itemPath Relative ICU data item path, for example "root.res" or + * "coll/ucadata.icu". + * @return The data as a read-only ByteBuffer. + */ + public static ByteBuffer getRequiredData(String itemPath) { + try (InputStream is = EagRuntime.getRequiredResourceStream(itemPath)) { + + // is.available() may return 0, or 1, or the total number of bytes in the + // stream, + // or some other number. + // Do not try to use is.available() == 0 to find the end of the stream! + byte[] bytes; + int avail = is.available(); + if (avail > 32) { + // There are more bytes available than just the ICU data header length. + // With luck, it is the total number of bytes. + bytes = new byte[avail]; + } else { + bytes = new byte[128]; // empty .res files are even smaller + } + // Call is.read(...) until one returns a negative value. + int length = 0; + for (;;) { + if (length < bytes.length) { + int numRead = is.read(bytes, length, bytes.length - length); + if (numRead < 0) { + break; // end of stream + } + length += numRead; + } else { + // See if we are at the end of the stream before we grow the array. + int nextByte = is.read(); + if (nextByte < 0) { + break; + } + int capacity = 2 * bytes.length; + if (capacity < 128) { + capacity = 128; + } else if (capacity < 0x4000) { + capacity *= 2; // Grow faster until we reach 16kB. + } + bytes = Arrays.copyOf(bytes, capacity); + bytes[length++] = (byte) nextByte; + } + } + return ByteBuffer.wrap(bytes, 0, length); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Same as readHeader(), but returns a VersionInfo rather than a compact int. + */ + public static VersionInfo readHeaderAndDataVersion(ByteBuffer bytes, int dataFormat, Authenticate authenticate) + throws IOException { + return getVersionInfoFromCompactInt(readHeader(bytes, dataFormat, authenticate)); + } + + private static final byte BIG_ENDIAN_ = 1; + + public static final byte[] readHeader(InputStream inputStream, byte dataFormatIDExpected[], + Authenticate authenticate) throws IOException { + DataInputStream input = new DataInputStream(inputStream); + char headersize = input.readChar(); + int readcount = 2; + // reading the header format + byte magic1 = input.readByte(); + readcount++; + byte magic2 = input.readByte(); + readcount++; + if (magic1 != MAGIC1 || magic2 != MAGIC2) { + throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); + } + + input.readChar(); // reading size + readcount += 2; + input.readChar(); // reading reserved word + readcount += 2; + byte bigendian = input.readByte(); + readcount++; + byte charset = input.readByte(); + readcount++; + byte charsize = input.readByte(); + readcount++; + input.readByte(); // reading reserved byte + readcount++; + + byte dataFormatID[] = new byte[4]; + input.readFully(dataFormatID); + readcount += 4; + byte dataVersion[] = new byte[4]; + input.readFully(dataVersion); + readcount += 4; + byte unicodeVersion[] = new byte[4]; + input.readFully(unicodeVersion); + readcount += 4; + if (headersize < readcount) { + throw new IOException("Internal Error: Header size error"); + } + input.skipBytes(headersize - readcount); + + if (bigendian != BIG_ENDIAN_ || charset != CHAR_SET_ || charsize != CHAR_SIZE_ + || !Arrays.equals(dataFormatIDExpected, dataFormatID) + || (authenticate != null && !authenticate.isDataVersionAcceptable(dataVersion))) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_); + } + return unicodeVersion; + } + + /** + * Reads an ICU data header, checks the data format, and returns the data + * version. + * + *

+ * Assumes that the ByteBuffer position is 0 on input. The buffer byte order is + * set according to the data. The buffer position is advanced past the header + * (including UDataInfo and comment). + * + *

+ * See C++ ucmndata.h and unicode/udata.h. + * + * @return dataVersion + * @throws IOException if this is not a valid ICU data item of the expected + * dataFormat + */ + public static int readHeader(ByteBuffer bytes, int dataFormat, Authenticate authenticate) throws IOException { + assert bytes.position() == 0; + byte magic1 = bytes.get(2); + byte magic2 = bytes.get(3); + if (magic1 != MAGIC1 || magic2 != MAGIC2) { + throw new IOException(MAGIC_NUMBER_AUTHENTICATION_FAILED_); + } + + byte isBigEndian = bytes.get(8); + byte charsetFamily = bytes.get(9); + byte sizeofUChar = bytes.get(10); + if (isBigEndian < 0 || 1 < isBigEndian || charsetFamily != CHAR_SET_ || sizeofUChar != CHAR_SIZE_) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_); + } + bytes.order(isBigEndian != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + + int headerSize = bytes.getChar(0); + int sizeofUDataInfo = bytes.getChar(4); + if (sizeofUDataInfo < 20 || headerSize < (sizeofUDataInfo + 4)) { + throw new IOException("Internal Error: Header size error"); + } + // TODO: Change Authenticate to take int major, int minor, int milli, int micro + // to avoid array allocation. + byte[] formatVersion = new byte[] { bytes.get(16), bytes.get(17), bytes.get(18), bytes.get(19) }; + if (bytes.get(12) != (byte) (dataFormat >> 24) || bytes.get(13) != (byte) (dataFormat >> 16) + || bytes.get(14) != (byte) (dataFormat >> 8) || bytes.get(15) != (byte) dataFormat + || (authenticate != null && !authenticate.isDataVersionAcceptable(formatVersion))) { + throw new IOException(HEADER_AUTHENTICATION_FAILED_ + + String.format("; data format %02x%02x%02x%02x, format version %d.%d.%d.%d", bytes.get(12), + bytes.get(13), bytes.get(14), bytes.get(15), formatVersion[0] & 0xff, + formatVersion[1] & 0xff, formatVersion[2] & 0xff, formatVersion[3] & 0xff)); + } + + bytes.position(headerSize); + return // dataVersion + ((int) bytes.get(20) << 24) | ((bytes.get(21) & 0xff) << 16) | ((bytes.get(22) & 0xff) << 8) + | (bytes.get(23) & 0xff); + } + + public static void skipBytes(ByteBuffer bytes, int skipLength) { + if (skipLength > 0) { + bytes.position(bytes.position() + skipLength); + } + } + + public static byte[] getBytes(ByteBuffer bytes, int length, int additionalSkipLength) { + byte[] dest = new byte[length]; + bytes.get(dest); + if (additionalSkipLength > 0) { + skipBytes(bytes, additionalSkipLength); + } + return dest; + } + + public static String getString(ByteBuffer bytes, int length, int additionalSkipLength) { + CharSequence cs = bytes.asCharBuffer(); + String s = cs.subSequence(0, length).toString(); + skipBytes(bytes, length * 2 + additionalSkipLength); + return s; + } + + public static char[] getChars(ByteBuffer bytes, int length, int additionalSkipLength) { + char[] dest = new char[length]; + bytes.asCharBuffer().get(dest); + skipBytes(bytes, length * 2 + additionalSkipLength); + return dest; + } + + public static int[] getInts(ByteBuffer bytes, int length, int additionalSkipLength) { + int[] dest = new int[length]; + bytes.asIntBuffer().get(dest); + skipBytes(bytes, length * 4 + additionalSkipLength); + return dest; + } + + /** + * Returns a VersionInfo for the bytes in the compact version integer. + */ + public static VersionInfo getVersionInfoFromCompactInt(int version) { + return VersionInfo.getInstance(version >>> 24, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); + } + + // private variables ------------------------------------------------- + + /** + * Magic numbers to authenticate the data file + */ + private static final byte MAGIC1 = (byte) 0xda; + private static final byte MAGIC2 = (byte) 0x27; + + /** + * File format authentication values + */ + private static final byte CHAR_SET_ = 0; + private static final byte CHAR_SIZE_ = 2; + + /** + * Error messages + */ + private static final String MAGIC_NUMBER_AUTHENTICATION_FAILED_ = "ICUBinary data file error: Magic number authentication failed"; + private static final String HEADER_AUTHENTICATION_FAILED_ = "ICUBinary data file error: Header authentication failed"; +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Norm2AllModes.java b/src/main/java/jdk_internal/bidi/icu/impl/Norm2AllModes.java new file mode 100755 index 00000000..aaabf2f0 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Norm2AllModes.java @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; + +import jdk_internal.bidi.icu.text.Normalizer2; + +public final class Norm2AllModes { + // Public API dispatch via Normalizer2 subclasses -------------------------- *** + + // Normalizer2 implementation for the old UNORM_NONE. + public static final class NoopNormalizer2 extends Normalizer2 { + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if (dest != src) { + dest.setLength(0); + return dest.append(src); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if (dest != src) { + try { + return dest.append(src); + } catch (IOException e) { + throw new InternalError(e.toString(), e); + } + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + if (first != second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + if (first != second) { + return first.append(second); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public String getDecomposition(int c) { + return null; + } + + // No need to override the default getRawDecomposition(). + @Override + public boolean isNormalized(CharSequence s) { + return true; + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return s.length(); + } + + @Override + public boolean hasBoundaryBefore(int c) { + return true; + } + } + + // Intermediate class: + // Has NormalizerImpl and does boilerplate argument checking and setup. + public abstract static class Normalizer2WithImpl extends Normalizer2 { + public Normalizer2WithImpl(NormalizerImpl ni) { + impl = ni; + } + + // normalize + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + dest.setLength(0); + normalize(src, new NormalizerImpl.ReorderingBuffer(impl, dest, src.length())); + return dest; + } + + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + NormalizerImpl.ReorderingBuffer buffer = new NormalizerImpl.ReorderingBuffer(impl, dest, src.length()); + normalize(src, buffer); + buffer.flush(); + return dest; + } + + protected abstract void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer); + + // normalize and append + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, true); + } + + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, false); + } + + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second, boolean doNormalize) { + if (first == second) { + throw new IllegalArgumentException(); + } + normalizeAndAppend(second, doNormalize, + new NormalizerImpl.ReorderingBuffer(impl, first, first.length() + second.length())); + return first; + } + + protected abstract void normalizeAndAppend(CharSequence src, boolean doNormalize, + NormalizerImpl.ReorderingBuffer buffer); + + @Override + public String getDecomposition(int c) { + return impl.getDecomposition(c); + } + + @Override + public int getCombiningClass(int c) { + return impl.getCC(impl.getNorm16(c)); + } + + // quick checks + @Override + public boolean isNormalized(CharSequence s) { + return s.length() == spanQuickCheckYes(s); + } + + public final NormalizerImpl impl; + } + + public static final class DecomposeNormalizer2 extends Normalizer2WithImpl { + public DecomposeNormalizer2(NormalizerImpl ni) { + super(ni); + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.decompose(src, 0, src.length(), buffer); + } + + @Override + protected void normalizeAndAppend(CharSequence src, boolean doNormalize, + NormalizerImpl.ReorderingBuffer buffer) { + impl.decomposeAndAppend(src, doNormalize, buffer); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.decompose(s, 0, s.length(), null); + } + + @Override + public boolean hasBoundaryBefore(int c) { + return impl.hasDecompBoundaryBefore(c); + } + } + + public static final class ComposeNormalizer2 extends Normalizer2WithImpl { + public ComposeNormalizer2(NormalizerImpl ni, boolean fcc) { + super(ni); + onlyContiguous = fcc; + } + + @Override + protected void normalize(CharSequence src, NormalizerImpl.ReorderingBuffer buffer) { + impl.compose(src, 0, src.length(), onlyContiguous, true, buffer); + } + + @Override + protected void normalizeAndAppend(CharSequence src, boolean doNormalize, + NormalizerImpl.ReorderingBuffer buffer) { + impl.composeAndAppend(src, doNormalize, onlyContiguous, buffer); + } + + @Override + public boolean isNormalized(CharSequence s) { + // 5: small destCapacity for substring normalization + return impl.compose(s, 0, s.length(), onlyContiguous, false, + new NormalizerImpl.ReorderingBuffer(impl, new StringBuilder(), 5)); + } + + @Override + public int spanQuickCheckYes(CharSequence s) { + return impl.composeQuickCheck(s, 0, s.length(), onlyContiguous, true) >>> 1; + } + + @Override + public boolean hasBoundaryBefore(int c) { + return impl.hasCompBoundaryBefore(c); + } + + private final boolean onlyContiguous; + } + + // instance cache ---------------------------------------------------------- *** + + private Norm2AllModes(NormalizerImpl ni) { + impl = ni; + comp = new ComposeNormalizer2(ni, false); + decomp = new DecomposeNormalizer2(ni); + } + + public final NormalizerImpl impl; + public final ComposeNormalizer2 comp; + public final DecomposeNormalizer2 decomp; + + private static Norm2AllModes getInstanceFromSingleton(Norm2AllModesSingleton singleton) { + if (singleton.exception != null) { + throw singleton.exception; + } + return singleton.allModes; + } + + public static Norm2AllModes getNFCInstance() { + return getInstanceFromSingleton(NFCSingleton.INSTANCE); + } + + public static Norm2AllModes getNFKCInstance() { + return getInstanceFromSingleton(NFKCSingleton.INSTANCE); + } + + public static final NoopNormalizer2 NOOP_NORMALIZER2 = new NoopNormalizer2(); + + private static final class Norm2AllModesSingleton { + private Norm2AllModesSingleton(String name) { + try { + @SuppressWarnings("deprecation") + String DATA_FILE_NAME = "/assets/eagler/icudt/" + name + ".nrm"; + NormalizerImpl impl = new NormalizerImpl().load(DATA_FILE_NAME); + allModes = new Norm2AllModes(impl); + } catch (RuntimeException e) { + exception = e; + } + } + + private Norm2AllModes allModes; + private RuntimeException exception; + } + + private static final class NFCSingleton { + private static final Norm2AllModesSingleton INSTANCE = new Norm2AllModesSingleton("nfc"); + } + + private static final class NFKCSingleton { + private static final Norm2AllModesSingleton INSTANCE = new Norm2AllModesSingleton("nfkc"); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/NormalizerImpl.java b/src/main/java/jdk_internal/bidi/icu/impl/NormalizerImpl.java new file mode 100755 index 00000000..920aa7a0 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/NormalizerImpl.java @@ -0,0 +1,2261 @@ +/* + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.Normalizer2; +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.util.CodePointTrie; +import jdk_internal.bidi.icu.util.VersionInfo; + +// Original filename in ICU4J: Normalizer2Impl.java +public final class NormalizerImpl { + public static final class Hangul { + /* Korean Hangul and Jamo constants */ + public static final int JAMO_L_BASE = 0x1100; /* "lead" jamo */ + public static final int JAMO_V_BASE = 0x1161; /* "vowel" jamo */ + public static final int JAMO_T_BASE = 0x11a7; /* "trail" jamo */ + + public static final int HANGUL_BASE = 0xac00; + public static final int HANGUL_END = 0xd7a3; + + public static final int JAMO_L_COUNT = 19; + public static final int JAMO_V_COUNT = 21; + public static final int JAMO_T_COUNT = 28; + + public static final int HANGUL_COUNT = JAMO_L_COUNT * JAMO_V_COUNT * JAMO_T_COUNT; + public static final int HANGUL_LIMIT = HANGUL_BASE + HANGUL_COUNT; + + public static boolean isHangul(int c) { + return HANGUL_BASE <= c && c < HANGUL_LIMIT; + } + + public static boolean isHangulLV(int c) { + c -= HANGUL_BASE; + return 0 <= c && c < HANGUL_COUNT && c % JAMO_T_COUNT == 0; + } + + /** + * Decomposes c, which must be a Hangul syllable, into buffer and returns the + * length of the decomposition (2 or 3). + */ + public static int decompose(int c, Appendable buffer) { + try { + c -= HANGUL_BASE; + int c2 = c % JAMO_T_COUNT; + c /= JAMO_T_COUNT; + buffer.append((char) (JAMO_L_BASE + c / JAMO_V_COUNT)); + buffer.append((char) (JAMO_V_BASE + c % JAMO_V_COUNT)); + if (c2 == 0) { + return 2; + } else { + buffer.append((char) (JAMO_T_BASE + c2)); + return 3; + } + } catch (IOException e) { + throw new InternalError(e); + } + } + } + + /** + * Writable buffer that takes care of canonical ordering. Its Appendable methods + * behave like the C++ implementation's appendZeroCC() methods. + *

+ * If dest is a StringBuilder, then the buffer writes directly to it. Otherwise, + * the buffer maintains a StringBuilder for intermediate text segments until no + * further changes are necessary and whole segments are appended. append() + * methods that take combining-class values always write to the StringBuilder. + * Other append() methods flush and append to the Appendable. + */ + public static final class ReorderingBuffer implements Appendable { + public ReorderingBuffer(NormalizerImpl ni, Appendable dest, int destCapacity) { + impl = ni; + app = dest; + if (app instanceof StringBuilder) { + appIsStringBuilder = true; + str = (StringBuilder) dest; + // In Java, the constructor subsumes public void init(int destCapacity) + str.ensureCapacity(destCapacity); + reorderStart = 0; + if (str.length() == 0) { + lastCC = 0; + } else { + setIterator(); + lastCC = previousCC(); + // Set reorderStart after the last code point with cc<=1 if there is one. + if (lastCC > 1) { + while (previousCC() > 1) { + } + } + reorderStart = codePointLimit; + } + } else { + appIsStringBuilder = false; + str = new StringBuilder(); + reorderStart = 0; + lastCC = 0; + } + } + + public boolean isEmpty() { + return str.length() == 0; + } + + public int length() { + return str.length(); + } + + public int getLastCC() { + return lastCC; + } + + public StringBuilder getStringBuilder() { + return str; + } + + public boolean equals(CharSequence s, int start, int limit) { + return UTF16Plus.equal(str, 0, str.length(), s, start, limit); + } + + public void append(int c, int cc) { + if (lastCC <= cc || cc == 0) { + str.appendCodePoint(c); + lastCC = cc; + if (cc <= 1) { + reorderStart = str.length(); + } + } else { + insert(c, cc); + } + } + + public void append(CharSequence s, int start, int limit, boolean isNFD, int leadCC, int trailCC) { + if (start == limit) { + return; + } + if (lastCC <= leadCC || leadCC == 0) { + if (trailCC <= 1) { + reorderStart = str.length() + (limit - start); + } else if (leadCC <= 1) { + reorderStart = str.length() + 1; // Ok if not a code point boundary. + } + str.append(s, start, limit); + lastCC = trailCC; + } else { + int c = Character.codePointAt(s, start); + start += Character.charCount(c); + insert(c, leadCC); // insert first code point + while (start < limit) { + c = Character.codePointAt(s, start); + start += Character.charCount(c); + if (start < limit) { + if (isNFD) { + leadCC = getCCFromYesOrMaybe(impl.getNorm16(c)); + } else { + leadCC = impl.getCC(impl.getNorm16(c)); + } + } else { + leadCC = trailCC; + } + append(c, leadCC); + } + } + } + + // The following append() methods work like C++ appendZeroCC(). + // They assume that the cc or trailCC of their input is 0. + // Most of them implement Appendable interface methods. + @Override + public ReorderingBuffer append(char c) { + str.append(c); + lastCC = 0; + reorderStart = str.length(); + return this; + } + + public void appendZeroCC(int c) { + str.appendCodePoint(c); + lastCC = 0; + reorderStart = str.length(); + } + + @Override + public ReorderingBuffer append(CharSequence s) { + if (s.length() != 0) { + str.append(s); + lastCC = 0; + reorderStart = str.length(); + } + return this; + } + + @Override + public ReorderingBuffer append(CharSequence s, int start, int limit) { + if (start != limit) { + str.append(s, start, limit); + lastCC = 0; + reorderStart = str.length(); + } + return this; + } + + /** + * Flushes from the intermediate StringBuilder to the Appendable, if they are + * different objects. Used after recomposition. Must be called at the end when + * writing to a non-StringBuilder Appendable. + */ + public void flush() { + if (appIsStringBuilder) { + reorderStart = str.length(); + } else { + try { + app.append(str); + str.setLength(0); + reorderStart = 0; + } catch (IOException e) { + throw new InternalError(e); // Avoid declaring "throws IOException". + } + } + lastCC = 0; + } + + /** + * Flushes from the intermediate StringBuilder to the Appendable, if they are + * different objects. Then appends the new text to the Appendable or + * StringBuilder. Normally used after quick check loops find a non-empty + * sequence. + */ + public ReorderingBuffer flushAndAppendZeroCC(CharSequence s, int start, int limit) { + if (appIsStringBuilder) { + str.append(s, start, limit); + reorderStart = str.length(); + } else { + try { + app.append(str).append(s, start, limit); + str.setLength(0); + reorderStart = 0; + } catch (IOException e) { + throw new InternalError(e); // Avoid declaring "throws IOException". + } + } + lastCC = 0; + return this; + } + + public void remove() { + str.setLength(0); + lastCC = 0; + reorderStart = 0; + } + + public void removeSuffix(int suffixLength) { + int oldLength = str.length(); + str.delete(oldLength - suffixLength, oldLength); + lastCC = 0; + reorderStart = str.length(); + } + + // Inserts c somewhere before the last character. + // Requires 0 cc;) { + } + // insert c at codePointLimit, after the character with prevCC<=cc + if (c <= 0xffff) { + str.insert(codePointLimit, (char) c); + if (cc <= 1) { + reorderStart = codePointLimit + 1; + } + } else { + str.insert(codePointLimit, Character.toChars(c)); + if (cc <= 1) { + reorderStart = codePointLimit + 2; + } + } + } + + private final NormalizerImpl impl; + private final Appendable app; + private final StringBuilder str; + private final boolean appIsStringBuilder; + private int reorderStart; + private int lastCC; + + // private backward iterator + private void setIterator() { + codePointStart = str.length(); + } + + private void skipPrevious() { // Requires 0= codePointStart) { + return 0; + } + int c = str.codePointBefore(codePointStart); + codePointStart -= Character.charCount(c); + return impl.getCCFromYesOrMaybeCP(c); + } + + private int codePointStart, codePointLimit; + } + + // TODO: Propose as public API on the UTF16 class. + // TODO: Propose widening UTF16 methods that take char to take int. + // TODO: Propose widening UTF16 methods that take String to take CharSequence. + public static final class UTF16Plus { + /** + * Is this code point a lead surrogate (U+d800..U+dbff)? + * + * @param c code unit or code point + * @return true or false + */ + public static boolean isLeadSurrogate(int c) { + return (c & 0xfffffc00) == 0xd800; + } + + /** + * Assuming c is a surrogate code point (UTF16.isSurrogate(c)), is it a lead + * surrogate? + * + * @param c code unit or code point + * @return true or false + */ + public static boolean isSurrogateLead(int c) { + return (c & 0x400) == 0; + } + + /** + * Compares two CharSequence subsequences for binary equality. + * + * @param s1 first sequence + * @param start1 start offset in first sequence + * @param limit1 limit offset in first sequence + * @param s2 second sequence + * @param start2 start offset in second sequence + * @param limit2 limit offset in second sequence + * @return true if s1.subSequence(start1, limit1) contains the same text as + * s2.subSequence(start2, limit2) + */ + public static boolean equal(CharSequence s1, int start1, int limit1, CharSequence s2, int start2, int limit2) { + if ((limit1 - start1) != (limit2 - start2)) { + return false; + } + if (s1 == s2 && start1 == start2) { + return true; + } + while (start1 < limit1) { + if (s1.charAt(start1++) != s2.charAt(start2++)) { + return false; + } + } + return true; + } + } + + public NormalizerImpl() { + } + + private static final class IsAcceptable implements ICUBinary.Authenticate { + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 4; + } + } + + private static final IsAcceptable IS_ACCEPTABLE = new IsAcceptable(); + private static final int DATA_FORMAT = 0x4e726d32; // "Nrm2" + + public NormalizerImpl load(ByteBuffer bytes) { + try { + dataVersion = ICUBinary.readHeaderAndDataVersion(bytes, DATA_FORMAT, IS_ACCEPTABLE); + int indexesLength = bytes.getInt() / 4; // inIndexes[IX_NORM_TRIE_OFFSET]/4 + if (indexesLength <= IX_MIN_LCCC_CP) { + throw new InternalError("Normalizer2 data: not enough indexes"); + } + int[] inIndexes = new int[indexesLength]; + inIndexes[0] = indexesLength * 4; + for (int i = 1; i < indexesLength; ++i) { + inIndexes[i] = bytes.getInt(); + } + + minDecompNoCP = inIndexes[IX_MIN_DECOMP_NO_CP]; + minCompNoMaybeCP = inIndexes[IX_MIN_COMP_NO_MAYBE_CP]; + minLcccCP = inIndexes[IX_MIN_LCCC_CP]; + + minYesNo = inIndexes[IX_MIN_YES_NO]; + minYesNoMappingsOnly = inIndexes[IX_MIN_YES_NO_MAPPINGS_ONLY]; + minNoNo = inIndexes[IX_MIN_NO_NO]; + minNoNoCompBoundaryBefore = inIndexes[IX_MIN_NO_NO_COMP_BOUNDARY_BEFORE]; + minNoNoCompNoMaybeCC = inIndexes[IX_MIN_NO_NO_COMP_NO_MAYBE_CC]; + minNoNoEmpty = inIndexes[IX_MIN_NO_NO_EMPTY]; + limitNoNo = inIndexes[IX_LIMIT_NO_NO]; + minMaybeYes = inIndexes[IX_MIN_MAYBE_YES]; + assert ((minMaybeYes & 7) == 0); // 8-aligned for noNoDelta bit fields + centerNoNoDelta = (minMaybeYes >> DELTA_SHIFT) - MAX_DELTA - 1; + + // Read the normTrie. + int offset = inIndexes[IX_NORM_TRIE_OFFSET]; + int nextOffset = inIndexes[IX_EXTRA_DATA_OFFSET]; + int triePosition = bytes.position(); + normTrie = CodePointTrie.Fast16.fromBinary(bytes); + int trieLength = bytes.position() - triePosition; + if (trieLength > (nextOffset - offset)) { + throw new InternalError("Normalizer2 data: not enough bytes for normTrie"); + } + ICUBinary.skipBytes(bytes, (nextOffset - offset) - trieLength); // skip padding after trie bytes + + // Read the composition and mapping data. + offset = nextOffset; + nextOffset = inIndexes[IX_SMALL_FCD_OFFSET]; + int numChars = (nextOffset - offset) / 2; + if (numChars != 0) { + maybeYesCompositions = ICUBinary.getString(bytes, numChars, 0); + extraData = maybeYesCompositions.substring((MIN_NORMAL_MAYBE_YES - minMaybeYes) >> OFFSET_SHIFT); + } + + // smallFCD: new in formatVersion 2 + offset = nextOffset; + smallFCD = new byte[0x100]; + bytes.get(smallFCD); + + return this; + } catch (IOException e) { + throw new InternalError(e); + } + } + + public NormalizerImpl load(String name) { + return load(ICUBinary.getRequiredData(name)); + } + + // The trie stores values for lead surrogate code *units*. + // Surrogate code *points* are inert. + public int getNorm16(int c) { + return UTF16Plus.isLeadSurrogate(c) ? INERT : normTrie.get(c); + } + + public int getRawNorm16(int c) { + return normTrie.get(c); + } + + public boolean isAlgorithmicNoNo(int norm16) { + return limitNoNo <= norm16 && norm16 < minMaybeYes; + } + + public boolean isCompNo(int norm16) { + return minNoNo <= norm16 && norm16 < minMaybeYes; + } + + public boolean isDecompYes(int norm16) { + return norm16 < minYesNo || minMaybeYes <= norm16; + } + + public int getCC(int norm16) { + if (norm16 >= MIN_NORMAL_MAYBE_YES) { + return getCCFromNormalYesOrMaybe(norm16); + } + if (norm16 < minNoNo || limitNoNo <= norm16) { + return 0; + } + return getCCFromNoNo(norm16); + } + + public static int getCCFromNormalYesOrMaybe(int norm16) { + return (norm16 >> OFFSET_SHIFT) & 0xff; + } + + public static int getCCFromYesOrMaybe(int norm16) { + return norm16 >= MIN_NORMAL_MAYBE_YES ? getCCFromNormalYesOrMaybe(norm16) : 0; + } + + public int getCCFromYesOrMaybeCP(int c) { + if (c < minCompNoMaybeCP) { + return 0; + } + return getCCFromYesOrMaybe(getNorm16(c)); + } + + /** + * Returns the FCD data for code point c. + * + * @param c A Unicode code point. + * @return The lccc(c) in bits 15..8 and tccc(c) in bits 7..0. + */ + public int getFCD16(int c) { + if (c < minDecompNoCP) { + return 0; + } else if (c <= 0xffff) { + if (!singleLeadMightHaveNonZeroFCD16(c)) { + return 0; + } + } + return getFCD16FromNormData(c); + } + + /** + * Returns true if the single-or-lead code unit c might have non-zero FCD data. + */ + public boolean singleLeadMightHaveNonZeroFCD16(int lead) { + // 0<=lead<=0xffff + byte bits = smallFCD[lead >> 8]; + if (bits == 0) { + return false; + } + return ((bits >> ((lead >> 5) & 7)) & 1) != 0; + } + + /** Gets the FCD value from the regular normalization data. */ + public int getFCD16FromNormData(int c) { + int norm16 = getNorm16(c); + if (norm16 >= limitNoNo) { + if (norm16 >= MIN_NORMAL_MAYBE_YES) { + // combining mark + norm16 = getCCFromNormalYesOrMaybe(norm16); + return norm16 | (norm16 << 8); + } else if (norm16 >= minMaybeYes) { + return 0; + } else { // isDecompNoAlgorithmic(norm16) + int deltaTrailCC = norm16 & DELTA_TCCC_MASK; + if (deltaTrailCC <= DELTA_TCCC_1) { + return deltaTrailCC >> OFFSET_SHIFT; + } + // Maps to an isCompYesAndZeroCC. + c = mapAlgorithmic(c, norm16); + norm16 = getRawNorm16(c); + } + } + if (norm16 <= minYesNo || isHangulLVT(norm16)) { + // no decomposition or Hangul syllable, all zeros + return 0; + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + int fcd16 = firstUnit >> 8; // tccc + if ((firstUnit & MAPPING_HAS_CCC_LCCC_WORD) != 0) { + fcd16 |= extraData.charAt(mapping - 1) & 0xff00; // lccc + } + return fcd16; + } + + /** + * Gets the decomposition for one code point. + * + * @param c code point + * @return c's decomposition, if it has one; returns null if it does not have a + * decomposition + */ + public String getDecomposition(int c) { + int norm16; + if (c < minDecompNoCP || isMaybeOrNonZeroCC(norm16 = getNorm16(c))) { + // c does not decompose + return null; + } + int decomp = -1; + if (isDecompNoAlgorithmic(norm16)) { + // Maps to an isCompYesAndZeroCC. + decomp = c = mapAlgorithmic(c, norm16); + // The mapping might decompose further. + norm16 = getRawNorm16(c); + } + if (norm16 < minYesNo) { + if (decomp < 0) { + return null; + } else { + return UTF16.valueOf(decomp); + } + } else if (isHangulLV(norm16) || isHangulLVT(norm16)) { + // Hangul syllable: decompose algorithmically + StringBuilder buffer = new StringBuilder(); + Hangul.decompose(c, buffer); + return buffer.toString(); + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int length = extraData.charAt(mapping++) & MAPPING_LENGTH_MASK; + return extraData.substring(mapping, mapping + length); + } + + // Fixed norm16 values. + public static final int MIN_YES_YES_WITH_CC = 0xfe02; + public static final int JAMO_VT = 0xfe00; + public static final int MIN_NORMAL_MAYBE_YES = 0xfc00; + public static final int JAMO_L = 2; // offset=1 hasCompBoundaryAfter=FALSE + public static final int INERT = 1; // offset=0 hasCompBoundaryAfter=TRUE + + // norm16 bit 0 is comp-boundary-after. + public static final int HAS_COMP_BOUNDARY_AFTER = 1; + public static final int OFFSET_SHIFT = 1; + + // For algorithmic one-way mappings, norm16 bits 2..1 indicate the + // tccc (0, 1, >1) for quick FCC boundary-after tests. + public static final int DELTA_TCCC_0 = 0; + public static final int DELTA_TCCC_1 = 2; + public static final int DELTA_TCCC_GT_1 = 4; + public static final int DELTA_TCCC_MASK = 6; + public static final int DELTA_SHIFT = 3; + + public static final int MAX_DELTA = 0x40; + + // Byte offsets from the start of the data, after the generic header. + public static final int IX_NORM_TRIE_OFFSET = 0; + public static final int IX_EXTRA_DATA_OFFSET = 1; + public static final int IX_SMALL_FCD_OFFSET = 2; + public static final int IX_RESERVED3_OFFSET = 3; + public static final int IX_TOTAL_SIZE = 7; + public static final int MIN_CCC_LCCC_CP = 0x300; + // Code point thresholds for quick check codes. + public static final int IX_MIN_DECOMP_NO_CP = 8; + public static final int IX_MIN_COMP_NO_MAYBE_CP = 9; + + // Norm16 value thresholds for quick check combinations and types of extra data. + + /** Mappings & compositions in [minYesNo..minYesNoMappingsOnly[. */ + public static final int IX_MIN_YES_NO = 10; + /** Mappings are comp-normalized. */ + public static final int IX_MIN_NO_NO = 11; + public static final int IX_LIMIT_NO_NO = 12; + public static final int IX_MIN_MAYBE_YES = 13; + + /** Mappings only in [minYesNoMappingsOnly..minNoNo[. */ + public static final int IX_MIN_YES_NO_MAPPINGS_ONLY = 14; + /** Mappings are not comp-normalized but have a comp boundary before. */ + public static final int IX_MIN_NO_NO_COMP_BOUNDARY_BEFORE = 15; + /** Mappings do not have a comp boundary before. */ + public static final int IX_MIN_NO_NO_COMP_NO_MAYBE_CC = 16; + /** Mappings to the empty string. */ + public static final int IX_MIN_NO_NO_EMPTY = 17; + + public static final int IX_MIN_LCCC_CP = 18; + public static final int IX_COUNT = 20; + + public static final int MAPPING_HAS_CCC_LCCC_WORD = 0x80; + public static final int MAPPING_HAS_RAW_MAPPING = 0x40; + // unused bit 0x20; + public static final int MAPPING_LENGTH_MASK = 0x1f; + + public static final int COMP_1_LAST_TUPLE = 0x8000; + public static final int COMP_1_TRIPLE = 1; + public static final int COMP_1_TRAIL_LIMIT = 0x3400; + public static final int COMP_1_TRAIL_MASK = 0x7ffe; + public static final int COMP_1_TRAIL_SHIFT = 9; // 10-1 for the "triple" bit + public static final int COMP_2_TRAIL_SHIFT = 6; + public static final int COMP_2_TRAIL_MASK = 0xffc0; + + // higher-level functionality ------------------------------------------ *** + + /** + * Decomposes s[src, limit[ and writes the result to dest. limit can be NULL if + * src is NUL-terminated. destLengthEstimate is the initial dest buffer capacity + * and can be -1. + */ + public void decompose(CharSequence s, int src, int limit, StringBuilder dest, int destLengthEstimate) { + if (destLengthEstimate < 0) { + destLengthEstimate = limit - src; + } + dest.setLength(0); + ReorderingBuffer buffer = new ReorderingBuffer(this, dest, destLengthEstimate); + decompose(s, src, limit, buffer); + } + + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int decompose(CharSequence s, int src, int limit, ReorderingBuffer buffer) { + int minNoCP = minDecompNoCP; + + int prevSrc; + int c = 0; + int norm16 = 0; + + // only for quick check + int prevBoundary = src; + int prevCC = 0; + + for (;;) { + // count code units below the minimum or with irrelevant data for the quick + // check + for (prevSrc = src; src != limit;) { + if ((c = s.charAt(src)) < minNoCP || isMostDecompYesAndZeroCC(norm16 = normTrie.bmpGet(c))) { + ++src; + } else if (!UTF16Plus.isLeadSurrogate(c)) { + break; + } else { + char c2; + if ((src + 1) != limit && Character.isLowSurrogate(c2 = s.charAt(src + 1))) { + c = Character.toCodePoint((char) c, c2); + norm16 = normTrie.suppGet(c); + if (isMostDecompYesAndZeroCC(norm16)) { + src += 2; + } else { + break; + } + } else { + ++src; // unpaired lead surrogate: inert + } + } + } + // copy these code units all at once + if (src != prevSrc) { + if (buffer != null) { + buffer.flushAndAppendZeroCC(s, prevSrc, src); + } else { + prevCC = 0; + prevBoundary = src; + } + } + if (src == limit) { + break; + } + + // Check one above-minimum, relevant code point. + src += Character.charCount(c); + if (buffer != null) { + decompose(c, norm16, buffer); + } else { + if (isDecompYes(norm16)) { + int cc = getCCFromYesOrMaybe(norm16); + if (prevCC <= cc || cc == 0) { + prevCC = cc; + if (cc <= 1) { + prevBoundary = src; + } + continue; + } + } + return prevBoundary; // "no" or cc out of order + } + } + return src; + } + + public void decomposeAndAppend(CharSequence s, boolean doDecompose, ReorderingBuffer buffer) { + int limit = s.length(); + if (limit == 0) { + return; + } + if (doDecompose) { + decompose(s, 0, limit, buffer); + return; + } + // Just merge the strings at the boundary. + int c = Character.codePointAt(s, 0); + int src = 0; + int firstCC, prevCC, cc; + firstCC = prevCC = cc = getCC(getNorm16(c)); + while (cc != 0) { + prevCC = cc; + src += Character.charCount(c); + if (src >= limit) { + break; + } + c = Character.codePointAt(s, src); + cc = getCC(getNorm16(c)); + } + ; + buffer.append(s, 0, src, false, firstCC, prevCC); + buffer.append(s, src, limit); + } + + // Very similar to composeQuickCheck(): Make the same changes in both places if + // relevant. + // doCompose: normalize + // !doCompose: isNormalized (buffer must be empty and initialized) + public boolean compose(CharSequence s, int src, int limit, boolean onlyContiguous, boolean doCompose, + ReorderingBuffer buffer) { + int prevBoundary = src; + int minNoMaybeCP = minCompNoMaybeCP; + + for (;;) { + // Fast path: Scan over a sequence of characters below the minimum "no or maybe" + // code point, + // or with (compYes && ccc==0) properties. + int prevSrc; + int c = 0; + int norm16 = 0; + for (;;) { + if (src == limit) { + if (prevBoundary != limit && doCompose) { + buffer.append(s, prevBoundary, limit); + } + return true; + } + if ((c = s.charAt(src)) < minNoMaybeCP || isCompYesAndZeroCC(norm16 = normTrie.bmpGet(c))) { + ++src; + } else { + prevSrc = src++; + if (!UTF16Plus.isLeadSurrogate(c)) { + break; + } else { + char c2; + if (src != limit && Character.isLowSurrogate(c2 = s.charAt(src))) { + ++src; + c = Character.toCodePoint((char) c, c2); + norm16 = normTrie.suppGet(c); + if (!isCompYesAndZeroCC(norm16)) { + break; + } + } + } + } + } + // isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo. + // The current character is either a "noNo" (has a mapping) + // or a "maybeYes" (combines backward) + // or a "yesYes" with ccc!=0. + // It is not a Hangul syllable or Jamo L because those have "yes" properties. + + // Medium-fast path: Handle cases that do not require full decomposition and + // recomposition. + if (!isMaybeOrNonZeroCC(norm16)) { // minNoNo <= norm16 < minMaybeYes + if (!doCompose) { + return false; + } + // Fast path for mapping a character that is immediately surrounded by + // boundaries. + // In this case, we need not decompose around the current character. + if (isDecompNoAlgorithmic(norm16)) { + // Maps to a single isCompYesAndZeroCC character + // which also implies hasCompBoundaryBefore. + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous) || hasCompBoundaryBefore(s, src, limit)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append(mapAlgorithmic(c, norm16), 0); + prevBoundary = src; + continue; + } + } else if (norm16 < minNoNoCompBoundaryBefore) { + // The mapping is comp-normalized which also implies hasCompBoundaryBefore. + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous) || hasCompBoundaryBefore(s, src, limit)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + int mapping = norm16 >> OFFSET_SHIFT; + int length = extraData.charAt(mapping++) & MAPPING_LENGTH_MASK; + buffer.append(extraData, mapping, mapping + length); + prevBoundary = src; + continue; + } + } else if (norm16 >= minNoNoEmpty) { + // The current character maps to nothing. + // Simply omit it from the output if there is a boundary before _or_ after it. + // The character itself implies no boundaries. + if (hasCompBoundaryBefore(s, src, limit) + || hasCompBoundaryAfter(s, prevBoundary, prevSrc, onlyContiguous)) { + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + prevBoundary = src; + continue; + } + } + // Other "noNo" type, or need to examine more text around this character: + // Fall through to the slow path. + } else if (isJamoVT(norm16) && prevBoundary != prevSrc) { + char prev = s.charAt(prevSrc - 1); + if (c < Hangul.JAMO_T_BASE) { + // The current character is a Jamo Vowel, + // compose with previous Jamo L and following Jamo T. + char l = (char) (prev - Hangul.JAMO_L_BASE); + if (l < Hangul.JAMO_L_COUNT) { + if (!doCompose) { + return false; + } + int t; + if (src != limit && 0 < (t = (s.charAt(src) - Hangul.JAMO_T_BASE)) && t < Hangul.JAMO_T_COUNT) { + // The next character is a Jamo T. + ++src; + } else if (hasCompBoundaryBefore(s, src, limit)) { + // No Jamo T follows, not even via decomposition. + t = 0; + } else { + t = -1; + } + if (t >= 0) { + int syllable = Hangul.HANGUL_BASE + + (l * Hangul.JAMO_V_COUNT + (c - Hangul.JAMO_V_BASE)) * Hangul.JAMO_T_COUNT + t; + --prevSrc; // Replace the Jamo L as well. + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append((char) syllable); + prevBoundary = src; + continue; + } + // If we see L+V+x where x!=T then we drop to the slow path, + // decompose and recompose. + // This is to deal with NFKC finding normal L and V but a + // compatibility variant of a T. + // We need to either fully compose that combination here + // (which would complicate the code and may not work with strange custom data) + // or use the slow path. + } + } else if (Hangul.isHangulLV(prev)) { + // The current character is a Jamo Trailing consonant, + // compose with previous Hangul LV that does not contain a Jamo T. + if (!doCompose) { + return false; + } + int syllable = prev + c - Hangul.JAMO_T_BASE; + --prevSrc; // Replace the Hangul LV as well. + if (prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + buffer.append((char) syllable); + prevBoundary = src; + continue; + } + // No matching context, or may need to decompose surrounding text first: + // Fall through to the slow path. + } else if (norm16 > JAMO_VT) { // norm16 >= MIN_YES_YES_WITH_CC + // One or more combining marks that do not combine-back: + // Check for canonical order, copy unchanged if ok and + // if followed by a character with a boundary-before. + int cc = getCCFromNormalYesOrMaybe(norm16); // cc!=0 + if (onlyContiguous /* FCC */ && getPreviousTrailCC(s, prevBoundary, prevSrc) > cc) { + // Fails FCD test, need to decompose and contiguously recompose. + if (!doCompose) { + return false; + } + } else { + // If !onlyContiguous (not FCC), then we ignore the tccc of + // the previous character which passed the quick check "yes && ccc==0" test. + int n16; + for (;;) { + if (src == limit) { + if (doCompose) { + buffer.append(s, prevBoundary, limit); + } + return true; + } + int prevCC = cc; + c = Character.codePointAt(s, src); + n16 = normTrie.get(c); + if (n16 >= MIN_YES_YES_WITH_CC) { + cc = getCCFromNormalYesOrMaybe(n16); + if (prevCC > cc) { + if (!doCompose) { + return false; + } + break; + } + } else { + break; + } + src += Character.charCount(c); + } + // p is after the last in-order combining mark. + // If there is a boundary here, then we continue with no change. + if (norm16HasCompBoundaryBefore(n16)) { + if (isCompYesAndZeroCC(n16)) { + src += Character.charCount(c); + } + continue; + } + // Use the slow path. There is no boundary in [prevSrc, src[. + } + } + + // Slow path: Find the nearest boundaries around the current character, + // decompose and recompose. + if (prevBoundary != prevSrc && !norm16HasCompBoundaryBefore(norm16)) { + c = Character.codePointBefore(s, prevSrc); + norm16 = normTrie.get(c); + if (!norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + prevSrc -= Character.charCount(c); + } + } + if (doCompose && prevBoundary != prevSrc) { + buffer.append(s, prevBoundary, prevSrc); + } + int recomposeStartIndex = buffer.length(); + // We know there is not a boundary here. + decomposeShort(s, prevSrc, src, false /* !stopAtCompBoundary */, onlyContiguous, buffer); + // Decompose until the next boundary. + src = decomposeShort(s, src, limit, true /* stopAtCompBoundary */, onlyContiguous, buffer); + recompose(buffer, recomposeStartIndex, onlyContiguous); + if (!doCompose) { + if (!buffer.equals(s, prevSrc, src)) { + return false; + } + buffer.remove(); + } + prevBoundary = src; + } + } + + /** + * Very similar to compose(): Make the same changes in both places if relevant. + * doSpan: spanQuickCheckYes (ignore bit 0 of the return value) !doSpan: + * quickCheck + * + * @return bits 31..1: spanQuickCheckYes (==s.length() if "yes") and bit 0: set + * if "maybe"; otherwise, if the span length<s.length() then the + * quick check result is "no" + */ + public int composeQuickCheck(CharSequence s, int src, int limit, boolean onlyContiguous, boolean doSpan) { + int qcResult = 0; + int prevBoundary = src; + int minNoMaybeCP = minCompNoMaybeCP; + + for (;;) { + // Fast path: Scan over a sequence of characters below the minimum "no or maybe" + // code point, + // or with (compYes && ccc==0) properties. + int prevSrc; + int c = 0; + int norm16 = 0; + for (;;) { + if (src == limit) { + return (src << 1) | qcResult; // "yes" or "maybe" + } + if ((c = s.charAt(src)) < minNoMaybeCP || isCompYesAndZeroCC(norm16 = normTrie.bmpGet(c))) { + ++src; + } else { + prevSrc = src++; + if (!UTF16Plus.isLeadSurrogate(c)) { + break; + } else { + char c2; + if (src != limit && Character.isLowSurrogate(c2 = s.charAt(src))) { + ++src; + c = Character.toCodePoint((char) c, c2); + norm16 = normTrie.suppGet(c); + if (!isCompYesAndZeroCC(norm16)) { + break; + } + } + } + } + } + // isCompYesAndZeroCC(norm16) is false, that is, norm16>=minNoNo. + // The current character is either a "noNo" (has a mapping) + // or a "maybeYes" (combines backward) + // or a "yesYes" with ccc!=0. + // It is not a Hangul syllable or Jamo L because those have "yes" properties. + + int prevNorm16 = INERT; + if (prevBoundary != prevSrc) { + prevBoundary = prevSrc; + if (!norm16HasCompBoundaryBefore(norm16)) { + c = Character.codePointBefore(s, prevSrc); + int n16 = getNorm16(c); + if (!norm16HasCompBoundaryAfter(n16, onlyContiguous)) { + prevBoundary -= Character.charCount(c); + prevNorm16 = n16; + } + } + } + + if (isMaybeOrNonZeroCC(norm16)) { + int cc = getCCFromYesOrMaybe(norm16); + if (onlyContiguous /* FCC */ && cc != 0 && getTrailCCFromCompYesAndZeroCC(prevNorm16) > cc) { + // The [prevBoundary..prevSrc[ character + // passed the quick check "yes && ccc==0" test + // but is out of canonical order with the current combining mark. + } else { + // If !onlyContiguous (not FCC), then we ignore the tccc of + // the previous character which passed the quick check "yes && ccc==0" test. + for (;;) { + if (norm16 < MIN_YES_YES_WITH_CC) { + if (!doSpan) { + qcResult = 1; + } else { + return prevBoundary << 1; // spanYes does not care to know it's "maybe" + } + } + if (src == limit) { + return (src << 1) | qcResult; // "yes" or "maybe" + } + int prevCC = cc; + c = Character.codePointAt(s, src); + norm16 = getNorm16(c); + if (isMaybeOrNonZeroCC(norm16)) { + cc = getCCFromYesOrMaybe(norm16); + if (!(prevCC <= cc || cc == 0)) { + break; + } + } else { + break; + } + src += Character.charCount(c); + } + // src is after the last in-order combining mark. + if (isCompYesAndZeroCC(norm16)) { + prevBoundary = src; + src += Character.charCount(c); + continue; + } + } + } + return prevBoundary << 1; // "no" + } + } + + public void composeAndAppend(CharSequence s, boolean doCompose, boolean onlyContiguous, ReorderingBuffer buffer) { + int src = 0, limit = s.length(); + if (!buffer.isEmpty()) { + int firstStarterInSrc = findNextCompBoundary(s, 0, limit, onlyContiguous); + if (0 != firstStarterInSrc) { + int lastStarterInDest = findPreviousCompBoundary(buffer.getStringBuilder(), buffer.length(), + onlyContiguous); + StringBuilder middle = new StringBuilder( + (buffer.length() - lastStarterInDest) + firstStarterInSrc + 16); + middle.append(buffer.getStringBuilder(), lastStarterInDest, buffer.length()); + buffer.removeSuffix(buffer.length() - lastStarterInDest); + middle.append(s, 0, firstStarterInSrc); + compose(middle, 0, middle.length(), onlyContiguous, true, buffer); + src = firstStarterInSrc; + } + } + if (doCompose) { + compose(s, src, limit, onlyContiguous, true, buffer); + } else { + buffer.append(s, src, limit); + } + } + + // Dual functionality: + // buffer!=NULL: normalize + // buffer==NULL: isNormalized/quickCheck/spanQuickCheckYes + public int makeFCD(CharSequence s, int src, int limit, ReorderingBuffer buffer) { + // Note: In this function we use buffer->appendZeroCC() because we track + // the lead and trail combining classes here, rather than leaving it to + // the ReorderingBuffer. + // The exception is the call to decomposeShort() which uses the buffer + // in the normal way. + + // Tracks the last FCD-safe boundary, before lccc=0 or after properly-ordered + // tccc<=1. + // Similar to the prevBoundary in the compose() implementation. + int prevBoundary = src; + int prevSrc; + int c = 0; + int prevFCD16 = 0; + int fcd16 = 0; + + for (;;) { + // count code units with lccc==0 + for (prevSrc = src; src != limit;) { + if ((c = s.charAt(src)) < minLcccCP) { + prevFCD16 = ~c; + ++src; + } else if (!singleLeadMightHaveNonZeroFCD16(c)) { + prevFCD16 = 0; + ++src; + } else { + if (UTF16Plus.isLeadSurrogate(c)) { + char c2; + if ((src + 1) != limit && Character.isLowSurrogate(c2 = s.charAt(src + 1))) { + c = Character.toCodePoint((char) c, c2); + } + } + if ((fcd16 = getFCD16FromNormData(c)) <= 0xff) { + prevFCD16 = fcd16; + src += Character.charCount(c); + } else { + break; + } + } + } + // copy these code units all at once + if (src != prevSrc) { + if (src == limit) { + if (buffer != null) { + buffer.flushAndAppendZeroCC(s, prevSrc, src); + } + break; + } + prevBoundary = src; + // We know that the previous character's lccc==0. + if (prevFCD16 < 0) { + // Fetching the fcd16 value was deferred for this below-minLcccCP code point. + int prev = ~prevFCD16; + if (prev < minDecompNoCP) { + prevFCD16 = 0; + } else { + prevFCD16 = getFCD16FromNormData(prev); + if (prevFCD16 > 1) { + --prevBoundary; + } + } + } else { + int p = src - 1; + if (Character.isLowSurrogate(s.charAt(p)) && prevSrc < p + && Character.isHighSurrogate(s.charAt(p - 1))) { + --p; + // Need to fetch the previous character's FCD value because + // prevFCD16 was just for the trail surrogate code point. + prevFCD16 = getFCD16FromNormData(Character.toCodePoint(s.charAt(p), s.charAt(p + 1))); + // Still known to have lccc==0 because its lead surrogate unit had lccc==0. + } + if (prevFCD16 > 1) { + prevBoundary = p; + } + } + if (buffer != null) { + // The last lccc==0 character is excluded from the + // flush-and-append call in case it needs to be modified. + buffer.flushAndAppendZeroCC(s, prevSrc, prevBoundary); + buffer.append(s, prevBoundary, src); + } + // The start of the current character (c). + prevSrc = src; + } else if (src == limit) { + break; + } + + src += Character.charCount(c); + // The current character (c) at [prevSrc..src[ has a non-zero lead combining + // class. + // Check for proper order, and decompose locally if necessary. + if ((prevFCD16 & 0xff) <= (fcd16 >> 8)) { + // proper order: prev tccc <= current lccc + if ((fcd16 & 0xff) <= 1) { + prevBoundary = src; + } + if (buffer != null) { + buffer.appendZeroCC(c); + } + prevFCD16 = fcd16; + continue; + } else if (buffer == null) { + return prevBoundary; // quick check "no" + } else { + /* + * Back out the part of the source that we copied or appended already but is now + * going to be decomposed. prevSrc is set to after what was copied/appended. + */ + buffer.removeSuffix(prevSrc - prevBoundary); + /* + * Find the part of the source that needs to be decomposed, up to the next safe + * boundary. + */ + src = findNextFCDBoundary(s, src, limit); + /* + * The source text does not fulfill the conditions for FCD. Decompose and + * reorder a limited piece of the text. + */ + decomposeShort(s, prevBoundary, src, false, false, buffer); + prevBoundary = src; + prevFCD16 = 0; + } + } + return src; + } + + public boolean hasDecompBoundaryBefore(int c) { + return c < minLcccCP || (c <= 0xffff && !singleLeadMightHaveNonZeroFCD16(c)) + || norm16HasDecompBoundaryBefore(getNorm16(c)); + } + + public boolean norm16HasDecompBoundaryBefore(int norm16) { + if (norm16 < minNoNoCompNoMaybeCC) { + return true; + } + if (norm16 >= limitNoNo) { + return norm16 <= MIN_NORMAL_MAYBE_YES || norm16 == JAMO_VT; + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + // true if leadCC==0 (hasFCDBoundaryBefore()) + return (firstUnit & MAPPING_HAS_CCC_LCCC_WORD) == 0 || (extraData.charAt(mapping - 1) & 0xff00) == 0; + } + + public boolean hasDecompBoundaryAfter(int c) { + if (c < minDecompNoCP) { + return true; + } + if (c <= 0xffff && !singleLeadMightHaveNonZeroFCD16(c)) { + return true; + } + return norm16HasDecompBoundaryAfter(getNorm16(c)); + } + + public boolean norm16HasDecompBoundaryAfter(int norm16) { + if (norm16 <= minYesNo || isHangulLVT(norm16)) { + return true; + } + if (norm16 >= limitNoNo) { + if (isMaybeOrNonZeroCC(norm16)) { + return norm16 <= MIN_NORMAL_MAYBE_YES || norm16 == JAMO_VT; + } + // Maps to an isCompYesAndZeroCC. + return (norm16 & DELTA_TCCC_MASK) <= DELTA_TCCC_1; + } + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + // decomp after-boundary: same as hasFCDBoundaryAfter(), + // fcd16<=1 || trailCC==0 + if (firstUnit > 0x1ff) { + return false; // trailCC>1 + } + if (firstUnit <= 0xff) { + return true; // trailCC==0 + } + // if(trailCC==1) test leadCC==0, same as checking for before-boundary + // true if leadCC==0 (hasFCDBoundaryBefore()) + return (firstUnit & MAPPING_HAS_CCC_LCCC_WORD) == 0 || (extraData.charAt(mapping - 1) & 0xff00) == 0; + } + + public boolean isDecompInert(int c) { + return isDecompYesAndZeroCC(getNorm16(c)); + } + + public boolean hasCompBoundaryBefore(int c) { + return c < minCompNoMaybeCP || norm16HasCompBoundaryBefore(getNorm16(c)); + } + + public boolean hasCompBoundaryAfter(int c, boolean onlyContiguous) { + return norm16HasCompBoundaryAfter(getNorm16(c), onlyContiguous); + } + + private boolean isMaybe(int norm16) { + return minMaybeYes <= norm16 && norm16 <= JAMO_VT; + } + + private boolean isMaybeOrNonZeroCC(int norm16) { + return norm16 >= minMaybeYes; + } + + private static boolean isInert(int norm16) { + return norm16 == INERT; + } + + private static boolean isJamoVT(int norm16) { + return norm16 == JAMO_VT; + } + + private int hangulLVT() { + return minYesNoMappingsOnly | HAS_COMP_BOUNDARY_AFTER; + } + + private boolean isHangulLV(int norm16) { + return norm16 == minYesNo; + } + + private boolean isHangulLVT(int norm16) { + return norm16 == hangulLVT(); + } + + private boolean isCompYesAndZeroCC(int norm16) { + return norm16 < minNoNo; + } + + // UBool isCompYes(uint16_t norm16) const { + // return norm16>=MIN_YES_YES_WITH_CC || norm16= limitNoNo; + } + + // For use with isCompYes(). + // Perhaps the compiler can combine the two tests for MIN_YES_YES_WITH_CC. + // static uint8_t getCCFromYes(uint16_t norm16) { + // return norm16>=MIN_YES_YES_WITH_CC ? getCCFromNormalYesOrMaybe(norm16) : 0; + // } + private int getCCFromNoNo(int norm16) { + int mapping = norm16 >> OFFSET_SHIFT; + if ((extraData.charAt(mapping) & MAPPING_HAS_CCC_LCCC_WORD) != 0) { + return extraData.charAt(mapping - 1) & 0xff; + } else { + return 0; + } + } + + int getTrailCCFromCompYesAndZeroCC(int norm16) { + if (norm16 <= minYesNo) { + return 0; // yesYes and Hangul LV have ccc=tccc=0 + } else { + // For Hangul LVT we harmlessly fetch a firstUnit with tccc=0 here. + return extraData.charAt(norm16 >> OFFSET_SHIFT) >> 8; // tccc from yesNo + } + } + + // Requires algorithmic-NoNo. + private int mapAlgorithmic(int c, int norm16) { + return c + (norm16 >> DELTA_SHIFT) - centerNoNoDelta; + } + + // Requires minYesNo>OFFSET_SHIFT); + // } + + /** + * @return index into maybeYesCompositions, or -1 + */ + private int getCompositionsListForDecompYes(int norm16) { + if (norm16 < JAMO_L || MIN_NORMAL_MAYBE_YES <= norm16) { + return -1; + } else { + if ((norm16 -= minMaybeYes) < 0) { + // norm16> OFFSET_SHIFT; + } + } + + /** + * @return index into maybeYesCompositions + */ + private int getCompositionsListForComposite(int norm16) { + // A composite has both mapping & compositions list. + int list = ((MIN_NORMAL_MAYBE_YES - minMaybeYes) + norm16) >> OFFSET_SHIFT; + int firstUnit = maybeYesCompositions.charAt(list); + return list + // mapping in maybeYesCompositions + 1 + // +1 to skip the first unit with the mapping length + (firstUnit & MAPPING_LENGTH_MASK); // + mapping length + } + + // Decompose a short piece of text which is likely to contain characters that + // fail the quick check loop and/or where the quick check loop's overhead + // is unlikely to be amortized. + // Called by the compose() and makeFCD() implementations. + // Public in Java for collation implementation code. + private int decomposeShort(CharSequence s, int src, int limit, boolean stopAtCompBoundary, boolean onlyContiguous, + ReorderingBuffer buffer) { + while (src < limit) { + int c = Character.codePointAt(s, src); + if (stopAtCompBoundary && c < minCompNoMaybeCP) { + return src; + } + int norm16 = getNorm16(c); + if (stopAtCompBoundary && norm16HasCompBoundaryBefore(norm16)) { + return src; + } + src += Character.charCount(c); + decompose(c, norm16, buffer); + if (stopAtCompBoundary && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + return src; + } + } + return src; + } + + private void decompose(int c, int norm16, ReorderingBuffer buffer) { + // get the decomposition and the lead and trail cc's + if (norm16 >= limitNoNo) { + if (isMaybeOrNonZeroCC(norm16)) { + buffer.append(c, getCCFromYesOrMaybe(norm16)); + return; + } + // Maps to an isCompYesAndZeroCC. + c = mapAlgorithmic(c, norm16); + norm16 = getRawNorm16(c); + } + if (norm16 < minYesNo) { + // c does not decompose + buffer.append(c, 0); + } else if (isHangulLV(norm16) || isHangulLVT(norm16)) { + // Hangul syllable: decompose algorithmically + Hangul.decompose(c, buffer); + } else { + // c decomposes, get everything from the variable-length extra data + int mapping = norm16 >> OFFSET_SHIFT; + int firstUnit = extraData.charAt(mapping); + int length = firstUnit & MAPPING_LENGTH_MASK; + int leadCC, trailCC; + trailCC = firstUnit >> 8; + if ((firstUnit & MAPPING_HAS_CCC_LCCC_WORD) != 0) { + leadCC = extraData.charAt(mapping - 1) >> 8; + } else { + leadCC = 0; + } + ++mapping; // skip over the firstUnit + buffer.append(extraData, mapping, mapping + length, true, leadCC, trailCC); + } + } + + /** + * Finds the recomposition result for a forward-combining "lead" character, + * specified with a pointer to its compositions list, and a backward-combining + * "trail" character. + * + *

+ * If the lead and trail characters combine, then this function returns the + * following "compositeAndFwd" value: + * + *

+	 * Bits 21..1  composite character
+	 * Bit      0  set if the composite is a forward-combining starter
+	 * 
+ * + * otherwise it returns -1. + * + *

+ * The compositions list has (trail, compositeAndFwd) pair entries, encoded as + * either pairs or triples of 16-bit units. The last entry has the high bit of + * its first unit set. + * + *

+ * The list is sorted by ascending trail characters (there are no duplicates). A + * linear search is used. + * + *

+ * See normalizer2impl.h for a more detailed description of the compositions + * list format. + */ + private static int combine(String compositions, int list, int trail) { + int key1, firstUnit; + if (trail < COMP_1_TRAIL_LIMIT) { + // trail character is 0..33FF + // result entry may have 2 or 3 units + key1 = (trail << 1); + while (key1 > (firstUnit = compositions.charAt(list))) { + list += 2 + (firstUnit & COMP_1_TRIPLE); + } + if (key1 == (firstUnit & COMP_1_TRAIL_MASK)) { + if ((firstUnit & COMP_1_TRIPLE) != 0) { + return (compositions.charAt(list + 1) << 16) | compositions.charAt(list + 2); + } else { + return compositions.charAt(list + 1); + } + } + } else { + // trail character is 3400..10FFFF + // result entry has 3 units + key1 = COMP_1_TRAIL_LIMIT + (((trail >> COMP_1_TRAIL_SHIFT)) & ~COMP_1_TRIPLE); + int key2 = (trail << COMP_2_TRAIL_SHIFT) & 0xffff; + int secondUnit; + for (;;) { + if (key1 > (firstUnit = compositions.charAt(list))) { + list += 2 + (firstUnit & COMP_1_TRIPLE); + } else if (key1 == (firstUnit & COMP_1_TRAIL_MASK)) { + if (key2 > (secondUnit = compositions.charAt(list + 1))) { + if ((firstUnit & COMP_1_LAST_TUPLE) != 0) { + break; + } else { + list += 3; + } + } else if (key2 == (secondUnit & COMP_2_TRAIL_MASK)) { + return ((secondUnit & ~COMP_2_TRAIL_MASK) << 16) | compositions.charAt(list + 2); + } else { + break; + } + } else { + break; + } + } + } + return -1; + } + + /* + * Recomposes the buffer text starting at recomposeStartIndex (which is in NFD - + * decomposed and canonically ordered), and truncates the buffer contents. + * + * Note that recomposition never lengthens the text: Any character consists of + * either one or two code units; a composition may contain at most one more code + * unit than the original starter, while the combining mark that is removed has + * at least one code unit. + */ + private void recompose(ReorderingBuffer buffer, int recomposeStartIndex, boolean onlyContiguous) { + StringBuilder sb = buffer.getStringBuilder(); + int p = recomposeStartIndex; + if (p == sb.length()) { + return; + } + + int starter, pRemove; + int compositionsList; + int c, compositeAndFwd; + int norm16; + int cc, prevCC; + boolean starterIsSupplementary; + + // Some of the following variables are not used until we have a + // forward-combining starter + // and are only initialized now to avoid compiler warnings. + compositionsList = -1; // used as indicator for whether we have a forward-combining starter + starter = -1; + starterIsSupplementary = false; + prevCC = 0; + + for (;;) { + c = sb.codePointAt(p); + p += Character.charCount(c); + norm16 = getNorm16(c); + cc = getCCFromYesOrMaybe(norm16); + if ( // this character combines backward and + isMaybe(norm16) && + // we have seen a starter that combines forward and + compositionsList >= 0 && + // the backward-combining character is not blocked + (prevCC < cc || prevCC == 0)) { + if (isJamoVT(norm16)) { + // c is a Jamo V/T, see if we can compose it with the previous character. + if (c < Hangul.JAMO_T_BASE) { + // c is a Jamo Vowel, compose with previous Jamo L and following Jamo T. + char prev = (char) (sb.charAt(starter) - Hangul.JAMO_L_BASE); + if (prev < Hangul.JAMO_L_COUNT) { + pRemove = p - 1; + char syllable = (char) (Hangul.HANGUL_BASE + + (prev * Hangul.JAMO_V_COUNT + (c - Hangul.JAMO_V_BASE)) * Hangul.JAMO_T_COUNT); + char t; + if (p != sb.length() + && (t = (char) (sb.charAt(p) - Hangul.JAMO_T_BASE)) < Hangul.JAMO_T_COUNT) { + ++p; + syllable += t; // The next character was a Jamo T. + } + sb.setCharAt(starter, syllable); + // remove the Jamo V/T + sb.delete(pRemove, p); + p = pRemove; + } + } + /* + * No "else" for Jamo T: Since the input is in NFD, there are no Hangul LV + * syllables that a Jamo T could combine with. All Jamo Ts are combined above + * when handling Jamo Vs. + */ + if (p == sb.length()) { + break; + } + compositionsList = -1; + continue; + } else if ((compositeAndFwd = combine(maybeYesCompositions, compositionsList, c)) >= 0) { + // The starter and the combining mark (c) do combine. + int composite = compositeAndFwd >> 1; + + // Remove the combining mark. + pRemove = p - Character.charCount(c); // pRemove & p: start & limit of the combining mark + sb.delete(pRemove, p); + p = pRemove; + // Replace the starter with the composite. + if (starterIsSupplementary) { + if (composite > 0xffff) { + // both are supplementary + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.setCharAt(starter + 1, UTF16.getTrailSurrogate(composite)); + } else { + sb.setCharAt(starter, (char) c); + sb.deleteCharAt(starter + 1); + // The composite is shorter than the starter, + // move the intermediate characters forward one. + starterIsSupplementary = false; + --p; + } + } else if (composite > 0xffff) { + // The composite is longer than the starter, + // move the intermediate characters back one. + starterIsSupplementary = true; + sb.setCharAt(starter, UTF16.getLeadSurrogate(composite)); + sb.insert(starter + 1, UTF16.getTrailSurrogate(composite)); + ++p; + } else { + // both are on the BMP + sb.setCharAt(starter, (char) composite); + } + + // Keep prevCC because we removed the combining mark. + + if (p == sb.length()) { + break; + } + // Is the composite a starter that combines forward? + if ((compositeAndFwd & 1) != 0) { + compositionsList = getCompositionsListForComposite(getRawNorm16(composite)); + } else { + compositionsList = -1; + } + + // We combined; continue with looking for compositions. + continue; + } + } + + // no combination this time + prevCC = cc; + if (p == sb.length()) { + break; + } + + // If c did not combine, then check if it is a starter. + if (cc == 0) { + // Found a new starter. + if ((compositionsList = getCompositionsListForDecompYes(norm16)) >= 0) { + // It may combine with something, prepare for it. + if (c <= 0xffff) { + starterIsSupplementary = false; + starter = p - 1; + } else { + starterIsSupplementary = true; + starter = p - 2; + } + } + } else if (onlyContiguous) { + // FCC: no discontiguous compositions; any intervening character blocks. + compositionsList = -1; + } + } + buffer.flush(); + } + + /** + * Does c have a composition boundary before it? True if its decomposition + * begins with a character that has ccc=0 && NFC_QC=Yes (isCompYesAndZeroCC()). + * As a shortcut, this is true if c itself has ccc=0 && NFC_QC=Yes + * (isCompYesAndZeroCC()) so we need not decompose. + */ + private boolean hasCompBoundaryBefore(int c, int norm16) { + return c < minCompNoMaybeCP || norm16HasCompBoundaryBefore(norm16); + } + + private boolean norm16HasCompBoundaryBefore(int norm16) { + return norm16 < minNoNoCompNoMaybeCC || isAlgorithmicNoNo(norm16); + } + + private boolean hasCompBoundaryBefore(CharSequence s, int src, int limit) { + return src == limit || hasCompBoundaryBefore(Character.codePointAt(s, src)); + } + + private boolean norm16HasCompBoundaryAfter(int norm16, boolean onlyContiguous) { + return (norm16 & HAS_COMP_BOUNDARY_AFTER) != 0 && (!onlyContiguous || isTrailCC01ForCompBoundaryAfter(norm16)); + } + + private boolean hasCompBoundaryAfter(CharSequence s, int start, int p, boolean onlyContiguous) { + return start == p || hasCompBoundaryAfter(Character.codePointBefore(s, p), onlyContiguous); + } + + /** For FCC: Given norm16 HAS_COMP_BOUNDARY_AFTER, does it have tccc<=1? */ + private boolean isTrailCC01ForCompBoundaryAfter(int norm16) { + return isInert(norm16) || (isDecompNoAlgorithmic(norm16) ? (norm16 & DELTA_TCCC_MASK) <= DELTA_TCCC_1 + : extraData.charAt(norm16 >> OFFSET_SHIFT) <= 0x1ff); + } + + private int findPreviousCompBoundary(CharSequence s, int p, boolean onlyContiguous) { + while (p > 0) { + int c = Character.codePointBefore(s, p); + int norm16 = getNorm16(c); + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + break; + } + p -= Character.charCount(c); + if (hasCompBoundaryBefore(c, norm16)) { + break; + } + } + return p; + } + + private int findNextCompBoundary(CharSequence s, int p, int limit, boolean onlyContiguous) { + while (p < limit) { + int c = Character.codePointAt(s, p); + int norm16 = normTrie.get(c); + if (hasCompBoundaryBefore(c, norm16)) { + break; + } + p += Character.charCount(c); + if (norm16HasCompBoundaryAfter(norm16, onlyContiguous)) { + break; + } + } + return p; + } + + private int findNextFCDBoundary(CharSequence s, int p, int limit) { + while (p < limit) { + int c = Character.codePointAt(s, p); + int norm16; + if (c < minLcccCP || norm16HasDecompBoundaryBefore(norm16 = getNorm16(c))) { + break; + } + p += Character.charCount(c); + if (norm16HasDecompBoundaryAfter(norm16)) { + break; + } + } + return p; + } + + /** + * Get the canonical decomposition sherman for ComposedCharIter + */ + public static int getDecompose(int chars[], String decomps[]) { + Normalizer2 impl = Normalizer2.getNFDInstance(); + + int length = 0; + int norm16 = 0; + int ch = -1; + int i = 0; + + while (++ch < 0x2fa1e) { // no cannoical above 0x3ffff + // TBD !!!! the hack code heres save us about 50ms for startup + // need a better solution/lookup + if (ch == 0x30ff) + ch = 0xf900; + else if (ch == 0x115bc) + ch = 0x1d15e; + else if (ch == 0x1d1c1) + ch = 0x2f800; + + String s = impl.getDecomposition(ch); + + if (s != null && i < chars.length) { + chars[i] = ch; + decomps[i++] = s; + } + } + return i; + } + + // ------------------------------------------------------ + // special method for Collation (RBTableBuilder.build()) + // ------------------------------------------------------ + private static boolean needSingleQuotation(char c) { + return (c >= 0x0009 && c <= 0x000D) || (c >= 0x0020 && c <= 0x002F) || (c >= 0x003A && c <= 0x0040) + || (c >= 0x005B && c <= 0x0060) || (c >= 0x007B && c <= 0x007E); + } + + public static String canonicalDecomposeWithSingleQuotation(String string) { + Normalizer2 impl = Normalizer2.getNFDInstance(); + char[] src = string.toCharArray(); + int srcIndex = 0; + int srcLimit = src.length; + char[] dest = new char[src.length * 3]; // MAX_BUF_SIZE_DECOMPOSE = 3 + int destIndex = 0; + int destLimit = dest.length; + + int prevSrc; + String norm; + int reorderStartIndex, length; + char c1, c2; + int cp; + int minNoMaybe = 0x00c0; + int cc, prevCC, trailCC; + char[] p; + int pStart; + + // initialize + reorderStartIndex = 0; + prevCC = 0; + norm = null; + cp = 0; + pStart = 0; + + cc = trailCC = -1; // initialize to bogus value + c1 = 0; + for (;;) { + prevSrc = srcIndex; + // quick check (1)less than minNoMaybe (2)no decomp (3)hangual + while (srcIndex != srcLimit && ((c1 = src[srcIndex]) < minNoMaybe + || (norm = impl.getDecomposition(cp = string.codePointAt(srcIndex))) == null + || (c1 >= '\uac00' && c1 <= '\ud7a3'))) { // Hangul Syllables + prevCC = 0; + srcIndex += (cp < 0x10000) ? 1 : 2; + } + + // copy these code units all at once + if (srcIndex != prevSrc) { + length = srcIndex - prevSrc; + if ((destIndex + length) <= destLimit) { + System.arraycopy(src, prevSrc, dest, destIndex, length); + } + + destIndex += length; + reorderStartIndex = destIndex; + } + + // end of source reached? + if (srcIndex == srcLimit) { + break; + } + + // cp already contains *src and norm32 is set for it, increment src + srcIndex += (cp < 0x10000) ? 1 : 2; + + if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + c2 = 0; + length = 1; + + if (Character.isHighSurrogate(c1) || Character.isLowSurrogate(c1)) { + norm = null; + } + } else { + length = 2; + c2 = src[srcIndex - 1]; + } + + // get the decomposition and the lead and trail cc's + if (norm == null) { + // cp does not decompose + cc = trailCC = UCharacter.getCombiningClass(cp); + p = null; + pStart = -1; + } else { + + pStart = 0; + p = norm.toCharArray(); + length = p.length; + int cpNum = norm.codePointCount(0, length); + cc = UCharacter.getCombiningClass(norm.codePointAt(0)); + trailCC = UCharacter.getCombiningClass(norm.codePointAt(cpNum - 1)); + if (length == 1) { + // fastpath a single code unit from decomposition + c1 = p[pStart]; + c2 = 0; + p = null; + pStart = -1; + } + } + + if ((destIndex + length * 3) >= destLimit) { // 2 SingleQuotations + // buffer overflow + char[] tmpBuf = new char[destLimit * 2]; + System.arraycopy(dest, 0, tmpBuf, 0, destIndex); + dest = tmpBuf; + destLimit = dest.length; + } + + // append the decomposition to the destination buffer, assume length>0 + { + int reorderSplit = destIndex; + if (p == null) { + // fastpath: single code point + if (needSingleQuotation(c1)) { + // if we need single quotation, no need to consider "prevCC" + // and it must NOT be a supplementary pair + dest[destIndex++] = '\''; + dest[destIndex++] = c1; + dest[destIndex++] = '\''; + trailCC = 0; + } else if (cc != 0 && cc < prevCC) { + // (c1, c2) is out of order with respect to the preceding + // text + destIndex += length; + trailCC = insertOrdered(dest, reorderStartIndex, reorderSplit, destIndex, c1, c2, cc); + } else { + // just append (c1, c2) + dest[destIndex++] = c1; + if (c2 != 0) { + dest[destIndex++] = c2; + } + } + } else { + // general: multiple code points (ordered by themselves) + // from decomposition + if (needSingleQuotation(p[pStart])) { + dest[destIndex++] = '\''; + dest[destIndex++] = p[pStart++]; + dest[destIndex++] = '\''; + length--; + do { + dest[destIndex++] = p[pStart++]; + } while (--length > 0); + } else if (cc != 0 && cc < prevCC) { + destIndex += length; + trailCC = mergeOrdered(dest, reorderStartIndex, reorderSplit, p, pStart, pStart + length); + } else { + // just append the decomposition + do { + dest[destIndex++] = p[pStart++]; + } while (--length > 0); + } + } + } + prevCC = trailCC; + if (prevCC == 0) { + reorderStartIndex = destIndex; + } + } + + return new String(dest, 0, destIndex); + } + + /** + * simpler, single-character version of mergeOrdered() - bubble-insert one + * single code point into the preceding string which is already canonically + * ordered (c, c2) may or may not yet have been inserted at src[current]..src[p] + * + * it must be p=current+lengthof(c, c2) i.e. p=current+(c2==0 ? 1 : 2) + * + * before: src[start]..src[current] is already ordered, and src[current]..src[p] + * may or may not hold (c, c2) but must be exactly the same length as (c, c2) + * after: src[start]..src[p] is ordered + * + * @return the trailing combining class + */ + private static int/* unsigned byte */ insertOrdered(char[] source, int start, int current, int p, char c1, char c2, + int/* unsigned byte */ cc) { + int back, preBack; + int r; + int prevCC, trailCC = cc; + + if (start < current && cc != 0) { + // search for the insertion point where cc>=prevCC + preBack = back = current; + + PrevArgs prevArgs = new PrevArgs(); + prevArgs.current = current; + prevArgs.start = start; + prevArgs.src = source; + prevArgs.c1 = c1; + prevArgs.c2 = c2; + + // get the prevCC + prevCC = getPrevCC(prevArgs); + preBack = prevArgs.current; + + if (cc < prevCC) { + // this will be the last code point, so keep its cc + trailCC = prevCC; + back = preBack; + while (start < preBack) { + prevCC = getPrevCC(prevArgs); + preBack = prevArgs.current; + if (cc >= prevCC) { + break; + } + back = preBack; + } + + // this is where we are right now with all these indicies: + // [start]..[pPreBack] 0..? code points that we can ignore + // [pPreBack]..[pBack] 0..1 code points with prevCC<=cc + // [pBack]..[current] 0..n code points with >cc, move up to insert (c, c2) + // [current]..[p] 1 code point (c, c2) with cc + + // move the code units in between up + r = p; + do { + source[--r] = source[--current]; + } while (back != current); + } + } + + // insert (c1, c2) + source[current] = c1; + if (c2 != 0) { + source[(current + 1)] = c2; + } + + // we know the cc of the last code point + return trailCC; + } + + /** + * merge two UTF-16 string parts together to canonically order (order by + * combining classes) their concatenation + * + * the two strings may already be adjacent, so that the merging is done in-place + * if the two strings are not adjacent, then the buffer holding the first one + * must be large enough the second string may or may not be ordered in itself + * + * before: [start]..[current] is already ordered, and [next]..[limit] may be + * ordered in itself, but is not in relation to [start..current[ after: + * [start..current+(limit-next)[ is ordered + * + * the algorithm is a simple bubble-sort that takes the characters from + * src[next++] and inserts them in correct combining class order into the + * preceding part of the string + * + * since this function is called much less often than the single-code point + * insertOrdered(), it just uses that for easier maintenance + * + * @return the trailing combining class + */ + private static int /* unsigned byte */ mergeOrdered(char[] source, int start, int current, char[] data, int next, + int limit) { + int r; + int /* unsigned byte */ cc, trailCC = 0; + boolean adjacent; + + adjacent = current == next; + NextCCArgs ncArgs = new NextCCArgs(); + ncArgs.source = data; + ncArgs.next = next; + ncArgs.limit = limit; + + if (start != current) { + + while (ncArgs.next < ncArgs.limit) { + cc = getNextCC(ncArgs); + if (cc == 0) { + // does not bubble back + trailCC = 0; + if (adjacent) { + current = ncArgs.next; + } else { + data[current++] = ncArgs.c1; + if (ncArgs.c2 != 0) { + data[current++] = ncArgs.c2; + } + } + break; + } else { + r = current + (ncArgs.c2 == 0 ? 1 : 2); + trailCC = insertOrdered(source, start, current, r, ncArgs.c1, ncArgs.c2, cc); + current = r; + } + } + } + + if (ncArgs.next == ncArgs.limit) { + // we know the cc of the last code point + return trailCC; + } else { + if (!adjacent) { + // copy the second string part + do { + source[current++] = data[ncArgs.next++]; + } while (ncArgs.next != ncArgs.limit); + ncArgs.limit = current; + } + PrevArgs prevArgs = new PrevArgs(); + prevArgs.src = data; + prevArgs.start = start; + prevArgs.current = ncArgs.limit; + return getPrevCC(prevArgs); + } + + } + + private static final class PrevArgs { + char[] src; + int start; + int current; + char c1; + char c2; + } + + private static final class NextCCArgs { + char[] source; + int next; + int limit; + char c1; + char c2; + } + + private static int /* unsigned byte */ getNextCC(NextCCArgs args) { + args.c1 = args.source[args.next++]; + args.c2 = 0; + + if (UTF16.isTrailSurrogate(args.c1)) { + /* unpaired second surrogate */ + return 0; + } else if (!UTF16.isLeadSurrogate(args.c1)) { + return UCharacter.getCombiningClass(args.c1); + } else if (args.next != args.limit && UTF16.isTrailSurrogate(args.c2 = args.source[args.next])) { + ++args.next; + return UCharacter.getCombiningClass(Character.toCodePoint(args.c1, args.c2)); + } else { + /* unpaired first surrogate */ + args.c2 = 0; + return 0; + } + } + + private static int /* unsigned */ getPrevCC(PrevArgs args) { + args.c1 = args.src[--args.current]; + args.c2 = 0; + + if (args.c1 < MIN_CCC_LCCC_CP) { + return 0; + } else if (UTF16.isLeadSurrogate(args.c1)) { + /* unpaired first surrogate */ + return 0; + } else if (!UTF16.isTrailSurrogate(args.c1)) { + return UCharacter.getCombiningClass(args.c1); + } else if (args.current != args.start && UTF16.isLeadSurrogate(args.c2 = args.src[args.current - 1])) { + --args.current; + return UCharacter.getCombiningClass(Character.toCodePoint(args.c2, args.c1)); + } else { + /* unpaired second surrogate */ + args.c2 = 0; + return 0; + } + } + + private int getPreviousTrailCC(CharSequence s, int start, int p) { + if (start == p) { + return 0; + } + return getFCD16(Character.codePointBefore(s, p)); + } + + private VersionInfo dataVersion; + + // BMP code point thresholds for quick check loops looking at single UTF-16 code + // units. + private int minDecompNoCP; + private int minCompNoMaybeCP; + private int minLcccCP; + + // Norm16 value thresholds for quick check combinations and types of extra data. + private int minYesNo; + private int minYesNoMappingsOnly; + private int minNoNo; + private int minNoNoCompBoundaryBefore; + private int minNoNoCompNoMaybeCC; + private int minNoNoEmpty; + private int limitNoNo; + private int centerNoNoDelta; + private int minMaybeYes; + + private CodePointTrie.Fast16 normTrie; + private String maybeYesCompositions; + private String extraData; // mappings and/or compositions for yesYes, yesNo & noNo characters + private byte[] smallFCD; // [0x100] one bit per 32 BMP code points, set if any FCD!=0 +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Punycode.java b/src/main/java/jdk_internal/bidi/icu/impl/Punycode.java new file mode 100755 index 00000000..c6491b0c --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Punycode.java @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 2003-2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/Punycode.java +// - move from package com.ibm.icu.text to package sun.net.idn +// - use ParseException instead of StringPrepParseException +// 2007-08-14 Martin Buchholz +// - remove redundant casts +// +package jdk_internal.bidi.icu.impl; + +import java.text.ParseException; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.UTF16; + +/** + * Ported code from ICU punycode.c + * + * @author ram + */ + +/* Package Private class */ +public final class Punycode { + + /* Punycode parameters for Bootstring */ + private static final int BASE = 36; + private static final int TMIN = 1; + private static final int TMAX = 26; + private static final int SKEW = 38; + private static final int DAMP = 700; + private static final int INITIAL_BIAS = 72; + private static final int INITIAL_N = 0x80; + + /* "Basic" Unicode/ASCII code points */ + private static final int HYPHEN = 0x2d; + private static final int DELIMITER = HYPHEN; + + private static final int ZERO = 0x30; + private static final int NINE = 0x39; + + private static final int SMALL_A = 0x61; + private static final int SMALL_Z = 0x7a; + + private static final int CAPITAL_A = 0x41; + private static final int CAPITAL_Z = 0x5a; + + // TODO: eliminate the 256 limitation + private static final int MAX_CP_COUNT = 256; + + private static final int UINT_MAGIC = 0x80000000; + private static final long ULONG_MAGIC = 0x8000000000000000L; + + private static int adaptBias(int delta, int length, boolean firstTime) { + if (firstTime) { + delta /= DAMP; + } else { + delta /= 2; + } + delta += delta / length; + + int count = 0; + for (; delta > ((BASE - TMIN) * TMAX) / 2; count += BASE) { + delta /= (BASE - TMIN); + } + + return count + (((BASE - TMIN + 1) * delta) / (delta + SKEW)); + } + + /** + * basicToDigit[] contains the numeric value of a basic code point (for use in + * representing integers) in the range 0 to BASE-1, or -1 if b is does not + * represent a value. + */ + static final int[] basicToDigit = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, + -1, -1, -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, + -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, + -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1 }; + + private static char asciiCaseMap(char b, boolean uppercase) { + if (uppercase) { + if (SMALL_A <= b && b <= SMALL_Z) { + b -= (SMALL_A - CAPITAL_A); + } + } else { + if (CAPITAL_A <= b && b <= CAPITAL_Z) { + b += (SMALL_A - CAPITAL_A); + } + } + return b; + } + + /** + * digitToBasic() returns the basic code point whose value (when used for + * representing integers) is d, which must be in the range 0 to BASE-1. The + * lowercase form is used unless the uppercase flag is nonzero, in which case + * the uppercase form is used. + */ + private static char digitToBasic(int digit, boolean uppercase) { + /* 0..25 map to ASCII a..z or A..Z */ + /* 26..35 map to ASCII 0..9 */ + if (digit < 26) { + if (uppercase) { + return (char) (CAPITAL_A + digit); + } else { + return (char) (SMALL_A + digit); + } + } else { + return (char) ((ZERO - 26) + digit); + } + } + + /** + * Converts Unicode to Punycode. The input string must not contain single, + * unpaired surrogates. The output will be represented as an array of ASCII code + * points. + * + * @param src + * @param caseFlags + * @return + * @throws ParseException + */ + public static StringBuffer encode(StringBuffer src, boolean[] caseFlags) throws ParseException { + + int[] cpBuffer = new int[MAX_CP_COUNT]; + int n, delta, handledCPCount, basicLength, destLength, bias, j, m, q, k, t, srcCPCount; + char c, c2; + int srcLength = src.length(); + int destCapacity = MAX_CP_COUNT; + char[] dest = new char[destCapacity]; + StringBuffer result = new StringBuffer(); + /* + * Handle the basic code points and convert extended ones to UTF-32 in cpBuffer + * (caseFlag in sign bit): + */ + srcCPCount = destLength = 0; + + for (j = 0; j < srcLength; ++j) { + if (srcCPCount == MAX_CP_COUNT) { + /* too many input code points */ + throw new ParseException("Too many input code points", -1); + } + c = src.charAt(j); + if (isBasic(c)) { + if (destLength < destCapacity) { + cpBuffer[srcCPCount++] = 0; + dest[destLength] = caseFlags != null ? asciiCaseMap(c, caseFlags[j]) : c; + } + ++destLength; + } else { + n = ((caseFlags != null && caseFlags[j]) ? 1 : 0) << 31L; + if (!UTF16.isSurrogate(c)) { + n |= c; + } else if (UTF16.isLeadSurrogate(c) && (j + 1) < srcLength + && UTF16.isTrailSurrogate(c2 = src.charAt(j + 1))) { + ++j; + + n |= UCharacter.getCodePoint(c, c2); + } else { + /* error: unmatched surrogate */ + throw new ParseException("Illegal char found", -1); + } + cpBuffer[srcCPCount++] = n; + } + } + + /* Finish the basic string - if it is not empty - with a delimiter. */ + basicLength = destLength; + if (basicLength > 0) { + if (destLength < destCapacity) { + dest[destLength] = DELIMITER; + } + ++destLength; + } + + /* + * handledCPCount is the number of code points that have been handled + * basicLength is the number of basic code points destLength is the number of + * chars that have been output + */ + + /* Initialize the state: */ + n = INITIAL_N; + delta = 0; + bias = INITIAL_BIAS; + + /* Main encoding loop: */ + for (handledCPCount = basicLength; handledCPCount < srcCPCount; /* no op */) { + /* + * All non-basic code points < n have been handled already. Find the next larger + * one: + */ + for (m = 0x7fffffff, j = 0; j < srcCPCount; ++j) { + q = cpBuffer[j] & 0x7fffffff; /* remove case flag from the sign bit */ + if (n <= q && q < m) { + m = q; + } + } + + /* + * Increase delta enough to advance the decoder's state to , but + * guard against overflow: + */ + if (m - n > (0x7fffffff - MAX_CP_COUNT - delta) / (handledCPCount + 1)) { + throw new RuntimeException("Internal program error"); + } + delta += (m - n) * (handledCPCount + 1); + n = m; + + /* Encode a sequence of same code points n */ + for (j = 0; j < srcCPCount; ++j) { + q = cpBuffer[j] & 0x7fffffff; /* remove case flag from the sign bit */ + if (q < n) { + ++delta; + } else if (q == n) { + /* Represent delta as a generalized variable-length integer: */ + for (q = delta, k = BASE; /* no condition */; k += BASE) { + + /** + * RAM: comment out the old code for conformance with + * draft-ietf-idn-punycode-03.txt + * + * t=k-bias; if(tTMAX) { t=TMAX; } + */ + + t = k - bias; + if (t < TMIN) { + t = TMIN; + } else if (k >= (bias + TMAX)) { + t = TMAX; + } + + if (q < t) { + break; + } + + if (destLength < destCapacity) { + dest[destLength++] = digitToBasic(t + (q - t) % (BASE - t), false); + } + q = (q - t) / (BASE - t); + } + + if (destLength < destCapacity) { + dest[destLength++] = digitToBasic(q, (cpBuffer[j] < 0)); + } + bias = adaptBias(delta, handledCPCount + 1, (handledCPCount == basicLength)); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + } + + return result.append(dest, 0, destLength); + } + + private static boolean isBasic(int ch) { + return (ch < INITIAL_N); + } + + private static boolean isBasicUpperCase(int ch) { + return (CAPITAL_A <= ch && ch <= CAPITAL_Z); + } + + private static boolean isSurrogate(int ch) { + return (((ch) & 0xfffff800) == 0xd800); + } + + /** + * Converts Punycode to Unicode. The Unicode string will be at most as long as + * the Punycode string. + * + * @param src + * @param caseFlags + * @return + * @throws ParseException + */ + public static StringBuffer decode(StringBuffer src, boolean[] caseFlags) throws ParseException { + int srcLength = src.length(); + StringBuffer result = new StringBuffer(); + int n, destLength, i, bias, basicLength, j, in, oldi, w, k, digit, t, destCPCount, firstSupplementaryIndex, + cpLength; + char b; + int destCapacity = MAX_CP_COUNT; + char[] dest = new char[destCapacity]; + + /* + * Handle the basic code points: Let basicLength be the number of input code + * points before the last delimiter, or 0 if there is none, then copy the first + * basicLength code points to the output. + * + * The two following loops iterate backward. + */ + for (j = srcLength; j > 0;) { + if (src.charAt(--j) == DELIMITER) { + break; + } + } + destLength = basicLength = destCPCount = j; + + while (j > 0) { + b = src.charAt(--j); + if (!isBasic(b)) { + throw new ParseException("Illegal char found", -1); + } + + if (j < destCapacity) { + dest[j] = b; + + if (caseFlags != null) { + caseFlags[j] = isBasicUpperCase(b); + } + } + } + + /* Initialize the state: */ + n = INITIAL_N; + i = 0; + bias = INITIAL_BIAS; + firstSupplementaryIndex = 1000000000; + + /* + * Main decoding loop: Start just after the last delimiter if any basic code + * points were copied; start at the beginning otherwise. + */ + for (in = basicLength > 0 ? basicLength + 1 : 0; in < srcLength; /* no op */) { + /* + * in is the index of the next character to be consumed, and destCPCount is the + * number of code points in the output array. + * + * Decode a generalized variable-length integer into delta, which gets added to + * i. The overflow checking is easier if we increase i as we go, then subtract + * off its starting value at the end to obtain delta. + */ + for (oldi = i, w = 1, k = BASE; /* no condition */; k += BASE) { + if (in >= srcLength) { + throw new ParseException("Illegal char found", -1); + } + + digit = basicToDigit[(byte) src.charAt(in++)]; + if (digit < 0) { + throw new ParseException("Invalid char found", -1); + } + if (digit > (0x7fffffff - i) / w) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + + i += digit * w; + t = k - bias; + if (t < TMIN) { + t = TMIN; + } else if (k >= (bias + TMAX)) { + t = TMAX; + } + if (digit < t) { + break; + } + + if (w > 0x7fffffff / (BASE - t)) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + w *= BASE - t; + } + + /* + * Modification from sample code: Increments destCPCount here, where needed + * instead of in for() loop tail. + */ + ++destCPCount; + bias = adaptBias(i - oldi, destCPCount, (oldi == 0)); + + /* + * i was supposed to wrap around from (incremented) destCPCount to 0, + * incrementing n each time, so we'll fix that now: + */ + if (i / destCPCount > (0x7fffffff - n)) { + /* integer overflow */ + throw new ParseException("Illegal char found", -1); + } + + n += i / destCPCount; + i %= destCPCount; + /* not needed for Punycode: */ + /* if (decode_digit(n) <= BASE) return punycode_invalid_input; */ + + if (n > 0x10ffff || isSurrogate(n)) { + /* Unicode code point overflow */ + throw new ParseException("Illegal char found", -1); + } + + /* Insert n at position i of the output: */ + cpLength = UTF16.getCharCount(n); + if ((destLength + cpLength) < destCapacity) { + int codeUnitIndex; + + /* + * Handle indexes when supplementary code points are present. + * + * In almost all cases, there will be only BMP code points before i and even in + * the entire string. This is handled with the same efficiency as with UTF-32. + * + * Only the rare cases with supplementary code points are handled more slowly - + * but not too bad since this is an insertion anyway. + */ + if (i <= firstSupplementaryIndex) { + codeUnitIndex = i; + if (cpLength > 1) { + firstSupplementaryIndex = codeUnitIndex; + } else { + ++firstSupplementaryIndex; + } + } else { + codeUnitIndex = firstSupplementaryIndex; + codeUnitIndex = UTF16.moveCodePointOffset(dest, 0, destLength, codeUnitIndex, i - codeUnitIndex); + } + + /* use the UChar index codeUnitIndex instead of the code point index i */ + if (codeUnitIndex < destLength) { + System.arraycopy(dest, codeUnitIndex, dest, codeUnitIndex + cpLength, (destLength - codeUnitIndex)); + if (caseFlags != null) { + System.arraycopy(caseFlags, codeUnitIndex, caseFlags, codeUnitIndex + cpLength, + destLength - codeUnitIndex); + } + } + if (cpLength == 1) { + /* BMP, insert one code unit */ + dest[codeUnitIndex] = (char) n; + } else { + /* supplementary character, insert two code units */ + dest[codeUnitIndex] = UTF16.getLeadSurrogate(n); + dest[codeUnitIndex + 1] = UTF16.getTrailSurrogate(n); + } + if (caseFlags != null) { + /* Case of last character determines uppercase flag: */ + caseFlags[codeUnitIndex] = isBasicUpperCase(src.charAt(in - 1)); + if (cpLength == 2) { + caseFlags[codeUnitIndex + 1] = false; + } + } + } + destLength += cpLength; + ++i; + } + result.append(dest, 0, destLength); + return result; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/ReplaceableUCharacterIterator.java b/src/main/java/jdk_internal/bidi/icu/impl/ReplaceableUCharacterIterator.java new file mode 100755 index 00000000..3e090726 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/ReplaceableUCharacterIterator.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import jdk_internal.bidi.icu.text.Replaceable; +import jdk_internal.bidi.icu.text.ReplaceableString; +import jdk_internal.bidi.icu.text.UCharacterIterator; + +/** + * DLF docs must define behavior when Replaceable is mutated underneath the + * iterator. + * + * This and ICUCharacterIterator share some code, maybe they should share an + * implementation, or the common state and implementation should be moved up + * into UCharacterIterator. + * + * What are first, last, and getBeginIndex doing here?!?!?! + */ +public class ReplaceableUCharacterIterator extends UCharacterIterator { + + // public constructor ------------------------------------------------------ + + /** + * Public constructor + * + * @param str text which the iterator will be based on + */ + public ReplaceableUCharacterIterator(String str) { + if (str == null) { + throw new IllegalArgumentException(); + } + this.replaceable = new ReplaceableString(str); + this.currentIndex = 0; + } + + /** + * Public constructor + * + * @param buf buffer of text on which the iterator will be based + */ + public ReplaceableUCharacterIterator(StringBuffer buf) { + if (buf == null) { + throw new IllegalArgumentException(); + } + this.replaceable = new ReplaceableString(buf); + this.currentIndex = 0; + } + + // public methods ---------------------------------------------------------- + + /** + * Creates a copy of this iterator, does not clone the underlying + * Replaceableobject + * + * @return copy of this iterator + */ + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; // never invoked + } + } + + /** + * Returns the current UTF16 character. + * + * @return current UTF16 character + */ + public int current() { + if (currentIndex < replaceable.length()) { + return replaceable.charAt(currentIndex); + } + return DONE; + } + + /** + * Returns the length of the text + * + * @return length of the text + */ + public int getLength() { + return replaceable.length(); + } + + /** + * Gets the current currentIndex in text. + * + * @return current currentIndex in text. + */ + public int getIndex() { + return currentIndex; + } + + /** + * Returns next UTF16 character and increments the iterator's currentIndex by 1. + * If the resulting currentIndex is greater or equal to the text length, the + * currentIndex is reset to the text length and a value of DONECODEPOINT is + * returned. + * + * @return next UTF16 character in text or DONE if the new currentIndex is off + * the end of the text range. + */ + public int next() { + if (currentIndex < replaceable.length()) { + return replaceable.charAt(currentIndex++); + } + return DONE; + } + + /** + * Returns previous UTF16 character and decrements the iterator's currentIndex + * by 1. If the resulting currentIndex is less than 0, the currentIndex is reset + * to 0 and a value of DONECODEPOINT is returned. + * + * @return next UTF16 character in text or DONE if the new currentIndex is off + * the start of the text range. + */ + public int previous() { + if (currentIndex > 0) { + return replaceable.charAt(--currentIndex); + } + return DONE; + } + + /** + * Sets the currentIndex to the specified currentIndex in the text and returns + * that single UTF16 character at currentIndex. This assumes the text is stored + * as 16-bit code units. + * + * @param currentIndex the currentIndex within the text. + * @exception IllegalArgumentException is thrown if an invalid currentIndex is + * supplied. i.e. currentIndex is out of + * bounds. + */ + public void setIndex(int currentIndex) { + if (currentIndex < 0 || currentIndex > replaceable.length()) { + throw new IllegalArgumentException(); + } + this.currentIndex = currentIndex; + } + + public int getText(char[] fillIn, int offset) { + int length = replaceable.length(); + if (offset < 0 || offset + length > fillIn.length) { + throw new IndexOutOfBoundsException(Integer.toString(length)); + } + replaceable.getChars(0, length, fillIn, offset); + return length; + } + + // private data members ---------------------------------------------------- + + /** + * Replaceable object + */ + private Replaceable replaceable; + /** + * Current currentIndex + */ + private int currentIndex; + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/StringPrepDataReader.java b/src/main/java/jdk_internal/bidi/icu/impl/StringPrepDataReader.java new file mode 100755 index 00000000..98aafc74 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/StringPrepDataReader.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/* + ****************************************************************************** + * Copyright (C) 2003, International Business Machines Corporation and * + * others. All Rights Reserved. * + ****************************************************************************** + * + * Created on May 2, 2003 + * + * To change the template for this generated file go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/impl/StringPrepDataReader.java +// - move from package com.ibm.icu.impl to package sun.net.idn +// +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * @author ram + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public final class StringPrepDataReader implements ICUBinary.Authenticate { + + /** + *

+ * private constructor. + *

+ * + * @param inputStream ICU uprop.dat file input stream + * @exception IOException throw if data file fails authentication + * @draft 2.1 + */ + public StringPrepDataReader(InputStream inputStream) throws IOException { + + unicodeVersion = ICUBinary.readHeader(inputStream, DATA_FORMAT_ID, this); + + dataInputStream = new DataInputStream(inputStream); + + } + + public void read(byte[] idnaBytes, char[] mappingTable) throws IOException { + + // Read the bytes that make up the idnaTrie + dataInputStream.read(idnaBytes); + + // Read the extra data + for (int i = 0; i < mappingTable.length; i++) { + mappingTable[i] = dataInputStream.readChar(); + } + } + + public byte[] getDataFormatVersion() { + return DATA_FORMAT_VERSION; + } + + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == DATA_FORMAT_VERSION[0] && version[2] == DATA_FORMAT_VERSION[2] + && version[3] == DATA_FORMAT_VERSION[3]; + } + + public int[] readIndexes(int length) throws IOException { + int[] indexes = new int[length]; + // Read the indexes + for (int i = 0; i < length; i++) { + indexes[i] = dataInputStream.readInt(); + } + return indexes; + } + + public byte[] getUnicodeVersion() { + return unicodeVersion; + } + // private data members ------------------------------------------------- + + /** + * ICU data file input stream + */ + private DataInputStream dataInputStream; + private byte[] unicodeVersion; + /** + * File format version that this class understands. No guarantees are made if a + * older version is used see store.c of gennorm for more information and values + */ + /// * dataFormat="SPRP" 0x53, 0x50, 0x52, 0x50 */ + private static final byte DATA_FORMAT_ID[] = { (byte) 0x53, (byte) 0x50, (byte) 0x52, (byte) 0x50 }; + private static final byte DATA_FORMAT_VERSION[] = { (byte) 0x3, (byte) 0x2, (byte) 0x5, (byte) 0x2 }; + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Trie.java b/src/main/java/jdk_internal/bidi/icu/impl/Trie.java new file mode 100755 index 00000000..2b5038ee --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Trie.java @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.DataInputStream; +import java.io.InputStream; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.UTF16; + +import java.io.IOException; + +/** + *

+ * A trie is a kind of compressed, serializable table of values associated with + * Unicode code points (0..0x10ffff). + *

+ *

+ * This class defines the basic structure of a trie and provides methods to + * retrieve the offsets to the actual data. + *

+ *

+ * Data will be the form of an array of basic types, char or int. + *

+ *

+ * The actual data format will have to be specified by the user in the inner + * static interface com.ibm.icu.impl.Trie.DataManipulate. + *

+ *

+ * This trie implementation is optimized for getting offset while walking + * forward through a UTF-16 string. Therefore, the simplest and fastest access + * macros are the fromLead() and fromOffsetTrail() methods. The fromBMP() method + * are a little more complicated; they get offsets even for lead surrogate + * codepoints, while the fromLead() method get special "folded" offsets for lead + * surrogate code units if there is relevant data associated with them. From + * such a folded offsets, an offset needs to be extracted to supply to the + * fromOffsetTrail() methods. To handle such supplementary codepoints, some + * offset information are kept in the data. + *

+ *

+ * Methods in com.ibm.icu.impl.Trie.DataManipulate are called to retrieve that + * offset from the folded value for the lead surrogate unit. + *

+ *

+ * For examples of use, see com.ibm.icu.impl.CharTrie or + * com.ibm.icu.impl.IntTrie. + *

+ * + * @author synwee + * @see com.ibm.icu.impl.CharTrie + * @see com.ibm.icu.impl.IntTrie + * @since release 2.1, Jan 01 2002 + */ +public abstract class Trie { + // public class declaration ---------------------------------------- + + /** + * Character data in com.ibm.impl.Trie have different user-specified format for + * different purposes. This interface specifies methods to be implemented in + * order for com.ibm.impl.Trie, to surrogate offset information encapsulated + * within the data. + */ + public static interface DataManipulate { + /** + * Called by com.ibm.icu.impl.Trie to extract from a lead surrogate's data the + * index array offset of the indexes for that lead surrogate. + * + * @param value data value for a surrogate from the trie, including the folding + * offset + * @return data offset or 0 if there is no data for the lead surrogate + */ + public int getFoldingOffset(int value); + } + + // default implementation + private static class DefaultGetFoldingOffset implements DataManipulate { + public int getFoldingOffset(int value) { + return value; + } + } + + // protected constructor ------------------------------------------- + + /** + * Trie constructor for CharTrie use. + * + * @param inputStream ICU data file input stream which contains the trie + * @param dataManipulate object containing the information to parse the trie + * data + * @throws IOException thrown when input stream does not have the right header. + */ + protected Trie(InputStream inputStream, DataManipulate dataManipulate) throws IOException { + DataInputStream input = new DataInputStream(inputStream); + // Magic number to authenticate the data. + int signature = input.readInt(); + m_options_ = input.readInt(); + + if (!checkHeader(signature)) { + throw new IllegalArgumentException( + "ICU data file error: Trie header authentication failed, please check if you have the most updated ICU data file"); + } + + if (dataManipulate != null) { + m_dataManipulate_ = dataManipulate; + } else { + m_dataManipulate_ = new DefaultGetFoldingOffset(); + } + m_isLatin1Linear_ = (m_options_ & HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; + m_dataOffset_ = input.readInt(); + m_dataLength_ = input.readInt(); + unserialize(inputStream); + } + + // protected data members ------------------------------------------ + + /** + * Lead surrogate code points' index displacement in the index array. + * + *
{@code
+	 * 0x10000-0xd800=0x2800
+	 * 0x2800 >> INDEX_STAGE_1_SHIFT_
+	 * }
+ */ + protected static final int LEAD_INDEX_OFFSET_ = 0x2800 >> 5; + /** + * Shift size for shifting right the input index. 1..9 + */ + protected static final int INDEX_STAGE_1_SHIFT_ = 5; + /** + * Shift size for shifting left the index array values. Increases possible data + * size with 16-bit index values at the cost of compactability. This requires + * blocks of stage 2 data to be aligned by DATA_GRANULARITY. + * 0..INDEX_STAGE_1_SHIFT + */ + protected static final int INDEX_STAGE_2_SHIFT_ = 2; + /** + * Number of data values in a stage 2 (data array) block. + */ + protected static final int DATA_BLOCK_LENGTH = 1 << INDEX_STAGE_1_SHIFT_; + /** + * Mask for getting the lower bits from the input index. DATA_BLOCK_LENGTH - 1. + */ + protected static final int INDEX_STAGE_3_MASK_ = DATA_BLOCK_LENGTH - 1; + /** + * Surrogate mask to use when shifting offset to retrieve supplementary values + */ + protected static final int SURROGATE_MASK_ = 0x3FF; + /** + * Index or UTF16 characters + */ + protected char m_index_[]; + /** + * Internal TrieValue which handles the parsing of the data value. This class is + * to be implemented by the user + */ + protected DataManipulate m_dataManipulate_; + /** + * Start index of the data portion of the trie. CharTrie combines index and data + * into a char array, so this is used to indicate the initial offset to the data + * portion. Note this index always points to the initial value. + */ + protected int m_dataOffset_; + /** + * Length of the data array + */ + protected int m_dataLength_; + + // protected methods ----------------------------------------------- + + /** + * Gets the offset to the data which the surrogate pair points to. + * + * @param lead lead surrogate + * @param trail trailing surrogate + * @return offset to data + */ + protected abstract int getSurrogateOffset(char lead, char trail); + + /** + * Gets the offset to the data which the index ch after variable offset points + * to. Note for locating a non-supplementary character data offset, calling + *

+ * getRawOffset(0, ch); + *

+ * will do. Otherwise if it is a supplementary character formed by surrogates + * lead and trail. Then we would have to call getRawOffset() with + * getFoldingIndexOffset(). See getSurrogateOffset(). + * + * @param offset index offset which ch is to start from + * @param ch index to be used after offset + * @return offset to the data + */ + protected final int getRawOffset(int offset, char ch) { + return (m_index_[offset + (ch >> INDEX_STAGE_1_SHIFT_)] << INDEX_STAGE_2_SHIFT_) + (ch & INDEX_STAGE_3_MASK_); + } + + /** + * Gets the offset to data which the BMP character points to Treats a lead + * surrogate as a normal code point. + * + * @param ch BMP character + * @return offset to data + */ + protected final int getBMPOffset(char ch) { + return (ch >= UTF16.LEAD_SURROGATE_MIN_VALUE && ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) + ? getRawOffset(LEAD_INDEX_OFFSET_, ch) + : getRawOffset(0, ch); + // using a getRawOffset(ch) makes no diff + } + + /** + * Gets the offset to the data which this lead surrogate character points to. + * Data at the returned offset may contain folding offset information for the + * next trailing surrogate character. + * + * @param ch lead surrogate character + * @return offset to data + */ + protected final int getLeadOffset(char ch) { + return getRawOffset(0, ch); + } + + /** + * Internal trie getter from a code point. Could be faster(?) but longer with + * {@code if((c32)<=0xd7ff) { (result)=_TRIE_GET_RAW(trie, data, 0, c32); }} + * Gets the offset to data which the codepoint points to + * + * @param ch codepoint + * @return offset to data + */ + protected final int getCodePointOffset(int ch) { + // if ((ch >> 16) == 0) slower + if (ch < 0) { + return -1; + } else if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { + // fastpath for the part of the BMP below surrogates (D800) where getRawOffset() + // works + return getRawOffset(0, (char) ch); + } else if (ch < UTF16.SUPPLEMENTARY_MIN_VALUE) { + // BMP codepoint + return getBMPOffset((char) ch); + } else if (ch <= UCharacter.MAX_VALUE) { + // look at the construction of supplementary characters + // trail forms the ends of it. + return getSurrogateOffset(UTF16.getLeadSurrogate(ch), (char) (ch & SURROGATE_MASK_)); + } else { + // return -1 if there is an error, in this case we return + return -1; + } + } + + /** + *

+ * Parses the inputstream and creates the trie index with it. + *

+ *

+ * This is overwritten by the child classes. + * + * @param inputStream input stream containing the trie information + * @exception IOException thrown when data reading fails. + */ + protected void unserialize(InputStream inputStream) throws IOException { + // indexLength is a multiple of 1024 >> INDEX_STAGE_2_SHIFT_ + m_index_ = new char[m_dataOffset_]; + DataInputStream input = new DataInputStream(inputStream); + for (int i = 0; i < m_dataOffset_; i++) { + m_index_[i] = input.readChar(); + } + } + + /** + * Determines if this is a 16 bit trie + * + * @return true if this is a 16 bit trie + */ + protected final boolean isCharTrie() { + return (m_options_ & HEADER_OPTIONS_DATA_IS_32_BIT_) == 0; + } + + // private data members -------------------------------------------- + + /** + * Latin 1 option mask + */ + protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200; + /** + * Constant number to authenticate the byte block + */ + protected static final int HEADER_SIGNATURE_ = 0x54726965; + /** + * Header option formatting + */ + private static final int HEADER_OPTIONS_SHIFT_MASK_ = 0xF; + protected static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4; + protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100; + + /** + * Flag indicator for Latin quick access data block + */ + private boolean m_isLatin1Linear_; + + /** + *

+ * Trie options field. + *

+ *

+ * options bit field:
+ * 9 1 = Latin-1 data is stored linearly at data + DATA_BLOCK_LENGTH
+ * 8 0 = 16-bit data, 1=32-bit data
+ * 7..4 INDEX_STAGE_1_SHIFT // 0..INDEX_STAGE_2_SHIFT
+ * 3..0 INDEX_STAGE_2_SHIFT // 1..9
+ */ + private int m_options_; + + // private methods --------------------------------------------------- + + /** + * Authenticates raw data header. Checking the header information, signature and + * options. + * + * @param signature This contains the options and type of a Trie + * @return true if the header is authenticated valid + */ + private final boolean checkHeader(int signature) { + // check the signature + // Trie in big-endian US-ASCII (0x54726965). + // Magic number to authenticate the data. + if (signature != HEADER_SIGNATURE_) { + return false; + } + + if ((m_options_ & HEADER_OPTIONS_SHIFT_MASK_) != INDEX_STAGE_1_SHIFT_ + || ((m_options_ >> HEADER_OPTIONS_INDEX_SHIFT_) & HEADER_OPTIONS_SHIFT_MASK_) != INDEX_STAGE_2_SHIFT_) { + return false; + } + return true; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Trie2.java b/src/main/java/jdk_internal/bidi/icu/impl/Trie2.java new file mode 100755 index 00000000..94c72fcd --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Trie2.java @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * This is the interface and common implementation of a Unicode Trie2. It is a + * kind of compressed table that maps from Unicode code points (0..0x10ffff) to + * 16- or 32-bit integer values. It works best when there are ranges of + * characters with the same value, which is generally the case with Unicode + * character properties. + * + * This is the second common version of a Unicode trie (hence the name Trie2). + * + */ +abstract class Trie2 implements Iterable { + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). + * + * Reads from the current position and leaves the buffer after the end of the + * trie. + * + * The serialized format is identical between ICU4C and ICU4J, so this function + * will work with serialized Trie2s from either. + * + * The actual type of the returned Trie2 will be either Trie2_16 or Trie2_32, + * depending on the width of the data. + * + * To obtain the width of the Trie2, check the actual class type of the returned + * Trie2. Or use the createFromSerialized() function of Trie2_16 or Trie2_32, + * which will return only Tries of their specific type/size. + * + * The serialized Trie2 on the stream may be in either little or big endian byte + * order. This allows using serialized Tries from ICU4C without needing to + * consider the byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2, ready for use. + * @throws IllegalArgumentException if the stream does not contain a serialized + * Trie2. + * @throws IOException if a read error occurs in the buffer. + * + */ + public static Trie2 createFromSerialized(ByteBuffer bytes) throws IOException { + // From ICU4C utrie2_impl.h + // * Trie2 data structure in serialized form: + // * + // * UTrie2Header header; + // * uint16_t index[header.index2Length]; + // * uint16_t data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + // * @internal + // */ + // typedef struct UTrie2Header { + // /** "Tri2" in big-endian US-ASCII (0x54726932) */ + // uint32_t signature; + + // /** + // * options bit field: + // * 15.. 4 reserved (0) + // * 3.. 0 UTrie2ValueBits valueBits + // */ + // uint16_t options; + // + // /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH */ + // uint16_t indexLength; + // + // /** (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT */ + // uint16_t shiftedDataLength; + // + // /** Null index and data blocks, not shifted. */ + // uint16_t index2NullOffset, dataNullOffset; + // + // /** + // * First code point of the single-value range ending with U+10ffff, + // * rounded up and then shifted right by UTRIE2_SHIFT_1. + // */ + // uint16_t shiftedHighStart; + // } UTrie2Header; + + ByteOrder outerByteOrder = bytes.order(); + try { + UTrie2Header header = new UTrie2Header(); + + /* check the signature */ + header.signature = bytes.getInt(); + switch (header.signature) { + case 0x54726932: + // The buffer is already set to the trie data byte order. + break; + case 0x32697254: + // Temporarily reverse the byte order. + boolean isBigEndian = outerByteOrder == ByteOrder.BIG_ENDIAN; + bytes.order(isBigEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + header.signature = 0x54726932; + break; + default: + throw new IllegalArgumentException("Buffer does not contain a serialized UTrie2"); + } + + header.options = bytes.getChar(); + header.indexLength = bytes.getChar(); + header.shiftedDataLength = bytes.getChar(); + header.index2NullOffset = bytes.getChar(); + header.dataNullOffset = bytes.getChar(); + header.shiftedHighStart = bytes.getChar(); + + if ((header.options & UTRIE2_OPTIONS_VALUE_BITS_MASK) != 0) { + throw new IllegalArgumentException("UTrie2 serialized format error."); + } + + Trie2 This; + This = new Trie2_16(); + This.header = header; + + /* get the length values and offsets */ + This.indexLength = header.indexLength; + This.dataLength = header.shiftedDataLength << UTRIE2_INDEX_SHIFT; + This.index2NullOffset = header.index2NullOffset; + This.dataNullOffset = header.dataNullOffset; + This.highStart = header.shiftedHighStart << UTRIE2_SHIFT_1; + This.highValueIndex = This.dataLength - UTRIE2_DATA_GRANULARITY; + This.highValueIndex += This.indexLength; + + // Allocate the Trie2 index array. If the data width is 16 bits, the array also + // includes the space for the data. + + int indexArraySize = This.indexLength; + indexArraySize += This.dataLength; + This.index = new char[indexArraySize]; + + /* Read in the index */ + int i; + for (i = 0; i < This.indexLength; i++) { + This.index[i] = bytes.getChar(); + } + + /* + * Read in the data. 16 bit data goes in the same array as the index. 32 bit + * data goes in its own separate data array. + */ + This.data16 = This.indexLength; + for (i = 0; i < This.dataLength; i++) { + This.index[This.data16 + i] = bytes.getChar(); + } + + This.data32 = null; + This.initialValue = This.index[This.dataNullOffset]; + This.errorValue = This.index[This.data16 + UTRIE2_BAD_UTF8_DATA_OFFSET]; + + return This; + } finally { + bytes.order(outerByteOrder); + } + } + + /** + * Get the value for a code point as stored in the Trie2. + * + * @param codePoint the code point + * @return the value + */ + public abstract int get(int codePoint); + + /** + * Get the trie value for a UTF-16 code unit. + * + * A Trie2 stores two distinct values for input in the lead surrogate range, one + * for lead surrogates, which is the value that will be returned by this + * function, and a second value that is returned by Trie2.get(). + * + * For code units outside of the lead surrogate range, this function returns the + * same result as Trie2.get(). + * + * This function, together with the alternate value for lead surrogates, makes + * possible very efficient processing of UTF-16 strings without first converting + * surrogate pairs to their corresponding 32 bit code point values. + * + * At build-time, enumerate the contents of the Trie2 to see if there is + * non-trivial (non-initialValue) data for any of the supplementary code points + * associated with a lead surrogate. If so, then set a special + * (application-specific) value for the lead surrogate code _unit_, with + * Trie2Writable.setForLeadSurrogateCodeUnit(). + * + * At runtime, use Trie2.getFromU16SingleLead(). If there is non-trivial data + * and the code unit is a lead surrogate, then check if a trail surrogate + * follows. If so, assemble the supplementary code point and look up its value + * with Trie2.get(); otherwise reset the lead surrogate's value or do a code + * point lookup for it. + * + * If there is only trivial data for lead and trail surrogates, then processing + * can often skip them. For example, in normalization or case mapping all + * characters that do not have any mappings are simply copied as is. + * + * @param c the code point or lead surrogate value. + * @return the value + */ + public abstract int getFromU16SingleLead(char c); + + /** + * When iterating over the contents of a Trie2, Elements of this type are + * produced. The iterator will return one item for each contiguous range of + * codepoints having the same value. + * + * When iterating, the same Trie2EnumRange object will be reused and returned + * for each range. If you need to retain complete iteration results, clone each + * returned Trie2EnumRange, or save the range in some other way, before + * advancing to the next iteration step. + */ + public static class Range { + public int startCodePoint; + public int endCodePoint; // Inclusive. + public int value; + public boolean leadSurrogate; + + public boolean equals(Object other) { + if (other == null || !(other.getClass().equals(getClass()))) { + return false; + } + Range tother = (Range) other; + return this.startCodePoint == tother.startCodePoint && this.endCodePoint == tother.endCodePoint + && this.value == tother.value && this.leadSurrogate == tother.leadSurrogate; + } + + public int hashCode() { + int h = initHash(); + h = hashUChar32(h, startCodePoint); + h = hashUChar32(h, endCodePoint); + h = hashInt(h, value); + h = hashByte(h, leadSurrogate ? 1 : 0); + return h; + } + } + + /** + * Create an iterator over the value ranges in this Trie2. Values from the Trie2 + * are not remapped or filtered, but are returned as they are stored in the + * Trie2. + * + * @return an Iterator + */ + public Iterator iterator() { + return iterator(defaultValueMapper); + } + + private static ValueMapper defaultValueMapper = new ValueMapper() { + public int map(int in) { + return in; + } + }; + + /** + * Create an iterator over the value ranges from this Trie2. Values from the + * Trie2 are passed through a caller-supplied remapping function, and it is the + * remapped values that determine the ranges that will be produced by the + * iterator. + * + * + * @param mapper provides a function to remap values obtained from the Trie2. + * @return an Iterator + */ + public Iterator iterator(ValueMapper mapper) { + return new Trie2Iterator(mapper); + } + + /** + * When iterating over the contents of a Trie2, an instance of TrieValueMapper + * may be used to remap the values from the Trie2. The remapped values will be + * used both in determining the ranges of codepoints and as the value to be + * returned for each range. + * + * Example of use, with an anonymous subclass of TrieValueMapper: + * + * + * ValueMapper m = new ValueMapper() { int map(int in) {return in & 0x1f;}; } + * for (Iterator iter = trie.iterator(m); i.hasNext(); ) { + * Trie2EnumRange r = i.next(); ... // Do something with the range r. } + * + */ + public interface ValueMapper { + public int map(int originalVal); + } + + // -------------------------------------------------------------------------------- + // + // Below this point are internal implementation items. No further public API. + // + // -------------------------------------------------------------------------------- + + /** + * Trie2 data structure in serialized form: + * + * UTrie2Header header; uint16_t index[header.index2Length]; uint16_t + * data[header.shiftedDataLength<<2]; -- or uint32_t data[...] + * + * For Java, this is read from the stream into an instance of UTrie2Header. (The + * C version just places a struct over the raw serialized data.) + * + * @internal + */ + static class UTrie2Header { + /** "Tri2" in big-endian US-ASCII (0x54726932) */ + int signature; + + /** + * options bit field (uint16_t): 15.. 4 reserved (0) 3.. 0 UTrie2ValueBits + * valueBits + */ + int options; + + /** UTRIE2_INDEX_1_OFFSET..UTRIE2_MAX_INDEX_LENGTH (uint16_t) */ + int indexLength; + + /** + * (UTRIE2_DATA_START_OFFSET..UTRIE2_MAX_DATA_LENGTH)>>UTRIE2_INDEX_SHIFT + * (uint16_t) + */ + int shiftedDataLength; + + /** Null index and data blocks, not shifted. (uint16_t) */ + int index2NullOffset, dataNullOffset; + + /** + * First code point of the single-value range ending with U+10ffff, rounded up + * and then shifted right by UTRIE2_SHIFT_1. (uint16_t) + */ + int shiftedHighStart; + } + + // + // Data members of UTrie2. + // + UTrie2Header header; + char index[]; // Index array. Includes data for 16 bit Tries. + int data16; // Offset to data portion of the index array, if 16 bit data. + // zero if 32 bit data. + int data32[]; // NULL if 16b data is used via index + + int indexLength; + int dataLength; + int index2NullOffset; // 0xffff if there is no dedicated index-2 null block + int initialValue; + + /** Value returned for out-of-range code points and illegal UTF-8. */ + int errorValue; + + /* Start of the last range which ends at U+10ffff, and its value. */ + int highStart; + int highValueIndex; + + int dataNullOffset; + + /** + * Trie2 constants, defining shift widths, index array lengths, etc. + * + * These are needed for the runtime macros but users can treat these as + * implementation details and skip to the actual public API further below. + */ + + static final int UTRIE2_OPTIONS_VALUE_BITS_MASK = 0x000f; + + /** Shift size for getting the index-1 table offset. */ + static final int UTRIE2_SHIFT_1 = 6 + 5; + + /** Shift size for getting the index-2 table offset. */ + static final int UTRIE2_SHIFT_2 = 5; + + /** + * Difference between the two shift sizes, for getting an index-1 offset from an + * index-2 offset. 6=11-5 + */ + static final int UTRIE2_SHIFT_1_2 = UTRIE2_SHIFT_1 - UTRIE2_SHIFT_2; + + /** + * Number of index-1 entries for the BMP. 32=0x20 This part of the index-1 table + * is omitted from the serialized form. + */ + static final int UTRIE2_OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> UTRIE2_SHIFT_1; + + /** Number of entries in an index-2 block. 64=0x40 */ + static final int UTRIE2_INDEX_2_BLOCK_LENGTH = 1 << UTRIE2_SHIFT_1_2; + + /** Mask for getting the lower bits for the in-index-2-block offset. */ + static final int UTRIE2_INDEX_2_MASK = UTRIE2_INDEX_2_BLOCK_LENGTH - 1; + + /** Number of entries in a data block. 32=0x20 */ + static final int UTRIE2_DATA_BLOCK_LENGTH = 1 << UTRIE2_SHIFT_2; + + /** Mask for getting the lower bits for the in-data-block offset. */ + static final int UTRIE2_DATA_MASK = UTRIE2_DATA_BLOCK_LENGTH - 1; + + /** + * Shift size for shifting left the index array values. Increases possible data + * size with 16-bit index values at the cost of compactability. This requires + * data blocks to be aligned by UTRIE2_DATA_GRANULARITY. + */ + static final int UTRIE2_INDEX_SHIFT = 2; + + /** The alignment size of a data block. Also the granularity for compaction. */ + static final int UTRIE2_DATA_GRANULARITY = 1 << UTRIE2_INDEX_SHIFT; + + /** + * The part of the index-2 table for U+D800..U+DBFF stores values for lead + * surrogate code _units_ not code _points_. Values for lead surrogate code + * _points_ are indexed with this portion of the table. + * Length=32=0x20=0x400>>UTRIE2_SHIFT_2. (There are 1024=0x400 lead surrogates.) + */ + static final int UTRIE2_LSCP_INDEX_2_OFFSET = 0x10000 >> UTRIE2_SHIFT_2; + static final int UTRIE2_LSCP_INDEX_2_LENGTH = 0x400 >> UTRIE2_SHIFT_2; + + /** Count the lengths of both BMP pieces. 2080=0x820 */ + static final int UTRIE2_INDEX_2_BMP_LENGTH = UTRIE2_LSCP_INDEX_2_OFFSET + UTRIE2_LSCP_INDEX_2_LENGTH; + + /** + * The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820. + * Length 32=0x20 for lead bytes C0..DF, regardless of UTRIE2_SHIFT_2. + */ + static final int UTRIE2_UTF8_2B_INDEX_2_OFFSET = UTRIE2_INDEX_2_BMP_LENGTH; + static final int UTRIE2_UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; /* U+0800 is the first code point after 2-byte UTF-8 */ + + /** + * The index-1 table, only used for supplementary code points, at offset + * 2112=0x840. Variable length, for code points up to highStart, where the last + * single-value range starts. Maximum length 512=0x200=0x100000>>UTRIE2_SHIFT_1. + * (For 0x100000 supplementary code points U+10000..U+10ffff.) + * + * The part of the index-2 table for supplementary code points starts after this + * index-1 table. + * + * Both the index-1 table and the following part of the index-2 table are + * omitted completely if there is only BMP data. + */ + static final int UTRIE2_INDEX_1_OFFSET = UTRIE2_UTF8_2B_INDEX_2_OFFSET + UTRIE2_UTF8_2B_INDEX_2_LENGTH; + + /** + * The illegal-UTF-8 data block follows the ASCII block, at offset 128=0x80. + * Used with linear access for single bytes 0..0xbf for simple error handling. + * Length 64=0x40, not UTRIE2_DATA_BLOCK_LENGTH. + */ + static final int UTRIE2_BAD_UTF8_DATA_OFFSET = 0x80; + + /** + * Implementation class for an iterator over a Trie2. + * + * Iteration over a Trie2 first returns all of the ranges that are indexed by + * code points, then returns the special alternate values for the lead + * surrogates + * + * @internal + */ + class Trie2Iterator implements Iterator { + + // The normal constructor that configures the iterator to cover the complete + // contents of the Trie2 + Trie2Iterator(ValueMapper vm) { + mapper = vm; + nextStart = 0; + limitCP = 0x110000; + doLeadSurrogates = true; + } + + /** + * The main next() function for Trie2 iterators + * + */ + public Range next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + if (nextStart >= limitCP) { + // Switch over from iterating normal code point values to + // doing the alternate lead-surrogate values. + doingCodePoints = false; + nextStart = 0xd800; + } + int endOfRange = 0; + int val = 0; + int mappedVal = 0; + + if (doingCodePoints) { + // Iteration over code point values. + val = get(nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEnd(nextStart, limitCP, val); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= limitCP - 1) { + break; + } + val = get(endOfRange + 1); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEnd(endOfRange + 1, limitCP, val); + } + } else { + // Iteration over the alternate lead surrogate values. + val = getFromU16SingleLead((char) nextStart); + mappedVal = mapper.map(val); + endOfRange = rangeEndLS((char) nextStart); + // Loop once for each range in the Trie2 with the same raw (unmapped) value. + // Loop continues so long as the mapped values are the same. + for (;;) { + if (endOfRange >= 0xdbff) { + break; + } + val = getFromU16SingleLead((char) (endOfRange + 1)); + if (mapper.map(val) != mappedVal) { + break; + } + endOfRange = rangeEndLS((char) (endOfRange + 1)); + } + } + returnValue.startCodePoint = nextStart; + returnValue.endCodePoint = endOfRange; + returnValue.value = mappedVal; + returnValue.leadSurrogate = !doingCodePoints; + nextStart = endOfRange + 1; + return returnValue; + } + + /** + * + */ + public boolean hasNext() { + return doingCodePoints && (doLeadSurrogates || nextStart < limitCP) || nextStart < 0xdc00; + } + + private int rangeEndLS(char startingLS) { + if (startingLS >= 0xdbff) { + return 0xdbff; + } + + int c; + int val = getFromU16SingleLead(startingLS); + for (c = startingLS + 1; c <= 0x0dbff; c++) { + if (getFromU16SingleLead((char) c) != val) { + break; + } + } + return c - 1; + } + + // + // Iteration State Variables + // + private ValueMapper mapper; + private Range returnValue = new Range(); + // The starting code point for the next range to be returned. + private int nextStart; + // The upper limit for the last normal range to be returned. Normally 0x110000, + // but + // may be lower when iterating over the code points for a single lead surrogate. + private int limitCP; + + // True while iterating over the Trie2 values for code points. + // False while iterating over the alternate values for lead surrogates. + private boolean doingCodePoints = true; + + // True if the iterator should iterate the special values for lead surrogates in + // addition to the normal values for code points. + private boolean doLeadSurrogates = true; + } + + /** + * Find the last character in a contiguous range of characters with the same + * Trie2 value as the input character. + * + * @param c The character to begin with. + * @return The last contiguous character with the same value. + */ + int rangeEnd(int start, int limitp, int val) { + int c; + int limit = Math.min(highStart, limitp); + + for (c = start + 1; c < limit; c++) { + if (get(c) != val) { + break; + } + } + if (c >= highStart) { + c = limitp; + } + return c - 1; + } + + // + // Hashing implementation functions. FNV hash. Respected public domain + // algorithm. + // + private static int initHash() { + return 0x811c9DC5; // unsigned 2166136261 + } + + private static int hashByte(int h, int b) { + h = h * 16777619; + h = h ^ b; + return h; + } + + private static int hashUChar32(int h, int c) { + h = Trie2.hashByte(h, c & 255); + h = Trie2.hashByte(h, (c >> 8) & 255); + h = Trie2.hashByte(h, c >> 16); + return h; + } + + private static int hashInt(int h, int i) { + h = Trie2.hashByte(h, i & 255); + h = Trie2.hashByte(h, (i >> 8) & 255); + h = Trie2.hashByte(h, (i >> 16) & 255); + h = Trie2.hashByte(h, (i >> 24) & 255); + return h; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Trie2_16.java b/src/main/java/jdk_internal/bidi/icu/impl/Trie2_16.java new file mode 100755 index 00000000..770754a7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Trie2_16.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * @author aheninger + * + * A read-only Trie2, holding 16 bit data values. + * + * A Trie2 is a highly optimized data structure for mapping from Unicode + * code points (values ranging from 0 to 0x10ffff) to a 16 or 32 bit + * value. + * + * See class Trie2 for descriptions of the API for accessing the + * contents of a trie. + * + * The fundamental data access methods are declared final in this class, + * with the intent that applications might gain a little extra + * performance, when compared with calling the same methods via the + * abstract UTrie2 base class. + */ +public final class Trie2_16 extends Trie2 { + + /** + * Internal constructor, not for general use. + */ + Trie2_16() { + } + + /** + * Create a Trie2 from its serialized form. Inverse of utrie2_serialize(). The + * serialized format is identical between ICU4C and ICU4J, so this function will + * work with serialized Trie2s from either. + * + * The serialized Trie2 in the bytes may be in either little or big endian byte + * order. This allows using serialized Tries from ICU4C without needing to + * consider the byte order of the system that created them. + * + * @param bytes a byte buffer to the serialized form of a UTrie2. + * @return An unserialized Trie2_16, ready for use. + * @throws IllegalArgumentException if the buffer does not contain a serialized + * Trie2. + * @throws IOException if a read error occurs in the buffer. + * @throws ClassCastException if the bytes contain a serialized Trie2_32 + */ + public static Trie2_16 createFromSerialized(ByteBuffer bytes) throws IOException { + return (Trie2_16) Trie2.createFromSerialized(bytes); + } + + /** + * Get the value for a code point as stored in the Trie2. + * + * @param codePoint the code point + * @return the value + */ + @Override + public final int get(int codePoint) { + int value; + int ix; + + if (codePoint >= 0) { + if (codePoint < 0x0d800 || (codePoint > 0x0dbff && codePoint <= 0x0ffff)) { + // Ordinary BMP code point, excluding leading surrogates. + // BMP uses a single level lookup. BMP index starts at offset 0 in the Trie2 + // index. + // 16 bit data is stored in the index array itself. + ix = index[codePoint >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0xffff) { + // Lead Surrogate Code Point. A Separate index section is stored for + // lead surrogate code units and code points. + // The main index has the code unit data. + // For this function, we need the code point data. + // Note: this expression could be refactored for slightly improved efficiency, + // but + // surrogate code points will be so rare in practice that it's not worth it. + ix = index[UTRIE2_LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> UTRIE2_SHIFT_2)]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint < highStart) { + // Supplemental code point, use two-level lookup. + ix = (UTRIE2_INDEX_1_OFFSET - UTRIE2_OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> UTRIE2_SHIFT_1); + ix = index[ix]; + ix += (codePoint >> UTRIE2_SHIFT_2) & UTRIE2_INDEX_2_MASK; + ix = index[ix]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codePoint & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + if (codePoint <= 0x10ffff) { + value = index[highValueIndex]; + return value; + } + } + + // Fall through. The code point is outside of the legal range of 0..0x10ffff. + return errorValue; + } + + /** + * Get a Trie2 value for a UTF-16 code unit. + * + * This function returns the same value as get() if the input character is + * outside of the lead surrogate range + * + * There are two values stored in a Trie2 for inputs in the lead surrogate + * range. This function returns the alternate value, while Trie2.get() returns + * the main value. + * + * @param codeUnit a 16 bit code unit or lead surrogate value. + * @return the value + */ + @Override + public int getFromU16SingleLead(char codeUnit) { + int value; + int ix; + + // Because the input is a 16 bit char, we can skip the tests for it being in + // the BMP range. It is. + ix = index[codeUnit >> UTRIE2_SHIFT_2]; + ix = (ix << UTRIE2_INDEX_SHIFT) + (codeUnit & UTRIE2_DATA_MASK); + value = index[ix]; + return value; + } + + /** + * @return the number of bytes of the serialized trie + */ + public int getSerializedLength() { + return 16 + (header.indexLength + dataLength) * 2; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/UBiDiProps.java b/src/main/java/jdk_internal/bidi/icu/impl/UBiDiProps.java new file mode 100755 index 00000000..b81ec6b7 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/UBiDiProps.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * + * Copyright (C) 2004-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ******************************************************************************* + * file name: UBiDiProps.java + * encoding: US-ASCII + * tab size: 8 (not used) + * indentation:4 + * + * created on: 2005jan16 + * created by: Markus W. Scherer + * + * Low-level Unicode bidi/shaping properties access. + * Java port of ubidi_props.h/.c. + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import jdk_internal.bidi.icu.lang.UCharacter; + +public final class UBiDiProps { + // constructors etc. --------------------------------------------------- *** + + // port of ubidi_openProps() + private UBiDiProps() throws IOException { + ByteBuffer bytes = ICUBinary.getRequiredData(DATA_FILE_NAME); + readData(bytes); + } + + private void readData(ByteBuffer bytes) throws IOException { + // read the header + ICUBinary.readHeader(bytes, FMT, new IsAcceptable()); + + // read indexes[] + int i, count; + count = bytes.getInt(); + if (count < IX_TOP) { + throw new IOException("indexes[0] too small in " + DATA_FILE_NAME); + } + indexes = new int[count]; + + indexes[0] = count; + for (i = 1; i < count; ++i) { + indexes[i] = bytes.getInt(); + } + + // read the trie + trie = Trie2_16.createFromSerialized(bytes); + int expectedTrieLength = indexes[IX_TRIE_SIZE]; + int trieLength = trie.getSerializedLength(); + if (trieLength > expectedTrieLength) { + throw new IOException(DATA_FILE_NAME + ": not enough bytes for the trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // read mirrors[] + count = indexes[IX_MIRROR_LENGTH]; + if (count > 0) { + mirrors = new int[count]; + for (i = 0; i < count; ++i) { + mirrors[i] = bytes.getInt(); + } + } + + // read jgArray[] + count = indexes[IX_JG_LIMIT] - indexes[IX_JG_START]; + jgArray = new byte[count]; + for (i = 0; i < count; ++i) { + jgArray[i] = bytes.get(); + } + + // read jgArray2[] + count = indexes[IX_JG_LIMIT2] - indexes[IX_JG_START2]; + jgArray2 = new byte[count]; + for (i = 0; i < count; ++i) { + jgArray2[i] = bytes.get(); + } + } + + // implement ICUBinary.Authenticate + private static final class IsAcceptable implements ICUBinary.Authenticate { + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 2; + } + } + + // property access functions ------------------------------------------- *** + + public final int getClass(int c) { + return getClassFromProps(trie.get(c)); + } + + private final int getMirror(int c, int props) { + int delta = getMirrorDeltaFromProps(props); + if (delta != ESC_MIRROR_DELTA) { + return c + delta; + } else { + /* look for mirror code point in the mirrors[] table */ + int m; + int i, length; + int c2; + + length = indexes[IX_MIRROR_LENGTH]; + + /* linear search */ + for (i = 0; i < length; ++i) { + m = mirrors[i]; + c2 = getMirrorCodePoint(m); + if (c == c2) { + /* found c, return its mirror code point using the index in m */ + return getMirrorCodePoint(mirrors[getMirrorIndex(m)]); + } else if (c < c2) { + break; + } + } + + /* c not found, return it itself */ + return c; + } + } + + public final int getMirror(int c) { + int props = trie.get(c); + return getMirror(c, props); + } + + public final int getJoiningType(int c) { + return (trie.get(c) & JT_MASK) >> JT_SHIFT; + } + + public final int getJoiningGroup(int c) { + int start, limit; + + start = indexes[IX_JG_START]; + limit = indexes[IX_JG_LIMIT]; + if (start <= c && c < limit) { + return (int) jgArray[c - start] & 0xff; + } + start = indexes[IX_JG_START2]; + limit = indexes[IX_JG_LIMIT2]; + if (start <= c && c < limit) { + return (int) jgArray2[c - start] & 0xff; + } + return UCharacter.JoiningGroup.NO_JOINING_GROUP; + } + + public final int getPairedBracketType(int c) { + return (trie.get(c) & BPT_MASK) >> BPT_SHIFT; + } + + public final int getPairedBracket(int c) { + int props = trie.get(c); + if ((props & BPT_MASK) == 0) { + return c; + } else { + return getMirror(c, props); + } + } + + // data members -------------------------------------------------------- *** + private int indexes[]; + private int mirrors[]; + private byte jgArray[]; + private byte jgArray2[]; + + private Trie2_16 trie; + + // data format constants ----------------------------------------------- *** + @SuppressWarnings("deprecation") + private static final String DATA_FILE_NAME = "/assets/eagler/icudt/ubidi.icu"; + + /* format "BiDi" */ + private static final int FMT = 0x42694469; + + /* indexes into indexes[] */ + private static final int IX_TRIE_SIZE = 2; + private static final int IX_MIRROR_LENGTH = 3; + + private static final int IX_JG_START = 4; + private static final int IX_JG_LIMIT = 5; + private static final int IX_JG_START2 = 6; /* new in format version 2.2, ICU 54 */ + private static final int IX_JG_LIMIT2 = 7; + + private static final int IX_TOP = 16; + + // definitions for 16-bit bidi/shaping properties word ----------------- *** + + /* CLASS_SHIFT=0, */ /* bidi class: 5 bits (4..0) */ + private static final int JT_SHIFT = 5; /* joining type: 3 bits (7..5) */ + + private static final int BPT_SHIFT = 8; /* Bidi_Paired_Bracket_Type(bpt): 2 bits (9..8) */ + + private static final int MIRROR_DELTA_SHIFT = 13; /* bidi mirroring delta: 3 bits (15..13) */ + + private static final int CLASS_MASK = 0x0000001f; + private static final int JT_MASK = 0x000000e0; + private static final int BPT_MASK = 0x00000300; + + private static final int getClassFromProps(int props) { + return props & CLASS_MASK; + } + + private static final boolean getFlagFromProps(int props, int shift) { + return ((props >> shift) & 1) != 0; + } + + private static final int getMirrorDeltaFromProps(int props) { + return (short) props >> MIRROR_DELTA_SHIFT; + } + + private static final int ESC_MIRROR_DELTA = -4; + + // definitions for 32-bit mirror table entry --------------------------- *** + + /* the source Unicode code point takes 21 bits (20..0) */ + private static final int MIRROR_INDEX_SHIFT = 21; + + private static final int getMirrorCodePoint(int m) { + return m & 0x1fffff; + } + + private static final int getMirrorIndex(int m) { + return m >>> MIRROR_INDEX_SHIFT; + } + + /* + * public singleton instance + */ + public static final UBiDiProps INSTANCE; + + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UBiDiProps(); + } catch (IOException e) { + throw new RuntimeException("Missing resource: \"" + DATA_FILE_NAME + "\"; Reason: " + e.getMessage()); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/UCharacterProperty.java b/src/main/java/jdk_internal/bidi/icu/impl/UCharacterProperty.java new file mode 100755 index 00000000..7b77640f --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/UCharacterProperty.java @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Iterator; + +import jdk_internal.bidi.icu.lang.UCharacter.HangulSyllableType; +import jdk_internal.bidi.icu.lang.UCharacter.NumericType; +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.text.UnicodeSet; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + *

+ * Internal class used for Unicode character property database. + *

+ *

+ * This classes store binary data read from uprops.icu. It does not have the + * capability to parse the data into more high-level information. It only + * returns bytes of information when required. + *

+ *

+ * Due to the form most commonly used for retrieval, array of char is used to + * store the binary data. + *

+ *

+ * UCharacterPropertyDB also contains information on accessing indexes to + * significant points in the binary data. + *

+ *

+ * Responsibility for molding the binary data into more meaning form lies on + * UCharacter. + *

+ * + * @author Syn Wee Quek + * @since release 2.1, february 1st 2002 + */ + +public final class UCharacterProperty { + // public data members ----------------------------------------------- + + /* + * public singleton instance + */ + public static final UCharacterProperty INSTANCE; + + /** + * Trie data + */ + public Trie2_16 m_trie_; + + /** + * Unicode version + */ + public VersionInfo m_unicodeVersion_; + + /** + * Character type mask + */ + public static final int TYPE_MASK = 0x1F; + + // uprops.h enum UPropertySource --------------------------------------- *** + + /** From uchar.c/uprops.icu main trie */ + public static final int SRC_CHAR = 1; + /** From uchar.c/uprops.icu properties vectors trie */ + public static final int SRC_PROPSVEC = 2; + /** From ubidi_props.c/ubidi.icu */ + public static final int SRC_BIDI = 5; + /** From normalizer2impl.cpp/nfc.nrm */ + public static final int SRC_NFC = 8; + /** From normalizer2impl.cpp/nfkc.nrm */ + public static final int SRC_NFKC = 9; + + // public methods ---------------------------------------------------- + + /** + * Gets the main property value for code point ch. + * + * @param ch code point whose property value is to be retrieved + * @return property value of code point + */ + public final int getProperty(int ch) { + return m_trie_.get(ch); + } + + /** + * Gets the unicode additional properties. Java version of C + * u_getUnicodeProperties(). + * + * @param codepoint codepoint whose additional properties is to be retrieved + * @param column The column index. + * @return unicode properties + */ + public int getAdditional(int codepoint, int column) { + assert column >= 0; + if (column >= m_additionalColumnsCount_) { + return 0; + } + return m_additionalVectors_[m_additionalTrie_.get(codepoint) + column]; + } + + /** + *

+ * Get the "age" of the code point. + *

+ *

+ * The "age" is the Unicode version when the code point was first designated (as + * a non-character or for Private Use) or assigned a character. + *

+ *

+ * This can be useful to avoid emitting code points to receiving processes that + * do not accept newer characters. + *

+ *

+ * The data is from the UCD file DerivedAge.txt. + *

+ *

+ * This API does not check the validity of the codepoint. + *

+ * + * @param codepoint The code point. + * @return the Unicode version number + */ + public VersionInfo getAge(int codepoint) { + int version = getAdditional(codepoint, 0) >> AGE_SHIFT_; + return VersionInfo.getInstance((version >> FIRST_NIBBLE_SHIFT_) & LAST_NIBBLE_MASK_, + version & LAST_NIBBLE_MASK_, 0, 0); + } + + // int-value and enumerated properties --------------------------------- *** + + public int getType(int c) { + return getProperty(c) & TYPE_MASK; + } + + /* + * Map some of the Grapheme Cluster Break values to Hangul Syllable Types. + * Hangul_Syllable_Type is fully redundant with a subset of + * Grapheme_Cluster_Break. + */ + private static final int /* UHangulSyllableType */ gcbToHst[] = { HangulSyllableType.NOT_APPLICABLE, /* + * U_GCB_OTHER + */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CONTROL */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_CR */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_EXTEND */ + HangulSyllableType.LEADING_JAMO, /* U_GCB_L */ + HangulSyllableType.NOT_APPLICABLE, /* U_GCB_LF */ + HangulSyllableType.LV_SYLLABLE, /* U_GCB_LV */ + HangulSyllableType.LVT_SYLLABLE, /* U_GCB_LVT */ + HangulSyllableType.TRAILING_JAMO, /* U_GCB_T */ + HangulSyllableType.VOWEL_JAMO /* U_GCB_V */ + /* + * Omit GCB values beyond what we need for hst. The code below checks for the + * array length. + */ + }; + + private class IntProperty { + int column; // SRC_PROPSVEC column, or "source" if mask==0 + int mask; + int shift; + + IntProperty(int column, int mask, int shift) { + this.column = column; + this.mask = mask; + this.shift = shift; + } + + IntProperty(int source) { + this.column = source; + this.mask = 0; + } + + int getValue(int c) { + // systematic, directly stored properties + return (getAdditional(c, column) & mask) >>> shift; + } + } + + private class BiDiIntProperty extends IntProperty { + BiDiIntProperty() { + super(SRC_BIDI); + } + } + + private class CombiningClassIntProperty extends IntProperty { + CombiningClassIntProperty(int source) { + super(source); + } + } + + private class NormQuickCheckIntProperty extends IntProperty { // UCHAR_NF*_QUICK_CHECK properties + int which; + int max; + + NormQuickCheckIntProperty(int source, int which, int max) { + super(source); + this.which = which; + this.max = max; + } + } + + private IntProperty intProp = new BiDiIntProperty() { // BIDI_PAIRED_BRACKET_TYPE + int getValue(int c) { + return UBiDiProps.INSTANCE.getPairedBracketType(c); + } + }; + + public int getIntPropertyValue(int c, int which) { + if (which == BIDI_PAIRED_BRACKET_TYPE) { + return intProp.getValue(c); + } + return 0; // undefined + } + + /** + * Forms a supplementary code point from the argument character
+ * Note this is for internal use hence no checks for the validity of the + * surrogate characters are done + * + * @param lead lead surrogate character + * @param trail trailing surrogate character + * @return code point of the supplementary character + */ + public static int getRawSupplementary(char lead, char trail) { + return (lead << LEAD_SURROGATE_SHIFT_) + trail + SURROGATE_OFFSET_; + } + + /** + * Gets the type mask + * + * @param type character type + * @return mask + */ + public static final int getMask(int type) { + return 1 << type; + } + + /** + * Returns the digit values of characters like 'A' - 'Z', normal, half-width and + * full-width. This method assumes that the other digit characters are checked + * by the calling method. + * + * @param ch character to test + * @return -1 if ch is not a character of the form 'A' - 'Z', otherwise its + * corresponding digit will be returned. + */ + public static int getEuropeanDigit(int ch) { + if ((ch > 0x7a && ch < 0xff21) || ch < 0x41 || (ch > 0x5a && ch < 0x61) || ch > 0xff5a + || (ch > 0xff3a && ch < 0xff41)) { + return -1; + } + if (ch <= 0x7a) { + // ch >= 0x41 or ch < 0x61 + return ch + 10 - ((ch <= 0x5a) ? 0x41 : 0x61); + } + // ch >= 0xff21 + if (ch <= 0xff3a) { + return ch + 10 - 0xff21; + } + // ch >= 0xff41 && ch <= 0xff5a + return ch + 10 - 0xff41; + } + + public int digit(int c) { + int value = getNumericTypeValue(getProperty(c)) - NTV_DECIMAL_START_; + if (value <= 9) { + return value; + } else { + return -1; + } + } + + // protected variables ----------------------------------------------- + + /** + * Extra property trie + */ + Trie2_16 m_additionalTrie_; + /** + * Extra property vectors, 1st column for age and second for binary properties. + */ + int m_additionalVectors_[]; + /** + * Number of additional columns + */ + int m_additionalColumnsCount_; + /** + * Maximum values for block, bits used as in vector word 0 + */ + int m_maxBlockScriptValue_; + /** + * Maximum values for script, bits used as in vector word 0 + */ + int m_maxJTGValue_; + /** + * Script_Extensions data + */ + public char[] m_scriptExtensions_; + + // private variables ------------------------------------------------- + + /** + * Default name of the datafile + */ + @SuppressWarnings("deprecation") + private static final String DATA_FILE_NAME_ = "/assets/eagler/icudt/uprops.icu"; + + /** + * Shift value for lead surrogate to form a supplementary character. + */ + private static final int LEAD_SURROGATE_SHIFT_ = 10; + /** + * Offset to add to combined surrogate pair to avoid masking. + */ + private static final int SURROGATE_OFFSET_ = UTF16.SUPPLEMENTARY_MIN_VALUE + - (UTF16.SURROGATE_MIN_VALUE << LEAD_SURROGATE_SHIFT_) - UTF16.TRAIL_SURROGATE_MIN_VALUE; + + // property data constants ------------------------------------------------- + + /** + * Numeric types and values in the main properties words. + */ + private static final int NUMERIC_TYPE_VALUE_SHIFT_ = 6; + + private static final int getNumericTypeValue(int props) { + return props >> NUMERIC_TYPE_VALUE_SHIFT_; + } + + /* constants for the storage form of numeric types and values */ + /** No numeric value. */ + private static final int NTV_NONE_ = 0; + /** Decimal digits: nv=0..9 */ + private static final int NTV_DECIMAL_START_ = 1; + /** Other digits: nv=0..9 */ + private static final int NTV_DIGIT_START_ = 11; + /** Small integers: nv=0..154 */ + private static final int NTV_NUMERIC_START_ = 21; + + private static final int ntvGetType(int ntv) { + return (ntv == NTV_NONE_) ? NumericType.NONE + : (ntv < NTV_DIGIT_START_) ? NumericType.DECIMAL + : (ntv < NTV_NUMERIC_START_) ? NumericType.DIGIT : NumericType.NUMERIC; + } + + /* + * Properties in vector word 0 Bits 31..24 DerivedAge version major/minor one + * nibble each 23..22 3..1: Bits 21..20 & 7..0 = Script_Extensions index 3: + * Script value from Script_Extensions 2: Script=Inherited 1: Script=Common 0: + * Script=bits 21..20 & 7..0 21..20 Bits 9..8 of the UScriptCode, or index to + * Script_Extensions 19..17 East Asian Width 16.. 8 UBlockCode 7.. 0 + * UScriptCode, or index to Script_Extensions + */ + + /** + * Script_Extensions: mask includes Script + */ + public static final int SCRIPT_X_MASK = 0x00f000ff; + // private static final int SCRIPT_X_SHIFT = 22; + + // The UScriptCode or Script_Extensions index is split across two bit fields. + // (Starting with Unicode 13/ICU 66/2019 due to more varied Script_Extensions.) + // Shift the high bits right by 12 to assemble the full value. + public static final int SCRIPT_HIGH_MASK = 0x00300000; + public static final int SCRIPT_HIGH_SHIFT = 12; + public static final int MAX_SCRIPT = 0x3ff; + + /** + * Integer properties mask and shift values for East Asian cell width. + * Equivalent to icu4c UPROPS_EA_MASK + */ + private static final int EAST_ASIAN_MASK_ = 0x000e0000; + /** + * Integer properties mask and shift values for East Asian cell width. + * Equivalent to icu4c UPROPS_EA_SHIFT + */ + private static final int EAST_ASIAN_SHIFT_ = 17; + /** + * Integer properties mask and shift values for blocks. Equivalent to icu4c + * UPROPS_BLOCK_MASK + */ + private static final int BLOCK_MASK_ = 0x0001ff00; + /** + * Integer properties mask and shift values for blocks. Equivalent to icu4c + * UPROPS_BLOCK_SHIFT + */ + private static final int BLOCK_SHIFT_ = 8; + /** + * Integer properties mask and shift values for scripts. Equivalent to icu4c + * UPROPS_SHIFT_LOW_MASK. + */ + public static final int SCRIPT_LOW_MASK = 0x000000ff; + + public static final int mergeScriptCodeOrIndex(int scriptX) { + return ((scriptX & SCRIPT_HIGH_MASK) >> SCRIPT_HIGH_SHIFT) | (scriptX & SCRIPT_LOW_MASK); + } + + /** + * Additional properties used in internal trie data + */ + /* + * Properties in vector word 1 Each bit encodes one binary property. The + * following constants represent the bit number, use 1< expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for main trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // skip unused intervening data structures + ICUBinary.skipBytes(bytes, (additionalOffset - propertyOffset) * 4); + + if (m_additionalColumnsCount_ > 0) { + // reads the additional property block + m_additionalTrie_ = Trie2_16.createFromSerialized(bytes); + expectedTrieLength = (additionalVectorsOffset - additionalOffset) * 4; + trieLength = m_additionalTrie_.getSerializedLength(); + if (trieLength > expectedTrieLength) { + throw new IOException("uprops.icu: not enough bytes for additional-properties trie"); + } + // skip padding after trie bytes + ICUBinary.skipBytes(bytes, expectedTrieLength - trieLength); + + // additional properties + int size = scriptExtensionsOffset - additionalVectorsOffset; + m_additionalVectors_ = new int[size]; + for (int i = 0; i < size; i++) { + m_additionalVectors_[i] = bytes.getInt(); + } + } + + // Script_Extensions + int numChars = (reservedOffset7 - scriptExtensionsOffset) * 2; + if (numChars > 0) { + m_scriptExtensions_ = new char[numChars]; + for (int i = 0; i < numChars; ++i) { + m_scriptExtensions_[i] = bytes.getChar(); + } + } + } + + private static final class IsAcceptable implements ICUBinary.Authenticate { + // @Override when we switch to Java 6 + public boolean isDataVersionAcceptable(byte version[]) { + return version[0] == 7; + } + } + + private static final int DATA_FORMAT = 0x5550726F; // "UPro" + + public void upropsvec_addPropertyStarts(UnicodeSet set) { + /* + * add the start code point of each same-value range of the properties vectors + * trie + */ + if (m_additionalColumnsCount_ > 0) { + /* + * if m_additionalColumnsCount_==0 then the properties vectors trie may not be + * there at all + */ + Iterator trieIterator = m_additionalTrie_.iterator(); + Trie2.Range range; + while (trieIterator.hasNext() && !(range = trieIterator.next()).leadSurrogate) { + set.add(range.startCodePoint); + } + } + } + + // This static initializer block must be placed after + // other static member initialization + static { + try { + INSTANCE = new UCharacterProperty(); + } catch (IOException e) { + throw new RuntimeException("Missing resource: \"" + DATA_FILE_NAME_ + "\"; Reason: " + e.getMessage()); + } + } + + // Moved from UProperty.java + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). Used in + * UAX #9: Unicode Bidirectional Algorithm (http://www.unicode.org/reports/tr9/) + * Returns UCharacter.BidiPairedBracketType values. + * + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/UnicodeSetStringSpan.java b/src/main/java/jdk_internal/bidi/icu/impl/UnicodeSetStringSpan.java new file mode 100755 index 00000000..c89f8b09 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/UnicodeSetStringSpan.java @@ -0,0 +1,1179 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ****************************************************************************** + * + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + * + ****************************************************************************** + */ + +package jdk_internal.bidi.icu.impl; + +import java.util.ArrayList; + +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.text.UnicodeSet; +import jdk_internal.bidi.icu.text.UnicodeSet.SpanCondition; +import jdk_internal.bidi.icu.util.OutputInt; + +/* + * Implement span() etc. for a set with strings. + * Avoid recursion because of its exponential complexity. + * Instead, try multiple paths at once and track them with an IndexList. + */ +public class UnicodeSetStringSpan { + + /* + * Which span() variant will be used? The object is either built for one variant + * and used once, or built for all and may be used many times. + */ + public static final int WITH_COUNT = 0x40; // spanAndCount() may be called + public static final int FWD = 0x20; + public static final int BACK = 0x10; + // public static final int UTF16 = 8; + public static final int CONTAINED = 2; + public static final int NOT_CONTAINED = 1; + + public static final int ALL = 0x7f; + + public static final int FWD_UTF16_CONTAINED = FWD | /* UTF16 | */ CONTAINED; + public static final int FWD_UTF16_NOT_CONTAINED = FWD | /* UTF16 | */NOT_CONTAINED; + public static final int BACK_UTF16_CONTAINED = BACK | /* UTF16 | */ CONTAINED; + public static final int BACK_UTF16_NOT_CONTAINED = BACK | /* UTF16 | */NOT_CONTAINED; + + /** + * Special spanLength short values. (since Java has not unsigned byte type) All + * code points in the string are contained in the parent set. + */ + static final short ALL_CP_CONTAINED = 0xff; + + /** The spanLength is >=0xfe. */ + static final short LONG_SPAN = ALL_CP_CONTAINED - 1; + + /** Set for span(). Same as parent but without strings. */ + private UnicodeSet spanSet; + + /** + * Set for span(not contained). Same as spanSet, plus characters that start or + * end strings. + */ + private UnicodeSet spanNotSet; + + /** The strings of the parent set. */ + private ArrayList strings; + + /** The lengths of span(), spanBack() etc. for each string. */ + private short[] spanLengths; + + /** Maximum lengths of relevant strings. */ + private int maxLength16; + + /** Are there strings that are not fully contained in the code point set? */ + private boolean someRelevant; + + /** Set up for all variants of span()? */ + private boolean all; + + /** Span helper */ + private OffsetList offsets; + + /** + * Constructs for all variants of span(), or only for any one variant. + * Initializes as little as possible, for single use. + */ + public UnicodeSetStringSpan(final UnicodeSet set, final ArrayList setStrings, int which) { + spanSet = new UnicodeSet(0, 0x10ffff); + // TODO: With Java 6, just take the parent set's strings as is, + // as a NavigableSet, rather than as an ArrayList copy of the set of + // strings. + // Then iterate via the first() and higher() methods. + // (We do not want to create multiple Iterator objects in each span().) + // See ICU ticket #7454. + strings = setStrings; + all = (which == ALL); + spanSet.retainAll(set); + if (0 != (which & NOT_CONTAINED)) { + // Default to the same sets. + // addToSpanNotSet() will create a separate set if necessary. + spanNotSet = spanSet; + } + offsets = new OffsetList(); + + // Determine if the strings even need to be taken into account at all for span() + // etc. + // If any string is relevant, then all strings need to be used for + // span(longest match) but only the relevant ones for span(while contained). + // TODO: Possible optimization: Distinguish CONTAINED vs. LONGEST_MATCH + // and do not store UTF-8 strings if !thisRelevant and CONTAINED. + // (Only store irrelevant UTF-8 strings for LONGEST_MATCH where they are + // relevant after all.) + // Also count the lengths of the UTF-8 versions of the strings for memory + // allocation. + int stringsLength = strings.size(); + + int i, spanLength; + someRelevant = false; + for (i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + someRelevant = true; + } + if (/* (0 != (which & UTF16)) && */ length16 > maxLength16) { + maxLength16 = length16; + } + } + if (!someRelevant && (which & WITH_COUNT) == 0) { + return; + } + + // Freeze after checking for the need to use strings at all because freezing + // a set takes some time and memory which are wasted if there are no relevant + // strings. + if (all) { + spanSet.freeze(); + } + + int spanBackLengthsOffset; + + // Allocate a block of meta data. + int allocSize; + if (all) { + // 2 sets of span lengths + allocSize = stringsLength * (2); + } else { + allocSize = stringsLength; // One set of span lengths. + } + spanLengths = new short[allocSize]; + + if (all) { + // Store span lengths for all span() variants. + spanBackLengthsOffset = stringsLength; + } else { + // Store span lengths for only one span() variant. + spanBackLengthsOffset = 0; + } + + // Set the meta data and spanNotSet and write the UTF-8 strings. + + for (i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + spanLength = spanSet.span(string, SpanCondition.CONTAINED); + if (spanLength < length16) { // Relevant string. + if (true /* 0 != (which & UTF16) */) { + if (0 != (which & CONTAINED)) { + if (0 != (which & FWD)) { + spanLengths[i] = makeSpanLengthByte(spanLength); + } + if (0 != (which & BACK)) { + spanLength = length16 - spanSet.spanBack(string, length16, SpanCondition.CONTAINED); + spanLengths[spanBackLengthsOffset + i] = makeSpanLengthByte(spanLength); + } + } else /* not CONTAINED, not all, but NOT_CONTAINED */ { + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = 0; // Only store a relevant/irrelevant + // flag. + } + } + if (0 != (which & NOT_CONTAINED)) { + // Add string start and end code points to the spanNotSet so that + // a span(while not contained) stops before any string. + int c; + if (0 != (which & FWD)) { + c = string.codePointAt(0); + addToSpanNotSet(c); + } + if (0 != (which & BACK)) { + c = string.codePointBefore(length16); + addToSpanNotSet(c); + } + } + } else { // Irrelevant string. + if (all) { + spanLengths[i] = spanLengths[spanBackLengthsOffset + i] = ALL_CP_CONTAINED; + } else { + // All spanXYZLengths pointers contain the same address. + spanLengths[i] = ALL_CP_CONTAINED; + } + } + } + + // Finish. + if (all) { + spanNotSet.freeze(); + } + } + + /** + * Do the strings need to be checked in span() etc.? + * + * @return true if strings need to be checked (call span() here), false if not + * (use a BMPSet for best performance). + */ + public boolean needsStringSpanUTF16() { + return someRelevant; + } + + /** For fast UnicodeSet::contains(c). */ + public boolean contains(int c) { + return spanSet.contains(c); + } + + /** + * Adds a starting or ending string character to the spanNotSet so that a + * character span ends before any string. + */ + private void addToSpanNotSet(int c) { + if (spanNotSet == null || spanNotSet == spanSet) { + if (spanSet.contains(c)) { + return; // Nothing to do. + } + spanNotSet = spanSet.cloneAsThawed(); + } + spanNotSet.add(c); + } + + /* + * Note: In span() when spanLength==0 (after a string match, or at the beginning + * after an empty code point span) and in spanNot() and spanNotUTF8(), string + * matching could use a binary search because all string matches are done from + * the same start index. + * + * For UTF-8, this would require a comparison function that returns UTF-16 + * order. + * + * This optimization should not be necessary for normal UnicodeSets because most + * sets have no strings, and most sets with strings have very few very short + * strings. For cases with many strings, it might be better to use a different + * API and implementation with a DFA (state machine). + */ + + /* + * Algorithm for span(SpanCondition.CONTAINED) + * + * Theoretical algorithm: - Iterate through the string, and at each code point + * boundary: + If the code point there is in the set, then remember to continue + * after it. + If a set string matches at the current position, then remember to + * continue after it. + Either recursively span for each code point or string + * match, or recursively span for all but the shortest one and iteratively + * continue the span with the shortest local match. + Remember the longest + * recursive span (the farthest end point). + If there is no match at the + * current position, neither for the code point there nor for any set string, + * then stop and return the longest recursive span length. + * + * Optimized implementation: + * + * (We assume that most sets will have very few very short strings. A span using + * a string-less set is extremely fast.) + * + * Create and cache a spanSet which contains all of the single code points of + * the original set but none of its strings. + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). - Loop: + Try + * to match each set string at the end of the spanLength. ~ Set strings that + * start with set-contained code points must be matched with a partial overlap + * because the recursive algorithm would have tried to match them at every + * position. ~ Set strings that entirely consist of set-contained code points + * are irrelevant for span(SpanCondition.CONTAINED) because the recursive + * algorithm would continue after them anyway and find the longest recursive + * match from their end. ~ Rather than recursing, note each end point of a set + * string match. + If no set string matched after spanSet.span(), then return + * with where the spanSet.span() ended. + If at least one set string matched + * after spanSet.span(), then pop the shortest string match end point and + * continue the loop, trying to match all set strings from there. + If at least + * one more set string matched after a previous string match, then test if the + * code point after the previous string match is also contained in the set. + * Continue the loop with the shortest end point of either this code point or a + * matching set string. + If no more set string matched after a previous string + * match, then try another spanLength=spanSet.span(SpanCondition.CONTAINED). + * Stop if spanLength==0, otherwise continue the loop. + * + * By noting each end point of a set string match, the function visits each + * string position at most once and finishes in linear time. + * + * The recursive algorithm may visit the same string position many times if + * multiple paths lead to it and finishes in exponential time. + */ + + /* + * Algorithm for span(SIMPLE) + * + * Theoretical algorithm: - Iterate through the string, and at each code point + * boundary: + If the code point there is in the set, then remember to continue + * after it. + If a set string matches at the current position, then remember to + * continue after it. + Continue from the farthest match position and ignore all + * others. + If there is no match at the current position, then stop and return + * the current position. + * + * Optimized implementation: + * + * (Same assumption and spanSet as above.) + * + * - Start with spanLength=spanSet.span(SpanCondition.CONTAINED). - Loop: + Try + * to match each set string at the end of the spanLength. ~ Set strings that + * start with set-contained code points must be matched with a partial overlap + * because the standard algorithm would have tried to match them earlier. ~ Set + * strings that entirely consist of set-contained code points must be matched + * with a full overlap because the longest-match algorithm would hide set string + * matches that end earlier. Such set strings need not be matched earlier inside + * the code point span because the standard algorithm would then have continued + * after the set string match anyway. ~ Remember the longest set string match + * (farthest end point) from the earliest starting point. + If no set string + * matched after spanSet.span(), then return with where the spanSet.span() + * ended. + If at least one set string matched, then continue the loop after the + * longest match from the earliest position. + If no more set string matched + * after a previous string match, then try another + * spanLength=spanSet.span(SpanCondition.CONTAINED). Stop if spanLength==0, + * otherwise continue the loop. + */ + /** + * Spans a string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the limit (exclusive end) of the span + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, null); + } + int spanLimit = spanSet.span(s, start, SpanCondition.CONTAINED); + if (spanLimit == s.length()) { + return spanLimit; + } + return spanWithStrings(s, start, spanLimit, spanCondition); + } + + /** + * Synchronized method for complicated spans using the offsets. Avoids + * synchronization for simple cases. + * + * @param spanLimit = spanSet.span(s, start, CONTAINED) + */ + private synchronized int spanWithStrings(CharSequence s, int start, int spanLimit, SpanCondition spanCondition) { + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int length = s.length(); + int pos = spanLimit, rest = length - spanLimit; + int spanLength = spanLimit - start; + int i, stringsLength = strings.size(); + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + overlap = string.offsetByCodePoints(overlap, -1); // Length of the string minus the last code + // point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest) { + break; + } + // Try to match if the increment is not listed already. + if (!offsets.containsOffset(inc) && matches16CPB(s, pos - overlap, length, string, length16)) { + if (inc == rest) { + return length; // Reached the end of the string. + } + offsets.addOffset(inc); + } + if (overlap == 0) { + break; + } + --overlap; + ++inc; + } + } + } else /* SIMPLE */ { + int maxInc = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the earliest start. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-overlap..pos. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the earliest start. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int inc = length16 - overlap; // Keep overlap+inc==length16. + for (;;) { + if (inc > rest || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or starts earlier. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */inc > maxInc) + && matches16CPB(s, pos - overlap, length, string, length16)) { + maxInc = inc; // Longest match from earliest start. + maxOverlap = overlap; + break; + } + --overlap; + ++inc; + } + } + + if (maxInc != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue after it. + pos += maxInc; + rest -= maxInc; + if (rest == 0) { + return length; // Reached the end of the string. + } + spanLength = 0; // Match strings from after a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == 0) { + // The position is after an unlimited code point span (spanLength!=0), + // not after a string match. + // The only position where spanLength==0 after a span is pos==0. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched after a span. + } + // Match strings from after the next string match. + } else { + // The position is after a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched after a previous string match. + // Try another code point span from after the last string match. + spanLimit = spanSet.span(s, pos, SpanCondition.CONTAINED); + spanLength = spanLimit - pos; + if (spanLength == rest || // Reached the end of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return spanLimit; + } + pos += spanLength; + rest -= spanLength; + continue; // spanLength>0: Match strings from after a span. + } else { + // Try to match only one code point from after a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOne(spanSet, s, pos, rest); + if (spanLength > 0) { + if (spanLength == rest) { + return length; // Reached the end of the string. + } + // Match strings after this code point. + // There cannot be any increments below it because UnicodeSet strings + // contain multiple code points. + pos += spanLength; + rest -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from after a single code point. + } + // Match strings from after the next string match. + } + } + int minOffset = offsets.popMinimum(null); + pos += minOffset; + rest -= minOffset; + spanLength = 0; // Match strings from after a string match. + } + } + + /** + * Spans a string and counts the smallest number of set elements on any path + * across the span. + * + *

+ * For proper counting, we cannot ignore strings that are fully contained in + * code point spans. + * + *

+ * If the set does not have any fully-contained strings, then we could optimize + * this like span(), but such sets are likely rare, and this is at least still + * linear. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @param outCount The count + * @return the limit (exclusive end) of the span + */ + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNot(s, start, outCount); + } + // Consider strings; they may overlap with the span, + // and they may result in a smaller count that with just code points. + if (spanCondition == SpanCondition.CONTAINED) { + return spanContainedAndCount(s, start, outCount); + } + // SIMPLE (not synchronized, does not use offsets) + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + int maxInc = (cpLength > 0) ? cpLength : 0; + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + if (maxInc < length16 && length16 <= rest && matches16CPB(s, pos, length, string, length16)) { + maxInc = length16; + } + } + // We are done if there is no match beyond pos. + if (maxInc == 0) { + outCount.value = count; + return pos; + } + // Continue from the longest match. + ++count; + pos += maxInc; + rest -= maxInc; + } + outCount.value = count; + return pos; + } + + private synchronized int spanContainedAndCount(CharSequence s, int start, OutputInt outCount) { + // Use offset list to try all possibilities. + offsets.setMaxLength(maxLength16); + int stringsLength = strings.size(); + int length = s.length(); + int pos = start; + int rest = length - start; + int count = 0; + while (rest != 0) { + // Try to match the next code point. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + offsets.addOffsetAndCount(cpLength, count + 1); + } + // Try to match all of the strings. + for (int i = 0; i < stringsLength; ++i) { + String string = strings.get(i); + int length16 = string.length(); + // Note: If the strings were sorted by length, then we could also + // avoid trying to match if there is already a match of the same length. + if (length16 <= rest && !offsets.hasCountAtOffset(length16, count + 1) + && matches16CPB(s, pos, length, string, length16)) { + offsets.addOffsetAndCount(length16, count + 1); + } + } + // We are done if there is no match beyond pos. + if (offsets.isEmpty()) { + outCount.value = count; + return pos; + } + // Continue from the nearest match. + int minOffset = offsets.popMinimum(outCount); + count = outCount.value; + pos += minOffset; + rest -= minOffset; + } + outCount.value = count; + return pos; + } + + /** + * Span a string backwards. + * + * @param s The string to be spanned + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + */ + public synchronized int spanBack(CharSequence s, int length, SpanCondition spanCondition) { + if (spanCondition == SpanCondition.NOT_CONTAINED) { + return spanNotBack(s, length); + } + int pos = spanSet.spanBack(s, length, SpanCondition.CONTAINED); + if (pos == 0) { + return 0; + } + int spanLength = length - pos; + + // Consider strings; they may overlap with the span. + int initSize = 0; + if (spanCondition == SpanCondition.CONTAINED) { + // Use offset list to try all possibilities. + initSize = maxLength16; + } + offsets.setMaxLength(initSize); + int i, stringsLength = strings.size(); + int spanBackLengthsOffset = 0; + if (all) { + spanBackLengthsOffset = stringsLength; + } + for (;;) { + if (spanCondition == SpanCondition.CONTAINED) { + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + if (overlap == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // While contained: No point matching fully inside the code point span. + int len1 = 0; + len1 = string.offsetByCodePoints(0, 1); + overlap -= len1; // Length of the string minus the first code point. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos) { + break; + } + // Try to match if the decrement is not listed already. + if (!offsets.containsOffset(dec) && matches16CPB(s, pos - dec, length, string, length16)) { + if (dec == pos) { + return 0; // Reached the start of the string. + } + offsets.addOffset(dec); + } + if (overlap == 0) { + break; + } + --overlap; + ++dec; + } + } + } else /* SIMPLE */ { + int maxDec = 0, maxOverlap = 0; + for (i = 0; i < stringsLength; ++i) { + int overlap = spanLengths[spanBackLengthsOffset + i]; + // For longest match, we do need to try to match even an all-contained string + // to find the match from the latest end. + + String string = strings.get(i); + + int length16 = string.length(); + + // Try to match this string at pos-(length16-overlap)..pos-length16. + if (overlap >= LONG_SPAN) { + overlap = length16; + // Longest match: Need to match fully inside the code point span + // to find the match from the latest end. + } + if (overlap > spanLength) { + overlap = spanLength; + } + int dec = length16 - overlap; // Keep dec+overlap==length16. + for (;;) { + if (dec > pos || overlap < maxOverlap) { + break; + } + // Try to match if the string is longer or ends later. + if ((overlap > maxOverlap || /* redundant overlap==maxOverlap && */dec > maxDec) + && matches16CPB(s, pos - dec, length, string, length16)) { + maxDec = dec; // Longest match from latest end. + maxOverlap = overlap; + break; + } + --overlap; + ++dec; + } + } + + if (maxDec != 0 || maxOverlap != 0) { + // Longest-match algorithm, and there was a string match. + // Simply continue before it. + pos -= maxDec; + if (pos == 0) { + return 0; // Reached the start of the string. + } + spanLength = 0; // Match strings from before a string match. + continue; + } + } + // Finished trying to match all strings at pos. + + if (spanLength != 0 || pos == length) { + // The position is before an unlimited code point span (spanLength!=0), + // not before a string match. + // The only position where spanLength==0 before a span is pos==length. + // Otherwise, an unlimited code point span is only tried again when no + // strings match, and if such a non-initial span fails we stop. + if (offsets.isEmpty()) { + return pos; // No strings matched before a span. + } + // Match strings from before the next string match. + } else { + // The position is before a string match (or a single code point). + if (offsets.isEmpty()) { + // No more strings matched before a previous string match. + // Try another code point span from before the last string match. + int oldPos = pos; + pos = spanSet.spanBack(s, oldPos, SpanCondition.CONTAINED); + spanLength = oldPos - pos; + if (pos == 0 || // Reached the start of the string, or + spanLength == 0 // neither strings nor span progressed. + ) { + return pos; + } + continue; // spanLength>0: Match strings from before a span. + } else { + // Try to match only one code point from before a string match if some + // string matched beyond it, so that we try all possible positions + // and don't overshoot. + spanLength = spanOneBack(spanSet, s, pos); + if (spanLength > 0) { + if (spanLength == pos) { + return 0; // Reached the start of the string. + } + // Match strings before this code point. + // There cannot be any decrements below it because UnicodeSet strings + // contain multiple code points. + pos -= spanLength; + offsets.shift(spanLength); + spanLength = 0; + continue; // Match strings from before a single code point. + } + // Match strings from before the next string match. + } + } + pos -= offsets.popMinimum(null); + spanLength = 0; // Match strings from before a string match. + } + } + + /** + * Algorithm for spanNot()==span(SpanCondition.NOT_CONTAINED) + * + * Theoretical algorithm: - Iterate through the string, and at each code point + * boundary: + If the code point there is in the set, then return with the + * current position. + If a set string matches at the current position, then + * return with the current position. + * + * Optimized implementation: + * + * (Same assumption as for span() above.) + * + * Create and cache a spanNotSet which contains all of the single code points of + * the original set but none of its strings. For each set string add its initial + * code point to the spanNotSet. (Also add its final code point for + * spanNotBack().) + * + * - Loop: + Do spanLength=spanNotSet.span(SpanCondition.NOT_CONTAINED). + If + * the current code point is in the original set, then return the current + * position. + If any set string matches at the current position, then return + * the current position. + If there is no match at the current position, neither + * for the code point there nor for any set string, then skip this code point + * and continue the loop. This happens for set-string-initial code points that + * were added to spanNotSet when there is not actually a match for such a set + * string. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param outCount If not null: Receives the number of code points across the + * span. + * @return the limit (exclusive end) of the span + */ + private int spanNot(CharSequence s, int start, OutputInt outCount) { + int length = s.length(); + int pos = start, rest = length - start; + int stringsLength = strings.size(); + int count = 0; + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + int spanLimit; + if (outCount == null) { + spanLimit = spanNotSet.span(s, pos, SpanCondition.NOT_CONTAINED); + } else { + spanLimit = spanNotSet.spanAndCount(s, pos, SpanCondition.NOT_CONTAINED, outCount); + outCount.value = count = count + outCount.value; + } + if (spanLimit == length) { + return length; // Reached the end of the string. + } + pos = spanLimit; + rest = length - spanLimit; + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOne(spanSet, s, pos, rest); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (int i = 0; i < stringsLength; ++i) { + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= rest && matches16CPB(s, pos, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos -= cpLength; + rest += cpLength; + ++count; + } while (rest != 0); + if (outCount != null) { + outCount.value = count; + } + return length; // Reached the end of the string. + } + + private int spanNotBack(CharSequence s, int length) { + int pos = length; + int i, stringsLength = strings.size(); + do { + // Span until we find a code point from the set, + // or a code point that starts or ends some string. + pos = spanNotSet.spanBack(s, pos, SpanCondition.NOT_CONTAINED); + if (pos == 0) { + return 0; // Reached the start of the string. + } + + // Check whether the current code point is in the original set, + // without the string starts and ends. + int cpLength = spanOneBack(spanSet, s, pos); + if (cpLength > 0) { + return pos; // There is a set element at pos. + } + + // Try to match the strings at pos. + for (i = 0; i < stringsLength; ++i) { + // Use spanLengths rather than a spanLengths pointer because + // it is easier and we only need to know whether the string is irrelevant + // which is the same in either array. + if (spanLengths[i] == ALL_CP_CONTAINED) { + continue; // Irrelevant string. + } + String string = strings.get(i); + + int length16 = string.length(); + if (length16 <= pos && matches16CPB(s, pos - length16, length, string, length16)) { + return pos; // There is a set element at pos. + } + } + + // The span(while not contained) ended on a string start/end which is + // not in the original set. Skip this code point and continue. + // cpLength<0 + pos += cpLength; + } while (pos != 0); + return 0; // Reached the start of the string. + } + + static short makeSpanLengthByte(int spanLength) { + // 0xfe==UnicodeSetStringSpan::LONG_SPAN + return spanLength < LONG_SPAN ? (short) spanLength : LONG_SPAN; + } + + // Compare strings without any argument checks. Requires length>0. + private static boolean matches16(CharSequence s, int start, final String t, int length) { + int end = start + length; + while (length-- > 0) { + if (s.charAt(--end) != t.charAt(length)) { + return false; + } + } + return true; + } + + /** + * Compare 16-bit Unicode strings (which may be malformed UTF-16) at code point + * boundaries. That is, each edge of a match must not be in the middle of a + * surrogate pair. + * + * @param s The string to match in. + * @param start The start index of s. + * @param limit The limit of the subsequence of s being spanned. + * @param t The substring to be matched in s. + * @param tlength The length of t. + */ + static boolean matches16CPB(CharSequence s, int start, int limit, final String t, int tlength) { + return matches16(s, start, t, tlength) + && !(0 < start && Character.isHighSurrogate(s.charAt(start - 1)) + && Character.isLowSurrogate(s.charAt(start))) + && !((start + tlength) < limit && Character.isHighSurrogate(s.charAt(start + tlength - 1)) + && Character.isLowSurrogate(s.charAt(start + tlength))); + } + + /** + * Does the set contain the next code point? If so, return its length; otherwise + * return its negative length. + */ + static int spanOne(final UnicodeSet set, CharSequence s, int start, int length) { + char c = s.charAt(start); + if (c >= 0xd800 && c <= 0xdbff && length >= 2) { + char c2 = s.charAt(start + 1); + if (UTF16.isTrailSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c, c2); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + static int spanOneBack(final UnicodeSet set, CharSequence s, int length) { + char c = s.charAt(length - 1); + if (c >= 0xdc00 && c <= 0xdfff && length >= 2) { + char c2 = s.charAt(length - 2); + if (UTF16.isLeadSurrogate(c2)) { + int supplementary = UCharacterProperty.getRawSupplementary(c2, c); + return set.contains(supplementary) ? 2 : -2; + } + } + return set.contains(c) ? 1 : -1; + } + + /** + * Helper class for UnicodeSetStringSpan. + * + *

+ * List of offsets from the current position from where to try matching a code + * point or a string. Stores offsets rather than indexes to simplify the code + * and use the same list for both increments (in span()) and decrements (in + * spanBack()). + * + *

+ * Assumption: The maximum offset is limited, and the offsets that are stored at + * any one time are relatively dense, that is, there are normally no gaps of + * hundreds or thousands of offset values. + * + *

+ * This class optionally also tracks the minimum non-negative count for each + * position, intended to count the smallest number of elements of any path + * leading to that position. + * + *

+ * The implementation uses a circular buffer of count integers, each indicating + * whether the corresponding offset is in the list, and its path element count. + * This avoids inserting into a sorted list of offsets (or absolute indexes) and + * physically moving part of the list. + * + *

+ * Note: In principle, the caller should setMaxLength() to the maximum of the + * max string length and U16_LENGTH/U8_LENGTH to account for "long" single code + * points. + * + *

+ * Note: An earlier version did not track counts and stored only byte flags. + * With boolean flags, if maxLength were guaranteed to be no more than 32 or 64, + * the list could be stored as bit flags in a single integer. Rather than + * handling a circular buffer with a start list index, the integer would simply + * be shifted when lower offsets are removed. UnicodeSet does not have a limit + * on the lengths of strings. + */ + private static final class OffsetList { + private int[] list; + private int length; + private int start; + + public OffsetList() { + list = new int[16]; // default size + } + + public void setMaxLength(int maxLength) { + if (maxLength > list.length) { + list = new int[maxLength]; + } + clear(); + } + + public void clear() { + for (int i = list.length; i-- > 0;) { + list[i] = 0; + } + start = length = 0; + } + + public boolean isEmpty() { + return (length == 0); + } + + /** + * Reduces all stored offsets by delta, used when the current position moves by + * delta. There must not be any offsets lower than delta. If there is an offset + * equal to delta, it is removed. + * + * @param delta [1..maxLength] + */ + public void shift(int delta) { + int i = start + delta; + if (i >= list.length) { + i -= list.length; + } + if (list[i] != 0) { + list[i] = 0; + --length; + } + start = i; + } + + /** + * Adds an offset. The list must not contain it yet. + * + * @param offset [1..maxLength] + */ + public void addOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + assert list[i] == 0; + list[i] = 1; + ++length; + } + + /** + * Adds an offset and updates its count. The list may already contain the + * offset. + * + * @param offset [1..maxLength] + */ + public void addOffsetAndCount(int offset, int count) { + assert count > 0; + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + if (list[i] == 0) { + list[i] = count; + ++length; + } else if (count < list[i]) { + list[i] = count; + } + } + + /** + * @param offset [1..maxLength] + */ + public boolean containsOffset(int offset) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + return list[i] != 0; + } + + /** + * @param offset [1..maxLength] + */ + public boolean hasCountAtOffset(int offset, int count) { + int i = start + offset; + if (i >= list.length) { + i -= list.length; + } + int oldCount = list[i]; + return oldCount != 0 && oldCount <= count; + } + + /** + * Finds the lowest stored offset from a non-empty list, removes it, and reduces + * all other offsets by this minimum. + * + * @return min=[1..maxLength] + */ + public int popMinimum(OutputInt outCount) { + // Look for the next offset in list[start+1..list.length-1]. + int i = start, result; + while (++i < list.length) { + int count = list[i]; + if (count != 0) { + list[i] = 0; + --length; + result = i - start; + start = i; + if (outCount != null) { + outCount.value = count; + } + return result; + } + } + // i==list.length + + // Wrap around and look for the next offset in list[0..start]. + // Since the list is not empty, there will be one. + result = list.length - start; + i = 0; + int count; + while ((count = list[i]) == 0) { + ++i; + } + list[i] = 0; + --length; + start = i; + if (outCount != null) { + outCount.value = count; + } + return result + i; + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/impl/Utility.java b/src/main/java/jdk_internal/bidi/icu/impl/Utility.java new file mode 100755 index 00000000..74d0852d --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/impl/Utility.java @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * Copyright (C) 1996-2011, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.impl; + +import java.io.IOException; +import java.util.Locale; + +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.text.UTF16; + +public final class Utility { + + /** + * Convert characters outside the range U+0020 to U+007F to Unicode escapes, and + * convert backslash to a double backslash. + */ + public static final String escape(String s) { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < s.length();) { + int c = Character.codePointAt(s, i); + i += UTF16.getCharCount(c); + if (c >= ' ' && c <= 0x007F) { + if (c == '\\') { + buf.append("\\\\"); // That is, "\\" + } else { + buf.append((char) c); + } + } else { + boolean four = c <= 0xFFFF; + buf.append(four ? "\\u" : "\\U"); + buf.append(hex(c, four ? 4 : 8)); + } + } + return buf.toString(); + } + + /* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */ + private static final char[] UNESCAPE_MAP = { + /* " 0x22, 0x22 */ + /* ' 0x27, 0x27 */ + /* ? 0x3F, 0x3F */ + /* \ 0x5C, 0x5C */ + /* a */ 0x61, 0x07, /* b */ 0x62, 0x08, /* e */ 0x65, 0x1b, /* f */ 0x66, 0x0c, /* n */ 0x6E, 0x0a, + /* r */ 0x72, 0x0d, /* t */ 0x74, 0x09, /* v */ 0x76, 0x0b }; + + /** + * Convert an escape to a 32-bit code point value. We attempt to parallel the + * icu4c unescapeAt() function. + * + * @param offset16 an array containing offset to the character after + * the backslash. Upon return offset16[0] will be updated to + * point after the escape sequence. + * @return character value from 0 to 10FFFF, or -1 on error. + */ + public static int unescapeAt(String s, int[] offset16) { + int c; + int result = 0; + int n = 0; + int minDig = 0; + int maxDig = 0; + int bitsPerDigit = 4; + int dig; + int i; + boolean braces = false; + + /* Check that offset is in range */ + int offset = offset16[0]; + int length = s.length(); + if (offset < 0 || offset >= length) { + return -1; + } + + /* Fetch first UChar after '\\' */ + c = Character.codePointAt(s, offset); + offset += UTF16.getCharCount(c); + + /* Convert hexadecimal and octal escapes */ + switch (c) { + case 'u': + minDig = maxDig = 4; + break; + case 'U': + minDig = maxDig = 8; + break; + case 'x': + minDig = 1; + if (offset < length && UTF16.charAt(s, offset) == 0x7B /* { */) { + ++offset; + braces = true; + maxDig = 8; + } else { + maxDig = 2; + } + break; + default: + dig = UCharacter.digit(c, 8); + if (dig >= 0) { + minDig = 1; + maxDig = 3; + n = 1; /* Already have first octal digit */ + bitsPerDigit = 3; + result = dig; + } + break; + } + if (minDig != 0) { + while (offset < length && n < maxDig) { + c = UTF16.charAt(s, offset); + dig = UCharacter.digit(c, (bitsPerDigit == 3) ? 8 : 16); + if (dig < 0) { + break; + } + result = (result << bitsPerDigit) | dig; + offset += UTF16.getCharCount(c); + ++n; + } + if (n < minDig) { + return -1; + } + if (braces) { + if (c != 0x7D /* } */) { + return -1; + } + ++offset; + } + if (result < 0 || result >= 0x110000) { + return -1; + } + // If an escape sequence specifies a lead surrogate, see + // if there is a trail surrogate after it, either as an + // escape or as a literal. If so, join them up into a + // supplementary. + if (offset < length && UTF16.isLeadSurrogate((char) result)) { + int ahead = offset + 1; + c = s.charAt(offset); // [sic] get 16-bit code unit + if (c == '\\' && ahead < length) { + int o[] = new int[] { ahead }; + c = unescapeAt(s, o); + ahead = o[0]; + } + if (UTF16.isTrailSurrogate((char) c)) { + offset = ahead; + result = UCharacterProperty.getRawSupplementary((char) result, (char) c); + } + } + offset16[0] = offset; + return result; + } + + /* Convert C-style escapes in table */ + for (i = 0; i < UNESCAPE_MAP.length; i += 2) { + if (c == UNESCAPE_MAP[i]) { + offset16[0] = offset; + return UNESCAPE_MAP[i + 1]; + } else if (c < UNESCAPE_MAP[i]) { + break; + } + } + + /* Map \cX to control-X: X & 0x1F */ + if (c == 'c' && offset < length) { + c = UTF16.charAt(s, offset); + offset16[0] = offset + UTF16.getCharCount(c); + return 0x1F & c; + } + + /* + * If no special forms are recognized, then consider the backslash to + * generically escape the next character. + */ + offset16[0] = offset; + return c; + } + + /** + * Supplies a zero-padded hex representation of an integer (without 0x) + */ + public static String hex(long i, int places) { + if (i == Long.MIN_VALUE) + return "-8000000000000000"; + boolean negative = i < 0; + if (negative) { + i = -i; + } + String result = Long.toString(i, 16).toUpperCase(Locale.ENGLISH); + if (result.length() < places) { + result = "0000000000000000".substring(result.length(), places) + result; + } + if (negative) { + return '-' + result; + } + return result; + } + + static final char DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + + /** + * Return true if the character is NOT printable ASCII. The tab, newline and + * linefeed characters are considered unprintable. + */ + public static boolean isUnprintable(int c) { + // 0x20 = 32 and 0x7E = 126 + return !(c >= 0x20 && c <= 0x7E); + } + + /** + * Escape unprintable characters using uxxxx notation for U+0000 to + * U+FFFF and Uxxxxxxxx for U+10000 and above. If the character is + * printable ASCII, then do nothing and return FALSE. Otherwise, append the + * escaped notation and return TRUE. + */ + public static boolean escapeUnprintable(T result, int c) { + try { + if (isUnprintable(c)) { + result.append('\\'); + if ((c & ~0xFFFF) != 0) { + result.append('U'); + result.append(DIGITS[0xF & (c >> 28)]); + result.append(DIGITS[0xF & (c >> 24)]); + result.append(DIGITS[0xF & (c >> 20)]); + result.append(DIGITS[0xF & (c >> 16)]); + } else { + result.append('u'); + } + result.append(DIGITS[0xF & (c >> 12)]); + result.append(DIGITS[0xF & (c >> 8)]); + result.append(DIGITS[0xF & (c >> 4)]); + result.append(DIGITS[0xF & c]); + return true; + } + return false; + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/lang/UCharacter.java b/src/main/java/jdk_internal/bidi/icu/lang/UCharacter.java new file mode 100755 index 00000000..3c0fce0e --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/lang/UCharacter.java @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** +******************************************************************************* +* Copyright (C) 1996-2014, International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +*/ + +package jdk_internal.bidi.icu.lang; + +import jdk_internal.bidi.icu.impl.UBiDiProps; +import jdk_internal.bidi.icu.impl.UCharacterProperty; +import jdk_internal.bidi.icu.text.Normalizer2; +import jdk_internal.bidi.icu.text.UTF16; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + *

+ * The UCharacter class provides extensions to the + * + * java.lang.Character class. These extensions provide support for more + * Unicode properties and together with the UTF16 + * class, provide support for supplementary characters (those with code points + * above U+FFFF). Each ICU release supports the latest version of Unicode + * available at that time. + * + *

+ * Code points are represented in these API using ints. While it would be more + * convenient in Java to have a separate primitive datatype for them, ints + * suffice in the meantime. + * + *

+ * To use this class please add the jar file name icu4j.jar to the class path, + * since it contains data files which supply the information used by this + * file.
+ * E.g. In Windows
+ * set CLASSPATH=%CLASSPATH%;$JAR_FILE_PATH/ucharacter.jar.
+ * Otherwise, another method would be to copy the files uprops.dat and + * unames.icu from the icu4j source subdirectory + * $ICU4J_SRC/src/com.ibm.icu.impl.data to your class directory + * $ICU4J_CLASS/com.ibm.icu.impl.data. + * + *

+ * Aside from the additions for UTF-16 support, and the updated Unicode + * properties, the main differences between UCharacter and Character are: + *

    + *
  • UCharacter is not designed to be a char wrapper and does not have APIs to + * which involves management of that single char.
    + * These include: + *
      + *
    • char charValue(), + *
    • int compareTo(java.lang.Character, java.lang.Character), etc. + *
    + *
  • UCharacter does not include Character APIs that are deprecated, nor does + * it include the Java-specific character information, such as boolean + * isJavaIdentifierPart(char ch). + *
  • Character maps characters 'A' - 'Z' and 'a' - 'z' to the numeric values + * '10' - '35'. UCharacter also does this in digit and getNumericValue, to + * adhere to the java semantics of these methods. New methods unicodeDigit, and + * getUnicodeNumericValue do not treat the above code points as having numeric + * values. This is a semantic change from ICU4J 1.3.1. + *
+ *

+ * Further detail on differences can be determined using the program + * com.ibm.icu.dev.test.lang.UCharacterCompare + *

+ *

+ * In addition to Java compatibility functions, which calculate derived + * properties, this API provides low-level access to the Unicode Character + * Database. + *

+ *

+ * Unicode assigns each code point (not just assigned character) values for many + * properties. Most of them are simple boolean flags, or constants from a small + * enumerated list. For some properties, values are strings or other relatively + * more complex types. + *

+ *

+ * For more information see "About the + * Unicode Character Database" (http://www.unicode.org/ucd/) and the + * ICU User Guide + * chapter on Properties + * (http://www.icu-project.org/userguide/properties.html). + *

+ *

+ * There are also functions that provide easy migration from C/POSIX functions + * like isblank(). Their use is generally discouraged because the C/POSIX + * standards do not define their semantics beyond the ASCII range, which means + * that different implementations exhibit very different behavior. Instead, + * Unicode properties should be used directly. + *

+ *

+ * There are also only a few, broad C/POSIX character classes, and they tend to + * be used for conflicting purposes. For example, the "isalpha()" class is + * sometimes used to determine word boundaries, while a more sophisticated + * approach would at least distinguish initial letters from continuation + * characters (the latter including combining marks). (In ICU, BreakIterator is + * the most sophisticated API for word boundaries.) Another example: There is no + * "istitle()" class for titlecase characters. + *

+ *

+ * ICU 3.4 and later provides API access for all twelve C/POSIX character + * classes. ICU implements them according to the Standard Recommendations in + * Annex C: Compatibility Properties of UTS #18 Unicode Regular Expressions + * (http://www.unicode.org/reports/tr18/#Compatibility_Properties). + *

+ *

+ * API access for C/POSIX character classes is as follows: + * + *

{@code
+ * - alpha:     isUAlphabetic(c) or hasBinaryProperty(c, UProperty.ALPHABETIC)
+ * - lower:     isULowercase(c) or hasBinaryProperty(c, UProperty.LOWERCASE)
+ * - upper:     isUUppercase(c) or hasBinaryProperty(c, UProperty.UPPERCASE)
+ * - punct:     ((1<
+ * 

+ *

+ * The C/POSIX character classes are also available in UnicodeSet patterns, + * using patterns like [:graph:] or \p{graph}. + *

+ * + * There are several ICU (and Java) whitespace functions. Comparison: + *
    + *
  • isUWhiteSpace=UCHAR_WHITE_SPACE: Unicode White_Space property; most of + * general categories "Z" (separators) + most whitespace ISO controls (including + * no-break spaces, but excluding IS1..IS4 and ZWSP) + *
  • isWhitespace: Java isWhitespace; Z + whitespace ISO controls but + * excluding no-break spaces + *
  • isSpaceChar: just Z (including no-break spaces) + *
+ *

+ *

+ * This class is not subclassable. + *

+ * + * @author Syn Wee Quek + * @stable ICU 2.1 + * @see com.ibm.icu.lang.UCharacterEnums + */ + +public final class UCharacter { + + /** + * Joining Group constants. + * + * @see UProperty#JOINING_GROUP + * @stable ICU 2.4 + */ + public static interface JoiningGroup { + /** + * @stable ICU 2.4 + */ + public static final int NO_JOINING_GROUP = 0; + } + + /** + * Numeric Type constants. + * + * @see UProperty#NUMERIC_TYPE + * @stable ICU 2.4 + */ + public static interface NumericType { + /** + * @stable ICU 2.4 + */ + public static final int NONE = 0; + /** + * @stable ICU 2.4 + */ + public static final int DECIMAL = 1; + /** + * @stable ICU 2.4 + */ + public static final int DIGIT = 2; + /** + * @stable ICU 2.4 + */ + public static final int NUMERIC = 3; + /** + * @stable ICU 2.4 + */ + public static final int COUNT = 4; + } + + /** + * Hangul Syllable Type constants. + * + * @see UProperty#HANGUL_SYLLABLE_TYPE + * @stable ICU 2.6 + */ + public static interface HangulSyllableType { + /** + * @stable ICU 2.6 + */ + public static final int NOT_APPLICABLE = 0; /* [NA] */ /* See note !! */ + /** + * @stable ICU 2.6 + */ + public static final int LEADING_JAMO = 1; /* [L] */ + /** + * @stable ICU 2.6 + */ + public static final int VOWEL_JAMO = 2; /* [V] */ + /** + * @stable ICU 2.6 + */ + public static final int TRAILING_JAMO = 3; /* [T] */ + /** + * @stable ICU 2.6 + */ + public static final int LV_SYLLABLE = 4; /* [LV] */ + /** + * @stable ICU 2.6 + */ + public static final int LVT_SYLLABLE = 5; /* [LVT] */ + /** + * @stable ICU 2.6 + */ + public static final int COUNT = 6; + } + + // public data members ----------------------------------------------- + + /** + * The lowest Unicode code point value. + * + * @stable ICU 2.1 + */ + public static final int MIN_VALUE = UTF16.CODEPOINT_MIN_VALUE; + + /** + * The highest Unicode code point value (scalar value) according to the Unicode + * Standard. This is a 21-bit value (21 bits, rounded up).
+ * Up-to-date Unicode implementation of java.lang.Character.MAX_VALUE + * + * @stable ICU 2.1 + */ + public static final int MAX_VALUE = UTF16.CODEPOINT_MAX_VALUE; + + // public methods ---------------------------------------------------- + + /** + * Returns the numeric value of a decimal digit code point.
+ * This method observes the semantics of + * java.lang.Character.digit(). Note that this will return positive + * values for code points for which isDigit returns false, just like + * java.lang.Character.
+ * Semantic Change: In release 1.3.1 and prior, this did not treat the + * European letters as having a digit value, and also treated numeric letters + * and other numbers as digits. This has been changed to conform to the java + * semantics.
+ * A code point is a valid digit if and only if: + *
    + *
  • ch is a decimal digit or one of the european letters, and + *
  • the value of ch is less than the specified radix. + *
+ * + * @param ch the code point to query + * @param radix the radix + * @return the numeric value represented by the code point in the specified + * radix, or -1 if the code point is not a decimal digit or if its value + * is too large for the radix + * @stable ICU 2.1 + */ + public static int digit(int ch, int radix) { + if (2 <= radix && radix <= 36) { + int value = digit(ch); + if (value < 0) { + // ch is not a decimal digit, try latin letters + value = UCharacterProperty.getEuropeanDigit(ch); + } + return (value < radix) ? value : -1; + } else { + return -1; // invalid radix + } + } + + /** + * Returns the numeric value of a decimal digit code point.
+ * This is a convenience overload of digit(int, int) that provides + * a decimal radix.
+ * Semantic Change: In release 1.3.1 and prior, this treated numeric + * letters and other numbers as digits. This has been changed to conform to the + * java semantics. + * + * @param ch the code point to query + * @return the numeric value represented by the code point, or -1 if the code + * point is not a decimal digit or if its value is too large for a + * decimal radix + * @stable ICU 2.1 + */ + public static int digit(int ch) { + return UCharacterProperty.INSTANCE.digit(ch); + } + + /** + * Returns a value indicating a code point's Unicode category. Up-to-date + * Unicode implementation of java.lang.Character.getType() except for the above + * mentioned code points that had their category changed.
+ * Return results are constants from the interface + * UCharacterCategory
+ * NOTE: the UCharacterCategory values are not compatible with + * those returned by java.lang.Character.getType. UCharacterCategory values + * match the ones used in ICU4C, while java.lang.Character type values, though + * similar, skip the value 17. + *

+ * + * @param ch code point whose type is to be determined + * @return category which is a value of UCharacterCategory + * @stable ICU 2.1 + */ + public static int getType(int ch) { + return UCharacterProperty.INSTANCE.getType(ch); + } + + /** + * Returns the Bidirection property of a code point. For example, 0x0041 (letter + * A) has the LEFT_TO_RIGHT directional property.
+ * Result returned belongs to the interface + * UCharacterDirection + * + * @param ch the code point to be determined its direction + * @return direction constant from UCharacterDirection. + * @stable ICU 2.1 + */ + public static int getDirection(int ch) { + return UBiDiProps.INSTANCE.getClass(ch); + } + + /** + * Maps the specified code point to a "mirror-image" code point. For code points + * with the "mirrored" property, implementations sometimes need a "poor man's" + * mapping to another code point such that the default glyph may serve as the + * mirror-image of the default glyph of the specified code point.
+ * This is useful for text conversion to and from codepages with visual order, + * and for displays without glyph selection capabilities. + * + * @param ch code point whose mirror is to be retrieved + * @return another code point that may serve as a mirror-image substitute, or ch + * itself if there is no such mapping or ch does not have the "mirrored" + * property + * @stable ICU 2.1 + */ + public static int getMirror(int ch) { + return UBiDiProps.INSTANCE.getMirror(ch); + } + + /** + * Maps the specified character to its paired bracket character. For + * Bidi_Paired_Bracket_Type!=None, this is the same as getMirror(int). Otherwise + * c itself is returned. See http://www.unicode.org/reports/tr9/ + * + * @param c the code point to be mapped + * @return the paired bracket code point, or c itself if there is no such + * mapping (Bidi_Paired_Bracket_Type=None) + * + * @see UProperty#BIDI_PAIRED_BRACKET + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @see #getMirror(int) + * @stable ICU 52 + */ + public static int getBidiPairedBracket(int c) { + return UBiDiProps.INSTANCE.getPairedBracket(c); + } + + /** + * Returns the combining class of the argument codepoint + * + * @param ch code point whose combining is to be retrieved + * @return the combining class of the codepoint + * @stable ICU 2.1 + */ + public static int getCombiningClass(int ch) { + return Normalizer2.getNFDInstance().getCombiningClass(ch); + } + + /** + * Returns the version of Unicode data used. + * + * @return the unicode version number used + * @stable ICU 2.1 + */ + public static VersionInfo getUnicodeVersion() { + return UCharacterProperty.INSTANCE.m_unicodeVersion_; + } + + /** + * Returns a code point corresponding to the two UTF16 characters. + * + * @param lead the lead char + * @param trail the trail char + * @return code point if surrogate characters are valid. + * @exception IllegalArgumentException thrown when argument characters do not + * form a valid codepoint + * @stable ICU 2.1 + */ + public static int getCodePoint(char lead, char trail) { + if (UTF16.isLeadSurrogate(lead) && UTF16.isTrailSurrogate(trail)) { + return UCharacterProperty.getRawSupplementary(lead, trail); + } + throw new IllegalArgumentException("Illegal surrogate characters"); + } + + /** + * Returns the "age" of the code point. + *

+ *

+ * The "age" is the Unicode version when the code point was first designated (as + * a non-character or for Private Use) or assigned a character. + *

+ * This can be useful to avoid emitting code points to receiving processes that + * do not accept newer characters. + *

+ *

+ * The data is from the UCD file DerivedAge.txt. + *

+ * + * @param ch The code point. + * @return the Unicode version number + * @stable ICU 2.6 + */ + public static VersionInfo getAge(int ch) { + if (ch < MIN_VALUE || ch > MAX_VALUE) { + throw new IllegalArgumentException("Codepoint out of bounds"); + } + return UCharacterProperty.INSTANCE.getAge(ch); + } + + /** + * Returns the property value for an Unicode property type of a code point. Also + * returns binary and mask property values. + *

+ *

+ * Unicode, especially in version 3.2, defines many more properties than the + * original set in UnicodeData.txt. + *

+ *

+ * The properties APIs are intended to reflect Unicode properties as defined in + * the Unicode Character Database (UCD) and Unicode Technical Reports (UTR). For + * details about the properties see http://www.unicode.org/. + *

+ *

+ * For names of Unicode properties see the UCD file PropertyAliases.txt. + *

+ * + *
+	 * Sample usage:
+	 * int ea = UCharacter.getIntPropertyValue(c, UProperty.EAST_ASIAN_WIDTH);
+	 * int ideo = UCharacter.getIntPropertyValue(c, UProperty.IDEOGRAPHIC);
+	 * boolean b = (ideo == 1) ? true : false;
+	 * 
+ * + * @param ch code point to test. + * @param type UProperty selector constant, identifies which binary property to + * check. Must be UProperty.BINARY_START <= type < + * UProperty.BINARY_LIMIT or UProperty.INT_START <= type < + * UProperty.INT_LIMIT or UProperty.MASK_START <= type < + * UProperty.MASK_LIMIT. + * @return numeric value that is directly the property value or, for enumerated + * properties, corresponds to the numeric value of the enumerated + * constant of the respective property value enumeration type (cast to + * enum type if necessary). Returns 0 or 1 (for false / true) for binary + * Unicode properties. Returns a bit-mask for mask properties. Returns 0 + * if 'type' is out of bounds or if the Unicode version does not have + * data for the property at all, or not for this code point. + * @see UProperty + * @see #hasBinaryProperty + * @see #getIntPropertyMinValue + * @see #getIntPropertyMaxValue + * @see #getUnicodeVersion + * @stable ICU 2.4 + */ + // for BiDiBase.java + public static int getIntPropertyValue(int ch, int type) { + return UCharacterProperty.INSTANCE.getIntPropertyValue(ch, type); + } + + // private constructor ----------------------------------------------- + + /** + * Private constructor to prevent instantiation + */ + private UCharacter() { + } + + /* + * Copied from UCharacterEnums.java + */ + + /** + * Character type Mn + * + * @stable ICU 2.1 + */ + public static final byte NON_SPACING_MARK = 6; + /** + * Character type Me + * + * @stable ICU 2.1 + */ + public static final byte ENCLOSING_MARK = 7; + /** + * Character type Mc + * + * @stable ICU 2.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + /** + * Character type count + * + * @stable ICU 2.1 + */ + public static final byte CHAR_CATEGORY_COUNT = 30; + + /** + * Directional type R + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT = 1; + /** + * Directional type AL + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_ARABIC = 13; +} diff --git a/src/main/java/jdk_internal/bidi/icu/lang/UCharacterDirection.java b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterDirection.java new file mode 100755 index 00000000..7a3c8035 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterDirection.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/** +******************************************************************************* +* Copyright (C) 1996-2004, International Business Machines Corporation and * +* others. All Rights Reserved. * +******************************************************************************* +*/ +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/lang/UCharacterDirection.java +// - move from package com.ibm.icu.lang to package sun.net.idn +// + +package jdk_internal.bidi.icu.lang; + +/** + * Enumerated Unicode character linguistic direction constants. Used as return + * results from UCharacter + *

+ * This class is not subclassable + *

+ * + * @author Syn Wee Quek + * @stable ICU 2.1 + */ + +@SuppressWarnings("deprecation") +public final class UCharacterDirection implements UCharacterEnums.ECharacterDirection { + + // private constructor ========================================= + /// CLOVER:OFF + /** + * Private constructor to prevent initialisation + */ + private UCharacterDirection() { + } + /// CLOVER:ON + + /** + * Gets the name of the argument direction + * + * @param dir direction type to retrieve name + * @return directional name + * @stable ICU 2.1 + */ + public static String toString(int dir) { + switch (dir) { + case LEFT_TO_RIGHT: + return "Left-to-Right"; + case RIGHT_TO_LEFT: + return "Right-to-Left"; + case EUROPEAN_NUMBER: + return "European Number"; + case EUROPEAN_NUMBER_SEPARATOR: + return "European Number Separator"; + case EUROPEAN_NUMBER_TERMINATOR: + return "European Number Terminator"; + case ARABIC_NUMBER: + return "Arabic Number"; + case COMMON_NUMBER_SEPARATOR: + return "Common Number Separator"; + case BLOCK_SEPARATOR: + return "Paragraph Separator"; + case SEGMENT_SEPARATOR: + return "Segment Separator"; + case WHITE_SPACE_NEUTRAL: + return "Whitespace"; + case OTHER_NEUTRAL: + return "Other Neutrals"; + case LEFT_TO_RIGHT_EMBEDDING: + return "Left-to-Right Embedding"; + case LEFT_TO_RIGHT_OVERRIDE: + return "Left-to-Right Override"; + case RIGHT_TO_LEFT_ARABIC: + return "Right-to-Left Arabic"; + case RIGHT_TO_LEFT_EMBEDDING: + return "Right-to-Left Embedding"; + case RIGHT_TO_LEFT_OVERRIDE: + return "Right-to-Left Override"; + case POP_DIRECTIONAL_FORMAT: + return "Pop Directional Format"; + case DIR_NON_SPACING_MARK: + return "Non-Spacing Mark"; + case BOUNDARY_NEUTRAL: + return "Boundary Neutral"; + } + return "Unassigned"; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/lang/UCharacterEnums.java b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterEnums.java new file mode 100755 index 00000000..dd09e6f6 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/lang/UCharacterEnums.java @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/** + ******************************************************************************* + * Copyright (C) 2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/lang/UCharacterEnums.java +// - move from package com.ibm.icu.lang to package sun.net.idn +// +// 2011-09-06 Kurchi Subhra Hazra +// - Added @Deprecated tag to the following: +// - class UCharacterEnums +// - interfaces ECharacterCategory, ECharacterDirection +// - fields INITIAL_QUOTE_PUNCTUATION, FINAL_QUOTE_PUNCTUATION, +// DIRECTIONALITY_LEFT_TO_RIGHT, DIRECTIONALITY_RIGHT_TO_LEFT, +// DIRECTIONALITY_EUROPEAN_NUMBER, DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR +// DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR, DIRECTIONALITY_ARABIC_NUMBER, +// DIRECTIONALITY_COMMON_NUMBER_SEPARATOR, DIRECTIONALITY_PARAGRAPH_SEPARATOR, +// DIRECTIONALITY_SEGMENT_SEPARATOR, DIRECTIONALITY_WHITESPACE, +// DIRECTIONALITY_OTHER_NEUTRALS, DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING, +// DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE, DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC, +// DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING, DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE, +// DIRECTIONALITY_POP_DIRECTIONAL_FORMAT, DIRECTIONALITY_NON_SPACING_MARK, +// DIRECTIONALITY_BOUNDARY_NEUTRAL, DIRECTIONALITY_UNDEFINED +// + +package jdk_internal.bidi.icu.lang; + +/** + * A container for the different 'enumerated types' used by UCharacter. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + +@Deprecated +class UCharacterEnums { + + /** This is just a namespace, it is not instantiatable. */ + private UCharacterEnums() { + }; + + /** + * 'Enum' for the CharacterCategory constants. These constants are compatible in + * name but not in value with those defined in + * java.lang.Character. + * + * @see UCharacterCategory + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static interface ECharacterCategory { + /** + * Unassigned character type + * + * @stable ICU 2.1 + */ + public static final int UNASSIGNED = 0; + + /** + * Character type Cn Not Assigned (no characters in [UnicodeData.txt] have this + * property) + * + * @stable ICU 2.6 + */ + public static final int GENERAL_OTHER_TYPES = 0; + + /** + * Character type Lu + * + * @stable ICU 2.1 + */ + public static final int UPPERCASE_LETTER = 1; + + /** + * Character type Ll + * + * @stable ICU 2.1 + */ + public static final int LOWERCASE_LETTER = 2; + + /** + * Character type Lt + * + * @stable ICU 2.1 + */ + + public static final int TITLECASE_LETTER = 3; + + /** + * Character type Lm + * + * @stable ICU 2.1 + */ + public static final int MODIFIER_LETTER = 4; + + /** + * Character type Lo + * + * @stable ICU 2.1 + */ + public static final int OTHER_LETTER = 5; + + /** + * Character type Mn + * + * @stable ICU 2.1 + */ + public static final int NON_SPACING_MARK = 6; + + /** + * Character type Me + * + * @stable ICU 2.1 + */ + public static final int ENCLOSING_MARK = 7; + + /** + * Character type Mc + * + * @stable ICU 2.1 + */ + public static final int COMBINING_SPACING_MARK = 8; + + /** + * Character type Nd + * + * @stable ICU 2.1 + */ + public static final int DECIMAL_DIGIT_NUMBER = 9; + + /** + * Character type Nl + * + * @stable ICU 2.1 + */ + public static final int LETTER_NUMBER = 10; + + /** + * Character type No + * + * @stable ICU 2.1 + */ + public static final int OTHER_NUMBER = 11; + + /** + * Character type Zs + * + * @stable ICU 2.1 + */ + public static final int SPACE_SEPARATOR = 12; + + /** + * Character type Zl + * + * @stable ICU 2.1 + */ + public static final int LINE_SEPARATOR = 13; + + /** + * Character type Zp + * + * @stable ICU 2.1 + */ + public static final int PARAGRAPH_SEPARATOR = 14; + + /** + * Character type Cc + * + * @stable ICU 2.1 + */ + public static final int CONTROL = 15; + + /** + * Character type Cf + * + * @stable ICU 2.1 + */ + public static final int FORMAT = 16; + + /** + * Character type Co + * + * @stable ICU 2.1 + */ + public static final int PRIVATE_USE = 17; + + /** + * Character type Cs + * + * @stable ICU 2.1 + */ + public static final int SURROGATE = 18; + + /** + * Character type Pd + * + * @stable ICU 2.1 + */ + public static final int DASH_PUNCTUATION = 19; + + /** + * Character type Ps + * + * @stable ICU 2.1 + */ + public static final int START_PUNCTUATION = 20; + + /** + * Character type Pe + * + * @stable ICU 2.1 + */ + public static final int END_PUNCTUATION = 21; + + /** + * Character type Pc + * + * @stable ICU 2.1 + */ + public static final int CONNECTOR_PUNCTUATION = 22; + + /** + * Character type Po + * + * @stable ICU 2.1 + */ + public static final int OTHER_PUNCTUATION = 23; + + /** + * Character type Sm + * + * @stable ICU 2.1 + */ + public static final int MATH_SYMBOL = 24; + + /** + * Character type Sc + * + * @stable ICU 2.1 + */ + public static final int CURRENCY_SYMBOL = 25; + + /** + * Character type Sk + * + * @stable ICU 2.1 + */ + public static final int MODIFIER_SYMBOL = 26; + + /** + * Character type So + * + * @stable ICU 2.1 + */ + public static final int OTHER_SYMBOL = 27; + + /** + * Character type Pi + * + * @see #INITIAL_QUOTE_PUNCTUATION + * @stable ICU 2.1 + */ + public static final int INITIAL_PUNCTUATION = 28; + + /** + * Character type Pi This name is compatible with java.lang.Character's name for + * this type. + * + * @see #INITIAL_PUNCTUATION + * @draft ICU 2.8 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final int INITIAL_QUOTE_PUNCTUATION = 28; + + /** + * Character type Pf + * + * @see #FINAL_QUOTE_PUNCTUATION + * @stable ICU 2.1 + */ + public static final int FINAL_PUNCTUATION = 29; + + /** + * Character type Pf This name is compatible with java.lang.Character's name for + * this type. + * + * @see #FINAL_PUNCTUATION + * @draft ICU 2.8 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final int FINAL_QUOTE_PUNCTUATION = 29; + + /** + * Character type count + * + * @stable ICU 2.1 + */ + public static final int CHAR_CATEGORY_COUNT = 30; + } + + /** + * 'Enum' for the CharacterDirection constants. There are two sets of names, + * those used in ICU, and those used in the JDK. The JDK constants are + * compatible in name but not in value with those defined in + * java.lang.Character. + * + * @see UCharacterDirection + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + + @Deprecated + public static interface ECharacterDirection { + /** + * Directional type L + * + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT = 0; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = (byte) LEFT_TO_RIGHT; + + /** + * Directional type R + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT = 1; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = (byte) RIGHT_TO_LEFT; + + /** + * Directional type EN + * + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER = 2; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = (byte) EUROPEAN_NUMBER; + + /** + * Directional type ES + * + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER_SEPARATOR = 3; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = (byte) EUROPEAN_NUMBER_SEPARATOR; + + /** + * Directional type ET + * + * @stable ICU 2.1 + */ + public static final int EUROPEAN_NUMBER_TERMINATOR = 4; + + /** + * JDK-compatible synonum for EUROPEAN_NUMBER_TERMINATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = (byte) EUROPEAN_NUMBER_TERMINATOR; + + /** + * Directional type AN + * + * @stable ICU 2.1 + */ + public static final int ARABIC_NUMBER = 5; + + /** + * JDK-compatible synonum for ARABIC_NUMBER. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_ARABIC_NUMBER = (byte) ARABIC_NUMBER; + + /** + * Directional type CS + * + * @stable ICU 2.1 + */ + public static final int COMMON_NUMBER_SEPARATOR = 6; + + /** + * JDK-compatible synonum for COMMON_NUMBER_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = (byte) COMMON_NUMBER_SEPARATOR; + + /** + * Directional type B + * + * @stable ICU 2.1 + */ + public static final int BLOCK_SEPARATOR = 7; + + /** + * JDK-compatible synonum for BLOCK_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = (byte) BLOCK_SEPARATOR; + + /** + * Directional type S + * + * @stable ICU 2.1 + */ + public static final int SEGMENT_SEPARATOR = 8; + + /** + * JDK-compatible synonum for SEGMENT_SEPARATOR. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = (byte) SEGMENT_SEPARATOR; + + /** + * Directional type WS + * + * @stable ICU 2.1 + */ + public static final int WHITE_SPACE_NEUTRAL = 9; + + /** + * JDK-compatible synonum for WHITE_SPACE_NEUTRAL. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_WHITESPACE = (byte) WHITE_SPACE_NEUTRAL; + + /** + * Directional type ON + * + * @stable ICU 2.1 + */ + public static final int OTHER_NEUTRAL = 10; + + /** + * JDK-compatible synonum for OTHER_NEUTRAL. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = (byte) OTHER_NEUTRAL; + + /** + * Directional type LRE + * + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT_EMBEDDING = 11; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT_EMBEDDING. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = (byte) LEFT_TO_RIGHT_EMBEDDING; + + /** + * Directional type LRO + * + * @stable ICU 2.1 + */ + public static final int LEFT_TO_RIGHT_OVERRIDE = 12; + + /** + * JDK-compatible synonum for LEFT_TO_RIGHT_OVERRIDE. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = (byte) LEFT_TO_RIGHT_OVERRIDE; + + /** + * Directional type AL + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_ARABIC = 13; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_ARABIC. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = (byte) RIGHT_TO_LEFT_ARABIC; + + /** + * Directional type RLE + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_EMBEDDING = 14; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_EMBEDDING. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = (byte) RIGHT_TO_LEFT_EMBEDDING; + + /** + * Directional type RLO + * + * @stable ICU 2.1 + */ + public static final int RIGHT_TO_LEFT_OVERRIDE = 15; + + /** + * JDK-compatible synonum for RIGHT_TO_LEFT_OVERRIDE. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = (byte) RIGHT_TO_LEFT_OVERRIDE; + + /** + * Directional type PDF + * + * @stable ICU 2.1 + */ + public static final int POP_DIRECTIONAL_FORMAT = 16; + + /** + * JDK-compatible synonum for POP_DIRECTIONAL_FORMAT. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = (byte) POP_DIRECTIONAL_FORMAT; + + /** + * Directional type NSM + * + * @stable ICU 2.1 + */ + public static final int DIR_NON_SPACING_MARK = 17; + + /** + * JDK-compatible synonum for DIR_NON_SPACING_MARK. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_NON_SPACING_MARK = (byte) DIR_NON_SPACING_MARK; + + /** + * Directional type BN + * + * @stable ICU 2.1 + */ + public static final int BOUNDARY_NEUTRAL = 18; + + /** + * JDK-compatible synonum for BOUNDARY_NEUTRAL. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = (byte) BOUNDARY_NEUTRAL; + + /** + * Number of directional types + * + * @stable ICU 2.1 + */ + public static final int CHAR_DIRECTION_COUNT = 19; + + /** + * Undefined bidirectional character type. Undefined char values + * have undefined directionality in the Unicode specification. + * + * @draft ICU 3.0 + * @deprecated This is a draft API and might change in a future release of ICU. + */ + @Deprecated + public static final byte DIRECTIONALITY_UNDEFINED = -1; + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiBase.java b/src/main/java/jdk_internal/bidi/icu/text/BidiBase.java new file mode 100755 index 00000000..ce33152a --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiBase.java @@ -0,0 +1,4729 @@ +/* + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ + +/* FOOD FOR THOUGHT: currently the reordering modes are a mixture of + * algorithm for direct BiDi, algorithm for inverse Bidi and the bizarre + * concept of RUNS_ONLY which is a double operation. + * It could be advantageous to divide this into 3 concepts: + * a) Operation: direct / inverse / RUNS_ONLY + * b) Direct algorithm: default / NUMBERS_SPECIAL / GROUP_NUMBERS_WITH_L + * c) Inverse algorithm: default / INVERSE_LIKE_DIRECT / NUMBERS_SPECIAL + * This would allow combinations not possible today like RUNS_ONLY with + * NUMBERS_SPECIAL. + * Also allow to set INSERT_MARKS for the direct step of RUNS_ONLY and + * REMOVE_CONTROLS for the inverse step. + * Not all combinations would be supported, and probably not all do make sense. + * This would need to document which ones are supported and what are the + * fallbacks for unsupported combinations. + */ + +package jdk_internal.bidi.icu.text; + +import java.lang.reflect.Array; +import java.util.Arrays; + +import jdk_internal.bidi.AttributedCharacterIterator; +import jdk_internal.bidi.Bidi; +import jdk_internal.bidi.NumericShaper; +import jdk_internal.bidi.TextAttribute; +import jdk_internal.bidi.icu.impl.UBiDiProps; +import jdk_internal.bidi.icu.lang.UCharacter; + +/** + * + *

Bidi algorithm for ICU

+ * + * This is an implementation of the Unicode Bidirectional Algorithm. The + * algorithm is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm. + *

+ * + * Note: Libraries that perform a bidirectional algorithm and reorder strings + * accordingly are sometimes called "Storage Layout Engines". ICU's Bidi and + * shaping (ArabicShaping) classes can be used at the core of such "Storage + * Layout Engines". + * + *

General remarks about the API:

+ * + * The "limit" of a sequence of characters is the position just after their last + * character, i.e., one more than that position. + *

+ * + * Some of the API methods provide access to "runs". Such a "run" is defined as + * a sequence of characters that are at the same embedding level after + * performing the Bidi algorithm. + * + *

Basic concept: paragraph

A piece of text can be divided into several + * paragraphs by characters with the Bidi class Block Separator. + * For handling of paragraphs, see: + *
    + *
  • {@link #countParagraphs} + *
  • {@link #getParaLevel} + *
  • {@link #getParagraph} + *
  • {@link #getParagraphByIndex} + *
+ * + *

Basic concept: text direction

The direction of a piece of text may + * be: + *
    + *
  • {@link #LTR} + *
  • {@link #RTL} + *
  • {@link #MIXED} + *
  • {@link #NEUTRAL} + *
+ * + *

Basic concept: levels

+ * + * Levels in this API represent embedding levels according to the Unicode + * Bidirectional Algorithm. Their low-order bit (even/odd value) indicates the + * visual direction. + *

+ * + * Levels can be abstract values when used for the paraLevel and + * embeddingLevels arguments of setPara(); there: + *

    + *
  • the high-order bit of an embeddingLevels[] value indicates + * whether the using application is specifying the level of a character to + * override whatever the Bidi implementation would resolve it to.
  • + *
  • paraLevel can be set to the pseudo-level values + * LEVEL_DEFAULT_LTR and LEVEL_DEFAULT_RTL.
  • + *
+ * + *

+ * The related constants are not real, valid level values. + * DEFAULT_XXX can be used to specify a default for the paragraph + * level for when the setPara() method shall determine it but there + * is no strongly typed character in the input. + *

+ * + * Note that the value for LEVEL_DEFAULT_LTR is even and the one + * for LEVEL_DEFAULT_RTL is odd, just like with normal LTR and RTL + * level values - these special values are designed that way. Also, the + * implementation assumes that MAX_EXPLICIT_LEVEL is odd. + * + *

+ * See Also: + *

    + *
  • {@link #LEVEL_DEFAULT_LTR} + *
  • {@link #LEVEL_DEFAULT_RTL} + *
  • {@link #LEVEL_OVERRIDE} + *
  • {@link #MAX_EXPLICIT_LEVEL} + *
  • {@link #setPara} + *
+ * + *

Basic concept: Reordering Mode

Reordering mode values indicate which + * variant of the Bidi algorithm to use. + * + *

+ * See Also: + *

    + *
  • {@link #setReorderingMode} + *
  • {@link #REORDER_DEFAULT} + *
  • {@link #REORDER_NUMBERS_SPECIAL} + *
  • {@link #REORDER_GROUP_NUMBERS_WITH_R} + *
  • {@link #REORDER_RUNS_ONLY} + *
  • {@link #REORDER_INVERSE_NUMBERS_AS_L} + *
  • {@link #REORDER_INVERSE_LIKE_DIRECT} + *
  • {@link #REORDER_INVERSE_FOR_NUMBERS_SPECIAL} + *
+ * + *

Basic concept: Reordering Options

Reordering options can be applied + * during Bidi text transformations. + * + *

+ * See Also: + *

    + *
  • {@link #setReorderingOptions} + *
  • {@link #OPTION_DEFAULT} + *
  • {@link #OPTION_INSERT_MARKS} + *
  • {@link #OPTION_REMOVE_CONTROLS} + *
  • {@link #OPTION_STREAMING} + *
+ * + * + * @author Simon Montagu, Matitiahu Allouche (ported from C code written by + * Markus W. Scherer) + * @stable ICU 3.8 + * + * + *

Sample code for the ICU Bidi API

+ * + *
Rendering a paragraph with the ICU Bidi API
+ * + * This is (hypothetical) sample code that illustrates how the ICU Bidi + * API could be used to render a paragraph of text. Rendering code + * depends highly on the graphics system, therefore this sample code + * must make a lot of assumptions, which may or may not match any + * existing graphics system's properties. + * + *

+ * The basic assumptions are: + *

+ *
    + *
  • Rendering is done from left to right on a horizontal line.
  • + *
  • A run of single-style, unidirectional text can be rendered at + * once.
  • + *
  • Such a run of text is passed to the graphics system with + * characters (code units) in logical order.
  • + *
  • The line-breaking algorithm is very complicated and + * Locale-dependent - and therefore its implementation omitted from this + * sample code.
  • + *
+ * + *
{@code
+ *
+ *  package com.ibm.icu.dev.test.bidi;
+ *
+ *  import com.ibm.icu.text.Bidi;
+ *  import com.ibm.icu.text.BidiRun;
+ *
+ *  public class Sample {
+ *
+ *      static final int styleNormal = 0;
+ *      static final int styleSelected = 1;
+ *      static final int styleBold = 2;
+ *      static final int styleItalics = 4;
+ *      static final int styleSuper=8;
+ *      static final int styleSub = 16;
+ *
+ *      static class StyleRun {
+ *          int limit;
+ *          int style;
+ *
+ *          public StyleRun(int limit, int style) {
+ *              this.limit = limit;
+ *              this.style = style;
+ *         }
+ *         }
+ *
+ *         static class Bounds {
+ *         int start;
+ *         int limit;
+ *
+ *         public Bounds(int start, int limit) {
+ *         this.start = start;
+ *         this.limit = limit;
+ *         }
+ *         }
+ *
+ *         static int getTextWidth(String text, int start, int limit, StyleRun[] styleRuns, int styleRunCount) {
+ *         // simplistic way to compute the width
+ *         return limit - start;
+ *         }
+ *
+ *         // set limit and StyleRun limit for a line
+ *         	// from text[start] and from styleRuns[styleRunStart]
+ *         	// using Bidi.getLogicalRun(...)
+ *         	// returns line width
+ *         static int getLineBreak(String text, Bounds line, Bidi para, StyleRun styleRuns[], Bounds styleRun) {
+ *         // dummy return
+ *         return 0;
+ *         }
+ *
+ *         // render runs on a line sequentially, always from left to right
+ *
+ *         // prepare rendering a new line
+ *         static void startLine(byte textDirection, int lineWidth) {
+ *         System.out.println();
+ *         }
+ *
+ *         // render a run of text and advance to the right by the run width
+ *         	// the text[start..limit-1] is always in logical order
+ *         static void renderRun(String text, int start, int limit, byte textDirection, int style) {
+ *         }
+ *
+ *         // We could compute a cross-product
+ *         	// from the style runs with the directional runs
+ *         	// and then reorder it.
+ *         	// Instead, here we iterate over each run type
+ *         	// and render the intersections -
+ *         	// with shortcuts in simple (and common) cases.
+ *         	// renderParagraph() is the main function.
+ *
+ *         // render a directional run with
+ *         	// (possibly) multiple style runs intersecting with it
+ *         static void renderDirectionalRun(String text, int start, int limit, byte direction, StyleRun styleRuns[],
+ *         int styleRunCount) {
+ *         int i;
+ *
+ *         // iterate over style runs
+ *         if (direction == Bidi.LTR) {
+ *         int styleLimit;
+ *         for (i = 0; i < styleRunCount; ++i) {
+ *         styleLimit = styleRuns[i].limit;
+ *         if (start < styleLimit) {
+ *         if (styleLimit > limit) {
+ *         styleLimit = limit;
+ *         }
+ *         renderRun(text, start, styleLimit, direction, styleRuns[i].style);
+ *         if (styleLimit == limit) {
+ *         break;
+ *         }
+ *         start = styleLimit;
+ *         }
+ *         }
+ *         } else {
+ *         int styleStart;
+ *
+ *         for (i = styleRunCount - 1; i >= 0; --i) {
+ *         if (i > 0) {
+ *         styleStart = styleRuns[i - 1].limit;
+ *         } else {
+ *         styleStart = 0;
+ *         }
+ *         if (limit >= styleStart) {
+ *         if (styleStart < start) {
+ *         styleStart = start;
+ *         }
+ *         renderRun(text, styleStart, limit, direction, styleRuns[i].style);
+ *         if (styleStart == start) {
+ *         break;
+ *         }
+ *         limit = styleStart;
+ *         }
+ *         }
+ *         }
+ *         }
+ *
+ *         // the line object represents text[start..limit-1]
+ *         static void renderLine(Bidi line, String text, int start, int limit, StyleRun styleRuns[], int styleRunCount) {
+ *         byte direction = line.getDirection();
+ *         if (direction != Bidi.MIXED) {
+ *         // unidirectional
+ *         if (styleRunCount <= 1) {
+ *         renderRun(text, start, limit, direction, styleRuns[0].style);
+ *         } else {
+ *         renderDirectionalRun(text, start, limit, direction, styleRuns, styleRunCount);
+ *         }
+ *         } else {
+ *         // mixed-directional
+ *         int count, i;
+ *         BidiRun run;
+ *
+ *         try {
+ *         count = line.countRuns();
+ *         } catch (IllegalStateException e) {
+ *         e.printStackTrace();
+ *         return;
+ *         }
+ *         if (styleRunCount <= 1) {
+ *         int style = styleRuns[0].style;
+ *
+ *         // iterate over directional runs
+ *         for (i = 0; i < count; ++i) {
+ *         run = line.getVisualRun(i);
+ *         renderRun(text, run.getStart(), run.getLimit(), run.getDirection(), style);
+ *         }
+ *         } else {
+ *         // iterate over both directional and style runs
+ *         for (i = 0; i < count; ++i) {
+ *         run = line.getVisualRun(i);
+ *         renderDirectionalRun(text, run.getStart(), run.getLimit(), run.getDirection(), styleRuns,
+ *         styleRunCount);
+ *         }
+ *         }
+ *         }
+ *         }
+ *
+ *         static void renderParagraph(String text, byte textDirection, StyleRun styleRuns[], int styleRunCount,
+ *         int lineWidth) {
+ *         int length = text.length();
+ *         Bidi para = new Bidi();
+ *         try {
+ *         para.setPara(text, textDirection != 0 ? Bidi.LEVEL_DEFAULT_RTL : Bidi.LEVEL_DEFAULT_LTR, null);
+ *         } catch (Exception e) {
+ *         e.printStackTrace();
+ *         return;
+ *         }
+ *         byte paraLevel = (byte) (1 & para.getParaLevel());
+ *         StyleRun styleRun = new StyleRun(length, styleNormal);
+ *
+ *         if (styleRuns == null || styleRunCount <= 0) {
+ *         styleRuns = new StyleRun[1];
+ *         styleRunCount = 1;
+ *         styleRuns[0] = styleRun;
+ *         }
+ *         // assume styleRuns[styleRunCount-1].limit>=length
+ *
+ *         int width = getTextWidth(text, 0, length, styleRuns, styleRunCount);
+ *         if (width <= lineWidth) {
+ *         // everything fits onto one line
+ *
+ *         // prepare rendering a new line from either left or right
+ *         startLine(paraLevel, width);
+ *
+ *         renderLine(para, text, 0, length, styleRuns, styleRunCount);
+ *         } else {
+ *         // we need to render several lines
+ *         Bidi line = new Bidi(length, 0);
+ *         int start = 0, limit;
+ *         int styleRunStart = 0, styleRunLimit;
+ *
+ *         for (;;) {
+ *         limit = length;
+ *         styleRunLimit = styleRunCount;
+ *         width = getLineBreak(text, new Bounds(start, limit), para, styleRuns,
+ *         new Bounds(styleRunStart, styleRunLimit));
+ *         try {
+ *         line = para.setLine(start, limit);
+ *         } catch (Exception e) {
+ *         e.printStackTrace();
+ *         return;
+ *         }
+ *         // prepare rendering a new line
+ *         				// from either left or right
+ *         startLine(paraLevel, width);
+ *
+ *         if (styleRunStart > 0) {
+ *         int newRunCount = styleRuns.length - styleRunStart;
+ *         StyleRun[] newRuns = new StyleRun[newRunCount];
+ *         System.arraycopy(styleRuns, styleRunStart, newRuns, 0, newRunCount);
+ *         renderLine(line, text, start, limit, newRuns, styleRunLimit - styleRunStart);
+ *         } else {
+ *         renderLine(line, text, start, limit, styleRuns, styleRunLimit - styleRunStart);
+ *         }
+ *         if (limit == length) {
+ *         break;
+ *         }
+ *         start = limit;
+ *         styleRunStart = styleRunLimit - 1;
+ *         if (start >= styleRuns[styleRunStart].limit) {
+ *         ++styleRunStart;
+ *         }
+ *         }
+ *         }
+ *         }
+ *
+ *         public static void main(String[] args) {
+ *         renderParagraph("Some Latin text...", Bidi.LTR, null, 0, 80);
+ *         renderParagraph("Some Hebrew text...", Bidi.RTL, null, 0, 60);
+ *         }
+ *         }
+ *
+ * }
+ */ + +/* + * General implementation notes: + * + * Throughout the implementation, there are comments like (W2) that refer to + * rules of the BiDi algorithm, in this example to the second rule of the + * resolution of weak types. + * + * For handling surrogate pairs, where two UChar's form one "abstract" (or + * UTF-32) character according to UTF-16, the second UChar gets the directional + * property of the entire character assigned, while the first one gets a BN, a + * boundary neutral, type, which is ignored by most of the algorithm according + * to rule (X9) and the implementation suggestions of the BiDi algorithm. + * + * Later, adjustWSLevels() will set the level for each BN to that of the + * following character (UChar), which results in surrogate pairs getting the + * same level on each of their surrogates. + * + * In a UTF-8 implementation, the same thing could be done: the last byte of a + * multi-byte sequence would get the "real" property, while all previous bytes + * of that sequence would get BN. + * + * It is not possible to assign all those parts of a character the same real + * property because this would fail in the resolution of weak types with rules + * that look at immediately surrounding types. + * + * As a related topic, this implementation does not remove Boundary Neutral + * types from the input, but ignores them wherever this is relevant. For + * example, the loop for the resolution of the weak types reads types until it + * finds a non-BN. Also, explicit embedding codes are neither changed into BN + * nor removed. They are only treated the same way real BNs are. As stated + * before, adjustWSLevels() takes care of them at the end. For the purpose of + * conformance, the levels of all these codes do not matter. + * + * Note that this implementation modifies the dirProps after the initial setup, + * when applying X5c (replace FSI by LRI or RLI), X6, N0 (replace paired + * brackets by L or R). + * + * In this implementation, the resolution of weak types (W1 to W6), neutrals (N1 + * and N2), and the assignment of the resolved level (In) are all done in one + * single loop, in resolveImplicitLevels(). Changes of dirProp values are done + * on the fly, without writing them back to the dirProps array. + * + * + * This implementation contains code that allows to bypass steps of the + * algorithm that are not needed on the specific paragraph in order to speed up + * the most common cases considerably, like text that is entirely LTR, or RTL + * text without numbers. + * + * Most of this is done by setting a bit for each directional property in a + * flags variable and later checking for whether there are any LTR characters or + * any RTL characters, or both, whether there are any explicit embedding codes, + * etc. + * + * If the (Xn) steps are performed, then the flags are re-evaluated, because + * they will then not contain the embedding codes any more and will be adjusted + * for override codes, so that subsequently more bypassing may be possible than + * what the initial flags suggested. + * + * If the text is not mixed-directional, then the algorithm steps for the weak + * type resolution are not performed, and all levels are set to the paragraph + * level. + * + * If there are no explicit embedding codes, then the (Xn) steps are not + * performed. + * + * If embedding levels are supplied as a parameter, then all explicit embedding + * codes are ignored, and the (Xn) steps are not performed. + * + * White Space types could get the level of the run they belong to, and are + * checked with a test of (flags&MASK_EMBEDDING) to consider if the paragraph + * direction should be considered in the flags variable. + * + * If there are no White Space types in the paragraph, then (L1) is not + * necessary in adjustWSLevels(). + */ + +// Original filename in ICU4J: Bidi.java +public class BidiBase { + + static class Point { + int pos; /* position in text */ + int flag; /* flag for LRM/RLM, before/after */ + } + + static class InsertPoints { + int size; + int confirmed; + Point[] points = new Point[0]; + } + + static class Opening { + int position; /* position of opening bracket */ + int match; /* matching char or -position of closing bracket */ + int contextPos; /* position of last strong char found before opening */ + short flags; /* bits for L or R/AL found within the pair */ + byte contextDir; /* L or R according to last strong char before opening */ + } + + static class IsoRun { + int contextPos; /* position of char determining context */ + short start; /* index of first opening entry for this run */ + short limit; /* index after last opening entry for this run */ + byte level; /* level of this run */ + byte lastStrong; /* bidi class of last strong char found in this run */ + byte lastBase; /* bidi class of last base char found in this run */ + byte contextDir; /* L or R to use as context for following openings */ + } + + static class BracketData { + Opening[] openings = new Opening[SIMPLE_PARAS_COUNT]; + int isoRunLast; /* index of last used entry */ + /* + * array of nested isolated sequence entries; can never excess + * UBIDI_MAX_EXPLICIT_LEVEL + 1 for index 0, + 1 for before the first isolated + * sequence + */ + IsoRun[] isoRuns = new IsoRun[MAX_EXPLICIT_LEVEL + 2]; + boolean isNumbersSpecial; /* reordering mode for NUMBERS_SPECIAL */ + } + + static class Isolate { + int startON; + int start1; + short stateImp; + short state; + } + + /** + * Paragraph level setting + *

+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, then set the + * paragraph level to 0 (left-to-right). + *

+ * + * If this value is used in conjunction with reordering modes + * REORDER_INVERSE_LIKE_DIRECT or + * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder is + * assumed to be visual LTR, and the text after reordering is required to be the + * corresponding logical string with appropriate contextual direction. The + * direction of the result string will be RTL if either the rightmost or + * leftmost strong character of the source text is RTL or Arabic Letter, the + * direction will be LTR otherwise. + *

+ * + * If reordering option OPTION_INSERT_MARKS is set, an RLM may be + * added at the beginning of the result string to ensure round trip (that the + * result string, when reordered back to visual, will produce the original + * source text). + * + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + public static final byte LEVEL_DEFAULT_LTR = (byte) 0x7e; + + /** + * Paragraph level setting + *

+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, then set the + * paragraph level to 1 (right-to-left). + *

+ * + * If this value is used in conjunction with reordering modes + * REORDER_INVERSE_LIKE_DIRECT or + * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder is + * assumed to be visual LTR, and the text after reordering is required to be the + * corresponding logical string with appropriate contextual direction. The + * direction of the result string will be RTL if either the rightmost or + * leftmost strong character of the source text is RTL or Arabic Letter, or if + * the text contains no strong character; the direction will be LTR otherwise. + *

+ * + * If reordering option OPTION_INSERT_MARKS is set, an RLM may be + * added at the beginning of the result string to ensure round trip (that the + * result string, when reordered back to visual, will produce the original + * source text). + * + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + public static final byte LEVEL_DEFAULT_RTL = (byte) 0x7f; + + /** + * Maximum explicit embedding level. (The maximum resolved level can be up to + * MAX_EXPLICIT_LEVEL+1). + * + * @stable ICU 3.8 + */ + public static final byte MAX_EXPLICIT_LEVEL = 125; + + /** + * Bit flag for level input. Overrides directional properties. + * + * @stable ICU 3.8 + */ + public static final byte LEVEL_OVERRIDE = (byte) 0x80; + + /** + * Special value which can be returned by the mapping methods when a logical + * index has no corresponding visual index or vice-versa. This may happen for + * the logical-to-visual mapping of a Bidi control when option + * OPTION_REMOVE_CONTROLS is specified. This can also happen for + * the visual-to-logical mapping of a Bidi mark (LRM or RLM) inserted by option + * OPTION_INSERT_MARKS. + * + * @see #getVisualIndex + * @see #getVisualMap + * @see #getLogicalIndex + * @see #getLogicalMap + * @see #OPTION_INSERT_MARKS + * @see #OPTION_REMOVE_CONTROLS + * @stable ICU 3.8 + */ + public static final int MAP_NOWHERE = -1; + + /** + * Left-to-right text. + *

    + *
  • As return value for getDirection(), it means that the source + * string contains no right-to-left characters, or that the source string is + * empty and the paragraph level is even. + *
  • As return value for getBaseDirection(), it means that the + * first strong character of the source string has a left-to-right direction. + *
+ * + * @stable ICU 3.8 + */ + public static final byte LTR = 0; + + /** + * Right-to-left text. + *
    + *
  • As return value for getDirection(), it means that the source + * string contains no left-to-right characters, or that the source string is + * empty and the paragraph level is odd. + *
  • As return value for getBaseDirection(), it means that the + * first strong character of the source string has a right-to-left direction. + *
+ * + * @stable ICU 3.8 + */ + public static final byte RTL = 1; + + /** + * Mixed-directional text. + *

+ * As return value for getDirection(), it means that the source + * string contains both left-to-right and right-to-left characters. + * + * @stable ICU 3.8 + */ + public static final byte MIXED = 2; + + /** + * option bit for writeReordered(): keep combining characters after their base + * characters in RTL runs + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short KEEP_BASE_COMBINING = 1; + + /** + * option bit for writeReordered(): replace characters with the "mirrored" + * property in RTL runs by their mirror-image mappings + * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short DO_MIRRORING = 2; + + /** + * option bit for writeReordered(): surround the run with LRMs if necessary; + * this is part of the approximate "inverse Bidi" algorithm + * + *

+ * This option does not imply corresponding adjustment of the index mappings. + *

+ * + * @see #setInverse + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short INSERT_LRM_FOR_NUMERIC = 4; + + /** + * option bit for writeReordered(): remove Bidi control characters (this does + * not affect INSERT_LRM_FOR_NUMERIC) + * + *

+ * This option does not imply corresponding adjustment of the index mappings. + *

+ * + * @see #writeReordered + * @see #INSERT_LRM_FOR_NUMERIC + * @stable ICU 3.8 + */ + public static final short REMOVE_BIDI_CONTROLS = 8; + + /** + * option bit for writeReordered(): write the output in reverse order + * + *

+ * This has the same effect as calling writeReordered() first + * without this option, and then calling writeReverse() without + * mirroring. Doing this in the same step is faster and avoids a temporary + * buffer. An example for using this option is output to a character terminal + * that is designed for RTL scripts and stores text in reverse order. + *

+ * + * @see #writeReordered + * @stable ICU 3.8 + */ + public static final short OUTPUT_REVERSE = 16; + + /** + * Reordering mode: Regular Logical to Visual Bidi algorithm according to + * Unicode. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_DEFAULT = 0; + + /** + * Reordering mode: Logical to Visual algorithm which handles numbers in a way + * which mimicks the behavior of Windows XP. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_NUMBERS_SPECIAL = 1; + + /** + * Reordering mode: Logical to Visual algorithm grouping numbers with adjacent R + * characters (reversible algorithm). + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + private static final short REORDER_GROUP_NUMBERS_WITH_R = 2; + + /** + * Reordering mode: Reorder runs only to transform a Logical LTR string to the + * logical RTL string with the same display, or vice-versa.
+ * If this mode is set together with option OPTION_INSERT_MARKS, + * some Bidi controls in the source text may be removed and other controls may + * be added to produce the minimum combination which has the required display. + * + * @see #OPTION_INSERT_MARKS + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_RUNS_ONLY = 3; + + /** + * Reordering mode: Visual to Logical algorithm which handles numbers like L + * (same algorithm as selected by setInverse(true). + * + * @see #setInverse + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_NUMBERS_AS_L = 4; + + /** + * Reordering mode: Visual to Logical algorithm equivalent to the regular + * Logical to Visual algorithm. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_LIKE_DIRECT = 5; + + /** + * Reordering mode: Inverse Bidi (Visual to Logical) algorithm for the + * REORDER_NUMBERS_SPECIAL Bidi algorithm. + * + * @see #setReorderingMode + * @stable ICU 3.8 + */ + static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; + + /* + * Reordering mode values must be ordered so that all the regular logical to + * visual modes come first, and all inverse Bidi modes come last. + */ + private static final short REORDER_LAST_LOGICAL_TO_VISUAL = REORDER_NUMBERS_SPECIAL; + + /** + * Option bit for setReorderingOptions: insert Bidi marks (LRM or + * RLM) when needed to ensure correct result of a reordering to a Logical order + * + *

+ * This option must be set or reset before calling setPara. + *

+ * + *

+ * This option is significant only with reordering modes which generate a result + * with Logical order, specifically. + *

+ *
    + *
  • REORDER_RUNS_ONLY
  • + *
  • REORDER_INVERSE_NUMBERS_AS_L
  • + *
  • REORDER_INVERSE_LIKE_DIRECT
  • + *
  • REORDER_INVERSE_FOR_NUMBERS_SPECIAL
  • + *
+ * + *

+ * If this option is set in conjunction with reordering mode + * REORDER_INVERSE_NUMBERS_AS_L or with calling + * setInverse(true), it implies option + * INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered(). + *

+ * + *

+ * For other reordering modes, a minimum number of LRM or RLM characters will be + * added to the source text after reordering it so as to ensure round trip, i.e. + * when applying the inverse reordering mode on the resulting logical text with + * removal of Bidi marks (option OPTION_REMOVE_CONTROLS set before + * calling setPara() or option REMOVE_BIDI_CONTROLS in + * writeReordered), the result will be identical to the source text + * in the first transformation. + * + *

+ * This option will be ignored if specified together with option + * OPTION_REMOVE_CONTROLS. It inhibits option + * REMOVE_BIDI_CONTROLS in calls to method + * writeReordered() and it implies option + * INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered() if the reordering mode is + * REORDER_INVERSE_NUMBERS_AS_L. + *

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #INSERT_LRM_FOR_NUMERIC + * @see #REMOVE_BIDI_CONTROLS + * @see #OPTION_REMOVE_CONTROLS + * @see #REORDER_RUNS_ONLY + * @see #REORDER_INVERSE_NUMBERS_AS_L + * @see #REORDER_INVERSE_LIKE_DIRECT + * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL + * @stable ICU 3.8 + */ + static final int OPTION_INSERT_MARKS = 1; + + /** + * Option bit for setReorderingOptions: remove Bidi control + * characters + * + *

+ * This option must be set or reset before calling setPara. + *

+ * + *

+ * This option nullifies option OPTION_INSERT_MARKS. It inhibits + * option INSERT_LRM_FOR_NUMERIC in calls to method + * writeReordered() and it implies option + * REMOVE_BIDI_CONTROLS in calls to that method. + *

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #OPTION_INSERT_MARKS + * @see #INSERT_LRM_FOR_NUMERIC + * @see #REMOVE_BIDI_CONTROLS + * @stable ICU 3.8 + */ + static final int OPTION_REMOVE_CONTROLS = 2; + + /** + * Option bit for setReorderingOptions: process the output as part + * of a stream to be continued + * + *

+ * This option must be set or reset before calling setPara. + *

+ * + *

+ * This option specifies that the caller is interested in processing large text + * object in parts. The results of the successive calls are expected to be + * concatenated by the caller. Only the call for the last part will have this + * option bit off. + *

+ * + *

+ * When this option bit is on, setPara() may process less than the + * full source text in order to truncate the text at a meaningful boundary. The + * caller should call getProcessedLength() immediately after + * calling setPara() in order to determine how much of the source + * text has been processed. Source text beyond that length should be resubmitted + * in following calls to setPara. The processed length may be less + * than the length of the source text if a character preceding the last + * character of the source text constitutes a reasonable boundary (like a block + * separator) for text to be continued.
+ * If the last character of the source text constitutes a reasonable boundary, + * the whole text will be processed at once.
+ * If nowhere in the source text there exists such a reasonable boundary, the + * processed length will be zero.
+ * The caller should check for such an occurrence and do one of the following: + *

    + *
  • submit a larger amount of text with a better chance to include a + * reasonable boundary.
  • + *
  • resubmit the same text after turning off option + * OPTION_STREAMING.
  • + *
+ * In all cases, this option should be turned off before processing the last + * part of the text. + *

+ * + *

+ * When the OPTION_STREAMING option is used, it is recommended to + * call orderParagraphsLTR(true) before calling + * setPara() so that later paragraphs may be concatenated to + * previous paragraphs on the right. + *

+ * + * @see #setReorderingMode + * @see #setReorderingOptions + * @see #getProcessedLength + * @stable ICU 3.8 + */ + private static final int OPTION_STREAMING = 4; + + /* + * Comparing the description of the Bidi algorithm with this implementation is + * easier with the same names for the Bidi types in the code as there. See + * UCharacterDirection + */ + /* private */ static final byte L = 0; + private static final byte R = 1; + private static final byte EN = 2; + private static final byte ES = 3; + private static final byte ET = 4; + private static final byte AN = 5; + private static final byte CS = 6; + static final byte B = 7; + private static final byte S = 8; + private static final byte WS = 9; + private static final byte ON = 10; + private static final byte LRE = 11; + private static final byte LRO = 12; + private static final byte AL = 13; + private static final byte RLE = 14; + private static final byte RLO = 15; + private static final byte PDF = 16; + private static final byte NSM = 17; + private static final byte BN = 18; + private static final byte FSI = 19; + private static final byte LRI = 20; + private static final byte RLI = 21; + private static final byte PDI = 22; + private static final byte ENL = PDI + 1; /* EN after W7 */ + private static final byte ENR = ENL + 1; /* EN not subject to W7 */ + + // Number of directional types + private static final int CHAR_DIRECTION_COUNT = 23; + + /** + * Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). Used in + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm. Returns UCharacter.BidiPairedBracketType + * values. + * + * @stable ICU 52 + */ + public static final int BIDI_PAIRED_BRACKET_TYPE = 0x1015; + + /** + * Bidi Paired Bracket Type constants. + * + * @see UProperty#BIDI_PAIRED_BRACKET_TYPE + * @stable ICU 52 + */ + public static interface BidiPairedBracketType { + /** + * Not a paired bracket. + * + * @stable ICU 52 + */ + public static final int NONE = 0; + /** + * Open paired bracket. + * + * @stable ICU 52 + */ + public static final int OPEN = 1; + /** + * Close paired bracket. + * + * @stable ICU 52 + */ + public static final int CLOSE = 2; + /** + * @stable ICU 52 + */ + public static final int COUNT = 3; + } + + /* number of paras entries allocated initially */ + static final int SIMPLE_PARAS_COUNT = 10; + + private static final char CR = '\r'; + private static final char LF = '\n'; + + static final int LRM_BEFORE = 1; + static final int LRM_AFTER = 2; + static final int RLM_BEFORE = 4; + static final int RLM_AFTER = 8; + + /* flags for Opening.flags */ + static final byte FOUND_L = (byte) DirPropFlag(L); + static final byte FOUND_R = (byte) DirPropFlag(R); + + /* + * The following bit is used for the directional isolate status. Stack entries + * corresponding to isolate sequences are greater than ISOLATE. + */ + static final int ISOLATE = 0x0100; + + /* + * reference to parent paragraph object (reference to self if this object is a + * paragraph object); set to null in a newly opened object; set to a real value + * after a successful execution of setPara or setLine + */ + BidiBase paraBidi; + + final UBiDiProps bdp; + + /* character array representing the current text */ + char[] text; + + /* length of the current text */ + int originalLength; + + /* + * if the option OPTION_STREAMING is set, this is the length of text actually + * processed by setPara, which may be shorter than the original + * length. Otherwise, it is identical to the original length. + */ + public int length; + + /* + * if option OPTION_REMOVE_CONTROLS is set, and/or Bidi marks are allowed to be + * inserted in one of the reordering modes, the length of the result string may + * be different from the processed length. + */ + int resultLength; + + /* indicators for whether memory may be allocated after construction */ + boolean mayAllocateText; + boolean mayAllocateRuns; + + /* arrays with one value per text-character */ + byte[] dirPropsMemory = new byte[1]; + byte[] levelsMemory = new byte[1]; + byte[] dirProps; + byte[] levels; + + /* are we performing an approximation of the "inverse Bidi" algorithm? */ + boolean isInverse; + + /* are we using the basic algorithm or its variation? */ + int reorderingMode; + + /* bitmask for reordering options */ + int reorderingOptions; + + /* must block separators receive level 0? */ + boolean orderParagraphsLTR; + + /* the paragraph level */ + byte paraLevel; + + /* original paraLevel when contextual */ + /* must be one of DEFAULT_xxx or 0 if not contextual */ + byte defaultParaLevel; + + /* the following is set in setPara, used in processPropertySeq */ + + ImpTabPair impTabPair; /* reference to levels state table pair */ + + /* the overall paragraph or line directionality */ + byte direction; + + /* flags is a bit set for which directional properties are in the text */ + int flags; + + /* lastArabicPos is index to the last AL in the text, -1 if none */ + int lastArabicPos; + + /* characters after trailingWSStart are WS and are */ + /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */ + int trailingWSStart; + + /* fields for paragraph handling, set in getDirProps() */ + int paraCount; + int[] paras_limit = new int[SIMPLE_PARAS_COUNT]; + byte[] paras_level = new byte[SIMPLE_PARAS_COUNT]; + + /* fields for line reordering */ + int runCount; /* ==-1: runs not set up yet */ + BidiRun[] runsMemory = new BidiRun[0]; + BidiRun[] runs; + + /* for non-mixed text, we only need a tiny array of runs (no allocation) */ + BidiRun[] simpleRuns = { new BidiRun() }; + + /* fields for managing isolate sequences */ + Isolate[] isolates; + + /* maximum or current nesting depth of isolate sequences */ + /* + * Within resolveExplicitLevels() and checkExplicitLevels(), this is the maximal + * nesting encountered. Within resolveImplicitLevels(), this is the index of the + * current isolates stack entry. + */ + int isolateCount; + + /* mapping of runs in logical order to visual order */ + int[] logicalToVisualRunsMap; + /* flag to indicate that the map has been updated */ + boolean isGoodLogicalToVisualRunsMap; + + /* for inverse Bidi with insertion of directional marks */ + InsertPoints insertPoints = new InsertPoints(); + + /* for option OPTION_REMOVE_CONTROLS */ + int controlCount; + + /* + * Sometimes, bit values are more appropriate to deal with directionality + * properties. Abbreviations in these method names refer to names used in the + * Bidi algorithm. + */ + static int DirPropFlag(byte dir) { + return (1 << dir); + } + + boolean testDirPropFlagAt(int flag, int index) { + return ((DirPropFlag(dirProps[index]) & flag) != 0); + } + + static final int DirPropFlagMultiRuns = DirPropFlag((byte) 31); + + /* to avoid some conditional statements, use tiny constant arrays */ + static final int DirPropFlagLR[] = { DirPropFlag(L), DirPropFlag(R) }; + static final int DirPropFlagE[] = { DirPropFlag(LRE), DirPropFlag(RLE) }; + static final int DirPropFlagO[] = { DirPropFlag(LRO), DirPropFlag(RLO) }; + + static final int DirPropFlagLR(byte level) { + return DirPropFlagLR[level & 1]; + } + + static final int DirPropFlagE(byte level) { + return DirPropFlagE[level & 1]; + } + + static final int DirPropFlagO(byte level) { + return DirPropFlagO[level & 1]; + } + + static final byte DirFromStrong(byte strong) { + return strong == L ? L : R; + } + + static final byte NoOverride(byte level) { + return (byte) (level & ~LEVEL_OVERRIDE); + } + + /* are there any characters that are LTR or RTL? */ + static final int MASK_LTR = DirPropFlag(L) | DirPropFlag(EN) | DirPropFlag(ENL) | DirPropFlag(ENR) | DirPropFlag(AN) + | DirPropFlag(LRE) | DirPropFlag(LRO) | DirPropFlag(LRI); + static final int MASK_RTL = DirPropFlag(R) | DirPropFlag(AL) | DirPropFlag(RLE) | DirPropFlag(RLO) + | DirPropFlag(RLI); + + static final int MASK_R_AL = DirPropFlag(R) | DirPropFlag(AL); + + /* explicit embedding codes */ + private static final int MASK_EXPLICIT = DirPropFlag(LRE) | DirPropFlag(LRO) | DirPropFlag(RLE) | DirPropFlag(RLO) + | DirPropFlag(PDF); + private static final int MASK_BN_EXPLICIT = DirPropFlag(BN) | MASK_EXPLICIT; + + /* explicit isolate codes */ + private static final int MASK_ISO = DirPropFlag(LRI) | DirPropFlag(RLI) | DirPropFlag(FSI) | DirPropFlag(PDI); + + /* paragraph and segment separators */ + private static final int MASK_B_S = DirPropFlag(B) | DirPropFlag(S); + + /* all types that are counted as White Space or Neutral in some steps */ + static final int MASK_WS = MASK_B_S | DirPropFlag(WS) | MASK_BN_EXPLICIT | MASK_ISO; + + /* types that are neutrals or could becomes neutrals in (Wn) */ + private static final int MASK_POSSIBLE_N = DirPropFlag(ON) | DirPropFlag(CS) | DirPropFlag(ES) | DirPropFlag(ET) + | MASK_WS; + + /* + * These types may be changed to "e", the embedding type (L or R) of the run, in + * the Bidi algorithm (N2) + */ + private static final int MASK_EMBEDDING = DirPropFlag(NSM) | MASK_POSSIBLE_N; + + /* + * the dirProp's L and R are defined to 0 and 1 values in + * UCharacterDirection.java + */ + private static byte GetLRFromLevel(byte level) { + return (byte) (level & 1); + } + + private static boolean IsDefaultLevel(byte level) { + return ((level & LEVEL_DEFAULT_LTR) == LEVEL_DEFAULT_LTR); + } + + static boolean IsBidiControlChar(int c) { + /* + * check for range 0x200c to 0x200f (ZWNJ, ZWJ, LRM, RLM) or 0x202a to 0x202e + * (LRE, RLE, PDF, LRO, RLO) + */ + return (((c & 0xfffffffc) == 0x200c) || ((c >= 0x202a) && (c <= 0x202e)) || ((c >= 0x2066) && (c <= 0x2069))); + } + + void verifyValidPara() { + if (!(this == this.paraBidi)) { + throw new IllegalStateException(); + } + } + + void verifyValidParaOrLine() { + BidiBase para = this.paraBidi; + /* verify Para */ + if (this == para) { + return; + } + /* verify Line */ + if ((para == null) || (para != para.paraBidi)) { + throw new IllegalStateException(); + } + } + + void verifyRange(int index, int start, int limit) { + if (index < start || index >= limit) { + throw new IllegalArgumentException("Value " + index + " is out of range " + start + " to " + limit); + } + } + + /** + * Allocate a Bidi object with preallocated memory for internal + * structures. This method provides a Bidi object like the default + * constructor but it also preallocates memory for internal structures according + * to the sizings supplied by the caller. + *

+ * The preallocation can be limited to some of the internal memory by setting + * some values to 0 here. That means that if, e.g., maxRunCount + * cannot be reasonably predetermined and should not be set to + * maxLength (the only failproof value) to avoid wasting memory, + * then maxRunCount could be set to 0 here and the internal + * structures that are associated with it will be allocated on demand, just like + * with the default constructor. + * + * @param maxLength is the maximum text or line length that internal memory + * will be preallocated for. An attempt to associate this + * object with a longer text will fail, unless this value is + * 0, which leaves the allocation up to the implementation. + * + * @param maxRunCount is the maximum anticipated number of same-level runs that + * internal memory will be preallocated for. An attempt to + * access visual runs on an object that was not preallocated + * for as many runs as the text was actually resolved to will + * fail, unless this value is 0, which leaves the allocation + * up to the implementation.
+ *
+ * The number of runs depends on the actual text and maybe + * anywhere between 1 and maxLength. It is + * typically small. + * + * @throws IllegalArgumentException if maxLength or maxRunCount is less than 0 + * @stable ICU 3.8 + */ + public BidiBase(int maxLength, int maxRunCount) { + /* check the argument values */ + if (maxLength < 0 || maxRunCount < 0) { + throw new IllegalArgumentException(); + } + + /* + * reset the object, all reference variables null, all flags false, all sizes 0. + * In fact, we don't need to do anything, since class members are initialized as + * zero when an instance is created. + */ + /* + * mayAllocateText = false; mayAllocateRuns = false; orderParagraphsLTR = false; + * paraCount = 0; runCount = 0; trailingWSStart = 0; flags = 0; paraLevel = 0; + * defaultParaLevel = 0; direction = 0; + */ + /* get Bidi properties */ + bdp = UBiDiProps.INSTANCE; + + /* allocate memory for arrays as requested */ + if (maxLength > 0) { + getInitialDirPropsMemory(maxLength); + getInitialLevelsMemory(maxLength); + } else { + mayAllocateText = true; + } + + if (maxRunCount > 0) { + // if maxRunCount == 1, use simpleRuns[] + if (maxRunCount > 1) { + getInitialRunsMemory(maxRunCount); + } + } else { + mayAllocateRuns = true; + } + } + + /* + * We are allowed to allocate memory if object==null or mayAllocate==true for + * each array that we need. + * + * Assume sizeNeeded>0. If object != null, then assume size > 0. + */ + private Object getMemory(String label, Object array, Class arrayClass, boolean mayAllocate, int sizeNeeded) { + int len = Array.getLength(array); + + /* we have at least enough memory and must not allocate */ + if (sizeNeeded == len) { + return array; + } + if (!mayAllocate) { + /* we must not allocate */ + if (sizeNeeded <= len) { + return array; + } + throw new OutOfMemoryError("Failed to allocate memory for " + label); + } + /* we may try to grow or shrink */ + /* + * FOOD FOR THOUGHT: when shrinking it should be possible to avoid the + * allocation altogether and rely on this.length + */ + try { + return Array.newInstance(arrayClass, sizeNeeded); + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for " + label); + } + } + + /* helper methods for each allocated array */ + private void getDirPropsMemory(boolean mayAllocate, int len) { + Object array = getMemory("DirProps", dirPropsMemory, Byte.TYPE, mayAllocate, len); + dirPropsMemory = (byte[]) array; + } + + void getDirPropsMemory(int len) { + getDirPropsMemory(mayAllocateText, len); + } + + private void getLevelsMemory(boolean mayAllocate, int len) { + Object array = getMemory("Levels", levelsMemory, Byte.TYPE, mayAllocate, len); + levelsMemory = (byte[]) array; + } + + void getLevelsMemory(int len) { + getLevelsMemory(mayAllocateText, len); + } + + private void getRunsMemory(boolean mayAllocate, int len) { + Object array = getMemory("Runs", runsMemory, BidiRun.class, mayAllocate, len); + runsMemory = (BidiRun[]) array; + } + + void getRunsMemory(int len) { + getRunsMemory(mayAllocateRuns, len); + } + + /* additional methods used by constructor - always allow allocation */ + private void getInitialDirPropsMemory(int len) { + getDirPropsMemory(true, len); + } + + private void getInitialLevelsMemory(int len) { + getLevelsMemory(true, len); + } + + private void getInitialRunsMemory(int len) { + getRunsMemory(true, len); + } + + /** + * Is this Bidi object set to perform the inverse Bidi algorithm? + *

+ * Note: calling this method after setting the reordering mode with + * setReorderingMode will return true if the + * reordering mode was set to REORDER_INVERSE_NUMBERS_AS_L, + * false for all other values. + *

+ * + * @return true if the Bidi object is set to perform + * the inverse Bidi algorithm by handling numbers as L. + * + * @see #setInverse + * @see #setReorderingMode + * @see #REORDER_INVERSE_NUMBERS_AS_L + * @stable ICU 3.8 + */ + public boolean isInverse() { + return isInverse; + } + + /* perform (P2)..(P3) ------------------------------------------------------- */ + + /* + * Check that there are enough entries in the arrays paras_limit and paras_level + */ + private void checkParaCount() { + int[] saveLimits; + byte[] saveLevels; + int count = paraCount; + if (count <= paras_level.length) + return; + int oldLength = paras_level.length; + saveLimits = paras_limit; + saveLevels = paras_level; + try { + paras_limit = new int[count * 2]; + paras_level = new byte[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for paras"); + } + System.arraycopy(saveLimits, 0, paras_limit, 0, oldLength); + System.arraycopy(saveLevels, 0, paras_level, 0, oldLength); + } + + /* + * Get the directional properties for the text, calculate the flags bit-set, and + * determine the paragraph level if necessary (in paras_level[i]). FSI + * initiators are also resolved and their dirProp replaced with LRI or RLI. When + * encountering an FSI, it is initially replaced with an LRI, which is the + * default. Only if a strong R or AL is found within its scope will the LRI be + * replaced by an RLI. + */ + static final int NOT_SEEKING_STRONG = 0; /* 0: not contextual paraLevel, not after FSI */ + static final int SEEKING_STRONG_FOR_PARA = 1; /* 1: looking for first strong char in para */ + static final int SEEKING_STRONG_FOR_FSI = 2; /* 2: looking for first strong after FSI */ + static final int LOOKING_FOR_PDI = 3; /* 3: found strong after FSI, looking for PDI */ + + private void getDirProps() { + int i = 0, i0, i1; + flags = 0; /* collect all directionalities in the text */ + int uchar; + byte dirProp; + byte defaultParaLevel = 0; /* initialize to avoid compiler warnings */ + boolean isDefaultLevel = IsDefaultLevel(paraLevel); + /* + * for inverse Bidi, the default para level is set to RTL if there is a strong R + * or AL character at either end of the text + */ + boolean isDefaultLevelInverse = isDefaultLevel && (reorderingMode == REORDER_INVERSE_LIKE_DIRECT + || reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL); + lastArabicPos = -1; + int controlCount = 0; + boolean removeBidiControls = (reorderingOptions & OPTION_REMOVE_CONTROLS) != 0; + + byte state; + byte lastStrong = ON; /* for default level & inverse Bidi */ + /* + * The following stacks are used to manage isolate sequences. Those sequences + * may be nested, but obviously never more deeply than the maximum explicit + * embedding level. lastStack is the index of the last used entry in the stack. + * A value of -1 means that there is no open isolate sequence. lastStack is + * reset to -1 on paragraph boundaries. + */ + /* + * The following stack contains the position of the initiator of each open + * isolate sequence + */ + int[] isolateStartStack = new int[MAX_EXPLICIT_LEVEL + 1]; + /* + * The following stack contains the last known state before encountering the + * initiator of an isolate sequence + */ + byte[] previousStateStack = new byte[MAX_EXPLICIT_LEVEL + 1]; + int stackLast = -1; + + if ((reorderingOptions & OPTION_STREAMING) != 0) + length = 0; + defaultParaLevel = (byte) (paraLevel & 1); + + if (isDefaultLevel) { + paras_level[0] = defaultParaLevel; + lastStrong = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; + } else { + paras_level[0] = paraLevel; + state = NOT_SEEKING_STRONG; + } + /* count paragraphs and determine the paragraph level (P2..P3) */ + /* + * see comment on constant fields: the LEVEL_DEFAULT_XXX values are designed so + * that their low-order bit alone yields the intended default + */ + + for (i = 0; i < originalLength; /* i is incremented in the loop */) { + i0 = i; /* index of first code unit */ + uchar = UTF16.charAt(text, 0, originalLength, i); + i += UTF16.getCharCount(uchar); + i1 = i - 1; /* index of last code unit, gets the directional property */ + + dirProp = (byte) getCustomizedClass(uchar); + flags |= DirPropFlag(dirProp); + dirProps[i1] = dirProp; + if (i1 > i0) { /* set previous code units' properties to BN */ + flags |= DirPropFlag(BN); + do { + dirProps[--i1] = BN; + } while (i1 > i0); + } + if (removeBidiControls && IsBidiControlChar(uchar)) { + controlCount++; + } + if (dirProp == L) { + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 0; + state = NOT_SEEKING_STRONG; + } else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + } + state = LOOKING_FOR_PDI; + } + lastStrong = L; + continue; + } + if (dirProp == R || dirProp == AL) { + if (state == SEEKING_STRONG_FOR_PARA) { + paras_level[paraCount - 1] = 1; + state = NOT_SEEKING_STRONG; + } else if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + dirProps[isolateStartStack[stackLast]] = RLI; + flags |= DirPropFlag(RLI); + } + state = LOOKING_FOR_PDI; + } + lastStrong = R; + if (dirProp == AL) + lastArabicPos = i - 1; + continue; + } + if (dirProp >= FSI && dirProp <= RLI) { /* FSI, LRI or RLI */ + stackLast++; + if (stackLast <= MAX_EXPLICIT_LEVEL) { + isolateStartStack[stackLast] = i - 1; + previousStateStack[stackLast] = state; + } + if (dirProp == FSI) { + dirProps[i - 1] = LRI; /* default if no strong char */ + state = SEEKING_STRONG_FOR_FSI; + } else + state = LOOKING_FOR_PDI; + continue; + } + if (dirProp == PDI) { + if (state == SEEKING_STRONG_FOR_FSI) { + if (stackLast <= MAX_EXPLICIT_LEVEL) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + } + } + if (stackLast >= 0) { + if (stackLast <= MAX_EXPLICIT_LEVEL) + state = previousStateStack[stackLast]; + stackLast--; + } + continue; + } + if (dirProp == B) { + if (i < originalLength && uchar == CR && text[i] == LF) /* do nothing on the CR */ + continue; + paras_limit[paraCount - 1] = i; + if (isDefaultLevelInverse && lastStrong == R) + paras_level[paraCount - 1] = 1; + if ((reorderingOptions & OPTION_STREAMING) != 0) { + /* + * When streaming, we only process whole paragraphs thus some updates are only + * done on paragraph boundaries + */ + length = i; /* i is index to next character */ + this.controlCount = controlCount; + } + if (i < originalLength) { /* B not last char in text */ + paraCount++; + checkParaCount(); /* check that there is enough memory for a new para entry */ + if (isDefaultLevel) { + paras_level[paraCount - 1] = defaultParaLevel; + state = SEEKING_STRONG_FOR_PARA; + lastStrong = defaultParaLevel; + } else { + paras_level[paraCount - 1] = paraLevel; + state = NOT_SEEKING_STRONG; + } + stackLast = -1; + } + continue; + } + } + /* +Ignore still open isolate sequences with overflow */ + if (stackLast > MAX_EXPLICIT_LEVEL) { + stackLast = MAX_EXPLICIT_LEVEL; + state = SEEKING_STRONG_FOR_FSI; /* to be on the safe side */ + } + /* Resolve direction of still unresolved open FSI sequences */ + while (stackLast >= 0) { + if (state == SEEKING_STRONG_FOR_FSI) { + /* no need for next statement, already set by default */ + /* dirProps[isolateStartStack[stackLast]] = LRI; */ + flags |= DirPropFlag(LRI); + break; + } + state = previousStateStack[stackLast]; + stackLast--; + } + /* When streaming, ignore text after the last paragraph separator */ + if ((reorderingOptions & OPTION_STREAMING) != 0) { + if (length < originalLength) + paraCount--; + } else { + paras_limit[paraCount - 1] = originalLength; + this.controlCount = controlCount; + } + /* + * For inverse bidi, default para direction is RTL if there is a strong R or AL + * at either end of the paragraph + */ + if (isDefaultLevelInverse && lastStrong == R) { + paras_level[paraCount - 1] = 1; + } + if (isDefaultLevel) { + paraLevel = paras_level[0]; + } + /* + * The following is needed to resolve the text direction for default level + * paragraphs containing no strong character + */ + for (i = 0; i < paraCount; i++) + flags |= DirPropFlagLR(paras_level[i]); + + if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { + flags |= DirPropFlag(L); + } + } + + /* determine the paragraph level at position index */ + byte GetParaLevelAt(int pindex) { + if (defaultParaLevel == 0 || pindex < paras_limit[0]) + return paraLevel; + int i; + for (i = 1; i < paraCount; i++) + if (pindex < paras_limit[i]) + break; + if (i >= paraCount) + i = paraCount - 1; + return paras_level[i]; + } + + /* Functions for handling paired brackets ----------------------------------- */ + + /* + * In the isoRuns array, the first entry is used for text outside of any isolate + * sequence. Higher entries are used for each more deeply nested isolate + * sequence. isoRunLast is the index of the last used entry. The openings array + * is used to note the data of opening brackets not yet matched by a closing + * bracket, or matched but still susceptible to change level. Each isoRun entry + * contains the index of the first and one-after-last openings entries for + * pending opening brackets it contains. The next openings entry to use is the + * one-after-last of the most deeply nested isoRun entry. isoRun entries also + * contain their current embedding level and the last encountered strong + * character, since these will be needed to resolve the level of paired + * brackets. + */ + + private void bracketInit(BracketData bd) { + bd.isoRunLast = 0; + bd.isoRuns[0] = new IsoRun(); + bd.isoRuns[0].start = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = GetParaLevelAt(0); + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte) (GetParaLevelAt(0) & 1); + bd.isoRuns[0].contextPos = 0; + bd.openings = new Opening[SIMPLE_PARAS_COUNT]; + bd.isNumbersSpecial = reorderingMode == REORDER_NUMBERS_SPECIAL + || reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL; + } + + /* paragraph boundary */ + private void bracketProcessB(BracketData bd, byte level) { + bd.isoRunLast = 0; + bd.isoRuns[0].limit = 0; + bd.isoRuns[0].level = level; + bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte) (level & 1); + bd.isoRuns[0].contextPos = 0; + } + + /* LRE, LRO, RLE, RLO, PDF */ + private void bracketProcessBoundary(BracketData bd, int lastCcPos, byte contextLevel, byte embeddingLevel) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if ((DirPropFlag(dirProps[lastCcPos]) & MASK_ISO) != 0) /* after an isolate */ + return; + if (NoOverride(embeddingLevel) > NoOverride(contextLevel)) /* not a PDF */ + contextLevel = embeddingLevel; + pLastIsoRun.limit = pLastIsoRun.start; + pLastIsoRun.level = embeddingLevel; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte) (contextLevel & 1); + pLastIsoRun.contextPos = lastCcPos; + } + + /* LRI or RLI */ + private void bracketProcessLRI_RLI(BracketData bd, byte level) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + short lastLimit; + pLastIsoRun.lastBase = ON; + lastLimit = pLastIsoRun.limit; + bd.isoRunLast++; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + if (pLastIsoRun == null) + pLastIsoRun = bd.isoRuns[bd.isoRunLast] = new IsoRun(); + pLastIsoRun.start = pLastIsoRun.limit = lastLimit; + pLastIsoRun.level = level; + pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte) (level & 1); + pLastIsoRun.contextPos = 0; + } + + /* PDI */ + private void bracketProcessPDI(BracketData bd) { + IsoRun pLastIsoRun; + bd.isoRunLast--; + pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + pLastIsoRun.lastBase = ON; + } + + /* newly found opening bracket: create an openings entry */ + private void bracketAddOpening(BracketData bd, char match, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening; + if (pLastIsoRun.limit >= bd.openings.length) { /* no available new entry */ + Opening[] saveOpenings = bd.openings; + int count; + try { + count = bd.openings.length; + bd.openings = new Opening[count * 2]; + } catch (Exception e) { + throw new OutOfMemoryError("Failed to allocate memory for openings"); + } + System.arraycopy(saveOpenings, 0, bd.openings, 0, count); + } + pOpening = bd.openings[pLastIsoRun.limit]; + if (pOpening == null) + pOpening = bd.openings[pLastIsoRun.limit] = new Opening(); + pOpening.position = position; + pOpening.match = match; + pOpening.contextDir = pLastIsoRun.contextDir; + pOpening.contextPos = pLastIsoRun.contextPos; + pOpening.flags = 0; + pLastIsoRun.limit++; + } + + /* + * change N0c1 to N0c2 when a preceding bracket is assigned the embedding level + */ + private void fixN0c(BracketData bd, int openingIndex, int newPropPosition, byte newProp) { + /* This function calls itself recursively */ + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening qOpening; + int k, openingPosition, closingPosition; + for (k = openingIndex + 1; k < pLastIsoRun.limit; k++) { + qOpening = bd.openings[k]; + if (qOpening.match >= 0) /* not an N0c match */ + continue; + if (newPropPosition < qOpening.contextPos) + break; + if (newPropPosition >= qOpening.position) + continue; + if (newProp == qOpening.contextDir) + break; + openingPosition = qOpening.position; + dirProps[openingPosition] = newProp; + closingPosition = -(qOpening.match); + dirProps[closingPosition] = newProp; + qOpening.match = 0; /* prevent further changes */ + fixN0c(bd, k, openingPosition, newProp); + fixN0c(bd, k, closingPosition, newProp); + } + } + + /* process closing bracket; return L or R if N0b or N0c, ON if N0d */ + private byte bracketProcessClosing(BracketData bd, int openIdx, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + Opening pOpening, qOpening; + byte direction; + boolean stable; + byte newProp; + pOpening = bd.openings[openIdx]; + direction = (byte) (pLastIsoRun.level & 1); + stable = true; /* assume stable until proved otherwise */ + + /* + * The stable flag is set when brackets are paired and their level is resolved + * and cannot be changed by what will be found later in the source string. An + * unstable match can occur only when applying N0c, where the resolved level + * depends on the preceding context, and this context may be affected by text + * occurring later. Example: RTL paragraph containing: abc[(latin) HEBREW] When + * the closing parenthesis is encountered, it appears that N0c1 must be applied + * since 'abc' sets an opposite direction context and both parentheses receive + * level 2. However, when the closing square bracket is processed, N0b applies + * because of 'HEBREW' being included within the brackets, thus the square + * brackets are treated like R and receive level 1. However, this changes the + * preceding context of the opening parenthesis, and it now appears that N0c2 + * must be applied to the parentheses rather than N0c1. + */ + + if ((direction == 0 && (pOpening.flags & FOUND_L) > 0) + || (direction == 1 && (pOpening.flags & FOUND_R) > 0)) { /* N0b */ + newProp = direction; + } else if ((pOpening.flags & (FOUND_L | FOUND_R)) != 0) { /* N0c */ + /* + * it is stable if there is no preceding text or in conditions too complicated + * and not worth checking + */ + stable = (openIdx == pLastIsoRun.start); + if (direction != pOpening.contextDir) + newProp = pOpening.contextDir; /* N0c1 */ + else + newProp = direction; /* N0c2 */ + } else { + /* forget this and any brackets nested within this pair */ + pLastIsoRun.limit = (short) openIdx; + return ON; /* N0d */ + } + dirProps[pOpening.position] = newProp; + dirProps[position] = newProp; + /* Update nested N0c pairs that may be affected */ + fixN0c(bd, openIdx, pOpening.position, newProp); + if (stable) { + pLastIsoRun.limit = (short) openIdx; /* forget any brackets nested within this pair */ + /* remove lower located synonyms if any */ + while (pLastIsoRun.limit > pLastIsoRun.start + && bd.openings[pLastIsoRun.limit - 1].position == pOpening.position) + pLastIsoRun.limit--; + } else { + int k; + pOpening.match = -position; + /* neutralize lower located synonyms if any */ + k = openIdx - 1; + while (k >= pLastIsoRun.start && bd.openings[k].position == pOpening.position) + bd.openings[k--].match = 0; + /* + * neutralize any unmatched opening between the current pair; this will also + * neutralize higher located synonyms if any + */ + for (k = openIdx + 1; k < pLastIsoRun.limit; k++) { + qOpening = bd.openings[k]; + if (qOpening.position >= position) + break; + if (qOpening.match > 0) + qOpening.match = 0; + } + } + return newProp; + } + + /* handle strong characters, digits and candidates for closing brackets */ + private void bracketProcessChar(BracketData bd, int position) { + IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast]; + byte dirProp, newProp; + byte level; + dirProp = dirProps[position]; + if (dirProp == ON) { + char c, match; + int idx; + /* + * First see if it is a matching closing bracket. Hopefully, this is more + * efficient than checking if it is a closing bracket at all + */ + c = text[position]; + for (idx = pLastIsoRun.limit - 1; idx >= pLastIsoRun.start; idx--) { + if (bd.openings[idx].match != c) + continue; + /* We have a match */ + newProp = bracketProcessClosing(bd, idx, position); + if (newProp == ON) { /* N0d */ + c = 0; /* prevent handling as an opening */ + break; + } + pLastIsoRun.lastBase = ON; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + short flag; + int i; + newProp = (byte) (level & 1); + pLastIsoRun.lastStrong = newProp; + flag = (short) DirPropFlag(newProp); + for (i = pLastIsoRun.start; i < idx; i++) + bd.openings[i].flags |= flag; + /* matching brackets are not overridden by LRO/RLO */ + levels[position] &= ~LEVEL_OVERRIDE; + } + /* matching brackets are not overridden by LRO/RLO */ + levels[bd.openings[idx].position] &= ~LEVEL_OVERRIDE; + return; + } + /* + * We get here only if the ON character is not a matching closing bracket or it + * is a case of N0d + */ + /* Now see if it is an opening bracket */ + if (c != 0) { + match = (char) UCharacter.getBidiPairedBracket(c); /* get the matching char */ + } else { + match = 0; + } + if (match != c && /* has a matching char */ + UCharacter.getIntPropertyValue(c, BIDI_PAIRED_BRACKET_TYPE) == + /* opening bracket */ BidiPairedBracketType.OPEN) { + /* + * special case: process synonyms create an opening entry for each synonym + */ + if (match == 0x232A) { /* RIGHT-POINTING ANGLE BRACKET */ + bracketAddOpening(bd, (char) 0x3009, position); + } else if (match == 0x3009) { /* RIGHT ANGLE BRACKET */ + bracketAddOpening(bd, (char) 0x232A, position); + } + bracketAddOpening(bd, match, position); + } + } + level = levels[position]; + if ((level & LEVEL_OVERRIDE) != 0) { /* X4, X5 */ + newProp = (byte) (level & 1); + if (dirProp != S && dirProp != WS && dirProp != ON) + dirProps[position] = newProp; + pLastIsoRun.lastBase = newProp; + pLastIsoRun.lastStrong = newProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } else if (dirProp <= R || dirProp == AL) { + newProp = DirFromStrong(dirProp); + pLastIsoRun.lastBase = dirProp; + pLastIsoRun.lastStrong = dirProp; + pLastIsoRun.contextDir = newProp; + pLastIsoRun.contextPos = position; + } else if (dirProp == EN) { + pLastIsoRun.lastBase = EN; + if (pLastIsoRun.lastStrong == L) { + newProp = L; /* W7 */ + if (!bd.isNumbersSpecial) + dirProps[position] = ENL; + pLastIsoRun.contextDir = L; + pLastIsoRun.contextPos = position; + } else { + newProp = R; /* N0 */ + if (pLastIsoRun.lastStrong == AL) + dirProps[position] = AN; /* W2 */ + else + dirProps[position] = ENR; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } + } else if (dirProp == AN) { + newProp = R; /* N0 */ + pLastIsoRun.lastBase = AN; + pLastIsoRun.contextDir = R; + pLastIsoRun.contextPos = position; + } else if (dirProp == NSM) { + /* + * if the last real char was ON, change NSM to ON so that it will stay ON even + * if the last real char is a bracket which may be changed to L or R + */ + newProp = pLastIsoRun.lastBase; + if (newProp == ON) + dirProps[position] = newProp; + } else { + newProp = dirProp; + pLastIsoRun.lastBase = dirProp; + } + if (newProp <= R || newProp == AL) { + int i; + short flag = (short) DirPropFlag(DirFromStrong(newProp)); + for (i = pLastIsoRun.start; i < pLastIsoRun.limit; i++) + if (position > bd.openings[i].position) + bd.openings[i].flags |= flag; + } + } + + /* perform (X1)..(X9) ------------------------------------------------------- */ + + /* determine if the text is mixed-directional or single-directional */ + private byte directionFromFlags() { + + /* if the text contains AN and neutrals, then some neutrals may become RTL */ + if (!((flags & MASK_RTL) != 0 || ((flags & DirPropFlag(AN)) != 0 && (flags & MASK_POSSIBLE_N) != 0))) { + return LTR; + } else if ((flags & MASK_LTR) == 0) { + return RTL; + } else { + return MIXED; + } + } + + /* + * Resolve the explicit levels as specified by explicit embedding codes. + * Recalculate the flags to have them reflect the real properties after taking + * the explicit embeddings into account. + * + * The BiDi algorithm is designed to result in the same behavior whether + * embedding levels are externally specified (from "styled text", supposedly the + * preferred method) or set by explicit embedding codes (LRx, RLx, PDF, FSI, + * PDI) in the plain text. That is why (X9) instructs to remove all not-isolate + * explicit codes (and BN). However, in a real implementation, the removal of + * these codes and their index positions in the plain text is undesirable since + * it would result in reallocated, reindexed text. Instead, this implementation + * leaves the codes in there and just ignores them in the subsequent processing. + * In order to get the same reordering behavior, positions with a BN or a + * not-isolate explicit embedding code just get the same level assigned as the + * last "real" character. + * + * Some implementations, not this one, then overwrite some of these + * directionality properties at "real" same-level-run boundaries by L or R codes + * so that the resolution of weak types can be performed on the entire paragraph + * at once instead of having to parse it once more and perform that resolution + * on same-level-runs. This limits the scope of the implicit rules in + * effectively the same way as the run limits. + * + * Instead, this implementation does not modify these codes, except for paired + * brackets whose properties (ON) may be replaced by L or R. On one hand, the + * paragraph has to be scanned for same-level-runs, but on the other hand, this + * saves another loop to reset these codes, or saves making and modifying a copy + * of dirProps[]. + * + * + * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi + * algorithm. + * + * + * Handling the stack of explicit levels (Xn): + * + * With the BiDi stack of explicit levels, as pushed with each LRE, RLE, LRO, + * RLO, LRI, RLI and FSI and popped with each PDF and PDI, the explicit level + * must never exceed MAX_EXPLICIT_LEVEL. + * + * In order to have a correct push-pop semantics even in the case of overflows, + * overflow counters and a valid isolate counter are used as described in UAX#9 + * section 3.3.2 "Explicit Levels and Directions". + * + * This implementation assumes that MAX_EXPLICIT_LEVEL is odd. + * + * Returns the direction + * + */ + private byte resolveExplicitLevels() { + int i = 0; + byte dirProp; + byte level = GetParaLevelAt(0); + byte dirct; + isolateCount = 0; + + /* determine if the text is mixed-directional or single-directional */ + dirct = directionFromFlags(); + + /* we may not need to resolve any explicit levels */ + if (dirct != MIXED) { + /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */ + return dirct; + } + + if (reorderingMode > REORDER_LAST_LOGICAL_TO_VISUAL) { + /* inverse BiDi: mixed, but all characters are at the same embedding level */ + /* set all levels to the paragraph level */ + int paraIndex, start, limit; + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex - 1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) + levels[i] = level; + } + return dirct; /* no bracket matching for inverse BiDi */ + } + if ((flags & (MASK_EXPLICIT | MASK_ISO)) == 0) { + /* no embeddings, set all levels to the paragraph level */ + /* we still have to perform bracket matching */ + int paraIndex, start, limit; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + for (paraIndex = 0; paraIndex < paraCount; paraIndex++) { + if (paraIndex == 0) + start = 0; + else + start = paras_limit[paraIndex - 1]; + limit = paras_limit[paraIndex]; + level = paras_level[paraIndex]; + for (i = start; i < limit; i++) { + levels[i] = level; + dirProp = dirProps[i]; + if (dirProp == BN) + continue; + if (dirProp == B) { + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + continue; /* skip CR when followed by LF */ + bracketProcessB(bracketData, level); + } + continue; + } + bracketProcessChar(bracketData, i); + } + } + return dirct; + } + /* continue to perform (Xn) */ + + /* + * (X1) level is set for all codes, embeddingLevel keeps track of the push/pop + * operations + */ + /* + * both variables may carry the LEVEL_OVERRIDE flag to indicate the override + * status + */ + byte embeddingLevel = level, newLevel; + byte previousLevel = level; /* previous level for regular (not CC) characters */ + int lastCcPos = 0; /* index of last effective LRx,RLx, PDx */ + + /* + * The following stack remembers the embedding level and the ISOLATE flag of + * level runs. stackLast points to its current entry. + */ + short[] stack = new short[MAX_EXPLICIT_LEVEL + 2]; /* + * we never push anything >= MAX_EXPLICIT_LEVEL but we need + * one more entry as base + */ + int stackLast = 0; + int overflowIsolateCount = 0; + int overflowEmbeddingCount = 0; + int validIsolateCount = 0; + BracketData bracketData = new BracketData(); + bracketInit(bracketData); + stack[0] = level; /* initialize base entry to para level, no override, no isolate */ + + /* recalculate the flags */ + flags = 0; + + for (i = 0; i < length; i++) { + dirProp = dirProps[i]; + switch (dirProp) { + case LRE: + case RLE: + case LRO: + case RLO: + /* (X2, X3, X4, X5) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + if (dirProp == LRE || dirProp == LRO) { + /* least greater even level */ + newLevel = (byte) ((embeddingLevel + 2) & ~(LEVEL_OVERRIDE | 1)); + } else { + /* least greater odd level */ + newLevel = (byte) ((NoOverride(embeddingLevel) + 1) | 1); + } + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && overflowEmbeddingCount == 0) { + lastCcPos = i; + embeddingLevel = newLevel; + if (dirProp == LRO || dirProp == RLO) + embeddingLevel |= LEVEL_OVERRIDE; + stackLast++; + stack[stackLast] = embeddingLevel; + /* + * we don't need to set LEVEL_OVERRIDE off for LRE and RLE since this has + * already been done for newLevel which is the source for embeddingLevel. + */ + } else { + if (overflowIsolateCount == 0) + overflowEmbeddingCount++; + } + break; + case PDF: + /* (X7) */ + flags |= DirPropFlag(BN); + levels[i] = previousLevel; + /* handle all the overflow cases first */ + if (overflowIsolateCount > 0) { + break; + } + if (overflowEmbeddingCount > 0) { + overflowEmbeddingCount--; + break; + } + if (stackLast > 0 && stack[stackLast] < ISOLATE) { /* not an isolate entry */ + lastCcPos = i; + stackLast--; + embeddingLevel = (byte) stack[stackLast]; + } + break; + case LRI: + case RLI: + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + levels[i] = NoOverride(embeddingLevel); + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + previousLevel = embeddingLevel; + /* (X5a, X5b) */ + if (dirProp == LRI) + /* least greater even level */ + newLevel = (byte) ((embeddingLevel + 2) & ~(LEVEL_OVERRIDE | 1)); + else + /* least greater odd level */ + newLevel = (byte) ((NoOverride(embeddingLevel) + 1) | 1); + if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 && overflowEmbeddingCount == 0) { + flags |= DirPropFlag(dirProp); + lastCcPos = i; + validIsolateCount++; + if (validIsolateCount > isolateCount) + isolateCount = validIsolateCount; + embeddingLevel = newLevel; + /* + * we can increment stackLast without checking because newLevel will exceed + * UBIDI_MAX_EXPLICIT_LEVEL before stackLast overflows + */ + stackLast++; + stack[stackLast] = (short) (embeddingLevel + ISOLATE); + bracketProcessLRI_RLI(bracketData, embeddingLevel); + } else { + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + overflowIsolateCount++; + } + break; + case PDI: + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + } + /* (X6a) */ + if (overflowIsolateCount > 0) { + overflowIsolateCount--; + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + } else if (validIsolateCount > 0) { + flags |= DirPropFlag(PDI); + lastCcPos = i; + overflowEmbeddingCount = 0; + while (stack[stackLast] < ISOLATE) /* pop embedding entries */ + stackLast--; /* until the last isolate entry */ + stackLast--; /* pop also the last isolate entry */ + validIsolateCount--; + bracketProcessPDI(bracketData); + } else + /* make it WS so that it is handled by adjustWSLevels() */ + dirProps[i] = WS; + embeddingLevel = (byte) (stack[stackLast] & ~ISOLATE); + flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel); + previousLevel = embeddingLevel; + levels[i] = NoOverride(embeddingLevel); + break; + case B: + flags |= DirPropFlag(B); + levels[i] = GetParaLevelAt(i); + if ((i + 1) < length) { + if (text[i] == CR && text[i + 1] == LF) + break; /* skip CR when followed by LF */ + overflowEmbeddingCount = overflowIsolateCount = 0; + validIsolateCount = 0; + stackLast = 0; + previousLevel = embeddingLevel = GetParaLevelAt(i + 1); + stack[0] = embeddingLevel; /* initialize base entry to para level, no override, no isolate */ + bracketProcessB(bracketData, embeddingLevel); + } + break; + case BN: + /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */ + /* they will get their levels set correctly in adjustWSLevels() */ + levels[i] = previousLevel; + flags |= DirPropFlag(BN); + break; + default: + /* all other types are normal characters and get the "real" level */ + if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) { + bracketProcessBoundary(bracketData, lastCcPos, previousLevel, embeddingLevel); + flags |= DirPropFlagMultiRuns; + if ((embeddingLevel & LEVEL_OVERRIDE) != 0) + flags |= DirPropFlagO(embeddingLevel); + else + flags |= DirPropFlagE(embeddingLevel); + } + previousLevel = embeddingLevel; + levels[i] = embeddingLevel; + bracketProcessChar(bracketData, i); + /* the dirProp may have been changed in bracketProcessChar() */ + flags |= DirPropFlag(dirProps[i]); + break; + } + } + if ((flags & MASK_EMBEDDING) != 0) { + flags |= DirPropFlagLR(paraLevel); + } + if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) { + flags |= DirPropFlag(L); + } + /* again, determine if the text is mixed-directional or single-directional */ + dirct = directionFromFlags(); + + return dirct; + } + + /* + * Use a pre-specified embedding levels array: + * + * Adjust the directional properties for overrides (->LEVEL_OVERRIDE), ignore + * all explicit codes (X9), and check all the preset levels. + * + * Recalculate the flags to have them reflect the real properties after taking + * the explicit embeddings into account. + */ + private byte checkExplicitLevels() { + byte dirProp; + int i; + int isolateCount = 0; + + this.flags = 0; /* collect all directionalities in the text */ + byte level; + this.isolateCount = 0; + + for (i = 0; i < length; ++i) { + if (levels[i] == 0) { + levels[i] = paraLevel; + } + + // for backward compatibility + if (MAX_EXPLICIT_LEVEL < (levels[i] & 0x7f)) { + if ((levels[i] & LEVEL_OVERRIDE) != 0) { + levels[i] = (byte) (paraLevel | LEVEL_OVERRIDE); + } else { + levels[i] = paraLevel; + } + } + + level = levels[i]; + dirProp = dirProps[i]; + if (dirProp == LRI || dirProp == RLI) { + isolateCount++; + if (isolateCount > this.isolateCount) + this.isolateCount = isolateCount; + } else if (dirProp == PDI) { + isolateCount--; + } else if (dirProp == B) { + isolateCount = 0; + } + if ((level & LEVEL_OVERRIDE) != 0) { + /* keep the override flag in levels[i] but adjust the flags */ + level &= ~LEVEL_OVERRIDE; /* make the range check below simpler */ + flags |= DirPropFlagO(level); + } else { + /* set the flags */ + flags |= DirPropFlagE(level) | DirPropFlag(dirProp); + } + if ((level < GetParaLevelAt(i) && !((0 == level) && (dirProp == B))) || (MAX_EXPLICIT_LEVEL < level)) { + /* level out of bounds */ + throw new IllegalArgumentException("level " + level + " out of bounds at " + i); + } + } + if ((flags & MASK_EMBEDDING) != 0) { + flags |= DirPropFlagLR(paraLevel); + } + /* determine if the text is mixed-directional or single-directional */ + return directionFromFlags(); + } + + /*********************************************************************/ + /* The Properties state machine table */ + /*********************************************************************/ + /* */ + /* All table cells are 8 bits: */ + /* bits 0..4: next state */ + /* bits 5..7: action to perform (if > 0) */ + /* */ + /* Cells may be of format "n" where n represents the next state */ + /* (except for the rightmost column). */ + /* Cells may also be of format "_(x,y)" where x represents an action */ + /* to perform and y represents the next state. */ + /* */ + /*********************************************************************/ + + /* Definitions and type for properties state tables */ + /*********************************************************************/ + private static final int IMPTABPROPS_COLUMNS = 16; + private static final int IMPTABPROPS_RES = IMPTABPROPS_COLUMNS - 1; + + private static short GetStateProps(short cell) { + return (short) (cell & 0x1f); + } + + private static short GetActionProps(short cell) { + return (short) (cell >> 5); + } + + private static final short groupProp[] = /* dirProp regrouped */ + { + /* + * L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN FSI LRI RLI PDI + * ENL ENR + */ + 0, 1, 2, 7, 8, 3, 9, 6, 5, 4, 4, 10, 10, 12, 10, 10, 10, 11, 10, 4, 4, 4, 4, 13, 14 }; + private static final short _L = 0; + private static final short _R = 1; + private static final short _EN = 2; + private static final short _AN = 3; + private static final short _ON = 4; + private static final short _S = 5; + private static final short _B = 6; /* reduced dirProp */ + + /*********************************************************************/ + /* */ + /* PROPERTIES STATE TABLE */ + /* */ + /* In table impTabProps, */ + /* - the ON column regroups ON and WS, FSI, RLI, LRI and PDI */ + /* - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF */ + /* - the Res column is the reduced property assigned to a run */ + /* */ + /* Action 1: process current run1, init new run1 */ + /* 2: init new run2 */ + /* 3: process run1, process run2, init new run1 */ + /* 4: process run1, set run1=run2, init new run2 */ + /* */ + /* Notes: */ + /* 1) This table is used in resolveImplicitLevels(). */ + /* 2) This table triggers actions when there is a change in the Bidi */ + /* property of incoming characters (action 1). */ + /* 3) Most such property sequences are processed immediately (in */ + /* fact, passed to processPropertySeq(). */ + /* 4) However, numbers are assembled as one sequence. This means */ + /* that undefined situations (like CS following digits, until */ + /* it is known if the next char will be a digit) are held until */ + /* following chars define them. */ + /* Example: digits followed by CS, then comes another CS or ON; */ + /* the digits will be processed, then the CS assigned */ + /* as the start of an ON sequence (action 3). */ + /* 5) There are cases where more than one sequence must be */ + /* processed, for instance digits followed by CS followed by L: */ + /* the digits must be processed as one sequence, and the CS */ + /* must be processed as an ON sequence, all this before starting */ + /* assembling chars for the opening L sequence. */ + /* */ + /* */ + private static final short impTabProps[][] = { + /* L, R, EN, AN, ON, S, B, ES, ET, CS, BN, NSM, AL, ENL, ENR, Res */ + /* 0 Init */ { 1, 2, 4, 5, 7, 15, 17, 7, 9, 7, 0, 7, 3, 18, 21, _ON }, + /* 1 L */ { 1, 32 + 2, 32 + 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 32 + 9, 32 + 7, 1, 1, 32 + 3, + 32 + 18, 32 + 21, _L }, + /* 2 R */ { 32 + 1, 2, 32 + 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 32 + 9, 32 + 7, 2, 2, 32 + 3, + 32 + 18, 32 + 21, _R }, + /* 3 AL */ { 32 + 1, 32 + 2, 32 + 6, 32 + 6, 32 + 8, 32 + 16, 32 + 17, 32 + 8, 32 + 8, 32 + 8, 3, 3, 3, + 32 + 18, 32 + 21, _R }, + /* 4 EN */ { 32 + 1, 32 + 2, 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 64 + 10, 11, 64 + 10, 4, 4, 32 + 3, 18, + 21, _EN }, + /* 5 AN */ { 32 + 1, 32 + 2, 32 + 4, 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 32 + 9, 64 + 12, 5, 5, 32 + 3, + 32 + 18, 32 + 21, _AN }, + /* 6 AL:EN/AN */ { 32 + 1, 32 + 2, 6, 6, 32 + 8, 32 + 16, 32 + 17, 32 + 8, 32 + 8, 64 + 13, 6, 6, 32 + 3, + 18, 21, _AN }, + /* 7 ON */ { 32 + 1, 32 + 2, 32 + 4, 32 + 5, 7, 32 + 15, 32 + 17, 7, 64 + 14, 7, 7, 7, 32 + 3, 32 + 18, + 32 + 21, _ON }, + /* 8 AL:ON */ { 32 + 1, 32 + 2, 32 + 6, 32 + 6, 8, 32 + 16, 32 + 17, 8, 8, 8, 8, 8, 32 + 3, 32 + 18, + 32 + 21, _ON }, + /* 9 ET */ { 32 + 1, 32 + 2, 4, 32 + 5, 7, 32 + 15, 32 + 17, 7, 9, 7, 9, 9, 32 + 3, 18, 21, _ON }, + /* 10 EN+ES/CS */ { 96 + 1, 96 + 2, 4, 96 + 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 10, + 128 + 7, 96 + 3, 18, 21, _EN }, + /* 11 EN+ET */ { 32 + 1, 32 + 2, 4, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 11, 32 + 7, 11, 11, 32 + 3, + 18, 21, _EN }, + /* 12 AN+CS */ { 96 + 1, 96 + 2, 96 + 4, 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 12, + 128 + 7, 96 + 3, 96 + 18, 96 + 21, _AN }, + /* 13 AL:EN/AN+CS */ { 96 + 1, 96 + 2, 6, 6, 128 + 8, 96 + 16, 96 + 17, 128 + 8, 128 + 8, 128 + 8, 13, + 128 + 8, 96 + 3, 18, 21, _AN }, + /* 14 ON+ET */ { 32 + 1, 32 + 2, 128 + 4, 32 + 5, 7, 32 + 15, 32 + 17, 7, 14, 7, 14, 14, 32 + 3, 128 + 18, + 128 + 21, _ON }, + /* 15 S */ { 32 + 1, 32 + 2, 32 + 4, 32 + 5, 32 + 7, 15, 32 + 17, 32 + 7, 32 + 9, 32 + 7, 15, 32 + 7, + 32 + 3, 32 + 18, 32 + 21, _S }, + /* 16 AL:S */ { 32 + 1, 32 + 2, 32 + 6, 32 + 6, 32 + 8, 16, 32 + 17, 32 + 8, 32 + 8, 32 + 8, 16, 32 + 8, + 32 + 3, 32 + 18, 32 + 21, _S }, + /* 17 B */ { 32 + 1, 32 + 2, 32 + 4, 32 + 5, 32 + 7, 32 + 15, 17, 32 + 7, 32 + 9, 32 + 7, 17, 32 + 7, + 32 + 3, 32 + 18, 32 + 21, _B }, + /* 18 ENL */ { 32 + 1, 32 + 2, 18, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 64 + 19, 20, 64 + 19, 18, 18, 32 + 3, + 18, 21, _L }, + /* 19 ENL+ES/CS */ { 96 + 1, 96 + 2, 18, 96 + 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 19, + 128 + 7, 96 + 3, 18, 21, _L }, + /* 20 ENL+ET */ { 32 + 1, 32 + 2, 18, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 20, 32 + 7, 20, 20, 32 + 3, + 18, 21, _L }, + /* 21 ENR */ { 32 + 1, 32 + 2, 21, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 64 + 22, 23, 64 + 22, 21, 21, 32 + 3, + 18, 21, _AN }, + /* 22 ENR+ES/CS */ { 96 + 1, 96 + 2, 21, 96 + 5, 128 + 7, 96 + 15, 96 + 17, 128 + 7, 128 + 14, 128 + 7, 22, + 128 + 7, 96 + 3, 18, 21, _AN }, + /* 23 ENR+ET */ { 32 + 1, 32 + 2, 21, 32 + 5, 32 + 7, 32 + 15, 32 + 17, 32 + 7, 23, 32 + 7, 23, 23, 32 + 3, + 18, 21, _AN } }; + + /*********************************************************************/ + /* The levels state machine tables */ + /*********************************************************************/ + /* */ + /* All table cells are 8 bits: */ + /* bits 0..3: next state */ + /* bits 4..7: action to perform (if > 0) */ + /* */ + /* Cells may be of format "n" where n represents the next state */ + /* (except for the rightmost column). */ + /* Cells may also be of format "_(x,y)" where x represents an action */ + /* to perform and y represents the next state. */ + /* */ + /* This format limits each table to 16 states each and to 15 actions. */ + /* */ + /*********************************************************************/ + /* Definitions and type for levels state tables */ + /*********************************************************************/ + private static final int IMPTABLEVELS_COLUMNS = _B + 2; + private static final int IMPTABLEVELS_RES = IMPTABLEVELS_COLUMNS - 1; + + private static short GetState(byte cell) { + return (short) (cell & 0x0f); + } + + private static short GetAction(byte cell) { + return (short) (cell >> 4); + } + + private static class ImpTabPair { + byte[][][] imptab; + short[][] impact; + + ImpTabPair(byte[][] table1, byte[][] table2, short[] act1, short[] act2) { + imptab = new byte[][][] { table1, table2 }; + impact = new short[][] { act1, act2 }; + } + } + + /*********************************************************************/ + /* */ + /* LEVELS STATE TABLES */ + /* */ + /* In all levels state tables, */ + /* - state 0 is the initial state */ + /* - the Res column is the increment to add to the text level */ + /* for this property sequence. */ + /* */ + /* The impact arrays for each table of a pair map the local action */ + /* numbers of the table to the total list of actions. For instance, */ + /* action 2 in a given table corresponds to the action number which */ + /* appears in entry [2] of the impact array for that table. */ + /* The first entry of all impact arrays must be 0. */ + /* */ + /* Action 1: init conditional sequence */ + /* 2: prepend conditional sequence to current sequence */ + /* 3: set ON sequence to new level - 1 */ + /* 4: init EN/AN/ON sequence */ + /* 5: fix EN/AN/ON sequence followed by R */ + /* 6: set previous level sequence to level 2 */ + /* */ + /* Notes: */ + /* 1) These tables are used in processPropertySeq(). The input */ + /* is property sequences as determined by resolveImplicitLevels. */ + /* 2) Most such property sequences are processed immediately */ + /* (levels are assigned). */ + /* 3) However, some sequences cannot be assigned a final level till */ + /* one or more following sequences are received. For instance, */ + /* ON following an R sequence within an even-level paragraph. */ + /* If the following sequence is R, the ON sequence will be */ + /* assigned basic run level+1, and so will the R sequence. */ + /* 4) S is generally handled like ON, since its level will be fixed */ + /* to paragraph level in adjustWSLevels(). */ + /* */ + + private static final byte impTabL_DEFAULT[][] = /* Even paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + { + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 1, 0, 2, 0, 0, 0, 0 }, /* 1 : R */ { 0, 1, 3, 3, 0x14, 0x14, 0, 1 }, + /* 2 : AN */ { 0, 1, 0, 2, 0x15, 0x15, 0, 2 }, /* 3 : R+EN/AN */ { 0, 1, 3, 3, 0x14, 0x14, 0, 2 }, + /* 4 : R+ON */ { 0, 0x21, 0x33, 0x33, 4, 4, 0, 0 }, + /* 5 : AN+ON */ { 0, 0x21, 0, 0x32, 5, 5, 0, 0 } }; + + private static final byte impTabR_DEFAULT[][] = /* Odd paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + { + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 2, 2, 0, 0, 0, 0 }, /* 1 : L */ { 1, 0, 1, 3, 0x14, 0x14, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 2, 2, 0, 0, 0, 1 }, /* 3 : L+AN */ { 1, 0, 1, 3, 5, 5, 0, 1 }, + /* 4 : L+ON */ { 0x21, 0, 0x21, 3, 4, 4, 0, 0 }, /* 5 : L+AN+ON */ { 1, 0, 1, 3, 5, 5, 0, 0 } }; + + private static final short[] impAct0 = { 0, 1, 2, 3, 4 }; + + private static final ImpTabPair impTab_DEFAULT = new ImpTabPair(impTabL_DEFAULT, impTabR_DEFAULT, impAct0, impAct0); + + private static final byte impTabL_NUMBERS_SPECIAL[][] = { /* Even paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 2, 0x11, 0x11, 0, 0, 0, 0 }, /* 1 : L+EN/AN */ { 0, 0x42, 1, 1, 0, 0, 0, 0 }, + /* 2 : R */ { 0, 2, 4, 4, 0x13, 0x13, 0, 1 }, /* 3 : R+ON */ { 0, 0x22, 0x34, 0x34, 3, 3, 0, 0 }, + /* 4 : R+EN/AN */ { 0, 2, 4, 4, 0x13, 0x13, 0, 2 } }; + private static final ImpTabPair impTab_NUMBERS_SPECIAL = new ImpTabPair(impTabL_NUMBERS_SPECIAL, impTabR_DEFAULT, + impAct0, impAct0); + + private static final byte impTabL_GROUP_NUMBERS_WITH_R[][] = { + /* + * In this table, EN/AN+ON sequences receive levels as if associated with R + * until proven that there is L or sor/eor on both sides. AN is handled like EN. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 init */ { 0, 3, 0x11, 0x11, 0, 0, 0, 0 }, /* 1 EN/AN */ { 0x20, 3, 1, 1, 2, 0x20, 0x20, 2 }, + /* 2 EN/AN+ON */ { 0x20, 3, 1, 1, 2, 0x20, 0x20, 1 }, /* 3 R */ { 0, 3, 5, 5, 0x14, 0, 0, 1 }, + /* 4 R+ON */ { 0x20, 3, 5, 5, 4, 0x20, 0x20, 1 }, /* 5 R+EN/AN */ { 0, 3, 5, 5, 0x14, 0, 0, 2 } }; + private static final byte impTabR_GROUP_NUMBERS_WITH_R[][] = { + /* + * In this table, EN/AN+ON sequences receive levels as if associated with R + * until proven that there is L on both sides. AN is handled like EN. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 init */ { 2, 0, 1, 1, 0, 0, 0, 0 }, /* 1 EN/AN */ { 2, 0, 1, 1, 0, 0, 0, 1 }, + /* 2 L */ { 2, 0, 0x14, 0x14, 0x13, 0, 0, 1 }, /* 3 L+ON */ { 0x22, 0, 4, 4, 3, 0, 0, 0 }, + /* 4 L+EN/AN */ { 0x22, 0, 4, 4, 3, 0, 0, 1 } }; + private static final ImpTabPair impTab_GROUP_NUMBERS_WITH_R = new ImpTabPair(impTabL_GROUP_NUMBERS_WITH_R, + impTabR_GROUP_NUMBERS_WITH_R, impAct0, impAct0); + + private static final byte impTabL_INVERSE_NUMBERS_AS_L[][] = { + /* + * This table is identical to the Default LTR table except that EN and AN are + * handled like L. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 1, 0, 0, 0, 0, 0, 0 }, /* 1 : R */ { 0, 1, 0, 0, 0x14, 0x14, 0, 1 }, + /* 2 : AN */ { 0, 1, 0, 0, 0x15, 0x15, 0, 2 }, /* 3 : R+EN/AN */ { 0, 1, 0, 0, 0x14, 0x14, 0, 2 }, + /* 4 : R+ON */ { 0x20, 1, 0x20, 0x20, 4, 4, 0x20, 1 }, + /* 5 : AN+ON */ { 0x20, 1, 0x20, 0x20, 5, 5, 0x20, 1 } }; + private static final byte impTabR_INVERSE_NUMBERS_AS_L[][] = { + /* + * This table is identical to the Default RTL table except that EN and AN are + * handled like L. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 1, 1, 0, 0, 0, 0 }, /* 1 : L */ { 1, 0, 1, 1, 0x14, 0x14, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 1, 1, 0, 0, 0, 1 }, /* 3 : L+AN */ { 1, 0, 1, 1, 5, 5, 0, 1 }, + /* 4 : L+ON */ { 0x21, 0, 0x21, 0x21, 4, 4, 0, 0 }, /* 5 : L+AN+ON */ { 1, 0, 1, 1, 5, 5, 0, 0 } }; + private static final ImpTabPair impTab_INVERSE_NUMBERS_AS_L = new ImpTabPair(impTabL_INVERSE_NUMBERS_AS_L, + impTabR_INVERSE_NUMBERS_AS_L, impAct0, impAct0); + + private static final byte impTabR_INVERSE_LIKE_DIRECT[][] = { /* Odd paragraph level */ + /* + * In this table, conditional sequences receive the lower possible level until + * proven otherwise. + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 1, 0, 2, 2, 0, 0, 0, 0 }, /* 1 : L */ { 1, 0, 1, 2, 0x13, 0x13, 0, 1 }, + /* 2 : EN/AN */ { 1, 0, 2, 2, 0, 0, 0, 1 }, /* 3 : L+ON */ { 0x21, 0x30, 6, 4, 3, 3, 0x30, 0 }, + /* 4 : L+ON+AN */ { 0x21, 0x30, 6, 4, 5, 5, 0x30, 3 }, + /* 5 : L+AN+ON */ { 0x21, 0x30, 6, 4, 5, 5, 0x30, 2 }, + /* 6 : L+ON+EN */ { 0x21, 0x30, 6, 4, 3, 3, 0x30, 1 } }; + private static final short[] impAct1 = { 0, 1, 13, 14 }; + private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT = new ImpTabPair(impTabL_DEFAULT, + impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); + + private static final byte impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = { + /* + * The case handled in this table is (visually): R EN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 0x63, 0, 1, 0, 0, 0, 0 }, /* 1 : L+AN */ { 0, 0x63, 0, 1, 0x12, 0x30, 0, 4 }, + /* 2 : L+AN+ON */ { 0x20, 0x63, 0x20, 1, 2, 0x30, 0x20, 3 }, + /* 3 : R */ { 0, 0x63, 0x55, 0x56, 0x14, 0x30, 0, 3 }, + /* 4 : R+ON */ { 0x30, 0x43, 0x55, 0x56, 4, 0x30, 0x30, 3 }, + /* 5 : R+EN */ { 0x30, 0x43, 5, 0x56, 0x14, 0x30, 0x30, 4 }, + /* 6 : R+AN */ { 0x30, 0x43, 0x55, 6, 0x14, 0x30, 0x30, 4 } }; + private static final byte impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = { + /* + * The cases handled in this table are (visually): R EN L R L AN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0x13, 0, 1, 1, 0, 0, 0, 0 }, /* 1 : R+EN/AN */ { 0x23, 0, 1, 1, 2, 0x40, 0, 1 }, + /* 2 : R+EN/AN+ON */ { 0x23, 0, 1, 1, 2, 0x40, 0, 0 }, /* 3 : L */ { 3, 0, 3, 0x36, 0x14, 0x40, 0, 1 }, + /* 4 : L+ON */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 0 }, + /* 5 : L+ON+EN */ { 0x53, 0x40, 5, 0x36, 4, 0x40, 0x40, 1 }, + /* 6 : L+AN */ { 0x53, 0x40, 6, 6, 4, 0x40, 0x40, 3 } }; + private static final short[] impAct2 = { 0, 1, 2, 5, 6, 7, 8 }; + private static final short[] impAct3 = { 0, 1, 9, 10, 11, 12 }; + private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS = new ImpTabPair( + impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS, impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); + + private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = new ImpTabPair(impTabL_NUMBERS_SPECIAL, + impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1); + + private static final byte impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS[][] = { + /* + * The case handled in this table is (visually): R EN L + */ + /* L, R, EN, AN, ON, S, B, Res */ + /* 0 : init */ { 0, 0x62, 1, 1, 0, 0, 0, 0 }, /* 1 : L+EN/AN */ { 0, 0x62, 1, 1, 0, 0x30, 0, 4 }, + /* 2 : R */ { 0, 0x62, 0x54, 0x54, 0x13, 0x30, 0, 3 }, + /* 3 : R+ON */ { 0x30, 0x42, 0x54, 0x54, 3, 0x30, 0x30, 3 }, + /* 4 : R+EN/AN */ { 0x30, 0x42, 4, 4, 0x13, 0x30, 0x30, 4 } }; + private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = new ImpTabPair( + impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS, impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3); + + private static class LevState { + byte[][] impTab; /* level table pointer */ + short[] impAct; /* action map array */ + int startON; /* start of ON sequence */ + int startL2EN; /* start of level 2 sequence */ + int lastStrongRTL; /* index of last found R or AL */ + int runStart; /* start position of the run */ + short state; /* current state */ + byte runLevel; /* run level before implicit solving */ + } + + /*------------------------------------------------------------------------*/ + + static final int FIRSTALLOC = 10; + + /* + * param pos: position where to insert param flag: one of LRM_BEFORE, LRM_AFTER, + * RLM_BEFORE, RLM_AFTER + */ + private void addPoint(int pos, int flag) { + Point point = new Point(); + + int len = insertPoints.points.length; + if (len == 0) { + insertPoints.points = new Point[FIRSTALLOC]; + len = FIRSTALLOC; + } + if (insertPoints.size >= len) { /* no room for new point */ + Point[] savePoints = insertPoints.points; + insertPoints.points = new Point[len * 2]; + System.arraycopy(savePoints, 0, insertPoints.points, 0, len); + } + point.pos = pos; + point.flag = flag; + insertPoints.points[insertPoints.size] = point; + insertPoints.size++; + } + + private void setLevelsOutsideIsolates(int start, int limit, byte level) { + byte dirProp; + int isolateCount = 0, k; + for (k = start; k < limit; k++) { + dirProp = dirProps[k]; + if (dirProp == PDI) + isolateCount--; + if (isolateCount == 0) { + levels[k] = level; + } + if (dirProp == LRI || dirProp == RLI) + isolateCount++; + } + } + + /* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */ + + /* + * This implementation of the (Wn) rules applies all rules in one pass. In order + * to do so, it needs a look-ahead of typically 1 character (except for W5: + * sequences of ET) and keeps track of changes in a rule Wp that affect a later + * Wq (p= 0) { + addPoint(levState.startL2EN, LRM_BEFORE); + } + levState.startL2EN = -1; /* not within previous if since could also be -2 */ + /* check if we had any relevant EN/AN after R/AL */ + if ((insertPoints.points.length == 0) || (insertPoints.size <= insertPoints.confirmed)) { + /* nothing, just clean up */ + levState.lastStrongRTL = -1; + /* check if we have a pending conditional segment */ + level = impTab[oldStateSeq][IMPTABLEVELS_RES]; + if ((level & 1) != 0 && levState.startON > 0) { /* after ON */ + start = levState.startON; /* reset to basic run level */ + } + if (_prop == _S) { /* add LRM before S */ + addPoint(start0, LRM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + } + /* reset previous RTL cont to level for LTR text */ + for (k = levState.lastStrongRTL + 1; k < start0; k++) { + /* reset odd level, leave runLevel+2 as is */ + levels[k] = (byte) ((levels[k] - 2) & ~1); + } + /* mark insert points as confirmed */ + insertPoints.confirmed = insertPoints.size; + levState.lastStrongRTL = -1; + if (_prop == _S) { /* add LRM before S */ + addPoint(start0, LRM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + + case 6: /* R/AL after possible relevant EN/AN */ + /* just clean up */ + if (insertPoints.points.length > 0) + /* remove all non confirmed insert points */ + insertPoints.size = insertPoints.confirmed; + levState.startON = -1; + levState.startL2EN = -1; + levState.lastStrongRTL = limit - 1; + break; + + case 7: /* EN/AN after R/AL + possible cont */ + /* check for real AN */ + + if ((_prop == _AN) && (dirProps[start0] == AN) + && (reorderingMode != REORDER_INVERSE_FOR_NUMBERS_SPECIAL)) { + /* real AN */ + if (levState.startL2EN == -1) { /* if no relevant EN already found */ + /* just note the rightmost digit as a strong RTL */ + levState.lastStrongRTL = limit - 1; + break; + } + if (levState.startL2EN >= 0) { /* after EN, no AN */ + addPoint(levState.startL2EN, LRM_BEFORE); + levState.startL2EN = -2; + } + /* note AN */ + addPoint(start0, LRM_BEFORE); + break; + } + /* if first EN/AN after R/AL */ + if (levState.startL2EN == -1) { + levState.startL2EN = start0; + } + break; + + case 8: /* note location of latest R/AL */ + levState.lastStrongRTL = limit - 1; + levState.startON = -1; + break; + + case 9: /* L after R+ON/EN/AN */ + /* include possible adjacent number on the left */ + for (k = start0 - 1; k >= 0 && ((levels[k] & 1) == 0); k--) { + } + if (k >= 0) { + addPoint(k, RLM_BEFORE); /* add RLM before */ + insertPoints.confirmed = insertPoints.size; /* confirm it */ + } + levState.startON = start0; + break; + + case 10: /* AN after L */ + /* AN numbers between L text on both sides may be trouble. */ + /* tentatively bracket with LRMs; will be confirmed if followed by L */ + addPoint(start0, LRM_BEFORE); /* add LRM before */ + addPoint(start0, LRM_AFTER); /* add LRM after */ + break; + + case 11: /* R after L+ON/EN/AN */ + /* false alert, infirm LRMs around previous AN */ + insertPoints.size = insertPoints.confirmed; + if (_prop == _S) { /* add RLM before S */ + addPoint(start0, RLM_BEFORE); + insertPoints.confirmed = insertPoints.size; + } + break; + + case 12: /* L after L+ON/AN */ + level = (byte) (levState.runLevel + addLevel); + for (k = levState.startON; k < start0; k++) { + if (levels[k] < level) { + levels[k] = level; + } + } + insertPoints.confirmed = insertPoints.size; /* confirm inserts */ + levState.startON = start0; + break; + + case 13: /* L after L+ON+EN/AN/ON */ + level = levState.runLevel; + for (k = start0 - 1; k >= levState.startON; k--) { + if (levels[k] == level + 3) { + while (levels[k] == level + 3) { + levels[k--] -= 2; + } + while (levels[k] == level) { + k--; + } + } + if (levels[k] == level + 2) { + levels[k] = level; + continue; + } + levels[k] = (byte) (level + 1); + } + break; + + case 14: /* R after L+ON+EN/AN/ON */ + level = (byte) (levState.runLevel + 1); + for (k = start0 - 1; k >= levState.startON; k--) { + if (levels[k] > level) { + levels[k] -= 2; + } + } + break; + + default: /* we should never get here */ + throw new IllegalStateException("Internal ICU error in processPropertySeq"); + } + } + if ((addLevel) != 0 || (start < start0)) { + level = (byte) (levState.runLevel + addLevel); + if (start >= levState.runStart) { + for (k = start; k < limit; k++) { + levels[k] = level; + } + } else { + setLevelsOutsideIsolates(start, limit, level); + } + } + } + + private void resolveImplicitLevels(int start, int limit, short sor, short eor) { + byte dirProp; + LevState levState = new LevState(); + int i, start1, start2; + short oldStateImp, stateImp, actionImp; + short gprop, resProp, cell; + boolean inverseRTL; + short nextStrongProp = R; + int nextStrongPos = -1; + + /* check for RTL inverse Bidi mode */ + /* + * FOOD FOR THOUGHT: in case of RTL inverse Bidi, it would make sense to loop on + * the text characters from end to start. This would need a different properties + * state table (at least different actions) and different levels state tables + * (maybe very similar to the LTR corresponding ones. + */ + inverseRTL = ((start < lastArabicPos) && ((GetParaLevelAt(start) & 1) > 0) + && (reorderingMode == REORDER_INVERSE_LIKE_DIRECT + || reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL)); + /* initialize for property and levels state table */ + levState.startL2EN = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ + levState.lastStrongRTL = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */ + levState.runStart = start; + levState.runLevel = levels[start]; + levState.impTab = impTabPair.imptab[levState.runLevel & 1]; + levState.impAct = impTabPair.impact[levState.runLevel & 1]; + + /* + * The isolates[] entries contain enough information to resume the bidi + * algorithm in the same state as it was when it was interrupted by an isolate + * sequence. + */ + if (dirProps[start] == PDI) { + levState.startON = isolates[isolateCount].startON; + start1 = isolates[isolateCount].start1; + stateImp = isolates[isolateCount].stateImp; + levState.state = isolates[isolateCount].state; + isolateCount--; + } else { + levState.startON = -1; + start1 = start; + if (dirProps[start] == NSM) + stateImp = (short) (1 + sor); + else + stateImp = 0; + levState.state = 0; + processPropertySeq(levState, sor, start, start); + } + start2 = start; /* to make the Java compiler happy */ + + for (i = start; i <= limit; i++) { + if (i >= limit) { + int k; + for (k = limit - 1; k > start && (DirPropFlag(dirProps[k]) & MASK_BN_EXPLICIT) != 0; k--) + ; + dirProp = dirProps[k]; + if (dirProp == LRI || dirProp == RLI) + break; /* no forced closing for sequence ending with LRI/RLI */ + gprop = eor; + } else { + byte prop, prop1; + prop = dirProps[i]; + if (prop == B) + isolateCount = -1; /* current isolates stack entry == none */ + if (inverseRTL) { + if (prop == AL) { + /* AL before EN does not make it AN */ + prop = R; + } else if (prop == EN) { + if (nextStrongPos <= i) { + /* look for next strong char (L/R/AL) */ + int j; + nextStrongProp = R; /* set default */ + nextStrongPos = limit; + for (j = i + 1; j < limit; j++) { + prop1 = dirProps[j]; + if (prop1 == L || prop1 == R || prop1 == AL) { + nextStrongProp = prop1; + nextStrongPos = j; + break; + } + } + } + if (nextStrongProp == AL) { + prop = AN; + } + } + } + gprop = groupProp[prop]; + } + oldStateImp = stateImp; + cell = impTabProps[oldStateImp][gprop]; + stateImp = GetStateProps(cell); /* isolate the new state */ + actionImp = GetActionProps(cell); /* isolate the action */ + if ((i == limit) && (actionImp == 0)) { + /* there is an unprocessed sequence if its property == eor */ + actionImp = 1; /* process the last sequence */ + } + if (actionImp != 0) { + resProp = impTabProps[oldStateImp][IMPTABPROPS_RES]; + switch (actionImp) { + case 1: /* process current seq1, init new seq1 */ + processPropertySeq(levState, resProp, start1, i); + start1 = i; + break; + case 2: /* init new seq2 */ + start2 = i; + break; + case 3: /* process seq1, process seq2, init new seq1 */ + processPropertySeq(levState, resProp, start1, start2); + processPropertySeq(levState, _ON, start2, i); + start1 = i; + break; + case 4: /* process seq1, set seq1=seq2, init new seq2 */ + processPropertySeq(levState, resProp, start1, start2); + start1 = start2; + start2 = i; + break; + default: /* we should never get here */ + throw new IllegalStateException("Internal ICU error in resolveImplicitLevels"); + } + } + } + + /* look for the last char not a BN or LRE/RLE/LRO/RLO/PDF */ + for (i = limit - 1; i > start && (DirPropFlag(dirProps[i]) & MASK_BN_EXPLICIT) != 0; i--) + ; + dirProp = dirProps[i]; + if ((dirProp == LRI || dirProp == RLI) && limit < length) { + isolateCount++; + if (isolates[isolateCount] == null) + isolates[isolateCount] = new Isolate(); + isolates[isolateCount].stateImp = stateImp; + isolates[isolateCount].state = levState.state; + isolates[isolateCount].start1 = start1; + isolates[isolateCount].startON = levState.startON; + } else + processPropertySeq(levState, eor, limit, limit); + } + + /* perform (L1) and (X9) ---------------------------------------------------- */ + + /* + * Reset the embedding levels for some non-graphic characters (L1). This method + * also sets appropriate levels for BN, and explicit embedding types that are + * supposed to have been removed from the paragraph in (X9). + */ + private void adjustWSLevels() { + int i; + + if ((flags & MASK_WS) != 0) { + int flag; + i = trailingWSStart; + while (i > 0) { + /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */ + while (i > 0 && ((flag = DirPropFlag(dirProps[--i])) & MASK_WS) != 0) { + if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { + levels[i] = 0; + } else { + levels[i] = GetParaLevelAt(i); + } + } + + /* + * reset BN to the next character's paraLevel until B/S, which restarts above + * loop + */ + /* here, i+1 is guaranteed to be 0) { + flag = DirPropFlag(dirProps[--i]); + if ((flag & MASK_BN_EXPLICIT) != 0) { + levels[i] = levels[i + 1]; + } else if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) { + levels[i] = 0; + break; + } else if ((flag & MASK_B_S) != 0) { + levels[i] = GetParaLevelAt(i); + break; + } + } + } + } + } + + private void setParaSuccess() { + paraBidi = this; /* mark successful setPara */ + } + + private int Bidi_Min(int x, int y) { + return x < y ? x : y; + } + + private int Bidi_Abs(int x) { + return x >= 0 ? x : -x; + } + + void setParaRunsOnly(char[] parmText, byte parmParaLevel) { + int[] visualMap; + String visualText; + int saveLength, saveTrailingWSStart; + byte[] saveLevels; + byte saveDirection; + int i, j, visualStart, logicalStart, oldRunCount, runLength, addedRuns, insertRemove, start, limit, step, + indexOddBit, logicalPos, index, index1; + int saveOptions; + + reorderingMode = REORDER_DEFAULT; + int parmLength = parmText.length; + if (parmLength == 0) { + setPara(parmText, parmParaLevel, null); + reorderingMode = REORDER_RUNS_ONLY; + return; + } + /* obtain memory for mapping table and visual text */ + saveOptions = reorderingOptions; + if ((saveOptions & OPTION_INSERT_MARKS) > 0) { + reorderingOptions &= ~OPTION_INSERT_MARKS; + reorderingOptions |= OPTION_REMOVE_CONTROLS; + } + parmParaLevel &= 1; /* accept only 0 or 1 */ + setPara(parmText, parmParaLevel, null); + /* + * we cannot access directly levels since it is not yet set if direction is not + * MIXED + */ + saveLevels = new byte[this.length]; + System.arraycopy(getLevels(), 0, saveLevels, 0, this.length); + saveTrailingWSStart = trailingWSStart; + + /* + * FOOD FOR THOUGHT: instead of writing the visual text, we could use the visual + * map and the dirProps array to drive the second call to setPara (but must make + * provision for possible removal of Bidi controls. Alternatively, only use the + * dirProps array via customized classifier callback. + */ + visualText = writeReordered(DO_MIRRORING); + visualMap = getVisualMap(); + this.reorderingOptions = saveOptions; + saveLength = this.length; + saveDirection = this.direction; + + this.reorderingMode = REORDER_INVERSE_LIKE_DIRECT; + parmParaLevel ^= 1; + setPara(visualText, parmParaLevel, null); + BidiLine.getRuns(this); + /* check if some runs must be split, count how many splits */ + addedRuns = 0; + oldRunCount = this.runCount; + visualStart = 0; + for (i = 0; i < oldRunCount; i++, visualStart += runLength) { + runLength = runs[i].limit - visualStart; + if (runLength < 2) { + continue; + } + logicalStart = runs[i].start; + for (j = logicalStart + 1; j < logicalStart + runLength; j++) { + index = visualMap[j]; + index1 = visualMap[j - 1]; + if ((Bidi_Abs(index - index1) != 1) || (saveLevels[index] != saveLevels[index1])) { + addedRuns++; + } + } + } + if (addedRuns > 0) { + getRunsMemory(oldRunCount + addedRuns); + if (runCount == 1) { + /* because we switch from UBiDi.simpleRuns to UBiDi.runs */ + runsMemory[0] = runs[0]; + } else { + System.arraycopy(runs, 0, runsMemory, 0, runCount); + } + runs = runsMemory; + runCount += addedRuns; + for (i = oldRunCount; i < runCount; i++) { + if (runs[i] == null) { + runs[i] = new BidiRun(0, 0, (byte) 0); + } + } + } + /* split runs which are not consecutive in source text */ + int newI; + for (i = oldRunCount - 1; i >= 0; i--) { + newI = i + addedRuns; + runLength = i == 0 ? runs[0].limit : runs[i].limit - runs[i - 1].limit; + logicalStart = runs[i].start; + indexOddBit = runs[i].level & 1; + if (runLength < 2) { + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = visualMap[logicalStart]; + runs[newI].start = logicalPos; + runs[newI].level = (byte) (saveLevels[logicalPos] ^ indexOddBit); + continue; + } + if (indexOddBit > 0) { + start = logicalStart; + limit = logicalStart + runLength - 1; + step = 1; + } else { + start = logicalStart + runLength - 1; + limit = logicalStart; + step = -1; + } + for (j = start; j != limit; j += step) { + index = visualMap[j]; + index1 = visualMap[j + step]; + if ((Bidi_Abs(index - index1) != 1) || (saveLevels[index] != saveLevels[index1])) { + logicalPos = Bidi_Min(visualMap[start], index); + runs[newI].start = logicalPos; + runs[newI].level = (byte) (saveLevels[logicalPos] ^ indexOddBit); + runs[newI].limit = runs[i].limit; + runs[i].limit -= Bidi_Abs(j - start) + 1; + insertRemove = runs[i].insertRemove & (LRM_AFTER | RLM_AFTER); + runs[newI].insertRemove = insertRemove; + runs[i].insertRemove &= ~insertRemove; + start = j + step; + addedRuns--; + newI--; + } + } + if (addedRuns > 0) { + runs[newI].copyFrom(runs[i]); + } + logicalPos = Bidi_Min(visualMap[start], visualMap[limit]); + runs[newI].start = logicalPos; + runs[newI].level = (byte) (saveLevels[logicalPos] ^ indexOddBit); + } + + cleanup1: + /* restore initial paraLevel */ + this.paraLevel ^= 1; + cleanup2: + /* restore real text */ + this.text = parmText; + this.length = saveLength; + this.originalLength = parmLength; + this.direction = saveDirection; + this.levels = saveLevels; + this.trailingWSStart = saveTrailingWSStart; + if (runCount > 1) { + this.direction = MIXED; + } + cleanup3: this.reorderingMode = REORDER_RUNS_ONLY; + } + + /** + * Perform the Unicode Bidi algorithm. It is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, also described in The + * Unicode Standard, Version 4.0 . + *

+ * + * This method takes a piece of plain text containing one or more paragraphs, + * with or without externally specified embedding levels from styled text + * and computes the left-right-directionality of each character. + *

+ * + * If the entire text is all of the same directionality, then the method may not + * perform all the steps described by the algorithm, i.e., some levels may not + * be the same as if all steps were performed. This is not relevant for + * unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get a resolved + * level of 2 higher than the surrounding text according to the algorithm. This + * implementation may set all resolved levels to the same value in such a case. + *

+ * + * The text can be composed of multiple paragraphs. Occurrence of a block + * separator in the text terminates a paragraph, and whatever comes next starts + * a new paragraph. The exception to this rule is when a Carriage Return (CR) is + * followed by a Line Feed (LF). Both CR and LF are block separators, but in + * that case, the pair of characters is considered as terminating the preceding + * paragraph, and a new paragraph will be started by a character coming after + * the LF. + * + * Although the text is passed here as a String, it is stored + * internally as an array of characters. Therefore the documentation will refer + * to indexes of the characters in the text. + * + * @param text contains the text that the Bidi algorithm will be + * performed on. This text can be retrieved with + * getText() or + * getTextAsString.
+ * + * @param paraLevel specifies the default level for the text; it is + * typically 0 (LTR) or 1 (RTL). If the method shall + * determine the paragraph level from the text, then + * paraLevel can be set to either + * LEVEL_DEFAULT_LTR or + * LEVEL_DEFAULT_RTL; if the text contains + * multiple paragraphs, the paragraph level shall be + * determined separately for each paragraph; if a + * paragraph does not include any strongly typed + * character, then the desired default is used (0 for LTR + * or 1 for RTL). Any other value between 0 and + * MAX_EXPLICIT_LEVEL is also valid, with + * odd levels indicating RTL. + * + * @param embeddingLevels (in) may be used to preset the embedding and override + * levels, ignoring characters like LRE and PDF in the + * text. A level overrides the directional property of + * its corresponding (same index) character if the level + * has the LEVEL_OVERRIDE bit set.
+ *
+ * Except for that bit, it must be + * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL, + * with one exception: a level of zero may be specified + * for a paragraph separator even if + * paraLevel>0 when multiple paragraphs + * are submitted in the same call to + * setPara().
+ *
+ * Caution: A reference to this array, + * not a copy of the levels, will be stored in the + * Bidi object; the + * embeddingLevels should not be modified to + * avoid unexpected results on subsequent Bidi + * operations. However, the setPara() and + * setLine() methods may modify some or all + * of the levels.
+ *
+ * Note: the + * embeddingLevels array must have one entry + * for each character in text. + * + * @throws IllegalArgumentException if the values in embeddingLevels are not + * within the allowed range + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #LEVEL_OVERRIDE + * @see #MAX_EXPLICIT_LEVEL + * @stable ICU 3.8 + */ + void setPara(String text, byte paraLevel, byte[] embeddingLevels) { + if (text == null) { + setPara(new char[0], paraLevel, embeddingLevels); + } else { + setPara(text.toCharArray(), paraLevel, embeddingLevels); + } + } + + /** + * Perform the Unicode Bidi algorithm. It is defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, also described in The + * Unicode Standard, Version 4.0 . + *

+ * + * This method takes a piece of plain text containing one or more paragraphs, + * with or without externally specified embedding levels from styled text + * and computes the left-right-directionality of each character. + *

+ * + * If the entire text is all of the same directionality, then the method may not + * perform all the steps described by the algorithm, i.e., some levels may not + * be the same as if all steps were performed. This is not relevant for + * unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get a resolved + * level of 2 higher than the surrounding text according to the algorithm. This + * implementation may set all resolved levels to the same value in such a case. + * + * The text can be composed of multiple paragraphs. Occurrence of a block + * separator in the text terminates a paragraph, and whatever comes next starts + * a new paragraph. The exception to this rule is when a Carriage Return (CR) is + * followed by a Line Feed (LF). Both CR and LF are block separators, but in + * that case, the pair of characters is considered as terminating the preceding + * paragraph, and a new paragraph will be started by a character coming after + * the LF. + * + * The text is stored internally as an array of characters. Therefore the + * documentation will refer to indexes of the characters in the text. + * + * @param chars contains the text that the Bidi algorithm will be + * performed on. This text can be retrieved with + * getText() or + * getTextAsString.
+ * + * @param paraLevel specifies the default level for the text; it is + * typically 0 (LTR) or 1 (RTL). If the method shall + * determine the paragraph level from the text, then + * paraLevel can be set to either + * LEVEL_DEFAULT_LTR or + * LEVEL_DEFAULT_RTL; if the text contains + * multiple paragraphs, the paragraph level shall be + * determined separately for each paragraph; if a + * paragraph does not include any strongly typed + * character, then the desired default is used (0 for LTR + * or 1 for RTL). Any other value between 0 and + * MAX_EXPLICIT_LEVEL is also valid, with + * odd levels indicating RTL. + * + * @param embeddingLevels (in) may be used to preset the embedding and override + * levels, ignoring characters like LRE and PDF in the + * text. A level overrides the directional property of + * its corresponding (same index) character if the level + * has the LEVEL_OVERRIDE bit set.
+ *
+ * Except for that bit, it must be + * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL, + * with one exception: a level of zero may be specified + * for a paragraph separator even if + * paraLevel>0 when multiple paragraphs + * are submitted in the same call to + * setPara().
+ *
+ * Caution: A reference to this array, + * not a copy of the levels, will be stored in the + * Bidi object; the + * embeddingLevels should not be modified to + * avoid unexpected results on subsequent Bidi + * operations. However, the setPara() and + * setLine() methods may modify some or all + * of the levels.
+ *
+ * Note: the + * embeddingLevels array must have one entry + * for each character in text. + * + * @throws IllegalArgumentException if the values in embeddingLevels are not + * within the allowed range + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #LEVEL_OVERRIDE + * @see #MAX_EXPLICIT_LEVEL + * @stable ICU 3.8 + */ + void setPara(char[] chars, byte paraLevel, byte[] embeddingLevels) { + /* check the argument values */ + if (paraLevel < LEVEL_DEFAULT_LTR) { + verifyRange(paraLevel, 0, MAX_EXPLICIT_LEVEL + 1); + } + if (chars == null) { + chars = new char[0]; + } + + /* special treatment for RUNS_ONLY mode */ + if (reorderingMode == REORDER_RUNS_ONLY) { + setParaRunsOnly(chars, paraLevel); + return; + } + + /* initialize the Bidi object */ + this.paraBidi = null; /* mark unfinished setPara */ + this.text = chars; + this.length = this.originalLength = this.resultLength = text.length; + this.paraLevel = paraLevel; + this.direction = (byte) (paraLevel & 1); + this.paraCount = 1; + + /* + * Allocate zero-length arrays instead of setting to null here; then checks for + * null in various places can be eliminated. + */ + dirProps = new byte[0]; + levels = new byte[0]; + runs = new BidiRun[0]; + isGoodLogicalToVisualRunsMap = false; + insertPoints.size = 0; /* clean up from last call */ + insertPoints.confirmed = 0; /* clean up from last call */ + + /* + * Save the original paraLevel if contextual; otherwise, set to 0. + */ + defaultParaLevel = IsDefaultLevel(paraLevel) ? paraLevel : 0; + + if (length == 0) { + /* + * For an empty paragraph, create a Bidi object with the paraLevel and the flags + * and the direction set but without allocating zero-length arrays. There is + * nothing more to do. + */ + if (IsDefaultLevel(paraLevel)) { + this.paraLevel &= 1; + defaultParaLevel = 0; + } + flags = DirPropFlagLR(paraLevel); + runCount = 0; + paraCount = 0; + setParaSuccess(); + return; + } + + runCount = -1; + + /* + * Get the directional properties, the flags bit-set, and determine the + * paragraph level if necessary. + */ + getDirPropsMemory(length); + dirProps = dirPropsMemory; + getDirProps(); + /* the processed length may have changed if OPTION_STREAMING is set */ + trailingWSStart = length; /* the levels[] will reflect the WS run */ + + /* are explicit levels specified? */ + if (embeddingLevels == null) { + /* no: determine explicit levels according to the (Xn) rules */ + getLevelsMemory(length); + levels = levelsMemory; + direction = resolveExplicitLevels(); + } else { + /* + * set BN for all explicit codes, check that all levels are 0 or + * paraLevel..MAX_EXPLICIT_LEVEL + */ + levels = embeddingLevels; + direction = checkExplicitLevels(); + } + + /* allocate isolate memory */ + if (isolateCount > 0) { + if (isolates == null || isolates.length < isolateCount) + isolates = new Isolate[isolateCount + 3]; /* keep some reserve */ + } + isolateCount = -1; /* current isolates stack entry == none */ + + /* + * The steps after (X9) in the Bidi algorithm are performed only if the + * paragraph text has mixed directionality! + */ + switch (direction) { + case LTR: + /* all levels are implicitly at paraLevel (important for getLevels()) */ + trailingWSStart = 0; + break; + case RTL: + /* all levels are implicitly at paraLevel (important for getLevels()) */ + trailingWSStart = 0; + break; + default: + /* + * Choose the right implicit state table + */ + switch (reorderingMode) { + case REORDER_DEFAULT: + this.impTabPair = impTab_DEFAULT; + break; + case REORDER_NUMBERS_SPECIAL: + this.impTabPair = impTab_NUMBERS_SPECIAL; + break; + case REORDER_GROUP_NUMBERS_WITH_R: + this.impTabPair = impTab_GROUP_NUMBERS_WITH_R; + break; + case REORDER_RUNS_ONLY: + /* we should never get here */ + throw new InternalError("Internal ICU error in setPara"); + /* break; */ + case REORDER_INVERSE_NUMBERS_AS_L: + this.impTabPair = impTab_INVERSE_NUMBERS_AS_L; + break; + case REORDER_INVERSE_LIKE_DIRECT: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_LIKE_DIRECT; + } + break; + case REORDER_INVERSE_FOR_NUMBERS_SPECIAL: + if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS; + } else { + this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL; + } + break; + } + /* + * If there are no external levels specified and there are no significant + * explicit level codes in the text, then we can treat the entire paragraph as + * one run. Otherwise, we need to perform the following rules on runs of the + * text with the same embedding levels. (X10) "Significant" explicit level codes + * are ones that actually affect non-BN characters. Examples for "insignificant" + * ones are empty embeddings LRE-PDF, LRE-RLE-PDF-PDF, etc. + */ + if (embeddingLevels == null && paraCount <= 1 && (flags & DirPropFlagMultiRuns) == 0) { + resolveImplicitLevels(0, length, GetLRFromLevel(GetParaLevelAt(0)), + GetLRFromLevel(GetParaLevelAt(length - 1))); + } else { + /* sor, eor: start and end types of same-level-run */ + int start, limit = 0; + byte level, nextLevel; + short sor, eor; + + /* + * determine the first sor and set eor to it because of the loop body (sor=eor + * there) + */ + level = GetParaLevelAt(0); + nextLevel = levels[0]; + if (level < nextLevel) { + eor = GetLRFromLevel(nextLevel); + } else { + eor = GetLRFromLevel(level); + } + + do { + /* determine start and limit of the run (end points just behind the run) */ + + /* the values for this run's start are the same as for the previous run's end */ + start = limit; + level = nextLevel; + if ((start > 0) && (dirProps[start - 1] == B)) { + /* except if this is a new paragraph, then set sor = para level */ + sor = GetLRFromLevel(GetParaLevelAt(start)); + } else { + sor = eor; + } + + /* search for the limit of this run */ + while ((++limit < length) + && ((levels[limit] == level) || ((DirPropFlag(dirProps[limit]) & MASK_BN_EXPLICIT) != 0))) { + } + + /* get the correct level of the next run */ + if (limit < length) { + nextLevel = levels[limit]; + } else { + nextLevel = GetParaLevelAt(length - 1); + } + + /* determine eor from max(level, nextLevel); sor is last run's eor */ + if (NoOverride(level) < NoOverride(nextLevel)) { + eor = GetLRFromLevel(nextLevel); + } else { + eor = GetLRFromLevel(level); + } + + /* + * if the run consists of overridden directional types, then there are no + * implicit types to be resolved + */ + if ((level & LEVEL_OVERRIDE) == 0) { + resolveImplicitLevels(start, limit, sor, eor); + } else { + /* remove the LEVEL_OVERRIDE flags */ + do { + levels[start++] &= ~LEVEL_OVERRIDE; + } while (start < limit); + } + } while (limit < length); + } + + /* reset the embedding levels for some non-graphic characters (L1), (X9) */ + adjustWSLevels(); + + break; + } + + /* + * add RLM for inverse Bidi with contextual orientation resolving to RTL which + * would not round-trip otherwise + */ + if ((defaultParaLevel > 0) && ((reorderingOptions & OPTION_INSERT_MARKS) != 0) + && ((reorderingMode == REORDER_INVERSE_LIKE_DIRECT) + || (reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) { + int start, last; + byte level; + byte dirProp; + for (int i = 0; i < paraCount; i++) { + last = paras_limit[i] - 1; + level = paras_level[i]; + if (level == 0) + continue; /* LTR paragraph */ + start = i == 0 ? 0 : paras_limit[i - 1]; + for (int j = last; j >= start; j--) { + dirProp = dirProps[j]; + if (dirProp == L) { + if (j < last) { + while (dirProps[last] == B) { + last--; + } + } + addPoint(last, RLM_BEFORE); + break; + } + if ((DirPropFlag(dirProp) & MASK_R_AL) != 0) { + break; + } + } + } + } + + if ((reorderingOptions & OPTION_REMOVE_CONTROLS) != 0) { + resultLength -= controlCount; + } else { + resultLength += insertPoints.size; + } + setParaSuccess(); + } + + /** + * Perform the Unicode Bidi algorithm on a given paragraph, as defined in the + * Unicode Standard Annex #9: + * Unicode Bidirectional Algorithm, version 13, also described in The + * Unicode Standard, Version 4.0 . + *

+ * + * This method takes a paragraph of text and computes the + * left-right-directionality of each character. The text should not contain any + * Unicode block separators. + *

+ * + * The RUN_DIRECTION attribute in the text, if present, determines the base + * direction (left-to-right or right-to-left). If not present, the base + * direction is computed using the Unicode Bidirectional Algorithm, defaulting + * to left-to-right if there are no strong directional characters in the text. + * This attribute, if present, must be applied to all the text in the paragraph. + *

+ * + * The BIDI_EMBEDDING attribute in the text, if present, represents embedding + * level information. Negative values from -1 to -62 indicate overrides at the + * absolute value of the level. Positive values from 1 to 62 indicate + * embeddings. Where values are zero or not defined, the base embedding level as + * determined by the base direction is assumed. + *

+ * + * The NUMERIC_SHAPING attribute in the text, if present, converts European + * digits to other decimal digits before running the bidi algorithm. This + * attribute, if present, must be applied to all the text in the paragraph. + * + * If the entire text is all of the same directionality, then the method may not + * perform all the steps described by the algorithm, i.e., some levels may not + * be the same as if all steps were performed. This is not relevant for + * unidirectional text.
+ * For example, in pure LTR text with numbers the numbers would get a resolved + * level of 2 higher than the surrounding text according to the algorithm. This + * implementation may set all resolved levels to the same value in such a case. + *

+ * + * @param paragraph a paragraph of text with optional character and paragraph + * attribute information + * @stable ICU 3.8 + */ + public void setPara(AttributedCharacterIterator paragraph) { + byte paraLvl; + char ch = paragraph.first(); + Boolean runDirection = (Boolean) paragraph.getAttribute(TextAttribute.RUN_DIRECTION); + Object shaper = paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING); + + if (runDirection == null) { + paraLvl = LEVEL_DEFAULT_LTR; + } else { + paraLvl = (runDirection.equals(TextAttribute.RUN_DIRECTION_LTR)) ? LTR : RTL; + } + + byte[] lvls = null; + int len = paragraph.getEndIndex() - paragraph.getBeginIndex(); + byte[] embeddingLevels = new byte[len]; + char[] txt = new char[len]; + int i = 0; + while (ch != AttributedCharacterIterator.DONE) { + txt[i] = ch; + Integer embedding = (Integer) paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING); + if (embedding != null) { + byte level = embedding.byteValue(); + if (level == 0) { + /* no-op */ + } else if (level < 0) { + lvls = embeddingLevels; + embeddingLevels[i] = (byte) ((0 - level) | LEVEL_OVERRIDE); + } else { + lvls = embeddingLevels; + embeddingLevels[i] = level; + } + } + ch = paragraph.next(); + ++i; + } + + if (shaper != null) { + ((NumericShaper) shaper).shape(txt, 0, len); + } + setPara(txt, paraLvl, lvls); + } + + /** + * Specify whether block separators must be allocated level zero, so that + * successive paragraphs will progress from left to right. This method must be + * called before setPara(). Paragraph separators (B) may appear in + * the text. Setting them to level zero means that all paragraph separators + * (including one possibly appearing in the last text position) are kept in the + * reordered text after the text that they follow in the source text. When this + * feature is not enabled, a paragraph separator at the last position of the + * text before reordering will go to the first position of the reordered text + * when the paragraph level is odd. + * + * @param ordarParaLTR specifies whether paragraph separators (B) must receive + * level 0, so that successive paragraphs progress from left + * to right. + * + * @see #setPara + * @stable ICU 3.8 + */ + public void orderParagraphsLTR(boolean ordarParaLTR) { + orderParagraphsLTR = ordarParaLTR; + } + + /** + * Get the directionality of the text. + * + * @return a value of LTR, RTL or MIXED + * that indicates if the entire text represented by this object is + * unidirectional, and which direction, or if it is mixed-directional. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #LTR + * @see #RTL + * @see #MIXED + * @stable ICU 3.8 + */ + public byte getDirection() { + verifyValidParaOrLine(); + return direction; + } + + /** + * Get the length of the text. + * + * @return The length of the text that the Bidi object was created + * for. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @stable ICU 3.8 + */ + public int getLength() { + verifyValidParaOrLine(); + return originalLength; + } + + /* paragraphs API methods ------------------------------------------------- */ + + /** + * Get the paragraph level of the text. + * + * @return The paragraph level. If there are multiple paragraphs, their level + * may vary if the required paraLevel is LEVEL_DEFAULT_LTR or + * LEVEL_DEFAULT_RTL. In that case, the level of the first paragraph is + * returned. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #LEVEL_DEFAULT_LTR + * @see #LEVEL_DEFAULT_RTL + * @see #getParagraph + * @see #getParagraphByIndex + * @stable ICU 3.8 + */ + public byte getParaLevel() { + verifyValidParaOrLine(); + return paraLevel; + } + + /** + * Retrieves the Bidi class for a given code point. + *

+ * If a BidiClassifier is defined and returns a value other than + * CLASS_DEFAULT, that value is used; otherwise the default class + * determination mechanism is invoked. + *

+ * + * @param c The code point to get a Bidi class for. + * + * @return The Bidi class for the character c that is in effect for + * this Bidi instance. + * + * @stable ICU 3.8 + */ + public int getCustomizedClass(int c) { + int dir; + + dir = bdp.getClass(c); + if (dir >= CHAR_DIRECTION_COUNT) + dir = ON; + return dir; + } + + /** + * setLine() returns a Bidi object to contain the + * reordering information, especially the resolved levels, for all the + * characters in a line of text. This line of text is specified by referring to + * a Bidi object representing this information for a piece of text + * containing one or more paragraphs, and by specifying a range of indexes in + * this text. + *

+ * In the new line object, the indexes will range from 0 to + * limit-start-1. + *

+ * + * This is used after calling setPara() for a piece of text, and + * after line-breaking on that text. It is not necessary if each paragraph is + * treated as a single line. + *

+ * + * After line-breaking, rules (L1) and (L2) for the treatment of trailing WS and + * for reordering are performed on a Bidi object that represents a + * line. + *

+ * + * Important: the line Bidi object may reference + * data within the global text Bidi object. You should not alter + * the content of the global text object until you are finished using the line + * object. + * + * @param start is the line's first index into the text. + * + * @param limit is just behind the line's last index into the text (its last + * index +1). + * + * @return a Bidi object that will now represent a line of the + * text. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @throws IllegalArgumentException if start and limit are not in the range + * 0<=start<limit<=getProcessedLength(), + * or if the specified line crosses a paragraph + * boundary + * + * @see #setPara + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public Bidi setLine(Bidi bidi, BidiBase bidiBase, Bidi newBidi, BidiBase newBidiBase, int start, int limit) { + verifyValidPara(); + verifyRange(start, 0, limit); + verifyRange(limit, 0, length + 1); + + return BidiLine.setLine(this, newBidi, newBidiBase, start, limit); + } + + /** + * Get the level for one character. + * + * @param charIndex the index of a character. + * + * @return The level for the character at charIndex. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if charIndex is not in the range + * 0<=charIndex<getProcessedLength() + * + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public byte getLevelAt(int charIndex) { + // for backward compatibility + if (charIndex < 0 || charIndex >= length) { + return (byte) getBaseLevel(); + } + + verifyValidParaOrLine(); + verifyRange(charIndex, 0, length); + return BidiLine.getLevelAt(this, charIndex); + } + + /** + * Get an array of levels for each character. + *

+ * + * Note that this method may allocate memory under some circumstances, unlike + * getLevelAt(). + * + * @return The levels array for the text, or null if an error + * occurs. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @stable ICU 3.8 + */ + byte[] getLevels() { + verifyValidParaOrLine(); + if (length <= 0) { + return new byte[0]; + } + return BidiLine.getLevels(this); + } + + /** + * Get the number of runs. This method may invoke the actual reordering on the + * Bidi object, after setPara() may have resolved only + * the levels of the text. Therefore, countRuns() may have to + * allocate memory, and may throw an exception if it fails to do so. + * + * @return The number of runs. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @stable ICU 3.8 + */ + public int countRuns() { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + return runCount; + } + + /** + * + * Get a BidiRun object according to its index. BidiRun methods may + * be used to retrieve the run's logical start, length and level, which can be + * even for an LTR run or odd for an RTL run. In an RTL run, the character at + * the logical start is visually on the right of the displayed run. The length + * is the number of characters in the run. + *

+ * countRuns() is normally called before the runs are retrieved. + * + *

+ * Example: + * + *

+	 * Bidi bidi = new Bidi();
+	 * String text = "abc 123 DEFG xyz";
+	 * bidi.setPara(text, Bidi.RTL, null);
+	 * int i, count = bidi.countRuns(), logicalStart, visualIndex = 0, length;
+	 * BidiRun run;
+	 * for (i = 0; i < count; ++i) {
+	 * 	run = bidi.getVisualRun(i);
+	 * 	logicalStart = run.getStart();
+	 * 	length = run.getLength();
+	 * 	if (Bidi.LTR == run.getEmbeddingLevel()) {
+	 * 		do { // LTR
+	 * 			show_char(text.charAt(logicalStart++), visualIndex++);
+	 * 		} while (--length > 0);
+	 * 	} else {
+	 * 		logicalStart += length; // logicalLimit
+	 * 		do { // RTL
+	 * 			show_char(text.charAt(--logicalStart), visualIndex++);
+	 * 		} while (--length > 0);
+	 * 	}
+	 * }
+	 * 
+ *

+ * Note that in right-to-left runs, code like this places second surrogates + * before first ones (which is generally a bad idea) and combining characters + * before base characters. + *

+ * Use of {@link #writeReordered}, optionally with the + * {@link #KEEP_BASE_COMBINING} option, can be considered in order + * to avoid these issues. + * + * @param runIndex is the number of the run in visual order, in the range + * [0..countRuns()-1]. + * + * @return a BidiRun object containing the details of the run. The + * directionality of the run is LTR==0 or + * RTL==1, never MIXED. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if runIndex is not in the range + * 0<=runIndex<countRuns() + * + * @see #countRuns() + * @see com.ibm.icu.text.BidiRun + * @see com.ibm.icu.text.BidiRun#getStart() + * @see com.ibm.icu.text.BidiRun#getLength() + * @see com.ibm.icu.text.BidiRun#getEmbeddingLevel() + * @stable ICU 3.8 + */ + BidiRun getVisualRun(int runIndex) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + verifyRange(runIndex, 0, runCount); + return BidiLine.getVisualRun(this, runIndex); + } + + /** + * Get a visual-to-logical index map (array) for the characters in the + * Bidi (paragraph or line) object. + *

+ * Some values in the map may be MAP_NOWHERE if the corresponding + * text characters are Bidi marks inserted in the visual output by the option + * OPTION_INSERT_MARKS. + *

+ * When the visual output is altered by using options of + * writeReordered() such as INSERT_LRM_FOR_NUMERIC, + * KEEP_BASE_COMBINING, OUTPUT_REVERSE, + * REMOVE_BIDI_CONTROLS, the logical positions returned may not be + * correct. It is advised to use, when possible, reordering options such as + * {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}. + * + * @return an array of getResultLength() indexes which will reflect + * the reordering of the characters.
+ *
+ * The index map will result in + * indexMap[visualIndex]==logicalIndex, where + * indexMap represents the returned array. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #getLogicalMap + * @see #getLogicalIndex + * @see #getResultLength + * @see #MAP_NOWHERE + * @see #OPTION_INSERT_MARKS + * @see #writeReordered + * @stable ICU 3.8 + */ + private int[] getVisualMap() { + /* countRuns() checks successful call to setPara/setLine */ + countRuns(); + if (resultLength <= 0) { + return new int[0]; + } + return BidiLine.getVisualMap(this); + } + + /** + * This is a convenience method that does not use a Bidi object. It + * is intended to be used for when an application has determined the levels of + * objects (character sequences) and just needs to have them reordered (L2). + * This is equivalent to using getVisualMap() on a + * Bidi object. + * + * @param levels is an array of levels that have been determined by the + * application. + * + * @return an array of levels.length indexes which will reflect the + * reordering of the characters. + *

+ * The index map will result in + * indexMap[visualIndex]==logicalIndex, where + * indexMap represents the returned array. + * + * @stable ICU 3.8 + */ + private static int[] reorderVisual(byte[] levels) { + return BidiLine.reorderVisual(levels); + } + + /** + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, the base direction + * is right-to-left. + * + * @stable ICU 3.8 + */ + public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = LEVEL_DEFAULT_RTL; + + /** + * Create Bidi from the given text, embedding, and direction information. The + * embeddings array may be null. If present, the values represent embedding + * level information. Negative values from -1 to -61 indicate overrides at the + * absolute value of the level. Positive values from 1 to 61 indicate + * embeddings. Where values are zero, the base embedding level as determined by + * the base direction is assumed. + *

+ * + * Note: this constructor calls setPara() internally. + * + * @param text an array containing the paragraph of text to process. + * @param textStart the index into the text array of the start of the + * paragraph. + * @param embeddings an array containing embedding values for each + * character in the paragraph. This can be null, in which + * case it is assumed that there is no external embedding + * information. + * @param embStart the index into the embedding array of the start of the + * paragraph. + * @param paragraphLength the length of the paragraph in the text and embeddings + * arrays. + * @param flags a collection of flags that control the algorithm. The + * algorithm understands the flags + * DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT, + * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and + * DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are + * reserved. + * + * @throws IllegalArgumentException if the values in embeddings are not within + * the allowed range + * + * @see #DIRECTION_LEFT_TO_RIGHT + * @see #DIRECTION_RIGHT_TO_LEFT + * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT + * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT + * @stable ICU 3.8 + */ + public BidiBase(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) { + this(0, 0); + byte paraLvl; + switch (flags) { + case Bidi.DIRECTION_LEFT_TO_RIGHT: + default: + paraLvl = LTR; + break; + case Bidi.DIRECTION_RIGHT_TO_LEFT: + paraLvl = RTL; + break; + case Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT: + paraLvl = LEVEL_DEFAULT_LTR; + break; + case Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT: + paraLvl = LEVEL_DEFAULT_RTL; + break; + } + byte[] paraEmbeddings; + if (embeddings == null) { + paraEmbeddings = null; + } else { + paraEmbeddings = new byte[paragraphLength]; + byte lev; + for (int i = 0; i < paragraphLength; i++) { + lev = embeddings[i + embStart]; + if (lev < 0) { + lev = (byte) ((-lev) | LEVEL_OVERRIDE); + } else if (lev == 0) { + lev = paraLvl; + if (paraLvl > MAX_EXPLICIT_LEVEL) { + lev &= 1; + } + } + paraEmbeddings[i] = lev; + } + } + + char[] paraText = new char[paragraphLength]; + System.arraycopy(text, textStart, paraText, 0, paragraphLength); + setPara(paraText, paraLvl, paraEmbeddings); + } + + /** + * Return true if the line is not left-to-right or right-to-left. This means it + * either has mixed runs of left-to-right and right-to-left text, or the base + * direction differs from the direction of the only run of text. + * + * @return true if the line is not left-to-right or right-to-left. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isMixed() { + return (!isLeftToRight() && !isRightToLeft()); + } + + /** + * Return true if the line is all left-to-right text and the base direction is + * left-to-right. + * + * @return true if the line is all left-to-right text and the base direction is + * left-to-right. + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isLeftToRight() { + return (getDirection() == LTR && (paraLevel & 1) == 0); + } + + /** + * Return true if the line is all right-to-left text, and the base direction is + * right-to-left + * + * @return true if the line is all right-to-left text, and the base direction is + * right-to-left + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara + * @stable ICU 3.8 + */ + public boolean isRightToLeft() { + return (getDirection() == RTL && (paraLevel & 1) == 1); + } + + /** + * Return true if the base direction is left-to-right + * + * @return true if the base direction is left-to-right + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @stable ICU 3.8 + */ + public boolean baseIsLeftToRight() { + return (getParaLevel() == LTR); + } + + /** + * Return the base level (0 if left-to-right, 1 if right-to-left). + * + * @return the base level + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @stable ICU 3.8 + */ + public int getBaseLevel() { + return getParaLevel(); + } + + /** + * Compute the logical to visual run mapping + */ + void getLogicalToVisualRunsMap() { + if (isGoodLogicalToVisualRunsMap) { + return; + } + int count = countRuns(); + if ((logicalToVisualRunsMap == null) || (logicalToVisualRunsMap.length < count)) { + logicalToVisualRunsMap = new int[count]; + } + int i; + long[] keys = new long[count]; + for (i = 0; i < count; i++) { + keys[i] = ((long) (runs[i].start) << 32) + i; + } + Arrays.sort(keys); + for (i = 0; i < count; i++) { + logicalToVisualRunsMap[i] = (int) (keys[i] & 0x00000000FFFFFFFF); + } + isGoodLogicalToVisualRunsMap = true; + } + + /** + * Return the level of the nth logical run in this line. + * + * @param run the index of the run, between 0 and countRuns()-1 + * + * @return the level of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if run is not in the range + * 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunLevel(int run) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (run < 0 || run >= runCount) { + return getParaLevel(); + } + + getLogicalToVisualRunsMap(); + return runs[logicalToVisualRunsMap[run]].level; + } + + /** + * Return the index of the character at the start of the nth logical run in this + * line, as an offset from the start of the line. + * + * @param run the index of the run, between 0 and countRuns() + * + * @return the start of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if run is not in the range + * 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunStart(int run) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (runCount == 1) { + return 0; + } else if (run == runCount) { + return length; + } + + getLogicalToVisualRunsMap(); + return runs[logicalToVisualRunsMap[run]].start; + } + + /** + * Return the index of the character past the end of the nth logical run in this + * line, as an offset from the start of the line. For example, this will return + * the length of the line for the last run on the line. + * + * @param run the index of the run, between 0 and countRuns() + * + * @return the limit of the run + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * @throws IllegalArgumentException if run is not in the range + * 0<=run<countRuns() + * @stable ICU 3.8 + */ + public int getRunLimit(int run) { + verifyValidParaOrLine(); + BidiLine.getRuns(this); + + // for backward compatibility + if (runCount == 1) { + return length; + } + + getLogicalToVisualRunsMap(); + int idx = logicalToVisualRunsMap[run]; + int len = idx == 0 ? runs[idx].limit : runs[idx].limit - runs[idx - 1].limit; + return runs[idx].start + len; + } + + /** + * Return true if the specified text requires bidi analysis. If this returns + * false, the text will display left-to-right. Clients can then avoid + * constructing a Bidi object. Text in the Arabic Presentation Forms area of + * Unicode is presumed to already be shaped and ordered for display, and so will + * not cause this method to return true. + * + * @param text the text containing the characters to test + * @param start the start of the range of characters to test + * @param limit the limit of the range of characters to test + * + * @return true if the range of characters requires bidi analysis + * + * @stable ICU 3.8 + */ + public static boolean requiresBidi(char[] text, int start, int limit) { + final int RTLMask = (1 << R | 1 << AL | 1 << RLE | 1 << RLO | 1 << AN); + + if (0 > start || start > limit || limit > text.length) { + throw new IllegalArgumentException("Value start " + start + " is out of range 0 to " + limit + ", or limit " + + limit + " is beyond the text length " + text.length); + } + + for (int i = start; i < limit; ++i) { + if (Character.isHighSurrogate(text[i]) && i < (limit - 1) && Character.isLowSurrogate(text[i + 1])) { + if (((1 << UCharacter.getDirection(Character.codePointAt(text, i))) & RTLMask) != 0) { + return true; + } + } else if (((1 << UCharacter.getDirection(text[i])) & RTLMask) != 0) { + return true; + } + } + + return false; + } + + /** + * Reorder the objects in the array into visual order based on their levels. + * This is a utility method to use when you have a collection of objects + * representing runs of text in logical order, each run containing text at a + * single level. The elements at index from + * objectStart up to objectStart + count in the + * objects array will be reordered into visual order assuming each run of text + * has the level indicated by the corresponding element in the levels array (at + * index - objectStart + levelStart). + * + * @param levels an array representing the bidi level of each object + * @param levelStart the start position in the levels array + * @param objects the array of objects to be reordered into visual order + * @param objectStart the start position in the objects array + * @param count the number of objects to reorder + * @stable ICU 3.8 + */ + public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) { + // for backward compatibility + if (0 > levelStart || levels.length <= levelStart) { + throw new IllegalArgumentException( + "Value levelStart " + levelStart + " is out of range 0 to " + (levels.length - 1)); + } + if (0 > objectStart || objects.length <= objectStart) { + throw new IllegalArgumentException( + "Value objectStart " + objectStart + " is out of range 0 to " + (objects.length - 1)); + } + if (0 > count || objects.length < (objectStart + count)) { + throw new IllegalArgumentException("Value count " + count + " is less than zero, or objectStart + count" + + " is beyond objects length " + objects.length); + } + + byte[] reorderLevels = new byte[count]; + System.arraycopy(levels, levelStart, reorderLevels, 0, count); + int[] indexMap = reorderVisual(reorderLevels); + Object[] temp = new Object[count]; + System.arraycopy(objects, objectStart, temp, 0, count); + for (int i = 0; i < count; ++i) { + objects[objectStart + i] = temp[indexMap[i]]; + } + } + + /** + * Take a Bidi object containing the reordering information for a + * piece of text (one or more paragraphs) set by setPara() or for a + * line of text set by setLine() and return a string containing the + * reordered text. + * + *

+ * The text may have been aliased (only a reference was stored without copying + * the contents), thus it must not have been modified since the + * setPara() call. + *

+ * + * This method preserves the integrity of characters with multiple code units + * and (optionally) combining characters. Characters in RTL runs can be replaced + * by mirror-image characters in the returned string. Note that "real" mirroring + * has to be done in a rendering engine by glyph selection and that for many + * "mirrored" characters there are no Unicode characters as mirror-image + * equivalents. There are also options to insert or remove Bidi control + * characters; see the descriptions of the return value and the + * options parameter, and of the option bit flags. + * + * @param options A bit set of options for the reordering that control how the + * reordered text is written. The options include mirroring the + * characters on a code point basis and inserting LRM characters, + * which is used especially for transforming visually stored text + * to logically stored text (although this is still an imperfect + * implementation of an "inverse Bidi" algorithm because it uses + * the "forward Bidi" algorithm at its core). The available + * options are: DO_MIRRORING, + * INSERT_LRM_FOR_NUMERIC, + * KEEP_BASE_COMBINING, OUTPUT_REVERSE, + * REMOVE_BIDI_CONTROLS, STREAMING + * + * @return The reordered text. If the INSERT_LRM_FOR_NUMERIC option + * is set, then the length of the returned string could be as large as + * getLength()+2*countRuns().
+ * If the REMOVE_BIDI_CONTROLS option is set, then the + * length of the returned string may be less than + * getLength().
+ * If none of these options is set, then the length of the returned + * string will be exactly getProcessedLength(). + * + * @throws IllegalStateException if this call is not preceded by a successful + * call to setPara or + * setLine + * + * @see #DO_MIRRORING + * @see #INSERT_LRM_FOR_NUMERIC + * @see #KEEP_BASE_COMBINING + * @see #OUTPUT_REVERSE + * @see #REMOVE_BIDI_CONTROLS + * @see #OPTION_STREAMING + * @see #getProcessedLength + * @stable ICU 3.8 + */ + public String writeReordered(int options) { + verifyValidParaOrLine(); + if (length == 0) { + /* nothing to do */ + return ""; + } + return BidiWriter.writeReordered(this, options); + } + + /** + * Display the bidi internal state, used in debugging. + */ + public String toString() { + StringBuilder buf = new StringBuilder(getClass().getName()); + + buf.append("[dir: "); + buf.append(direction); + buf.append(" baselevel: "); + buf.append(paraLevel); + buf.append(" length: "); + buf.append(length); + buf.append(" runs: "); + if (levels == null) { + buf.append("none"); + } else { + buf.append('['); + buf.append(levels[0]); + for (int i = 1; i < levels.length; i++) { + buf.append(' '); + buf.append(levels[i]); + } + buf.append(']'); + } + buf.append(" text: [0x"); + buf.append(Integer.toHexString(text[0])); + for (int i = 1; i < text.length; i++) { + buf.append(" 0x"); + buf.append(Integer.toHexString(text[i])); + } + buf.append("]]"); + + return buf.toString(); + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiLine.java b/src/main/java/jdk_internal/bidi/icu/text/BidiLine.java new file mode 100755 index 00000000..19d8e73e --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiLine.java @@ -0,0 +1,821 @@ +/* + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk_internal.bidi.icu.text; + +import java.util.Arrays; + +import jdk_internal.bidi.Bidi; + +final class BidiLine { + + /* + * General remarks about the functions in this file: + * + * These functions deal with the aspects of potentially mixed-directional text + * in a single paragraph or in a line of a single paragraph which has already + * been processed according to the Unicode 3.0 Bidi algorithm as defined in Unicode Standard Annex #9: Unicode + * Bidirectional Algorithm, version 13, also described in The Unicode + * Standard, Version 4.0.1 . + * + * This means that there is a Bidi object with a levels and a dirProps array. + * paraLevel and direction are also set. Only if the length of the text is zero, + * then levels==dirProps==NULL. + * + * The overall directionality of the paragraph or line is used to bypass the + * reordering steps if possible. Even purely RTL text does not need reordering + * there because the getLogical/VisualIndex() methods can compute the index on + * the fly in such a case. + * + * The implementation of the access to same-level-runs and of the reordering do + * attempt to provide better performance and less memory usage compared to a + * direct implementation of especially rule (L2) with an array of one (32-bit) + * integer per text character. + * + * Here, the levels array is scanned as soon as necessary, and a vector of + * same-level-runs is created. Reordering then is done on this vector. For each + * run of text positions that were resolved to the same level, only 8 bytes are + * stored: the first text position of the run and the visual position behind the + * run after reordering. One sign bit is used to hold the directionality of the + * run. This is inefficient if there are many very short runs. If the average + * run length is <2, then this uses more memory. + * + * In a further attempt to save memory, the levels array is never changed after + * all the resolution rules (Xn, Wn, Nn, In). Many methods have to consider the + * field trailingWSStart: if it is less than length, then there is an implicit + * trailing run at the paraLevel, which is not reflected in the levels array. + * This allows a line Bidi object to use the same levels array as its paragraph + * parent object. + * + * When a Bidi object is created for a line of a paragraph, then the paragraph's + * levels and dirProps arrays are reused by way of setting a pointer into them, + * not by copying. This again saves memory and forbids to change the now shared + * levels for (L1). + */ + + /* handle trailing WS (L1) -------------------------------------------------- */ + + /* + * setTrailingWSStart() sets the start index for a trailing run of WS in the + * line. This is necessary because we do not modify the paragraph's levels array + * that we just point into. Using trailingWSStart is another form of performing + * (L1). + * + * To make subsequent operations easier, we also include the run before the WS + * if it is at the paraLevel - we merge the two here. + * + * This method is called only from setLine(), so paraLevel is set correctly for + * the line even when contextual multiple paragraphs. + */ + + static void setTrailingWSStart(BidiBase bidiBase) { + byte[] dirProps = bidiBase.dirProps; + byte[] levels = bidiBase.levels; + int start = bidiBase.length; + byte paraLevel = bidiBase.paraLevel; + + /* + * If the line is terminated by a block separator, all preceding WS etc... are + * already set to paragraph level. Setting trailingWSStart to pBidi->length will + * avoid changing the level of B chars from 0 to paraLevel in getLevels when + * orderParagraphsLTR==TRUE + */ + if (dirProps[start - 1] == BidiBase.B) { + bidiBase.trailingWSStart = start; /* currently == bidiBase.length */ + return; + } + /* go backwards across all WS, BN, explicit codes */ + while (start > 0 && (BidiBase.DirPropFlag(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) { + --start; + } + + /* if the WS run can be merged with the previous run then do so here */ + while (start > 0 && levels[start - 1] == paraLevel) { + --start; + } + + bidiBase.trailingWSStart = start; + } + + static Bidi setLine(BidiBase paraBidi, Bidi newBidi, BidiBase lineBidi, int start, int limit) { + int length; + + /* set the values in lineBidi from its paraBidi parent */ + /* class members are already initialized to 0 */ + // lineBidi.paraBidi = null; /* mark unfinished setLine */ + // lineBidi.flags = 0; + // lineBidi.controlCount = 0; + + length = lineBidi.length = lineBidi.originalLength = lineBidi.resultLength = limit - start; + + lineBidi.text = new char[length]; + System.arraycopy(paraBidi.text, start, lineBidi.text, 0, length); + lineBidi.paraLevel = paraBidi.GetParaLevelAt(start); + lineBidi.paraCount = paraBidi.paraCount; + lineBidi.runs = new BidiRun[0]; + lineBidi.reorderingMode = paraBidi.reorderingMode; + lineBidi.reorderingOptions = paraBidi.reorderingOptions; + if (paraBidi.controlCount > 0) { + int j; + for (j = start; j < limit; j++) { + if (BidiBase.IsBidiControlChar(paraBidi.text[j])) { + lineBidi.controlCount++; + } + } + lineBidi.resultLength -= lineBidi.controlCount; + } + /* copy proper subset of DirProps */ + lineBidi.getDirPropsMemory(length); + lineBidi.dirProps = lineBidi.dirPropsMemory; + System.arraycopy(paraBidi.dirProps, start, lineBidi.dirProps, 0, length); + /* copy proper subset of Levels */ + lineBidi.getLevelsMemory(length); + lineBidi.levels = lineBidi.levelsMemory; + System.arraycopy(paraBidi.levels, start, lineBidi.levels, 0, length); + lineBidi.runCount = -1; + + if (paraBidi.direction != BidiBase.MIXED) { + /* the parent is already trivial */ + lineBidi.direction = paraBidi.direction; + + /* + * The parent's levels are all either implicitly or explicitly ==paraLevel; do + * the same here. + */ + if (paraBidi.trailingWSStart <= start) { + lineBidi.trailingWSStart = 0; + } else if (paraBidi.trailingWSStart < limit) { + lineBidi.trailingWSStart = paraBidi.trailingWSStart - start; + } else { + lineBidi.trailingWSStart = length; + } + } else { + byte[] levels = lineBidi.levels; + int i, trailingWSStart; + byte level; + + setTrailingWSStart(lineBidi); + trailingWSStart = lineBidi.trailingWSStart; + + /* recalculate lineBidiBase.direction */ + if (trailingWSStart == 0) { + /* all levels are at paraLevel */ + lineBidi.direction = (byte) (lineBidi.paraLevel & 1); + } else { + /* get the level of the first character */ + level = (byte) (levels[0] & 1); + + /* + * if there is anything of a different level, then the line is mixed + */ + if (trailingWSStart < length && (lineBidi.paraLevel & 1) != level) { + /* + * the trailing WS is at paraLevel, which differs from levels[0] + */ + lineBidi.direction = BidiBase.MIXED; + } else { + /* + * see if levels[1..trailingWSStart-1] have the same direction as levels[0] and + * paraLevel + */ + for (i = 1;; i++) { + if (i == trailingWSStart) { + /* the direction values match those in level */ + lineBidi.direction = level; + break; + } else if ((levels[i] & 1) != level) { + lineBidi.direction = BidiBase.MIXED; + break; + } + } + } + } + + switch (lineBidi.direction) { + case Bidi.DIRECTION_LEFT_TO_RIGHT: + /* make sure paraLevel is even */ + lineBidi.paraLevel = (byte) ((lineBidi.paraLevel + 1) & ~1); + + /* + * all levels are implicitly at paraLevel (important for getLevels()) + */ + lineBidi.trailingWSStart = 0; + break; + case Bidi.DIRECTION_RIGHT_TO_LEFT: + /* make sure paraLevel is odd */ + lineBidi.paraLevel |= 1; + + /* + * all levels are implicitly at paraLevel (important for getLevels()) + */ + lineBidi.trailingWSStart = 0; + break; + default: + break; + } + } + + lineBidi.paraBidi = paraBidi; /* mark successful setLine */ + + return newBidi; + } + + static byte getLevelAt(BidiBase bidiBase, int charIndex) { + /* return paraLevel if in the trailing WS run, otherwise the real level */ + if (bidiBase.direction != BidiBase.MIXED || charIndex >= bidiBase.trailingWSStart) { + return bidiBase.GetParaLevelAt(charIndex); + } else { + return bidiBase.levels[charIndex]; + } + } + + static byte[] getLevels(BidiBase bidiBase) { + int start = bidiBase.trailingWSStart; + int length = bidiBase.length; + + if (start != length) { + /* the current levels array does not reflect the WS run */ + /* + * After the previous if(), we know that the levels array has an implicit + * trailing WS run and therefore does not fully reflect itself all the levels. + * This must be a Bidi object for a line, and we need to create a new levels + * array. + */ + /* + * bidiBase.paraLevel is ok even if contextual multiple paragraphs, since + * bidiBase is a line object + */ + Arrays.fill(bidiBase.levels, start, length, bidiBase.paraLevel); + + /* this new levels array is set for the line and reflects the WS run */ + bidiBase.trailingWSStart = length; + } + if (length < bidiBase.levels.length) { + byte[] levels = new byte[length]; + System.arraycopy(bidiBase.levels, 0, levels, 0, length); + return levels; + } + return bidiBase.levels; + } + + static BidiRun getVisualRun(BidiBase bidiBase, int runIndex) { + int start = bidiBase.runs[runIndex].start; + int limit; + byte level = bidiBase.runs[runIndex].level; + + if (runIndex > 0) { + limit = start + bidiBase.runs[runIndex].limit - bidiBase.runs[runIndex - 1].limit; + } else { + limit = start + bidiBase.runs[0].limit; + } + return new BidiRun(start, limit, level); + } + + /* in trivial cases there is only one trivial run; called by getRuns() */ + private static void getSingleRun(BidiBase bidiBase, byte level) { + /* simple, single-run case */ + bidiBase.runs = bidiBase.simpleRuns; + bidiBase.runCount = 1; + + /* fill and reorder the single run */ + bidiBase.runs[0] = new BidiRun(0, bidiBase.length, level); + } + + /* reorder the runs array (L2) ---------------------------------------------- */ + + /* + * Reorder the same-level runs in the runs array. Here, runCount>1 and + * maxLevel>=minLevel>=paraLevel. All the visualStart fields=logical start + * before reordering. The "odd" bits are not set yet. + * + * Reordering with this data structure lends itself to some handy shortcuts: + * + * Since each run is moved but not modified, and since at the initial maxLevel + * each sequence of same-level runs consists of only one run each, we don't need + * to do anything there and can predecrement maxLevel. In many simple cases, the + * reordering is thus done entirely in the index mapping. Also, reordering + * occurs only down to the lowest odd level that occurs, which is minLevel|1. + * However, if the lowest level itself is odd, then in the last reordering the + * sequence of the runs at this level or higher will be all runs, and we don't + * need the elaborate loop to search for them. This is covered by ++minLevel + * instead of minLevel|=1 followed by an extra reorder-all after the + * reorder-some loop. About a trailing WS run: Such a run would need special + * treatment because its level is not reflected in levels[] if this is not a + * paragraph object. Instead, all characters from trailingWSStart on are + * implicitly at paraLevel. However, for all maxLevel>paraLevel, this run will + * never be reordered and does not need to be taken into account. + * maxLevel==paraLevel is only reordered if minLevel==paraLevel is odd, which is + * done in the extra segment. This means that for the main reordering loop we + * don't need to consider this run and can --runCount. If it is later part of + * the all-runs reordering, then runCount is adjusted accordingly. + */ + private static void reorderLine(BidiBase bidiBase, byte minLevel, byte maxLevel) { + + /* nothing to do? */ + if (maxLevel <= (minLevel | 1)) { + return; + } + + BidiRun[] runs; + BidiRun tempRun; + byte[] levels; + int firstRun, endRun, limitRun, runCount; + + /* + * Reorder only down to the lowest odd level and reorder at an odd minLevel in a + * separate, simpler loop. See comments above for why minLevel is always + * incremented. + */ + ++minLevel; + + runs = bidiBase.runs; + levels = bidiBase.levels; + runCount = bidiBase.runCount; + + /* + * do not include the WS run at paraLevel<=old minLevel except in the simple + * loop + */ + if (bidiBase.trailingWSStart < bidiBase.length) { + --runCount; + } + + while (--maxLevel >= minLevel) { + firstRun = 0; + + /* loop for all sequences of runs */ + for (;;) { + /* look for a sequence of runs that are all at >=maxLevel */ + /* look for the first run of such a sequence */ + while (firstRun < runCount && levels[runs[firstRun].start] < maxLevel) { + ++firstRun; + } + if (firstRun >= runCount) { + break; /* no more such runs */ + } + + /* look for the limit run of such a sequence (the run behind it) */ + for (limitRun = firstRun; ++limitRun < runCount && levels[runs[limitRun].start] >= maxLevel;) { + } + + /* Swap the entire sequence of runs from firstRun to limitRun-1. */ + endRun = limitRun - 1; + while (firstRun < endRun) { + tempRun = runs[firstRun]; + runs[firstRun] = runs[endRun]; + runs[endRun] = tempRun; + ++firstRun; + --endRun; + } + + if (limitRun == runCount) { + break; /* no more such runs */ + } else { + firstRun = limitRun + 1; + } + } + } + + /* now do maxLevel==old minLevel (==odd!), see above */ + if ((minLevel & 1) == 0) { + firstRun = 0; + + /* include the trailing WS run in this complete reordering */ + if (bidiBase.trailingWSStart == bidiBase.length) { + --runCount; + } + + /* Swap the entire sequence of all runs. (endRun==runCount) */ + while (firstRun < runCount) { + tempRun = runs[firstRun]; + runs[firstRun] = runs[runCount]; + runs[runCount] = tempRun; + ++firstRun; + --runCount; + } + } + } + + /* compute the runs array --------------------------------------------------- */ + + static int getRunFromLogicalIndex(BidiBase bidiBase, int logicalIndex) { + BidiRun[] runs = bidiBase.runs; + int runCount = bidiBase.runCount, visualStart = 0, i, length, logicalStart; + + for (i = 0; i < runCount; i++) { + length = runs[i].limit - visualStart; + logicalStart = runs[i].start; + if ((logicalIndex >= logicalStart) && (logicalIndex < (logicalStart + length))) { + return i; + } + visualStart += length; + } + /* we should never get here */ + throw new IllegalStateException("Internal ICU error in getRunFromLogicalIndex"); + } + + /* + * Compute the runs array from the levels array. After getRuns() returns true, + * runCount is guaranteed to be >0 and the runs are reordered. Odd-level runs + * have visualStart on their visual right edge and they progress visually to the + * left. If option OPTION_INSERT_MARKS is set, insertRemove will contain the sum + * of appropriate LRM/RLM_BEFORE/AFTER flags. If option OPTION_REMOVE_CONTROLS + * is set, insertRemove will contain the negative number of BiDi control + * characters within this run. + */ + static void getRuns(BidiBase bidiBase) { + /* + * This method returns immediately if the runs are already set. This includes + * the case of length==0 (handled in setPara).. + */ + if (bidiBase.runCount >= 0) { + return; + } + if (bidiBase.direction != BidiBase.MIXED) { + /* simple, single-run case - this covers length==0 */ + /* bidiBase.paraLevel is ok even for contextual multiple paragraphs */ + getSingleRun(bidiBase, bidiBase.paraLevel); + } else /* BidiBase.MIXED, length>0 */ { + /* mixed directionality */ + int length = bidiBase.length, limit; + byte[] levels = bidiBase.levels; + int i, runCount; + byte level = -1; /* initialize with no valid level */ + /* + * If there are WS characters at the end of the line and the run preceding them + * has a level different from paraLevel, then they will form their own run at + * paraLevel (L1). Count them separately. We need some special treatment for + * this in order to not modify the levels array which a line Bidi object shares + * with its paragraph parent and its other line siblings. In other words, for + * the trailing WS, it may be levels[]!=paraLevel but we have to treat it like + * it were so. + */ + limit = bidiBase.trailingWSStart; + /* count the runs, there is at least one non-WS run, and limit>0 */ + runCount = 0; + for (i = 0; i < limit; ++i) { + /* increment runCount at the start of each run */ + if (levels[i] != level) { + ++runCount; + level = levels[i]; + } + } + + /* + * We don't need to see if the last run can be merged with a trailing WS run + * because setTrailingWSStart() would have done that. + */ + if (runCount == 1 && limit == length) { + /* There is only one non-WS run and no trailing WS-run. */ + getSingleRun(bidiBase, levels[0]); + } else /* runCount>1 || limit 1 */ + bidiBase.getRunsMemory(runCount); + runs = bidiBase.runsMemory; + + /* set the runs */ + /* + * FOOD FOR THOUGHT: this could be optimized, e.g.: 464->444, 484->444, + * 575->555, 595->555 However, that would take longer. Check also how it would + * interact with BiDi control removal and inserting Marks. + */ + runIndex = 0; + + /* + * search for the run limits and initialize visualLimit values with the run + * lengths + */ + i = 0; + do { + /* prepare this run */ + start = i; + level = levels[i]; + if (level < minLevel) { + minLevel = level; + } + if (level > maxLevel) { + maxLevel = level; + } + + /* look for the run limit */ + while (++i < limit && levels[i] == level) { + } + + /* i is another run limit */ + runs[runIndex] = new BidiRun(start, i - start, level); + ++runIndex; + } while (i < limit); + + if (limit < length) { + /* there is a separate WS run */ + runs[runIndex] = new BidiRun(limit, length - limit, bidiBase.paraLevel); + /* + * For the trailing WS run, bidiBase.paraLevel is ok even if contextual multiple + * paragraphs. + */ + if (bidiBase.paraLevel < minLevel) { + minLevel = bidiBase.paraLevel; + } + } + + /* set the object fields */ + bidiBase.runs = runs; + bidiBase.runCount = runCount; + + reorderLine(bidiBase, minLevel, maxLevel); + + /* now add the direction flags and adjust the visualLimit's to be just that */ + /* this loop will also handle the trailing WS run */ + limit = 0; + for (i = 0; i < runCount; ++i) { + runs[i].level = levels[runs[i].start]; + limit = (runs[i].limit += limit); + } + + /* Set the embedding level for the trailing WS run. */ + /* For a RTL paragraph, it will be the *first* run in visual order. */ + /* + * For the trailing WS run, bidiBase.paraLevel is ok even if contextual multiple + * paragraphs. + */ + if (runIndex < runCount) { + int trailingRun = ((bidiBase.paraLevel & 1) != 0) ? 0 : runIndex; + runs[trailingRun].level = bidiBase.paraLevel; + } + } + } + + /* handle insert LRM/RLM BEFORE/AFTER run */ + if (bidiBase.insertPoints.size > 0) { + BidiBase.Point point; + int runIndex, ip; + for (ip = 0; ip < bidiBase.insertPoints.size; ip++) { + point = bidiBase.insertPoints.points[ip]; + runIndex = getRunFromLogicalIndex(bidiBase, point.pos); + bidiBase.runs[runIndex].insertRemove |= point.flag; + } + } + + /* handle remove BiDi control characters */ + if (bidiBase.controlCount > 0) { + int runIndex, ic; + char c; + for (ic = 0; ic < bidiBase.length; ic++) { + c = bidiBase.text[ic]; + if (BidiBase.IsBidiControlChar(c)) { + runIndex = getRunFromLogicalIndex(bidiBase, ic); + bidiBase.runs[runIndex].insertRemove--; + } + } + } + } + + static int[] prepareReorder(byte[] levels, byte[] pMinLevel, byte[] pMaxLevel) { + int start; + byte level, minLevel, maxLevel; + + if (levels == null || levels.length <= 0) { + return null; + } + + /* determine minLevel and maxLevel */ + minLevel = BidiBase.MAX_EXPLICIT_LEVEL + 1; + maxLevel = 0; + for (start = levels.length; start > 0;) { + level = levels[--start]; + if (level < 0 || level > (BidiBase.MAX_EXPLICIT_LEVEL + 1)) { + return null; + } + if (level < minLevel) { + minLevel = level; + } + if (level > maxLevel) { + maxLevel = level; + } + } + pMinLevel[0] = minLevel; + pMaxLevel[0] = maxLevel; + + /* initialize the index map */ + int[] indexMap = new int[levels.length]; + for (start = levels.length; start > 0;) { + --start; + indexMap[start] = start; + } + + return indexMap; + } + + static int[] reorderVisual(byte[] levels) { + byte[] aMinLevel = new byte[1]; + byte[] aMaxLevel = new byte[1]; + int start, end, limit, temp; + byte minLevel, maxLevel; + + int[] indexMap = prepareReorder(levels, aMinLevel, aMaxLevel); + if (indexMap == null) { + return null; + } + + minLevel = aMinLevel[0]; + maxLevel = aMaxLevel[0]; + + /* nothing to do? */ + if (minLevel == maxLevel && (minLevel & 1) == 0) { + return indexMap; + } + + /* reorder only down to the lowest odd level */ + minLevel |= 1; + + /* loop maxLevel..minLevel */ + do { + start = 0; + + /* loop for all sequences of levels to reorder at the current maxLevel */ + for (;;) { + /* look for a sequence of levels that are all at >=maxLevel */ + /* look for the first index of such a sequence */ + while (start < levels.length && levels[start] < maxLevel) { + ++start; + } + if (start >= levels.length) { + break; /* no more such runs */ + } + + /* look for the limit of such a sequence (the index behind it) */ + for (limit = start; ++limit < levels.length && levels[limit] >= maxLevel;) { + } + + /* + * Swap the entire interval of indexes from start to limit-1. We don't need to + * swap the levels for the purpose of this algorithm: the sequence of levels + * that we look at does not move anyway. + */ + end = limit - 1; + while (start < end) { + temp = indexMap[start]; + indexMap[start] = indexMap[end]; + indexMap[end] = temp; + + ++start; + --end; + } + + if (limit == levels.length) { + break; /* no more such sequences */ + } else { + start = limit + 1; + } + } + } while (--maxLevel >= minLevel); + + return indexMap; + } + + static int[] getVisualMap(BidiBase bidiBase) { + /* fill a visual-to-logical index map using the runs[] */ + BidiRun[] runs = bidiBase.runs; + int logicalStart, visualStart, visualLimit; + int allocLength = bidiBase.length > bidiBase.resultLength ? bidiBase.length : bidiBase.resultLength; + int[] indexMap = new int[allocLength]; + + visualStart = 0; + int idx = 0; + for (int j = 0; j < bidiBase.runCount; ++j) { + logicalStart = runs[j].start; + visualLimit = runs[j].limit; + if (runs[j].isEvenRun()) { + do { /* LTR */ + indexMap[idx++] = logicalStart++; + } while (++visualStart < visualLimit); + } else { + logicalStart += visualLimit - visualStart; /* logicalLimit */ + do { /* RTL */ + indexMap[idx++] = --logicalStart; + } while (++visualStart < visualLimit); + } + /* visualStart==visualLimit; */ + } + + if (bidiBase.insertPoints.size > 0) { + int markFound = 0, runCount = bidiBase.runCount; + int insertRemove, i, j, k; + runs = bidiBase.runs; + /* count all inserted marks */ + for (i = 0; i < runCount; i++) { + insertRemove = runs[i].insertRemove; + if ((insertRemove & (BidiBase.LRM_BEFORE | BidiBase.RLM_BEFORE)) > 0) { + markFound++; + } + if ((insertRemove & (BidiBase.LRM_AFTER | BidiBase.RLM_AFTER)) > 0) { + markFound++; + } + } + /* move back indexes by number of preceding marks */ + k = bidiBase.resultLength; + for (i = runCount - 1; i >= 0 && markFound > 0; i--) { + insertRemove = runs[i].insertRemove; + if ((insertRemove & (BidiBase.LRM_AFTER | BidiBase.RLM_AFTER)) > 0) { + indexMap[--k] = BidiBase.MAP_NOWHERE; + markFound--; + } + visualStart = i > 0 ? runs[i - 1].limit : 0; + for (j = runs[i].limit - 1; j >= visualStart && markFound > 0; j--) { + indexMap[--k] = indexMap[j]; + } + if ((insertRemove & (BidiBase.LRM_BEFORE | BidiBase.RLM_BEFORE)) > 0) { + indexMap[--k] = BidiBase.MAP_NOWHERE; + markFound--; + } + } + } else if (bidiBase.controlCount > 0) { + int runCount = bidiBase.runCount, logicalEnd; + int insertRemove, length, i, j, k, m; + char uchar; + boolean evenRun; + runs = bidiBase.runs; + visualStart = 0; + /* move forward indexes by number of preceding controls */ + k = 0; + for (i = 0; i < runCount; i++, visualStart += length) { + length = runs[i].limit - visualStart; + insertRemove = runs[i].insertRemove; + /* if no control found yet, nothing to do in this run */ + if ((insertRemove == 0) && (k == visualStart)) { + k += length; + continue; + } + /* if no control in this run */ + if (insertRemove == 0) { + visualLimit = runs[i].limit; + for (j = visualStart; j < visualLimit; j++) { + indexMap[k++] = indexMap[j]; + } + continue; + } + logicalStart = runs[i].start; + evenRun = runs[i].isEvenRun(); + logicalEnd = logicalStart + length - 1; + for (j = 0; j < length; j++) { + m = evenRun ? logicalStart + j : logicalEnd - j; + uchar = bidiBase.text[m]; + if (!BidiBase.IsBidiControlChar(uchar)) { + indexMap[k++] = m; + } + } + } + } + if (allocLength == bidiBase.resultLength) { + return indexMap; + } + int[] newMap = new int[bidiBase.resultLength]; + System.arraycopy(indexMap, 0, newMap, 0, bidiBase.resultLength); + return newMap; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiRun.java b/src/main/java/jdk_internal/bidi/icu/text/BidiRun.java new file mode 100755 index 00000000..97b0e810 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiRun.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk_internal.bidi.icu.text; + +/** + * A BidiRun represents a sequence of characters at the same embedding level. + * The Bidi algorithm decomposes a piece of text into sequences of characters at + * the same embedding level, each such sequence is called a "run". + * + *

+ * A BidiRun represents such a run by storing its essential properties, but does + * not duplicate the characters which form the run. + * + *

+ * The "limit" of the run is the position just after the last + * character, i.e., one more than that position. + * + *

+ * This class has no public constructor, and its members cannot be modified by + * users. + * + * @see com.ibm.icu.text.Bidi + */ +class BidiRun { + + int start; /* first logical position of the run */ + int limit; /* last visual position of the run +1 */ + int insertRemove; /* + * if >0, flags for inserting LRM/RLM before/after run, if <0, count of bidi + * controls within run + */ + byte level; + + /* + * Default constructor + * + * Note that members start and limit of a run instance have different meanings + * depending whether the run is part of the runs array of a Bidi object, or if + * it is a reference returned by getVisualRun() or getLogicalRun(). For a member + * of the runs array of a Bidi object, - start is the first logical position of + * the run in the source text. - limit is one after the last visual position of + * the run. For a reference returned by getLogicalRun() or getVisualRun(), - + * start is the first logical position of the run in the source text. - limit is + * one after the last logical position of the run. + */ + BidiRun() { + this(0, 0, (byte) 0); + } + + /* + * Constructor + */ + BidiRun(int start, int limit, byte embeddingLevel) { + this.start = start; + this.limit = limit; + this.level = embeddingLevel; + } + + /* + * Copy the content of a BidiRun instance + */ + void copyFrom(BidiRun run) { + this.start = run.start; + this.limit = run.limit; + this.level = run.level; + this.insertRemove = run.insertRemove; + } + + /** + * Get level of run + */ + byte getEmbeddingLevel() { + return level; + } + + /** + * Check if run level is even + * + * @return true if the embedding level of this run is even, i.e. it is a + * left-to-right run. + */ + boolean isEvenRun() { + return (level & 1) == 0; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/BidiWriter.java b/src/main/java/jdk_internal/bidi/icu/text/BidiWriter.java new file mode 100755 index 00000000..e9fa71e6 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/BidiWriter.java @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2001-2010, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +/* Written by Simon Montagu, Matitiahu Allouche + * (ported from C code written by Markus W. Scherer) + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.icu.lang.UCharacter; + +final class BidiWriter { + + /** Bidi control code points */ + static final char LRM_CHAR = 0x200e; + static final char RLM_CHAR = 0x200f; + static final int MASK_R_AL = (1 << UCharacter.RIGHT_TO_LEFT | 1 << UCharacter.RIGHT_TO_LEFT_ARABIC); + + private static boolean IsCombining(int type) { + return ((1 << type & (1 << UCharacter.NON_SPACING_MARK | 1 << UCharacter.COMBINING_SPACING_MARK + | 1 << UCharacter.ENCLOSING_MARK)) != 0); + } + + /* + * When we have OUTPUT_REVERSE set on writeReordered(), then we semantically + * write RTL runs in reverse and later reverse them again. Instead, we actually + * write them in forward order to begin with. However, if the RTL run was to be + * mirrored, we need to mirror here now since the implicit second reversal must + * not do it. It looks strange to do mirroring in LTR output, but it is only + * because we are writing RTL output in reverse. + */ + private static String doWriteForward(String src, int options) { + /* optimize for several combinations of options */ + switch (options & (BidiBase.REMOVE_BIDI_CONTROLS | BidiBase.DO_MIRRORING)) { + case 0: { + /* simply return the LTR run */ + return src; + } + case BidiBase.DO_MIRRORING: { + StringBuffer dest = new StringBuffer(src.length()); + + /* do mirroring */ + int i = 0; + int c; + + do { + c = UTF16.charAt(src, i); + i += UTF16.getCharCount(c); + UTF16.append(dest, UCharacter.getMirror(c)); + } while (i < src.length()); + return dest.toString(); + } + case BidiBase.REMOVE_BIDI_CONTROLS: { + StringBuilder dest = new StringBuilder(src.length()); + + /* copy the LTR run and remove any Bidi control characters */ + int i = 0; + char c; + do { + c = src.charAt(i++); + if (!BidiBase.IsBidiControlChar(c)) { + dest.append(c); + } + } while (i < src.length()); + return dest.toString(); + } + default: { + StringBuffer dest = new StringBuffer(src.length()); + + /* remove Bidi control characters and do mirroring */ + int i = 0; + int c; + do { + c = UTF16.charAt(src, i); + i += UTF16.getCharCount(c); + if (!BidiBase.IsBidiControlChar(c)) { + UTF16.append(dest, UCharacter.getMirror(c)); + } + } while (i < src.length()); + return dest.toString(); + } + } /* end of switch */ + } + + private static String doWriteForward(char[] text, int start, int limit, int options) { + return doWriteForward(new String(text, start, limit - start), options); + } + + static String writeReverse(String src, int options) { + /* + * RTL run - + * + * RTL runs need to be copied to the destination in reverse order of code + * points, not code units, to keep Unicode characters intact. + * + * The general strategy for this is to read the source text in backward order, + * collect all code units for a code point (and optionally following combining + * characters, see below), and copy all these code units in ascending order to + * the destination for this run. + * + * Several options request whether combining characters should be kept after + * their base characters, whether Bidi control characters should be removed, and + * whether characters should be replaced by their mirror-image equivalent + * Unicode characters. + */ + StringBuffer dest = new StringBuffer(src.length()); + + /* optimize for several combinations of options */ + switch (options & (BidiBase.REMOVE_BIDI_CONTROLS | BidiBase.DO_MIRRORING | BidiBase.KEEP_BASE_COMBINING)) { + + case 0: + /* + * With none of the "complicated" options set, the destination run will have the + * same length as the source run, and there is no mirroring and no keeping + * combining characters with their base characters. + * + * XXX: or dest = UTF16.reverse(new StringBuffer(src)); + */ + + int srcLength = src.length(); + + /* preserve character integrity */ + do { + /* + * i is always after the last code unit known to need to be kept in this segment + */ + int i = srcLength; + + /* collect code units for one base character */ + srcLength -= UTF16.getCharCount(UTF16.charAt(src, srcLength - 1)); + + /* copy this base character */ + dest.append(src.substring(srcLength, i)); + } while (srcLength > 0); + break; + + case BidiBase.KEEP_BASE_COMBINING: + /* + * Here, too, the destination run will have the same length as the source run, + * and there is no mirroring. We do need to keep combining characters with their + * base characters. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* + * i is always after the last code unit known to need to be kept in this segment + */ + int c; + int i = srcLength; + + /* + * collect code units and modifier letters for one base character + */ + do { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } while (srcLength > 0 && IsCombining(UCharacter.getType(c))); + + /* copy this "user character" */ + dest.append(src.substring(srcLength, i)); + } while (srcLength > 0); + break; + + default: + /* + * With several "complicated" options set, this is the most general and the + * slowest copying of an RTL run. We will do mirroring, remove Bidi controls, + * and keep combining characters with their base characters as requested. + */ + srcLength = src.length(); + + /* preserve character integrity */ + do { + /* + * i is always after the last code unit known to need to be kept in this segment + */ + int i = srcLength; + + /* collect code units for one base character */ + int c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + if ((options & BidiBase.KEEP_BASE_COMBINING) != 0) { + /* collect modifier letters for this base character */ + while (srcLength > 0 && IsCombining(UCharacter.getType(c))) { + c = UTF16.charAt(src, srcLength - 1); + srcLength -= UTF16.getCharCount(c); + } + } + + if ((options & BidiBase.REMOVE_BIDI_CONTROLS) != 0 && BidiBase.IsBidiControlChar(c)) { + /* do not copy this Bidi control character */ + continue; + } + + /* copy this "user character" */ + int j = srcLength; + if ((options & BidiBase.DO_MIRRORING) != 0) { + /* mirror only the base character */ + c = UCharacter.getMirror(c); + UTF16.append(dest, c); + j += UTF16.getCharCount(c); + } + dest.append(src.substring(j, i)); + } while (srcLength > 0); + break; + } /* end of switch */ + + return dest.toString(); + } + + static String doWriteReverse(char[] text, int start, int limit, int options) { + return writeReverse(new String(text, start, limit - start), options); + } + + static String writeReordered(BidiBase bidi, int options) { + int run, runCount; + StringBuilder dest; + char[] text = bidi.text; + runCount = bidi.countRuns(); + + /* + * Option "insert marks" implies BidiBase.INSERT_LRM_FOR_NUMERIC if the + * reordering mode (checked below) is appropriate. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_INSERT_MARKS) != 0) { + options |= BidiBase.INSERT_LRM_FOR_NUMERIC; + options &= ~BidiBase.REMOVE_BIDI_CONTROLS; + } + /* + * Option "remove controls" implies BidiBase.REMOVE_BIDI_CONTROLS and cancels + * BidiBase.INSERT_LRM_FOR_NUMERIC. + */ + if ((bidi.reorderingOptions & BidiBase.OPTION_REMOVE_CONTROLS) != 0) { + options |= BidiBase.REMOVE_BIDI_CONTROLS; + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + /* + * If we do not perform the "inverse Bidi" algorithm, then we don't need to + * insert any LRMs, and don't need to test for it. + */ + if ((bidi.reorderingMode != BidiBase.REORDER_INVERSE_NUMBERS_AS_L) + && (bidi.reorderingMode != BidiBase.REORDER_INVERSE_LIKE_DIRECT) + && (bidi.reorderingMode != BidiBase.REORDER_INVERSE_FOR_NUMBERS_SPECIAL) + && (bidi.reorderingMode != BidiBase.REORDER_RUNS_ONLY)) { + options &= ~BidiBase.INSERT_LRM_FOR_NUMERIC; + } + dest = new StringBuilder((options & BidiBase.INSERT_LRM_FOR_NUMERIC) != 0 ? bidi.length * 2 : bidi.length); + /* + * Iterate through all visual runs and copy the run text segments to the + * destination, according to the options. + * + * The tests for where to insert LRMs ignore the fact that there may be BN codes + * or non-BMP code points at the beginning and end of a run; they may insert + * LRMs unnecessarily but the tests are faster this way (this would have to be + * improved for UTF-8). + */ + if ((options & BidiBase.OUTPUT_REVERSE) == 0) { + /* forward output */ + if ((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append( + doWriteForward(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteReverse(text, bidiRun.start, bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + byte[] dirProps = bidi.dirProps; + char uc; + int markFlag; + + for (run = 0; run < runCount; ++run) { + BidiRun bidiRun = bidi.getVisualRun(run); + markFlag = 0; + /* check if something relevant in insertPoints */ + markFlag = bidi.runs[run].insertRemove; + if (markFlag < 0) { /* bidi controls count */ + markFlag = 0; + } + if (bidiRun.isEvenRun()) { + if (bidi.isInverse() && dirProps[bidiRun.start] != BidiBase.L) { + markFlag |= BidiBase.LRM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append( + doWriteForward(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + + if (bidi.isInverse() && dirProps[bidiRun.limit - 1] != BidiBase.L) { + markFlag |= BidiBase.LRM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } else { /* RTL run */ + if (bidi.isInverse() && !bidi.testDirPropFlagAt(MASK_R_AL, bidiRun.limit - 1)) { + markFlag |= BidiBase.RLM_BEFORE; + } + if ((markFlag & BidiBase.LRM_BEFORE) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_BEFORE) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + dest.append(doWriteReverse(text, bidiRun.start, bidiRun.limit, options)); + + if (bidi.isInverse() && (MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + markFlag |= BidiBase.RLM_AFTER; + } + if ((markFlag & BidiBase.LRM_AFTER) != 0) { + uc = LRM_CHAR; + } else if ((markFlag & BidiBase.RLM_AFTER) != 0) { + uc = RLM_CHAR; + } else { + uc = 0; + } + if (uc != 0) { + dest.append(uc); + } + } + } + } + } else { + /* reverse output */ + if ((options & BidiBase.INSERT_LRM_FOR_NUMERIC) == 0) { + /* do not insert Bidi controls */ + for (run = runCount; --run >= 0;) { + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + dest.append( + doWriteReverse(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + } else { + dest.append(doWriteForward(text, bidiRun.start, bidiRun.limit, options)); + } + } + } else { + /* insert Bidi controls for "inverse Bidi" */ + + byte[] dirProps = bidi.dirProps; + + for (run = runCount; --run >= 0;) { + /* reverse output */ + BidiRun bidiRun = bidi.getVisualRun(run); + if (bidiRun.isEvenRun()) { + if (dirProps[bidiRun.limit - 1] != BidiBase.L) { + dest.append(LRM_CHAR); + } + + dest.append( + doWriteReverse(text, bidiRun.start, bidiRun.limit, options & ~BidiBase.DO_MIRRORING)); + + if (dirProps[bidiRun.start] != BidiBase.L) { + dest.append(LRM_CHAR); + } + } else { + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.start])) == 0) { + dest.append(RLM_CHAR); + } + + dest.append(doWriteForward(text, bidiRun.start, bidiRun.limit, options)); + + if ((MASK_R_AL & BidiBase.DirPropFlag(dirProps[bidiRun.limit - 1])) == 0) { + dest.append(RLM_CHAR); + } + } + } + } + } + + return dest.toString(); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/FilteredNormalizer2.java b/src/main/java/jdk_internal/bidi/icu/text/FilteredNormalizer2.java new file mode 100755 index 00000000..3f9046bb --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/FilteredNormalizer2.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* +******************************************************************************* +* Copyright (C) 2009-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ +package jdk_internal.bidi.icu.text; + +import java.io.IOException; + +/** + * Normalization filtered by a UnicodeSet. Normalizes portions of the text + * contained in the filter set and leaves portions not contained in the filter + * set unchanged. Filtering is done via UnicodeSet.span(..., + * UnicodeSet.SpanCondition.SIMPLE). Not-in-the-filter text is treated as "is + * normalized" and "quick check yes". This class implements all of (and only) + * the Normalizer2 API. An instance of this class is unmodifiable/immutable. + * + * @stable ICU 4.4 + * @author Markus W. Scherer + */ +class FilteredNormalizer2 extends Normalizer2 { + + /** + * Constructs a filtered normalizer wrapping any Normalizer2 instance and a + * filter set. Both are aliased and must not be modified or deleted while this + * object is used. The filter set should be frozen; otherwise the performance + * will suffer greatly. + * + * @param n2 wrapped Normalizer2 instance + * @param filterSet UnicodeSet which determines the characters to be normalized + * @stable ICU 4.4 + */ + public FilteredNormalizer2(Normalizer2 n2, UnicodeSet filterSet) { + norm2 = n2; + set = filterSet; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public StringBuilder normalize(CharSequence src, StringBuilder dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + dest.setLength(0); + normalize(src, dest, UnicodeSet.SpanCondition.SIMPLE); + return dest; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.6 + */ + @Override + public Appendable normalize(CharSequence src, Appendable dest) { + if (dest == src) { + throw new IllegalArgumentException(); + } + return normalize(src, dest, UnicodeSet.SpanCondition.SIMPLE); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, true); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public StringBuilder append(StringBuilder first, CharSequence second) { + return normalizeSecondAndAppend(first, second, false); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.6 + */ + @Override + public String getDecomposition(int c) { + return set.contains(c) ? norm2.getDecomposition(c) : null; + } + + /** + * {@inheritDoc} + * + * @stable ICU 49 + */ + @Override + public int getCombiningClass(int c) { + return set.contains(c) ? norm2.getCombiningClass(c) : 0; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public boolean isNormalized(CharSequence s) { + UnicodeSet.SpanCondition spanCondition = UnicodeSet.SpanCondition.SIMPLE; + for (int prevSpanLimit = 0; prevSpanLimit < s.length();) { + int spanLimit = set.span(s, prevSpanLimit, spanCondition); + if (spanCondition == UnicodeSet.SpanCondition.NOT_CONTAINED) { + spanCondition = UnicodeSet.SpanCondition.SIMPLE; + } else { + if (!norm2.isNormalized(s.subSequence(prevSpanLimit, spanLimit))) { + return false; + } + spanCondition = UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit = spanLimit; + } + return true; + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public int spanQuickCheckYes(CharSequence s) { + UnicodeSet.SpanCondition spanCondition = UnicodeSet.SpanCondition.SIMPLE; + for (int prevSpanLimit = 0; prevSpanLimit < s.length();) { + int spanLimit = set.span(s, prevSpanLimit, spanCondition); + if (spanCondition == UnicodeSet.SpanCondition.NOT_CONTAINED) { + spanCondition = UnicodeSet.SpanCondition.SIMPLE; + } else { + int yesLimit = prevSpanLimit + norm2.spanQuickCheckYes(s.subSequence(prevSpanLimit, spanLimit)); + if (yesLimit < spanLimit) { + return yesLimit; + } + spanCondition = UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit = spanLimit; + } + return s.length(); + } + + /** + * {@inheritDoc} + * + * @stable ICU 4.4 + */ + @Override + public boolean hasBoundaryBefore(int c) { + return !set.contains(c) || norm2.hasBoundaryBefore(c); + } + + // Internal: No argument checking, and appends to dest. + // Pass as input spanCondition the one that is likely to yield a non-zero + // span length at the start of src. + // For set=[:age=3.2:], since almost all common characters were in Unicode 3.2, + // UnicodeSet.SpanCondition.SIMPLE should be passed in for the start of src + // and UnicodeSet.SpanCondition.NOT_CONTAINED should be passed in if we continue + // after + // an in-filter prefix. + private Appendable normalize(CharSequence src, Appendable dest, UnicodeSet.SpanCondition spanCondition) { + // Don't throw away destination buffer between iterations. + StringBuilder tempDest = new StringBuilder(); + try { + for (int prevSpanLimit = 0; prevSpanLimit < src.length();) { + int spanLimit = set.span(src, prevSpanLimit, spanCondition); + int spanLength = spanLimit - prevSpanLimit; + if (spanCondition == UnicodeSet.SpanCondition.NOT_CONTAINED) { + if (spanLength != 0) { + dest.append(src, prevSpanLimit, spanLimit); + } + spanCondition = UnicodeSet.SpanCondition.SIMPLE; + } else { + if (spanLength != 0) { + // Not norm2.normalizeSecondAndAppend() because we do not want + // to modify the non-filter part of dest. + dest.append(norm2.normalize(src.subSequence(prevSpanLimit, spanLimit), tempDest)); + } + spanCondition = UnicodeSet.SpanCondition.NOT_CONTAINED; + } + prevSpanLimit = spanLimit; + } + } catch (IOException e) { + throw new InternalError(e.toString(), e); + } + return dest; + } + + private StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second, boolean doNormalize) { + if (first == second) { + throw new IllegalArgumentException(); + } + if (first.length() == 0) { + if (doNormalize) { + return normalize(second, first); + } else { + return first.append(second); + } + } + // merge the in-filter suffix of the first string with the in-filter prefix of + // the second + int prefixLimit = set.span(second, 0, UnicodeSet.SpanCondition.SIMPLE); + if (prefixLimit != 0) { + CharSequence prefix = second.subSequence(0, prefixLimit); + int suffixStart = set.spanBack(first, 0x7fffffff, UnicodeSet.SpanCondition.SIMPLE); + if (suffixStart == 0) { + if (doNormalize) { + norm2.normalizeSecondAndAppend(first, prefix); + } else { + norm2.append(first, prefix); + } + } else { + StringBuilder middle = new StringBuilder(first.subSequence(suffixStart, first.length())); + if (doNormalize) { + norm2.normalizeSecondAndAppend(middle, prefix); + } else { + norm2.append(middle, prefix); + } + first.delete(suffixStart, 0x7fffffff).append(middle); + } + } + if (prefixLimit < second.length()) { + CharSequence rest = second.subSequence(prefixLimit, second.length()); + if (doNormalize) { + normalize(rest, first, UnicodeSet.SpanCondition.NOT_CONTAINED); + } else { + first.append(rest); + } + } + return first; + } + + private Normalizer2 norm2; + private UnicodeSet set; +}; diff --git a/src/main/java/jdk_internal/bidi/icu/text/Normalizer2.java b/src/main/java/jdk_internal/bidi/icu/text/Normalizer2.java new file mode 100755 index 00000000..f833478f --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/Normalizer2.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2009-2014, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.icu.impl.Norm2AllModes; + +/** + * Unicode normalization functionality for standard Unicode normalization or for + * using custom mapping tables. All instances of this class are + * unmodifiable/immutable. The Normalizer2 class is not intended for public + * subclassing. + *

+ * The primary functions are to produce a normalized string and to detect + * whether a string is already normalized. The most commonly used normalization + * forms are those defined in + * Unicode Standard Annex #15: + * Unicode Normalization Forms. However, this API supports additional + * normalization forms for specialized purposes. For example, NFKC_Casefold is + * provided via getInstance("nfkc_cf", COMPOSE) and can be used in + * implementations of UTS #46. + *

+ * Not only are the standard compose and decompose modes supplied, but + * additional modes are provided as documented in the Mode enum. + *

+ * Some of the functions in this class identify normalization boundaries. At a + * normalization boundary, the portions of the string before it and starting + * from it do not interact and can be handled independently. + *

+ * The spanQuickCheckYes() stops at a normalization boundary. When the goal is a + * normalized string, then the text before the boundary can be copied, and the + * remainder can be processed with normalizeSecondAndAppend(). + *

+ * The hasBoundaryBefore(), hasBoundaryAfter() and isInert() functions test + * whether a character is guaranteed to be at a normalization boundary, + * regardless of context. This is used for moving from one normalization + * boundary to the next or preceding boundary, and for performing iterative + * normalization. + *

+ * Iterative normalization is useful when only a small portion of a longer + * string needs to be processed. For example, in ICU, iterative normalization is + * used by the NormalizationTransliterator (to avoid replacing + * already-normalized text) and ucol_nextSortKeyPart() (to process only the + * substring for which sort key bytes are computed). + *

+ * The set of normalization boundaries returned by these functions may not be + * complete: There may be more boundaries that could be returned. Different + * functions may return different boundaries. + * + * @stable ICU 4.4 + * @author Markus W. Scherer + */ +public abstract class Normalizer2 { + + /** + * Returns a Normalizer2 instance for Unicode NFC normalization. Same as + * getInstance(null, "nfc", Mode.COMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFCInstance() { + return Norm2AllModes.getNFCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFD normalization. Same as + * getInstance(null, "nfc", Mode.DECOMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFDInstance() { + return Norm2AllModes.getNFCInstance().decomp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKC normalization. Same as + * getInstance(null, "nfkc", Mode.COMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKCInstance() { + return Norm2AllModes.getNFKCInstance().comp; + } + + /** + * Returns a Normalizer2 instance for Unicode NFKD normalization. Same as + * getInstance(null, "nfkc", Mode.DECOMPOSE). Returns an unmodifiable singleton + * instance. + * + * @return the requested Normalizer2, if successful + * @stable ICU 49 + */ + public static Normalizer2 getNFKDInstance() { + return Norm2AllModes.getNFKCInstance().decomp; + } + + /** + * Returns the normalized form of the source string. + * + * @param src source string + * @return normalized src + * @stable ICU 4.4 + */ + public String normalize(CharSequence src) { + if (src instanceof String) { + // Fastpath: Do not construct a new String if the src is a String + // and is already normalized. + int spanLength = spanQuickCheckYes(src); + if (spanLength == src.length()) { + return (String) src; + } + if (spanLength != 0) { + StringBuilder sb = new StringBuilder(src.length()).append(src, 0, spanLength); + return normalizeSecondAndAppend(sb, src.subSequence(spanLength, src.length())).toString(); + } + } + return normalize(src, new StringBuilder(src.length())).toString(); + } + + /** + * Writes the normalized form of the source string to the destination string + * (replacing its contents) and returns the destination string. The source and + * destination strings must be different objects. + * + * @param src source string + * @param dest destination string; its contents is replaced with normalized src + * @return dest + * @stable ICU 4.4 + */ + public abstract StringBuilder normalize(CharSequence src, StringBuilder dest); + + /** + * Writes the normalized form of the source string to the destination Appendable + * and returns the destination Appendable. The source and destination strings + * must be different objects. + * + *

+ * Any {@link java.io.IOException} is wrapped into a + * {@link com.ibm.icu.util.ICUUncheckedIOException}. + * + * @param src source string + * @param dest destination Appendable; gets normalized src appended + * @return dest + * @stable ICU 4.6 + */ + public abstract Appendable normalize(CharSequence src, Appendable dest); + + /** + * Appends the normalized form of the second string to the first string (merging + * them at the boundary) and returns the first string. The result is normalized + * if the first string was normalized. The first and second strings must be + * different objects. + * + * @param first string, should be normalized + * @param second string, will be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder normalizeSecondAndAppend(StringBuilder first, CharSequence second); + + /** + * Appends the second string to the first string (merging them at the boundary) + * and returns the first string. The result is normalized if both the strings + * were normalized. The first and second strings must be different objects. + * + * @param first string, should be normalized + * @param second string, should be normalized + * @return first + * @stable ICU 4.4 + */ + public abstract StringBuilder append(StringBuilder first, CharSequence second); + + /** + * Gets the decomposition mapping of c. Roughly equivalent to normalizing the + * String form of c on a DECOMPOSE Normalizer2 instance, but much faster, and + * except that this function returns null if c does not have a decomposition + * mapping in this instance's data. This function is independent of the mode of + * the Normalizer2. + * + * @param c code point + * @return c's decomposition mapping, if any; otherwise null + * @stable ICU 4.6 + */ + public abstract String getDecomposition(int c); + + /** + * Gets the combining class of c. The default implementation returns 0 but all + * standard implementations return the Unicode Canonical_Combining_Class value. + * + * @param c code point + * @return c's combining class + * @stable ICU 49 + */ + public int getCombiningClass(int c) { + return 0; + } + + /** + * Tests if the string is normalized. Internally, in cases where the + * quickCheck() method would return "maybe" (which is only possible for the two + * COMPOSE modes) this method resolves to "yes" or "no" to provide a definitive + * result, at the cost of doing more work in those cases. + * + * @param s input string + * @return true if s is normalized + * @stable ICU 4.4 + */ + public abstract boolean isNormalized(CharSequence s); + + /** + * Returns the end of the normalized substring of the input string. In other + * words, with end=spanQuickCheckYes(s); the substring + * s.subSequence(0, end) will pass the quick check with a "yes" + * result. + *

+ * The returned end index is usually one or more characters before the "no" or + * "maybe" character: The end index is at a normalization boundary. (See the + * class documentation for more about normalization boundaries.) + *

+ * When the goal is a normalized string and most input strings are expected to + * be normalized already, then call this method, and if it returns a prefix + * shorter than the input string, copy that prefix and use + * normalizeSecondAndAppend() for the remainder. + * + * @param s input string + * @return "yes" span end index + * @stable ICU 4.4 + */ + public abstract int spanQuickCheckYes(CharSequence s); + + /** + * Tests if the character always has a normalization boundary before it, + * regardless of context. If true, then the character does not + * normalization-interact with preceding characters. In other words, a string + * containing this character can be normalized by processing portions before + * this character and starting from this character independently. This is used + * for iterative normalization. See the class documentation for details. + * + * @param c character to test + * @return true if c has a normalization boundary before it + * @stable ICU 4.4 + */ + public abstract boolean hasBoundaryBefore(int c); + + /** + * Sole constructor. (For invocation by subclass constructors, typically + * implicit.) + * + * @internal deprecated This API is ICU internal only. + */ + protected Normalizer2() { + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/NormalizerBase.java b/src/main/java/jdk_internal/bidi/icu/text/NormalizerBase.java new file mode 100755 index 00000000..5887aecb --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/NormalizerBase.java @@ -0,0 +1,791 @@ +/* + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2000-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.CharacterIterator; +import jdk_internal.bidi.Normalizer; +import jdk_internal.bidi.icu.impl.Norm2AllModes; + +/** + * Unicode Normalization + * + *

Unicode normalization API

+ * + * normalize transforms Unicode text into an equivalent composed or + * decomposed form, allowing for easier sorting and searching of text. + * normalize supports the standard normalization forms described in + * Unicode + * Standard Annex #15 — Unicode Normalization Forms. + * + * Characters with accents or other adornments can be encoded in several + * different ways in Unicode. For example, take the character A-acute. In + * Unicode, this can be encoded as a single character (the "composed" form): + * + *
+ *      00C1    LATIN CAPITAL LETTER A WITH ACUTE
+ * 
+ * + * or as two separate characters (the "decomposed" form): + * + *
+ *      0041    LATIN CAPITAL LETTER A
+ *      0301    COMBINING ACUTE ACCENT
+ * 
+ * + * To a user of your program, however, both of these sequences should be treated + * as the same "user-level" character "A with acute accent". When you are + * searching or comparing text, you must ensure that these two sequences are + * treated equivalently. In addition, you must handle characters with more than + * one accent. Sometimes the order of a character's combining accents is + * significant, while in other cases accent sequences in different orders are + * really equivalent. + * + * Similarly, the string "ffi" can be encoded as three separate letters: + * + *
+ *      0066    LATIN SMALL LETTER F
+ *      0066    LATIN SMALL LETTER F
+ *      0069    LATIN SMALL LETTER I
+ * 
+ * + * or as the single character + * + *
+ *      FB03    LATIN SMALL LIGATURE FFI
+ * 
+ * + * The ffi ligature is not a distinct semantic character, and strictly speaking + * it shouldn't be in Unicode at all, but it was included for compatibility with + * existing character sets that already provided it. The Unicode standard + * identifies such characters by giving them "compatibility" decompositions into + * the corresponding semantic characters. When sorting and searching, you will + * often want to use these mappings. + * + * normalize helps solve these problems by transforming text into + * the canonical composed and decomposed forms as shown in the first example + * above. In addition, you can have it perform compatibility decompositions so + * that you can treat compatibility characters the same as their equivalents. + * Finally, normalize rearranges accents into the proper canonical + * order, so that you do not have to worry about accent rearrangement on your + * own. + * + * Form FCD, "Fast C or D", is also designed for collation. It allows to work on + * strings that are not necessarily normalized with an algorithm (like in + * collation) that works under "canonical closure", i.e., it treats precomposed + * characters and their decomposed equivalents the same. + * + * It is not a normalization form because it does not provide for uniqueness of + * representation. Multiple strings may be canonically equivalent (their NFDs + * are identical) and may all conform to FCD without being identical themselves. + * + * The form is defined such that the "raw decomposition", the recursive + * canonical decomposition of each character, results in a string that is + * canonically ordered. This means that precomposed characters are allowed for + * as long as their decompositions do not need canonical reordering. + * + * Its advantage for a process like collation is that all NFD and most NFC texts + * - and many unnormalized texts - already conform to FCD and do not need to be + * normalized (NFD) for such a process. The FCD quick check will return YES for + * most strings in practice. + * + * normalize(FCD) may be implemented with NFD. + * + * For more details on FCD see Unicode Technical Note #5 (Canonical Equivalence + * in Applications): http://www.unicode.org/notes/tn5/#FCD + * + * ICU collation performs either NFD or FCD normalization automatically if + * normalization is turned on for the collator object. Beyond collation and + * string search, normalized strings may be useful for string equivalence + * comparisons, transliteration/transcription, unique representations, etc. + * + * The W3C generally recommends to exchange texts in NFC. Note also that most + * legacy character encodings use only precomposed forms and often do not encode + * any combining marks by themselves. For conversion to such character encodings + * the Unicode text needs to be normalized to NFC. For more usage examples, see + * the Unicode Standard Annex. + * + * Note: The Normalizer class also provides API for iterative normalization. + * While the setIndex() and getIndex() refer to indices in the underlying + * Unicode input text, the next() and previous() methods iterate through + * characters in the normalized output. This means that there is not necessarily + * a one-to-one correspondence between characters returned by next() and + * previous() and the indices passed to and returned from setIndex() and + * getIndex(). It is for this reason that Normalizer does not implement the + * CharacterIterator interface. + * + * @stable ICU 2.8 + */ +// Original filename in ICU4J: Normalizer.java +public final class NormalizerBase implements Cloneable { + + // The input text and our position in it + private UCharacterIterator text; + private Normalizer2 norm2; + private Mode mode; + private int options; + + // The normalization buffer is the result of normalization + // of the source in [currentIndex..nextIndex] . + private int currentIndex; + private int nextIndex; + + // A buffer for holding intermediate results + private StringBuilder buffer; + private int bufferPos; + + // Helper classes to defer loading of normalization data. + private static final class ModeImpl { + private ModeImpl(Normalizer2 n2) { + normalizer2 = n2; + } + + private final Normalizer2 normalizer2; + } + + private static final class NFDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFDInstance()); + } + + private static final class NFKDModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKDInstance()); + } + + private static final class NFCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFCInstance()); + } + + private static final class NFKCModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl(Normalizer2.getNFKCInstance()); + } + + private static final class Unicode32 { + private static final UnicodeSet INSTANCE = new UnicodeSet("[:age=3.2:]").freeze(); + } + + private static final class NFD32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFDInstance(), Unicode32.INSTANCE)); + } + + private static final class NFKD32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFKDInstance(), Unicode32.INSTANCE)); + } + + private static final class NFC32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFCInstance(), Unicode32.INSTANCE)); + } + + private static final class NFKC32ModeImpl { + private static final ModeImpl INSTANCE = new ModeImpl( + new FilteredNormalizer2(Normalizer2.getNFKCInstance(), Unicode32.INSTANCE)); + } + + /** + * Options bit set value to select Unicode 3.2 normalization (except + * NormalizationCorrections). At most one Unicode version can be selected at a + * time. + * + * @stable ICU 2.6 + */ + public static final int UNICODE_3_2 = 0x20; + + public static final int UNICODE_3_2_0_ORIGINAL = UNICODE_3_2; + + /* + * Default option for the latest Unicode normalization. This option is provided + * mainly for testing. The value zero means that normalization is done with the + * fixes for - Corrigendum 4 (Five CJK Canonical Mapping Errors) - Corrigendum 5 + * (Normalization Idempotency) + */ + public static final int UNICODE_LATEST = 0x00; + + /** + * Constant indicating that the end of the iteration has been reached. This is + * guaranteed to have the same value as {@link UCharacterIterator#DONE}. + * + * @stable ICU 2.8 + */ + public static final int DONE = UCharacterIterator.DONE; + + /** + * Constants for normalization modes. + *

+ * The Mode class is not intended for public subclassing. Only the Mode + * constants provided by the Normalizer class should be used, and any fields or + * methods should not be called or overridden by users. + * + * @stable ICU 2.8 + */ + public abstract static class Mode { + + /** + * Sole constructor + * + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected Mode() { + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected abstract Normalizer2 getNormalizer2(int options); + } + + private static Mode toMode(Normalizer.Form form) { + switch (form) { + case NFC: + return NFC; + case NFD: + return NFD; + case NFKC: + return NFKC; + case NFKD: + return NFKD; + } + + throw new IllegalArgumentException("Unexpected normalization form: " + form); + } + + private static final class NONEMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return Norm2AllModes.NOOP_NORMALIZER2; + } + } + + private static final class NFDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFD32ModeImpl.INSTANCE.normalizer2 : NFDModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFKDMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFKD32ModeImpl.INSTANCE.normalizer2 + : NFKDModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFC32ModeImpl.INSTANCE.normalizer2 : NFCModeImpl.INSTANCE.normalizer2; + } + } + + private static final class NFKCMode extends Mode { + protected Normalizer2 getNormalizer2(int options) { + return (options & UNICODE_3_2) != 0 ? NFKC32ModeImpl.INSTANCE.normalizer2 + : NFKCModeImpl.INSTANCE.normalizer2; + } + } + + /** + * No decomposition/composition. + * + * @stable ICU 2.8 + */ + public static final Mode NONE = new NONEMode(); + + /** + * Canonical decomposition. + * + * @stable ICU 2.8 + */ + public static final Mode NFD = new NFDMode(); + + /** + * Compatibility decomposition. + * + * @stable ICU 2.8 + */ + public static final Mode NFKD = new NFKDMode(); + + /** + * Canonical decomposition followed by canonical composition. + * + * @stable ICU 2.8 + */ + public static final Mode NFC = new NFCMode(); + + public static final Mode NFKC = new NFKCMode(); + + // ------------------------------------------------------------------------- + // Iterator constructors + // ------------------------------------------------------------------------- + + /** + * Creates a new {@code NormalizerBase} object for iterating over the normalized + * form of a given string. + *

+ * The {@code options} parameter specifies which optional {@code NormalizerBase} + * features are to be enabled for this object. + *

+ * + * @param str The string to be normalized. The normalization will start at the + * beginning of the string. + * + * @param mode The normalization mode. + * + * @param opt Any optional features to be enabled. Currently the only available + * option is {@link #UNICODE_3_2}. If you want the default behavior + * corresponding to one of the standard Unicode Normalization Forms, + * use 0 for this argument. + * @stable ICU 2.6 + */ + public NormalizerBase(String str, Mode mode, int opt) { + this.text = UCharacterIterator.getInstance(str); + this.mode = mode; + this.options = opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); + } + + public NormalizerBase(String str, Mode mode) { + this(str, mode, 0); + } + + /** + * Creates a new {@code NormalizerBase} object for iterating over the normalized + * form of the given text. + *

+ * + * @param iter The input text to be normalized. The normalization will start at + * the beginning of the string. + * + * @param mode The normalization mode. + * + * @param opt Any optional features to be enabled. Currently the only available + * option is {@link #UNICODE_3_2}. If you want the default behavior + * corresponding to one of the standard Unicode Normalization Forms, + * use 0 for this argument. + * @stable ICU 2.6 + */ + public NormalizerBase(CharacterIterator iter, Mode mode, int opt) { + this.text = UCharacterIterator.getInstance((CharacterIterator) iter.clone()); + this.mode = mode; + this.options = opt; + norm2 = mode.getNormalizer2(opt); + buffer = new StringBuilder(); + } + + public NormalizerBase(CharacterIterator iter, Mode mode) { + this(iter, mode, 0); + } + + /** + * Clones this {@code NormalizerBase} object. All properties of this object are + * duplicated in the new object, including the cloning of any + * {@link CharacterIterator} that was passed in to the constructor or to + * {@link #setText(CharacterIterator) setText}. However, the text storage + * underlying the {@code CharacterIterator} is not duplicated unless the + * iterator's {@code clone} method does so. + * + * @stable ICU 2.8 + */ + public Object clone() { + try { + NormalizerBase copy = (NormalizerBase) super.clone(); + copy.text = (UCharacterIterator) text.clone(); + copy.mode = mode; + copy.options = options; + copy.norm2 = norm2; + copy.buffer = new StringBuilder(buffer); + copy.bufferPos = bufferPos; + copy.currentIndex = currentIndex; + copy.nextIndex = nextIndex; + return copy; + } catch (CloneNotSupportedException e) { + throw new InternalError(e.toString(), e); + } + } + + /** + * Normalizes a {@code String} using the given normalization operation. + *

+ * The {@code options} parameter specifies which optional {@code NormalizerBase} + * features are to be enabled for this operation. Currently the only available + * option is {@link #UNICODE_3_2}. If you want the default behavior + * corresponding to one of the standard Unicode Normalization Forms, use 0 for + * this argument. + *

+ * + * @param str the input string to be normalized. + * @param mode the normalization mode + * @param options the optional features to be enabled. + * @return String the normalized string + * @stable ICU 2.6 + */ + public static String normalize(String str, Mode mode, int options) { + return mode.getNormalizer2(options).normalize(str); + } + + public static String normalize(String str, Normalizer.Form form) { + return NormalizerBase.normalize(str, toMode(form), UNICODE_LATEST); + } + + public static String normalize(String str, Normalizer.Form form, int options) { + return NormalizerBase.normalize(str, toMode(form), options); + } + + /** + * Test if a string is in a given normalization form. This is semantically + * equivalent to source.equals(normalize(source, mode)). + * + * Unlike quickCheck(), this function returns a definitive result, never a + * "maybe". For NFD, NFKD, and FCD, both functions work exactly the same. For + * NFC and NFKC where quickCheck may return "maybe", this function will perform + * further tests to arrive at a true/false result. + * + * @param str the input string to be checked to see if it is normalized + * @param mode the normalization mode + * @param options Options for use with exclusion set and tailored Normalization + * The only option that is currently recognized is UNICODE_3_2 + * @see #isNormalized + * @stable ICU 2.6 + */ + public static boolean isNormalized(String str, Mode mode, int options) { + return mode.getNormalizer2(options).isNormalized(str); + } + + public static boolean isNormalized(String str, Normalizer.Form form) { + return NormalizerBase.isNormalized(str, toMode(form), UNICODE_LATEST); + } + + public static boolean isNormalized(String str, Normalizer.Form form, int options) { + return NormalizerBase.isNormalized(str, toMode(form), options); + } + + // ------------------------------------------------------------------------- + // Iteration API + // ------------------------------------------------------------------------- + + /** + * Return the current character in the normalized text. + * + * @return The codepoint as an int + * @stable ICU 2.8 + */ + public int current() { + if (bufferPos < buffer.length() || nextNormalize()) { + return buffer.codePointAt(bufferPos); + } else { + return DONE; + } + } + + /** + * Return the next character in the normalized text and advance the iteration + * position by one. If the end of the text has already been reached, + * {@link #DONE} is returned. + * + * @return The codepoint as an int + * @stable ICU 2.8 + */ + public int next() { + if (bufferPos < buffer.length() || nextNormalize()) { + int c = buffer.codePointAt(bufferPos); + bufferPos += Character.charCount(c); + return c; + } else { + return DONE; + } + } + + /** + * Return the previous character in the normalized text and decrement the + * iteration position by one. If the beginning of the text has already been + * reached, {@link #DONE} is returned. + * + * @return The codepoint as an int + * @stable ICU 2.8 + */ + public int previous() { + if (bufferPos > 0 || previousNormalize()) { + int c = buffer.codePointBefore(bufferPos); + bufferPos -= Character.charCount(c); + return c; + } else { + return DONE; + } + } + + /** + * Reset the index to the beginning of the text. This is equivalent to + * setIndexOnly(startIndex)). + * + * @stable ICU 2.8 + */ + public void reset() { + text.setIndex(0); + currentIndex = nextIndex = 0; + clearBuffer(); + } + + /** + * Set the iteration position in the input text that is being normalized, + * without any immediate normalization. After setIndexOnly(), getIndex() will + * return the same index that is specified here. + * + * @param index the desired index in the input text. + * @stable ICU 2.8 + */ + public void setIndexOnly(int index) { + text.setIndex(index); // validates index + currentIndex = nextIndex = index; + clearBuffer(); + } + + /** + * Set the iteration position in the input text that is being normalized and + * return the first normalized character at that position. + *

+ * Note: This method sets the position in the input text, while + * {@link #next} and {@link #previous} iterate through characters in the + * normalized output. This means that there is not necessarily a + * one-to-one correspondence between characters returned by {@code next} and + * {@code previous} and the indices passed to and returned from {@code setIndex} + * and {@link #getIndex}. + *

+ * + * @param index the desired index in the input text. + * + * @return the first normalized character that is the result of iterating + * forward starting at the given index. + * + * @throws IllegalArgumentException if the given index is less than + * {@link #getBeginIndex} or greater than + * {@link #getEndIndex}. deprecated ICU 3.2 + * @obsolete ICU 3.2 + */ + public int setIndex(int index) { + setIndexOnly(index); + return current(); + } + + /** + * Retrieve the index of the start of the input text. This is the begin index of + * the {@code CharacterIterator} or the start (i.e. 0) of the {@code String} + * over which this {@code NormalizerBase} is iterating + * + * @deprecated ICU 2.2. Use startIndex() instead. + * @return The codepoint as an int + * @see #startIndex + */ + @Deprecated + public int getBeginIndex() { + return 0; + } + + /** + * Retrieve the index of the end of the input text. This is the end index of the + * {@code CharacterIterator} or the length of the {@code String} over which this + * {@code NormalizerBase} is iterating + * + * @deprecated ICU 2.2. Use endIndex() instead. + * @return The codepoint as an int + * @see #endIndex + */ + @Deprecated + public int getEndIndex() { + return endIndex(); + } + + /** + * Retrieve the current iteration position in the input text that is being + * normalized. This method is useful in applications such as searching, where + * you need to be able to determine the position in the input text that + * corresponds to a given normalized output character. + *

+ * Note: This method sets the position in the input, while + * {@link #next} and {@link #previous} iterate through characters in the + * output. This means that there is not necessarily a one-to-one + * correspondence between characters returned by {@code next} and + * {@code previous} and the indices passed to and returned from {@code setIndex} + * and {@link #getIndex}. + * + * @return The current iteration position + * @stable ICU 2.8 + */ + public int getIndex() { + if (bufferPos < buffer.length()) { + return currentIndex; + } else { + return nextIndex; + } + } + + /** + * Retrieve the index of the end of the input text. This is the end index of the + * {@code CharacterIterator} or the length of the {@code String} over which this + * {@code NormalizerBase} is iterating + * + * @return The current iteration position + * @stable ICU 2.8 + */ + public int endIndex() { + return text.getLength(); + } + + // ------------------------------------------------------------------------- + // Iterator attributes + // ------------------------------------------------------------------------- + /** + * Set the normalization mode for this object. + *

+ * Note:If the normalization mode is changed while iterating over a + * string, calls to {@link #next} and {@link #previous} may return previously + * buffers characters in the old normalization mode until the iteration is able + * to re-sync at the next base character. It is safest to call {@link #setText + * setText()}, {@link #first}, {@link #last}, etc. after calling + * {@code setMode}. + *

+ * + * @param newMode the new mode for this {@code NormalizerBase}. The supported + * modes are: + *

    + *
  • {@link #NFC} - Unicode canonical decompositiion followed + * by canonical composition. + *
  • {@link #NFKC} - Unicode compatibility decompositiion + * follwed by canonical composition. + *
  • {@link #NFD} - Unicode canonical decomposition + *
  • {@link #NFKD} - Unicode compatibility decomposition. + *
  • {@link #NONE} - Do nothing but return characters from the + * underlying input text. + *
+ * + * @see #getMode + * @stable ICU 2.8 + */ + public void setMode(Mode newMode) { + mode = newMode; + norm2 = mode.getNormalizer2(options); + } + + /** + * Return the basic operation performed by this {@code NormalizerBase} + * + * @see #setMode + * @stable ICU 2.8 + */ + public Mode getMode() { + return mode; + } + + /** + * Set the input text over which this {@code NormalizerBase} will iterate. The + * iteration position is set to the beginning of the input text. + * + * @param newText The new string to be normalized. + * @stable ICU 2.8 + */ + public void setText(String newText) { + UCharacterIterator newIter = UCharacterIterator.getInstance(newText); + if (newIter == null) { + throw new IllegalStateException("Could not create a new UCharacterIterator"); + } + text = newIter; + reset(); + } + + /** + * Set the input text over which this {@code NormalizerBase} will iterate. The + * iteration position is set to the beginning of the input text. + * + * @param newText The new string to be normalized. + * @stable ICU 2.8 + */ + public void setText(CharacterIterator newText) { + UCharacterIterator newIter = UCharacterIterator.getInstance(newText); + if (newIter == null) { + throw new IllegalStateException("Could not create a new UCharacterIterator"); + } + text = newIter; + currentIndex = nextIndex = 0; + clearBuffer(); + } + + private void clearBuffer() { + buffer.setLength(0); + bufferPos = 0; + } + + private boolean nextNormalize() { + clearBuffer(); + currentIndex = nextIndex; + text.setIndex(nextIndex); + // Skip at least one character so we make progress. + int c = text.nextCodePoint(); + if (c < 0) { + return false; + } + StringBuilder segment = new StringBuilder().appendCodePoint(c); + while ((c = text.nextCodePoint()) >= 0) { + if (norm2.hasBoundaryBefore(c)) { + text.moveCodePointIndex(-1); + break; + } + segment.appendCodePoint(c); + } + nextIndex = text.getIndex(); + norm2.normalize(segment, buffer); + return buffer.length() != 0; + } + + private boolean previousNormalize() { + clearBuffer(); + nextIndex = currentIndex; + text.setIndex(currentIndex); + StringBuilder segment = new StringBuilder(); + int c; + while ((c = text.previousCodePoint()) >= 0) { + if (c <= 0xffff) { + segment.insert(0, (char) c); + } else { + segment.insert(0, Character.toChars(c)); + } + if (norm2.hasBoundaryBefore(c)) { + break; + } + } + currentIndex = text.getIndex(); + norm2.normalize(segment, buffer); + bufferPos = buffer.length(); + return buffer.length() != 0; + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/Replaceable.java b/src/main/java/jdk_internal/bidi/icu/text/Replaceable.java new file mode 100755 index 00000000..22c7fff6 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/Replaceable.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +/** + * Replaceable is an interface representing a string of characters + * that supports the replacement of a range of itself with a new string of + * characters. It is used by APIs that change a piece of text while retaining + * metadata. Metadata is data other than the Unicode characters returned by + * char32At(). One example of metadata is style attributes; another is an edit + * history, marking each character with an author and revision number. + * + *

+ * An implicit aspect of the Replaceable API is that during a + * replace operation, new characters take on the metadata of the old characters. + * For example, if the string "the bold font" has range (4, 8) replaced + * with "strong", then it becomes "the strong font". + * + *

+ * Replaceable specifies ranges using a start offset and a limit + * offset. The range of characters thus specified includes the characters at + * offset start..limit-1. That is, the start offset is inclusive, and the limit + * offset is exclusive. + * + *

+ * Replaceable also includes API to access characters in the + * string: length(), charAt(), + * char32At(), and extractBetween(). + * + *

+ * For a subclass to support metadata, typical behavior of + * replace() is the following: + *

    + *
  • Set the metadata of the new text to the metadata of the first character + * replaced
  • + *
  • If no characters are replaced, use the metadata of the previous + * character
  • + *
  • If there is no previous character (i.e. start == 0), use the following + * character
  • + *
  • If there is no following character (i.e. the replaceable was empty), use + * default metadata
  • + *
  • If the code point U+FFFF is seen, it should be interpreted as a special + * marker having no metadata
  • + *
+ * If this is not the behavior, the subclass should document any differences. + * + *

+ * Copyright © IBM Corporation 1999. All rights reserved. + * + * @author Alan Liu + * @stable ICU 2.0 + */ +public interface Replaceable { + /** + * Returns the number of 16-bit code units in the text. + * + * @return number of 16-bit code units in text + * @stable ICU 2.0 + */ + int length(); + + /** + * Returns the 16-bit code unit at the given offset into the text. + * + * @param offset an integer between 0 and length()-1 inclusive + * @return 16-bit code unit of text at given offset + * @stable ICU 2.0 + */ + char charAt(int offset); + + /** + * Copies characters from this object into the destination character array. The + * first character to be copied is at index srcStart; the last + * character to be copied is at index srcLimit-1 (thus the total + * number of characters to be copied is srcLimit-srcStart). The + * characters are copied into the subarray of dst starting at index + * dstStart and ending at index + * dstStart + (srcLimit-srcStart) - 1. + * + * @param srcStart the beginning index to copy, inclusive; + * {@code 0 <= start <= limit}. + * @param srcLimit the ending index to copy, exclusive; + * {@code start <= limit <= length()}. + * @param dst the destination array. + * @param dstStart the start offset in the destination array. + * @stable ICU 2.0 + */ + void getChars(int srcStart, int srcLimit, char dst[], int dstStart); +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/ReplaceableString.java b/src/main/java/jdk_internal/bidi/icu/text/ReplaceableString.java new file mode 100755 index 00000000..661eccac --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/ReplaceableString.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2009, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +/** + * ReplaceableString is an adapter class that implements the + * Replaceable API around an ordinary StringBuffer. + * + *

+ * Note: This class does not support attributes and is not intended for + * general use. Most clients will need to implement {@link Replaceable} in their + * text representation class. + * + *

+ * Copyright © IBM Corporation 1999. All rights reserved. + * + * @see Replaceable + * @author Alan Liu + * @stable ICU 2.0 + */ +public class ReplaceableString implements Replaceable { + + private StringBuffer buf; + + /** + * Construct a new object with the given initial contents. + * + * @param str initial contents + * @stable ICU 2.0 + */ + public ReplaceableString(String str) { + buf = new StringBuffer(str); + } + + /** + * Construct a new object using buf for internal storage. The + * contents of buf at the time of construction are used as the + * initial contents. Note! Modifications to buf will modify + * this object, and vice versa. + * + * @param buf object to be used as internal storage + * @stable ICU 2.0 + */ + public ReplaceableString(StringBuffer buf) { + this.buf = buf; + } + + /** + * Return the number of characters contained in this object. + * Replaceable API. + * + * @stable ICU 2.0 + */ + public int length() { + return buf.length(); + } + + /** + * Return the character at the given position in this object. + * Replaceable API. + * + * @param offset offset into the contents, from 0 to length() - 1 + * @stable ICU 2.0 + */ + public char charAt(int offset) { + return buf.charAt(offset); + } + + /** + * Copies characters from this object into the destination character array. The + * first character to be copied is at index srcStart; the last + * character to be copied is at index srcLimit-1 (thus the total + * number of characters to be copied is srcLimit-srcStart). The + * characters are copied into the subarray of dst starting at index + * dstStart and ending at index + * dstStart + (srcLimit-srcStart) - 1. + * + * @param srcStart the beginning index to copy, inclusive; + * {@code 0 <= start <= limit}. + * @param srcLimit the ending index to copy, exclusive; + * {@code start <= limit <= length()}. + * @param dst the destination array. + * @param dstStart the start offset in the destination array. + * @stable ICU 2.0 + */ + public void getChars(int srcStart, int srcLimit, char dst[], int dstStart) { + if (srcStart != srcLimit) { + buf.getChars(srcStart, srcLimit, dst, dstStart); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/StringPrep.java b/src/main/java/jdk_internal/bidi/icu/text/StringPrep.java new file mode 100755 index 00000000..da41151a --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/StringPrep.java @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* +/* + ******************************************************************************* + * Copyright (C) 2003-2004, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +// +// CHANGELOG +// 2005-05-19 Edward Wang +// - copy this file from icu4jsrc_3_2/src/com/ibm/icu/text/StringPrep.java +// - move from package com.ibm.icu.text to package sun.net.idn +// - use ParseException instead of StringPrepParseException +// - change 'Normalizer.getUnicodeVersion()' to 'NormalizerImpl.getUnicodeVersion()' +// - remove all @deprecated tag to make compiler happy +// 2007-08-14 Martin Buchholz +// - remove redundant casts +// +package jdk_internal.bidi.icu.text; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import jdk_internal.bidi.Normalizer; +import jdk_internal.bidi.ParseException; +import jdk_internal.bidi.SunNormalizer; +import jdk_internal.bidi.icu.impl.CharTrie; +import jdk_internal.bidi.icu.impl.StringPrepDataReader; +import jdk_internal.bidi.icu.impl.Trie; +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.lang.UCharacterDirection; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + * StringPrep API implements the StingPrep framework as described by + * RFC 3454. StringPrep + * prepares Unicode strings for use in network protocols. Profiles of StingPrep + * are set of rules and data according to which the Unicode Strings are + * prepared. Each profiles contains tables which describe how a code point + * should be treated. The tables are broadly classied into + *

    + *
  • Unassigned Table: Contains code points that are unassigned in the Unicode + * Version supported by StringPrep. Currently RFC 3454 supports Unicode 3.2. + *
  • + *
  • Prohibited Table: Contains code points that are prohibted from the output + * of the StringPrep processing function.
  • + *
  • Mapping Table: Contains code ponts that are deleted from the output or + * case mapped.
  • + *
+ * + * The procedure for preparing Unicode strings: + *
    + *
  1. Map: For each character in the input, check if it has a mapping and, if + * so, replace it with its mapping.
  2. + *
  3. Normalize: Possibly normalize the result of step 1 using Unicode + * normalization.
  4. + *
  5. Prohibit: Check for any characters that are not allowed in the output. If + * any are found, return an error.
  6. + *
  7. Check bidi: Possibly check for right-to-left characters, and if any are + * found, make sure that the whole string satisfies the requirements for + * bidirectional strings. If the string does not satisfy the requirements for + * bidirectional strings, return an error.
  8. + *
+ * + * @author Ram Viswanadha + * @draft ICU 2.8 + */ +public final class StringPrep { + /** + * Option to prohibit processing of unassigned code points in the input + * + * @see #prepare + * @draft ICU 2.8 + */ + public static final int DEFAULT = 0x0000; + + /** + * Option to allow processing of unassigned code points in the input + * + * @see #prepare + * @draft ICU 2.8 + */ + public static final int ALLOW_UNASSIGNED = 0x0001; + + private static final int UNASSIGNED = 0x0000; + private static final int MAP = 0x0001; + private static final int PROHIBITED = 0x0002; + private static final int DELETE = 0x0003; + private static final int TYPE_LIMIT = 0x0004; + + private static final int NORMALIZATION_ON = 0x0001; + private static final int CHECK_BIDI_ON = 0x0002; + + private static final int TYPE_THRESHOLD = 0xFFF0; + private static final int MAX_INDEX_VALUE = 0x3FBF; /* 16139 */ + private static final int MAX_INDEX_TOP_LENGTH = 0x0003; + + /* indexes[] value names */ + private static final int INDEX_TRIE_SIZE = 0; /* number of bytes in normalization trie */ + private static final int INDEX_MAPPING_DATA_SIZE = 1; /* The array that contains the mapping */ + private static final int NORM_CORRECTNS_LAST_UNI_VERSION = 2; /* + * The index of Unicode version of last entry in + * NormalizationCorrections.txt + */ + private static final int ONE_UCHAR_MAPPING_INDEX_START = 3; /* + * The starting index of 1 UChar mapping index in the + * mapping data array + */ + private static final int TWO_UCHARS_MAPPING_INDEX_START = 4; /* + * The starting index of 2 UChars mapping index in + * the mapping data array + */ + private static final int THREE_UCHARS_MAPPING_INDEX_START = 5; + private static final int FOUR_UCHARS_MAPPING_INDEX_START = 6; + private static final int OPTIONS = 7; /* Bit set of options to turn on in the profile */ + private static final int INDEX_TOP = 16; /* changing this requires a new formatVersion */ + + /** + * Default buffer size of datafile + */ + private static final int DATA_BUFFER_SIZE = 25000; + + /* Wrappers for Trie implementations */ + private static final class StringPrepTrieImpl implements Trie.DataManipulate { + private CharTrie sprepTrie = null; + + /** + * Called by com.ibm.icu.util.Trie to extract from a lead surrogate's data the + * index array offset of the indexes for that lead surrogate. + * + * @param property data value for a surrogate from the trie, including the + * folding offset + * @return data offset or 0 if there is no data for the lead surrogate + */ + public int getFoldingOffset(int value) { + return value; + } + } + + // CharTrie implementation for reading the trie data + private StringPrepTrieImpl sprepTrieImpl; + // Indexes read from the data file + private int[] indexes; + // mapping data read from the data file + private char[] mappingData; + // format version of the data file + private byte[] formatVersion; + // the version of Unicode supported by the data file + private VersionInfo sprepUniVer; + // the Unicode version of last entry in the + // NormalizationCorrections.txt file if normalization + // is turned on + private VersionInfo normCorrVer; + // Option to turn on Normalization + private boolean doNFKC; + // Option to turn on checking for BiDi rules + private boolean checkBiDi; + + private char getCodePointValue(int ch) { + return sprepTrieImpl.sprepTrie.getCodePointValue(ch); + } + + private static VersionInfo getVersionInfo(int comp) { + int micro = comp & 0xFF; + int milli = (comp >> 8) & 0xFF; + int minor = (comp >> 16) & 0xFF; + int major = (comp >> 24) & 0xFF; + return VersionInfo.getInstance(major, minor, milli, micro); + } + + private static VersionInfo getVersionInfo(byte[] version) { + if (version.length != 4) { + return null; + } + return VersionInfo.getInstance((int) version[0], (int) version[1], (int) version[2], (int) version[3]); + } + + /** + * Creates an StringPrep object after reading the input stream. The object does + * not hold a reference to the input steam, so the stream can be closed after + * the method returns. + * + * @param inputStream The stream for reading the StringPrep profile binarySun + * @throws IOException + * @draft ICU 2.8 + */ + public StringPrep(InputStream inputStream) throws IOException { + + BufferedInputStream b = new BufferedInputStream(inputStream, DATA_BUFFER_SIZE); + + StringPrepDataReader reader = new StringPrepDataReader(b); + + // read the indexes + indexes = reader.readIndexes(INDEX_TOP); + + byte[] sprepBytes = new byte[indexes[INDEX_TRIE_SIZE]]; + + // indexes[INDEX_MAPPING_DATA_SIZE] store the size of mappingData in bytes + mappingData = new char[indexes[INDEX_MAPPING_DATA_SIZE] / 2]; + // load the rest of the data and initialize the data members + reader.read(sprepBytes, mappingData); + + sprepTrieImpl = new StringPrepTrieImpl(); + sprepTrieImpl.sprepTrie = new CharTrie(new ByteArrayInputStream(sprepBytes), sprepTrieImpl); + + // get the data format version + formatVersion = reader.getDataFormatVersion(); + + // get the options + doNFKC = ((indexes[OPTIONS] & NORMALIZATION_ON) > 0); + checkBiDi = ((indexes[OPTIONS] & CHECK_BIDI_ON) > 0); + sprepUniVer = getVersionInfo(reader.getUnicodeVersion()); + normCorrVer = getVersionInfo(indexes[NORM_CORRECTNS_LAST_UNI_VERSION]); + VersionInfo normUniVer = UCharacter.getUnicodeVersion(); + if (normUniVer.compareTo(sprepUniVer) < 0 && /* + * the Unicode version of SPREP file must be less than the + * Unicode Vesion of the normalization data + */ + normUniVer.compareTo(normCorrVer) < 0 + && /* + * the Unicode version of the NormalizationCorrections.txt file should be less + * than the Unicode Vesion of the normalization data + */ + ((indexes[OPTIONS] & NORMALIZATION_ON) > 0) /* normalization turned on */ + ) { + throw new IOException("Normalization Correction version not supported"); + } + b.close(); + } + + private static final class Values { + boolean isIndex; + int value; + int type; + + public void reset() { + isIndex = false; + value = 0; + type = -1; + } + } + + private static final void getValues(char trieWord, Values values) { + values.reset(); + if (trieWord == 0) { + /* + * Initial value stored in the mapping table just return TYPE_LIMIT .. so that + * the source codepoint is copied to the destination + */ + values.type = TYPE_LIMIT; + } else if (trieWord >= TYPE_THRESHOLD) { + values.type = (trieWord - TYPE_THRESHOLD); + } else { + /* get the type */ + values.type = MAP; + /* ascertain if the value is index or delta */ + if ((trieWord & 0x02) > 0) { + values.isIndex = true; + values.value = trieWord >> 2; // mask off the lower 2 bits and shift + + } else { + values.isIndex = false; + values.value = (trieWord << 16) >> 16; + values.value = (values.value >> 2); + + } + + if ((trieWord >> 2) == MAX_INDEX_VALUE) { + values.type = DELETE; + values.isIndex = false; + values.value = 0; + } + } + } + + private StringBuffer map(UCharacterIterator iter, int options) throws ParseException { + + Values val = new Values(); + char result = 0; + int ch = UCharacterIterator.DONE; + StringBuffer dest = new StringBuffer(); + boolean allowUnassigned = ((options & ALLOW_UNASSIGNED) > 0); + + while ((ch = iter.nextCodePoint()) != UCharacterIterator.DONE) { + + result = getCodePointValue(ch); + getValues(result, val); + + // check if the source codepoint is unassigned + if (val.type == UNASSIGNED && allowUnassigned == false) { + throw new ParseException("An unassigned code point was found in the input " + iter.getText(), + iter.getIndex()); + } else if ((val.type == MAP)) { + int index, length; + + if (val.isIndex) { + index = val.value; + if (index >= indexes[ONE_UCHAR_MAPPING_INDEX_START] + && index < indexes[TWO_UCHARS_MAPPING_INDEX_START]) { + length = 1; + } else if (index >= indexes[TWO_UCHARS_MAPPING_INDEX_START] + && index < indexes[THREE_UCHARS_MAPPING_INDEX_START]) { + length = 2; + } else if (index >= indexes[THREE_UCHARS_MAPPING_INDEX_START] + && index < indexes[FOUR_UCHARS_MAPPING_INDEX_START]) { + length = 3; + } else { + length = mappingData[index++]; + } + /* copy mapping to destination */ + dest.append(mappingData, index, length); + continue; + + } else { + ch -= val.value; + } + } else if (val.type == DELETE) { + // just consume the codepoint and contine + continue; + } + // copy the source into destination + UTF16.append(dest, ch); + } + + return dest; + } + + private StringBuffer normalize(StringBuffer src) { + /* + * Option UNORM_BEFORE_PRI_29: + * + * IDNA as interpreted by IETF members (see unicode mailing list 2004H1) + * requires strict adherence to Unicode 3.2 normalization, including buggy + * composition from before fixing Public Review Issue #29. Note that this + * results in some valid but nonsensical text to be either corrupted or + * rejected, depending on the text. See + * http://www.unicode.org/review/resolved-pri.html#pri29 See unorm.cpp and + * cnormtst.c + */ + return new StringBuffer( + SunNormalizer.normalize(src.toString(), Normalizer.Form.NFKC, SunNormalizer.UNICODE_3_2)); + } + + /* + * boolean isLabelSeparator(int ch){ int result = getCodePointValue(ch); if( + * (result & 0x07) == LABEL_SEPARATOR){ return true; } return false; } + */ + /* + * 1) Map -- For each character in the input, check if it has a mapping and, if + * so, replace it with its mapping. + * + * 2) Normalize -- Possibly normalize the result of step 1 using Unicode + * normalization. + * + * 3) Prohibit -- Check for any characters that are not allowed in the output. + * If any are found, return an error. + * + * 4) Check bidi -- Possibly check for right-to-left characters, and if any are + * found, make sure that the whole string satisfies the requirements for + * bidirectional strings. If the string does not satisfy the requirements for + * bidirectional strings, return an error. [Unicode3.2] defines several + * bidirectional categories; each character has one bidirectional category + * assigned to it. For the purposes of the requirements below, an + * "RandALCat character" is a character that has Unicode bidirectional + * categories "R" or "AL"; an "LCat character" is a character that has Unicode + * bidirectional category "L". Note + * + * + * that there are many characters which fall in neither of the above + * definitions; Latin digits ( through ) are examples of this + * because they have bidirectional category "EN". + * + * In any profile that specifies bidirectional character handling, all three of + * the following requirements MUST be met: + * + * 1) The characters in section 5.8 MUST be prohibited. + * + * 2) If a string contains any RandALCat character, the string MUST NOT contain + * any LCat character. + * + * 3) If a string contains any RandALCat character, a RandALCat character MUST + * be the first character of the string, and a RandALCat character MUST be the + * last character of the string. + */ + /** + * Prepare the input buffer for use in applications with the given profile. This + * operation maps, normalizes(NFKC), checks for prohited and BiDi characters in + * the order defined by RFC 3454 depending on the options specified in the + * profile. + * + * @param src A UCharacterIterator object containing the source string + * @param options A bit set of options: + * + * - StringPrep.NONE Prohibit processing of unassigned code + * points in the input + * + * - StringPrep.ALLOW_UNASSIGNED Treat the unassigned code points + * are in the input as normal Unicode code points. + * + * @return StringBuffer A StringBuffer containing the output + * @throws ParseException + * @draft ICU 2.8 + */ + public StringBuffer prepare(UCharacterIterator src, int options) throws ParseException { + + // map + StringBuffer mapOut = map(src, options); + StringBuffer normOut = mapOut;// initialize + + if (doNFKC) { + // normalize + normOut = normalize(mapOut); + } + + int ch; + char result; + UCharacterIterator iter = UCharacterIterator.getInstance(normOut); + Values val = new Values(); + int direction = UCharacterDirection.CHAR_DIRECTION_COUNT, + firstCharDir = UCharacterDirection.CHAR_DIRECTION_COUNT; + int rtlPos = -1, ltrPos = -1; + boolean rightToLeft = false, leftToRight = false; + + while ((ch = iter.nextCodePoint()) != UCharacterIterator.DONE) { + result = getCodePointValue(ch); + getValues(result, val); + + if (val.type == PROHIBITED) { + throw new ParseException("A prohibited code point was found in the input" + iter.getText(), val.value); + } + + direction = UCharacter.getDirection(ch); + if (firstCharDir == UCharacterDirection.CHAR_DIRECTION_COUNT) { + firstCharDir = direction; + } + if (direction == UCharacterDirection.LEFT_TO_RIGHT) { + leftToRight = true; + ltrPos = iter.getIndex() - 1; + } + if (direction == UCharacterDirection.RIGHT_TO_LEFT + || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC) { + rightToLeft = true; + rtlPos = iter.getIndex() - 1; + } + } + if (checkBiDi == true) { + // satisfy 2 + if (leftToRight == true && rightToLeft == true) { + throw new ParseException( + "The input does not conform to the rules for BiDi code points." + iter.getText(), + (rtlPos > ltrPos) ? rtlPos : ltrPos); + } + + // satisfy 3 + if (rightToLeft == true && !((firstCharDir == UCharacterDirection.RIGHT_TO_LEFT + || firstCharDir == UCharacterDirection.RIGHT_TO_LEFT_ARABIC) + && (direction == UCharacterDirection.RIGHT_TO_LEFT + || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC))) { + throw new ParseException( + "The input does not conform to the rules for BiDi code points." + iter.getText(), + (rtlPos > ltrPos) ? rtlPos : ltrPos); + } + } + return normOut; + + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/UCharacterIterator.java b/src/main/java/jdk_internal/bidi/icu/text/UCharacterIterator.java new file mode 100755 index 00000000..656b4df5 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/UCharacterIterator.java @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.CharacterIterator; +import jdk_internal.bidi.icu.impl.CharacterIteratorWrapper; +import jdk_internal.bidi.icu.impl.ReplaceableUCharacterIterator; +import jdk_internal.bidi.icu.impl.UCharacterProperty; + +/** + * Abstract class that defines an API for iteration on text objects.This is an + * interface for forward and backward iteration and random access into a text + * object. Forward iteration is done with post-increment and backward iteration + * is done with pre-decrement semantics, while the + * java.text.CharacterIterator interface methods provided forward + * iteration with "pre-increment" and backward iteration with pre-decrement + * semantics. This API is more efficient for forward iteration over code points. + * The other major difference is that this API can do both code unit and code + * point iteration, java.text.CharacterIterator can only iterate + * over code units and is limited to BMP (0 - 0xFFFF) + * + * @author Ram + * @stable ICU 2.4 + */ +public abstract class UCharacterIterator implements Cloneable { + + /** + * Protected default constructor for the subclasses + * + * @stable ICU 2.4 + */ + protected UCharacterIterator() { + } + + /** + * Indicator that we have reached the ends of the UTF16 text. Moved from + * UForwardCharacterIterator.java + * + * @stable ICU 2.4 + */ + public static final int DONE = -1; + + // static final methods ---------------------------------------------------- + + /** + * Returns a UCharacterIterator object given a source string. + * + * @param source a string + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(String source) { + return new ReplaceableUCharacterIterator(source); + } + + /** + * Returns a UCharacterIterator object given a source StringBuffer. + * + * @param source an string buffer of UTF-16 code units + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(StringBuffer source) { + return new ReplaceableUCharacterIterator(source); + } + + /** + * Returns a UCharacterIterator object given a CharacterIterator. + * + * @param source a valid CharacterIterator object. + * @return UCharacterIterator object + * @exception IllegalArgumentException if the argument is null + * @stable ICU 2.4 + */ + public static final UCharacterIterator getInstance(CharacterIterator source) { + return new CharacterIteratorWrapper(source); + } + + // public methods ---------------------------------------------------------- + + /** + * Returns the length of the text + * + * @return length of the text + * @stable ICU 2.4 + */ + public abstract int getLength(); + + /** + * Gets the current index in text. + * + * @return current index in text. + * @stable ICU 2.4 + */ + public abstract int getIndex(); + + /** + * Returns the UTF16 code unit at index, and increments to the next code unit + * (post-increment semantics). If index is out of range, DONE is returned, and + * the iterator is reset to the limit of the text. + * + * @return the next UTF16 code unit, or DONE if the index is at the limit of the + * text. + * @stable ICU 2.4 + */ + public abstract int next(); + + /** + * Returns the code point at index, and increments to the next code point + * (post-increment semantics). If index does not point to a valid surrogate + * pair, the behavior is the same as next(). Otherwise the iterator + * is incremented past the surrogate pair, and the code point represented by the + * pair is returned. + * + * @return the next codepoint in text, or DONE if the index is at the limit of + * the text. + * @stable ICU 2.4 + */ + public int nextCodePoint() { + int ch1 = next(); + if (UTF16.isLeadSurrogate((char) ch1)) { + int ch2 = next(); + if (UTF16.isTrailSurrogate((char) ch2)) { + return UCharacterProperty.getRawSupplementary((char) ch1, (char) ch2); + } else if (ch2 != DONE) { + // unmatched surrogate so back out + previous(); + } + } + return ch1; + } + + /** + * Decrement to the position of the previous code unit in the text, and return + * it (pre-decrement semantics). If the resulting index is less than 0, the + * index is reset to 0 and DONE is returned. + * + * @return the previous code unit in the text, or DONE if the new index is + * before the start of the text. + * @stable ICU 2.4 + */ + public abstract int previous(); + + /** + * Retreat to the start of the previous code point in the text, and return it + * (pre-decrement semantics). If the index is not preceeded by a valid surrogate + * pair, the behavior is the same as previous(). Otherwise the + * iterator is decremented to the start of the surrogate pair, and the code + * point represented by the pair is returned. + * + * @return the previous code point in the text, or DONE if the new index is + * before the start of the text. + * @stable ICU 2.4 + */ + public int previousCodePoint() { + int ch1 = previous(); + if (UTF16.isTrailSurrogate((char) ch1)) { + int ch2 = previous(); + if (UTF16.isLeadSurrogate((char) ch2)) { + return UCharacterProperty.getRawSupplementary((char) ch2, (char) ch1); + } else if (ch2 != DONE) { + // unmatched trail surrogate so back out + next(); + } + } + return ch1; + } + + /** + * Sets the index to the specified index in the text. + * + * @param index the index within the text. + * @exception IndexOutOfBoundsException is thrown if an invalid index is + * supplied + * @stable ICU 2.4 + */ + public abstract void setIndex(int index); + + /** + * Sets the current index to the start. + * + * @stable ICU 2.4 + */ + public void setToStart() { + setIndex(0); + } + + /** + * Fills the buffer with the underlying text storage of the iterator If the + * buffer capacity is not enough a exception is thrown. The capacity of the fill + * in buffer should at least be equal to length of text in the iterator obtained + * by calling getLength(). Usage: + * + *
{@code
+	 *         UChacterIterator iter = new UCharacterIterator.getInstance(text);
+	 *         char[] buf = new char[iter.getLength()];
+	 *         iter.getText(buf);
+	 *
+	 *         OR
+	 *         char[] buf= new char[1];
+	 *         int len = 0;
+	 *         for(;;){
+	 *             try{
+	 *                 len = iter.getText(buf);
+	 *                 break;
+	 *             }catch(IndexOutOfBoundsException e){
+	 *                 buf = new char[iter.getLength()];
+	 *             }
+	 *         }
+	 * }
+ * + * @param fillIn an array of chars to fill with the underlying UTF-16 code + * units. + * @param offset the position within the array to start putting the data. + * @return the number of code units added to fillIn, as a convenience + * @exception IndexOutOfBoundsException exception if there is not enough room + * after offset in the array, or if offset + * < 0. + * @stable ICU 2.4 + */ + public abstract int getText(char[] fillIn, int offset); + + /** + * Convenience override for getText(char[], int) that provides an + * offset of 0. + * + * @param fillIn an array of chars to fill with the underlying UTF-16 code + * units. + * @return the number of code units added to fillIn, as a convenience + * @exception IndexOutOfBoundsException exception if there is not enough room in + * the array. + * @stable ICU 2.4 + */ + public final int getText(char[] fillIn) { + return getText(fillIn, 0); + } + + /** + * Convenience method for returning the underlying text storage as a string + * + * @return the underlying text storage in the iterator as a string + * @stable ICU 2.4 + */ + public String getText() { + char[] text = new char[getLength()]; + getText(text); + return new String(text); + } + + /** + * Moves the current position by the number of code points specified, either + * forward or backward depending on the sign of delta (positive or negative + * respectively). If the current index is at a trail surrogate then the first + * adjustment is by code unit, and the remaining adjustments are by code points. + * If the resulting index would be less than zero, the index is set to zero, and + * if the resulting index would be greater than limit, the index is set to + * limit. + * + * @param delta the number of code units to move the current index. + * @return the new index + * @exception IndexOutOfBoundsException is thrown if an invalid delta is + * supplied + * @stable ICU 2.4 + * + */ + public int moveCodePointIndex(int delta) { + if (delta > 0) { + while (delta > 0 && nextCodePoint() != DONE) { + delta--; + } + } else { + while (delta < 0 && previousCodePoint() != DONE) { + delta++; + } + } + if (delta != 0) { + throw new IndexOutOfBoundsException(); + } + + return getIndex(); + } + + /** + * Creates a copy of this iterator, independent from other iterators. If it is + * not possible to clone the iterator, returns null. + * + * @return copy of this iterator + * @stable ICU 2.4 + */ + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/UTF16.java b/src/main/java/jdk_internal/bidi/icu/text/UTF16.java new file mode 100755 index 00000000..5a39fedf --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/UTF16.java @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + ******************************************************************************* + * Copyright (C) 1996-2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.text; + +import jdk_internal.bidi.icu.impl.UCharacterProperty; + +/** + *

+ * Standalone utility class providing UTF16 character conversions and indexing + * conversions. + *

+ * Code that uses strings alone rarely need modification. By design, UTF-16 does + * not allow overlap, so searching for strings is a safe operation. Similarly, + * concatenation is always safe. Substringing is safe if the start and end are + * both on UTF-32 boundaries. In normal code, the values for start and end are + * on those boundaries, since they arose from operations like searching. If not, + * the nearest UTF-32 boundaries can be determined using bounds(). + * Examples: + *

+ * The following examples illustrate use of some of these methods. + * + *

{@code
+ * // iteration forwards: Original
+ * for (int i = 0; i < s.length(); ++i) {
+ * 	char ch = s.charAt(i);
+ * 	doSomethingWith(ch);
+ * }
+ *
+ * // iteration forwards: Changes for UTF-32
+ * int ch;
+ * for (int i = 0; i < s.length(); i += UTF16.getCharCount(ch)) {
+ * 	ch = UTF16.charAt(s, i);
+ * 	doSomethingWith(ch);
+ * }
+ *
+ * // iteration backwards: Original
+ * for (int i = s.length() - 1; i >= 0; --i) {
+ * 	char ch = s.charAt(i);
+ * 	doSomethingWith(ch);
+ * }
+ *
+ * // iteration backwards: Changes for UTF-32
+ * int ch;
+ * for (int i = s.length() - 1; i > 0; i -= UTF16.getCharCount(ch)) {
+ * 	ch = UTF16.charAt(s, i);
+ * 	doSomethingWith(ch);
+ * }
+ * }
+ * + * Notes: + *
    + *
  • Naming: For clarity, High and Low surrogates are called + * Lead and Trail in the API, which gives a better + * sense of their ordering in a string. offset16 and + * offset32 are used to distinguish offsets to UTF-16 boundaries vs + * offsets to UTF-32 boundaries. int char32 is used to contain + * UTF-32 characters, as opposed to char16, which is a UTF-16 code + * unit.
  • + *
  • Roundtripping Offsets: You can always roundtrip from a + * UTF-32 offset to a UTF-16 offset and back. Because of the difference in + * structure, you can roundtrip from a UTF-16 offset to a UTF-32 offset and back + * if and only if bounds(string, offset16) != TRAIL.
  • + *
  • Exceptions: The error checking will throw an exception + * if indices are out of bounds. Other than that, all methods will behave + * reasonably, even if unmatched surrogates or out-of-bounds UTF-32 values are + * present. UCharacter.isLegal() can be used to check for validity + * if desired.
  • + *
  • Unmatched Surrogates: If the string contains unmatched + * surrogates, then these are counted as one UTF-32 value. This matches their + * iteration behavior, which is vital. It also matches common display practice + * as missing glyphs (see the Unicode Standard Section 5.4, 5.5).
  • + *
  • Optimization: The method implementations may need + * optimization if the compiler doesn't fold static final methods. Since + * surrogate pairs will form an exceeding small percentage of all the text in + * the world, the singleton case should always be optimized for.
  • + *
+ * + * @author Mark Davis, with help from Markus Scherer + * @stable ICU 2.1 + */ + +public final class UTF16 { + // public variables --------------------------------------------------- + + /** + * The lowest Unicode code point value. + * + * @stable ICU 2.1 + */ + public static final int CODEPOINT_MIN_VALUE = 0; + /** + * The highest Unicode code point value (scalar value) according to the Unicode + * Standard. + * + * @stable ICU 2.1 + */ + public static final int CODEPOINT_MAX_VALUE = 0x10ffff; + /** + * The minimum value for Supplementary code points + * + * @stable ICU 2.1 + */ + public static final int SUPPLEMENTARY_MIN_VALUE = 0x10000; + /** + * Lead surrogate minimum value + * + * @stable ICU 2.1 + */ + public static final int LEAD_SURROGATE_MIN_VALUE = 0xD800; + /** + * Trail surrogate minimum value + * + * @stable ICU 2.1 + */ + public static final int TRAIL_SURROGATE_MIN_VALUE = 0xDC00; + /** + * Lead surrogate maximum value + * + * @stable ICU 2.1 + */ + public static final int LEAD_SURROGATE_MAX_VALUE = 0xDBFF; + /** + * Trail surrogate maximum value + * + * @stable ICU 2.1 + */ + public static final int TRAIL_SURROGATE_MAX_VALUE = 0xDFFF; + /** + * Surrogate minimum value + * + * @stable ICU 2.1 + */ + public static final int SURROGATE_MIN_VALUE = LEAD_SURROGATE_MIN_VALUE; + /** + * Lead surrogate bitmask + */ + private static final int LEAD_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Trail surrogate bitmask + */ + private static final int TRAIL_SURROGATE_BITMASK = 0xFFFFFC00; + /** + * Surrogate bitmask + */ + private static final int SURROGATE_BITMASK = 0xFFFFF800; + /** + * Lead surrogate bits + */ + private static final int LEAD_SURROGATE_BITS = 0xD800; + /** + * Trail surrogate bits + */ + private static final int TRAIL_SURROGATE_BITS = 0xDC00; + /** + * Surrogate bits + */ + private static final int SURROGATE_BITS = 0xD800; + + // constructor -------------------------------------------------------- + + // /CLOVER:OFF + /** + * Prevent instance from being created. + */ + private UTF16() { + } + + // /CLOVER:ON + // public method ------------------------------------------------------ + + /** + * Extract a single UTF-32 value from a string. Used when iterating forwards or + * backwards (with UTF16.getCharCount(), as well as random access. + * If a validity check is required, use + * + * UCharacter.isLegal() on the return value. If the char retrieved is + * part of a surrogate pair, its supplementary character will be returned. If a + * complete supplementary character is not found the incomplete character will + * be returned + * + * @param source array of UTF-16 chars + * @param offset16 UTF-16 offset to the start of the character. + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. + * The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException thrown if offset16 is out of bounds. + * @stable ICU 2.1 + */ + public static int charAt(String source, int offset16) { + char single = source.charAt(offset16); + if (single < LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(String source, int offset16, char single) { + if (single > TRAIL_SURROGATE_MAX_VALUE) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + + if (single <= LEAD_SURROGATE_MAX_VALUE) { + ++offset16; + if (source.length() != offset16) { + char trail = source.charAt(offset16); + if (trail >= TRAIL_SURROGATE_MIN_VALUE && trail <= TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= LEAD_SURROGATE_MIN_VALUE && lead <= LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); + } + } + } + return single; // return unmatched surrogate + } + + /** + * Extract a single UTF-32 value from a string. Used when iterating forwards or + * backwards (with UTF16.getCharCount(), as well as random access. + * If a validity check is required, use + * UCharacter.isLegal() + * on the return value. If the char retrieved is part of a surrogate + * pair, its supplementary character will be returned. If a complete + * supplementary character is not found the incomplete character will be + * returned + * + * @param source array of UTF-16 chars + * @param offset16 UTF-16 offset to the start of the character. + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. + * The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException thrown if offset16 is out of bounds. + * @stable ICU 2.1 + */ + public static int charAt(CharSequence source, int offset16) { + char single = source.charAt(offset16); + if (single < UTF16.LEAD_SURROGATE_MIN_VALUE) { + return single; + } + return _charAt(source, offset16, single); + } + + private static int _charAt(CharSequence source, int offset16, char single) { + if (single > UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + + if (single <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + ++offset16; + if (source.length() != offset16) { + char trail = source.charAt(offset16); + if (trail >= UTF16.TRAIL_SURROGATE_MIN_VALUE && trail <= UTF16.TRAIL_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } + } else { + --offset16; + if (offset16 >= 0) { + // single is a trail surrogate so + char lead = source.charAt(offset16); + if (lead >= UTF16.LEAD_SURROGATE_MIN_VALUE && lead <= UTF16.LEAD_SURROGATE_MAX_VALUE) { + return UCharacterProperty.getRawSupplementary(lead, single); + } + } + } + return single; // return unmatched surrogate + } + + /** + * Extract a single UTF-32 value from a substring. Used when iterating forwards + * or backwards (with UTF16.getCharCount(), as well as random + * access. If a validity check is required, use + * UCharacter.isLegal() + * on the return value. If the char retrieved is part of a surrogate + * pair, its supplementary character will be returned. If a complete + * supplementary character is not found the incomplete character will be + * returned + * + * @param source Array of UTF-16 chars + * @param start Offset to substring in the source array for analyzing + * @param limit Offset to substring in the source array for analyzing + * @param offset16 UTF-16 offset relative to start + * @return UTF-32 value for the UTF-32 value that contains the char at offset16. + * The boundaries of that codepoint are the same as in + * bounds32(). + * @exception IndexOutOfBoundsException Thrown if offset16 is not within the + * range of start and limit. + * @stable ICU 2.1 + */ + public static int charAt(char source[], int start, int limit, int offset16) { + offset16 += start; + if (offset16 < start || offset16 >= limit) { + throw new ArrayIndexOutOfBoundsException(offset16); + } + + char single = source[offset16]; + if (!isSurrogate(single)) { + return single; + } + + // Convert the UTF-16 surrogate pair if necessary. + // For simplicity in usage, and because the frequency of pairs is + // low, look both directions. + if (single <= LEAD_SURROGATE_MAX_VALUE) { + offset16++; + if (offset16 >= limit) { + return single; + } + char trail = source[offset16]; + if (isTrailSurrogate(trail)) { + return UCharacterProperty.getRawSupplementary(single, trail); + } + } else { // isTrailSurrogate(single), so + if (offset16 == start) { + return single; + } + offset16--; + char lead = source[offset16]; + if (isLeadSurrogate(lead)) + return UCharacterProperty.getRawSupplementary(lead, single); + } + return single; // return unmatched surrogate + } + + /** + * Determines how many chars this char32 requires. If a validity check is + * required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input codepoint. + * @return 2 if is in supplementary space, otherwise 1. + * @stable ICU 2.1 + */ + public static int getCharCount(int char32) { + if (char32 < SUPPLEMENTARY_MIN_VALUE) { + return 1; + } + return 2; + } + + /** + * Determines whether the code value is a surrogate. + * + * @param char16 the input character. + * @return true if the input character is a surrogate. + * @stable ICU 2.1 + */ + public static boolean isSurrogate(char char16) { + return (char16 & SURROGATE_BITMASK) == SURROGATE_BITS; + } + + /** + * Determines whether the character is a trail surrogate. + * + * @param char16 the input character. + * @return true if the input character is a trail surrogate. + * @stable ICU 2.1 + */ + public static boolean isTrailSurrogate(char char16) { + return (char16 & TRAIL_SURROGATE_BITMASK) == TRAIL_SURROGATE_BITS; + } + + /** + * Determines whether the character is a lead surrogate. + * + * @param char16 the input character. + * @return true if the input character is a lead surrogate + * @stable ICU 2.1 + */ + public static boolean isLeadSurrogate(char char16) { + return (char16 & LEAD_SURROGATE_BITMASK) == LEAD_SURROGATE_BITS; + } + + /** + * Returns the lead surrogate. If a validity check is required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input character. + * @return lead surrogate if the getCharCount(ch) is 2;
+ * and 0 otherwise (note: 0 is not a valid lead surrogate). + * @stable ICU 2.1 + */ + public static char getLeadSurrogate(int char32) { + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + return (char) (LEAD_SURROGATE_OFFSET_ + (char32 >> LEAD_SURROGATE_SHIFT_)); + } + + return 0; + } + + /** + * Returns the trail surrogate. If a validity check is required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input character. + * @return the trail surrogate if the getCharCount(ch) is 2;
+ * otherwise the character itself + * @stable ICU 2.1 + */ + public static char getTrailSurrogate(int char32) { + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + return (char) (TRAIL_SURROGATE_MIN_VALUE + (char32 & TRAIL_SURROGATE_MASK_)); + } + + return (char) char32; + } + + /** + * Convenience method corresponding to String.valueOf(char). Returns a one or + * two char string containing the UTF-32 value in UTF16 format. If a validity + * check is required, use + * isLegal() on + * char32 before calling. + * + * @param char32 the input character. + * @return string value of char32 in UTF16 format + * @exception IllegalArgumentException thrown if char32 is a invalid codepoint. + * @stable ICU 2.1 + */ + public static String valueOf(int char32) { + if (char32 < CODEPOINT_MIN_VALUE || char32 > CODEPOINT_MAX_VALUE) { + throw new IllegalArgumentException("Illegal codepoint"); + } + return toString(char32); + } + + /** + * Append a single UTF-32 value to the end of a StringBuffer. If a validity + * check is required, use + * isLegal() on + * char32 before calling. + * + * @param target the buffer to append to + * @param char32 value to append. + * @return the updated StringBuffer + * @exception IllegalArgumentException thrown when char32 does not lie within + * the range of the Unicode codepoints + * @stable ICU 2.1 + */ + public static StringBuffer append(StringBuffer target, int char32) { + // Check for irregular values + if (char32 < CODEPOINT_MIN_VALUE || char32 > CODEPOINT_MAX_VALUE) { + throw new IllegalArgumentException("Illegal codepoint: " + Integer.toHexString(char32)); + } + + // Write the UTF-16 values + if (char32 >= SUPPLEMENTARY_MIN_VALUE) { + target.append(getLeadSurrogate(char32)); + target.append(getTrailSurrogate(char32)); + } else { + target.append((char) char32); + } + return target; + } + + /** + * Shifts offset16 by the argument number of codepoints within a subarray. + * + * @param source char array + * @param start position of the subarray to be performed on + * @param limit position of the subarray to be performed on + * @param offset16 UTF16 position to shift relative to start + * @param shift32 number of codepoints to shift + * @return new shifted offset16 relative to start + * @exception IndexOutOfBoundsException if the new offset16 is out of bounds + * with respect to the subarray or the + * subarray bounds are out of range. + * @stable ICU 2.1 + */ + public static int moveCodePointOffset(char source[], int start, int limit, int offset16, int shift32) { + int size = source.length; + int count; + char ch; + int result = offset16 + start; + if (start < 0 || limit < start) { + throw new StringIndexOutOfBoundsException(start); + } + if (limit > size) { + throw new StringIndexOutOfBoundsException(limit); + } + if (offset16 < 0 || result > limit) { + throw new StringIndexOutOfBoundsException(offset16); + } + if (shift32 > 0) { + if (shift32 + result > size) { + throw new StringIndexOutOfBoundsException(result); + } + count = shift32; + while (result < limit && count > 0) { + ch = source[result]; + if (isLeadSurrogate(ch) && (result + 1 < limit) && isTrailSurrogate(source[result + 1])) { + result++; + } + count--; + result++; + } + } else { + if (result + shift32 < start) { + throw new StringIndexOutOfBoundsException(result); + } + for (count = -shift32; count > 0; count--) { + result--; + if (result < start) { + break; + } + ch = source[result]; + if (isTrailSurrogate(ch) && result > start && isLeadSurrogate(source[result - 1])) { + result--; + } + } + } + if (count != 0) { + throw new StringIndexOutOfBoundsException(shift32); + } + result -= start; + return result; + } + + // private data members ------------------------------------------------- + + /** + * Shift value for lead surrogate to form a supplementary character. + */ + private static final int LEAD_SURROGATE_SHIFT_ = 10; + + /** + * Mask to retrieve the significant value from a trail surrogate. + */ + private static final int TRAIL_SURROGATE_MASK_ = 0x3FF; + + /** + * Value that all lead surrogate starts with + */ + private static final int LEAD_SURROGATE_OFFSET_ = LEAD_SURROGATE_MIN_VALUE + - (SUPPLEMENTARY_MIN_VALUE >> LEAD_SURROGATE_SHIFT_); + + // private methods ------------------------------------------------------ + + /** + *

+ * Converts argument code point and returns a String object representing the + * code point's value in UTF16 format. + *

+ * This method does not check for the validity of the codepoint, the results are + * not guaranteed if a invalid codepoint is passed as argument. + *

+ * The result is a string whose length is 1 for non-supplementary code points, 2 + * otherwise. + * + * @param ch code point + * @return string representation of the code point + */ + private static String toString(int ch) { + if (ch < SUPPLEMENTARY_MIN_VALUE) { + return String.valueOf((char) ch); + } + + StringBuilder result = new StringBuilder(); + result.append(getLeadSurrogate(ch)); + result.append(getTrailSurrogate(ch)); + return result.toString(); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/text/UnicodeSet.java b/src/main/java/jdk_internal/bidi/icu/text/UnicodeSet.java new file mode 100755 index 00000000..5797c6be --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/text/UnicodeSet.java @@ -0,0 +1,1515 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 1996-2015, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.text; + +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.TreeSet; + +import jdk_internal.bidi.icu.impl.BMPSet; +import jdk_internal.bidi.icu.impl.UCharacterProperty; +import jdk_internal.bidi.icu.impl.UnicodeSetStringSpan; +import jdk_internal.bidi.icu.impl.Utility; +import jdk_internal.bidi.icu.lang.UCharacter; +import jdk_internal.bidi.icu.util.OutputInt; +import jdk_internal.bidi.icu.util.VersionInfo; + +/** + * A mutable set of Unicode characters and multicharacter strings. Objects of + * this class represent character classes used in regular expressions. + * A character specifies a subset of Unicode code points. Legal code points are + * U+0000 to U+10FFFF, inclusive. + * + * Note: method freeze() will not only make the set immutable, but also makes + * important methods much higher performance: contains(c), containsNone(...), + * span(...), spanBack(...) etc. After the object is frozen, any subsequent call + * that wants to change the object will throw UnsupportedOperationException. + * + *

+ * The UnicodeSet class is not designed to be subclassed. + * + *

+ * UnicodeSet supports two APIs. The first is the operand + * API that allows the caller to modify the value of a UnicodeSet + * object. It conforms to Java 2's java.util.Set interface, + * although UnicodeSet does not actually implement that interface. + * All methods of Set are supported, with the modification that + * they take a character range or single character instead of an + * Object, and they take a UnicodeSet instead of a + * Collection. The operand API may be thought of in terms of + * boolean logic: a boolean OR is implemented by add, a boolean AND + * is implemented by retain, a boolean XOR is implemented by + * complement taking an argument, and a boolean NOT is implemented + * by complement with no argument. In terms of traditional set + * theory function names, add is a union, retain is an + * intersection, remove is an asymmetric difference, and + * complement with no argument is a set complement with respect to + * the superset range MIN_VALUE-MAX_VALUE + * + *

+ * The second API is the applyPattern()/toPattern() + * API from the java.text.Format-derived classes. Unlike the + * methods that add characters, add categories, and control the logic of the + * set, the method applyPattern() sets all attributes of a + * UnicodeSet at once, based on a string pattern. + * + *

+ * Pattern syntax + *

+ * + * Patterns are accepted by the constructors and the applyPattern() + * methods and returned by the toPattern() method. These patterns + * follow a syntax similar to that employed by version 8 regular expression + * character classes. Here are some simple examples: + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
[]No characters
[a]The character 'a'
[ae]The characters 'a' and 'e'
[a-e]The characters 'a' through 'e' inclusive, in Unicode code + * point order
[\\u4E01]The character U+4E01
[a{ab}{ac}]The character 'a' and the multicharacter strings "ab" and + * "ac"
[\p{Lu}]All characters in the general category Uppercase Letter
+ *
+ * + * Any character may be preceded by a backslash in order to remove any special + * meaning. White space characters, as defined by the Unicode + * Pattern_White_Space property, are ignored, unless they are escaped. + * + *

+ * Property patterns specify a set of characters having a certain property as + * defined by the Unicode standard. Both the POSIX-like "[:Lu:]" and the + * Perl-like syntax "\p{Lu}" are recognized. For a complete list of supported + * property patterns, see the User's Guide for UnicodeSet at + * + * http://www.icu-project.org/userguide/unicodeSet.html. Actual + * determination of property data is defined by the underlying Unicode database + * as implemented by UCharacter. + * + *

+ * Patterns specify individual characters, ranges of characters, and Unicode + * property sets. When elements are concatenated, they specify their union. To + * complement a set, place a '^' immediately after the opening '['. Property + * patterns are inverted by modifying their delimiters; "[:^foo]" and "\P{foo}". + * In any other location, '^' has no special meaning. + * + *

+ * Ranges are indicated by placing two a '-' between two characters, as in + * "a-z". This specifies the range of all characters from the left to the right, + * in Unicode order. If the left character is greater than or equal to the right + * character it is a syntax error. If a '-' occurs as the first character after + * the opening '[' or '[^', or if it occurs as the last character before the + * closing ']', then it is taken as a literal. Thus "[a\\-b]", "[-ab]", and + * "[ab-]" all indicate the same set of three characters, 'a', 'b', and '-'. + * + *

+ * Sets may be intersected using the {@literal '&'} operator or the asymmetric + * set difference may be taken using the '-' operator, for example, + * "{@code [[:L:]&[\\u0000-\\u0FFF]]}" indicates the set of all Unicode letters + * with values less than 4096. Operators ({@literal '&'} and '|') have equal + * precedence and bind left-to-right. Thus "[[:L:]-[a-z]-[\\u0100-\\u01FF]]" is + * equivalent to "[[[:L:]-[a-z]]-[\\u0100-\\u01FF]]". This only really matters + * for difference; intersection is commutative. + * + * + * + * + * + * + * + * + * + * + *
[a] + * The set containing 'a' + *
[a-z] + * The set containing 'a' through 'z' and all letters in between, in Unicode + * order + *
[^a-z] + * The set containing all characters but 'a' through 'z', that is, U+0000 + * through 'a'-1 and 'z'+1 through U+10FFFF + *
[[pat1][pat2]] + * The union of sets specified by pat1 and pat2 + *
[[pat1]&[pat2]] + * The intersection of sets specified by pat1 and pat2 + *
[[pat1]-[pat2]] + * The asymmetric difference of sets specified by pat1 and + * pat2 + *
[:Lu:] or \p{Lu} + * The set of characters having the specified Unicode property; in this + * case, Unicode uppercase letters + *
[:^Lu:] or \P{Lu} + * The set of characters not having the given Unicode property + *
+ * + *

+ * Warning: you cannot add an empty string ("") to a UnicodeSet. + *

+ * + *

+ * Formal syntax + *

+ * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
pattern :=  ('[' '^'? item* ']') | + * property
item :=  char | (char '-' char) | pattern-expr
+ *
pattern-expr :=  pattern | pattern-expr pattern | + * pattern-expr op pattern
+ *
op :=  '&' | '-'
+ *
special :=  '[' | ']' | '-'
+ *
char :=  any character that is not special
+ * | ('\\'
any character)
+ * | ('\u' hex hex hex hex)
+ *
hex :=  any character for which + * Character.digit(c, 16) returns a non-negative + * result
property :=  a Unicode property set pattern
+ *
+ * + * + * + * + *
Legend: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
a := b a may be replaced by b
a?zero or one instance of a
+ *
a*one or more instances of a
+ *
a | beither a or b
+ *
'a'the literal string between the quotes
+ *
+ *
+ *

+ * To iterate over contents of UnicodeSet, the following are available: + *

    + *
  • {@link #ranges()} to iterate through the ranges
  • + *
  • {@link #strings()} to iterate through the strings
  • + *
  • {@link #iterator()} to iterate through the entire contents in a single + * loop. That method is, however, not particularly efficient, since it "boxes" + * each code point into a String. + *
+ * All of the above can be used in for loops. The + * {@link com.ibm.icu.text.UnicodeSetIterator UnicodeSetIterator} can also be + * used, but not in for loops. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @author Alan Liu + * @stable ICU 2.0 + */ +public class UnicodeSet { + + private static final int LOW = 0x000000; // LOW <= all valid values. ZERO for codepoints + private static final int HIGH = 0x110000; // HIGH > all valid values. 10000 for code units. + // 110000 for codepoints + + /** + * Minimum value that can be stored in a UnicodeSet. + * + * @stable ICU 2.0 + */ + public static final int MIN_VALUE = LOW; + + /** + * Maximum value that can be stored in a UnicodeSet. + * + * @stable ICU 2.0 + */ + public static final int MAX_VALUE = HIGH - 1; + + private int len; // length used; list may be longer to minimize reallocs + private int[] list; // MUST be terminated with HIGH + private int[] rangeList; // internal buffer + private int[] buffer; // internal buffer + + // NOTE: normally the field should be of type SortedSet; but that is missing a + // public clone!! + // is not private so that UnicodeSetIterator can get access + TreeSet strings = new TreeSet(); + + /** + * The pattern representation of this set. This may not be the most economical + * pattern. It is the pattern supplied to applyPattern(), with variables + * substituted and whitespace removed. For sets constructed without + * applyPattern(), or modified using the non-pattern API, this string will be + * null, indicating that toPattern() must generate a pattern representation from + * the inversion list. + */ + + private static final int START_EXTRA = 16; // initial storage. Must be >= 0 + private static final int GROW_EXTRA = START_EXTRA; // extra amount for growth. Must be >= 0 + + private static UnicodeSet INCLUSION = null; + + private volatile BMPSet bmpSet; // The set is frozen if bmpSet or stringSpan is not null. + private volatile UnicodeSetStringSpan stringSpan; + + // ---------------------------------------------------------------- + // Public API + // ---------------------------------------------------------------- + + /** + * Constructs an empty set. + * + * @stable ICU 2.0 + */ + private UnicodeSet() { + list = new int[1 + START_EXTRA]; + list[len++] = HIGH; + } + + /** + * Constructs a copy of an existing set. + * + * @stable ICU 2.0 + */ + private UnicodeSet(UnicodeSet other) { + set(other); + } + + /** + * Constructs a set containing the given range. If end > + * start then an empty set is created. + * + * @param start first character, inclusive, of range + * @param end last character, inclusive, of range + * @stable ICU 2.0 + */ + public UnicodeSet(int start, int end) { + this(); + complement(start, end); + } + + /** + * Constructs a set from the given pattern. See the class description for the + * syntax of the pattern language. Whitespace is ignored. + * + * @param pattern a string specifying what characters are in the set + * @exception java.lang.IllegalArgumentException if the pattern contains a + * syntax error. + * @stable ICU 2.0 + */ + public UnicodeSet(String pattern) { + this(); + applyPattern(pattern, null); + } + + /** + * Make this object represent the same set as other. + * + * @param other a UnicodeSet whose value will be copied to this + * object + * @stable ICU 2.0 + */ + public UnicodeSet set(UnicodeSet other) { + checkFrozen(); + list = other.list.clone(); + len = other.len; + strings = new TreeSet(other.strings); + return this; + } + + /** + * Returns the number of elements in this set (its cardinality) Note than the + * elements of a set may include both individual codepoints and strings. + * + * @return the number of elements in this set (its cardinality). + * @stable ICU 2.0 + */ + public int size() { + int n = 0; + int count = getRangeCount(); + for (int i = 0; i < count; ++i) { + n += getRangeEnd(i) - getRangeStart(i) + 1; + } + return n + strings.size(); + } + + // for internal use, after checkFrozen has been called + private UnicodeSet add_unchecked(int start, int end) { + if (start < MIN_VALUE || start > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); + } + if (end < MIN_VALUE || end > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(end, 6)); + } + if (start < end) { + add(range(start, end), 2, 0); + } else if (start == end) { + add(start); + } + return this; + } + + /** + * Adds the specified character to this set if it is not already present. If + * this set already contains the specified character, the call leaves this set + * unchanged. + * + * @stable ICU 2.0 + */ + public final UnicodeSet add(int c) { + checkFrozen(); + return add_unchecked(c); + } + + // for internal use only, after checkFrozen has been called + private final UnicodeSet add_unchecked(int c) { + if (c < MIN_VALUE || c > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); + } + + // find smallest i such that c < list[i] + // if odd, then it is IN the set + // if even, then it is OUT of the set + int i = findCodePoint(c); + + // already in set? + if ((i & 1) != 0) + return this; + + // HIGH is 0x110000 + // assert(list[len-1] == HIGH); + + // empty = [HIGH] + // [start_0, limit_0, start_1, limit_1, HIGH] + + // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // i == 0 means c is before the first range + + if (c == list[i] - 1) { + // c is before start of next range + list[i] = c; + // if we touched the HIGH mark, then add a new one + if (c == MAX_VALUE) { + ensureCapacity(len + 1); + list[len++] = HIGH; + } + if (i > 0 && c == list[i - 1]) { + // collapse adjacent ranges + + // [..., start_k-1, c, c, limit_k, ..., HIGH] + // ^ + // list[i] + System.arraycopy(list, i + 1, list, i - 1, len - i - 1); + len -= 2; + } + } + + else if (i > 0 && c == list[i - 1]) { + // c is after end of prior range + list[i - 1]++; + // no need to chcek for collapse here + } + + else { + // At this point we know the new char is not adjacent to + // any existing ranges, and it is not 10FFFF. + + // [..., start_k-1, limit_k-1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // [..., start_k-1, limit_k-1, c, c+1, start_k, limit_k, ..., HIGH] + // ^ + // list[i] + + // Don't use ensureCapacity() to save on copying. + // NOTE: This has no measurable impact on performance, + // but it might help in some usage patterns. + if (len + 2 > list.length) { + int[] temp = new int[len + 2 + GROW_EXTRA]; + if (i != 0) + System.arraycopy(list, 0, temp, 0, i); + System.arraycopy(list, i, temp, i + 2, len - i); + list = temp; + } else { + System.arraycopy(list, i, list, i + 2, len - i); + } + + list[i] = c; + list[i + 1] = c + 1; + len += 2; + } + + return this; + } + + /** + * Adds the specified multicharacter to this set if it is not already present. + * If this set already contains the multicharacter, the call leaves this set + * unchanged. Thus {@code "ch" => {"ch"}}
+ * Warning: you cannot add an empty string ("") to a UnicodeSet. + * + * @param s the source string + * @return this object, for chaining + * @stable ICU 2.0 + */ + public final UnicodeSet add(CharSequence s) { + checkFrozen(); + int cp = getSingleCP(s); + if (cp < 0) { + strings.add(s.toString()); + } else { + add_unchecked(cp, cp); + } + return this; + } + + /** + * Utility for getting code point from single code point CharSequence. See the + * public UTF16.getSingleCodePoint() + * + * @return a code point IF the string consists of a single one. otherwise + * returns -1. + * @param s to test + */ + private static int getSingleCP(CharSequence s) { + if (s.length() < 1) { + throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet"); + } + if (s.length() > 2) + return -1; + if (s.length() == 1) + return s.charAt(0); + + // at this point, len = 2 + int cp = UTF16.charAt(s, 0); + if (cp > 0xFFFF) { // is surrogate pair + return cp; + } + return -1; + } + + /** + * Complements the specified range in this set. Any character in the range will + * be removed if it is in this set, or will be added if it is not in this set. + * If {@code end > start} then an empty range is complemented, leaving the set + * unchanged. + * + * @param start first character, inclusive, of range to be removed from this + * set. + * @param end last character, inclusive, of range to be removed from this set. + * @stable ICU 2.0 + */ + public UnicodeSet complement(int start, int end) { + checkFrozen(); + if (start < MIN_VALUE || start > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(start, 6)); + } + if (end < MIN_VALUE || end > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(end, 6)); + } + if (start <= end) { + xor(range(start, end), 2, 0); + } + return this; + } + + /** + * Returns true if this set contains the given character. + * + * @param c character to be checked for containment + * @return true if the test condition is met + * @stable ICU 2.0 + */ + public boolean contains(int c) { + if (c < MIN_VALUE || c > MAX_VALUE) { + throw new IllegalArgumentException("Invalid code point U+" + Utility.hex(c, 6)); + } + if (bmpSet != null) { + return bmpSet.contains(c); + } + if (stringSpan != null) { + return stringSpan.contains(c); + } + + /* + * // Set i to the index of the start item greater than ch // We know we will + * terminate without length test! int i = -1; while (true) { if (c < list[++i]) + * break; } + */ + + int i = findCodePoint(c); + + return ((i & 1) != 0); // return true if odd + } + + /** + * Returns the smallest value i such that c < list[i]. Caller must ensure that c + * is a legal value or this method will enter an infinite loop. This method + * performs a binary search. + * + * @param c a character in the range MIN_VALUE..MAX_VALUE inclusive + * @return the smallest integer i in the range 0..len-1, inclusive, such that c + * < list[i] + */ + private final int findCodePoint(int c) { + /* + * Examples: findCodePoint(c) set list[] c=0 1 3 4 7 8 === ============== + * =========== [] [110000] 0 0 0 0 0 0 [\u0000-\u0003] [0, 4, 110000] 1 1 1 2 2 + * 2 [\u0004-\u0007] [4, 8, 110000] 0 0 0 1 1 2 [:all:] [0, 110000] 1 1 1 1 1 1 + */ + + // Return the smallest i such that c < list[i]. Assume + // list[len - 1] == HIGH and that c is legal (0..HIGH-1). + if (c < list[0]) + return 0; + // High runner test. c is often after the last range, so an + // initial check for this condition pays off. + if (len >= 2 && c >= list[len - 2]) + return len - 1; + int lo = 0; + int hi = len - 1; + // invariant: c >= list[lo] + // invariant: c < list[hi] + for (;;) { + int i = (lo + hi) >>> 1; + if (i == lo) + return hi; + if (c < list[i]) { + hi = i; + } else { + lo = i; + } + } + } + + /** + * Retains only the elements in this set that are contained in the specified + * set. In other words, removes from this set all of its elements that are not + * contained in the specified set. This operation effectively modifies this set + * so that its value is the intersection of the two sets. + * + * @param c set that defines which elements this set will retain. + * @stable ICU 2.0 + */ + public UnicodeSet retainAll(UnicodeSet c) { + checkFrozen(); + retain(c.list, c.len, 0); + strings.retainAll(c.strings); + return this; + } + + /** + * Removes all of the elements from this set. This set will be empty after this + * call returns. + * + * @stable ICU 2.0 + */ + public UnicodeSet clear() { + checkFrozen(); + list[0] = HIGH; + len = 1; + strings.clear(); + return this; + } + + /** + * Iteration method that returns the number of ranges contained in this set. + * + * @see #getRangeStart + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeCount() { + return len / 2; + } + + /** + * Iteration method that returns the first character in the specified range of + * this set. + * + * @exception ArrayIndexOutOfBoundsException if index is outside the range + * 0..getRangeCount()-1 + * @see #getRangeCount + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeStart(int index) { + return list[index * 2]; + } + + /** + * Iteration method that returns the last character in the specified range of + * this set. + * + * @exception ArrayIndexOutOfBoundsException if index is outside the range + * 0..getRangeCount()-1 + * @see #getRangeStart + * @see #getRangeEnd + * @stable ICU 2.0 + */ + public int getRangeEnd(int index) { + return (list[index * 2 + 1] - 1); + } + + // ---------------------------------------------------------------- + // Implementation: Pattern parsing + // ---------------------------------------------------------------- + + /** + * Parses the given pattern, starting at the given position. The character at + * pattern.charAt(pos.getIndex()) must be '[', or the parse fails. Parsing + * continues until the corresponding closing ']'. If a syntax error is + * encountered between the opening and closing brace, the parse fails. Upon + * return from a successful parse, the ParsePosition is updated to point to the + * character following the closing ']', and an inversion list for the parsed + * pattern is returned. This method calls itself recursively to parse embedded + * subpatterns. + * + * @param pattern the string containing the pattern to be parsed. The portion of + * the string from pos.getIndex(), which must be a '[', to the + * corresponding closing ']', is parsed. + * @param pos upon entry, the position at which to being parsing. The + * character at pattern.charAt(pos.getIndex()) must be a '['. + * Upon return from a successful parse, pos.getIndex() is either + * the character after the closing ']' of the parsed pattern, or + * pattern.length() if the closing ']' is the last character of + * the pattern string. + * @return an inversion list for the parsed substring of pattern + * @exception java.lang.IllegalArgumentException if the parse fails. + */ + private UnicodeSet applyPattern(String pattern, ParsePosition pos) { + if ("[:age=3.2:]".equals(pattern)) { + checkFrozen(); + VersionInfo version = VersionInfo.getInstance("3.2"); + applyFilter(new VersionFilter(version), UCharacterProperty.SRC_PROPSVEC); + } else { + throw new IllegalStateException("UnicodeSet.applyPattern(unexpected pattern " + pattern + ")"); + } + + return this; + } + + // ---------------------------------------------------------------- + // Implementation: Utility methods + // ---------------------------------------------------------------- + + private void ensureCapacity(int newLen) { + if (newLen <= list.length) + return; + int[] temp = new int[newLen + GROW_EXTRA]; + System.arraycopy(list, 0, temp, 0, len); + list = temp; + } + + private void ensureBufferCapacity(int newLen) { + if (buffer != null && newLen <= buffer.length) + return; + buffer = new int[newLen + GROW_EXTRA]; + } + + /** + * Assumes start <= end. + */ + private int[] range(int start, int end) { + if (rangeList == null) { + rangeList = new int[] { start, end + 1, HIGH }; + } else { + rangeList[0] = start; + rangeList[1] = end + 1; + } + return rangeList; + } + + // ---------------------------------------------------------------- + // Implementation: Fundamental operations + // ---------------------------------------------------------------- + + // polarity = 0, 3 is normal: x xor y + // polarity = 1, 2: x xor ~y == x === y + + private UnicodeSet xor(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b; + if (polarity == 1 || polarity == 2) { + b = LOW; + if (other[j] == LOW) { // skip base if already LOW + ++j; + b = other[j]; + } + } else { + b = other[j++]; + } + // simplest of all the routines + // sort the values, discarding identicals! + while (true) { + if (a < b) { + buffer[k++] = a; + a = list[i++]; + } else if (b < a) { + buffer[k++] = b; + b = other[j++]; + } else if (a != HIGH) { // at this point, a == b + // discard both values! + a = list[i++]; + b = other[j++]; + } else { // DONE! + buffer[k++] = HIGH; + len = k; + break; + } + } + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + // polarity = 0 is normal: x union y + // polarity = 2: x union ~y + // polarity = 1: ~x union y + // polarity = 3: ~x union ~y + + private UnicodeSet add(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b = other[j++]; + // change from xor is that we have to check overlapping pairs + // polarity bit 1 means a is second, bit 2 means b is. + main: while (true) { + switch (polarity) { + case 0: // both first; take lower if unequal + if (a < b) { // take a + // Back up over overlapping ranges in buffer[] + if (k > 0 && a <= buffer[k - 1]) { + // Pick latter end value in buffer[] vs. list[] + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; // Common if/else code factored out + polarity ^= 1; + } else if (b < a) { // take b + if (k > 0 && b <= buffer[k - 1]) { + b = max(other[j], buffer[--k]); + } else { + buffer[k++] = b; + b = other[j]; + } + j++; + polarity ^= 2; + } else { // a == b, take a, drop b + if (a == HIGH) + break main; + // This is symmetrical; it doesn't matter if + // we backtrack with a or b. - liu + if (k > 0 && a <= buffer[k - 1]) { + a = max(list[i], buffer[--k]); + } else { + // No overlap + buffer[k++] = a; + a = list[i]; + } + i++; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 3: // both second; take higher if unequal, and drop other + if (b <= a) { // take a + if (a == HIGH) + break main; + buffer[k++] = a; + } else { // take b + if (b == HIGH) + break main; + buffer[k++] = b; + } + a = list[i++]; + polarity ^= 1; // factored common code + b = other[j++]; + polarity ^= 2; + break; + case 1: // a second, b first; if b < a, overlap + if (a < b) { // no overlap, take a + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // OVERLAP, drop b + b = other[j++]; + polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, take b + buffer[k++] = b; + b = other[j++]; + polarity ^= 2; + } else if (a < b) { // OVERLAP, drop a + a = list[i++]; + polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + } + } + buffer[k++] = HIGH; // terminate + len = k; + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + // polarity = 0 is normal: x intersect y + // polarity = 2: x intersect ~y == set-minus + // polarity = 1: ~x intersect y + // polarity = 3: ~x intersect ~y + + private UnicodeSet retain(int[] other, int otherLen, int polarity) { + ensureBufferCapacity(len + otherLen); + int i = 0, j = 0, k = 0; + int a = list[i++]; + int b = other[j++]; + // change from xor is that we have to check overlapping pairs + // polarity bit 1 means a is second, bit 2 means b is. + main: while (true) { + switch (polarity) { + case 0: // both first; drop the smaller + if (a < b) { // drop a + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // drop b + b = other[j++]; + polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) + break main; + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 3: // both second; take lower if unequal + if (a < b) { // take a + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // take b + buffer[k++] = b; + b = other[j++]; + polarity ^= 2; + } else { // a == b, take one, drop other + if (a == HIGH) + break main; + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 1: // a second, b first; + if (a < b) { // NO OVERLAP, drop a + a = list[i++]; + polarity ^= 1; + } else if (b < a) { // OVERLAP, take b + buffer[k++] = b; + b = other[j++]; + polarity ^= 2; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + case 2: // a first, b second; if a < b, overlap + if (b < a) { // no overlap, drop b + b = other[j++]; + polarity ^= 2; + } else if (a < b) { // OVERLAP, take a + buffer[k++] = a; + a = list[i++]; + polarity ^= 1; + } else { // a == b, drop both! + if (a == HIGH) + break main; + a = list[i++]; + polarity ^= 1; + b = other[j++]; + polarity ^= 2; + } + break; + } + } + buffer[k++] = HIGH; // terminate + len = k; + // swap list and buffer + int[] temp = list; + list = buffer; + buffer = temp; + return this; + } + + private static final int max(int a, int b) { + return (a > b) ? a : b; + } + + // ---------------------------------------------------------------- + // Generic filter-based scanning code + // ---------------------------------------------------------------- + + private static interface Filter { + boolean contains(int codePoint); + } + + private static final VersionInfo NO_VERSION = VersionInfo.getInstance(0, 0, 0, 0); + + private static class VersionFilter implements Filter { + VersionInfo version; + + VersionFilter(VersionInfo version) { + this.version = version; + } + + public boolean contains(int ch) { + VersionInfo v = UCharacter.getAge(ch); + // Reference comparison ok; VersionInfo caches and reuses + // unique objects. + return v != NO_VERSION && v.compareTo(version) <= 0; + } + } + + private static synchronized UnicodeSet getInclusions(int src) { + if (src != UCharacterProperty.SRC_PROPSVEC) { + throw new IllegalStateException("UnicodeSet.getInclusions(unknown src " + src + ")"); + } + + if (INCLUSION == null) { + UnicodeSet incl = new UnicodeSet(); + UCharacterProperty.INSTANCE.upropsvec_addPropertyStarts(incl); + INCLUSION = incl; + } + return INCLUSION; + } + + /** + * Generic filter-based scanning code for UCD property UnicodeSets. + */ + private UnicodeSet applyFilter(Filter filter, int src) { + // Logically, walk through all Unicode characters, noting the start + // and end of each range for which filter.contain(c) is + // true. Add each range to a set. + // + // To improve performance, use an inclusions set which + // encodes information about character ranges that are known + // to have identical properties. + // getInclusions(src) contains exactly the first characters of + // same-value ranges for the given properties "source". + + clear(); + + int startHasProperty = -1; + UnicodeSet inclusions = getInclusions(src); + int limitRange = inclusions.getRangeCount(); + + for (int j = 0; j < limitRange; ++j) { + // get current range + int start = inclusions.getRangeStart(j); + int end = inclusions.getRangeEnd(j); + + // for all the code points in the range, process + for (int ch = start; ch <= end; ++ch) { + // only add to the unicodeset on inflection points -- + // where the hasProperty value changes to false + if (filter.contains(ch)) { + if (startHasProperty < 0) { + startHasProperty = ch; + } + } else if (startHasProperty >= 0) { + add_unchecked(startHasProperty, ch - 1); + startHasProperty = -1; + } + } + } + if (startHasProperty >= 0) { + add_unchecked(startHasProperty, 0x10FFFF); + } + + return this; + } + + /** + * Is this frozen, according to the Freezable interface? + * + * @return value + * @stable ICU 3.8 + */ + public boolean isFrozen() { + return (bmpSet != null || stringSpan != null); + } + + /** + * Freeze this class, according to the Freezable interface. + * + * @return this + * @stable ICU 4.4 + */ + public UnicodeSet freeze() { + if (!isFrozen()) { + // Do most of what compact() does before freezing because + // compact() will not work when the set is frozen. + // Small modification: Don't shrink if the savings would be tiny (<=GROW_EXTRA). + + // Delete buffer first to defragment memory less. + buffer = null; + if (list.length > (len + GROW_EXTRA)) { + // Make the capacity equal to len or 1. + // We don't want to realloc of 0 size. + int capacity = (len == 0) ? 1 : len; + int[] oldList = list; + list = new int[capacity]; + for (int i = capacity; i-- > 0;) { + list[i] = oldList[i]; + } + } + + // Optimize contains() and span() and similar functions. + if (!strings.isEmpty()) { + stringSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), UnicodeSetStringSpan.ALL); + } + if (stringSpan == null || !stringSpan.needsStringSpanUTF16()) { + // Optimize for code point spans. + // There are no strings, or + // all strings are irrelevant for span() etc. because + // all of each string's code points are contained in this set. + // However, fully contained strings are relevant for spanAndCount(), + // so we create both objects. + bmpSet = new BMPSet(list, len); + } + } + return this; + } + + /** + * Span a string using this UnicodeSet. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param s The string to be spanned + * @param spanCondition The span condition + * @return the length of the span + * @stable ICU 4.4 + */ + public int span(CharSequence s, SpanCondition spanCondition) { + return span(s, 0, spanCondition); + } + + /** + * Span a string using this UnicodeSet. If the start index is less than 0, span + * will start from 0. If the start index is greater than the string length, span + * returns the string length. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param s The string to be spanned + * @param start The start index that the span begins + * @param spanCondition The span condition + * @return the string index which ends the span (i.e. exclusive) + * @stable ICU 4.4 + */ + public int span(CharSequence s, int start, SpanCondition spanCondition) { + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for span(). + return bmpSet.span(s, start, spanCondition, null); + } + if (stringSpan != null) { + return stringSpan.span(s, start, spanCondition); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.span(s, start, spanCondition); + } + } + + return spanCodePointsAndCount(s, start, spanCondition, null); + } + + /** + * Same as span() but also counts the smallest number of set elements on any + * path across the span. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param outCount An output-only object (must not be null) for returning the + * count. + * @return the limit (exclusive end) of the span + */ + public int spanAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + if (outCount == null) { + throw new IllegalArgumentException("outCount must not be null"); + } + int end = s.length(); + if (start < 0) { + start = 0; + } else if (start >= end) { + return end; + } + if (stringSpan != null) { + // We might also have bmpSet != null, + // but fully-contained strings are relevant for counting elements. + return stringSpan.spanAndCount(s, start, spanCondition, outCount); + } else if (bmpSet != null) { + return bmpSet.span(s, start, spanCondition, outCount); + } else if (!strings.isEmpty()) { + int which = spanCondition == SpanCondition.NOT_CONTAINED ? UnicodeSetStringSpan.FWD_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.FWD_UTF16_CONTAINED; + which |= UnicodeSetStringSpan.WITH_COUNT; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + return strSpan.spanAndCount(s, start, spanCondition, outCount); + } + + return spanCodePointsAndCount(s, start, spanCondition, outCount); + } + + private int spanCodePointsAndCount(CharSequence s, int start, SpanCondition spanCondition, OutputInt outCount) { + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int next = start; + int length = s.length(); + int count = 0; + do { + c = Character.codePointAt(s, next); + if (spanContained != contains(c)) { + break; + } + ++count; + next += Character.charCount(c); + } while (next < length); + if (outCount != null) { + outCount.value = count; + } + return next; + } + + /** + * Span a string backwards (from the fromIndex) using this UnicodeSet. If the + * fromIndex is less than 0, spanBack will return 0. If fromIndex is greater + * than the string length, spanBack will start from the string length. + *

+ * To replace, count elements, or delete spans, see + * {@link com.ibm.icu.text.UnicodeSetSpanner UnicodeSetSpanner}. + * + * @param s The string to be spanned + * @param fromIndex The index of the char (exclusive) that the string should + * be spanned backwards + * @param spanCondition The span condition + * @return The string index which starts the span (i.e. inclusive). + * @stable ICU 4.4 + */ + public int spanBack(CharSequence s, int fromIndex, SpanCondition spanCondition) { + if (fromIndex <= 0) { + return 0; + } + if (fromIndex > s.length()) { + fromIndex = s.length(); + } + if (bmpSet != null) { + // Frozen set without strings, or no string is relevant for spanBack(). + return bmpSet.spanBack(s, fromIndex, spanCondition); + } + if (stringSpan != null) { + return stringSpan.spanBack(s, fromIndex, spanCondition); + } else if (!strings.isEmpty()) { + int which = (spanCondition == SpanCondition.NOT_CONTAINED) ? UnicodeSetStringSpan.BACK_UTF16_NOT_CONTAINED + : UnicodeSetStringSpan.BACK_UTF16_CONTAINED; + UnicodeSetStringSpan strSpan = new UnicodeSetStringSpan(this, new ArrayList(strings), which); + if (strSpan.needsStringSpanUTF16()) { + return strSpan.spanBack(s, fromIndex, spanCondition); + } + } + + // Pin to 0/1 values. + boolean spanContained = (spanCondition != SpanCondition.NOT_CONTAINED); + + int c; + int prev = fromIndex; + do { + c = Character.codePointBefore(s, prev); + if (spanContained != contains(c)) { + break; + } + prev -= Character.charCount(c); + } while (prev > 0); + return prev; + } + + /** + * Clone a thawed version of this class, according to the Freezable interface. + * + * @return the clone, not frozen + * @stable ICU 4.4 + */ + public UnicodeSet cloneAsThawed() { + UnicodeSet result = new UnicodeSet(this); + assert !result.isFrozen(); + return result; + } + + // internal function + private void checkFrozen() { + if (isFrozen()) { + throw new UnsupportedOperationException("Attempt to modify frozen object"); + } + } + + /** + * Argument values for whether span() and similar functions continue while the + * current character is contained vs. not contained in the set. + *

+ * The functionality is straightforward for sets with only single code points, + * without strings (which is the common case): + *

    + *
  • CONTAINED and SIMPLE work the same. + *
  • CONTAINED and SIMPLE are inverses of NOT_CONTAINED. + *
  • span() and spanBack() partition any string the same way when alternating + * between span(NOT_CONTAINED) and span(either "contained" condition). + *
  • Using a complemented (inverted) set and the opposite span conditions + * yields the same results. + *
+ * When a set contains multi-code point strings, then these statements may not + * be true, depending on the strings in the set (for example, whether they + * overlap with each other) and the string that is processed. For a set with + * strings: + *
    + *
  • The complement of the set contains the opposite set of code points, but + * the same set of strings. Therefore, complementing both the set and the span + * conditions may yield different results. + *
  • When starting spans at different positions in a string (span(s, ...) vs. + * span(s+1, ...)) the ends of the spans may be different because a set string + * may start before the later position. + *
  • span(SIMPLE) may be shorter than span(CONTAINED) because it will not + * recursively try all possible paths. For example, with a set which contains + * the three strings "xy", "xya" and "ax", span("xyax", CONTAINED) will return 4 + * but span("xyax", SIMPLE) will return 3. span(SIMPLE) will never be longer + * than span(CONTAINED). + *
  • With either "contained" condition, span() and spanBack() may partition a + * string in different ways. For example, with a set which contains the two + * strings "ab" and "ba", and when processing the string "aba", span() will + * yield contained/not-contained boundaries of { 0, 2, 3 } while spanBack() will + * yield boundaries of { 0, 1, 3 }. + *
+ * Note: If it is important to get the same boundaries whether iterating forward + * or backward through a string, then either only span() should be used and the + * boundaries cached for backward operation, or an ICU BreakIterator could be + * used. + *

+ * Note: Unpaired surrogates are treated like surrogate code points. Similarly, + * set strings match only on code point boundaries, never in the middle of a + * surrogate pair. + * + * @stable ICU 4.4 + */ + public enum SpanCondition { + /** + * Continues a span() while there is no set element at the current position. + * Increments by one code point at a time. Stops before the first set element + * (character or string). (For code points only, this is like while + * contains(current)==false). + *

+ * When span() returns, the substring between where it started and the position + * it returned consists only of characters that are not in the set, and none of + * its strings overlap with the span. + * + * @stable ICU 4.4 + */ + NOT_CONTAINED, + + /** + * Spans the longest substring that is a concatenation of set elements + * (characters or strings). (For characters only, this is like while + * contains(current)==true). + *

+ * When span() returns, the substring between where it started and the position + * it returned consists only of set elements (characters or strings) that are in + * the set. + *

+ * If a set contains strings, then the span will be the longest substring for + * which there exists at least one non-overlapping concatenation of set elements + * (characters or strings). This is equivalent to a POSIX regular expression for + * (OR of each set element)*. (Java/ICU/Perl regex stops at the + * first match of an OR.) + * + * @stable ICU 4.4 + */ + CONTAINED, + + /** + * Continues a span() while there is a set element at the current position. + * Increments by the longest matching element at each position. (For characters + * only, this is like while contains(current)==true). + *

+ * When span() returns, the substring between where it started and the position + * it returned consists only of set elements (characters or strings) that are in + * the set. + *

+ * If a set only contains single characters, then this is the same as CONTAINED. + *

+ * If a set contains strings, then the span will be the longest substring with a + * match at each position with the longest single set element (character or + * string). + *

+ * Use this span condition together with other longest-match algorithms, such as + * ICU converters (ucnv_getUnicodeSet()). + * + * @stable ICU 4.4 + */ + SIMPLE, + } + +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/CodePointMap.java b/src/main/java/jdk_internal/bidi/icu/util/CodePointMap.java new file mode 100755 index 00000000..358b631b --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/CodePointMap.java @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// (c) 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html#License + +// created: 2018may10 Markus W. Scherer + +package jdk_internal.bidi.icu.util; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Abstract map from Unicode code points (U+0000..U+10FFFF) to integer values. + * This does not implement java.util.Map. + * + * @stable ICU 63 + */ +public abstract class CodePointMap implements Iterable { + /** + * Selectors for how getRange() should report value ranges overlapping with + * surrogates. Most users should use NORMAL. + * + * @see #getRange + * @stable ICU 63 + */ + public enum RangeOption { + /** + * getRange() enumerates all same-value ranges as stored in the map. Most users + * should use this option. + * + * @stable ICU 63 + */ + NORMAL, + /** + * getRange() enumerates all same-value ranges as stored in the map, except that + * lead surrogates (U+D800..U+DBFF) are treated as having the surrogateValue, + * which is passed to getRange() as a separate parameter. The surrogateValue is + * not transformed via filter(). See {@link Character#isHighSurrogate}. + * + *

+ * Most users should use NORMAL instead. + * + *

+ * This option is useful for maps that map surrogate code *units* to special + * values optimized for UTF-16 string processing or for special error behavior + * for unpaired surrogates, but those values are not to be associated with the + * lead surrogate code *points*. + * + * @stable ICU 63 + */ + FIXED_LEAD_SURROGATES, + /** + * getRange() enumerates all same-value ranges as stored in the map, except that + * all surrogates (U+D800..U+DFFF) are treated as having the surrogateValue, + * which is passed to getRange() as a separate parameter. The surrogateValue is + * not transformed via filter(). See {@link Character#isSurrogate}. + * + *

+ * Most users should use NORMAL instead. + * + *

+ * This option is useful for maps that map surrogate code *units* to special + * values optimized for UTF-16 string processing or for special error behavior + * for unpaired surrogates, but those values are not to be associated with the + * lead surrogate code *points*. + * + * @stable ICU 63 + */ + FIXED_ALL_SURROGATES + } + + /** + * Callback function interface: Modifies a map value. Optionally called by + * getRange(). The modified value will be returned by the getRange() function. + * + *

+ * Can be used to ignore some of the value bits, make a filter for one of + * several values, return a value index computed from the map value, etc. + * + * @see #getRange + * @see #iterator + * @stable ICU 63 + */ + public interface ValueFilter { + /** + * Modifies the map value. + * + * @param value map value + * @return modified value + * @stable ICU 63 + */ + public int apply(int value); + } + + /** + * Range iteration result data. Code points from start to end map to the same + * value. The value may have been modified by {@link ValueFilter#apply(int)}, or + * it may be the surrogateValue if a RangeOption other than "normal" was used. + * + * @see #getRange + * @see #iterator + * @stable ICU 63 + */ + public static final class Range { + private int start; + private int end; + private int value; + + /** + * Constructor. Sets start and end to -1 and value to 0. + * + * @stable ICU 63 + */ + public Range() { + start = end = -1; + value = 0; + } + + /** + * @return the start code point + * @stable ICU 63 + */ + public int getStart() { + return start; + } + + /** + * @return the (inclusive) end code point + * @stable ICU 63 + */ + public int getEnd() { + return end; + } + + /** + * @return the range value + * @stable ICU 63 + */ + public int getValue() { + return value; + } + + /** + * Sets the range. When using {@link #iterator()}, iteration will resume after + * the newly set end. + * + * @param start new start code point + * @param end new end code point + * @param value new value + * @stable ICU 63 + */ + public void set(int start, int end, int value) { + this.start = start; + this.end = end; + this.value = value; + } + } + + private final class RangeIterator implements Iterator { + private Range range = new Range(); + + @Override + public boolean hasNext() { + return -1 <= range.end && range.end < 0x10ffff; + } + + @Override + public Range next() { + if (getRange(range.end + 1, null, range)) { + return range; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public final void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Iterates over code points of a string and fetches map values. This does not + * implement java.util.Iterator. + * + *

+	 * void onString(CodePointMap map, CharSequence s, int start) {
+	 * 	CodePointMap.StringIterator iter = map.stringIterator(s, start);
+	 * 	while (iter.next()) {
+	 * 		int end = iter.getIndex(); // code point from between start and end
+	 * 		useValue(s, start, end, iter.getCodePoint(), iter.getValue());
+	 * 		start = end;
+	 * 	}
+	 * }
+	 * 
+ * + *

+ * This class is not intended for public subclassing. + * + * @stable ICU 63 + */ + public class StringIterator { + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected CharSequence s; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int sIndex; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int c; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected int value; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected StringIterator(CharSequence s, int sIndex) { + this.s = s; + this.sIndex = sIndex; + c = -1; + value = 0; + } + + /** + * Resets the iterator to a new string and/or a new string index. + * + * @param s string to iterate over + * @param sIndex string index where the iteration will start + * @stable ICU 63 + */ + public void reset(CharSequence s, int sIndex) { + this.s = s; + this.sIndex = sIndex; + c = -1; + value = 0; + } + + /** + * Reads the next code point, post-increments the string index, and gets a value + * from the map. Sets an implementation-defined error value if the code point is + * an unpaired surrogate. + * + * @return true if the string index was not yet at the end of the string; + * otherwise the iterator did not advance + * @stable ICU 63 + */ + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + c = Character.codePointAt(s, sIndex); + sIndex += Character.charCount(c); + value = get(c); + return true; + } + + /** + * Reads the previous code point, pre-decrements the string index, and gets a + * value from the map. Sets an implementation-defined error value if the code + * point is an unpaired surrogate. + * + * @return true if the string index was not yet at the start of the string; + * otherwise the iterator did not advance + * @stable ICU 63 + */ + public boolean previous() { + if (sIndex <= 0) { + return false; + } + c = Character.codePointBefore(s, sIndex); + sIndex -= Character.charCount(c); + value = get(c); + return true; + } + + /** + * @return the string index + * @stable ICU 63 + */ + public final int getIndex() { + return sIndex; + } + + /** + * @return the code point + * @stable ICU 63 + */ + public final int getCodePoint() { + return c; + } + + /** + * @return the map value, or an implementation-defined error value if the code + * point is an unpaired surrogate + * @stable ICU 63 + */ + public final int getValue() { + return value; + } + } + + /** + * Protected no-args constructor. + * + * @stable ICU 63 + */ + protected CodePointMap() { + } + + /** + * Returns the value for a code point as stored in the map, with range checking. + * Returns an implementation-defined error value if c is not in the range + * 0..U+10FFFF. + * + * @param c the code point + * @return the map value, or an implementation-defined error value if the code + * point is not in the range 0..U+10FFFF + * @stable ICU 63 + */ + public abstract int get(int c); + + /** + * Sets the range object to a range of code points beginning with the start + * parameter. The range start is the same as the start input parameter (even if + * there are preceding code points that have the same value). The range end is + * the last code point such that all those from start to there have the same + * value. Returns false if start is not 0..U+10FFFF. Can be used to efficiently + * iterate over all same-value ranges in a map. (This is normally faster than + * iterating over code points and get()ting each value, but may be much slower + * than a data structure that stores ranges directly.) + * + *

+ * If the {@link ValueFilter} parameter is not null, then the value to be + * delivered is passed through that filter, and the return value is the end of + * the range where all values are modified to the same actual value. The value + * is unchanged if that parameter is null. + * + *

+ * Example: + * + *

+	 * int start = 0;
+	 * CodePointMap.Range range = new CodePointMap.Range();
+	 * while (map.getRange(start, null, range)) {
+	 * 	int end = range.getEnd();
+	 * 	int value = range.getValue();
+	 * 	// Work with the range start..end and its value.
+	 * 	start = end + 1;
+	 * }
+	 * 
+ * + * @param start range start + * @param filter an object that may modify the map data value, or null if the + * values from the map are to be used unmodified + * @param range the range object that will be set to the code point range and + * value + * @return true if start is 0..U+10FFFF; otherwise no new range is fetched + * @stable ICU 63 + */ + public abstract boolean getRange(int start, ValueFilter filter, Range range); + + /** + * Sets the range object to a range of code points beginning with the start + * parameter. The range start is the same as the start input parameter (even if + * there are preceding code points that have the same value). The range end is + * the last code point such that all those from start to there have the same + * value. Returns false if start is not 0..U+10FFFF. + * + *

+ * Same as the simpler {@link #getRange(int, ValueFilter, Range)} but optionally + * modifies the range if it overlaps with surrogate code points. + * + * @param start range start + * @param option defines whether surrogates are treated normally, or as + * having the surrogateValue; usually + * {@link RangeOption#NORMAL} + * @param surrogateValue value for surrogates; ignored if + * option=={@link RangeOption#NORMAL} + * @param filter an object that may modify the map data value, or null + * if the values from the map are to be used unmodified + * @param range the range object that will be set to the code point + * range and value + * @return true if start is 0..U+10FFFF; otherwise no new range is fetched + * @stable ICU 63 + */ + public boolean getRange(int start, RangeOption option, int surrogateValue, ValueFilter filter, Range range) { + assert option != null; + if (!getRange(start, filter, range)) { + return false; + } + if (option == RangeOption.NORMAL) { + return true; + } + int surrEnd = option == RangeOption.FIXED_ALL_SURROGATES ? 0xdfff : 0xdbff; + int end = range.end; + if (end < 0xd7ff || start > surrEnd) { + return true; + } + // The range overlaps with surrogates, or ends just before the first one. + if (range.value == surrogateValue) { + if (end >= surrEnd) { + // Surrogates followed by a non-surrValue range, + // or surrogates are part of a larger surrValue range. + return true; + } + } else { + if (start <= 0xd7ff) { + range.end = 0xd7ff; // Non-surrValue range ends before surrValue surrogates. + return true; + } + // Start is a surrogate with a non-surrValue code *unit* value. + // Return a surrValue code *point* range. + range.value = surrogateValue; + if (end > surrEnd) { + range.end = surrEnd; // Surrogate range ends before non-surrValue rest of range. + return true; + } + } + // See if the surrValue surrogate range can be merged with + // an immediately following range. + if (getRange(surrEnd + 1, filter, range) && range.value == surrogateValue) { + range.start = start; + return true; + } + range.start = start; + range.end = surrEnd; + range.value = surrogateValue; + return true; + } + + /** + * Convenience iterator over same-map-value code point ranges. Same as looping + * over all ranges with {@link #getRange(int, ValueFilter, Range)} without + * filtering. Adjacent ranges have different map values. + * + *

+ * The iterator always returns the same Range object. + * + * @return a Range iterator + * @stable ICU 63 + */ + @Override + public Iterator iterator() { + return new RangeIterator(); + } + + /** + * Returns an iterator (not a java.util.Iterator) over code points of a string + * for fetching map values. + * + * @param s string to iterate over + * @param sIndex string index where the iteration will start + * @return the iterator + * @stable ICU 63 + */ + public StringIterator stringIterator(CharSequence s, int sIndex) { + return new StringIterator(s, sIndex); + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/CodePointTrie.java b/src/main/java/jdk_internal/bidi/icu/util/CodePointTrie.java new file mode 100755 index 00000000..e84c2d0e --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/CodePointTrie.java @@ -0,0 +1,1357 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// (c) 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html#License + +// created: 2018may04 Markus W. Scherer + +package jdk_internal.bidi.icu.util; + +import static jdk_internal.bidi.icu.impl.NormalizerImpl.UTF16Plus; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import jdk_internal.bidi.icu.impl.ICUBinary; + +/** + * Immutable Unicode code point trie. Fast, reasonably compact, map from Unicode + * code points (U+0000..U+10FFFF) to integer values. For details see + * http://site.icu-project.org/design/struct/utrie + * + *

+ * This class is not intended for public subclassing. + * + * @see MutableCodePointTrie + * @stable ICU 63 + */ +@SuppressWarnings("deprecation") +public abstract class CodePointTrie extends CodePointMap { + /** + * Selectors for the type of a CodePointTrie. Different trade-offs for size vs. + * speed. + * + *

+ * Use null for {@link #fromBinary} to accept any type; {@link #getType} will + * return the actual type. + * + * @see MutableCodePointTrie#buildImmutable(CodePointTrie.Type, + * CodePointTrie.ValueWidth) + * @see #fromBinary + * @see #getType + * @stable ICU 63 + */ + public enum Type { + /** + * Fast/simple/larger BMP data structure. The {@link Fast} subclasses have + * additional functions for lookup for BMP and supplementary code points. + * + * @see Fast + * @stable ICU 63 + */ + FAST, + /** + * Small/slower BMP data structure. + * + * @see Small + * @stable ICU 63 + */ + SMALL + } + + /** + * Selectors for the number of bits in a CodePointTrie data value. + * + *

+ * Use null for {@link #fromBinary} to accept any data value width; + * {@link #getValueWidth} will return the actual data value width. + * + * @stable ICU 63 + */ + public enum ValueWidth { + /** + * The trie stores 16 bits per data value. It returns them as unsigned values + * 0..0xffff=65535. + * + * @stable ICU 63 + */ + BITS_16, + /** + * The trie stores 32 bits per data value. + * + * @stable ICU 63 + */ + BITS_32, + /** + * The trie stores 8 bits per data value. It returns them as unsigned values + * 0..0xff=255. + * + * @stable ICU 63 + */ + BITS_8 + } + + private CodePointTrie(char[] index, Data data, int highStart, int index3NullOffset, int dataNullOffset) { + this.ascii = new int[ASCII_LIMIT]; + this.index = index; + this.data = data; + this.dataLength = data.getDataLength(); + this.highStart = highStart; + this.index3NullOffset = index3NullOffset; + this.dataNullOffset = dataNullOffset; + + for (int c = 0; c < ASCII_LIMIT; ++c) { + ascii[c] = data.getFromIndex(c); + } + + int nullValueOffset = dataNullOffset; + if (nullValueOffset >= dataLength) { + nullValueOffset = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + } + nullValue = data.getFromIndex(nullValueOffset); + } + + /** + * Creates a trie from its binary form, stored in the ByteBuffer starting at the + * current position. Advances the buffer position to just after the trie data. + * Inverse of {@link #toBinary(OutputStream)}. + * + *

+ * The data is copied from the buffer; later modification of the buffer will not + * affect the trie. + * + * @param type selects the trie type; this method throws an exception if + * the type does not match the binary data; use null to accept + * any type + * @param valueWidth selects the number of bits in a data value; this method + * throws an exception if the valueWidth does not match the + * binary data; use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @see MutableCodePointTrie#MutableCodePointTrie(int, int) + * @see MutableCodePointTrie#buildImmutable(CodePointTrie.Type, + * CodePointTrie.ValueWidth) + * @see #toBinary(OutputStream) + * @stable ICU 63 + */ + public static CodePointTrie fromBinary(Type type, ValueWidth valueWidth, ByteBuffer bytes) { + ByteOrder outerByteOrder = bytes.order(); + try { + // Enough data for a trie header? + if (bytes.remaining() < 16 /* sizeof(UCPTrieHeader) */) { + throw new InternalError("Buffer too short for a CodePointTrie header"); + } + + // struct UCPTrieHeader + /** "Tri3" in big-endian US-ASCII (0x54726933) */ + int signature = bytes.getInt(); + + // Check the signature. + switch (signature) { + case 0x54726933: + // The buffer is already set to the trie data byte order. + break; + case 0x33697254: + // Temporarily reverse the byte order. + boolean isBigEndian = outerByteOrder == ByteOrder.BIG_ENDIAN; + bytes.order(isBigEndian ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN); + signature = 0x54726933; + break; + default: + throw new InternalError("Buffer does not contain a serialized CodePointTrie"); + } + + // struct UCPTrieHeader continued + /** + * Options bit field: Bits 15..12: Data length bits 19..16. Bits 11..8: Data + * null block offset bits 19..16. Bits 7..6: UCPTrieType Bits 5..3: Reserved + * (0). Bits 2..0: UCPTrieValueWidth + */ + int options = bytes.getChar(); + + /** Total length of the index tables. */ + int indexLength = bytes.getChar(); + + /** Data length bits 15..0. */ + int dataLength = bytes.getChar(); + + /** Index-3 null block offset, 0x7fff or 0xffff if none. */ + int index3NullOffset = bytes.getChar(); + + /** Data null block offset bits 15..0, 0xfffff if none. */ + int dataNullOffset = bytes.getChar(); + + /** + * First code point of the single-value range ending with U+10ffff, rounded up + * and then shifted right by SHIFT_2. + */ + int shiftedHighStart = bytes.getChar(); + // struct UCPTrieHeader end + + int typeInt = (options >> 6) & 3; + Type actualType; + switch (typeInt) { + case 0: + actualType = Type.FAST; + break; + case 1: + actualType = Type.SMALL; + break; + default: + throw new InternalError("CodePointTrie data header has an unsupported type"); + } + + int valueWidthInt = options & OPTIONS_VALUE_BITS_MASK; + ValueWidth actualValueWidth; + switch (valueWidthInt) { + case 0: + actualValueWidth = ValueWidth.BITS_16; + break; + case 1: + actualValueWidth = ValueWidth.BITS_32; + break; + case 2: + actualValueWidth = ValueWidth.BITS_8; + break; + default: + throw new InternalError("CodePointTrie data header has an unsupported value width"); + } + + if ((options & OPTIONS_RESERVED_MASK) != 0) { + throw new InternalError("CodePointTrie data header has unsupported options"); + } + + if (type == null) { + type = actualType; + } + if (valueWidth == null) { + valueWidth = actualValueWidth; + } + if (type != actualType || valueWidth != actualValueWidth) { + throw new InternalError("CodePointTrie data header has a different type or value width than required"); + } + + // Get the length values and offsets. + dataLength |= ((options & OPTIONS_DATA_LENGTH_MASK) << 4); + dataNullOffset |= ((options & OPTIONS_DATA_NULL_OFFSET_MASK) << 8); + + int highStart = shiftedHighStart << SHIFT_2; + + // Calculate the actual length, minus the header. + int actualLength = indexLength * 2; + if (valueWidth == ValueWidth.BITS_16) { + actualLength += dataLength * 2; + } else if (valueWidth == ValueWidth.BITS_32) { + actualLength += dataLength * 4; + } else { + actualLength += dataLength; + } + if (bytes.remaining() < actualLength) { + throw new InternalError("Buffer too short for the CodePointTrie data"); + } + + char[] index = ICUBinary.getChars(bytes, indexLength, 0); + switch (valueWidth) { + case BITS_16: { + char[] data16 = ICUBinary.getChars(bytes, dataLength, 0); + return type == Type.FAST ? new Fast16(index, data16, highStart, index3NullOffset, dataNullOffset) + : new Small16(index, data16, highStart, index3NullOffset, dataNullOffset); + } + case BITS_32: { + int[] data32 = ICUBinary.getInts(bytes, dataLength, 0); + return type == Type.FAST ? new Fast32(index, data32, highStart, index3NullOffset, dataNullOffset) + : new Small32(index, data32, highStart, index3NullOffset, dataNullOffset); + } + case BITS_8: { + byte[] data8 = ICUBinary.getBytes(bytes, dataLength, 0); + return type == Type.FAST ? new Fast8(index, data8, highStart, index3NullOffset, dataNullOffset) + : new Small8(index, data8, highStart, index3NullOffset, dataNullOffset); + } + default: + throw new AssertionError("should be unreachable"); + } + } finally { + bytes.order(outerByteOrder); + } + } + + /** + * Returns the trie type. + * + * @return the trie type + * @stable ICU 63 + */ + public abstract Type getType(); + + /** + * Returns the number of bits in a trie data value. + * + * @return the number of bits in a trie data value + * @stable ICU 63 + */ + public final ValueWidth getValueWidth() { + return data.getValueWidth(); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public int get(int c) { + return data.getFromIndex(cpIndex(c)); + } + + /** + * Returns a trie value for an ASCII code point, without range checking. + * + * @param c the input code point; must be U+0000..U+007F + * @return The ASCII code point's trie value. + * @stable ICU 63 + */ + public final int asciiGet(int c) { + return ascii[c]; + } + + private static final int MAX_UNICODE = 0x10ffff; + + private static final int ASCII_LIMIT = 0x80; + + private static final int maybeFilterValue(int value, int trieNullValue, int nullValue, ValueFilter filter) { + if (value == trieNullValue) { + value = nullValue; + } else if (filter != null) { + value = filter.apply(value); + } + return value; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final boolean getRange(int start, ValueFilter filter, Range range) { + if (start < 0 || MAX_UNICODE < start) { + return false; + } + if (start >= highStart) { + int di = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + int value = data.getFromIndex(di); + if (filter != null) { + value = filter.apply(value); + } + range.set(start, MAX_UNICODE, value); + return true; + } + + int nullValue = this.nullValue; + if (filter != null) { + nullValue = filter.apply(nullValue); + } + Type type = getType(); + + int prevI3Block = -1; + int prevBlock = -1; + int c = start; + // Initialize to make compiler happy. Real value when haveValue is true. + int trieValue = 0, value = 0; + boolean haveValue = false; + do { + int i3Block; + int i3; + int i3BlockLength; + int dataBlockLength; + if (c <= 0xffff && (type == Type.FAST || c <= SMALL_MAX)) { + i3Block = 0; + i3 = c >> FAST_SHIFT; + i3BlockLength = type == Type.FAST ? BMP_INDEX_LENGTH : SMALL_INDEX_LENGTH; + dataBlockLength = FAST_DATA_BLOCK_LENGTH; + } else { + // Use the multi-stage index. + int i1 = c >> SHIFT_1; + if (type == Type.FAST) { + assert (0xffff < c && c < highStart); + i1 += BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH; + } else { + assert (c < highStart && highStart > SMALL_LIMIT); + i1 += SMALL_INDEX_LENGTH; + } + i3Block = index[index[i1] + ((c >> SHIFT_2) & INDEX_2_MASK)]; + if (i3Block == prevI3Block && (c - start) >= CP_PER_INDEX_2_ENTRY) { + // The index-3 block is the same as the previous one, and filled with value. + assert ((c & (CP_PER_INDEX_2_ENTRY - 1)) == 0); + c += CP_PER_INDEX_2_ENTRY; + continue; + } + prevI3Block = i3Block; + if (i3Block == index3NullOffset) { + // This is the index-3 null block. + if (haveValue) { + if (nullValue != value) { + range.set(start, c - 1, value); + return true; + } + } else { + trieValue = this.nullValue; + value = nullValue; + haveValue = true; + } + prevBlock = dataNullOffset; + c = (c + CP_PER_INDEX_2_ENTRY) & ~(CP_PER_INDEX_2_ENTRY - 1); + continue; + } + i3 = (c >> SHIFT_3) & INDEX_3_MASK; + i3BlockLength = INDEX_3_BLOCK_LENGTH; + dataBlockLength = SMALL_DATA_BLOCK_LENGTH; + } + // Enumerate data blocks for one index-3 block. + do { + int block; + if ((i3Block & 0x8000) == 0) { + block = index[i3Block + i3]; + } else { + // 18-bit indexes stored in groups of 9 entries per 8 indexes. + int group = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3); + int gi = i3 & 7; + block = (index[group++] << (2 + (2 * gi))) & 0x30000; + block |= index[group + gi]; + } + if (block == prevBlock && (c - start) >= dataBlockLength) { + // The block is the same as the previous one, and filled with value. + assert ((c & (dataBlockLength - 1)) == 0); + c += dataBlockLength; + } else { + int dataMask = dataBlockLength - 1; + prevBlock = block; + if (block == dataNullOffset) { + // This is the data null block. + if (haveValue) { + if (nullValue != value) { + range.set(start, c - 1, value); + return true; + } + } else { + trieValue = this.nullValue; + value = nullValue; + haveValue = true; + } + c = (c + dataBlockLength) & ~dataMask; + } else { + int di = block + (c & dataMask); + int trieValue2 = data.getFromIndex(di); + if (haveValue) { + if (trieValue2 != trieValue) { + if (filter == null + || maybeFilterValue(trieValue2, this.nullValue, nullValue, filter) != value) { + range.set(start, c - 1, value); + return true; + } + trieValue = trieValue2; // may or may not help + } + } else { + trieValue = trieValue2; + value = maybeFilterValue(trieValue2, this.nullValue, nullValue, filter); + haveValue = true; + } + while ((++c & dataMask) != 0) { + trieValue2 = data.getFromIndex(++di); + if (trieValue2 != trieValue) { + if (filter == null + || maybeFilterValue(trieValue2, this.nullValue, nullValue, filter) != value) { + range.set(start, c - 1, value); + return true; + } + trieValue = trieValue2; // may or may not help + } + } + } + } + } while (++i3 < i3BlockLength); + } while (c < highStart); + assert (haveValue); + int di = dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + int highValue = data.getFromIndex(di); + if (maybeFilterValue(highValue, this.nullValue, nullValue, filter) != value) { + --c; + } else { + c = MAX_UNICODE; + } + range.set(start, c, value); + return true; + } + + /** + * Writes a representation of the trie to the output stream. Inverse of + * {@link #fromBinary}. + * + * @param os the output stream + * @return the number of bytes written + * @stable ICU 63 + */ + public final int toBinary(OutputStream os) { + try { + DataOutputStream dos = new DataOutputStream(os); + + // Write the UCPTrieHeader + dos.writeInt(0x54726933); // signature="Tri3" + dos.writeChar( // options + ((dataLength & 0xf0000) >> 4) | ((dataNullOffset & 0xf0000) >> 8) | (getType().ordinal() << 6) + | getValueWidth().ordinal()); + dos.writeChar(index.length); + dos.writeChar(dataLength); + dos.writeChar(index3NullOffset); + dos.writeChar(dataNullOffset); + dos.writeChar(highStart >> SHIFT_2); // shiftedHighStart + int length = 16; // sizeof(UCPTrieHeader) + + for (char i : index) { + dos.writeChar(i); + } + length += index.length * 2; + length += data.write(dos); + return length; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** @internal */ + static final int FAST_SHIFT = 6; + + /** + * Number of entries in a data block for code points below the fast limit. + * 64=0x40 @internal + */ + static final int FAST_DATA_BLOCK_LENGTH = 1 << FAST_SHIFT; + + /** + * Mask for getting the lower bits for the in-fast-data-block offset. @internal + */ + private static final int FAST_DATA_MASK = FAST_DATA_BLOCK_LENGTH - 1; + + /** @internal */ + private static final int SMALL_MAX = 0xfff; + + /** + * Offset from dataLength (to be subtracted) for fetching the value returned for + * out-of-range code points and ill-formed UTF-8/16. + * + * @internal + */ + private static final int ERROR_VALUE_NEG_DATA_OFFSET = 1; + /** + * Offset from dataLength (to be subtracted) for fetching the value returned for + * code points highStart..U+10FFFF. + * + * @internal + */ + private static final int HIGH_VALUE_NEG_DATA_OFFSET = 2; + + // ucptrie_impl.h + + /** The length of the BMP index table. 1024=0x400 */ + private static final int BMP_INDEX_LENGTH = 0x10000 >> FAST_SHIFT; + + static final int SMALL_LIMIT = 0x1000; + private static final int SMALL_INDEX_LENGTH = SMALL_LIMIT >> FAST_SHIFT; + + /** Shift size for getting the index-3 table offset. */ + static final int SHIFT_3 = 4; + + /** Shift size for getting the index-2 table offset. */ + private static final int SHIFT_2 = 5 + SHIFT_3; + + /** Shift size for getting the index-1 table offset. */ + private static final int SHIFT_1 = 5 + SHIFT_2; + + /** + * Difference between two shift sizes, for getting an index-2 offset from an + * index-3 offset. 5=9-4 + */ + static final int SHIFT_2_3 = SHIFT_2 - SHIFT_3; + + /** + * Difference between two shift sizes, for getting an index-1 offset from an + * index-2 offset. 5=14-9 + */ + static final int SHIFT_1_2 = SHIFT_1 - SHIFT_2; + + /** + * Number of index-1 entries for the BMP. (4) This part of the index-1 table is + * omitted from the serialized form. + */ + private static final int OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1; + + /** Number of entries in an index-2 block. 32=0x20 */ + static final int INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2; + + /** Mask for getting the lower bits for the in-index-2-block offset. */ + static final int INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1; + + /** Number of code points per index-2 table entry. 512=0x200 */ + static final int CP_PER_INDEX_2_ENTRY = 1 << SHIFT_2; + + /** Number of entries in an index-3 block. 32=0x20 */ + static final int INDEX_3_BLOCK_LENGTH = 1 << SHIFT_2_3; + + /** Mask for getting the lower bits for the in-index-3-block offset. */ + private static final int INDEX_3_MASK = INDEX_3_BLOCK_LENGTH - 1; + + /** Number of entries in a small data block. 16=0x10 */ + static final int SMALL_DATA_BLOCK_LENGTH = 1 << SHIFT_3; + + /** Mask for getting the lower bits for the in-small-data-block offset. */ + static final int SMALL_DATA_MASK = SMALL_DATA_BLOCK_LENGTH - 1; + + // ucptrie_impl.h: Constants for use with UCPTrieHeader.options. + private static final int OPTIONS_DATA_LENGTH_MASK = 0xf000; + private static final int OPTIONS_DATA_NULL_OFFSET_MASK = 0xf00; + private static final int OPTIONS_RESERVED_MASK = 0x38; + private static final int OPTIONS_VALUE_BITS_MASK = 7; + /** + * Value for index3NullOffset which indicates that there is no index-3 null + * block. Bit 15 is unused for this value because this bit is used if the + * index-3 contains 18-bit indexes. + */ + static final int NO_INDEX3_NULL_OFFSET = 0x7fff; + static final int NO_DATA_NULL_OFFSET = 0xfffff; + + private static abstract class Data { + abstract ValueWidth getValueWidth(); + + abstract int getDataLength(); + + abstract int getFromIndex(int index); + + abstract int write(DataOutputStream dos) throws IOException; + } + + private static final class Data16 extends Data { + char[] array; + + Data16(char[] a) { + array = a; + } + + @Override + ValueWidth getValueWidth() { + return ValueWidth.BITS_16; + } + + @Override + int getDataLength() { + return array.length; + } + + @Override + int getFromIndex(int index) { + return array[index]; + } + + @Override + int write(DataOutputStream dos) throws IOException { + for (char v : array) { + dos.writeChar(v); + } + return array.length * 2; + } + } + + private static final class Data32 extends Data { + int[] array; + + Data32(int[] a) { + array = a; + } + + @Override + ValueWidth getValueWidth() { + return ValueWidth.BITS_32; + } + + @Override + int getDataLength() { + return array.length; + } + + @Override + int getFromIndex(int index) { + return array[index]; + } + + @Override + int write(DataOutputStream dos) throws IOException { + for (int v : array) { + dos.writeInt(v); + } + return array.length * 4; + } + } + + private static final class Data8 extends Data { + byte[] array; + + Data8(byte[] a) { + array = a; + } + + @Override + ValueWidth getValueWidth() { + return ValueWidth.BITS_8; + } + + @Override + int getDataLength() { + return array.length; + } + + @Override + int getFromIndex(int index) { + return array[index] & 0xff; + } + + @Override + int write(DataOutputStream dos) throws IOException { + for (byte v : array) { + dos.writeByte(v); + } + return array.length; + } + } + + /** @internal */ + private final int[] ascii; + + /** @internal */ + private final char[] index; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final Data data; + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int dataLength; + /** + * Start of the last range which ends at U+10FFFF. + * + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int highStart; + + /** + * Internal index-3 null block offset. Set to an impossibly high value (e.g., + * 0xffff) if there is no dedicated index-3 null block. + * + * @internal + */ + private final int index3NullOffset; + /** + * Internal data null block offset, not shifted. Set to an impossibly high value + * (e.g., 0xfffff) if there is no dedicated data null block. + * + * @internal + */ + private final int dataNullOffset; + /** @internal */ + private final int nullValue; + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int fastIndex(int c) { + return index[c >> FAST_SHIFT] + (c & FAST_DATA_MASK); + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected final int smallIndex(Type type, int c) { + // Split into two methods to make this part inline-friendly. + // In C, this part is a macro. + if (c >= highStart) { + return dataLength - HIGH_VALUE_NEG_DATA_OFFSET; + } + return internalSmallIndex(type, c); + } + + private final int internalSmallIndex(Type type, int c) { + int i1 = c >> SHIFT_1; + if (type == Type.FAST) { + assert (0xffff < c && c < highStart); + i1 += BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH; + } else { + assert (0 <= c && c < highStart && highStart > SMALL_LIMIT); + i1 += SMALL_INDEX_LENGTH; + } + int i3Block = index[index[i1] + ((c >> SHIFT_2) & INDEX_2_MASK)]; + int i3 = (c >> SHIFT_3) & INDEX_3_MASK; + int dataBlock; + if ((i3Block & 0x8000) == 0) { + // 16-bit indexes + dataBlock = index[i3Block + i3]; + } else { + // 18-bit indexes stored in groups of 9 entries per 8 indexes. + i3Block = (i3Block & 0x7fff) + (i3 & ~7) + (i3 >> 3); + i3 &= 7; + dataBlock = (index[i3Block++] << (2 + (2 * i3))) & 0x30000; + dataBlock |= index[i3Block + i3]; + } + return dataBlock + (c & SMALL_DATA_MASK); + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + protected abstract int cpIndex(int c); + + /** + * A CodePointTrie with {@link Type#FAST}. + * + * @stable ICU 63 + */ + public static abstract class Fast extends CodePointTrie { + private Fast(char[] index, Data data, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, data, highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST}. + * + * @param valueWidth selects the number of bits in a data value; this method + * throws an exception if the valueWidth does not match the + * binary data; use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast fromBinary(ValueWidth valueWidth, ByteBuffer bytes) { + return (Fast) CodePointTrie.fromBinary(Type.FAST, valueWidth, bytes); + } + + /** + * @return {@link Type#FAST} + * @stable ICU 63 + */ + @Override + public final Type getType() { + return Type.FAST; + } + + /** + * Returns a trie value for a BMP code point (U+0000..U+FFFF), without range + * checking. Can be used to look up a value for a UTF-16 code unit if other + * parts of the string processing check for surrogates. + * + * @param c the input code point, must be U+0000..U+FFFF + * @return The BMP code point's trie value. + * @stable ICU 63 + */ + public abstract int bmpGet(int c); + + /** + * Returns a trie value for a supplementary code point (U+10000..U+10FFFF), + * without range checking. + * + * @param c the input code point, must be U+10000..U+10FFFF + * @return The supplementary code point's trie value. + * @stable ICU 63 + */ + public abstract int suppGet(int c); + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + @Override + protected final int cpIndex(int c) { + if (c >= 0) { + if (c <= 0xffff) { + return fastIndex(c); + } else if (c <= 0x10ffff) { + return smallIndex(Type.FAST, c); + } + } + return dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final StringIterator stringIterator(CharSequence s, int sIndex) { + return new FastStringIterator(s, sIndex); + } + + private final class FastStringIterator extends StringIterator { + private FastStringIterator(CharSequence s, int sIndex) { + super(s, sIndex); + } + + @Override + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + char lead = s.charAt(sIndex++); + c = lead; + int dataIndex; + if (!Character.isSurrogate(lead)) { + dataIndex = fastIndex(c); + } else { + char trail; + if (UTF16Plus.isSurrogateLead(lead) && sIndex < s.length() + && Character.isLowSurrogate(trail = s.charAt(sIndex))) { + ++sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.FAST, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + + @Override + public boolean previous() { + if (sIndex <= 0) { + return false; + } + char trail = s.charAt(--sIndex); + c = trail; + int dataIndex; + if (!Character.isSurrogate(trail)) { + dataIndex = fastIndex(c); + } else { + char lead; + if (!UTF16Plus.isSurrogateLead(trail) && sIndex > 0 + && Character.isHighSurrogate(lead = s.charAt(sIndex - 1))) { + --sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.FAST, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + } + } + + /** + * A CodePointTrie with {@link Type#SMALL}. + * + * @stable ICU 63 + */ + public static abstract class Small extends CodePointTrie { + private Small(char[] index, Data data, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, data, highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL}. + * + * @param valueWidth selects the number of bits in a data value; this method + * throws an exception if the valueWidth does not match the + * binary data; use null to accept any data value width + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small fromBinary(ValueWidth valueWidth, ByteBuffer bytes) { + return (Small) CodePointTrie.fromBinary(Type.SMALL, valueWidth, bytes); + } + + /** + * @return {@link Type#SMALL} + * @stable ICU 63 + */ + @Override + public final Type getType() { + return Type.SMALL; + } + + /** + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + @Override + protected final int cpIndex(int c) { + if (c >= 0) { + if (c <= SMALL_MAX) { + return fastIndex(c); + } else if (c <= 0x10ffff) { + return smallIndex(Type.SMALL, c); + } + } + return dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final StringIterator stringIterator(CharSequence s, int sIndex) { + return new SmallStringIterator(s, sIndex); + } + + private final class SmallStringIterator extends StringIterator { + private SmallStringIterator(CharSequence s, int sIndex) { + super(s, sIndex); + } + + @Override + public boolean next() { + if (sIndex >= s.length()) { + return false; + } + char lead = s.charAt(sIndex++); + c = lead; + int dataIndex; + if (!Character.isSurrogate(lead)) { + dataIndex = cpIndex(c); + } else { + char trail; + if (UTF16Plus.isSurrogateLead(lead) && sIndex < s.length() + && Character.isLowSurrogate(trail = s.charAt(sIndex))) { + ++sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.SMALL, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + + @Override + public boolean previous() { + if (sIndex <= 0) { + return false; + } + char trail = s.charAt(--sIndex); + c = trail; + int dataIndex; + if (!Character.isSurrogate(trail)) { + dataIndex = cpIndex(c); + } else { + char lead; + if (!UTF16Plus.isSurrogateLead(trail) && sIndex > 0 + && Character.isHighSurrogate(lead = s.charAt(sIndex - 1))) { + --sIndex; + c = Character.toCodePoint(lead, trail); + dataIndex = smallIndex(Type.SMALL, c); + } else { + dataIndex = dataLength - ERROR_VALUE_NEG_DATA_OFFSET; + } + } + value = data.getFromIndex(dataIndex); + return true; + } + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_16}. + * + * @stable ICU 63 + */ + public static final class Fast16 extends Fast { + private final char[] dataArray; + + Fast16(char[] index, char[] data16, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data16(data16), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data16; + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST} and {@link ValueWidth#BITS_16}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast16 fromBinary(ByteBuffer bytes) { + return (Fast16) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_16, bytes); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)]; + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_32}. + * + * @stable ICU 63 + */ + public static final class Fast32 extends Fast { + private final int[] dataArray; + + Fast32(char[] index, int[] data32, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data32(data32), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data32; + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST} and {@link ValueWidth#BITS_32}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast32 fromBinary(ByteBuffer bytes) { + return (Fast32) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_32, bytes); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)]; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)]; + } + } + + /** + * A CodePointTrie with {@link Type#FAST} and {@link ValueWidth#BITS_8}. + * + * @stable ICU 63 + */ + public static final class Fast8 extends Fast { + private final byte[] dataArray; + + Fast8(char[] index, byte[] data8, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data8(data8), highStart, index3NullOffset, dataNullOffset); + this.dataArray = data8; + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#FAST} and {@link ValueWidth#BITS_8}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Fast8 fromBinary(ByteBuffer bytes) { + return (Fast8) CodePointTrie.fromBinary(Type.FAST, ValueWidth.BITS_8, bytes); + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int get(int c) { + return dataArray[cpIndex(c)] & 0xff; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int bmpGet(int c) { + assert 0 <= c && c <= 0xffff; + return dataArray[fastIndex(c)] & 0xff; + } + + /** + * {@inheritDoc} + * + * @stable ICU 63 + */ + @Override + public final int suppGet(int c) { + assert 0x10000 <= c && c <= 0x10ffff; + return dataArray[smallIndex(Type.FAST, c)] & 0xff; + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_16}. + * + * @stable ICU 63 + */ + public static final class Small16 extends Small { + Small16(char[] index, char[] data16, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data16(data16), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL} and {@link ValueWidth#BITS_16}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small16 fromBinary(ByteBuffer bytes) { + return (Small16) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_16, bytes); + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_32}. + * + * @stable ICU 63 + */ + public static final class Small32 extends Small { + Small32(char[] index, int[] data32, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data32(data32), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL} and {@link ValueWidth#BITS_32}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small32 fromBinary(ByteBuffer bytes) { + return (Small32) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_32, bytes); + } + } + + /** + * A CodePointTrie with {@link Type#SMALL} and {@link ValueWidth#BITS_8}. + * + * @stable ICU 63 + */ + public static final class Small8 extends Small { + Small8(char[] index, byte[] data8, int highStart, int index3NullOffset, int dataNullOffset) { + super(index, new Data8(data8), highStart, index3NullOffset, dataNullOffset); + } + + /** + * Creates a trie from its binary form. Same as + * {@link CodePointTrie#fromBinary(Type, ValueWidth, ByteBuffer)} with + * {@link Type#SMALL} and {@link ValueWidth#BITS_8}. + * + * @param bytes a buffer containing the binary data of a CodePointTrie + * @return the trie + * @stable ICU 63 + */ + public static Small8 fromBinary(ByteBuffer bytes) { + return (Small8) CodePointTrie.fromBinary(Type.SMALL, ValueWidth.BITS_8, bytes); + } + } +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/OutputInt.java b/src/main/java/jdk_internal/bidi/icu/util/OutputInt.java new file mode 100755 index 00000000..433bf28a --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/OutputInt.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + ******************************************************************************* + * Copyright (C) 2014, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package jdk_internal.bidi.icu.util; + +/** + * Simple struct-like class for int output parameters. Like + * Output<Integer> but without auto-boxing. + * + * @internal but could become public deprecated This API is ICU internal only. + */ +public class OutputInt { + + /** + * The value field. + * + * @internal deprecated This API is ICU internal only. + */ + public int value; +} diff --git a/src/main/java/jdk_internal/bidi/icu/util/VersionInfo.java b/src/main/java/jdk_internal/bidi/icu/util/VersionInfo.java new file mode 100755 index 00000000..d6abf225 --- /dev/null +++ b/src/main/java/jdk_internal/bidi/icu/util/VersionInfo.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +package jdk_internal.bidi.icu.util; + +import java.util.HashMap; + +/** + * Class to store version numbers of the form major.minor.milli.micro. + * + * @author synwee + * @stable ICU 2.6 + */ +public final class VersionInfo { + // public data members ------------------------------------------------- + + /** + * Data version string for ICU's internal data. Used for appending to data path + * (e.g. icudt43b) + * + * @internal + * @deprecated This API is ICU internal only. + */ + @Deprecated + public static final String ICU_DATA_VERSION_PATH = "67b"; + + // public methods ------------------------------------------------------ + + /** + * Returns an instance of VersionInfo with the argument version. + * + * @param version version String in the format of "major.minor.milli.micro" or + * "major.minor.milli" or "major.minor" or "major", where major, + * minor, milli, micro are non-negative numbers {@literal <=} + * 255. If the trailing version numbers are not specified they + * are taken as 0s. E.g. Version "3.1" is equivalent to + * "3.1.0.0". + * @return an instance of VersionInfo with the argument version. + * @exception throws an IllegalArgumentException when the argument version is + * not in the right format + * @stable ICU 2.6 + */ + public static VersionInfo getInstance(String version) { + int length = version.length(); + int array[] = { 0, 0, 0, 0 }; + int count = 0; + int index = 0; + + while (count < 4 && index < length) { + char c = version.charAt(index); + if (c == '.') { + count++; + } else { + c -= '0'; + if (c < 0 || c > 9) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + array[count] *= 10; + array[count] += c; + } + index++; + } + if (index != length) { + throw new IllegalArgumentException( + "Invalid version number: String '" + version + "' exceeds version format"); + } + for (int i = 0; i < 4; i++) { + if (array[i] < 0 || array[i] > 255) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + } + + return getInstance(array[0], array[1], array[2], array[3]); + } + + /** + * Returns an instance of VersionInfo with the argument version. + * + * @param major major version, non-negative number {@literal <=} 255. + * @param minor minor version, non-negative number {@literal <=} 255. + * @param milli milli version, non-negative number {@literal <=} 255. + * @param micro micro version, non-negative number {@literal <=} 255. + * @exception throws an IllegalArgumentException when either arguments are + * negative or {@literal >} 255 + * @stable ICU 2.6 + */ + public static VersionInfo getInstance(int major, int minor, int milli, int micro) { + // checks if it is in the hashmap + // else + if (major < 0 || major > 255 || minor < 0 || minor > 255 || milli < 0 || milli > 255 || micro < 0 + || micro > 255) { + throw new IllegalArgumentException(INVALID_VERSION_NUMBER_); + } + int version = getInt(major, minor, milli, micro); + Integer key = Integer.valueOf(version); + Object result = MAP_.get(key); + if (result == null) { + result = new VersionInfo(version); + MAP_.put(key, result); + } + return (VersionInfo) result; + } + + /** + * Compares other with this VersionInfo. + * + * @param other VersionInfo to be compared + * @return 0 if the argument is a VersionInfo object that has version + * information equal to this object. Less than 0 if the argument is a + * VersionInfo object that has version information greater than this + * object. Greater than 0 if the argument is a VersionInfo object that + * has version information less than this object. + * @stable ICU 2.6 + */ + public int compareTo(VersionInfo other) { + return m_version_ - other.m_version_; + } + + // private data members ---------------------------------------------- + + /** + * Version number stored as a byte for each of the major, minor, milli and micro + * numbers in the 32 bit int. Most significant for the major and the least + * significant contains the micro numbers. + */ + private int m_version_; + /** + * Map of singletons + */ + private static final HashMap MAP_ = new HashMap<>(); + /** + * Error statement string + */ + private static final String INVALID_VERSION_NUMBER_ = "Invalid version number: Version number may be negative or greater than 255"; + + // private constructor ----------------------------------------------- + + /** + * Constructor with int + * + * @param compactversion a 32 bit int with each byte representing a number + */ + private VersionInfo(int compactversion) { + m_version_ = compactversion; + } + + /** + * Gets the int from the version numbers + * + * @param major non-negative version number + * @param minor non-negativeversion number + * @param milli non-negativeversion number + * @param micro non-negativeversion number + */ + private static int getInt(int major, int minor, int milli, int micro) { + return (major << 24) | (minor << 16) | (milli << 8) | micro; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerBidiReorder.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerBidiReorder.java new file mode 100755 index 00000000..4a480072 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerBidiReorder.java @@ -0,0 +1,87 @@ +package net.lax1dude.eaglercraft.v1_8; + +import jdk_internal.bidi.Bidi; + +/** + * 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. + * + */ +public class EaglerBidiReorder { + + /** + * Taken from minecraft 1.6 + */ + public static String bidiReorder(String par1Str) { + if (par1Str != null && Bidi.requiresBidi(par1Str.toCharArray(), 0, par1Str.length())) { + Bidi bidi = new Bidi(par1Str, -2); + byte[] abyte = new byte[bidi.getRunCount()]; + String[] astring = new String[abyte.length]; + int i; + + for (int j = 0; j < abyte.length; ++j) { + int k = bidi.getRunStart(j); + i = bidi.getRunLimit(j); + int l = bidi.getRunLevel(j); + String s1 = par1Str.substring(k, i); + abyte[j] = (byte) l; + astring[j] = s1; + } + + String[] astring1 = (String[]) astring.clone(); + Bidi.reorderVisually(abyte, 0, astring, 0, abyte.length); + StringBuilder stringbuilder = new StringBuilder(); + i = 0; + + while (i < astring.length) { + byte b0 = abyte[i]; + int i1 = 0; + + while (true) { + if (i1 < astring1.length) { + if (!astring1[i1].equals(astring[i])) { + ++i1; + continue; + } + + b0 = abyte[i1]; + } + + if ((b0 & 1) == 0) { + stringbuilder.append(astring[i]); + } else { + for (i1 = astring[i].length() - 1; i1 >= 0; --i1) { + char c0 = astring[i].charAt(i1); + + if (c0 == 40) { + c0 = 41; + } else if (c0 == 41) { + c0 = 40; + } + + stringbuilder.append(c0); + } + } + + ++i; + break; + } + } + + return stringbuilder.toString(); + } else { + return par1Str; + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java index 49a8dbb2..94100a5c 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglerZLIB.java @@ -26,15 +26,33 @@ public class EaglerZLIB { public static OutputStream newDeflaterOutputStream(OutputStream os) throws IOException { return PlatformRuntime.newDeflaterOutputStream(os); } - + + public static int deflateFull(byte[] input, byte[] output) throws IOException { + return PlatformRuntime.deflateFull(input, 0, input.length, output, 0, output.length); + } + + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + return PlatformRuntime.deflateFull(input, inputOff, inputLen, output, outputOff, outputLen); + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return PlatformRuntime.newGZIPOutputStream(os); } - + public static InputStream newInflaterInputStream(InputStream is) throws IOException { return PlatformRuntime.newInflaterInputStream(is); } - + + public static int inflateFull(byte[] input, byte[] output) throws IOException { + return PlatformRuntime.inflateFull(input, 0, input.length, output, 0, output.length); + } + + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + return PlatformRuntime.inflateFull(input, inputOff, inputLen, output, outputOff, outputLen); + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return PlatformRuntime.newGZIPInputStream(is); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java index 6434d403..430ff1d3 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/EaglercraftVersion.java +++ b/src/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 = "u46"; + public static final String projectForkVersion = "u47"; 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 = "u46"; + public static final String projectOriginVersion = "u47"; public static final String projectOriginURL = "https://gitlab.com/lax1dude/eaglercraftx-1.8"; // rest in peace // EPK Version Identifier - public static final String EPKVersionIdentifier = "u46"; // Set to null to disable EPK version check + public static final String EPKVersionIdentifier = "u47"; // 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 = 46; + public static final int updateBundlePackageVersionInt = 47; public static final String updateLatestLocalStorageKey = "latestUpdate_" + updateBundlePackageName; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java index 8b4f843d..bf00ed96 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ByteBuffer.java @@ -2,7 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; /** - * 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 @@ -16,88 +16,100 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface ByteBuffer extends Buffer { +public abstract class ByteBuffer implements Buffer { - ByteBuffer duplicate(); + public abstract ByteBuffer duplicate(); - byte get(); + public abstract byte get(); - ByteBuffer put(byte b); + public abstract ByteBuffer put(byte b); - byte get(int index); + public abstract byte get(int index); - ByteBuffer put(int index, byte b); + public abstract ByteBuffer put(int index, byte b); - ByteBuffer get(byte[] dst, int offset, int length); + public abstract ByteBuffer get(byte[] dst, int offset, int length); - ByteBuffer get(byte[] dst); + public abstract ByteBuffer get(byte[] dst); - ByteBuffer put(ByteBuffer src); + public abstract ByteBuffer put(ByteBuffer src); - ByteBuffer put(byte[] src, int offset, int length); + public abstract ByteBuffer put(byte[] src, int offset, int length); - ByteBuffer put(byte[] src); + public abstract ByteBuffer put(byte[] src); - char getChar(); + public abstract char getChar(); - ByteBuffer putChar(char value); + public abstract ByteBuffer putChar(char value); - char getChar(int index); + public abstract char getChar(int index); - ByteBuffer putChar(int index, char value); + public abstract ByteBuffer putChar(int index, char value); - short getShort(); + public abstract short getShort(); - ByteBuffer putShort(short value); + public abstract ByteBuffer putShort(short value); - short getShort(int index); + public abstract short getShort(int index); - ByteBuffer putShort(int index, short value); + public abstract ByteBuffer putShort(int index, short value); - ShortBuffer asShortBuffer(); + public abstract ShortBuffer asShortBuffer(); - int getInt(); + public abstract int getInt(); - ByteBuffer putInt(int value); + public abstract ByteBuffer putInt(int value); - int getInt(int index); + public abstract int getInt(int index); - ByteBuffer putInt(int index, int value); + public abstract ByteBuffer putInt(int index, int value); - IntBuffer asIntBuffer(); + public abstract IntBuffer asIntBuffer(); - long getLong(); + public abstract long getLong(); - ByteBuffer putLong(long value); + public abstract ByteBuffer putLong(long value); - long getLong(int index); + public abstract long getLong(int index); - ByteBuffer putLong(int index, long value); + public abstract ByteBuffer putLong(int index, long value); - float getFloat(); + public abstract float getFloat(); - ByteBuffer putFloat(float value); + public abstract ByteBuffer putFloat(float value); - float getFloat(int index); + public abstract float getFloat(int index); - ByteBuffer putFloat(int index, float value); + public abstract ByteBuffer putFloat(int index, float value); - FloatBuffer asFloatBuffer(); + public abstract FloatBuffer asFloatBuffer(); - ByteBuffer mark(); + public abstract ByteBuffer mark(); - ByteBuffer reset(); + public abstract ByteBuffer reset(); - ByteBuffer clear(); + public abstract ByteBuffer clear(); - ByteBuffer flip(); + public abstract ByteBuffer flip(); - ByteBuffer rewind(); + public abstract ByteBuffer rewind(); - ByteBuffer limit(int newLimit); + public abstract ByteBuffer limit(int newLimit); - ByteBuffer position(int newPosition); + public abstract int limit(); - byte[] array(); + public abstract ByteBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract byte[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java index 6d9a9374..e34484eb 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/FloatBuffer.java @@ -1,7 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; /** - * 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 @@ -15,49 +15,61 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface FloatBuffer extends Buffer { +public abstract class FloatBuffer implements Buffer { - FloatBuffer duplicate(); + public abstract FloatBuffer duplicate(); - float get(); + public abstract float get(); - FloatBuffer put(float b); + public abstract FloatBuffer put(float b); - float get(int index); + public abstract float get(int index); - FloatBuffer put(int index, float b); + public abstract FloatBuffer put(int index, float b); - float getElement(int index); + public abstract float getElement(int index); - void putElement(int index, float value); + public abstract void putElement(int index, float value); - FloatBuffer get(float[] dst, int offset, int length); + public abstract FloatBuffer get(float[] dst, int offset, int length); - FloatBuffer get(float[] dst); + public abstract FloatBuffer get(float[] dst); - FloatBuffer put(FloatBuffer src); + public abstract FloatBuffer put(FloatBuffer src); - FloatBuffer put(float[] src, int offset, int length); + public abstract FloatBuffer put(float[] src, int offset, int length); - FloatBuffer put(float[] src); + public abstract FloatBuffer put(float[] src); - boolean isDirect(); + public abstract boolean isDirect(); - FloatBuffer mark(); + public abstract FloatBuffer mark(); - FloatBuffer reset(); + public abstract FloatBuffer reset(); - FloatBuffer clear(); + public abstract FloatBuffer clear(); - FloatBuffer flip(); + public abstract FloatBuffer flip(); - FloatBuffer rewind(); + public abstract FloatBuffer rewind(); - FloatBuffer limit(int newLimit); + public abstract FloatBuffer limit(int newLimit); - FloatBuffer position(int newPosition); + public abstract int limit(); - float[] array(); + public abstract FloatBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract float[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java index 44e5967d..8414e4ee 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/IntBuffer.java @@ -15,49 +15,61 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface IntBuffer extends Buffer { +public abstract class IntBuffer implements Buffer { - IntBuffer duplicate(); + public abstract IntBuffer duplicate(); - int get(); + public abstract int get(); - IntBuffer put(int b); + public abstract IntBuffer put(int b); - int get(int index); + public abstract int get(int index); - IntBuffer put(int index, int b); + public abstract IntBuffer put(int index, int b); - int getElement(int index); + public abstract int getElement(int index); - void putElement(int index, int value); + public abstract void putElement(int index, int value); - IntBuffer get(int[] dst, int offset, int length); + public abstract IntBuffer get(int[] dst, int offset, int length); - IntBuffer get(int[] dst); + public abstract IntBuffer get(int[] dst); - IntBuffer put(IntBuffer src); + public abstract IntBuffer put(IntBuffer src); - IntBuffer put(int[] src, int offset, int length); + public abstract IntBuffer put(int[] src, int offset, int length); - IntBuffer put(int[] src); + public abstract IntBuffer put(int[] src); - boolean isDirect(); + public abstract boolean isDirect(); - IntBuffer mark(); + public abstract IntBuffer mark(); - IntBuffer reset(); + public abstract IntBuffer reset(); - IntBuffer clear(); + public abstract IntBuffer clear(); - IntBuffer flip(); + public abstract IntBuffer flip(); - IntBuffer rewind(); + public abstract IntBuffer rewind(); - IntBuffer limit(int newLimit); + public abstract IntBuffer limit(int newLimit); - IntBuffer position(int newPosition); + public abstract int limit(); - int[] array(); + public abstract IntBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract int[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java index bb158828..b9649f6a 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/ShortBuffer.java @@ -1,7 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; /** - * 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 @@ -15,48 +15,60 @@ package net.lax1dude.eaglercraft.v1_8.internal.buffer; * POSSIBILITY OF SUCH DAMAGE. * */ -public interface ShortBuffer extends Buffer { +public abstract class ShortBuffer implements Buffer { - ShortBuffer duplicate(); + public abstract ShortBuffer duplicate(); - short get(); + public abstract short get(); - ShortBuffer put(short b); + public abstract ShortBuffer put(short b); - short get(int index); + public abstract short get(int index); - ShortBuffer put(int index, short b); + public abstract ShortBuffer put(int index, short b); - short getElement(int index); + public abstract short getElement(int index); - void putElement(int index, short value); + public abstract void putElement(int index, short value); - ShortBuffer get(short[] dst, int offset, int length); + public abstract ShortBuffer get(short[] dst, int offset, int length); - ShortBuffer get(short[] dst); + public abstract ShortBuffer get(short[] dst); - ShortBuffer put(ShortBuffer src); + public abstract ShortBuffer put(ShortBuffer src); - ShortBuffer put(short[] src, int offset, int length); + public abstract ShortBuffer put(short[] src, int offset, int length); - ShortBuffer put(short[] src); + public abstract ShortBuffer put(short[] src); - boolean isDirect(); + public abstract boolean isDirect(); - ShortBuffer mark(); + public abstract ShortBuffer mark(); - ShortBuffer reset(); + public abstract ShortBuffer reset(); - ShortBuffer clear(); + public abstract ShortBuffer clear(); - ShortBuffer flip(); + public abstract ShortBuffer flip(); - ShortBuffer rewind(); + public abstract ShortBuffer rewind(); - ShortBuffer limit(int newLimit); + public abstract ShortBuffer limit(int newLimit); - ShortBuffer position(int newPosition); + public abstract int limit(); - short[] array(); + public abstract ShortBuffer position(int newPosition); + + public abstract int position(); + + public abstract int remaining(); + + public abstract boolean hasRemaining(); + + public abstract int capacity(); + + public abstract boolean hasArray(); + + public abstract short[] array(); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java index 910f379b..b9cd3758 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/minecraft/EaglerTextureAtlasSprite.java @@ -1,10 +1,10 @@ package net.lax1dude.eaglercraft.v1_8.minecraft; import java.io.IOException; -import java.util.Iterator; import java.util.List; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.HString; @@ -228,10 +228,8 @@ public class EaglerTextureAtlasSprite { int l = i; this.height = this.width; if (meta.getFrameCount() > 0) { - Iterator iterator = meta.getFrameIndexSet().iterator(); - - while (iterator.hasNext()) { - int i1 = iterator.next().intValue(); + for (IntCursor cur : meta.getFrameIndexSet()) { + int i1 = cur.value; if (i1 >= j1) { throw new RuntimeException("invalid frameindex " + i1); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java index c2d1ad37..3a243e71 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglerMeshLoader.java @@ -49,6 +49,7 @@ public class EaglerMeshLoader implements IResourceManagerReloadListener { if(theMesh == null) { theMesh = new HighPolyMesh(); reloadMesh(meshLoc, theMesh, Minecraft.getMinecraft().getResourceManager()); + meshCache.put(meshLoc, theMesh); } meshLoc.cachedPointerType = ResourceLocation.CACHED_POINTER_EAGLER_MESH; meshLoc.cachedPointer = theMesh; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java index c44464f6..d0ab885f 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/EaglercraftGPU.java @@ -7,8 +7,8 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; import net.minecraft.util.MathHelper; -import java.util.HashMap; -import java.util.Map; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.internal.GLObjectMap; @@ -213,15 +213,18 @@ public class EaglercraftGPU { ++GlStateManager.stateNormalSerial; } - private static final Map stringCache = new HashMap<>(); + private static final IntObjectMap stringCache = new IntObjectHashMap<>(); public static final String glGetString(int param) { String str = stringCache.get(param); if(str == null) { str = _wglGetString(param); + if(str == null) { + str = ""; + } stringCache.put(param, str); } - return str; + return str.length() == 0 ? null : str; } public static final void glGetInteger(int param, int[] values) { diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java index e766dc22..699888b0 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/WorldRenderer.java @@ -3,9 +3,10 @@ package net.lax1dude.eaglercraft.v1_8.opengl; import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer; import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer; import net.lax1dude.eaglercraft.v1_8.internal.buffer.IntBuffer; -import java.util.Arrays; import java.util.BitSet; -import java.util.Comparator; +import java.util.function.IntBinaryOperator; + +import com.carrotsearch.hppc.sorting.QuickSort; import net.lax1dude.eaglercraft.v1_8.EagRuntime; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -84,12 +85,37 @@ public class WorldRenderer { } } + private float[] sortArrayCacheA = null; + private int[] sortArrayCacheB = null; + private BitSet sortBitSetCache = null; + private final IntBinaryOperator sortArrayCacheLambda = this::sortFunction_func_181674_a; + private final IntBinaryOperator swapArrayCacheLambda = this::swapFunction_func_181674_a; + + protected int sortFunction_func_181674_a(int integer, int integer1) { + return Float.compare(sortArrayCacheA[sortArrayCacheB[integer1]], sortArrayCacheA[sortArrayCacheB[integer]]); + } + + protected int swapFunction_func_181674_a(int i, int j) { + int swap = sortArrayCacheB[i]; + sortArrayCacheB[i] = sortArrayCacheB[j]; + sortArrayCacheB[j] = swap; + return 0; + } + /** * MOST LIKELY USED TO SORT QUADS BACK TO FRONT */ public void func_181674_a(float parFloat1, float parFloat2, float parFloat3) { int i = this.vertexCount / 4; - final float[] afloat = new float[i]; + if(i == 0) { + return; + } + + float[] afloat = sortArrayCacheA; + if(afloat == null || afloat.length < i) { + afloat = new float[i]; + sortArrayCacheA = afloat; + } for (int j = 0; j < i; ++j) { afloat[j] = func_181665_a(this.floatBuffer, (float) ((double) parFloat1 + this.xOffset), @@ -97,30 +123,38 @@ public class WorldRenderer { this.vertexFormat.attribStride >> 2, j * this.vertexFormat.attribStride); } - Integer[] ainteger = new Integer[i]; - - for (int k = 0; k < ainteger.length; ++k) { - ainteger[k] = Integer.valueOf(k); + int[] ainteger = sortArrayCacheB; + if(ainteger == null || ainteger.length < i) { + ainteger = new int[i]; + sortArrayCacheB = ainteger; + } + + for (int k = 0; k < i; ++k) { + ainteger[k] = k; + } + + QuickSort.sort(0, i, sortArrayCacheLambda, swapArrayCacheLambda); + + BitSet bitset = sortBitSetCache; + if(bitset == null) { + bitset = new BitSet(); + sortBitSetCache = bitset; + }else { + bitset.clear(); } - Arrays.sort(ainteger, new Comparator() { - public int compare(Integer integer, Integer integer1) { - return Float.compare(afloat[integer1.intValue()], afloat[integer.intValue()]); - } - }); - BitSet bitset = new BitSet(); int l = this.vertexFormat.attribStride; int[] aint = new int[l]; - for (int l1 = 0; (l1 = bitset.nextClearBit(l1)) < ainteger.length; ++l1) { - int i1 = ainteger[l1].intValue(); + for (int l1 = 0; (l1 = bitset.nextClearBit(l1)) < i; ++l1) { + int i1 = ainteger[l1]; if (i1 != l1) { this.intBuffer.limit(i1 * l + l); this.intBuffer.position(i1 * l); this.intBuffer.get(aint); int j1 = i1; - for (int k1 = ainteger[i1].intValue(); j1 != l1; k1 = ainteger[k1].intValue()) { + for (int k1 = ainteger[i1]; j1 != l1; k1 = ainteger[k1]) { this.intBuffer.limit(k1 * l + l); this.intBuffer.position(k1 * l); IntBuffer intbuffer = this.intBuffer.duplicate(); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java index 5f6bcff1..7f8c1555 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/BlockVertexIDs.java @@ -3,8 +3,8 @@ package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred; import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; @@ -32,7 +32,7 @@ public class BlockVertexIDs implements IResourceManagerReloadListener { private static final Logger logger = LogManager.getLogger("BlockVertexIDsCSV"); - public static final Map modelToID = new HashMap<>(); + public static final ObjectIntMap modelToID = new ObjectIntHashMap<>(); public static int builtin_water_still_vertex_id = 0; public static int builtin_water_flow_vertex_id = 0; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java index 848208ed..28327d8a 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/DebugFramebufferView.java @@ -316,6 +316,14 @@ public class DebugFramebufferView { GlStateManager.bindTexture(pipeline.realisticWaterMaskTexture); DrawUtils.drawStandardQuad2D(); })), + (new DebugFramebufferView("Water: Combined Normals", (pipeline) -> { + if(!pipeline.config.is_rendering_realisticWater) throw new NoDataException(); + PipelineShaderGBufferDebugView dbv = pipeline.useDebugViewShader(1); + EaglerDeferredPipeline.uniformMatrixHelper(dbv.uniforms.u_inverseViewMatrix, DeferredStateManager.inverseViewMatrix); + GlStateManager.setActiveTexture(GL_TEXTURE0); + GlStateManager.bindTexture(pipeline.realisticWaterCombinedNormalsTexture); + DrawUtils.drawStandardQuad2D(); + })), (new DebugFramebufferView("Water: Surface Depth", (pipeline) -> { if(!pipeline.config.is_rendering_realisticWater) throw new NoDataException(); float depthStart = 0.001f; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java index fb4d71f8..dbea1ec5 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/EaglerDeferredPipeline.java @@ -34,6 +34,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderP import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterControl; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterNoise; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterNormalMap; +import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderRealisticWaterNormalsMix; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderReprojControl; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderReprojSSR; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderSSAOGenerate; @@ -43,6 +44,7 @@ import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderS import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderSkyboxRender; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderSkyboxRenderEnd; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.PipelineShaderTonemap; +import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program.ShaderMissingException; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture.MetalsLUT; import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture.TemperaturesLUT; import net.lax1dude.eaglercraft.v1_8.vector.Matrix3f; @@ -291,6 +293,7 @@ public class EaglerDeferredPipeline { public PipelineShaderRealisticWaterControl shader_realistic_water_control = null; public PipelineShaderRealisticWaterNoise shader_realistic_water_noise = null; public PipelineShaderRealisticWaterNormalMap shader_realistic_water_normals = null; + public PipelineShaderRealisticWaterNormalsMix shader_realistic_water_normals_mix = null; public PipelineShaderHandDepthMask shader_hand_depth_mask = null; public PipelineShaderFXAA shader_post_fxaa = null; public SkyboxRenderer skybox = null; @@ -913,6 +916,12 @@ public class EaglerDeferredPipeline { shader_realistic_water_normals = PipelineShaderRealisticWaterNormalMap.compile(); shader_realistic_water_normals.loadUniforms(); _wglUniform2f(shader_realistic_water_normals.uniforms.u_sampleOffset2f, 0.00390625f, 0.00390625f); + try { + shader_realistic_water_normals_mix = PipelineShaderRealisticWaterNormalsMix.compile(); + shader_realistic_water_normals_mix.loadUniforms(); + }catch(ShaderMissingException exx) { + shader_realistic_water_normals_mix = null; + } if(!config.is_rendering_raytracing) { shader_reproject_ssr = PipelineShaderReprojSSR.compile(); shader_reproject_ssr.loadUniforms(); @@ -1083,7 +1092,7 @@ public class EaglerDeferredPipeline { double distX = worldX - reprojectionOriginCoordinateX; double distY = worldY - reprojectionOriginCoordinateY; double distZ = worldZ - reprojectionOriginCoordinateZ; - if(distX * distX + distY * distY + distZ * distZ > 48.0 * 48.0) { + if(distX * distX + distY * distY + distZ * distZ > 72.0 * 72.0) { reprojectionOriginCoordinateX = worldX; reprojectionOriginCoordinateY = worldY; reprojectionOriginCoordinateZ = worldZ; @@ -1098,7 +1107,7 @@ public class EaglerDeferredPipeline { } distX = worldX - cloudRenderOriginCoordinateX; distZ = worldZ - cloudRenderOriginCoordinateZ; - if(distX * distX + distZ * distZ > 256.0 * 256.0) { + if(distX * distX + distZ * distZ > 384.0 * 384.0) { cloudRenderOriginCoordinateX = worldX; cloudRenderOriginCoordinateZ = worldZ; cloudRenderViewerOffsetX = 0.0f; @@ -1844,39 +1853,44 @@ public class EaglerDeferredPipeline { _wglUniformMatrix4x2fv(shader_reproject_ssr.uniforms.u_lastInverseProjMatrix4x2f, false, matrixCopyBuffer); _wglUniform1f(shader_reproject_ssr.uniforms.u_sampleStep1f, 0.125f); - DrawUtils.drawStandardQuad2D(); // sample 1 + if(shader_reproject_ssr.uniforms.u_sampleDelta1i != null) { + _wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5); + DrawUtils.drawStandardQuad2D(); + }else { + DrawUtils.drawStandardQuad2D(); // sample 1 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 2 + DrawUtils.drawStandardQuad2D(); // sample 2 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 3 + DrawUtils.drawStandardQuad2D(); // sample 3 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 4 + DrawUtils.drawStandardQuad2D(); // sample 4 - _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(reprojectionSSRHitVector[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(reprojectionSSRTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, reprojectionSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(reprojectionSSRHitVector[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(reprojectionSSRTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 5 + DrawUtils.drawStandardQuad2D(); // sample 5 + } DeferredStateManager.checkGLError("combineGBuffersAndIlluminate(): RUN SCREENSPACE REFLECTIONS ALGORITHM"); } @@ -2663,14 +2677,24 @@ public class EaglerDeferredPipeline { _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterCombinedNormalsFramebuffer); GlStateManager.viewport(0, 0, currentWidth, currentHeight); - GlStateManager.bindTexture(gBufferNormalsTexture); - TextureCopyUtil.blitTexture(); - - GlStateManager.bindTexture(realisticWaterMaskTexture); - GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); - TextureCopyUtil.blitTexture(); - GlStateManager.disableBlend(); + if(shader_realistic_water_normals_mix != null) { + GlStateManager.disableBlend(); + GlStateManager.setActiveTexture(GL_TEXTURE1); + GlStateManager.bindTexture(realisticWaterMaskTexture); + GlStateManager.setActiveTexture(GL_TEXTURE0); + GlStateManager.bindTexture(gBufferNormalsTexture); + shader_realistic_water_normals_mix.useProgram(); + DrawUtils.drawStandardQuad2D(); + }else { + GlStateManager.bindTexture(gBufferNormalsTexture); + TextureCopyUtil.blitTexture(); + + GlStateManager.bindTexture(realisticWaterMaskTexture); + GlStateManager.enableBlend(); + GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + TextureCopyUtil.blitTexture(); + GlStateManager.disableBlend(); + } DeferredStateManager.checkGLError("endDrawRealisticWaterMask(): COMBINE NORMALS"); @@ -2773,39 +2797,44 @@ public class EaglerDeferredPipeline { _wglUniformMatrix4x2fv(shader_reproject_ssr.uniforms.u_lastInverseProjMatrix4x2f, false, matrixCopyBuffer); _wglUniform1f(shader_reproject_ssr.uniforms.u_sampleStep1f, 0.5f); - DrawUtils.drawStandardQuad2D(); // sample 1 + if(shader_reproject_ssr.uniforms.u_sampleDelta1i != null) { + _wglUniform1i(shader_reproject_ssr.uniforms.u_sampleDelta1i, 5); + DrawUtils.drawStandardQuad2D(); + }else { + DrawUtils.drawStandardQuad2D(); // sample 1 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 2 + DrawUtils.drawStandardQuad2D(); // sample 2 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 3 + DrawUtils.drawStandardQuad2D(); // sample 3 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[0]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[1]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[1]); - DrawUtils.drawStandardQuad2D(); // sample 4 + DrawUtils.drawStandardQuad2D(); // sample 4 - _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); - GlStateManager.setActiveTexture(GL_TEXTURE3); - GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); - GlStateManager.setActiveTexture(GL_TEXTURE2); - GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); + _wglBindFramebuffer(_GL_FRAMEBUFFER, realisticWaterSSRFramebuffer[1]); + GlStateManager.setActiveTexture(GL_TEXTURE3); + GlStateManager.bindTexture(realisticWaterControlHitVectorTexture[0]); + GlStateManager.setActiveTexture(GL_TEXTURE2); + GlStateManager.bindTexture(realisticWaterControlReflectionTexture[0]); - DrawUtils.drawStandardQuad2D(); // sample 5 + DrawUtils.drawStandardQuad2D(); // sample 5 + } DeferredStateManager.checkGLError("endDrawRealisticWaterMask(): RUN SCREENSPACE REFLECTIONS ALGORITHM"); @@ -3066,6 +3095,8 @@ public class EaglerDeferredPipeline { GlStateManager.clear(GL_DEPTH_BUFFER_BIT); GlStateManager.enableDepth(); DeferredStateManager.setDefaultMaterialConstants(); + DeferredStateManager.disableFog(); + updateForwardRenderWorldLightingData(); DeferredStateManager.checkGLError("Post: beginDrawHandOverlay()"); } @@ -3838,6 +3869,10 @@ public class EaglerDeferredPipeline { shader_realistic_water_normals.destroy(); shader_realistic_water_normals = null; } + if(shader_realistic_water_normals_mix != null) { + shader_realistic_water_normals_mix.destroy(); + shader_realistic_water_normals_mix = null; + } if(shader_post_fxaa != null) { shader_post_fxaa.destroy(); shader_post_fxaa = null; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderRealisticWaterNormalsMix.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderRealisticWaterNormalsMix.java new file mode 100755 index 00000000..ed2ceb85 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderRealisticWaterNormalsMix.java @@ -0,0 +1,57 @@ +package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program; + +import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL.*; +import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; + +import net.lax1dude.eaglercraft.v1_8.internal.IProgramGL; +import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL; + +/** + * 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. + * + */ +public class PipelineShaderRealisticWaterNormalsMix extends ShaderProgram { + + public static PipelineShaderRealisticWaterNormalsMix compile() throws ShaderException { + IShaderGL normalsMix = ShaderCompiler.compileShader("realistic_water_normals_mix", GL_FRAGMENT_SHADER, + ShaderSource.realistic_water_normals_mix_fsh); + try { + IProgramGL prog = ShaderCompiler.linkProgram("realistic_water_normals_mix", + SharedPipelineShaders.deferred_local, normalsMix); + return new PipelineShaderRealisticWaterNormalsMix(prog); + }finally { + if(normalsMix != null) { + normalsMix.free(); + } + } + } + + private PipelineShaderRealisticWaterNormalsMix(IProgramGL program) { + super(program, new Uniforms()); + } + + public static class Uniforms implements IProgramUniforms { + + private Uniforms() { + } + + @Override + public void loadUniforms(IProgramGL prog) { + _wglUniform1i(_wglGetUniformLocation(prog, "u_gbufferNormalsTexture"), 0); + _wglUniform1i(_wglGetUniformLocation(prog, "u_surfaceNormalsTexture"), 1); + } + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java index 41c0cf98..4b7a90f0 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/PipelineShaderReprojSSR.java @@ -48,6 +48,7 @@ public class PipelineShaderReprojSSR extends ShaderProgram compileFlags) throws ShaderCompileException { - return compileShader(name, stage, filename.toString(), ShaderSource.getSourceFor(filename), compileFlags); + String src = ShaderSource.getSourceFor(filename); + if(src == null) { + throw new ShaderMissingException(name, "File not found: " + filename); + } + return compileShader(name, stage, filename.toString(), src, compileFlags); } public static IShaderGL compileShader(String name, int stage, String filename, String source, List compileFlags) throws ShaderCompileException { diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderMissingException.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderMissingException.java new file mode 100755 index 00000000..b76437f1 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderMissingException.java @@ -0,0 +1,24 @@ +package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.program; + +/** + * 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. + * + */ +public class ShaderMissingException extends ShaderException { + + public ShaderMissingException(String shaderName, String msg) { + super(shaderName, msg); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java index c0fa936c..b89d9bde 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/program/ShaderSource.java @@ -54,6 +54,7 @@ public class ShaderSource { public static final ResourceLocation realistic_water_render_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_render.fsh"); public static final ResourceLocation realistic_water_control_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_control.fsh"); public static final ResourceLocation realistic_water_normals_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_normals.fsh"); + public static final ResourceLocation realistic_water_normals_mix_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_normals_mix.fsh"); public static final ResourceLocation realistic_water_noise_fsh = new ResourceLocation("eagler:glsl/deferred/realistic_water_noise.fsh"); public static final ResourceLocation gbuffer_debug_view_fsh = new ResourceLocation("eagler:glsl/deferred/gbuffer_debug_view.fsh"); public static final ResourceLocation ssao_generate_fsh = new ResourceLocation("eagler:glsl/deferred/ssao_generate.fsh"); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java index 9032dfd6..d481ee4e 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/opengl/ext/deferred/texture/EaglerTextureAtlasSpritePBR.java @@ -1,10 +1,10 @@ package net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.texture; import java.io.IOException; -import java.util.Iterator; import java.util.List; import java.util.concurrent.Callable; +import com.carrotsearch.hppc.cursors.IntCursor; import com.google.common.collect.Lists; import net.lax1dude.eaglercraft.v1_8.HString; @@ -104,10 +104,8 @@ public class EaglerTextureAtlasSpritePBR extends EaglerTextureAtlasSprite { int l = i; this.height = this.width; if (meta.getFrameCount() > 0) { - Iterator iterator = meta.getFrameIndexSet().iterator(); - - while (iterator.hasNext()) { - int i1 = ((Integer) iterator.next()).intValue(); + for (IntCursor cur : meta.getFrameIndexSet()) { + int i1 = cur.value; if (i1 >= j1) { throw new RuntimeException("invalid frameindex " + i1); } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java index b98622cf..f996858c 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/profile/ServerSkinCache.java @@ -201,7 +201,7 @@ public class ServerSkinCache { } public SkinCacheEntry getSkin(String url, SkinModel skinModelResponse) { - if(url.length() > 0xFFFF) { + if(url.length() > 0x7F00) { return skinModelResponse == SkinModel.ALEX ? defaultSlimCacheEntry : defaultCacheEntry; } EaglercraftUUID generatedUUID = SkinPackets.createEaglerURLSkinUUID(url); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java index a9b2047a..6b22ba14 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/ServerQueryImpl.java @@ -10,7 +10,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.EnumServerRateLimit; import net.lax1dude.eaglercraft.v1_8.internal.IServerQuery; import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketClient; import net.lax1dude.eaglercraft.v1_8.internal.IWebSocketFrame; -import net.lax1dude.eaglercraft.v1_8.internal.PlatformRuntime; import net.lax1dude.eaglercraft.v1_8.internal.QueryResponse; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; import net.lax1dude.eaglercraft.v1_8.log4j.Logger; diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java index 56e5fd63..ccf4bf6f 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/socket/protocol/client/GameProtocolMessageController.java @@ -1,6 +1,7 @@ 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; @@ -149,10 +150,12 @@ public class GameProtocolMessageController { while(sendQueueV4.size() > 0) { sendCount = 0; totalLen = 0; + Iterator itr = sendQueueV4.iterator(); do { - i = sendQueueV4.get(sendCount++).readableBytes(); + i = itr.next().readableBytes(); totalLen += GamePacketOutputBuffer.getVarIntSize(i) + i; - }while(totalLen < 32760 && sendCount < sendQueueV4.size()); + ++sendCount; + }while(totalLen < 32760 && itr.hasNext()); if(totalLen >= 32760) { --sendCount; } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java index 96080f10..d56c248d 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/ipc/IPCPacketManager.java @@ -3,9 +3,11 @@ package net.lax1dude.eaglercraft.v1_8.sp.ipc; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.HashMap; import java.util.function.Supplier; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; + /** * Copyright (c) 2023-2024 lax1dude. All Rights Reserved. * @@ -23,7 +25,7 @@ import java.util.function.Supplier; */ public class IPCPacketManager { - public static final HashMap> mappings = new HashMap<>(); + public static final IntObjectMap> mappings = new IntObjectHashMap<>(); public final IPCInputStream IPC_INPUT_STREAM = new IPCInputStream(); public final IPCOutputStream IPC_OUTPUT_STREAM = new IPCOutputStream(); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java index 777f754a..8cb99607 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/lan/LANClientNetworkManager.java @@ -2,9 +2,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.lan; 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.EaglerZLIB; -import net.lax1dude.eaglercraft.v1_8.IOUtils; import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState; import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -21,7 +19,6 @@ import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.IChatComponent; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -308,13 +305,26 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager { } for(int k = 0, l = packets.size(); k < l; ++k) { byte[] data = packets.get(k); + + if(firstPacket) { + // 1.5 kick packet + if(data.length == 31 && data[0] == (byte)0xFF && data[1] == (byte)0x00 && data[2] == (byte)0x0E) { + logger.error("Detected a 1.5 LAN server!"); + this.closeChannel(new ChatComponentTranslation("singleplayer.outdatedLANServerKick")); + firstPacket = false; + return; + } + firstPacket = false; + } + byte[] fullData; boolean compressed = false; + int off = 0; if (data[0] == 0 || data[0] == 2) { if(fragmentedPacket.isEmpty()) { - fullData = new byte[data.length - 1]; - System.arraycopy(data, 1, fullData, 0, fullData.length); + fullData = data; + off = 1; }else { fragmentedPacket.add(data); int len = 0; @@ -341,34 +351,23 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager { } if(compressed) { - if(fullData.length < 4) { + if(fullData.length < 4 + off) { throw new IOException("Recieved invalid " + fullData.length + " byte compressed packet"); } - EaglerInputStream bi = new EaglerInputStream(fullData); - int i = (bi.read() << 24) | (bi.read() << 16) | (bi.read() << 8) | bi.read(); - fullData = new byte[i]; - int r; - try(InputStream inflaterInputStream = EaglerZLIB.newInflaterInputStream(bi)) { - r = IOUtils.readFully(inflaterInputStream, fullData); - } + int i = (((int) fullData[off] & 0xFF) << 24) | (((int) fullData[off + 1] & 0xFF) << 16) + | (((int) fullData[off + 2] & 0xFF) << 8) | ((int) fullData[off + 3] & 0xFF); + byte[] fullData2 = new byte[i]; + int r = EaglerZLIB.inflateFull(fullData, off + 4, fullData.length - off - 4, fullData2, 0, i); + fullData = fullData2; + off = 0; if (i != r) { logger.warn("Decompressed packet expected size {} differs from actual size {}!", i, r); } } - if(firstPacket) { - // 1.5 kick packet - if(fullData.length == 31 && fullData[0] == (byte)0xFF && fullData[1] == (byte)0x00 && fullData[2] == (byte)0x0E) { - logger.error("Detected a 1.5 LAN server!"); - this.closeChannel(new ChatComponentTranslation("singleplayer.outdatedLANServerKick")); - firstPacket = false; - return; - } - firstPacket = false; - } - ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length); nettyBuffer.writerIndex(fullData.length); + nettyBuffer.readerIndex(off); PacketBuffer input = new PacketBuffer(nettyBuffer); int pktId = input.readVarIntFromBuffer(); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/GenLayerEaglerRivers.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/GenLayerEaglerRivers.java new file mode 100755 index 00000000..81946edc --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/GenLayerEaglerRivers.java @@ -0,0 +1,107 @@ +package net.lax1dude.eaglercraft.v1_8.sp.server; + +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.gen.layer.GenLayer; +import net.minecraft.world.gen.layer.IntCache; + +/** + * 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. + * + */ +public class GenLayerEaglerRivers extends GenLayer { + + private static final int[] pattern = new int[] { + 0b111000011100001110000111, + 0b111000111110011111000111, + 0b011100011100001110001110, + 0b011100000000000000001110, + 0b001110000000000000011100, + 0b001110000000000000011100, + 0b000111000000000000111000, + 0b000111000000000000111000, + 0b000011100000000001110000, + 0b000011100000000001110000, + 0b000001110000000011100000, + 0b000001110000000011100000, + 0b000000111000000111000000, + 0b000000111000000111000000, + 0b000000011100001110000000, + 0b000000011100001110000000, + 0b000000001110011100000000, + 0b000000001110011100000000, + 0b000000000111111000000000, + 0b000000000111111000000000, + 0b000000000011110000000000, + 0b000000000011110000000000, + 0b000000000001100000000000, + 0b000000000001100000000000, + }; + + private static final int patternSize = 24; + + public GenLayerEaglerRivers(long parLong1, GenLayer p) { + super(parLong1); + this.parent = p; + } + + @Override + public int[] getInts(int x, int y, int w, int h) { + int[] aint = this.parent.getInts(x, y, w, h); + int[] aint1 = IntCache.getIntCache(w * h); + + long a = worldGenSeed * 6364136223846793005L + 1442695040888963407L; + long b = ((a & 112104l) == 0) ? (((a & 534l) == 0) ? 1l : 15l) : 746l; + for (int yy = 0; yy < h; ++yy) { + for (int xx = 0; xx < w; ++xx) { + int i = xx + yy * w; + aint1[i] = aint[i]; + long xxx = (long)(x + xx) & 0xFFFFFFFFl; + long yyy = (long)(y + yy) & 0xFFFFFFFFl; + long hash = a + (xxx / patternSize); + hash *= hash * 6364136223846793005L + 1442695040888963407L; + hash += (yyy / patternSize); + hash *= hash * 6364136223846793005L + 1442695040888963407L; + hash += a; + if ((hash & b) == 0l) { + xxx %= (long)patternSize; + yyy %= (long)patternSize; + long tmp; + switch((int)((hash >>> 16l) & 3l)) { + case 1: + tmp = xxx; + xxx = yyy; + yyy = (long)patternSize - tmp - 1l; + break; + case 2: + tmp = xxx; + xxx = (long)patternSize - yyy - 1l; + yyy = tmp; + break; + case 3: + tmp = xxx; + xxx = (long)patternSize - yyy - 1l; + yyy = (long)patternSize - tmp - 1l; + break; + } + if((pattern[(int)yyy] & (1 << (int)xxx)) != 0) { + aint1[i] = BiomeGenBase.river.biomeID; + } + } + } + } + + return aint1; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java index eee0b86a..56e58f7f 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/server/socket/IntegratedServerPlayerNetworkManager.java @@ -2,8 +2,8 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.socket; import java.io.DataOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import net.lax1dude.eaglercraft.v1_8.EaglerOutputStream; @@ -48,10 +48,9 @@ public class IntegratedServerPlayerNetworkManager { public final String playerChannel; private EnumConnectionState packetState = EnumConnectionState.HANDSHAKING; private static PacketBuffer temporaryBuffer; - private static EaglerOutputStream temporaryOutputStream; + private static byte[] compressedPacketTmp; private int debugPacketCounter = 0; - private byte[][] recievedPacketBuffer = new byte[16384][]; - private int recievedPacketBufferCounter = 0; + private final List recievedPacketBuffer = new LinkedList<>(); private final boolean enableSendCompression; private boolean firstPacket = true; @@ -69,11 +68,6 @@ public class IntegratedServerPlayerNetworkManager { } this.playerChannel = playerChannel; this.enableSendCompression = !SingleplayerServerController.PLAYER_CHANNEL.equals(playerChannel); - if(this.enableSendCompression) { - if(temporaryOutputStream == null) { - temporaryOutputStream = new EaglerOutputStream(16386); - } - } } public void connect() { @@ -97,19 +91,14 @@ public class IntegratedServerPlayerNetworkManager { } public void addRecievedPacket(byte[] next) { - if(recievedPacketBufferCounter < recievedPacketBuffer.length - 1) { - recievedPacketBuffer[recievedPacketBufferCounter++] = next; - }else { - logger.error("Dropping packets on recievedPacketBuffer for channel \"{}\"! (overflow)", playerChannel); - } + recievedPacketBuffer.add(next); } public void processReceivedPackets() { if(nethandler == null) return; - - for(int i = 0; i < recievedPacketBufferCounter; ++i) { - byte[] data = recievedPacketBuffer[i]; + while(!recievedPacketBuffer.isEmpty()) { + byte[] data = recievedPacketBuffer.remove(0); byte[] fullData; if(enableSendCompression) { @@ -132,7 +121,6 @@ public class IntegratedServerPlayerNetworkManager { ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, kickPacketBAO.toByteArray())); closeChannel(new ChatComponentText("Recieved unsuppoorted connection from an Eaglercraft 1.5.2 client!")); firstPacket = false; - recievedPacketBufferCounter = 0; return; } firstPacket = false; @@ -169,7 +157,6 @@ public class IntegratedServerPlayerNetworkManager { fullData = data; } - recievedPacketBuffer[i] = null; ++debugPacketCounter; try { ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length); @@ -206,7 +193,6 @@ public class IntegratedServerPlayerNetworkManager { logger.error(t); } } - recievedPacketBufferCounter = 0; } public void sendPacket(Packet pkt) { @@ -234,22 +220,24 @@ public class IntegratedServerPlayerNetworkManager { int len = temporaryBuffer.readableBytes(); if(enableSendCompression) { if(len > compressionThreshold) { - temporaryOutputStream.reset(); - byte[] compressedData; + if(compressedPacketTmp == null || compressedPacketTmp.length < len) { + compressedPacketTmp = new byte[len]; + } + int cmpLen; try { - temporaryOutputStream.write(2); - temporaryOutputStream.write((len >>> 24) & 0xFF); - temporaryOutputStream.write((len >>> 16) & 0xFF); - temporaryOutputStream.write((len >>> 8) & 0xFF); - temporaryOutputStream.write(len & 0xFF); - try(OutputStream os = EaglerZLIB.newDeflaterOutputStream(temporaryOutputStream)) { - temporaryBuffer.readBytes(os, len); - } - compressedData = temporaryOutputStream.toByteArray(); + cmpLen = EaglerZLIB.deflateFull(temporaryBuffer.array(), 0, len, compressedPacketTmp, 0, compressedPacketTmp.length); }catch(IOException ex) { logger.error("Failed to compress packet {}!", pkt.getClass().getSimpleName()); + 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) { diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java index b5373d39..c9267607 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/socket/ClientIntegratedServerNetworkManager.java @@ -1,6 +1,8 @@ package net.lax1dude.eaglercraft.v1_8.sp.socket; import java.io.IOException; +import java.util.LinkedList; +import java.util.List; import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState; import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData; @@ -34,8 +36,7 @@ import net.minecraft.util.IChatComponent; public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkManager { private int debugPacketCounter = 0; - private byte[][] recievedPacketBuffer = new byte[16384][]; - private int recievedPacketBufferCounter = 0; + private final List recievedPacketBuffer = new LinkedList<>(); public boolean isPlayerChannelOpen = false; public ClientIntegratedServerNetworkManager(String channel) { @@ -65,20 +66,15 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana } public void addRecievedPacket(byte[] next) { - if(recievedPacketBufferCounter < recievedPacketBuffer.length - 1) { - recievedPacketBuffer[recievedPacketBufferCounter++] = next; - }else { - logger.error("Dropping packets on recievedPacketBuffer for channel \"{}\"! (overflow)", address); - } + recievedPacketBuffer.add(next); } @Override public void processReceivedPackets() throws IOException { if(nethandler == null) return; - for(int i = 0; i < recievedPacketBufferCounter; ++i) { - byte[] next = recievedPacketBuffer[i]; - recievedPacketBuffer[i] = null; + while(!recievedPacketBuffer.isEmpty()) { + byte[] next = recievedPacketBuffer.remove(0); ++debugPacketCounter; try { ByteBuf nettyBuffer = Unpooled.buffer(next, next.length); @@ -115,7 +111,6 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana logger.error(t); } } - recievedPacketBufferCounter = 0; } @Override @@ -170,9 +165,6 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana } public void clearRecieveQueue() { - for(int i = 0; i < recievedPacketBufferCounter; ++i) { - recievedPacketBuffer[i] = null; - } - recievedPacketBufferCounter = 0; + recievedPacketBuffer.clear(); } } diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java index 94bbaa58..587f8eb1 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchControls.java @@ -7,6 +7,10 @@ import net.minecraft.client.gui.ScaledResolution; import java.util.*; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.carrotsearch.hppc.cursors.ObjectCursor; + /** * Copyright (c) 2024 lax1dude, ayunami2000. All Rights Reserved. * @@ -24,7 +28,7 @@ import java.util.*; */ public class TouchControls { - public static final Map touchControls = new HashMap<>(); + public static final IntObjectMap touchControls = new IntObjectHashMap<>(); protected static Set touchControlPressed = EnumSet.noneOf(EnumTouchControl.class); protected static boolean isSneakToggled = false; @@ -112,7 +116,8 @@ public class TouchControls { if(!touchControls.isEmpty()) { Set newPressed = EnumSet.noneOf(EnumTouchControl.class); TouchOverlayRenderer renderer = Minecraft.getMinecraft().touchOverlayRenderer; - for (TouchControlInput input : touchControls.values()) { + for (ObjectCursor input_ : touchControls.values()) { + TouchControlInput input = input_.value; TouchAction action = input.control.getAction(); if(action != null) { action.call(input.control, input.x, input.y); diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java index 663196c7..edb12677 100755 --- a/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/touch_gui/TouchOverlayRenderer.java @@ -17,6 +17,7 @@ import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*; import java.util.Set; +import com.carrotsearch.hppc.cursors.ObjectCursor; import com.google.common.collect.Sets; /** @@ -103,8 +104,8 @@ public class TouchOverlayRenderer { GlStateManager.clear(GL_COLOR_BUFFER_BIT); } Set controls = Sets.newHashSet(EnumTouchControl._VALUES); - for (TouchControlInput input : TouchControls.touchControls.values()) { - controls.remove(input.control); + for (ObjectCursor input : TouchControls.touchControls.values()) { + controls.remove(input.value.control); } for (EnumTouchControl control : controls) { if(invalidDeep || control.invalid) { @@ -115,7 +116,8 @@ public class TouchOverlayRenderer { control.invalid = false; } } - for (TouchControlInput input : TouchControls.touchControls.values()) { + for (ObjectCursor input_ : TouchControls.touchControls.values()) { + TouchControlInput input = input_.value; EnumTouchControl control = input.control; if(invalidDeep || control.invalid) { if(control.visible) { diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java index 628ee0ba..9b0f996c 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java @@ -42,9 +42,11 @@ import org.teavm.platform.PlatformRunnable; import com.google.common.collect.Collections2; import com.google.common.collect.Iterators; import com.google.common.collect.Sets; +import com.jcraft.jzlib.Deflater; import com.jcraft.jzlib.DeflaterOutputStream; import com.jcraft.jzlib.GZIPInputStream; import com.jcraft.jzlib.GZIPOutputStream; +import com.jcraft.jzlib.Inflater; import com.jcraft.jzlib.InflaterInputStream; import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer; @@ -539,11 +541,21 @@ public class PlatformRuntime { } public static String getGLVersion() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static String getGLRenderer() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static ByteBuffer allocateByteBuffer(int length) { @@ -1070,6 +1082,23 @@ public class PlatformRuntime { return new DeflaterOutputStream(os); } + @SuppressWarnings("deprecation") + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Deflater df = new Deflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + df.init(5); + int c; + do { + c = df.deflate(4); + if(c != 0 && c != 1) { + throw new IOException("Deflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return new GZIPOutputStream(os); } @@ -1078,6 +1107,22 @@ public class PlatformRuntime { return new InflaterInputStream(is); } + @SuppressWarnings("deprecation") + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Inflater df = new Inflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + int c; + do { + c = df.inflate(0); + if(c != 0 && c != 1) { + throw new IOException("Inflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return new GZIPInputStream(is); } diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java index c3d37a0d..6aa6e497 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayByteBuffer.java @@ -9,7 +9,7 @@ import org.teavm.jso.typedarrays.Int8Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 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 @@ -23,7 +23,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayByteBuffer implements ByteBuffer { +public class EaglerArrayByteBuffer extends ByteBuffer { final DataView dataView; final Int8Array typedArray; diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java index b94ee42f..68ce9211 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayFloatBuffer.java @@ -5,7 +5,7 @@ import org.teavm.jso.typedarrays.Float32Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 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 @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayFloatBuffer implements FloatBuffer { +public class EaglerArrayFloatBuffer extends FloatBuffer { final Float32Array typedArray; diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java index 85cb3f44..5a4f2019 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayIntBuffer.java @@ -5,7 +5,7 @@ import org.teavm.jso.typedarrays.Int32Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 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 @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayIntBuffer implements IntBuffer { +public class EaglerArrayIntBuffer extends IntBuffer { final Int32Array typedArray; diff --git a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java index d83b9a7c..e7e4e12e 100755 --- a/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/EaglerArrayShortBuffer.java @@ -5,7 +5,7 @@ import org.teavm.jso.typedarrays.Int16Array; import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; /** - * Copyright (c) 2022-2023 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 @@ -19,7 +19,7 @@ import net.lax1dude.eaglercraft.v1_8.internal.teavm.TeaVMUtils; * POSSIBILITY OF SUCH DAMAGE. * */ -public class EaglerArrayShortBuffer implements ShortBuffer { +public class EaglerArrayShortBuffer extends ShortBuffer { final Int16Array typedArray; diff --git a/src/wasm-gc-teavm-bootstrap/js/main.js b/src/wasm-gc-teavm-bootstrap/js/main.js index fd577594..8aaccc34 100755 --- a/src/wasm-gc-teavm-bootstrap/js/main.js +++ b/src/wasm-gc-teavm-bootstrap/js/main.js @@ -133,6 +133,24 @@ function asyncSleep(ms) { }); } +/** + * @param {string} url + * @param {number} ms + * @return {!Promise} + */ +function preloadImage(url, ms) { + return new Promise(function(resolve) { + const imgObj = new Image(); + imgObj.addEventListener("load", resolve); + imgObj.addEventListener("error", function() { + logWarn("Failed to preload image: " + url); + resolve(); + }); + imgObj.src = url; + setTimeout(resolve, ms); + }); +} + /** * @param {string} url * @return {!Promise} @@ -248,6 +266,9 @@ window.main = async function() { splashElement.style.background = "center / contain no-repeat url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAAAAAB3tzPbAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG+UlEQVR42u2cy23jOhRATwbTwGwFvAJoF6BFGjColcGkASNuIPA6C68DN+BADZiCVxLSQBYqIGYBAbSdEvwWkvUzZWfymwlwCQwQUZeXPOT9URPkYs/3bj8QAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAH4x9vPvzFpAhAzM98UILmqfjDf1YT0N/cBk+71v+wDSczHmDeJ6TqO+SIfyD7IvC9g33Yc7dP6CQDxB+q62Hc2xnyJD2Sf5vuzL3Hi5MM0WbCN51u/Y/30ryEGmDVHlhwsY9Y7xlq0CuzVc4lh2n7NkGsnQ1nB7IefmrY/araJcbrq6Ryk9YqW4l3J/dHww1jdej+8kte042EW0Nba1hyWdl+9irq/FNXaD6BbQoexuvf+tQC2vX1+AFvP0kxiuyidfWwEbOtQtK0n0r6xbYCKsLcM21+pLZX3u4984Kq2xlnWDimllRudAXEpkGSHfqMzsmxfWnLWNf9aQznW4wMZWOMJxvGs/Ff5X+yPcD0g3dqZesdsI2f7Z2/73W2JSok9Gqu7P1q/I2qtj0qn/ZkTaCPWO2a0VyjrxY7sNUG1LxRlaE90MpDpGVeAxpaGobN2XPWH0aQVE1stfXPAj0+XzUmcob3aTRdVZ2+tRv+gMNBDaTkZ4k6uhtYPaK7iUkUcx9lgij92gZ6aXmxoDeK8D1hPfm18oBvTfPGwXoVG+4VfXcwl8dEOtCJS7De9M0VTqTA2p081O3kJ+uk5cU/RVN8C262Ms9HMlLHSmhNFTcc9u1uQRX4jMhqyNIk1GRk69a6hb0IDZ3pITnbfNqFuJWE9gbYrfmSqen/SiKy27G0VS20VWc+UEn59/YDPkc+0EunrAXQ/JXucYL+3VutyAqvP5wFvtEoyQPsMJMpKc3v7/Su9ALLkhAJDPCObGTDmonfNHAij3sg5866fmTHGnFt/crroh6vEv/Rq6vhEoP7hWWb2ylSQZP5zOVrDqVxSZnm/xL6OFnZwF3/4JoyGjyXu1X3n0rEFyE5Jzc5KEDfT7s2ZYs52s5e1HU88hB17nKTqAroXWPpXiHbN7R3Q8fVDbjzU6vb8hUbX67FWN8Xo4U5SIWjbukr1knY9XrcwS30aOuTatqa0vkA6cI05dyPrzWBbj7ZZrPUT2O7pdpKFtp4rph0E0AxtfN0u9kNVg25d4BPiDF0+R83dPol7/l4m4yQmQzdX+ISewqTnc8ngp94yaCan4vT+Hc228q8/T35+e8+XueSqCaPmEz9ofdbX6eSqE5iN/m4A8Qd9w/1bAEl2fPmafT3Axdv/ytlFeXUwTZyyf+NA3hWDGPrm+HXtHSdQ7nrz7fvv+MPFe/9Q3nAS+iYA3zcKCYAACIAACIAACIAACIAACIAACIAA1C2Komh++r9cogdv90M0+GoZAVHkSiGSaFmOmJdTRdESiKJ5Je4eovnSldoGNJ44gTBNbx+XH7tDYxwOniAPgEdygGWxTm/jBCAHV0u7xa90PV64IW0uOWdCapK7t600vfF2j4Ad5FCE4IopCSWMSg0Q4NgRVNKrwIBJ1ZDGxXO/5+fxhDvFQ87EsHxZMy9Sli/raMbjf9eqMpiciQG3yYOJwW1eQoBoesNBzG3yKdvqNwie1HMwiXFcwo7L7aMBtlSrC7c79RzyUm5w0f66Gk1vcJs8vFYHxUvy/u8leJz4N8t8vX5ccl04Chz5BOLR+mVVWXX5lsU4ncSOFevL7WFsJbYiPfQpcvJwhNsBxKiwcHDPNnoojzp8Jh8PnusiSMcLd1B8R5i+Igq5/BZKU3IEO8cIpoqw6L5NR8kjuOIaFR6GlmKdvmnhuFTsfqNwTBnzBOo+ZFua+jh3jAZtnksMu/b850wIfh1sVwVPhMEzKK9lz/+7Hi3Kx8CjOajVbVCEz3kIT1wyYnsD6s5t8tUaGLFpTfC7q2TH4rjzHMCoGgqTOJiMFi/TY5kduOJWHfzdtzdFrS4PYBwzhi0LAKcAdTcvKhur+VWQ3/TWcq/+LJG5VahUsILHUDGiGCmKy26cOrxlxwZUsMHlvVDW7lMQwghGOGZpmt6zcdFD47EhtQVyWySQRHUgVDzhmkeClyZFlGmiA5BH0WpyB+twPp/cgQpQBH0Lqt6qaTwfs+OW6Kl/RrdET/WqQi5BgWLDqNxmdV/Mo1X1QX5Ms0Pq/jmaP7d2/b6IVq3HW+a9qT7v6/TDNv2+tVA0hzz8klroc07AbXKmN98YQMppARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAD2//A2iD9ZsgY5XpAAAAAElFTkSuQmCC\") white"; rootElement.appendChild(splashElement); + // allow the screen to update + await asyncSleep(20); + /** @type {ArrayBuffer} */ var theEPWFileBuffer; if(assetsURI.startsWith("data:")) { @@ -319,6 +340,9 @@ window.main = async function() { const splashBinSlice = new Uint8Array(theEPWFileBuffer, splashDataOffset, splashDataLength); const splashMIMESlice = new Uint8Array(theEPWFileBuffer, splashMIMEOffset, splashMIMELength); const splashURL = URL.createObjectURL(new Blob([ splashBinSlice ], { "type": textDecoder.decode(splashMIMESlice) })); + + await preloadImage(splashURL, 50); + logInfo("Loaded splash img: " + splashURL); splashElement.style.background = "center / contain no-repeat url(\"" + splashURL + "\"), 0px 0px / 1000000% 1000000% no-repeat url(\"" + splashURL + "\") white"; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java index e036354b..d1387c3e 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformNetworking.java @@ -1,21 +1,7 @@ package net.lax1dude.eaglercraft.v1_8.internal; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - import org.teavm.interop.Import; -import org.teavm.jso.JSObject; -import org.teavm.jso.JSProperty; import org.teavm.jso.core.JSString; -import org.teavm.jso.typedarrays.ArrayBuffer; -import org.teavm.jso.typedarrays.Uint8Array; - -import net.lax1dude.eaglercraft.v1_8.EagUtils; -import net.lax1dude.eaglercraft.v1_8.EaglerInputStream; -import net.lax1dude.eaglercraft.v1_8.internal.buffer.ByteBuffer; -import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator; -import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCWebSocketClient; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java index 0afae531..53a750be 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformRuntime.java @@ -3,8 +3,6 @@ package net.lax1dude.eaglercraft.v1_8.internal; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; import java.util.function.Consumer; import org.teavm.interop.Import; @@ -19,9 +17,13 @@ import org.teavm.jso.dom.html.HTMLElement; import org.teavm.jso.typedarrays.ArrayBuffer; import org.teavm.jso.typedarrays.Uint8Array; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; +import com.jcraft.jzlib.Deflater; import com.jcraft.jzlib.DeflaterOutputStream; import com.jcraft.jzlib.GZIPInputStream; import com.jcraft.jzlib.GZIPOutputStream; +import com.jcraft.jzlib.Inflater; import com.jcraft.jzlib.InflaterInputStream; import net.lax1dude.eaglercraft.v1_8.Filesystem; @@ -163,11 +165,21 @@ public class PlatformRuntime { } public static String getGLVersion() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_VERSION); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static String getGLRenderer() { - return PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + String ret = PlatformOpenGL._wglGetString(RealOpenGLEnums.GL_RENDERER); + if(ret != null) { + return ret; + }else { + return "null"; + } } public static ByteBuffer allocateByteBuffer(int length) { @@ -311,7 +323,7 @@ public class PlatformRuntime { @Import(module = "platformRuntime", name = "getNextEvent") private static native JSEagRuntimeEvent getNextEvent(); - private static final Map> waitingAsyncDownloads = new HashMap<>(); + private static final IntObjectMap> waitingAsyncDownloads = new IntObjectHashMap<>(); private static int asyncDownloadID = 0; private static void queueAsyncDownload(String uri, boolean forceCache, Consumer cb) { @@ -479,6 +491,23 @@ public class PlatformRuntime { return new DeflaterOutputStream(os); } + @SuppressWarnings("deprecation") + public static int deflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Deflater df = new Deflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + df.init(5); + int c; + do { + c = df.deflate(4); + if(c != 0 && c != 1) { + throw new IOException("Deflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static OutputStream newGZIPOutputStream(OutputStream os) throws IOException { return new GZIPOutputStream(os); } @@ -487,6 +516,22 @@ public class PlatformRuntime { return new InflaterInputStream(is); } + @SuppressWarnings("deprecation") + public static int inflateFull(byte[] input, int inputOff, int inputLen, byte[] output, int outputOff, + int outputLen) throws IOException { + Inflater df = new Inflater(); + df.setInput(input, inputOff, inputLen, false); + df.setOutput(output, outputOff, outputLen); + int c; + do { + c = df.inflate(0); + if(c != 0 && c != 1) { + throw new IOException("Inflater failed! Code " + c); + } + }while(c != 1); + return (int)df.getTotalOut(); + } + public static InputStream newGZIPInputStream(InputStream is) throws IOException { return new GZIPInputStream(is); } diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java index ec775acc..10454ef9 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/PlatformVoiceClient.java @@ -20,6 +20,9 @@ import org.teavm.jso.webaudio.MediaStreamAudioDestinationNode; import org.teavm.jso.webaudio.MediaStreamAudioSourceNode; import org.teavm.jso.webaudio.PannerNode; +import com.carrotsearch.hppc.IntObjectHashMap; +import com.carrotsearch.hppc.IntObjectMap; + import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; import net.lax1dude.eaglercraft.v1_8.log4j.LogManager; @@ -133,7 +136,7 @@ public class PlatformVoiceClient { } static final Map peerList = new HashMap<>(); - static final Map peerListI = new HashMap<>(); + static final IntObjectMap peerListI = new IntObjectHashMap<>(); private static class VoicePeer { diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java index 6726f237..6cc0d7d1 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocByteBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * 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 @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocByteBuffer implements ByteBuffer { +public class DirectMallocByteBuffer extends ByteBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java index 6b1ebbd5..831bf045 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocFloatBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * 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 @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocFloatBuffer implements FloatBuffer { +public class DirectMallocFloatBuffer extends FloatBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java index 5cb69fd9..f333ddc5 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocIntBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * 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 @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocIntBuffer implements IntBuffer { +public class DirectMallocIntBuffer extends IntBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java index 78863a1a..39e892cd 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/DirectMallocShortBuffer.java @@ -4,7 +4,7 @@ import org.teavm.interop.Address; import org.teavm.interop.DirectMalloc; /** - * 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 @@ -18,7 +18,7 @@ import org.teavm.interop.DirectMalloc; * POSSIBILITY OF SUCH DAMAGE. * */ -public class DirectMallocShortBuffer implements ShortBuffer { +public class DirectMallocShortBuffer extends ShortBuffer { final Address address; final boolean original; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java index 7ebe8d6d..b3b97bd8 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/buffer/WASMGCBufferAllocator.java @@ -202,7 +202,7 @@ public class WASMGCBufferAllocator { } public static Uint8Array getUnsignedByteBufferView(ShortBuffer buffer) { - DirectMallocIntBuffer buf = (DirectMallocIntBuffer)buffer; + DirectMallocShortBuffer buf = (DirectMallocShortBuffer)buffer; return getUnsignedByteBufferView0(buf.address.add(buf.position()), buf.remaining() << 1); } diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java index 33a435a4..9027f51d 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/BetterJSStringConverter.java @@ -1,13 +1,11 @@ package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm; import org.teavm.interop.Address; -import org.teavm.interop.DirectMalloc; import org.teavm.interop.Import; import org.teavm.interop.Unmanaged; import org.teavm.jso.core.JSArray; import org.teavm.jso.core.JSString; -import net.lax1dude.eaglercraft.v1_8.EagUtils; import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCBufferAllocator; /** diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java index befab836..bee3bbf3 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/TeaVMUtils.java @@ -2,13 +2,6 @@ package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm; import org.teavm.jso.JSBody; import org.teavm.jso.JSObject; -import org.teavm.jso.typedarrays.ArrayBuffer; -import org.teavm.jso.typedarrays.ArrayBufferView; -import org.teavm.jso.typedarrays.Float32Array; -import org.teavm.jso.typedarrays.Int16Array; -import org.teavm.jso.typedarrays.Int32Array; -import org.teavm.jso.typedarrays.Int8Array; -import org.teavm.jso.typedarrays.Uint8Array; /** * Copyright (c) 2024 lax1dude. All Rights Reserved. diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java index 001cb805..3f9716f1 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/internal/wasm_gc_teavm/WASMGCWebSocketClient.java @@ -1,6 +1,5 @@ package net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java index 2cd9699a..628a464c 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/ServerPlatformSingleplayer.java @@ -23,7 +23,6 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.WASMGCClientConfigAdapter; -import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker; import net.lax1dude.eaglercraft.v1_8.sp.server.IWASMCrashCallback; import net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm.JS_IPCPacketData; diff --git a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java index 751f2aa8..a9fb29c4 100755 --- a/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java +++ b/src/wasm-gc-teavm/java/net/lax1dude/eaglercraft/v1_8/sp/server/internal/wasm_gc_teavm/JS_IPCPacketData.java @@ -2,10 +2,12 @@ package net.lax1dude.eaglercraft.v1_8.sp.server.internal.wasm_gc_teavm; import org.teavm.jso.JSObject; import org.teavm.jso.JSProperty; +import org.teavm.jso.core.JSString; import org.teavm.jso.typedarrays.Uint8Array; import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData; import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; +import net.lax1dude.eaglercraft.v1_8.internal.wasm_gc_teavm.BetterJSStringConverter; /** * Copyright (c) 2024 lax1dude. All Rights Reserved. @@ -25,13 +27,14 @@ import net.lax1dude.eaglercraft.v1_8.internal.buffer.WASMGCDirectArrayConverter; public interface JS_IPCPacketData extends JSObject { @JSProperty - String getCh(); + JSString getCh(); @JSProperty Uint8Array getData(); default IPCPacketData internalize() { - return new IPCPacketData(getCh(), WASMGCDirectArrayConverter.externU8ArrayToByteArray(getData())); + return new IPCPacketData(BetterJSStringConverter.stringFromJS(getCh()), + WASMGCDirectArrayConverter.externU8ArrayToByteArray(getData())); } } diff --git a/wasm_gc_teavm/javascript/epw_meta.txt b/wasm_gc_teavm/javascript/epw_meta.txt index 9af6abcc..5a50c686 100755 --- a/wasm_gc_teavm/javascript/epw_meta.txt +++ b/wasm_gc_teavm/javascript/epw_meta.txt @@ -1,8 +1,8 @@ -client-version-integer=46 +client-version-integer=47 client-package-name=net.lax1dude.eaglercraft.v1_8.client client-origin-name=EaglercraftX -client-origin-version=u46 +client-origin-version=u47 client-origin-vendor=lax1dude client-fork-name=EaglercraftX -client-fork-version=u46 +client-fork-version=u47 client-fork-vendor=lax1dude diff --git a/wasm_gc_teavm/javascript_dist/bootstrap.js b/wasm_gc_teavm/javascript_dist/bootstrap.js index 1062d55e..1c94eac3 100755 --- a/wasm_gc_teavm/javascript_dist/bootstrap.js +++ b/wasm_gc_teavm/javascript_dist/bootstrap.js @@ -1,12 +1,13 @@ -(function(){'use strict';function g(a){console.log("LoaderBootstrap: [INFO] "+a)}function n(a){console.error("LoaderBootstrap: [ERROR] "+a)}var q=null; -function r(){const a=[];for(var c=0;64>c;++c)a["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c)]=c;a[45]=62;a[95]=63;return function(b,d){var e=b.length-d;if(0>16&255,f[h++]=d>>8&255,f[h++]=d&255;2===e?(d=a[b.charCodeAt(k)]<<2|a[b.charCodeAt(k+1)]>>4,f[h++]=d&255):1===e&&(d=a[b.charCodeAt(k)]<<10|a[b.charCodeAt(k+1)]<<4|a[b.charCodeAt(k+2)]>>2,f[h++]=d>>8&255,f[h++]=d&255);return f.buffer}}function u(){return new Promise(function(a){setTimeout(a,20)})}function v(a){return new Promise(function(c){fetch(a,{cache:"force-cache"}).then(function(b){return b.arrayBuffer()}).then(c).catch(function(b){n("Failed to fetch URL! "+b);c(null)})})} -function w(a){return a.startsWith("data:application/octet-stream;base64,")?new Promise(function(c){v(a).then(function(b){if(b)c(b);else{console.log("LoaderBootstrap: [WARN] Failed to decode base64 via fetch, doing it the slow way instead...");try{q||=r();var d=q(a,37);c(d)}catch(e){n("Failed to decode base64! "+e),c(null)}}})}):v(a)} -function x(a,c){const b=document.createElement("h2");b.style.color="#AA0000";b.style.padding="25px";b.style.fontFamily="sans-serif";b.style.marginBlock="0px";b.appendChild(document.createTextNode(c));a.appendChild(b);c=document.createElement("h4");c.style.color="#AA0000";c.style.padding="25px";c.style.fontFamily="sans-serif";c.style.marginBlock="0px";c.appendChild(document.createTextNode("Try again later"));a.style.backgroundColor="white";a.appendChild(c)} -window.main=async function(){if("undefined"===typeof window.eaglercraftXOpts)n("window.eaglercraftXOpts is not defined!"),alert("window.eaglercraftXOpts is not defined!");else{var a=window.eaglercraftXOpts.container;if("string"!==typeof a)n("window.eaglercraftXOpts.container is not a string!"),alert("window.eaglercraftXOpts.container is not a string!");else{var c=window.eaglercraftXOpts.assetsURI;if("string"!==typeof c)if("object"===typeof c&&"object"===typeof c[0]&&"string"===typeof c[0].url)c=c[0].url; -else{n("window.eaglercraftXOpts.assetsURI is not a string!");alert("window.eaglercraftXOpts.assetsURI is not a string!");return}var b=document.getElementById(a);if(b){for(;a=b.lastChild;)b.removeChild(a);a=document.createElement("div");a.style.width="100%";a.style.height="100%";a.style.setProperty("image-rendering","pixelated");a.style.background='center / contain no-repeat url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAAAAAB3tzPbAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG+UlEQVR42u2cy23jOhRATwbTwGwFvAJoF6BFGjColcGkASNuIPA6C68DN+BADZiCVxLSQBYqIGYBAbSdEvwWkvUzZWfymwlwCQwQUZeXPOT9URPkYs/3bj8QAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAH4x9vPvzFpAhAzM98UILmqfjDf1YT0N/cBk+71v+wDSczHmDeJ6TqO+SIfyD7IvC9g33Yc7dP6CQDxB+q62Hc2xnyJD2Sf5vuzL3Hi5MM0WbCN51u/Y/30ryEGmDVHlhwsY9Y7xlq0CuzVc4lh2n7NkGsnQ1nB7IefmrY/araJcbrq6Ryk9YqW4l3J/dHww1jdej+8kte042EW0Nba1hyWdl+9irq/FNXaD6BbQoexuvf+tQC2vX1+AFvP0kxiuyidfWwEbOtQtK0n0r6xbYCKsLcM21+pLZX3u4984Kq2xlnWDimllRudAXEpkGSHfqMzsmxfWnLWNf9aQznW4wMZWOMJxvGs/Ff5X+yPcD0g3dqZesdsI2f7Z2/73W2JSok9Gqu7P1q/I2qtj0qn/ZkTaCPWO2a0VyjrxY7sNUG1LxRlaE90MpDpGVeAxpaGobN2XPWH0aQVE1stfXPAj0+XzUmcob3aTRdVZ2+tRv+gMNBDaTkZ4k6uhtYPaK7iUkUcx9lgij92gZ6aXmxoDeK8D1hPfm18oBvTfPGwXoVG+4VfXcwl8dEOtCJS7De9M0VTqTA2p081O3kJ+uk5cU/RVN8C262Ms9HMlLHSmhNFTcc9u1uQRX4jMhqyNIk1GRk69a6hb0IDZ3pITnbfNqFuJWE9gbYrfmSqen/SiKy27G0VS20VWc+UEn59/YDPkc+0EunrAXQ/JXucYL+3VutyAqvP5wFvtEoyQPsMJMpKc3v7/Su9ALLkhAJDPCObGTDmonfNHAij3sg5866fmTHGnFt/crroh6vEv/Rq6vhEoP7hWWb2ylSQZP5zOVrDqVxSZnm/xL6OFnZwF3/4JoyGjyXu1X3n0rEFyE5Jzc5KEDfT7s2ZYs52s5e1HU88hB17nKTqAroXWPpXiHbN7R3Q8fVDbjzU6vb8hUbX67FWN8Xo4U5SIWjbukr1knY9XrcwS30aOuTatqa0vkA6cI05dyPrzWBbj7ZZrPUT2O7pdpKFtp4rph0E0AxtfN0u9kNVg25d4BPiDF0+R83dPol7/l4m4yQmQzdX+ISewqTnc8ngp94yaCan4vT+Hc228q8/T35+e8+XueSqCaPmEz9ofdbX6eSqE5iN/m4A8Qd9w/1bAEl2fPmafT3Axdv/ytlFeXUwTZyyf+NA3hWDGPrm+HXtHSdQ7nrz7fvv+MPFe/9Q3nAS+iYA3zcKCYAACIAACIAACIAACIAACIAACIAA1C2Komh++r9cogdv90M0+GoZAVHkSiGSaFmOmJdTRdESiKJ5Je4eovnSldoGNJ44gTBNbx+XH7tDYxwOniAPgEdygGWxTm/jBCAHV0u7xa90PV64IW0uOWdCapK7t600vfF2j4Ad5FCE4IopCSWMSg0Q4NgRVNKrwIBJ1ZDGxXO/5+fxhDvFQ87EsHxZMy9Sli/raMbjf9eqMpiciQG3yYOJwW1eQoBoesNBzG3yKdvqNwie1HMwiXFcwo7L7aMBtlSrC7c79RzyUm5w0f66Gk1vcJs8vFYHxUvy/u8leJz4N8t8vX5ccl04Chz5BOLR+mVVWXX5lsU4ncSOFevL7WFsJbYiPfQpcvJwhNsBxKiwcHDPNnoojzp8Jh8PnusiSMcLd1B8R5i+Igq5/BZKU3IEO8cIpoqw6L5NR8kjuOIaFR6GlmKdvmnhuFTsfqNwTBnzBOo+ZFua+jh3jAZtnksMu/b850wIfh1sVwVPhMEzKK9lz/+7Hi3Kx8CjOajVbVCEz3kIT1wyYnsD6s5t8tUaGLFpTfC7q2TH4rjzHMCoGgqTOJiMFi/TY5kduOJWHfzdtzdFrS4PYBwzhi0LAKcAdTcvKhur+VWQ3/TWcq/+LJG5VahUsILHUDGiGCmKy26cOrxlxwZUsMHlvVDW7lMQwghGOGZpmt6zcdFD47EhtQVyWySQRHUgVDzhmkeClyZFlGmiA5BH0WpyB+twPp/cgQpQBH0Lqt6qaTwfs+OW6Kl/RrdET/WqQi5BgWLDqNxmdV/Mo1X1QX5Ms0Pq/jmaP7d2/b6IVq3HW+a9qT7v6/TDNv2+tVA0hzz8klroc07AbXKmN98YQMppARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAD2//A2iD9ZsgY5XpAAAAAElFTkSuQmCC") white'; -b.appendChild(a);c.startsWith("data:")?(g('Downloading EPW file ""...'),c=await w(c)):(g('Downloading EPW file "'+c+'"...'),c=await v(c));var d=!1;c?384>c.byteLength&&(n("The EPW file is too short"),d=!0):d=!0;if(d)b.removeChild(a),x(b,"Failed to download EPW file!"),n("Failed to download EPW file!");else{var e=new DataView(c);if(608649541!==e.getUint32(0,!0)||1297301847!==e.getUint32(4,!0))n("The file is not an EPW file"),d=!0;var f=c.byteLength;e.getUint32(8,!0)!==f&&(n("The EPW file is the wrong length"), -d=!0);if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{var l=new TextDecoder("utf-8"),h=e.getUint32(100,!0),k=e.getUint32(104,!0),m=e.getUint32(108,!0),p=e.getUint32(112,!0);if(0>h||h+k>f||0>m||m+p>f)n("The EPW file contains an invalid offset (component: splash)"),d=!0;if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{h=new Uint8Array(c,h,k);m=new Uint8Array(c,m,p);l=URL.createObjectURL(new Blob([h],{type:l.decode(m)}));g("Loaded splash img: "+ -l);a.style.background='center / contain no-repeat url("'+l+'"), 0px 0px / 1000000% 1000000% no-repeat url("'+l+'") white';await u();p=e.getUint32(164,!0);h=e.getUint32(168,!0);m=e.getUint32(180,!0);e=e.getUint32(184,!0);if(0>p||p+h>f||0>m||m+e>f)n("The EPW file contains an invalid offset (component: loader)"),d=!0;if(d)b.removeChild(a),x(b,"EPW file is invalid!"),n("EPW file is invalid!");else{a=new Uint8Array(c,p,h);a=URL.createObjectURL(new Blob([a],{type:"text/javascript;charset=utf-8"}));g("Loaded loader.js: "+ -l);d=new Uint8Array(c,m,e);d=URL.createObjectURL(new Blob([d],{type:"application/wasm"}));g("Loaded loader.wasm: "+d);f={};for(const [t,y]of Object.entries(window.eaglercraftXOpts))"container"!==t&&"assetsURI"!==t&&(f[t]=y);window.__eaglercraftXLoaderContextPre={rootElement:b,eaglercraftXOpts:f,theEPWFileBuffer:c,loaderWASMURL:d,splashURL:l};g("Appending loader.js to document...");b=document.createElement("script");b.type="text/javascript";b.src=a;document.head.appendChild(b)}}}}}else b='window.eaglercraftXOpts.container "'+ -a+'" is not a known element id!',n(b),alert(b)}}};}).call(this); +(function(){'use strict';function g(a){console.log("LoaderBootstrap: [INFO] "+a)}function n(a){console.log("LoaderBootstrap: [WARN] "+a)}function q(a){console.error("LoaderBootstrap: [ERROR] "+a)}var r=null; +function u(){const a=[];for(var c=0;64>c;++c)a["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(c)]=c;a[45]=62;a[95]=63;return function(b,d){var e=b.length-d;if(0>16&255,f[h++]=d>>8&255,f[h++]=d&255;2===e?(d=a[b.charCodeAt(k)]<<2|a[b.charCodeAt(k+1)]>>4,f[h++]=d&255):1===e&&(d=a[b.charCodeAt(k)]<<10|a[b.charCodeAt(k+1)]<<4|a[b.charCodeAt(k+2)]>>2,f[h++]=d>>8&255,f[h++]=d&255);return f.buffer}}function v(){return new Promise(function(a){setTimeout(a,20)})} +function w(a){return new Promise(function(c){const b=new Image;b.addEventListener("load",c);b.addEventListener("error",function(){n("Failed to preload image: "+a);c()});b.src=a;setTimeout(c,50)})}function x(a){return new Promise(function(c){fetch(a,{cache:"force-cache"}).then(function(b){return b.arrayBuffer()}).then(c).catch(function(b){q("Failed to fetch URL! "+b);c(null)})})} +function y(a){return a.startsWith("data:application/octet-stream;base64,")?new Promise(function(c){x(a).then(function(b){if(b)c(b);else{n("Failed to decode base64 via fetch, doing it the slow way instead...");try{r||=u();var d=r(a,37);c(d)}catch(e){q("Failed to decode base64! "+e),c(null)}}})}):x(a)} +function z(a,c){const b=document.createElement("h2");b.style.color="#AA0000";b.style.padding="25px";b.style.fontFamily="sans-serif";b.style.marginBlock="0px";b.appendChild(document.createTextNode(c));a.appendChild(b);c=document.createElement("h4");c.style.color="#AA0000";c.style.padding="25px";c.style.fontFamily="sans-serif";c.style.marginBlock="0px";c.appendChild(document.createTextNode("Try again later"));a.style.backgroundColor="white";a.appendChild(c)} +window.main=async function(){if("undefined"===typeof window.eaglercraftXOpts)q("window.eaglercraftXOpts is not defined!"),alert("window.eaglercraftXOpts is not defined!");else{var a=window.eaglercraftXOpts.container;if("string"!==typeof a)q("window.eaglercraftXOpts.container is not a string!"),alert("window.eaglercraftXOpts.container is not a string!");else{var c=window.eaglercraftXOpts.assetsURI;if("string"!==typeof c)if("object"===typeof c&&"object"===typeof c[0]&&"string"===typeof c[0].url)c=c[0].url; +else{q("window.eaglercraftXOpts.assetsURI is not a string!");alert("window.eaglercraftXOpts.assetsURI is not a string!");return}var b=document.getElementById(a);if(b){for(;a=b.lastChild;)b.removeChild(a);a=document.createElement("div");a.style.width="100%";a.style.height="100%";a.style.setProperty("image-rendering","pixelated");a.style.background='center / contain no-repeat url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAAAAAB3tzPbAAAACXBIWXMAAC4jAAAuIwF4pT92AAAG+UlEQVR42u2cy23jOhRATwbTwGwFvAJoF6BFGjColcGkASNuIPA6C68DN+BADZiCVxLSQBYqIGYBAbSdEvwWkvUzZWfymwlwCQwQUZeXPOT9URPkYs/3bj8QAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAEQAAH4x9vPvzFpAhAzM98UILmqfjDf1YT0N/cBk+71v+wDSczHmDeJ6TqO+SIfyD7IvC9g33Yc7dP6CQDxB+q62Hc2xnyJD2Sf5vuzL3Hi5MM0WbCN51u/Y/30ryEGmDVHlhwsY9Y7xlq0CuzVc4lh2n7NkGsnQ1nB7IefmrY/araJcbrq6Ryk9YqW4l3J/dHww1jdej+8kte042EW0Nba1hyWdl+9irq/FNXaD6BbQoexuvf+tQC2vX1+AFvP0kxiuyidfWwEbOtQtK0n0r6xbYCKsLcM21+pLZX3u4984Kq2xlnWDimllRudAXEpkGSHfqMzsmxfWnLWNf9aQznW4wMZWOMJxvGs/Ff5X+yPcD0g3dqZesdsI2f7Z2/73W2JSok9Gqu7P1q/I2qtj0qn/ZkTaCPWO2a0VyjrxY7sNUG1LxRlaE90MpDpGVeAxpaGobN2XPWH0aQVE1stfXPAj0+XzUmcob3aTRdVZ2+tRv+gMNBDaTkZ4k6uhtYPaK7iUkUcx9lgij92gZ6aXmxoDeK8D1hPfm18oBvTfPGwXoVG+4VfXcwl8dEOtCJS7De9M0VTqTA2p081O3kJ+uk5cU/RVN8C262Ms9HMlLHSmhNFTcc9u1uQRX4jMhqyNIk1GRk69a6hb0IDZ3pITnbfNqFuJWE9gbYrfmSqen/SiKy27G0VS20VWc+UEn59/YDPkc+0EunrAXQ/JXucYL+3VutyAqvP5wFvtEoyQPsMJMpKc3v7/Su9ALLkhAJDPCObGTDmonfNHAij3sg5866fmTHGnFt/crroh6vEv/Rq6vhEoP7hWWb2ylSQZP5zOVrDqVxSZnm/xL6OFnZwF3/4JoyGjyXu1X3n0rEFyE5Jzc5KEDfT7s2ZYs52s5e1HU88hB17nKTqAroXWPpXiHbN7R3Q8fVDbjzU6vb8hUbX67FWN8Xo4U5SIWjbukr1knY9XrcwS30aOuTatqa0vkA6cI05dyPrzWBbj7ZZrPUT2O7pdpKFtp4rph0E0AxtfN0u9kNVg25d4BPiDF0+R83dPol7/l4m4yQmQzdX+ISewqTnc8ngp94yaCan4vT+Hc228q8/T35+e8+XueSqCaPmEz9ofdbX6eSqE5iN/m4A8Qd9w/1bAEl2fPmafT3Axdv/ytlFeXUwTZyyf+NA3hWDGPrm+HXtHSdQ7nrz7fvv+MPFe/9Q3nAS+iYA3zcKCYAACIAACIAACIAACIAACIAACIAA1C2Komh++r9cogdv90M0+GoZAVHkSiGSaFmOmJdTRdESiKJ5Je4eovnSldoGNJ44gTBNbx+XH7tDYxwOniAPgEdygGWxTm/jBCAHV0u7xa90PV64IW0uOWdCapK7t600vfF2j4Ad5FCE4IopCSWMSg0Q4NgRVNKrwIBJ1ZDGxXO/5+fxhDvFQ87EsHxZMy9Sli/raMbjf9eqMpiciQG3yYOJwW1eQoBoesNBzG3yKdvqNwie1HMwiXFcwo7L7aMBtlSrC7c79RzyUm5w0f66Gk1vcJs8vFYHxUvy/u8leJz4N8t8vX5ccl04Chz5BOLR+mVVWXX5lsU4ncSOFevL7WFsJbYiPfQpcvJwhNsBxKiwcHDPNnoojzp8Jh8PnusiSMcLd1B8R5i+Igq5/BZKU3IEO8cIpoqw6L5NR8kjuOIaFR6GlmKdvmnhuFTsfqNwTBnzBOo+ZFua+jh3jAZtnksMu/b850wIfh1sVwVPhMEzKK9lz/+7Hi3Kx8CjOajVbVCEz3kIT1wyYnsD6s5t8tUaGLFpTfC7q2TH4rjzHMCoGgqTOJiMFi/TY5kduOJWHfzdtzdFrS4PYBwzhi0LAKcAdTcvKhur+VWQ3/TWcq/+LJG5VahUsILHUDGiGCmKy26cOrxlxwZUsMHlvVDW7lMQwghGOGZpmt6zcdFD47EhtQVyWySQRHUgVDzhmkeClyZFlGmiA5BH0WpyB+twPp/cgQpQBH0Lqt6qaTwfs+OW6Kl/RrdET/WqQi5BgWLDqNxmdV/Mo1X1QX5Ms0Pq/jmaP7d2/b6IVq3HW+a9qT7v6/TDNv2+tVA0hzz8klroc07AbXKmN98YQMppARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARAAARCAD2//A2iD9ZsgY5XpAAAAAElFTkSuQmCC") white'; +b.appendChild(a);await v();c.startsWith("data:")?(g('Downloading EPW file ""...'),c=await y(c)):(g('Downloading EPW file "'+c+'"...'),c=await x(c));var d=!1;c?384>c.byteLength&&(q("The EPW file is too short"),d=!0):d=!0;if(d)b.removeChild(a),z(b,"Failed to download EPW file!"),q("Failed to download EPW file!");else{var e=new DataView(c);if(608649541!==e.getUint32(0,!0)||1297301847!==e.getUint32(4,!0))q("The file is not an EPW file"),d=!0;var f=c.byteLength;e.getUint32(8, +!0)!==f&&(q("The EPW file is the wrong length"),d=!0);if(d)b.removeChild(a),z(b,"EPW file is invalid!"),q("EPW file is invalid!");else{var l=new TextDecoder("utf-8"),h=e.getUint32(100,!0),k=e.getUint32(104,!0),m=e.getUint32(108,!0),p=e.getUint32(112,!0);if(0>h||h+k>f||0>m||m+p>f)q("The EPW file contains an invalid offset (component: splash)"),d=!0;if(d)b.removeChild(a),z(b,"EPW file is invalid!"),q("EPW file is invalid!");else{h=new Uint8Array(c,h,k);m=new Uint8Array(c,m,p);l=URL.createObjectURL(new Blob([h], +{type:l.decode(m)}));await w(l);g("Loaded splash img: "+l);a.style.background='center / contain no-repeat url("'+l+'"), 0px 0px / 1000000% 1000000% no-repeat url("'+l+'") white';await v();p=e.getUint32(164,!0);h=e.getUint32(168,!0);m=e.getUint32(180,!0);e=e.getUint32(184,!0);if(0>p||p+h>f||0>m||m+e>f)q("The EPW file contains an invalid offset (component: loader)"),d=!0;if(d)b.removeChild(a),z(b,"EPW file is invalid!"),q("EPW file is invalid!");else{a=new Uint8Array(c,p,h);a=URL.createObjectURL(new Blob([a], +{type:"text/javascript;charset=utf-8"}));g("Loaded loader.js: "+l);d=new Uint8Array(c,m,e);d=URL.createObjectURL(new Blob([d],{type:"application/wasm"}));g("Loaded loader.wasm: "+d);f={};for(const [t,A]of Object.entries(window.eaglercraftXOpts))"container"!==t&&"assetsURI"!==t&&(f[t]=A);window.__eaglercraftXLoaderContextPre={rootElement:b,eaglercraftXOpts:f,theEPWFileBuffer:c,loaderWASMURL:d,splashURL:l};g("Appending loader.js to document...");b=document.createElement("script");b.type="text/javascript"; +b.src=a;document.head.appendChild(b)}}}}}else b='window.eaglercraftXOpts.container "'+a+'" is not a known element id!',q(b),alert(b)}}};}).call(this);