diff --git a/.idea/misc.xml b/.idea/misc.xml
index fe9a321..21a5a76 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -44,7 +44,7 @@
-
+
diff --git a/build.gradle.kts b/build.gradle.kts
index 055f68f..fc87dbe 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -23,7 +23,7 @@ defaultTasks("mvgCorrector", "test", "publish", "mvgTagger")
plugins {
`java-library`
`maven-publish`
- id("org.modelingvalue.gradle.mvgplugin") version "2.3.15"
+ id("org.modelingvalue.gradle.mvgplugin") version "2.3.21"
}
dependencies {
diff --git a/gradle.properties b/gradle.properties
index adf8a44..4dbf979 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -21,5 +21,5 @@
# suppress inspection "UnusedProperty" for whole file
group = org.modelingvalue
artifact = immutable-collections
-version = 5.0.0
-version_java = 17
+version = 6.0.0
+version_java = 21
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e644113..b1b8ef5 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 37f78a6..df6a6ad 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
networkTimeout=10000
+retries=0
+retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1aa94a4..b9bb139 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -170,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -203,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 25da30d..24c62d5 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -21,8 +23,8 @@
@rem
@rem ##########################################################################
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@@ -49,7 +51,7 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
-goto fail
+"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -63,30 +65,18 @@ echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
-goto fail
+"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-:omega
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 4fac11a..cdfb4fc 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -22,9 +22,3 @@ rootProject.name = "immutable-collections"
include("generator")
-pluginManagement {
- repositories {
- maven { url = uri("https://modelingvaluegroup.github.io/gradlePlugins/") }
- gradlePluginPortal()
- }
-}
diff --git a/src/main/java/org/modelingvalue/collections/impl/EntryImpl.java b/src/main/java/org/modelingvalue/collections/impl/EntryImpl.java
index 04da6e8..91e4181 100644
--- a/src/main/java/org/modelingvalue/collections/impl/EntryImpl.java
+++ b/src/main/java/org/modelingvalue/collections/impl/EntryImpl.java
@@ -25,7 +25,7 @@
import java.util.stream.Stream;
import org.modelingvalue.collections.Entry;
-import org.modelingvalue.collections.util.Age;
+import org.modelingvalue.collections.util.IdentityRank;
import org.modelingvalue.collections.util.Internable;
import org.modelingvalue.collections.util.StringUtil;
@@ -73,7 +73,7 @@ public boolean equals(Object obj) {
return true;
} else if (value == null || !value.equals(other.value)) {
return false;
- } else if (Age.age(value) > Age.age(other.value)) {
+ } else if (IdentityRank.rank(value) < IdentityRank.rank(other.value)) {
other.value = value;
return true;
} else {
diff --git a/src/main/java/org/modelingvalue/collections/impl/GraphImpl.java b/src/main/java/org/modelingvalue/collections/impl/GraphImpl.java
index d5d79eb..5d41742 100644
--- a/src/main/java/org/modelingvalue/collections/impl/GraphImpl.java
+++ b/src/main/java/org/modelingvalue/collections/impl/GraphImpl.java
@@ -360,13 +360,13 @@ public boolean equals(Object obj) {
if (!this.outgoing.equals(other.outgoing))
return false;
- if (Age.age(this.outgoing) > Age.age(other.outgoing)) {
+ if (IdentityRank.rank(this.outgoing) < IdentityRank.rank(other.outgoing)) {
other.outgoing = this.outgoing;
} else {
this.outgoing = other.outgoing;
}
- if (Age.age(this.incoming) > Age.age(other.incoming)) {
+ if (IdentityRank.rank(this.incoming) < IdentityRank.rank(other.incoming)) {
other.incoming = this.incoming;
} else {
this.incoming = other.incoming;
diff --git a/src/main/java/org/modelingvalue/collections/impl/HashCollectionImpl.java b/src/main/java/org/modelingvalue/collections/impl/HashCollectionImpl.java
index 39f844a..6d5f8ca 100644
--- a/src/main/java/org/modelingvalue/collections/impl/HashCollectionImpl.java
+++ b/src/main/java/org/modelingvalue/collections/impl/HashCollectionImpl.java
@@ -33,7 +33,7 @@
import org.modelingvalue.collections.ContainingCollection;
import org.modelingvalue.collections.Set;
import org.modelingvalue.collections.StreamCollection;
-import org.modelingvalue.collections.util.Age;
+import org.modelingvalue.collections.util.IdentityRank;
import org.modelingvalue.collections.util.Concurrent;
import org.modelingvalue.collections.util.ContextThread;
import org.modelingvalue.collections.util.Reusable;
@@ -189,7 +189,7 @@ protected boolean equalsWithStop(Object obj, boolean[] stop) {
} else if (values[ia] == other.values[ib]) {
continue outer;
} else if (Objects.equals(values[ia], other.values[ib])) {
- if (Age.age(values[ia]) > Age.age(other.values[ib])) {
+ if (IdentityRank.rank(values[ia]) < IdentityRank.rank(other.values[ib])) {
other.values[ib] = values[ia];
} else {
values[ia] = other.values[ib];
@@ -210,7 +210,7 @@ protected boolean equalsWithStop(Object obj, boolean[] stop) {
} else if (!TreeCollectionImpl.equalsWithStop(values[i], other.values[i], stop)) {
stop[0] = true;
return false;
- } else if (Age.age(values[i]) > Age.age(other.values[i])) {
+ } else if (IdentityRank.rank(values[i]) < IdentityRank.rank(other.values[i])) {
other.values[i] = values[i];
return true;
} else {
diff --git a/src/main/java/org/modelingvalue/collections/impl/TreeCollectionImpl.java b/src/main/java/org/modelingvalue/collections/impl/TreeCollectionImpl.java
index 9781459..6b778fe 100644
--- a/src/main/java/org/modelingvalue/collections/impl/TreeCollectionImpl.java
+++ b/src/main/java/org/modelingvalue/collections/impl/TreeCollectionImpl.java
@@ -137,7 +137,7 @@ public boolean equals(Object obj) {
return true;
} else if (!equalsWithStop(value, other.value, new boolean[1])) {
return false;
- } else if (Age.age(value) > Age.age(other.value)) {
+ } else if (IdentityRank.rank(value) < IdentityRank.rank(other.value)) {
other.value = value;
return true;
} else {
diff --git a/src/main/java/org/modelingvalue/collections/mutable/MutableList.java b/src/main/java/org/modelingvalue/collections/mutable/MutableList.java
index 29dd580..14bf5ee 100644
--- a/src/main/java/org/modelingvalue/collections/mutable/MutableList.java
+++ b/src/main/java/org/modelingvalue/collections/mutable/MutableList.java
@@ -265,6 +265,11 @@ public List getAndSet(UnaryOperator> oper) {
return pre;
}
+ @Override
+ public MutableList subList(int fromIndex, int toIndex) {
+ return of(get().sublist(toIndex, toIndex));
+ }
+
}
private static class ConcurrentImpl extends MutableList {
@@ -284,10 +289,12 @@ public List get() {
public boolean set(UnaryOperator> oper) {
List prev = ref.get(), next = null;
for (boolean haveNext = false;;) {
- if (!haveNext)
+ if (!haveNext) {
next = oper.apply(prev);
- if (ref.weakCompareAndSetVolatile(prev, next))
+ }
+ if (ref.weakCompareAndSetVolatile(prev, next)) {
return prev != next;
+ }
haveNext = (prev == (prev = ref.get()));
}
}
@@ -297,6 +304,11 @@ public List getAndSet(UnaryOperator> oper) {
return ref.getAndUpdate(oper);
}
+ @Override
+ public MutableList subList(int fromIndex, int toIndex) {
+ return concurrent(get().sublist(toIndex, toIndex));
+ }
+
}
}
diff --git a/src/main/java/org/modelingvalue/collections/struct/impl/StructImpl.java b/src/main/java/org/modelingvalue/collections/struct/impl/StructImpl.java
index 330de52..b914ab4 100644
--- a/src/main/java/org/modelingvalue/collections/struct/impl/StructImpl.java
+++ b/src/main/java/org/modelingvalue/collections/struct/impl/StructImpl.java
@@ -26,7 +26,7 @@
import java.util.function.Consumer;
import org.modelingvalue.collections.struct.Struct;
-import org.modelingvalue.collections.util.Age;
+import org.modelingvalue.collections.util.IdentityRank;
import org.modelingvalue.collections.util.Internable;
import org.modelingvalue.collections.util.StringUtil;
@@ -63,7 +63,7 @@ public boolean equals(Object obj) {
return true;
} else if (!Arrays.equals(data, other.data)) {
return false;
- } else if (Age.age(data) > Age.age(other.data)) {
+ } else if (IdentityRank.rank(data) < IdentityRank.rank(other.data)) {
other.data = data;
return true;
} else {
diff --git a/src/main/java/org/modelingvalue/collections/util/IdentifiedByArray.java b/src/main/java/org/modelingvalue/collections/util/IdentifiedByArray.java
index adc7e67..5db7ab8 100644
--- a/src/main/java/org/modelingvalue/collections/util/IdentifiedByArray.java
+++ b/src/main/java/org/modelingvalue/collections/util/IdentifiedByArray.java
@@ -50,7 +50,7 @@ public boolean equals(Object obj) {
} else if (!Arrays.equals(array, other.array)) {
return false;
} else {
- if (Age.age(array) > Age.age(other.array)) {
+ if (IdentityRank.rank(array) < IdentityRank.rank(other.array)) {
other.array = array;
} else {
array = other.array;
diff --git a/src/main/java/org/modelingvalue/collections/util/Age.java b/src/main/java/org/modelingvalue/collections/util/IdentityRank.java
similarity index 79%
rename from src/main/java/org/modelingvalue/collections/util/Age.java
rename to src/main/java/org/modelingvalue/collections/util/IdentityRank.java
index 8323d51..183c28f 100644
--- a/src/main/java/org/modelingvalue/collections/util/Age.java
+++ b/src/main/java/org/modelingvalue/collections/util/IdentityRank.java
@@ -20,29 +20,13 @@
package org.modelingvalue.collections.util;
-import sun.misc.Unsafe;
+public final class IdentityRank {
-import java.lang.reflect.Field;
-
-public final class Age {
-
- private static Unsafe UNSAFE = null;
-
- static {
- try {
- Field declaredField = Unsafe.class.getDeclaredField("theUnsafe");
- declaredField.setAccessible(true);
- UNSAFE = (Unsafe) declaredField.get(null);
- } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
- e.printStackTrace();
- }
- }
-
- public static int age(Object object) {
- return (UNSAFE.getByte(object, 0L) & 0x78) >> 3;
+ public static int rank(Object object) {
+ return System.identityHashCode(object);
}
- private Age() {
+ private IdentityRank() {
}
}
diff --git a/src/test/java/org/modelingvalue/collections/test/AgeTest.java b/src/test/java/org/modelingvalue/collections/test/IdentityRankTest.java
similarity index 67%
rename from src/test/java/org/modelingvalue/collections/test/AgeTest.java
rename to src/test/java/org/modelingvalue/collections/test/IdentityRankTest.java
index 68d7aff..ca7f761 100644
--- a/src/test/java/org/modelingvalue/collections/test/AgeTest.java
+++ b/src/test/java/org/modelingvalue/collections/test/IdentityRankTest.java
@@ -21,44 +21,15 @@
package org.modelingvalue.collections.test;
import static org.junit.jupiter.api.Assertions.*;
-import static org.modelingvalue.collections.util.Age.*;
-
-import java.util.function.Consumer;
+import static org.modelingvalue.collections.util.IdentityRank.*;
import org.junit.jupiter.api.Test;
-public class AgeTest {
- public static final int LOOPS = 100_000_000;
+public class IdentityRankTest {
@Test
- public void ageCheck() {
- Object[] arr = new Object[]{new Object()};
-
- int age_arr_pre = age(arr);
- int age_sub_pre = age(arr[0]);
- assertAll(
- () -> assertEquals(0, age_arr_pre, "age was " + age_arr_pre),
- () -> assertEquals(0, age_sub_pre, "age was " + age_sub_pre)
- );
-
- useLotsOfMemory(i -> System.out.printf("... i=%2d age=%2d age=%2d\n", i, age(arr), age(arr[0])));
-
- int age_arr_post = age(arr);
- int age_sub_post = age(arr[0]);
- assertAll(
- () -> assertTrue(0 < age_arr_post, "age was " + age_arr_post),
- () -> assertTrue(0 < age_sub_post, "age was " + age_sub_post)
- );
- }
-
- private void useLotsOfMemory(Consumer r) {
- r.accept(0);
- for (int j = 1; j <= 10; j++) {
- for (int i = 0; i < LOOPS / 10; i++) {
- @SuppressWarnings("unused")
- int h = new Object().hashCode();
- }
- r.accept(j);
- }
+ public void rankIsStable() {
+ Object o = new Object();
+ assertEquals(rank(o), rank(o));
}
}