diff --git a/LewisOmniscientDebugger-1.5.jar b/LewisOmniscientDebugger-1.5.jar
deleted file mode 100755
index 70dfb60..0000000
Binary files a/LewisOmniscientDebugger-1.5.jar and /dev/null differ
diff --git a/README.md b/README.md
index 80916fe..a19723b 100644
--- a/README.md
+++ b/README.md
@@ -36,11 +36,11 @@ compile group: 'com.neuronrobotics', name: 'LewisOmniscientDebugger', version: '
# Usage
If you normally run your program on UNIX like this:
-`` % java com.lambda.tests.TestMyArrayList ``
+`` % java your.package.Main ``
You can run the debugger like this:
-`` % java -cp LewisOmniscientDebugger-1.5.jar:$CLASSPATH com.lambda.Debugger.Debugger com.lambda.tests.TestMyArrayList ``
+`` % java -cp build/libs/LewisOmniscientDebugger.jar:$CLASSPATH com.lambda.Debugger.Debugger your.package.Main ``
There are alias files and .BAT files that allow you to type this:
diff --git a/build.gradle b/build.gradle
index 627b77c..24df486 100644
--- a/build.gradle
+++ b/build.gradle
@@ -24,20 +24,21 @@ repositories {
}
dependencies {
- implementation 'org.apache.bcel:bcel:6.2'
+ implementation 'org.apache.bcel:bcel:6.12.0'
+ implementation 'org.apache.commons:commons-lang3:3.20.0'
+ implementation 'commons-io:commons-io:2.21.0'
implementation 'org.ow2.asm:asm:9.7.1'
testImplementation 'junit:junit:4.13.2'
}
+apply from: 'gradle/runtime-provenance.gradle'
+
def manifestAttributes = [
'Manifest-Version' : '1.0',
- 'Created-By' : 'Neuron Robotics Cooperative',
'Specification-Title' : 'LewisOmniscientDebugger',
'Specification-Version' : java.targetCompatibility,
- 'Specification-Vendor' : 'Neuron Robotics Cooperative',
'Implementation-Title' : 'LewisOmniscientDebugger',
'Implementation-Version' : java.targetCompatibility,
- 'Implementation-Vendor' : 'Neuron Robotics Cooperative',
'Main-Class' : 'com.lambda.Debugger.Debugger',
]
@@ -59,6 +60,9 @@ def launchProgramClasses = { File dir ->
def debuggerDebuggerGeneratedSourceDir = layout.buildDirectory.dir('generated/sources/debuggerDebugger/java')
def debuggerDebuggerMainClassesDir = layout.buildDirectory.dir('debuggerDebugger/mainClasses')
def debuggerDebuggerWorkDir = layout.buildDirectory.dir('debuggerDebugger/work')
+def pristineRuntimeClassesDir = layout.buildDirectory.dir('runtime/pristineClasses')
+def instrumentedRuntimeClassesDir = layout.buildDirectory.dir('runtime/instrumentedClasses')
+def runtimeInstrumentationWorkDir = layout.buildDirectory.dir('runtime/work')
def debuggerDebuggerSourceReplacements = [
['com.lambda', 'lambda'],
['edu.insa.LSD', 'insa.LSD'],
@@ -82,6 +86,9 @@ sourceSets {
}
}
+def compiledMainClassesDirs = files(sourceSets.main.output.classesDirs.files)
+sourceSets.main.output.setClassesDirs(files(instrumentedRuntimeClassesDir))
+
tasks.register('generateDebuggerDebuggerSources') {
description = 'Generate the package-rewritten ODB sources used to debug ODB itself'
group = 'build'
@@ -130,17 +137,43 @@ tasks.register('prepareDebuggerDebuggerWorkDir') {
}
}
-tasks.register('debugifyLaunchPrograms', JavaExec) {
+tasks.register('stageRuntimeClasses', Sync) {
dependsOn tasks.named('compileJava')
- classpath = sourceSets.main.runtimeClasspath
+ from compiledMainClassesDirs
+ into pristineRuntimeClassesDir
+}
+
+def debugifyLaunchPrograms = tasks.register('debugifyLaunchPrograms', JavaExec) {
+ dependsOn tasks.named('stageRuntimeClasses')
+ classpath = files(instrumentedRuntimeClassesDir) + configurations.runtimeClasspath
mainClass = 'com.lambda.Debugger.Debugify'
+ workingDir = runtimeInstrumentationWorkDir.get().asFile
+
+ inputs.dir(pristineRuntimeClassesDir)
+ inputs.file('.debuggerDefaults')
+ inputs.property('debugifyClassPatterns', debugifyClassPatterns)
+ outputs.dir(instrumentedRuntimeClassesDir)
+ outputs.dir(runtimeInstrumentationWorkDir)
def debugifyOutput = new ByteArrayOutputStream()
standardOutput = debugifyOutput
errorOutput = debugifyOutput
doFirst {
- def dir = file("${layout.buildDirectory.get()}/classes/java/main/com/lambda/Debugger")
+ def classesDir = instrumentedRuntimeClassesDir.get().asFile
+ delete classesDir
+ copy {
+ from pristineRuntimeClassesDir
+ into classesDir
+ }
+ def workDir = runtimeInstrumentationWorkDir.get().asFile
+ delete workDir
+ workDir.mkdirs()
+ copy {
+ from '.debuggerDefaults'
+ into workDir
+ }
+ def dir = new File(classesDir, 'com/lambda/Debugger')
args = launchProgramClasses(dir)*.absolutePath
if (args.isEmpty()) {
throw new GradleException("No launch program classes matched for debugification in ${dir}")
@@ -159,6 +192,7 @@ tasks.register('debugifyLaunchPrograms', JavaExec) {
}
}
}
+sourceSets.main.output.classesDirs.builtBy(debugifyLaunchPrograms)
tasks.register('debugifyDebuggerDebuggerLaunchPrograms', JavaExec) {
description = 'Pre-instrument launch programs in the package-rewritten ODB'
@@ -196,7 +230,7 @@ tasks.register('debugifyDebuggerDebuggerLaunchPrograms', JavaExec) {
tasks.register('copyMainClassesForDebuggerDebugger', Sync) {
dependsOn tasks.named('debugifyLaunchPrograms')
- from sourceSets.main.output.classesDirs
+ from instrumentedRuntimeClassesDir
into debuggerDebuggerMainClassesDir
}
@@ -244,17 +278,26 @@ tasks.register('debugifyDebuggerDebuggerMainClasses', JavaExec) {
tasks.named('jar', Jar) {
dependsOn tasks.named('debugifyLaunchPrograms')
+ dependsOn tasks.named('processResources')
archiveFileName = 'LewisOmniscientDebugger.jar'
manifest.attributes(manifestAttributes)
- duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ duplicatesStrategy = DuplicatesStrategy.FAIL
from {
- configurations.runtimeClasspath.collect { dep ->
- dep.isDirectory() ? dep : zipTree(dep)
- }
+ configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts
+ .sort { artifact ->
+ def id = artifact.moduleVersion.id
+ "${id.group}:${artifact.name}:${id.version}".toString()
+ }
+ .collect { zipTree(it.file) }
}
-
+ exclude 'com/lambda/tests/**'
+ exclude 'edu/insa/LSD/Test*.class'
+ exclude 'module-info.class'
+ exclude 'META-INF/versions/**'
+ exclude 'META-INF/LICENSE*'
+ exclude 'META-INF/NOTICE*'
exclude 'META-INF/MANIFEST.MF'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
@@ -269,17 +312,26 @@ tasks.register('debuggerDebuggerJar', Jar) {
archiveFileName = 'LewisOmniscientDebugger-debugger-debugger.jar'
manifest.attributes(manifestAttributes + ['Main-Class': 'lambda.Debugger.Debugger'])
- duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+ duplicatesStrategy = DuplicatesStrategy.FAIL
from(debuggerDebuggerMainClassesDir)
from(sourceSets.debuggerDebugger.output)
from(sourceSets.main.output.resourcesDir)
from {
- configurations.runtimeClasspath.collect { dep ->
- dep.isDirectory() ? dep : zipTree(dep)
- }
+ configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts
+ .sort { artifact ->
+ def id = artifact.moduleVersion.id
+ "${id.group}:${artifact.name}:${id.version}".toString()
+ }
+ .collect { zipTree(it.file) }
}
+ exclude 'com/lambda/tests/**'
+ exclude 'edu/insa/LSD/Test*.class'
+ exclude 'module-info.class'
+ exclude 'META-INF/versions/**'
+ exclude 'META-INF/LICENSE*'
+ exclude 'META-INF/NOTICE*'
exclude 'META-INF/MANIFEST.MF'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
@@ -308,3 +360,19 @@ tasks.register('verifyDemoRecordings', Test) {
testClassesDirs = sourceSets.test.output.classesDirs
include '**/VerifyRecordingTest.class'
}
+
+tasks.register('verifyRuntimeTests', Test) {
+ description = 'Run finite ODB unit and adapter tests against the runtime JAR'
+ group = 'verification'
+ dependsOn tasks.named('jar')
+ dependsOn tasks.named('testClasses')
+
+ def jarFile = tasks.named('jar', Jar).get().archiveFile
+ def mainClasses = sourceSets.main.output.classesDirs.files
+ classpath = sourceSets.test.runtimeClasspath.filter { !mainClasses.contains(it) } + files(jarFile)
+ testClassesDirs = sourceSets.test.output.classesDirs
+ exclude '**/VerifyRecordingTest.class'
+}
+
+apply from: 'gradle/collection-provenance.gradle'
+apply from: 'gradle/reproducible-release.gradle'
diff --git a/docs/legal/COLLECTION-PROVENANCE.md b/docs/legal/COLLECTION-PROVENANCE.md
new file mode 100644
index 0000000..53086c6
--- /dev/null
+++ b/docs/legal/COLLECTION-PROVENANCE.md
@@ -0,0 +1,17 @@
+# Collection compatibility provenance
+
+Lewis ODB commit `48bbb7dfaf31b129906056b422c7b97f5dde77e0`
+replaced the former collection implementation bodies with original
+compatibility implementations based only on public Java 8 collection APIs.
+The retained class names preserve ODB callers and serialized data.
+
+`MyArrayList` remains ODB instrumentation machinery. `HashMapEq` preserves
+identity-key behavior. `VectorD` preserves identity search and its
+non-traversing debugger string while using `java.util.Vector` storage.
+
+The historical prebuilt `LewisOmniscientDebugger-1.5.jar` was removed in
+commit `0ffedc6`. `verifyCollectionProvenance` rejects that binary, former
+proprietary notice text, or missing compatibility classes.
+
+These changes are modifications under the repository's GPL terms. This record
+describes project provenance and is not legal advice.
diff --git a/gradle.lockfile b/gradle.lockfile
new file mode 100644
index 0000000..6d15806
--- /dev/null
+++ b/gradle.lockfile
@@ -0,0 +1,8 @@
+# This is a Gradle generated file for dependency locking.
+# Manual edits can break the build and are not advised.
+# This file is expected to be part of source control.
+commons-io:commons-io:2.21.0=runtimeClasspath
+org.apache.bcel:bcel:6.12.0=runtimeClasspath
+org.apache.commons:commons-lang3:3.20.0=runtimeClasspath
+org.ow2.asm:asm:9.7.1=runtimeClasspath
+empty=
diff --git a/gradle/canonical-build.properties b/gradle/canonical-build.properties
new file mode 100644
index 0000000..b53edba
--- /dev/null
+++ b/gradle/canonical-build.properties
@@ -0,0 +1,10 @@
+container.image=azul/zulu-openjdk:8u492@sha256:185e7ab12b3706a39a56b2d5c8921f36ddff8e1c95d704a0a2f22b7e35c611d1
+environment.LC_ALL=C.UTF-8
+environment.TZ=UTC
+file.encoding=UTF-8
+gradle.version=8.12.1
+java.runtime.version=1.8.0_492-b09
+java.vendor=Azul Systems, Inc.
+java.version=1.8.0_492
+os.arch=amd64
+os.name=Linux
diff --git a/gradle/collection-provenance.gradle b/gradle/collection-provenance.gradle
new file mode 100644
index 0000000..25e047c
--- /dev/null
+++ b/gradle/collection-provenance.gradle
@@ -0,0 +1,135 @@
+def arrayListHistoryClassesDir = layout.buildDirectory.dir('verification/array-list-history/classes')
+def debuggerDebuggerGeneratedSourceDir = tasks.named('generateDebuggerDebuggerSources').map {
+ it.outputs.files.singleFile
+}
+tasks.register('prepareArrayListHistoryTarget', Sync) {
+ dependsOn tasks.named('testClasses')
+ from(sourceSets.test.output.classesDirs) {
+ include 'outside/ArrayListHistoryTarget.class'
+ }
+ into(arrayListHistoryClassesDir)
+}
+
+tasks.register('debugifyArrayListHistoryTarget', JavaExec) {
+ description = 'Pre-instrument the ArrayList history verification target'
+ group = 'verification'
+ dependsOn tasks.named('prepareArrayListHistoryTarget')
+ classpath = sourceSets.test.runtimeClasspath
+ mainClass = 'com.lambda.Debugger.Debugify'
+
+ def debugifyOutput = new ByteArrayOutputStream()
+ standardOutput = debugifyOutput
+ errorOutput = debugifyOutput
+
+ doFirst {
+ args = [new File(arrayListHistoryClassesDir.get().asFile,
+ 'outside/ArrayListHistoryTarget.class').absolutePath]
+ }
+ doLast {
+ def output = debugifyOutput.toString('UTF-8')
+ if (!output.isBlank()) {
+ logger.lifecycle(output.trim())
+ }
+ if (executionResult.get().exitValue != 0 || !(output =~ /debugified 1 files\./).find()) {
+ throw new GradleException('Failed to instrument ArrayList history verification target')
+ }
+ }
+}
+
+tasks.named('verifyDemoRecordings', Test) {
+ dependsOn tasks.named('debugifyArrayListHistoryTarget')
+
+ def jarFile = tasks.named('jar', Jar).get().archiveFile
+ def mainClasses = sourceSets.main.output.classesDirs.files
+ classpath = files(arrayListHistoryClassesDir) +
+ sourceSets.test.runtimeClasspath.filter { !mainClasses.contains(it) } +
+ files(jarFile)
+}
+
+tasks.register('verifyCollectionProvenance') {
+ description = 'Verify retained ODB collection compatibility classes and release exclusions'
+ group = 'verification'
+ dependsOn tasks.named('jar')
+ dependsOn tasks.named('compileDebuggerDebuggerJava')
+ dependsOn tasks.named('debuggerDebuggerJar')
+
+ doLast {
+ def expectedClasses = [
+ 'com/lambda/Debugger/HashMapEq.class',
+ 'com/lambda/Debugger/MyAbstractCollection.class',
+ 'com/lambda/Debugger/MyAbstractList.class',
+ 'com/lambda/Debugger/MyArrayList.class',
+ 'com/lambda/Debugger/MyCollections.class',
+ 'com/lambda/Debugger/SubList.class',
+ 'com/lambda/Debugger/VectorD.class',
+ ]
+ def jarChecks = [
+ [
+ file: tasks.named('jar', Jar).get().archiveFile.get().asFile,
+ classes: expectedClasses,
+ ],
+ [
+ file: tasks.named('debuggerDebuggerJar', Jar).get().archiveFile.get().asFile,
+ classes: expectedClasses + expectedClasses.collect {
+ it.replace('com/lambda/Debugger/', 'lambda/Debugger/')
+ },
+ ],
+ ]
+ jarChecks.each { check ->
+ def jarFile = check.file
+ def zip = new java.util.zip.ZipFile(jarFile)
+ try {
+ check.classes.each { entry ->
+ if (zip.getEntry(entry) == null) {
+ throw new GradleException("${jarFile.name} lacks retained compatibility class ${entry}")
+ }
+ }
+ if (zip.entries().find { it.name.endsWith('LewisOmniscientDebugger-1.5.jar') }) {
+ throw new GradleException("${jarFile.name} embeds the historical binary")
+ }
+ } finally {
+ zip.close()
+ }
+ }
+
+ def legacyJar = file('LewisOmniscientDebugger-1.5.jar')
+ if (legacyJar.exists()) {
+ throw new GradleException('Historical JAR must not remain in the source tree')
+ }
+
+ def rewrittenNames = [
+ 'HashMapEq.java',
+ 'VectorD.java',
+ 'MyAbstractCollection.java',
+ 'MyAbstractList.java',
+ 'MyCollections.java',
+ ]
+ def forbiddenPhrases = [
+ 'Sun Microsystems',
+ 'confidential and proprietary information',
+ 'Use is subject to license terms',
+ ]
+ def sourceRoots = [
+ file('src/main/java/com/lambda/Debugger'),
+ debuggerDebuggerGeneratedSourceDir.get().toPath()
+ .resolve('lambda/Debugger').toFile(),
+ ]
+ sourceRoots.each { root ->
+ rewrittenNames.each { name ->
+ def source = new File(root, name)
+ if (!source.isFile()) {
+ throw new GradleException("Missing retained collection source ${source}")
+ }
+ forbiddenPhrases.each { phrase ->
+ if (source.getText('UTF-8').contains(phrase)) {
+ throw new GradleException("${source} retains prohibited copied notice text: ${phrase}")
+ }
+ }
+ }
+ }
+ }
+}
+
+tasks.named('check') {
+ dependsOn tasks.named('verifyCollectionProvenance')
+}
diff --git a/gradle/reproducible-release.gradle b/gradle/reproducible-release.gradle
new file mode 100644
index 0000000..c5690c2
--- /dev/null
+++ b/gradle/reproducible-release.gradle
@@ -0,0 +1,389 @@
+import org.gradle.api.tasks.bundling.AbstractArchiveTask
+import org.gradle.api.tasks.bundling.Compression
+
+def configureReproducibleArchive = { AbstractArchiveTask archiveTask ->
+ archiveTask.preserveFileTimestamps = false
+ archiveTask.reproducibleFileOrder = true
+ archiveTask.filePermissions {
+ unix('rw-r--r--')
+ }
+ archiveTask.dirPermissions {
+ unix('rwxr-xr-x')
+ }
+}
+
+configureReproducibleArchive(tasks.named('jar', Jar).get())
+configureReproducibleArchive(tasks.named('debuggerDebuggerJar', Jar).get())
+
+def injectedSourceCommit = providers.gradleProperty('odbSourceCommit')
+def sourceCommit = {
+ def marker = file('SOURCE-COMMIT')
+ def value
+ if (injectedSourceCommit.isPresent()) {
+ value = injectedSourceCommit.get()
+ } else if (marker.isFile()) {
+ value = marker.getText('UTF-8').trim()
+ } else {
+ def output = new ByteArrayOutputStream()
+ exec {
+ commandLine 'git', 'rev-parse', 'HEAD'
+ standardOutput = output
+ }
+ value = output.toString('UTF-8').trim()
+ }
+ if (!(value ==~ /[0-9a-f]{40}/)) {
+ throw new GradleException("Invalid source commit: ${value}")
+ }
+ value
+}
+def sha256 = { File artifact ->
+ def digest = java.security.MessageDigest.getInstance('SHA-256')
+ artifact.withInputStream { input ->
+ def buffer = new byte[8192]
+ for (int read = input.read(buffer); read != -1; read = input.read(buffer)) {
+ digest.update(buffer, 0, read)
+ }
+ }
+ digest.digest().encodeHex().toString()
+}
+def sourceCommitFile = layout.buildDirectory.file('generated/release/SOURCE-COMMIT')
+def generateSourceCommit = tasks.register('generateSourceCommit') {
+ inputs.property('sourceCommit', providers.provider { sourceCommit() })
+ outputs.file(sourceCommitFile)
+ doLast {
+ def output = sourceCommitFile.get().asFile
+ output.parentFile.mkdirs()
+ output.setText(sourceCommit() + '\n', 'UTF-8')
+ }
+}
+def sourceArchiveFile = tasks.register('sourceArchive', Tar) {
+ description = 'Build deterministic corresponding source for the ODB runtime'
+ group = 'distribution'
+ compression = Compression.GZIP
+ destinationDirectory = layout.buildDirectory.dir('distributions')
+ archiveFileName = providers.provider { "odb-source-${sourceCommit()}.tar.gz" }
+ configureReproducibleArchive(delegate)
+
+ dependsOn 'verifyReleaseCheckout'
+ dependsOn generateSourceCommit
+
+ from(rootDir) {
+ include '.debuggerDefaults'
+ include 'COPYING'
+ include 'README.md'
+ include 'build.gradle'
+ include 'settings.gradle'
+ include 'gradle.lockfile'
+ include 'gradlew.bat'
+ include 'gradle/**'
+ include 'src/**'
+ include 'docs/legal/**'
+ include 'verification/**'
+ }
+ from('scripts/verify-canonical-release.sh') {
+ into 'scripts'
+ filePermissions {
+ unix('rwxr-xr-x')
+ }
+ }
+ from('gradlew') {
+ filePermissions {
+ unix('rwxr-xr-x')
+ }
+ }
+ from(sourceCommitFile)
+}
+
+tasks.register('verifyReleaseCheckout') {
+ description = 'Require a clean Git checkout for release artifacts'
+ group = 'verification'
+
+ doLast {
+ if (file('.git').exists()) {
+ def output = new ByteArrayOutputStream()
+ exec {
+ commandLine 'git', 'status', '--porcelain', '--untracked-files=all'
+ standardOutput = output
+ }
+ if (!output.toString('UTF-8').trim().isEmpty()) {
+ throw new GradleException('Release artifacts require a clean worktree')
+ }
+ } else if (!injectedSourceCommit.isPresent()) {
+ throw new GradleException(
+ 'Release artifacts require a clean Git checkout or canonical source snapshot')
+ }
+ sourceCommit()
+ }
+}
+
+tasks.register('verifySourceArchive') {
+ description = 'Verify corresponding-source contents and exclusions'
+ group = 'verification'
+ dependsOn sourceArchiveFile
+
+ doLast {
+ def archive = sourceArchiveFile.get().archiveFile.get().asFile
+ def tree = tarTree(resources.gzip(archive))
+ def relativeNames = []
+ tree.visit { details ->
+ if (!details.directory) {
+ relativeNames.add(details.relativePath.pathString)
+ }
+ }
+ def required = [
+ '.debuggerDefaults',
+ 'COPYING',
+ 'SOURCE-COMMIT',
+ 'build.gradle',
+ 'settings.gradle',
+ 'gradle.lockfile',
+ 'gradlew',
+ 'gradlew.bat',
+ 'gradle/verification-metadata.xml',
+ 'gradle/wrapper/gradle-wrapper.jar',
+ 'gradle/wrapper/gradle-wrapper.properties',
+ 'scripts/verify-canonical-release.sh',
+ 'src/main/java/com/lambda/Debugger/IntegrationLauncher.java',
+ 'src/test/java/com/lambda/Debugger/IntegrationLauncherProcessTest.java',
+ 'docs/legal/COLLECTION-PROVENANCE.md',
+ 'verification/odb-runtime-osv.json',
+ ]
+ required.each { name ->
+ if (!relativeNames.contains(name)) {
+ throw new GradleException("Source archive lacks ${name}")
+ }
+ }
+ def forbidden = relativeNames.find { name ->
+ name.startsWith('build/')
+ || name.startsWith('.git/')
+ || name.startsWith('.gradle/')
+ || name.endsWith('LewisOmniscientDebugger-1.5.jar')
+ || (name.endsWith('.jar') && name != 'gradle/wrapper/gradle-wrapper.jar')
+ }
+ if (forbidden != null) {
+ throw new GradleException("Source archive contains forbidden entry ${forbidden}")
+ }
+ def commitEntry = tree.matching { include 'SOURCE-COMMIT' }.singleFile
+ if (commitEntry.getText('UTF-8').trim() != sourceCommit()) {
+ throw new GradleException('Source archive commit marker is incorrect')
+ }
+ }
+}
+
+def releaseMetadataFile = layout.buildDirectory.file('generated/release/odb-release.json')
+def runtimeSbomFile = layout.buildDirectory.file('reports/odb-runtime.cdx.json')
+def vulnerabilityEvidence = file('verification/odb-runtime-osv.json')
+def canonicalEnvironment = file('gradle/canonical-build.properties')
+def collectionProvenance = file('docs/legal/COLLECTION-PROVENANCE.md')
+
+tasks.register('generateReleaseMetadata') {
+ description = 'Generate deterministic ODB release metadata'
+ group = 'distribution'
+ dependsOn tasks.named('jar')
+ dependsOn sourceArchiveFile
+ dependsOn tasks.named('generateRuntimeSbom')
+ inputs.file(tasks.named('jar', Jar).flatMap { it.archiveFile })
+ inputs.file(sourceArchiveFile.flatMap { it.archiveFile })
+ inputs.file(runtimeSbomFile)
+ inputs.file(vulnerabilityEvidence)
+ inputs.file(canonicalEnvironment)
+ inputs.property('sourceCommit', providers.provider { sourceCommit() })
+ outputs.file(releaseMetadataFile)
+
+ doLast {
+ def runtime = tasks.named('jar', Jar).get().archiveFile.get().asFile
+ def source = sourceArchiveFile.get().archiveFile.get().asFile
+ def sbom = runtimeSbomFile.get().asFile
+ def environment = new Properties()
+ canonicalEnvironment.withInputStream { environment.load(it) }
+ def environmentValues = new TreeMap()
+ environment.each { key, value -> environmentValues[key.toString()] = value.toString() }
+ def dependencies = configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts.collect {
+ def id = it.moduleVersion.id
+ "${id.group}:${it.name}:${id.version}".toString()
+ }.sort()
+ def metadata = [
+ sourceCommit : sourceCommit(),
+ runtime : [name: runtime.name, sha256: sha256(runtime)],
+ source : [name: source.name, sha256: sha256(source)],
+ javaClassVersion : 52,
+ integrationProtocol : 1,
+ dependencies : dependencies,
+ sbomSha256 : sha256(sbom),
+ vulnerabilityEvidence : [
+ name : vulnerabilityEvidence.name,
+ sha256 : sha256(vulnerabilityEvidence),
+ ],
+ canonicalBuildEnvironment: environmentValues,
+ buildCommand : './scripts/verify-canonical-release.sh',
+ ]
+ def output = releaseMetadataFile.get().asFile
+ output.parentFile.mkdirs()
+ output.setText(
+ groovy.json.JsonOutput.prettyPrint(
+ groovy.json.JsonOutput.toJson(metadata)) + '\n',
+ 'UTF-8')
+ }
+}
+
+def checksumsFile = layout.buildDirectory.file('generated/release/SHA256SUMS')
+tasks.register('generateReleaseChecksums') {
+ description = 'Generate sorted checksums for ODB release inputs'
+ group = 'distribution'
+ dependsOn tasks.named('generateReleaseMetadata')
+ dependsOn tasks.named('prepareRuntimeLegal')
+ inputs.file(tasks.named('jar', Jar).flatMap { it.archiveFile })
+ inputs.file(sourceArchiveFile.flatMap { it.archiveFile })
+ inputs.file(releaseMetadataFile)
+ inputs.file(runtimeSbomFile)
+ inputs.file(vulnerabilityEvidence)
+ inputs.file('COPYING')
+ inputs.file(collectionProvenance)
+ inputs.dir(layout.buildDirectory.dir('generated/runtime-legal'))
+ inputs.file('src/main/resources/META-INF/third-party/asm/LICENSE.txt')
+ outputs.file(checksumsFile)
+
+ doLast {
+ def artifacts = [
+ [name: tasks.named('jar', Jar).get().archiveFile.get().asFile.name,
+ file: tasks.named('jar', Jar).get().archiveFile.get().asFile],
+ [name: sourceArchiveFile.get().archiveFile.get().asFile.name,
+ file: sourceArchiveFile.get().archiveFile.get().asFile],
+ [name: 'odb-release.json', file: releaseMetadataFile.get().asFile],
+ [name: 'odb-runtime.cdx.json', file: runtimeSbomFile.get().asFile],
+ [name: 'odb-runtime-osv.json', file: vulnerabilityEvidence],
+ [name: 'COPYING', file: file('COPYING')],
+ [name: 'COLLECTION-PROVENANCE.md', file: collectionProvenance],
+ ]
+ def runtimeLegal = layout.buildDirectory.dir('generated/runtime-legal').get().asFile
+ fileTree(runtimeLegal).files.sort { it.absolutePath }.each { legal ->
+ artifacts.add([
+ name: "third-party/${runtimeLegal.toPath().relativize(legal.toPath())}".replace('\\', '/'),
+ file: legal,
+ ])
+ }
+ artifacts.add([
+ name: 'third-party/asm/LICENSE.txt',
+ file: file('src/main/resources/META-INF/third-party/asm/LICENSE.txt'),
+ ])
+ def output = checksumsFile.get().asFile
+ output.parentFile.mkdirs()
+ output.setText(artifacts.sort { it.name }.collect {
+ "${sha256(it.file)} ${it.name}"
+ }.join('\n') + '\n', 'UTF-8')
+ }
+}
+
+tasks.register('releaseBundle', Sync) {
+ description = 'Collect the reproducible ODB runtime and release evidence'
+ group = 'distribution'
+ dependsOn tasks.named('verifyReleaseCheckout')
+ dependsOn tasks.named('generateReleaseChecksums')
+ into layout.buildDirectory.dir('release')
+
+ from(tasks.named('jar', Jar).map { it.archiveFile })
+ from(sourceArchiveFile.map { it.archiveFile })
+ from(releaseMetadataFile)
+ from(checksumsFile)
+ from(runtimeSbomFile)
+ from(vulnerabilityEvidence)
+ from('COPYING')
+ from(collectionProvenance)
+ from(layout.buildDirectory.dir('generated/runtime-legal')) {
+ into 'third-party'
+ }
+ from('src/main/resources/META-INF/third-party/asm/LICENSE.txt') {
+ into 'third-party/asm'
+ }
+}
+
+def rebuildRoots = [
+ layout.buildDirectory.dir('verification/rebuild-one'),
+ layout.buildDirectory.dir('verification/rebuild-two'),
+]
+def rebuildTasks = rebuildRoots.withIndex().collect { rebuildRoot, index ->
+ def extractTask = tasks.register("extractSourceArchive${index + 1}", Sync) {
+ dependsOn sourceArchiveFile
+ from {
+ tarTree(resources.gzip(sourceArchiveFile.get().archiveFile.get().asFile))
+ }
+ into rebuildRoot
+ }
+ tasks.register("buildSourceArchive${index + 1}", Exec) {
+ dependsOn extractTask
+ inputs.file(sourceArchiveFile.flatMap { it.archiveFile })
+ workingDir rebuildRoot
+ commandLine './gradlew', '--offline', '--no-daemon', '--no-watch-fs',
+ 'clean', 'jar', 'verifyRuntimeArtifact'
+ outputs.file(rebuildRoot.map { it.file('build/libs/LewisOmniscientDebugger.jar') })
+ }
+}
+
+tasks.register('verifyReproducibleRuntime') {
+ description = 'Compare two isolated source-archive rebuilds with the runtime JAR'
+ group = 'verification'
+ dependsOn tasks.named('jar')
+ dependsOn tasks.named('verifySourceArchive')
+ dependsOn rebuildTasks
+
+ doLast {
+ def expected = tasks.named('jar', Jar).get().archiveFile.get().asFile
+ def expectedSha = sha256(expected)
+ rebuildRoots.each { root ->
+ def rebuilt = root.get().file('build/libs/LewisOmniscientDebugger.jar').asFile
+ def rebuiltSha = sha256(rebuilt)
+ if (rebuiltSha != expectedSha) {
+ throw new GradleException(
+ "Source rebuild digest ${rebuiltSha} differs from ${expectedSha}")
+ }
+ }
+ }
+}
+
+tasks.register('verifyCanonicalBuildEnvironment') {
+ description = 'Verify the pinned Linux and JDK 8 release environment'
+ group = 'verification'
+ inputs.file(canonicalEnvironment)
+
+ doLast {
+ def expected = new Properties()
+ canonicalEnvironment.withInputStream { expected.load(it) }
+ def actual = [
+ 'os.name' : System.getProperty('os.name'),
+ 'os.arch' : System.getProperty('os.arch'),
+ 'java.version' : System.getProperty('java.version'),
+ 'java.runtime.version': System.getProperty('java.runtime.version'),
+ 'java.vendor' : System.getProperty('java.vendor'),
+ 'file.encoding' : System.getProperty('file.encoding'),
+ 'gradle.version' : gradle.gradleVersion,
+ ]
+ actual.each { key, value ->
+ if (value != expected.getProperty(key)) {
+ throw new GradleException(
+ "Canonical build requires ${key}=${expected.getProperty(key)}, found ${value}")
+ }
+ }
+ ['LC_ALL', 'TZ'].each { name ->
+ def key = "environment.${name}"
+ if (System.getenv(name) != expected.getProperty(key)) {
+ throw new GradleException(
+ "Canonical build requires ${name}=${expected.getProperty(key)}, "
+ + "found ${System.getenv(name)}")
+ }
+ }
+ }
+}
+
+tasks.register('verifyCanonicalRelease') {
+ description = 'Run finite canonical ODB release gates'
+ group = 'verification'
+ dependsOn tasks.named('verifyCanonicalBuildEnvironment')
+ dependsOn tasks.named('verifyReproducibleRuntime')
+ dependsOn tasks.named('verifyRuntimeDependencies')
+ dependsOn tasks.named('verifyRuntimeArtifact')
+ dependsOn tasks.named('verifyCollectionProvenance')
+ dependsOn tasks.named('test')
+ dependsOn tasks.named('verifyRuntimeTests')
+ dependsOn tasks.named('verifyDemoRecordings')
+ dependsOn tasks.named('releaseBundle')
+}
diff --git a/gradle/runtime-provenance.gradle b/gradle/runtime-provenance.gradle
new file mode 100644
index 0000000..058988c
--- /dev/null
+++ b/gradle/runtime-provenance.gradle
@@ -0,0 +1,334 @@
+configurations.runtimeClasspath.resolutionStrategy.activateDependencyLocking()
+
+def runtimeComponents = [
+ [
+ group : 'commons-io',
+ name : 'commons-io',
+ probeClass : 'org/apache/commons/io/IOUtils.class',
+ license : 'Apache-2.0',
+ directory : 'commons-io',
+ ],
+ [
+ group : 'org.apache.bcel',
+ name : 'bcel',
+ probeClass : 'org/apache/bcel/Const.class',
+ license : 'Apache-2.0',
+ directory : 'bcel',
+ ],
+ [
+ group : 'org.apache.commons',
+ name : 'commons-lang3',
+ probeClass : 'org/apache/commons/lang3/StringUtils.class',
+ license : 'Apache-2.0',
+ directory : 'commons-lang3',
+ ],
+ [
+ group : 'org.ow2.asm',
+ name : 'asm',
+ probeClass : 'org/objectweb/asm/ClassReader.class',
+ license : 'BSD-3-Clause',
+ ],
+]
+def runtimeComponentKeys = runtimeComponents.collect { "${it.group}:${it.name}".toString() }.sort()
+def runtimeComponentByKey = runtimeComponents.collectEntries { [
+ ("${it.group}:${it.name}".toString()): it,
+] }
+def runtimeCoordinate = { artifact ->
+ def id = artifact.moduleVersion.id
+ "${id.group}:${artifact.name}:${id.version}".toString()
+}
+def runtimeSbomFile = layout.buildDirectory.file('reports/odb-runtime.cdx.json')
+def runtimeLegalDir = layout.buildDirectory.dir('generated/runtime-legal')
+def sha256 = { File artifact ->
+ def digest = java.security.MessageDigest.getInstance('SHA-256')
+ artifact.withInputStream { input ->
+ def buffer = new byte[8192]
+ for (int read = input.read(buffer); read != -1; read = input.read(buffer)) {
+ digest.update(buffer, 0, read)
+ }
+ }
+ digest.digest().encodeHex().toString()
+}
+def sbomCoordinates = { sbom ->
+ sbom.components.collect {
+ it.properties.find { property -> property.name == 'lewisodb:coordinate' }.value
+ }.sort()
+}
+
+tasks.register('generateRuntimeSbom') {
+ description = 'Generate the CycloneDX inventory for the ODB runtime graph'
+ group = 'build'
+ inputs.files(configurations.runtimeClasspath)
+ inputs.property('runtimeComponents', runtimeComponents)
+ outputs.file(runtimeSbomFile)
+
+ doLast {
+ def components = configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts.collect { artifact ->
+ def id = artifact.moduleVersion.id
+ def key = "${id.group}:${artifact.name}".toString()
+ def component = runtimeComponentByKey[key]
+ if (component == null) {
+ throw new GradleException("Unapproved runtime dependency ${runtimeCoordinate(artifact)}")
+ }
+ [
+ type : 'library',
+ group : id.group,
+ name : artifact.name,
+ version : id.version,
+ purl : "pkg:maven/${id.group}/${artifact.name}@${id.version}",
+ hashes : [[alg: 'SHA-256', content: sha256(artifact.file)]],
+ licenses : [[license: [id: component.license]]],
+ properties : [[name: 'lewisodb:coordinate', value: runtimeCoordinate(artifact)]],
+ ]
+ }.sort { it.properties[0].value }
+
+ def bom = [
+ bomFormat : 'CycloneDX',
+ specVersion : '1.5',
+ version : 1,
+ metadata : [component: [
+ type : 'application',
+ group : project.group.toString(),
+ name : base.archivesName.get(),
+ version : project.version.toString(),
+ ]],
+ components : components,
+ ]
+ def output = runtimeSbomFile.get().asFile
+ output.parentFile.mkdirs()
+ output.setText(
+ groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(bom)) + '\n',
+ 'UTF-8')
+ }
+}
+
+tasks.register('prepareRuntimeLegal') {
+ description = 'Collect dependency licenses and notices for the ODB runtime JAR'
+ group = 'build'
+ inputs.files(configurations.runtimeClasspath)
+ inputs.property('runtimeComponents', runtimeComponents)
+ outputs.dir(runtimeLegalDir)
+
+ doLast {
+ def output = runtimeLegalDir.get().asFile
+ delete output
+ def artifacts = configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts
+ runtimeComponents.findAll { it.directory }.each { component ->
+ def artifact = artifacts.find {
+ def id = it.moduleVersion.id
+ id.group == component.group && it.name == component.name
+ }
+ if (artifact == null) {
+ throw new GradleException("Runtime dependency ${component.group}:${component.name} is missing")
+ }
+ def zip = new java.util.zip.ZipFile(artifact.file)
+ try {
+ ['LICENSE.txt', 'NOTICE.txt'].each { fileName ->
+ def entry = zip.getEntry("META-INF/${fileName}")
+ if (entry == null) {
+ throw new GradleException("${component.group}:${component.name} lacks META-INF/${fileName}")
+ }
+ def target = new File(output, "${component.directory}/${fileName}")
+ target.parentFile.mkdirs()
+ zip.getInputStream(entry).withCloseable { input ->
+ target.withOutputStream { stream -> stream << input }
+ }
+ }
+ } finally {
+ zip.close()
+ }
+ }
+ }
+}
+
+tasks.register('verifyRuntimeDependencies') {
+ description = 'Verify the locked ODB runtime dependency graph and Java 8 compatibility'
+ group = 'verification'
+ dependsOn tasks.named('generateRuntimeSbom')
+ inputs.file('verification/odb-runtime-osv.json')
+
+ doLast {
+ def artifacts = configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts
+ def resolvedKeys = artifacts.collect {
+ "${it.moduleVersion.id.group}:${it.name}".toString()
+ }.sort()
+ if (resolvedKeys != runtimeComponentKeys) {
+ throw new GradleException("Runtime dependency graph differs from the approved graph: ${resolvedKeys}")
+ }
+
+ artifacts.each { artifact ->
+ def key = "${artifact.moduleVersion.id.group}:${artifact.name}".toString()
+ def component = runtimeComponentByKey[key]
+ def zip = new java.util.zip.ZipFile(artifact.file)
+ try {
+ def entry = zip.getEntry(component.probeClass)
+ if (entry == null) {
+ throw new GradleException("${runtimeCoordinate(artifact)} lacks ${component.probeClass}")
+ }
+ def input = new DataInputStream(zip.getInputStream(entry))
+ try {
+ if (input.readInt() != -889275714) {
+ throw new GradleException("${runtimeCoordinate(artifact)} probe is not a class file")
+ }
+ input.readUnsignedShort()
+ def majorVersion = input.readUnsignedShort()
+ if (majorVersion > 52) {
+ throw new GradleException(
+ "${runtimeCoordinate(artifact)} requires class-file version "
+ + "${majorVersion}, above Java 8")
+ }
+ } finally {
+ input.close()
+ }
+ } finally {
+ zip.close()
+ }
+ }
+
+ def expectedCoordinates = artifacts.collect(runtimeCoordinate).sort()
+ def sbom = new groovy.json.JsonSlurper().parse(runtimeSbomFile.get().asFile)
+ if (sbom.bomFormat != 'CycloneDX'
+ || sbom.specVersion != '1.5'
+ || sbomCoordinates(sbom) != expectedCoordinates) {
+ throw new GradleException('Generated CycloneDX SBOM differs from the runtime graph')
+ }
+
+ def vulnerabilityEvidence = new groovy.json.JsonSlurper()
+ .parse(file('verification/odb-runtime-osv.json'))
+ def expectedPurls = artifacts.collect {
+ def id = it.moduleVersion.id
+ "pkg:maven/${id.group}/${it.name}@${id.version}".toString()
+ }.sort()
+ def evidencePurls = vulnerabilityEvidence.packages.collect { it.purl }.sort()
+ if (vulnerabilityEvidence.schemaVersion != 1
+ || evidencePurls != expectedPurls) {
+ throw new GradleException(
+ 'OSV evidence differs from the approved runtime graph')
+ }
+ def reportedVulnerabilities = vulnerabilityEvidence.packages.collectMany {
+ it.vulnerabilities ?: []
+ }
+ if (!reportedVulnerabilities.isEmpty()) {
+ throw new GradleException(
+ "OSV evidence reports runtime vulnerabilities: ${reportedVulnerabilities}")
+ }
+ }
+}
+
+tasks.register('verifyRuntimeArtifact') {
+ description = 'Verify runtime inventory and legal files in the ODB fat JAR'
+ group = 'verification'
+ dependsOn tasks.named('jar')
+
+ doLast {
+ def jarFile = tasks.named('jar', Jar).get().archiveFile.get().asFile
+ def expectedEntries = [
+ 'META-INF/odb-runtime.cdx.json',
+ 'META-INF/third-party/asm/LICENSE.txt',
+ 'META-INF/third-party/bcel/LICENSE.txt',
+ 'META-INF/third-party/bcel/NOTICE.txt',
+ 'META-INF/third-party/commons-io/LICENSE.txt',
+ 'META-INF/third-party/commons-io/NOTICE.txt',
+ 'META-INF/third-party/commons-lang3/LICENSE.txt',
+ 'META-INF/third-party/commons-lang3/NOTICE.txt',
+ ]
+ def zip = new java.util.zip.ZipFile(jarFile)
+ try {
+ def requiredEntries = [
+ 'com/lambda/Debugger/Debugger.class',
+ 'com/lambda/Debugger/IntegrationLauncher.class',
+ 'com/lambda/Debugger/IntegrationState.class',
+ ]
+ requiredEntries.each { entry ->
+ def requiredEntry = zip.getEntry(entry)
+ if (requiredEntry == null) {
+ throw new GradleException("Runtime JAR lacks ${entry}")
+ }
+ def requiredInput = new DataInputStream(zip.getInputStream(requiredEntry))
+ try {
+ requiredInput.readInt()
+ requiredInput.readUnsignedShort()
+ if (requiredInput.readUnsignedShort() != 52) {
+ throw new GradleException(
+ "${entry} is not compiled for Java 8 class version 52")
+ }
+ } finally {
+ requiredInput.close()
+ }
+ }
+ expectedEntries.each { entry ->
+ if (zip.getEntry(entry) == null) {
+ throw new GradleException("Runtime JAR lacks ${entry}")
+ }
+ }
+ def forbiddenEntryPatterns = [
+ ~/^com\/lambda\/tests\//,
+ ~/^outside\//,
+ ~/^org\/junit\//,
+ ~/^META-INF\/versions\//,
+ ~/(^|\/)module-info\.class$/,
+ ~/\.(so|dll|dylib|jnilib)$/,
+ ~/LewisOmniscientDebugger-1\.5\.jar$/,
+ ]
+ zip.entries().each { entry ->
+ if (forbiddenEntryPatterns.any { pattern ->
+ pattern.matcher(entry.name).find()
+ }) {
+ throw new GradleException("Runtime JAR contains forbidden entry ${entry.name}")
+ }
+ if (entry.name.endsWith('.class')) {
+ def classInput = new DataInputStream(zip.getInputStream(entry))
+ try {
+ if (classInput.readInt() != -889275714) {
+ throw new GradleException("${entry.name} is not a valid class file")
+ }
+ classInput.readUnsignedShort()
+ def majorVersion = classInput.readUnsignedShort()
+ if (majorVersion > 52) {
+ throw new GradleException(
+ "${entry.name} uses class-file version ${majorVersion}, "
+ + 'above Java 8')
+ }
+ } finally {
+ classInput.close()
+ }
+ }
+ }
+ def input = zip.getInputStream(zip.getEntry('META-INF/odb-runtime.cdx.json'))
+ try {
+ def sbom = new groovy.json.JsonSlurper().parse(input)
+ def expectedCoordinates = configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts
+ .collect(runtimeCoordinate).sort()
+ if (sbomCoordinates(sbom) != expectedCoordinates) {
+ throw new GradleException('Runtime JAR SBOM differs from the runtime graph')
+ }
+ } finally {
+ input.close()
+ }
+ } finally {
+ zip.close()
+ }
+ }
+}
+
+def addRuntimeMetadataToJar = { Jar jarTask ->
+ jarTask.dependsOn tasks.named('generateRuntimeSbom')
+ jarTask.dependsOn tasks.named('prepareRuntimeLegal')
+ jarTask.from(runtimeSbomFile) {
+ into 'META-INF'
+ }
+ jarTask.from(runtimeLegalDir) {
+ into 'META-INF/third-party'
+ }
+}
+
+tasks.withType(Jar).configureEach { jarTask ->
+ if (jarTask.name in ['jar', 'debuggerDebuggerJar']) {
+ addRuntimeMetadataToJar(jarTask)
+ }
+}
+
+tasks.named('check') {
+ dependsOn tasks.named('verifyRuntimeDependencies')
+ dependsOn tasks.named('verifyRuntimeArtifact')
+}
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
new file mode 100644
index 0000000..a89ee21
--- /dev/null
+++ b/gradle/verification-metadata.xml
@@ -0,0 +1,108 @@
+
+
- * - * This implementation provides constant-time performance for the basic - * operations (get and put), assuming the hash function - * disperses the elements properly among the buckets. Iteration over - * collection views requires time proportional to the "capacity" of the - * HashMap instance (the number of buckets) plus its size (the number - * of key-value mappings). Thus, it's very important not to set the intial - * capacity too high (or the load factor too low) if iteration performance is - * important.
- * - * An instance of HashMap has two parameters that affect its - * performance: initial capacity and load factor. The - * capacity is the number of buckets in the hash table, and the initial - * capacity is simply the capacity at the time the hash table is created. The - * load factor is a measure of how full the hash table is allowed to - * get before its capacity is automatically increased. When the number of - * entries in the hash table exceeds the product of the load factor and the - * current capacity, the capacity is roughly doubled by calling the - * rehash method.
- * - * As a general rule, te default load factor (.75) offers a good tradeoff - * between time and space costs. Higher values decrease the space overhead - * but increase the lookup cost (reflected in most of the operations of the - * HashMap class, including get and put). The - * expected number of entries in the map and its load factor should be taken - * into account when setting its initial capacity, so as to minimize the - * number of rehash operations. If the initial capacity is greater - * than the maximum number of entries divided by the load factor, no - * rehash operations will ever occur.
- * - * If many mappings are to be stored in a HashMap instance, creating - * it with a sufficiently large capacity will allow the mappings to be stored - * more efficiently than letting it perform automatic rehashing as needed to - * grow the table.
- * - * Note that this implementation is not synchronized. If multiple - * threads access this map concurrently, and at least one of the threads - * modifies the map structurally, it must be synchronized externally. - * (A structural modification is any operation that adds or deletes one or - * more mappings; merely changing the value associated with a key that an - * instance already contains is not a structural modification.) This is - * typically accomplished by synchronizing on some object that naturally - * encapsulates the map. If no such object exists, the map should be - * "wrapped" using the Collections.synchronizedMap method. This is - * best done at creation time, to prevent accidental unsynchronized access to - * the map:
Map m = Collections.synchronizedMap(new HashMap(...)); - *
- *
- * The iterators returned by all of this class's "collection view methods" are
- * fail-fast: if the map is structurally modified at any time after the
- * iterator is created, in any way except through the iterator's own
- * remove or add methods, the iterator will throw a
- * ConcurrentModificationException. Thus, in the face of concurrent
- * modification, the iterator fails quickly and cleanly, rather than risking
- * arbitrary, non-deterministic behavior at an undetermined time in the
- * future.
- *
- * @author Josh Bloch
- * @author Arthur van Hoff
- * @version 1.29, 04/22/99
- * @see Object#hashCode()
- * @see Collection
- * @see Map
- * @see TreeMap
- * @see Hashtable
- * @since JDK1.2
- */
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/** ODB's identity-based map compatibility type. */
public final class HashMapEq extends AbstractMap implements Map, Cloneable,
- java.io.Serializable {
- /**
- * The hash table data.
- */
- private transient Entry table[];
-
- /**
- * The total number of mappings in the hash table.
- */
- private transient int count;
-
- /**
- * The table is rehashed when its size exceeds this threshold. (The
- * value of this field is (int)(capacity * loadFactor).)
- *
- * @serial
- */
- private int threshold;
-
- /**
- * The load factor for the hashtable.
- *
- * @serial
- */
+ Serializable {
+ private static final long serialVersionUID = 362498820763181265L;
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("loadFactor", Float.TYPE),
+ new ObjectStreamField("threshold", Integer.TYPE)
+ };
+ private static final int DEFAULT_CAPACITY = 101;
+ private static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+ private IdentityHashMap delegate;
+ private int initialCapacity;
private float loadFactor;
- /**
- * The number of times this HashMapEq has been structurally modified
- * Structural modifications are those that change the number of mappings in
- * the HashMapEq or otherwise modify its internal structure (e.g.,
- * rehash). This field is used to make iterators on Collection-views of
- * the HashMapEq fail-fast. (See ConcurrentModificationException).
- */
- private transient int modCount = 0;
-
- /**
- * Constructs a new, empty map with the specified initial
- * capacity and the specified load factor.
- *
- * @param initialCapacity the initial capacity of the HashMapEq.
- * @param loadFactor the load factor of the HashMapEq
- * @throws IllegalArgumentException if the initial capacity is less
- * than zero, or if the load factor is nonpositive.
- */
public HashMapEq(int initialCapacity, float loadFactor) {
- if (initialCapacity < 0)
- throw new IllegalArgumentException("Illegal Initial Capacity: "+
- initialCapacity);
- if (loadFactor <= 0)
- throw new IllegalArgumentException("Illegal Load factor: "+
- loadFactor);
- if (initialCapacity==0)
- initialCapacity = 1;
- this.loadFactor = loadFactor;
- table = new Entry[initialCapacity];
- threshold = (int)(initialCapacity * loadFactor);
+ if (initialCapacity < 0) {
+ throw new IllegalArgumentException(
+ "Illegal Initial Capacity: " + initialCapacity);
+ }
+ if (loadFactor <= 0) {
+ throw new IllegalArgumentException(
+ "Illegal Load factor: " + loadFactor);
+ }
+ this.initialCapacity = initialCapacity == 0 ? 1 : initialCapacity;
+ this.loadFactor = loadFactor;
+ delegate = new IdentityHashMap(initialCapacity);
}
- /**
- * Constructs a new, empty map with the specified initial capacity
- * and default load factor, which is 0.75.
- *
- * @param initialCapacity the initial capacity of the HashMapEq.
- * @throws IllegalArgumentException if the initial capacity is less
- * than zero.
- */
public HashMapEq(int initialCapacity) {
- this(initialCapacity, 0.75f);
+ this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
- /**
- * Constructs a new, empty map with a default capacity and load
- * factor, which is 0.75.
- */
public HashMapEq() {
- this(101, 0.75f);
- }
-
- /**
- * Constructs a new map with the same mappings as the given map. The
- * map is created with a capacity of twice the number of mappings in
- * the given map or 11 (whichever is greater), and a default load factor,
- * which is 0.75.
- * @param t incoming map
- */
- public HashMapEq(Map t) {
- this(Math.max(2*t.size(), 11), 0.75f);
- putAll(t);
- }
-
- /**
- * Returns the number of key-value mappings in this map.
- *
- * @return the number of key-value mappings in this map.
- */
- public int size() {
- return count;
+ this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
}
- /**
- * Returns true if this map contains no key-value mappings.
- *
- * @return true if this map contains no key-value mappings.
- */
- public boolean isEmpty() {
- return count == 0;
+ public HashMapEq(Map source) {
+ this(Math.max(2 * source.size(), 11), DEFAULT_LOAD_FACTOR);
+ putAll(source);
}
- /**
- * Returns true if this map maps one or more keys to the
- * specified value.
- *
- * @param value value whose presence in this map is to be tested.
- * @return true if this map maps one or more keys to the
- * specified value.
- */
- public boolean containsValue(Object value) {
- Entry tab[] = table;
-
- if (value==null) {
- for (int i = tab.length ; i-- > 0 ;)
- for (Entry e = tab[i] ; e != null ; e = e.next)
- if (e.value==null)
- return true;
- } else {
- for (int i = tab.length ; i-- > 0 ;)
- for (Entry e = tab[i] ; e != null ; e = e.next)
- if (value == e.value) // BIL'S MOD
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns true if this map contains a mapping for the specified
- * key.
- *
- * @return true if this map contains a mapping for the specified
- * key.
- * @param key key whose presence in this Map is to be tested.
- */
- public boolean containsKey(Object key) {
- Entry tab[] = table;
- if (key != null) {
- int hash = System.identityHashCode(key);
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry e = tab[index]; e != null; e = e.next)
- if (e.hash==hash && key == e.key) // BIL'S MOD
- return true;
- } else {
- for (Entry e = tab[0]; e != null; e = e.next)
- if (e.key==null)
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns the value to which this map maps the specified key. Returns
- * null if the map contains no mapping for this key. A return
- * value of null does not necessarily indicate that the
- * map contains no mapping for the key; it's also possible that the map
- * explicitly maps the key to null. The containsKey
- * operation may be used to distinguish these two cases.
- *
- * @return the value to which this map maps the specified key.
- * @param key key whose associated value is to be returned.
- */
- public Object get(Object key) {
- Entry tab[] = table;
-
- if (key != null) {
- int hash = System.identityHashCode(key);
- int index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry e = tab[index]; e != null; e = e.next)
- if ((e.hash == hash) && key == e.key) // BIL'S MOD
- return e.value;
- } else {
- for (Entry e = tab[0]; e != null; e = e.next)
- if (e.key==null)
- return e.value;
- }
-
- return null;
- }
-
- /**
- * Rehashes the contents of this map into a new HashMapEq instance
- * with a larger capacity. This method is called automatically when the
- * number of keys in this map exceeds its capacity and load factor.
- */
- private void rehash() {
- int oldCapacity = table.length;
- Entry oldMap[] = table;
-
- int newCapacity = oldCapacity * 2 + 1;
- Entry newMap[] = new Entry[newCapacity];
-
- modCount++;
- threshold = (int)(newCapacity * loadFactor);
- table = newMap;
-
- for (int i = oldCapacity ; i-- > 0 ;) {
- for (Entry old = oldMap[i] ; old != null ; ) {
- Entry e = old;
- old = old.next;
-
- int index = (e.hash & 0x7FFFFFFF) % newCapacity;
- e.next = newMap[index];
- newMap[index] = e;
- }
- }
- }
-
- /**
- * Associates the specified value with the specified key in this map.
- * If the map previously contained a mapping for this key, the old
- * value is replaced.
- *
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- * @return previous value associated with specified key, or null
- * if there was no mapping for key. A null return can
- * also indicate that the HashMapEq previously associated
- * null with the specified key.
- */
+ public int size() { return delegate.size(); }
+ public boolean isEmpty() { return delegate.isEmpty(); }
+ public boolean containsValue(Object value) { return delegate.containsValue(value); }
+ public boolean containsKey(Object key) { return delegate.containsKey(key); }
+ public Object get(Object key) { return delegate.get(key); }
public Object put(Object key, Object value) {
- // Makes sure the key is not already in the HashMapEq.
- Entry tab[] = table;
- int hash = 0;
- int index = 0;
-
- if (key != null) {
- hash = System.identityHashCode(key);
- index = (hash & 0x7FFFFFFF) % tab.length;
- for (Entry e = tab[index] ; e != null ; e = e.next) {
- if ((e.hash == hash) && key == e.key) { // BIL'S MOD
- Object old = e.value;
- e.value = value;
- return old;
- }
- }
- } else {
- for (Entry e = tab[0] ; e != null ; e = e.next) {
- if (e.key == null) {
- Object old = e.value;
- e.value = value;
- return old;
- }
- }
+ if (!delegate.containsKey(key)
+ && delegate.size() >= (int) (initialCapacity * loadFactor)) {
+ initialCapacity = 2 * initialCapacity + 1;
}
-
- modCount++;
- if (count >= threshold) {
- // Rehash the table if the threshold is exceeded
- rehash();
-
- tab = table;
- index = (hash & 0x7FFFFFFF) % tab.length;
- }
-
- // Creates the new entry.
- Entry e = new Entry(hash, key, value, tab[index]);
- tab[index] = e;
- count++;
- return null;
+ return delegate.put(key, value);
}
-
- /**
- * Removes the mapping for this key from this map if present.
- *
- * @param key key whose mapping is to be removed from the map.
- * @return previous value associated with specified key, or null
- * if there was no mapping for key. A null return can
- * also indicate that the map previously associated null
- * with the specified key.
- */
- public Object remove(Object key) {
- Entry tab[] = table;
-
- if (key != null) {
- int hash = System.identityHashCode(key);
- int index = (hash & 0x7FFFFFFF) % tab.length;
-
- for (Entry e = tab[index], prev = null; e != null;
- prev = e, e = e.next) {
- if ((e.hash == hash) && key == e.key) { // BIL'S MOD
- modCount++;
- if (prev != null)
- prev.next = e.next;
- else
- tab[index] = e.next;
-
- count--;
- Object oldValue = e.value;
- e.value = null;
- return oldValue;
- }
- }
- } else {
- for (Entry e = tab[0], prev = null; e != null;
- prev = e, e = e.next) {
- if (e.key == null) {
- modCount++;
- if (prev != null)
- prev.next = e.next;
- else
- tab[0] = e.next;
-
- count--;
- Object oldValue = e.value;
- e.value = null;
- return oldValue;
- }
- }
+ public Object remove(Object key) { return delegate.remove(key); }
+ public void putAll(Map source) {
+ for (Object entryObject : source.entrySet()) {
+ Map.Entry entry = (Map.Entry) entryObject;
+ put(entry.getKey(), entry.getValue());
}
-
- return null;
}
+ public void clear() { delegate.clear(); }
- /**
- * Copies all of the mappings from the specified map to this one.
- *
- * These mappings replace any mappings that this map had for any of the
- * keys currently in the specified Map.
- *
- * @param t Mappings to be stored in this map.
- */
- public void putAll(Map t) {
- Iterator i = t.entrySet().iterator();
- while (i.hasNext()) {
- Map.Entry e = (Map.Entry) i.next();
- put(e.getKey(), e.getValue());
- }
- }
-
- /**
- * Removes all mappings from this map.
- */
- public void clear() {
- Entry tab[] = table;
- modCount++;
- for (int index = tab.length; --index >= 0; )
- tab[index] = null;
- count = 0;
- }
-
- /**
- * Returns a shallow copy of this HashMapEq instance: the keys and
- * values themselves are not cloned.
- *
- * @return a shallow copy of this map.
- */
public Object clone() {
- try {
- HashMapEq t = (HashMapEq)super.clone();
- t.table = new Entry[table.length];
- for (int i = table.length ; i-- > 0 ; ) {
- t.table[i] = (table[i] != null)
- ? (Entry)table[i].clone() : null;
- }
- t.keySet = null;
- t.entrySet = null;
- t.values = null;
- t.modCount = 0;
- return t;
- } catch (CloneNotSupportedException e) {
- // this shouldn't happen, since we are Cloneable
- throw new InternalError();
- }
- }
-
- // Views
-
- private transient Set keySet = null;
- private transient Set entrySet = null;
- private transient Collection values = null;
-
- /**
- * Returns a set view of the keys contained in this map. The set is
- * backed by the map, so changes to the map are reflected in the set, and
- * vice-versa. The set supports element removal, which removes the
- * corresponding mapping from this map, via the Iterator.remove,
- * Set.remove, removeAll, retainAll, and
- * clear operations. It does not support the add or
- * addAll operations.
- *
- * @return a set view of the keys contained in this map.
- */
- public Set keySet() {
- if (keySet == null) {
- keySet = new AbstractSet() {
- public Iterator iterator() {
- return new HashIterator(KEYS);
- }
- public int size() {
- return count;
- }
- public boolean contains(Object o) {
- return containsKey(o);
- }
- public boolean remove(Object o) {
- return HashMapEq.this.remove(o) != null;
- }
- public void clear() {
- HashMapEq.this.clear();
- }
- };
- }
- return keySet;
- }
-
- /**
- * Returns a collection view of the values contained in this map. The
- * collection is backed by the map, so changes to the map are reflected in
- * the collection, and vice-versa. The collection supports element
- * removal, which removes the corresponding mapping from this map, via the
- * Iterator.remove, Collection.remove,
- * removeAll, retainAll, and clear operations.
- * It does not support the add or addAll operations.
- *
- * @return a collection view of the values contained in this map.
- */
- public Collection values() {
- if (values==null) {
- values = new AbstractCollection() {
- public Iterator iterator() {
- return new HashIterator(VALUES);
- }
- public int size() {
- return count;
- }
- public boolean contains(Object o) {
- return containsValue(o);
- }
- public void clear() {
- HashMapEq.this.clear();
- }
- };
+ HashMapEq copy = new HashMapEq(initialCapacity, loadFactor);
+ copy.delegate.putAll(delegate);
+ return copy;
+ }
+
+ public Set keySet() { return delegate.keySet(); }
+ public Collection values() { return delegate.values(); }
+ public Set entrySet() { return delegate.entrySet(); }
+
+ int capacity() { return initialCapacity; }
+ float loadFactor() { return loadFactor; }
+
+ public synchronized String toString() { return delegate.toString(); }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ ObjectOutputStream.PutField fields = stream.putFields();
+ fields.put("loadFactor", loadFactor);
+ fields.put("threshold", (int) (initialCapacity * loadFactor));
+ stream.writeFields();
+ stream.writeInt(initialCapacity);
+ stream.writeInt(delegate.size());
+ for (Object entryObject : delegate.entrySet()) {
+ Map.Entry entry = (Map.Entry) entryObject;
+ stream.writeObject(entry.getKey());
+ stream.writeObject(entry.getValue());
}
- return values;
}
- /**
- * Returns a collection view of the mappings contained in this map. Each
- * element in the returned collection is a Map.Entry. The
- * collection is backed by the map, so changes to the map are reflected in
- * the collection, and vice-versa. The collection supports element
- * removal, which removes the corresponding mapping from the map, via the
- * Iterator.remove, Collection.remove,
- * removeAll, retainAll, and clear operations.
- * It does not support the add or addAll operations.
- *
- * @return a collection view of the mappings contained in this map.
- * @see Map.Entry
- */
- public Set entrySet() {
- if (entrySet==null) {
- entrySet = new AbstractSet() {
- public Iterator iterator() {
- return new HashIterator(ENTRIES);
- }
-
- public boolean contains(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry entry = (Map.Entry)o;
- Object key = entry.getKey();
- Entry tab[] = table;
- int hash = (key==null ? 0 : System.identityHashCode(key));
- int index = (hash & 0x7FFFFFFF) % tab.length;
-
- for (Entry e = tab[index]; e != null; e = e.next)
- if (e.hash==hash && e == entry) // BIL'S MOD
- return true;
- return false;
- }
-
- public boolean remove(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry entry = (Map.Entry)o;
- Object key = entry.getKey();
- Entry tab[] = table;
- int hash = (key==null ? 0 : System.identityHashCode(key));
- int index = (hash & 0x7FFFFFFF) % tab.length;
-
- for (Entry e = tab[index], prev = null; e != null;
- prev = e, e = e.next) {
- if (e.hash==hash && e == entry) { // BIL'S MOD
- modCount++;
- if (prev != null)
- prev.next = e.next;
- else
- tab[index] = e.next;
-
- count--;
- e.value = null;
- return true;
- }
- }
- return false;
- }
-
- public int size() {
- return count;
- }
-
- public void clear() {
- HashMapEq.this.clear();
- }
- };
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream.GetField fields = stream.readFields();
+ loadFactor = fields.get("loadFactor", DEFAULT_LOAD_FACTOR);
+ initialCapacity = stream.readInt();
+ int size = stream.readInt();
+ delegate = new IdentityHashMap(initialCapacity);
+ for (int i = 0; i < size; i++) {
+ put(stream.readObject(), stream.readObject());
}
-
- return entrySet;
- }
-
- /**
- * HashMapEq collision list entry.
- */
- private static class Entry implements Map.Entry {
- int hash;
- Object key;
- Object value;
- Entry next;
-
- Entry(int hash, Object key, Object value, Entry next) {
- this.hash = hash;
- this.key = key;
- this.value = value;
- this.next = next;
- }
-
- protected Object clone() {
- return new Entry(hash, key, value,
- (next==null ? null : (Entry)next.clone()));
- }
-
- // Map.Entry Ops
-
- public Object getKey() {
- return key;
- }
-
- public Object getValue() {
- return value;
- }
-
- public Object setValue(Object value) {
- Object oldValue = this.value;
- this.value = value;
- return oldValue;
- }
-
- public boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false;
- Map.Entry e = (Map.Entry)o;
-
- return (key==null ? e.getKey()==null : key == e.getKey()) && // BIL'S MOD
- (value==null ? e.getValue()==null : value == e.getValue()); // BIL'S MOD
- }
-
- public int hashCode() {
- return hash ^ (value==null ? 0 : value.hashCode());
- }
-
- public String toString() {
- return key+"="+value;
- }
- }
-
- // Types of Iterators
- private static final int KEYS = 0;
- private static final int VALUES = 1;
- private static final int ENTRIES = 2;
-
- private class HashIterator implements Iterator {
- Entry[] table = HashMapEq.this.table;
- int index = table.length;
- Entry entry = null;
- Entry lastReturned = null;
- int type;
-
- /**
- * The modCount value that the iterator believes that the backing
- * List should have. If this expectation is violated, the iterator
- * has detected concurrent modification.
- */
- private int expectedModCount = modCount;
-
- HashIterator(int type) {
- this.type = type;
- }
-
- public boolean hasNext() {
- while (entry==null && index>0)
- entry = table[--index];
-
- return entry != null;
- }
-
- public Object next() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
-
- while (entry==null && index>0)
- entry = table[--index];
-
- if (entry != null) {
- Entry e = lastReturned = entry;
- entry = e.next;
- return type == KEYS ? e.key : (type == VALUES ? e.value : e);
- }
- throw new NoSuchElementException();
- }
-
- public void remove() {
- if (lastReturned == null)
- throw new IllegalStateException();
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
-
- Entry[] tab = HashMapEq.this.table;
- int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
-
- for (Entry e = tab[index], prev = null; e != null;
- prev = e, e = e.next) {
- if (e == lastReturned) {
- modCount++;
- expectedModCount++;
- if (prev == null)
- tab[index] = e.next;
- else
- prev.next = e.next;
- count--;
- lastReturned = null;
- return;
- }
- }
- throw new ConcurrentModificationException();
- }
- }
-
- /**
- * Save the state of the HashMapEq instance to a stream (i.e.,
- * serialize it).
- *
- * @serialData The capacity of the HashMapEq (the length of the
- * bucket array) is emitted (int), followed by the
- * size of the HashMapEq (the number of key-value
- * mappings), followed by the key (Object) and value (Object)
- * for each key-value mapping represented by the HashMapEq
- * The key-value mappings are emitted in no particular order.
- */
- private void writeObject(java.io.ObjectOutputStream s)
- throws IOException
- {
- // Write out the threshold, loadfactor, and any hidden stuff
- s.defaultWriteObject();
-
- // Write out number of buckets
- s.writeInt(table.length);
-
- // Write out size (number of Mappings)
- s.writeInt(count);
-
- // Write out keys and values (alternating)
- for (int index = table.length-1; index >= 0; index--) {
- Entry entry = table[index];
-
- while (entry != null) {
- s.writeObject(entry.key);
- s.writeObject(entry.value);
- entry = entry.next;
- }
- }
- }
-
- private static final long serialVersionUID = 362498820763181265L;
-
- /**
- * Reconstitute the HashMapEq instance from a stream (i.e.,
- * deserialize it).
- */
- private void readObject(java.io.ObjectInputStream s)
- throws IOException, ClassNotFoundException
- {
- // Read in the threshold, loadfactor, and any hidden stuff
- s.defaultReadObject();
-
- // Read in number of buckets and allocate the bucket array;
- int numBuckets = s.readInt();
- table = new Entry[numBuckets];
-
- // Read in size (number of Mappings)
- int size = s.readInt();
-
- // Read the keys and values, and put the mappings in the HashMapEq
- for (int i=0; i
- *
- * To implement an unmodifiable collection, the programmer needs only to
- * extend this class and provide implementations for the iterator and
- * size methods. (The iterator returned by the iterator
- * method must implement hasNext and next.)
- *
- * To implement a modifiable collection, the programmer must additionally
- * override this class's add method (which otherwise throws an
- * UnsupportedOperationException), and the iterator returned by the
- * iterator method must additionally implement its remove
- * method.
- *
- * The programmer should generally provide a void (no argument) and
- * Collection constructor, as per the recommendation in the
- * Collection interface specification.
- *
- * The documentation for each non-abstract methods in this class describes its
- * implementation in detail. Each of these methods may be overridden if
- * the collection being implemented admits a more efficient implementation.
- *
- * @author Josh Bloch
- * @version 1.16, 02/02/00
- * @see Collection
- * @since 1.2
- */
-
-public abstract class MyAbstractCollection implements Collection {
- /**
- * Sole constructor. (For invocation by subclass constructors, typically
- * implicit.)
- */
+/** Retained ODB compatibility name for Java's collection skeleton. */
+public abstract class MyAbstractCollection extends AbstractCollection
+ implements Collection {
protected MyAbstractCollection() {
}
-
- // Query Operations
-
- /**
- * Returns an iterator over the elements contained in this collection.
- *
- * @return an iterator over the elements contained in this collection.
- */
- public abstract Iterator iterator();
-
- /**
- * Returns the number of elements in this collection. If the collection
- * contains more than Integer.MAX_VALUE elements, returns
- * Integer.MAX_VALUE.
- *
- * @return the number of elements in this collection.
- */
- public abstract int size();
-
- /**
- * Returns true if this collection contains no elements.
- *
- * This implementation returns size() == 0.
- *
- * @return true if this collection contains no elements.
- */
- public boolean isEmpty() {
- return size() == 0;
- }
-
- /**
- * Returns true if this collection contains the specified
- * element. More formally, returns true if and only if this
- * collection contains at least one element e such that
- * (o==null ? e==null : o.equals(e)).
- *
- * This implementation iterates over the elements in the collection,
- * checking each element in turn for equality with the specified element.
- *
- * @param o object to be checked for containment in this collection.
- * @return true if this collection contains the specified element.
- */
- public boolean contains(Object o) {
- Iterator e = iterator();
- if (o==null) {
- while (e.hasNext())
- if (e.next()==null)
- return true;
- } else {
- while (e.hasNext())
- if (o.equals(e.next()))
- return true;
- }
- return false;
- }
-
- /**
- * Returns an array containing all of the elements in this collection. If
- * the collection makes any guarantees as to what order its elements are
- * returned by its iterator, this method must return the elements in the
- * same order. The returned array will be "safe" in that no references to
- * it are maintained by the collection. (In other words, this method must
- * allocate a new array even if the collection is backed by an Array).
- * The caller is thus free to modify the returned array.
- *
- * This implementation allocates the array to be returned, and iterates
- * over the elements in the collection, storing each object reference in
- * the next consecutive element of the array, starting with element 0.
- *
- * @return an array containing all of the elements in this collection.
- */
- public Object[] toArray() {
- Object[] result = new Object[size()];
- Iterator e = iterator();
- for (int i=0; e.hasNext(); i++)
- result[i] = e.next();
- return result;
- }
-
- /**
- * Returns an array with a runtime type is that of the specified array and
- * that contains all of the elements in this collection. If the
- * collection fits in the specified array, it is returned therein.
- * Otherwise, a new array is allocated with the runtime type of the
- * specified array and the size of this collection.
- *
- * If the collection fits in the specified array with room to spare (i.e.,
- * the array has more elements than the collection), the element in the
- * array immediately following the end of the collection is set to
- * null. This is useful in determining the length of the
- * collection only if the caller knows that the collection does
- * not contain any null elements.)
- *
- * If this collection makes any guarantees as to what order its elements
- * are returned by its iterator, this method must return the elements in
- * the same order.
- *
- * This implementation checks if the array is large enough to contain the
- * collection; if not, it allocates a new array of the correct size and
- * type (using reflection). Then, it iterates over the collection,
- * storing each object reference in the next consecutive element of the
- * array, starting with element 0. If the array is larger than the
- * collection, a null is stored in the first location after the
- * end of the collection.
- *
- * @param a the array into which the elements of the collection are to
- * be stored, if it is big enough; otherwise, a new array of the
- * same runtime type is allocated for this purpose.
- * @return an array containing the elements of the collection.
- *
- * @throws NullPointerException if the specified array is null.
- *
- * @throws ArrayStoreException if the runtime type of the specified array
- * is not a supertype of the runtime type of every element in this
- * collection.
- */
- public Object[] toArray(Object a[]) {
- int size = size();
- if (a.length < size)
- a = (Object[])java.lang.reflect.Array.newInstance(
- a.getClass().getComponentType(), size);
-
- Iterator it=iterator();
- for (int i=0; i
- *
- * This implementation always throws an
- * UnsupportedOperationException.
- *
- * @param o element whose presence in this collection is to be ensured.
- * @return true if the collection changed as a result of the call.
- *
- * @throws UnsupportedOperationException if the add method is not
- * supported by this collection.
- *
- * @throws NullPointerException if this collection does not permit
- * null elements, and the specified element is
- * null.
- *
- * @throws ClassCastException if the class of the specified element
- * prevents it from being added to this collection.
- *
- * @throws IllegalArgumentException if some aspect of this element
- * prevents it from being added to this collection.
- */
- public boolean add(Object o) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Removes a single instance of the specified element from this
- * collection, if it is present (optional operation). More formally,
- * removes an element e such that (o==null ? e==null :
- * o.equals(e)), if the collection contains one or more such
- * elements. Returns true if the collection contained the
- * specified element (or equivalently, if the collection changed as a
- * result of the call).
- *
- * This implementation iterates over the collection looking for the
- * specified element. If it finds the element, it removes the element
- * from the collection using the iterator's remove method.
- *
- * Note that this implementation throws an
- * UnsupportedOperationException if the iterator returned by this
- * collection's iterator method does not implement the remove
- * method.
- *
- * @param o element to be removed from this collection, if present.
- * @return true if the collection contained the specified
- * element.
- *
- * @throws UnsupportedOperationException if the remove method is
- * not supported by this collection.
- */
- public boolean remove(Object o) {
- Iterator e = iterator();
- if (o==null) {
- while (e.hasNext()) {
- if (e.next()==null) {
- e.remove();
- return true;
- }
- }
- } else {
- while (e.hasNext()) {
- if (o.equals(e.next())) {
- e.remove();
- return true;
- }
- }
- }
- return false;
- }
-
-
- // Bulk Operations
-
- /**
- * Returns true if this collection contains all of the elements
- * in the specified collection.
- *
- * This implementation iterates over the specified collection, checking
- * each element returned by the iterator in turn to see if it's
- * contained in this collection. If all elements are so contained
- * true is returned, otherwise false.
- *
- * @param c collection to be checked for containment in this collection.
- * @return true if this collection contains all of the elements
- * in the specified collection.
- *
- * @see #contains(Object)
- */
- public boolean containsAll(Collection c) {
- Iterator e = c.iterator();
- while (e.hasNext())
- if(!contains(e.next()))
- return false;
-
- return true;
- }
-
- /**
- * Adds all of the elements in the specified collection to this collection
- * (optional operation). The behavior of this operation is undefined if
- * the specified collection is modified while the operation is in
- * progress. (This implies that the behavior of this call is undefined if
- * the specified collection is this collection, and this collection is
- * nonempty.)
- *
- * This implementation iterates over the specified collection, and adds
- * each object returned by the iterator to this collection, in turn.
- *
- * Note that this implementation will throw an
- * UnsupportedOperationException unless add is
- * overridden.
- *
- * @param c collection whose elements are to be added to this collection.
- * @return true if this collection changed as a result of the
- * call.
- * @throws UnsupportedOperationException if the addAll method is
- * not supported by this collection.
- *
- * @see #add(Object)
- */
- public boolean addAll(Collection c) {
- boolean modified = false;
- Iterator e = c.iterator();
- while (e.hasNext()) {
- if(add(e.next()))
- modified = true;
- }
- return modified;
- }
-
- /**
- * Removes from this collection all of its elements that are contained in
- * the specified collection (optional operation).
- *
- * This implementation iterates over this collection, checking each
- * element returned by the iterator in turn to see if it's contained
- * in the specified collection. If it's so contained, it's removed from
- * this collection with the iterator's remove method.
- *
- * Note that this implementation will throw an
- * UnsupportedOperationException if the iterator returned by the
- * iterator method does not implement the remove method.
- *
- * @param c elements to be removed from this collection.
- * @return true if this collection changed as a result of the
- * call.
- *
- * @throws UnsupportedOperationException removeAll is not supported
- * by this collection.
- *
- * @see #remove(Object)
- * @see #contains(Object)
- */
- public boolean removeAll(Collection c) {
- boolean modified = false;
- Iterator e = iterator();
- while (e.hasNext()) {
- if(c.contains(e.next())) {
- e.remove();
- modified = true;
- }
- }
- return modified;
- }
-
- /**
- * Retains only the elements in this collection that are contained in the
- * specified collection (optional operation). In other words, removes
- * from this collection all of its elements that are not contained in the
- * specified collection.
- *
- * This implementation iterates over this collection, checking each
- * element returned by the iterator in turn to see if it's contained
- * in the specified collection. If it's not so contained, it's removed
- * from this collection with the iterator's remove method.
- *
- * Note that this implementation will throw an
- * UnsupportedOperationException if the iterator returned by the
- * iterator method does not implement the remove method.
- *
- * @param c elements to be retained in this collection.
- * @return true if this collection changed as a result of the
- * call.
- *
- * @throws UnsupportedOperationException if the retainAll method
- * is not supported by this collection.
- *
- * @see #remove(Object)
- * @see #contains(Object)
- */
- public boolean retainAll(Collection c) {
- boolean modified = false;
- Iterator e = iterator();
- while (e.hasNext()) {
- if(!c.contains(e.next())) {
- e.remove();
- modified = true;
- }
- }
- return modified;
- }
-
- /**
- * Removes all of the elements from this collection (optional operation).
- * The collection will be empty after this call returns (unless it throws
- * an exception).
- *
- * This implementation iterates over this collection, removing each
- * element using the Iterator.remove operation. Most
- * implementations will probably choose to override this method for
- * efficiency.
- *
- * Note that this implementation will throw an
- * UnsupportedOperationException if the iterator returned by this
- * collection's iterator method does not implement the
- * remove method.
- *
- * @throws UnsupportedOperationException if the remove method is
- * not supported by this collection.
- */
- public void clear() {
- Iterator e = iterator();
- while (e.hasNext()) {
- e.next();
- e.remove();
- }
- }
-
-
- // String conversion
-
- /**
- * Returns a string representation of this collection. The string
- * representation consists of a list of the collection's elements in the
- * order they are returned by its iterator, enclosed in square brackets
- * ("[]"). Adjacent elements are separated by the characters
- * ", " (comma and space). Elements are converted to strings as
- * by String.valueOf(Object).
- *
- * This implementation creates an empty string buffer, appends a left
- * square bracket, and iterates over the collection appending the string
- * representation of each element in turn. After appending each element
- * except the last, the string ", " is appended. Finally a right
- * bracket is appended. A string is obtained from the string buffer, and
- * returned.
- *
- * @return a string representation of this collection.
- */
- /*
- public String toString() {
- StringBuffer buf = new StringBuffer();
- Iterator e = iterator();
- buf.append("[");
- int maxIndex = size() - 1;
- for (int i = 0; i <= maxIndex; i++) {
- buf.append(String.valueOf(e.next()));
- if (i < maxIndex)
- buf.append(", ");
- }
- buf.append("]");
- return buf.toString();
- }
- */
-
- public String toString() {
- return "
- *
- * To implement an unmodifiable list, the programmer needs only to extend this
- * class and provide implementations for the get(int index) and
- * size() methods.
- *
- * To implement a modifiable list, the programmer must additionally override
- * the set(int index, Object element) method (which otherwise throws
- * an UnsupportedOperationException. If the list is variable-size
- * the programmer must additionally override the add(int index, Object
- * element) and remove(int index) methods.
- *
- * The programmer should generally provide a void (no argument) and collection
- * constructor, as per the recommendation in the Collection interface
- * specification.
- *
- * Unlike the other abstract collection implementations, the programmer does
- * not have to provide an iterator implementation; the iterator and
- * list iterator are implemented by this class, on top the "random access"
- * methods: get(int index), set(int index, Object element),
- * set(int index, Object element), add(int index, Object
- * element) and remove(int index).
- *
- * The documentation for each non-abstract methods in this class describes its
- * implementation in detail. Each of these methods may be overridden if the
- * collection being implemented admits a more efficient implementation.
- *
- * @author Josh Bloch
- * @version 1.31, 02/02/00
- * @see Collection
- * @see List
- * @see AbstractSequentialList
- * @see AbstractCollection
- * @since 1.2
- */
+/** Retained ODB compatibility name for an indexed list skeleton. */
+public abstract class MyAbstractList extends MyAbstractCollection
+ implements List {
+ protected transient int modCount = 0;
-public abstract class MyAbstractList extends MyAbstractCollection implements List {
- /**
- * Sole constructor. (For invocation by subclass constructors, typically
- * implicit.)
- */
protected MyAbstractList() {
}
- /**
- * Appends the specified element to the end of this List (optional
- * operation).
- *
- * This implementation calls add(size(), o).
- *
- * Note that this implementation throws an
- * UnsupportedOperationException unless add(int, Object)
- * is overridden.
- *
- * @param o element to be appended to this list.
- *
- * @return true (as per the general contract of
- * Collection.add).
- *
- * @throws UnsupportedOperationException if the add method is not
- * supported by this Set.
- *
- * @throws ClassCastException if the class of the specified element
- * prevents it from being added to this set.
- *
- * @throws IllegalArgumentException some aspect of this element prevents
- * it from being added to this collection.
- */
- public boolean add(Object o) {
- add(size(), o);
- return true;
+ public abstract Object get(int index);
+
+ public boolean add(Object value) {
+ add(size(), value);
+ return true;
}
- /**
- * Returns the element at the specified position in this list.
- *
- * @param index index of element to return.
- *
- * @return the element at the specified position in this list.
- * @throws IndexOutOfBoundsException if the given index is out of range
- * (index < 0 || index >= size()).
- */
- abstract public Object get(int index);
-
- /**
- * Replaces the element at the specified position in this list with the
- * specified element (optional operation).
- *
- * This implementation always throws an
- * UnsupportedOperationException.
- *
- * @param index index of element to replace.
- * @param element element to be stored at the specified position.
- * @return the element previously at the specified position.
- *
- * @throws UnsupportedOperationException if the set method is not
- * supported by this List.
- * @throws ClassCastException if the class of the specified element
- * prevents it from being added to this list.
- * @throws IllegalArgumentException if some aspect of the specified
- * element prevents it from being added to this list.
- *
- * @throws IndexOutOfBoundsException if the specified index is out of
- * range (index < 0 || index >= size()).
- */
-
- public Object set(int index, Object element) {
- throw new UnsupportedOperationException();
+ public Object set(int index, Object value) {
+ throw new UnsupportedOperationException();
}
- /**
- * Inserts the specified element at the specified position in this list
- * (optional operation). Shifts the element currently at that position
- * (if any) and any subsequent elements to the right (adds one to their
- * indices).
- *
- * This implementation always throws an UnsupportedOperationException.
- *
- * @param index index at which the specified element is to be inserted.
- * @param element element to be inserted.
- *
- * @throws UnsupportedOperationException if the add method is not
- * supported by this list.
- * @throws ClassCastException if the class of the specified element
- * prevents it from being added to this list.
- * @throws IllegalArgumentException if some aspect of the specified
- * element prevents it from being added to this list.
- * @throws IndexOutOfBoundsException index is out of range (index <
- * 0 || index > size()).
- */
- public void add(int index, Object element) {
- throw new UnsupportedOperationException();
+ public void add(int index, Object value) {
+ throw new UnsupportedOperationException();
}
- /**
- * Removes the element at the specified position in this list (optional
- * operation). Shifts any subsequent elements to the left (subtracts one
- * from their indices). Returns the element that was removed from the
- * list.
- *
- * This implementation always throws an
- * UnsupportedOperationException.
- *
- * @param index the index of the element to remove.
- * @return the element previously at the specified position.
- *
- * @throws UnsupportedOperationException if the remove method is
- * not supported by this list.
- * @throws IndexOutOfBoundsException if the specified index is out of
- * range (index < 0 || index >= size()).
- */
public Object remove(int index) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException();
}
-
- // Search Operations
-
- /**
- * Returns the index in this list of the first occurence of the specified
- * element, or -1 if the list does not contain this element. More
- * formally, returns the lowest index i such that (o==null ?
- * get(i)==null : o.equals(get(i))), or -1 if there is no such
- * index.
- *
- * This implementation first gets a list iterator (with
- * listIterator()). Then, it iterates over the list until the
- * specified element is found or the end of the list is reached.
- *
- * @param o element to search for.
- *
- * @return the index in this List of the first occurence of the specified
- * element, or -1 if the List does not contain this element.
- */
- public int indexOf(Object o) {
- ListIterator e = listIterator();
- if (o==null) {
- while (e.hasNext())
- if (e.next()==null)
- return e.previousIndex();
- } else {
- while (e.hasNext())
- if (o.equals(e.next()))
- return e.previousIndex();
- }
- return -1;
+ public int indexOf(Object value) {
+ ListIterator iterator = listIterator();
+ while (iterator.hasNext()) {
+ Object candidate = iterator.next();
+ if (value == null ? candidate == null : value.equals(candidate)) {
+ return iterator.previousIndex();
+ }
+ }
+ return -1;
}
- /**
- * Returns the index in this list of the last occurence of the specified
- * element, or -1 if the list does not contain this element. More
- * formally, returns the highest index i such that (o==null ?
- * get(i)==null : o.equals(get(i))), or -1 if there is no such
- * index.
- *
- * This implementation first gets a list iterator that points to the end
- * of the list (with listIterator(size())). Then, it iterates backwards
- * over the list until the specified element is found, or the beginning of
- * the list is reached.
- *
- * @param o element to search for.
- *
- * @return the index in this list of the last occurence of the specified
- * element, or -1 if the list does not contain this element.
- */
- public int lastIndexOf(Object o) {
- ListIterator e = listIterator(size());
- if (o==null) {
- while (e.hasPrevious())
- if (e.previous()==null)
- return e.nextIndex();
- } else {
- while (e.hasPrevious())
- if (o.equals(e.previous()))
- return e.nextIndex();
- }
- return -1;
+ public int lastIndexOf(Object value) {
+ ListIterator iterator = listIterator(size());
+ while (iterator.hasPrevious()) {
+ Object candidate = iterator.previous();
+ if (value == null ? candidate == null : value.equals(candidate)) {
+ return iterator.nextIndex();
+ }
+ }
+ return -1;
}
-
- // Bulk Operations
-
- /**
- * Removes all of the elements from this collection (optional operation).
- * The collection will be empty after this call returns (unless it throws
- * an exception).
- *
- * This implementation calls removeRange(0, size()).
- *
- * Note that this implementation throws an
- * UnsupportedOperationException unless remove(int
- * index) or removeRange(int fromIndex, int toIndex) is
- * overridden.
- *
- * @throws UnsupportedOperationException if the clear method is
- * not supported by this Collection.
- */
public void clear() {
removeRange(0, size());
}
- /**
- * Inserts all of the elements in the specified collection into this list
- * at the specified position (optional operation). Shifts the element
- * currently at that position (if any) and any subsequent elements to the
- * right (increases their indices). The new elements will appear in the
- * list in the order that they are returned by the specified collection's
- * iterator. The behavior of this operation is unspecified if the
- * specified collection is modified while the operation is in progress.
- * (Note that this will occur if the specified collection is this list,
- * and it's nonempty.)
- *
- * This implementation gets an iterator over the specified collection and
- * iterates over it, inserting the elements obtained from the iterator
- * into this list at the appropriate position, one at a time, using
- * add(int, Object). Many implementations will override this
- * method for efficiency.
- *
- * Note that this implementation throws an
- * UnsupportedOperationException unless add(int, Object)
- * is overridden.
- *
- * @return true if this list changed as a result of the call.
- * @param index index at which to insert the first element from the
- * specified collection.
- * @param c elements to be inserted into this List.
- *
- * @throws UnsupportedOperationException if the addAll method is
- * not supported by this list.
- *
- * @throws ClassCastException if the class of an element of the specified
- * collection prevents it from being added to this List.
- *
- * @throws IllegalArgumentException some aspect an element of the
- * specified collection prevents it from being added to this
- * List.
- *
- * @throws IndexOutOfBoundsException index out of range (index < 0
- * || index > size()).
- */
- public boolean addAll(int index, Collection c) {
- boolean modified = false;
- Iterator e = c.iterator();
- while (e.hasNext()) {
- add(index++, e.next());
- modified = true;
- }
- return modified;
+ public boolean addAll(int index, Collection collection) {
+ rangeCheckForAdd(index);
+ boolean changed = false;
+ for (Object value : collection) {
+ add(index++, value);
+ changed = true;
+ }
+ return changed;
}
-
- // Iterators
-
- /**
- * Returns an iterator over the elements in this list in proper
- * sequence.
- *
- * This implementation returns a straightforward implementation of the
- * iterator interface, relying on the backing list's size(),
- * get(int), and remove(int) methods.
- *
- * Note that the iterator returned by this method will throw an
- * UnsupportedOperationException in response to its
- * remove method unless the list's remove(int) method is
- * overridden.
- *
- * This implementation can be made to throw runtime exceptions in the face
- * of concurrent modification, as described in the specification for the
- * (protected) modCount field.
- *
- * @return an iterator over the elements in this list in proper sequence.
- *
- * @see #modCount
- */
public Iterator iterator() {
- return new Itr();
+ return listIterator();
}
- /**
- * Returns an iterator of the elements in this list (in proper sequence).
- * This implementation returns listIterator(0).
- *
- * @return an iterator of the elements in this list (in proper sequence).
- *
- * @see #listIterator(int)
- */
public ListIterator listIterator() {
- return listIterator(0);
+ return listIterator(0);
}
- /**
- * Returns a list iterator of the elements in this list (in proper
- * sequence), starting at the specified position in the list. The
- * specified index indicates the first element that would be returned by
- * an initial call to the next method. An initial call to
- * the previous method would return the element with the
- * specified index minus one.
- *
- * This implementation returns a straightforward implementation of the
- * ListIterator interface that extends the implementation of the
- * Iterator interface returned by the iterator() method.
- * The ListIterator implementation relies on the backing list's
- * get(int), set(int, Object), add(int, Object)
- * and remove(int) methods.
- *
- * Note that the list iterator returned by this implementation will throw
- * an UnsupportedOperationException in response to its
- * remove, set and add methods unless the
- * list's remove(int), set(int, Object), and
- * add(int, Object) methods are overridden.
- *
- * This implementation can be made to throw runtime exceptions in the
- * face of concurrent modification, as described in the specification for
- * the (protected) modCount field.
- *
- * @param index index of the first element to be returned from the list
- * iterator (by a call to the next method).
- *
- * @return a list iterator of the elements in this list (in proper
- * sequence), starting at the specified position in the list.
- *
- * @throws IndexOutOfBoundsException if the specified index is out of
- * range (index < 0 || index > size()).
- *
- * @see #modCount
- */
public ListIterator listIterator(final int index) {
- if (index<0 || index>size())
- throw new IndexOutOfBoundsException("Index: "+index);
+ rangeCheckForAdd(index);
+ return new ListIterator() {
+ private int cursor = index;
+ private int lastReturned = -1;
+ private int expectedModCount = modCount;
- return new ListItr(index);
- }
+ public boolean hasNext() { return cursor < size(); }
+ public boolean hasPrevious() { return cursor > 0; }
+ public int nextIndex() { return cursor; }
+ public int previousIndex() { return cursor - 1; }
- private class Itr implements Iterator {
- /**
- * Index of element to be returned by subsequent call to next.
- */
- int cursor = 0;
-
- /**
- * Index of element returned by most recent call to next or
- * previous. Reset to -1 if this element is deleted by a call
- * to remove.
- */
- int lastRet = -1;
-
- /**
- * The modCount value that the iterator believes that the backing
- * List should have. If this expectation is violated, the iterator
- * has detected concurrent modification.
- */
- int expectedModCount = modCount;
-
- public boolean hasNext() {
- return cursor != size();
- }
-
- public Object next() {
- try {
- Object next = get(cursor);
- checkForComodification();
- lastRet = cursor++;
- return next;
- } catch(IndexOutOfBoundsException e) {
- checkForComodification();
- throw new NoSuchElementException();
- }
- }
-
- public void remove() {
- if (lastRet == -1)
- throw new IllegalStateException();
- checkForComodification();
-
- try {
- MyAbstractList.this.remove(lastRet);
- if (lastRet < cursor)
- cursor--;
- lastRet = -1;
- expectedModCount = modCount;
- } catch(IndexOutOfBoundsException e) {
- throw new ConcurrentModificationException();
- }
- }
-
- final void checkForComodification() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- }
- }
+ public Object next() {
+ checkForComodification();
+ if (!hasNext()) throw new NoSuchElementException();
+ Object value = get(cursor);
+ lastReturned = cursor++;
+ return value;
+ }
- private class ListItr extends Itr implements ListIterator {
- ListItr(int index) {
- cursor = index;
- }
-
- public boolean hasPrevious() {
- return cursor != 0;
- }
-
- public Object previous() {
- try {
- Object previous = get(--cursor);
- checkForComodification();
- lastRet = cursor;
- return previous;
- } catch(IndexOutOfBoundsException e) {
- checkForComodification();
- throw new NoSuchElementException();
- }
- }
-
- public int nextIndex() {
- return cursor;
- }
-
- public int previousIndex() {
- return cursor-1;
- }
-
- public void set(Object o) {
- if (lastRet == -1)
- throw new IllegalStateException();
- checkForComodification();
-
- try {
- MyAbstractList.this.set(lastRet, o);
- expectedModCount = modCount;
- } catch(IndexOutOfBoundsException e) {
- throw new ConcurrentModificationException();
- }
- }
-
- public void add(Object o) {
- checkForComodification();
-
- try {
- MyAbstractList.this.add(cursor++, o);
- lastRet = -1;
- expectedModCount = modCount;
- } catch(IndexOutOfBoundsException e) {
- throw new ConcurrentModificationException();
- }
- }
+ public Object previous() {
+ checkForComodification();
+ if (!hasPrevious()) throw new NoSuchElementException();
+ Object value = get(--cursor);
+ lastReturned = cursor;
+ return value;
+ }
+
+ public void remove() {
+ checkForComodification();
+ if (lastReturned < 0) throw new IllegalStateException();
+ MyAbstractList.this.remove(lastReturned);
+ if (lastReturned < cursor) cursor--;
+ lastReturned = -1;
+ expectedModCount = modCount;
+ }
+
+ public void set(Object value) {
+ checkForComodification();
+ if (lastReturned < 0) throw new IllegalStateException();
+ MyAbstractList.this.set(lastReturned, value);
+ }
+
+ public void add(Object value) {
+ checkForComodification();
+ MyAbstractList.this.add(cursor++, value);
+ lastReturned = -1;
+ expectedModCount = modCount;
+ }
+
+ private void checkForComodification() {
+ if (expectedModCount != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ };
}
- /**
- * Returns a view of the portion of this list between fromIndex,
- * inclusive, and toIndex, exclusive. (If fromIndex and
- * toIndex are equal, the returned list is empty.) The returned
- * list is backed by this list, so changes in the returned list are
- * reflected in this list, and vice-versa. The returned list supports all
- * of the optional list operations supported by this list.
- *
- * This method eliminates the need for explicit range operations (of the
- * sort that commonly exist for arrays). Any operation that expects a
- * list can be used as a range operation by operating on a subList view
- * instead of a whole list. For example, the following idiom removes a
- * range of elements from a list:
- *
- *
- * The semantics of the list returned by this method become undefined if
- * the backing list (i.e., this list) is structurally modified in
- * any way other than via the returned list. (Structural modifications are
- * those that change the size of the list, or otherwise perturb it in such
- * a fashion that iterations in progress may yield incorrect results.)
- *
- * This implementation returns a list that subclasses
- * MyAbstractList. The subclass stores, in private fields, the
- * offset of the subList within the backing list, the size of the subList
- * (which can change over its lifetime), and the expected
- * modCount value of the backing list.
- *
- * The subclass's set(int, Object), get(int),
- * add(int, Object), remove(int), addAll(int,
- * Collection) and removeRange(int, int) methods all
- * delegate to the corresponding methods on the backing abstract list,
- * after bounds-checking the index and adjusting for the offset. The
- * addAll(Collection c) method merely returns addAll(size,
- * c).
- *
- * The listIterator(int) method returns a "wrapper object" over a
- * list iterator on the backing list, which is created with the
- * corresponding method on the backing list. The iterator method
- * merely returns listIterator(), and the size method
- * merely returns the subclass's size field.
- *
- * All methods first check to see if the actual modCount of the
- * backing list is equal to its expected value, and throw a
- * ConcurrentModificationException if it is not.
- *
- * @param fromIndex low endpoint (inclusive) of the subList.
- * @param toIndex high endpoint (exclusive) of the subList.
- * @return a view of the specified range within this list.
- * @throws IndexOutOfBoundsException endpoint index value out of range
- * (fromIndex < 0 || toIndex > size)
- * @throws IllegalArgumentException endpoint indices out of order
- * (fromIndex > toIndex) */
public List subList(int fromIndex, int toIndex) {
return new SubList(this, fromIndex, toIndex);
}
- // Comparison and hashing
-
- /**
- * Compares the specified object with this list for equality. Returns
- * true if and only if the specified object is also a list, both
- * lists have the same size, and all corresponding pairs of elements in
- * the two lists are equal. (Two elements e1 and
- * e2 are equal if (e1==null ? e2==null :
- * e1.equals(e2)).) In other words, two lists are defined to be
- * equal if they contain the same elements in the same order.
- *
- * This implementation first checks if the specified object is this
- * list. If so, it returns true; if not, it checks if the
- * specified object is a list. If not, it returns false; if so,
- * it iterates over both lists, comparing corresponding pairs of elements.
- * If any comparison returns false, this method returns
- * false. If either iterator runs out of elements before the
- * other it returns false (as the lists are of unequal length);
- * otherwise it returns true when the iterations complete.
- *
- * @param o the object to be compared for equality with this list.
- *
- * @return true if the specified object is equal to this list.
- */
- public boolean equals(Object o) {
- if (o == this)
- return true;
- if (!(o instanceof List))
- return false;
-
- ListIterator e1 = listIterator();
- ListIterator e2 = ((List) o).listIterator();
- while(e1.hasNext() && e2.hasNext()) {
- Object o1 = e1.next();
- Object o2 = e2.next();
- if (!(o1==null ? o2==null : o1.equals(o2)))
- return false;
- }
- return !(e1.hasNext() || e2.hasNext());
+ public boolean equals(Object other) {
+ if (other == this) return true;
+ if (!(other instanceof List)) return false;
+ Iterator left = iterator();
+ Iterator right = ((List) other).iterator();
+ while (left.hasNext() && right.hasNext()) {
+ Object a = left.next();
+ Object b = right.next();
+ if (!(a == null ? b == null : a.equals(b))) return false;
+ }
+ return !left.hasNext() && !right.hasNext();
}
- /**
- * Returns the hash code value for this list.
- *
- * This implementation uses exactly the code that is used to define the
- * list hash function in the documentation for the List.hashCode
- * method.
- *
- * @return the hash code value for this list.
- */
public int hashCode() {
- int hashCode = 1;
- Iterator i = iterator();
- while (i.hasNext()) {
- Object obj = i.next();
- hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
- }
- return hashCode;
+ int hash = 1;
+ for (Object value : this) {
+ hash = 31 * hash + (value == null ? 0 : value.hashCode());
+ }
+ return hash;
}
- /**
- * Removes from this list all of the elements whose index is between
- * fromIndex, inclusive, and toIndex, exclusive.
- * Shifts any succeeding elements to the left (reduces their index). This
- * call shortens the ArrayList by (toIndex - fromIndex)
- * elements. (If toIndex==fromIndex, this operation has no
- * effect.)
- *
- * This method is called by the clear operation on this list
- * and its subLists. Overriding this method to take advantage of
- * the internals of the list implementation can substantially
- * improve the performance of the clear operation on this list
- * and its subLists.
- *
- * This implementation gets a list iterator positioned before
- * fromIndex, and repeatedly calls ListIterator.next
- * followed by ListIterator.remove until the entire range has
- * been removed. Note: if ListIterator.remove requires linear
- * time, this implementation requires quadratic time.
- *
- * @param fromIndex index of first element to be removed.
- * @param toIndex index after last element to be removed.
- */
protected void removeRange(int fromIndex, int toIndex) {
- ListIterator it = listIterator(fromIndex);
- for (int i=0, n=toIndex-fromIndex; i
- *
- * This field is used by the iterator and list iterator implementation
- * returned by the iterator and listIterator methods.
- * If the value of this field changes unexpectedly, the iterator (or list
- * iterator) will throw a ConcurrentModificationException in
- * response to the next, remove, previous,
- * set or add operations. This provides
- * fail-fast behavior, rather than non-deterministic behavior in
- * the face of concurrent modification during iteration.
- *
- * Use of this field by subclasses is optional. If a subclass
- * wishes to provide fail-fast iterators (and list iterators), then it
- * merely has to increment this field in its add(int, Object) and
- * remove(int) methods (and any other methods that it overrides
- * that result in structural modifications to the list). A single call to
- * add(int, Object) or remove(int) must add no more than
- * one to this field, or the iterators (and list iterators) will throw
- * bogus ConcurrentModificationExceptions. If an implementation
- * does not wish to provide fail-fast iterators, this field may be
- * ignored.
- */
- protected transient int modCount = 0;
+ private void rangeCheckForAdd(int index) {
+ if (index < 0 || index > size()) {
+ throw new IndexOutOfBoundsException(
+ "Index: " + index + ", Size: " + size());
+ }
+ }
}
+/** Retained package-level compatibility type for historic callers. */
class SubList extends MyAbstractList {
- private MyAbstractList l;
- private int offset;
- private int size;
- private int expectedModCount;
+ private final MyAbstractList parent;
+ private final int offset;
+ private int length;
+ private int expectedParentModCount;
SubList(MyAbstractList list, int fromIndex, int toIndex) {
- if (fromIndex < 0)
- throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
- if (toIndex > list.size())
- throw new IndexOutOfBoundsException("toIndex = " + toIndex);
- if (fromIndex > toIndex)
- throw new IllegalArgumentException("fromIndex(" + fromIndex +
- ") > toIndex(" + toIndex + ")");
- l = list;
+ if (fromIndex < 0 || toIndex > list.size()) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (fromIndex > toIndex) {
+ throw new IllegalArgumentException();
+ }
+ parent = list;
offset = fromIndex;
- size = toIndex - fromIndex;
- expectedModCount = l.modCount;
- }
-
- public Object set(int index, Object element) {
- rangeCheck(index);
- checkForComodification();
- return l.set(index+offset, element);
+ length = toIndex - fromIndex;
+ expectedParentModCount = parent.modCount;
}
public Object get(int index) {
rangeCheck(index);
checkForComodification();
- return l.get(index+offset);
+ return parent.get(offset + index);
}
public int size() {
checkForComodification();
- return size;
+ return length;
}
- public void add(int index, Object element) {
- if (index<0 || index>size)
- throw new IndexOutOfBoundsException();
- checkForComodification();
- l.add(index+offset, element);
- expectedModCount = l.modCount;
- size++;
- modCount++;
- }
-
- public Object remove(int index) {
+ public Object set(int index, Object value) {
rangeCheck(index);
checkForComodification();
- Object result = l.remove(index+offset);
- expectedModCount = l.modCount;
- size--;
- modCount++;
- return result;
+ return parent.set(offset + index, value);
}
- protected void removeRange(int fromIndex, int toIndex) {
+ public void add(int index, Object value) {
+ if (index < 0 || index > length) throw new IndexOutOfBoundsException();
checkForComodification();
- l.removeRange(fromIndex+offset, toIndex+offset);
- expectedModCount = l.modCount;
- size -= (toIndex-fromIndex);
- modCount++;
+ parent.add(offset + index, value);
+ length++;
+ modified();
}
- public boolean addAll(Collection c) {
- return addAll(size, c);
- }
-
- public boolean addAll(int index, Collection c) {
- if (index<0 || index>size)
- throw new IndexOutOfBoundsException(
- "Index: "+index+", Size: "+size);
- int cSize = c.size();
- if (cSize==0)
- return false;
-
+ public Object remove(int index) {
+ rangeCheck(index);
checkForComodification();
- l.addAll(offset+index, c);
- expectedModCount = l.modCount;
- size += cSize;
- modCount++;
- return true;
+ Object removed = parent.remove(offset + index);
+ length--;
+ modified();
+ return removed;
}
- public Iterator iterator() {
- return listIterator();
+ public boolean addAll(Collection collection) {
+ return addAll(length, collection);
}
- public ListIterator listIterator(final int index) {
+ public boolean addAll(int index, Collection collection) {
+ if (index < 0 || index > length) throw new IndexOutOfBoundsException();
checkForComodification();
- if (index<0 || index>size)
- throw new IndexOutOfBoundsException(
- "Index: "+index+", Size: "+size);
-
- return new ListIterator() {
- private ListIterator i = l.listIterator(index+offset);
-
- public boolean hasNext() {
- return nextIndex() < size;
- }
-
- public Object next() {
- if (hasNext())
- return i.next();
- else
- throw new NoSuchElementException();
- }
-
- public boolean hasPrevious() {
- return previousIndex() >= 0;
- }
-
- public Object previous() {
- if (hasPrevious())
- return i.previous();
- else
- throw new NoSuchElementException();
- }
-
- public int nextIndex() {
- return i.nextIndex() - offset;
- }
-
- public int previousIndex() {
- return i.previousIndex() - offset;
- }
-
- public void remove() {
- i.remove();
- expectedModCount = l.modCount;
- size--;
- modCount++;
- }
-
- public void set(Object o) {
- i.set(o);
- }
-
- public void add(Object o) {
- i.add(o);
- expectedModCount = l.modCount;
- size++;
- modCount++;
- }
- };
- }
-
- public List subList(int fromIndex, int toIndex) {
- return new SubList(this, fromIndex, toIndex);
+ if (collection.isEmpty()) return false;
+ parent.addAll(offset + index, collection);
+ length += collection.size();
+ modified();
+ return true;
}
private void rangeCheck(int index) {
- if (index<0 || index>=size)
- throw new IndexOutOfBoundsException("Index: "+index+
- ",Size: "+size);
+ if (index < 0 || index >= length) throw new IndexOutOfBoundsException();
}
private void checkForComodification() {
- if (l.modCount != expectedModCount)
+ if (parent.modCount != expectedParentModCount) {
throw new ConcurrentModificationException();
+ }
}
-}
+ private void modified() {
+ expectedParentModCount = parent.modCount;
+ modCount++;
+ }
+}
diff --git a/src/main/java/com/lambda/Debugger/MyCollections.java b/src/main/java/com/lambda/Debugger/MyCollections.java
index 9a0cd6d..ef0d77c 100644
--- a/src/main/java/com/lambda/Debugger/MyCollections.java
+++ b/src/main/java/com/lambda/Debugger/MyCollections.java
@@ -1,1709 +1,112 @@
-/* MyCollections.java
-
- Copyright 2003, Bil Lewis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-/*
- * @(#)MyCollections.java 1.34 99/04/22
+ /*
+ * Copyright 2003, Bil Lewis
*
- * Copyright 1997-1999 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
*/
-
-//package java.util;
package com.lambda.Debugger;
-import java.util.*;
-import java.io.Serializable;
-
-/**
- * This class consists exclusively of static methods that operate on or return
- * collections. It contains polymorphic algorithms that operate on
- * collections, "wrappers", which return a new collection backed by a
- * specified collection, and a few other odds and ends.
- *
- * The documentation for the polymorphic algorithms contained in this class
- * generally includes a brief description of the implementation. Such
- * descriptions should be regarded as implementation notes, rather than
- * parts of the specification. Implementors should feel free to
- * substitute other algorithms, so long as the specification itself is adhered
- * to. (For example, the algorithm used by sort does not have to be
- * a mergesort, but it does have to be stable.)
- *
- * @author Josh Bloch
- * @version 1.34 04/22/99
- * @see Collection
- * @see Set
- * @see List
- * @see Map
- * @since JDK1.2
- */
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+
+/** Retained ODB compatibility facade over {@link Collections}. */
public class MyCollections {
- // Suppresses default constructor, ensuring non-instantiability.
- private MyCollections() {
- }
-
- // Algorithms
+ public static final Set EMPTY_SET = Collections.EMPTY_SET;
+ public static final List EMPTY_LIST = Collections.EMPTY_LIST;
- /**
- * Sorts the specified list into ascending order, according to the
- * natural ordering of its elements. All elements in the list must
- * implement the Comparable interface. Furthermore, all elements
- * in the list must be mutually comparable (that is,
- * e1.compareTo(e2) must not throw a ClassCastException
- * for any elements e1 and e2 in the list).
- *
- * This sort is guaranteed to be stable: equal elements will
- * not be reordered as a result of the sort.
- *
- * The specified list must be modifiable, but need not be resizable.
- *
- * The sorting algorithm is a modified mergesort (in which the merge is
- * omitted if the highest element in the low sublist is less than the
- * lowest element in the high sublist). This algorithm offers guaranteed
- * n log(n) performance, and can approach linear performance on nearly
- * sorted lists.
- *
- * This implementation dumps the specified list into an array, sorts
- * the array, and iterates over the list resetting each element
- * from the corresponding position in the array. This avoids the
- * n2 log(n) performance that would result from attempting
- * to sort a linked list in place.
- *
- * @param list the list to be sorted.
- * @throws ClassCastException if the list contains elements that are not
- * mutually comparable (for example, strings and integers).
- * @throws UnsupportedOperationException if the specified list's
- * list-iterator does not support the set operation.
- * @see Comparable
- */
- public static void sort(List list) {
- Object a[] = list.toArray();
- Arrays.sort(a);
- ListIterator i = list.listIterator();
- for (int j=0; j
- *
- * This sort is guaranteed to be stable: equal elements will
- * not be reordered as a result of the sort.
- *
- * The sorting algorithm is a modified mergesort (in which the merge is
- * omitted if the highest element in the low sublist is less than the
- * lowest element in the high sublist). This algorithm offers guaranteed
- * n log(n) performance, and can approach linear performance on nearly
- * sorted lists.
- *
- * The specified list must be modifiable, but need not be resizable.
- * This implementation dumps the specified list into an array, sorts
- * the array, and iterates over the list resetting each element
- * from the corresponding position in the array. This avoids the
- * n2 log(n) performance that would result from attempting
- * to sort a linked list in place.
- *
- * @param list the list to be sorted.
- * @param c the comparator to determine the order of the array.
- * @throws ClassCastException if the list contains elements that are not
- * mutually comparable using the specified comparator.
- * @throws UnsupportedOperationException if the specified list's
- * list-iterator does not support the set operation.
- * @see Comparator
- */
- public static void sort(List list, Comparator c) {
- Object a[] = list.toArray();
- Arrays.sort(a, c);
- ListIterator i = list.listIterator();
- for (int j=0; j
- *
- * This method runs in log(n) time for a "random access" list (which
- * provides near-constant-time positional access). It may
- * run in n log(n) time if it is called on a "sequential access" list
- * (which provides linear-time positional access).
- *
- * This method runs in log(n) time for a "random access" list (which
- * provides near-constant-time positional access). It may
- * run in n log(n) time if it is called on a "sequential access" list
- * (which provides linear-time positional access).
- *
- * This method runs in linear time.
- * @param l the list whose elements are to be reversed.
- * @throws UnsupportedOperationException if the specified list's
- * list-iterator does not support the set operation.
- */
- public static void reverse(List l) {
- ListIterator fwd = l.listIterator(), rev = l.listIterator(l.size());
- for (int i=0, n=l.size()/2; i
- *
- * This implementation traverses the list backwards, from the last element
- * up to the second, repeatedly swapping a randomly selected element into
- * the "current position". Elements are randomly selected from the
- * portion of the list that runs from the first element to the current
- * position, inclusive.
- *
- * This method runs in linear time for a "random access" list (which
- * provides near-constant-time positional access). It may require
- * quadratic time for a "sequential access" list.
- *
- * @param list the list to be shuffled.
- * @throws UnsupportedOperationException if the specified list's
- * list-iterator does not support the set operation.
- */
- public static void shuffle(List list) {
- shuffle(list, r);
- }
- private static Random r = new Random();
-
- /**
- * Randomly permute the specified list using the specified source of
- * randomness. All permutations occur with equal likelihood
- * assuming that the source of randomness is fair.
- *
- * This implementation traverses the list backwards, from the last element
- * up to the second, repeatedly swapping a randomly selected element into
- * the "current position". Elements are randomly selected from the
- * portion of the list that runs from the first element to the current
- * position, inclusive.
- *
- * This method runs in linear time for a "random access" list (which
- * provides near-constant-time positional access). It may require
- * quadratic time for a "sequential access" list.
- *
- * @param list the list to be shuffled.
- * @param rnd the source of randomness to use to shuffle the list.
- * @throws UnsupportedOperationException if the specified list's
- * list-iterator does not support the set operation.
- */
- public static void shuffle(List list, Random rnd) {
- for (int i=list.size(); i>1; i--)
- swap(list, i-1, rnd.nextInt(i));
- }
-
- /**
- * Swaps the two specified elements in the specified list.
- */
- private static void swap(List a, int i, int j) {
- Object tmp = a.get(i);
- a.set(i, a.get(j));
- a.set(j, tmp);
- }
-
- /**
- * Replaces all of the elements of the specified list with the specified
- * element.
- *
- * This method runs in linear time.
- *
- * @param list the list to be filled with the specified element.
- * @param o The element with which to fill the specified list.
- * @throws UnsupportedOperationException if the specified list's
- * list-iterator does not support the set operation.
- */
- public static void fill(List list, Object o) {
- for (ListIterator i = list.listIterator(); i.hasNext(); ) {
- i.next();
- i.set(o);
- }
- }
-
- /**
- * Copies all of the elements from one list into another. After the
- * operation, the index of each copied element in the destination list
- * will be identical to its index in the source list. The destination
- * list must be at least as long as the source list. If it is longer, the
- * remaining elements in the destination list are unaffected.
- *
- * This method runs in linear time.
- *
- * @param dest The destination list.
- * @param src The source list.
- * @throws IndexOutOfBoundsException if the destination list is too small
- * to contain the entire source List.
- * @throws UnsupportedOperationException if the destination list's
- * list-iterator does not support the set operation.
- */
- public static void copy (List dest, List src) {
- try {
- for (ListIterator di=dest.listIterator(), si=src.listIterator();
- si.hasNext(); ) {
- di.next();
- di.set(si.next());
- }
- } catch(NoSuchElementException e) {
- throw new IndexOutOfBoundsException("Source does not fit in dest.");
- }
+ public static int binarySearch(List list, Object key,
+ Comparator comparator) {
+ return Collections.binarySearch(list, key, comparator);
}
-
- /**
- * Returns the minimum element of the given collection, according to the
- * natural ordering of its elements. All elements in the
- * collection must implement the Comparable interface.
- * Furthermore, all elements in the collection must be mutually
- * comparable (that is, e1.compareTo(e2) must not throw a
- * ClassCastException for any elements e1 and
- * e2 in the collection).
- *
- * This method iterates over the entire collection, hence it requires
- * time proportional to the size of the collection.
- *
- * @param coll the collection whose minimum element is to be determined.
- * @return the minimum element of the given collection, according
- * to the natural ordering of its elements.
- * @throws ClassCastException if the collection contains elements that are
- * not mutually comparable (for example, strings and
- * integers).
- * @throws NoSuchElementException if the collection is empty.
- * @see Comparable
- */
- public static Object min(Collection coll) {
- Iterator i = coll.iterator();
- Comparable candidate = (Comparable)(i.next());
- while (i.hasNext()) {
- Comparable next = (Comparable)(i.next());
- if (next.compareTo(candidate) < 0)
- candidate = next;
- }
- return candidate;
+ public static void reverse(List list) { Collections.reverse(list); }
+ public static void shuffle(List list) { Collections.shuffle(list); }
+ public static void shuffle(List list, Random random) {
+ Collections.shuffle(list, random);
}
-
- /**
- * Returns the minimum element of the given collection, according to the
- * order induced by the specified comparator. All elements in the
- * collection must be mutually comparable by the specified
- * comparator (that is, comp.compare(e1, e2) must not throw a
- * ClassCastException for any elements e1 and
- * e2 in the collection).
- *
- * This method iterates over the entire collection, hence it requires
- * time proportional to the size of the collection.
- *
- * @param coll the collection whose minimum element is to be determined.
- * @param comp
- * @return the minimum element of the given collection, according
- * to the specified comparator.
- * @throws ClassCastException if the collection contains elements that are
- * not mutually comparable using the specified comparator.
- * @throws NoSuchElementException if the collection is empty.
- * @see Comparable
- */
- public static Object min(Collection coll, Comparator comp) {
- Iterator i = coll.iterator();
- Object candidate = i.next();
- while (i.hasNext()) {
- Object next = i.next();
- if (comp.compare(next, candidate) < 0)
- candidate = next;
- }
- return candidate;
+ public static void fill(List list, Object value) {
+ Collections.fill(list, value);
}
-
- /**
- * Returns the maximum element of the given collection, according to the
- * natural ordering of its elements. All elements in the
- * collection must implement the Comparable interface.
- * Furthermore, all elements in the collection must be mutually
- * comparable (that is, e1.compareTo(e2) must not throw a
- * ClassCastException for any elements e1 and
- * e2 in the collection).
- *
- * This method iterates over the entire collection, hence it requires
- * time proportional to the size of the collection.
- *
- * @param coll the collection whose maximum element is to be determined.
- * @return the maximum element of the given collection, according
- * to the natural ordering of its elements.
- * @throws ClassCastException if the collection contains elements that are
- * not mutually comparable (for example, strings and
- * integers).
- * @throws NoSuchElementException if the collection is empty.
- * @see Comparable
- */
- public static Object max(Collection coll) {
- Iterator i = coll.iterator();
- Comparable candidate = (Comparable)(i.next());
- while (i.hasNext()) {
- Comparable next = (Comparable)(i.next());
- if (next.compareTo(candidate) > 0)
- candidate = next;
- }
- return candidate;
+ public static void copy(List destination, List source) {
+ Collections.copy(destination, source);
}
-
- /**
- * Returns the maximum element of the given collection, according to the
- * order induced by the specified comparator. All elements in the
- * collection must be mutually comparable by the specified
- * comparator (that is, comp.compare(e1, e2) must not throw a
- * ClassCastException for any elements e1 and
- * e2 in the collection).
- *
- * This method iterates over the entire collection, hence it requires
- * time proportional to the size of the collection.
- *
- * @param coll the collection whose maximum element is to be determined.
- * @param comp
- * @return the maximum element of the given collection, according
- * to the specified comparator.
- * @throws ClassCastException if the collection contains elements that are
- * not mutually comparable using the specified comparator.
- * @throws NoSuchElementException if the collection is empty.
- * @see Comparable
- */
- public static Object max(Collection coll, Comparator comp) {
- Iterator i = coll.iterator();
- Object candidate = i.next();
- while (i.hasNext()) {
- Object next = i.next();
- if (comp.compare(next, candidate) > 0)
- candidate = next;
- }
- return candidate;
+ public static Object min(Collection collection) {
+ return Collections.min(collection);
}
-
-
- // Unmodifiable Wrappers
-
- /**
- * Returns an unmodifiable view of the specified collection. This method
- * allows modules to provide users with "read-only" access to internal
- * collections. Query operations on the returned collection "read through"
- * to the specified collection, and attempts to modify the returned
- * collection, whether direct or via its iterator, result in an
- * UnsupportedOperationException.
- *
- * The returned collection does not pass the hashCode and equals
- * operations through to the backing collection, but relies on
- * Object's equals and hashCode methods. This
- * is necessary to preserve the contracts of these operations in the case
- * that the backing collection is a set or a list.
- *
- * The returned collection will be serializable if the specified collection
- * is serializable.
- *
- * @param c the collection for which an unmodifiable view is to be
- * returned.
- * @return an unmodifiable view of the specified collection.
- */
- public static Collection unmodifiableCollection(Collection c) {
- return new UnmodifiableCollection(c);
+ public static Object min(Collection collection, Comparator comparator) {
+ return Collections.min(collection, comparator);
}
-
- static class UnmodifiableCollection implements Collection, Serializable {
- Collection c;
-
- UnmodifiableCollection(Collection c) {this.c = c;}
-
- public int size() {return c.size();}
- public boolean isEmpty() {return c.isEmpty();}
- public boolean contains(Object o) {return c.contains(o);}
- public Object[] toArray() {return c.toArray();}
- public Object[] toArray(Object[] a) {return c.toArray(a);}
-
- public Iterator iterator() {
- return new Iterator() {
- Iterator i = c.iterator();
-
- public boolean hasNext() {return i.hasNext();}
- public Object next() {return i.next();}
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- public boolean add(Object o){
- throw new UnsupportedOperationException();
- }
- public boolean remove(Object o) {
- throw new UnsupportedOperationException();
- }
-
- public boolean containsAll(Collection coll) {
- return c.containsAll(coll);
- }
- public boolean addAll(Collection coll) {
- throw new UnsupportedOperationException();
- }
- public boolean removeAll(Collection coll) {
- throw new UnsupportedOperationException();
- }
- public boolean retainAll(Collection coll) {
- throw new UnsupportedOperationException();
- }
- public void clear() {
- throw new UnsupportedOperationException();
- }
+ public static Object max(Collection collection) {
+ return Collections.max(collection);
}
-
- /**
- * Returns an unmodifiable view of the specified set. This method allows
- * modules to provide users with "read-only" access to internal sets.
- * Query operations on the returned set "read through" to the specified
- * set, and attempts to modify the returned set, whether direct or via its
- * iterator, result in an UnsupportedOperationException.
- *
- * The returned set will be serializable if the specified set
- * is serializable.
- *
- * @param s the set for which an unmodifiable view is to be returned.
- * @return an unmodifiable view of the specified set.
- */
-
- public static Set unmodifiableSet(Set s) {
- return new UnmodifiableSet(s);
+ public static Object max(Collection collection, Comparator comparator) {
+ return Collections.max(collection, comparator);
}
-
- static class UnmodifiableSet extends UnmodifiableCollection
- implements Set, Serializable {
- UnmodifiableSet(Set s) {super(s);}
-
- public boolean equals(Object o) {return c.equals(o);}
- public int hashCode() {return c.hashCode();}
+ public static Collection unmodifiableCollection(Collection collection) {
+ return Collections.unmodifiableCollection(collection);
}
-
- /**
- * Returns an unmodifiable view of the specified sorted set. This method
- * allows modules to provide users with "read-only" access to internal
- * sorted sets. Query operations on the returned sorted set "read
- * through" to the specified sorted set. Attempts to modify the returned
- * sorted set, whether direct, via its iterator, or via its
- * subSet, headSet, or tailSet views, result in
- * an UnsupportedOperationException.
- *
- * The returned sorted set will be serializable if the specified sorted set
- * is serializable.
- *
- * @param s the sorted set for which an unmodifiable view is to be
- * returned.
- * @return an unmodifiable view of the specified sorted set.
- */
- public static SortedSet unmodifiableSortedSet(SortedSet s) {
- return new UnmodifiableSortedSet(s);
+ public static Set unmodifiableSet(Set set) {
+ return Collections.unmodifiableSet(set);
}
-
- static class UnmodifiableSortedSet extends UnmodifiableSet
- implements SortedSet, Serializable {
- private SortedSet ss;
-
- UnmodifiableSortedSet(SortedSet s) {super(s); ss = s;}
-
- public Comparator comparator() {return ss.comparator();}
-
- public SortedSet subSet(Object fromElement, Object toElement) {
- return new UnmodifiableSortedSet(ss.subSet(fromElement,toElement));
- }
- public SortedSet headSet(Object toElement) {
- return new UnmodifiableSortedSet(ss.headSet(toElement));
- }
- public SortedSet tailSet(Object fromElement) {
- return new UnmodifiableSortedSet(ss.tailSet(fromElement));
- }
-
- public Object first() {return ss.first();}
- public Object last() {return ss.last();}
+ public static SortedSet unmodifiableSortedSet(SortedSet set) {
+ return Collections.unmodifiableSortedSet(set);
}
-
- /**
- * Returns an unmodifiable view of the specified list. This method allows
- * modules to provide users with "read-only" access to internal
- * lists. Query operations on the returned list "read through" to the
- * specified list, and attempts to modify the returned list, whether
- * direct or via its iterator, result in an
- * UnsupportedOperationException.
- *
- * The returned list will be serializable if the specified list
- * is serializable.
- *
- * @param list the list for which an unmodifiable view is to be returned.
- * @return an unmodifiable view of the specified list.
- */
public static List unmodifiableList(List list) {
- return new UnmodifiableList(list);
- }
-
- static class UnmodifiableList extends UnmodifiableCollection
- implements List {
- private List list;
-
- UnmodifiableList(List list) {
- super(list);
- this.list = list;
- }
-
- public boolean equals(Object o) {return list.equals(o);}
- public int hashCode() {return list.hashCode();}
-
- public Object get(int index) {return list.get(index);}
- public Object set(int index, Object element) {
- throw new UnsupportedOperationException();
- }
- public void add(int index, Object element) {
- throw new UnsupportedOperationException();
- }
- public Object remove(int index) {
- throw new UnsupportedOperationException();
- }
- public int indexOf(Object o) {return list.indexOf(o);}
- public int lastIndexOf(Object o) {return list.lastIndexOf(o);}
- public boolean addAll(int index, Collection c) {
- throw new UnsupportedOperationException();
- }
- public ListIterator listIterator() {return listIterator(0);}
-
- public ListIterator listIterator(final int index) {
- return new ListIterator() {
- ListIterator i = list.listIterator(index);
-
- public boolean hasNext() {return i.hasNext();}
- public Object next() {return i.next();}
- public boolean hasPrevious() {return i.hasPrevious();}
- public Object previous() {return i.previous();}
- public int nextIndex() {return i.nextIndex();}
- public int previousIndex() {return i.previousIndex();}
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
- public void set(Object o) {
- throw new UnsupportedOperationException();
- }
- public void add(Object o) {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- public List subList(int fromIndex, int toIndex) {
- return new UnmodifiableList(list.subList(fromIndex, toIndex));
- }
- }
-
- /**
- * Returns an unmodifiable view of the specified map. This method
- * allows modules to provide users with "read-only" access to internal
- * maps. Query operations on the returned map "read through"
- * to the specified map, and attempts to modify the returned
- * map, whether direct or via its collection views, result in an
- * UnsupportedOperationException.
- *
- * The returned map will be serializable if the specified map
- * is serializable.
- *
- * @param m the map for which an unmodifiable view is to be returned.
- * @return an unmodifiable view of the specified map.
- */
- public static Map unmodifiableMap(Map m) {
- return new UnmodifiableMap(m);
- }
-
- private static class UnmodifiableMap implements Map, Serializable {
- private final Map m;
-
- UnmodifiableMap(Map m) {this.m = m;}
-
- public int size() {return m.size();}
- public boolean isEmpty() {return m.isEmpty();}
- public boolean containsKey(Object key) {return m.containsKey(key);}
- public boolean containsValue(Object val) {return m.containsValue(val);}
- public Object get(Object key) {return m.get(key);}
-
- public Object put(Object key, Object value) {
- throw new UnsupportedOperationException();
- }
- public Object remove(Object key) {
- throw new UnsupportedOperationException();
- }
- public void putAll(Map t) {
- throw new UnsupportedOperationException();
- }
- public void clear() {
- throw new UnsupportedOperationException();
- }
-
- private transient Set keySet = null;
- private transient Set entrySet = null;
- private transient Collection values = null;
-
- public Set keySet() {
- if (keySet==null)
- keySet = unmodifiableSet(m.keySet());
- return keySet;
- }
-
- public Set entrySet() {
- if (entrySet==null)
- entrySet = new UnmodifiableEntrySet(m.entrySet());
- return entrySet;
- }
-
- public Collection values() {
- if (values==null)
- values = unmodifiableCollection(m.values());
- return values;
- }
-
- public boolean equals(Object o) {return m.equals(o);}
- public int hashCode() {return m.hashCode();}
-
-
- /**
- * We need this class in addition to UnmodifiableSet as
- * Map.Entries themselves permit modification of the backing Map
- * via their setValue operation. This class is subtle: there are
- * many possible attacks that must be thwarted.
- */
- static class UnmodifiableEntrySet extends UnmodifiableSet {
- UnmodifiableEntrySet(Set s) {
- super(s);
- }
-
- public Iterator iterator() {
- return new Iterator() {
- Iterator i = c.iterator();
-
- public boolean hasNext() {
- return i.hasNext();
- }
- public Object next() {
- return new UnmodifiableEntry((Map.Entry)i.next());
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- public Object[] toArray() {
- Object[] a = c.toArray();
- for (int i=0; i
- *
- * The returned sorted map will be serializable if the specified sorted map
- * is serializable.
- *
- * @param m the sorted map for which an unmodifiable view is to be
- * returned.
- * @return an unmodifiable view of the specified sorted map.
- */
- public static SortedMap unmodifiableSortedMap(SortedMap m) {
- return new UnmodifiableSortedMap(m);
- }
-
- static class UnmodifiableSortedMap extends UnmodifiableMap
- implements SortedMap, Serializable {
- private SortedMap sm;
-
- UnmodifiableSortedMap(SortedMap m) {super(m); sm = m;}
-
- public Comparator comparator() {return sm.comparator();}
-
- public SortedMap subMap(Object fromKey, Object toKey) {
- return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey));
- }
- public SortedMap headMap(Object toKey) {
- return new UnmodifiableSortedMap(sm.headMap(toKey));
- }
- public SortedMap tailMap(Object fromKey) {
- return new UnmodifiableSortedMap(sm.tailMap(fromKey));
- }
-
- public Object firstKey() {return sm.firstKey();}
- public Object lastKey() {return sm.lastKey();}
- }
-
-
- // Synch Wrappers
-
- /**
- * Returns a synchronized (thread-safe) collection backed by the specified
- * collection. In order to guarantee serial access, it is critical that
- * all access to the backing collection is accomplished
- * through the returned collection.
- *
- * It is imperative that the user manually synchronize on the returned
- * collection when iterating over it:
- * The returned collection does not pass the hashCode
- * and equals operations through to the backing collection, but
- * relies on Object's equals and hashCode methods. This is
- * necessary to preserve the contracts of these operations in the case
- * that the backing collection is a set or a list.
- *
- * The returned collection will be serializable if the specified collection
- * is serializable.
- *
- * @param c the collection to be "wrapped" in a synchronized collection.
- * @return a synchronized view of the specified collection.
- */
- public static Collection synchronizedCollection(Collection c) {
- return new SynchronizedCollection(c);
- }
-
- static Collection synchronizedCollection(Collection c, Object mutex) {
- return new SynchronizedCollection(c, mutex);
- }
-
- static class SynchronizedCollection implements Collection, Serializable {
- Collection c; // Backing Collection
- Object mutex; // Object on which to synchronize
-
- SynchronizedCollection(Collection c) {
- this.c = c; mutex = this;
- }
- SynchronizedCollection(Collection c, Object mutex) {
- this.c = c; this.mutex = mutex;
- }
-
- public int size() {
- synchronized(mutex) {return c.size();}
- }
- public boolean isEmpty() {
- synchronized(mutex) {return c.isEmpty();}
- }
- public boolean contains(Object o) {
- synchronized(mutex) {return c.contains(o);}
- }
- public Object[] toArray() {
- synchronized(mutex) {return c.toArray();}
- }
- public Object[] toArray(Object[] a) {
- synchronized(mutex) {return c.toArray(a);}
- }
-
- public Iterator iterator() {
- return c.iterator(); // Must be manually synched by user!
- }
-
- public boolean add(Object o) {
- synchronized(mutex) {return c.add(o);}
- }
- public boolean remove(Object o) {
- synchronized(mutex) {return c.remove(o);}
- }
-
- public boolean containsAll(Collection coll) {
- synchronized(mutex) {return c.containsAll(coll);}
- }
- public boolean addAll(Collection coll) {
- synchronized(mutex) {return c.addAll(coll);}
- }
- public boolean removeAll(Collection coll) {
- synchronized(mutex) {return c.removeAll(coll);}
- }
- public boolean retainAll(Collection coll) {
- synchronized(mutex) {return c.retainAll(coll);}
- }
- public void clear() {
- synchronized(mutex) {c.clear();}
- }
+ return Collections.unmodifiableList(list);
}
-
- /**
- * Returns a synchronized (thread-safe) set backed by the specified
- * set. In order to guarantee serial access, it is critical that
- * all access to the backing set is accomplished
- * through the returned set.
- *
- * It is imperative that the user manually synchronize on the returned
- * set when iterating over it:
- * The returned set will be serializable if the specified set is
- * serializable.
- *
- * @param s the set to be "wrapped" in a synchronized set.
- * @return a synchronized view of the specified set.
- */
- public static Set synchronizedSet(Set s) {
- return new SynchronizedSet(s);
+ public static Map unmodifiableMap(Map map) {
+ return Collections.unmodifiableMap(map);
}
-
- static Set synchronizedSet(Set s, Object mutex) {
- return new SynchronizedSet(s, mutex);
+ public static SortedMap unmodifiableSortedMap(SortedMap map) {
+ return Collections.unmodifiableSortedMap(map);
}
-
- static class SynchronizedSet extends SynchronizedCollection
- implements Set {
- SynchronizedSet(Set s) {
- super(s);
- }
- SynchronizedSet(Set s, Object mutex) {
- super(s, mutex);
- }
-
- public boolean equals(Object o) {
- synchronized(mutex) {return c.equals(o);}
- }
- public int hashCode() {
- synchronized(mutex) {return c.hashCode();}
- }
+ public static Collection synchronizedCollection(Collection collection) {
+ return Collections.synchronizedCollection(collection);
}
-
- /**
- * Returns a synchronized (thread-safe) sorted set backed by the specified
- * sorted set. In order to guarantee serial access, it is critical that
- * all access to the backing sorted set is accomplished
- * through the returned sorted set (or its views).
- *
- * It is imperative that the user manually synchronize on the returned
- * sorted set when iterating over it or any of its subSet,
- * headSet, or tailSet views.
- * The returned sorted set will be serializable if the specified
- * sorted set is serializable.
- *
- * @param s the sorted set to be "wrapped" in a synchronized sorted set.
- * @return a synchronized view of the specified sorted set.
- */
- public static SortedSet synchronizedSortedSet(SortedSet s) {
- return new SynchronizedSortedSet(s);
+ public static Set synchronizedSet(Set set) {
+ return Collections.synchronizedSet(set);
}
-
- static class SynchronizedSortedSet extends SynchronizedSet
- implements SortedSet
- {
- private SortedSet ss;
-
- SynchronizedSortedSet(SortedSet s) {
- super(s);
- ss = s;
- }
- SynchronizedSortedSet(SortedSet s, Object mutex) {
- super(s, mutex);
- ss = s;
- }
-
- public Comparator comparator() {
- synchronized(mutex) {return ss.comparator();}
- }
-
- public SortedSet subSet(Object fromElement, Object toElement) {
- synchronized(mutex) {
- return new SynchronizedSortedSet(
- ss.subSet(fromElement, toElement), mutex);
- }
- }
- public SortedSet headSet(Object toElement) {
- synchronized(mutex) {
- return new SynchronizedSortedSet(ss.headSet(toElement), mutex);
- }
- }
- public SortedSet tailSet(Object fromElement) {
- synchronized(mutex) {
- return new SynchronizedSortedSet(ss.tailSet(fromElement),mutex);
- }
- }
-
- public Object first() {
- synchronized(mutex) {return ss.first();}
- }
- public Object last() {
- synchronized(mutex) {return ss.last();}
- }
+ public static SortedSet synchronizedSortedSet(SortedSet set) {
+ return Collections.synchronizedSortedSet(set);
}
-
- /**
- * Returns a synchronized (thread-safe) list backed by the specified
- * list. In order to guarantee serial access, it is critical that
- * all access to the backing list is accomplished
- * through the returned list.
- *
- * It is imperative that the user manually synchronize on the returned
- * list when iterating over it:
- * The returned list will be serializable if the specified list is
- * serializable.
- *
- * @param list the list to be "wrapped" in a synchronized list.
- * @return a synchronized view of the specified list.
- */
public static List synchronizedList(List list) {
- return new SynchronizedList(list);
- }
-
- static List synchronizedList(List list, Object mutex) {
- return new SynchronizedList(list, mutex);
- }
-
- static class SynchronizedList extends SynchronizedCollection
- implements List {
- private List list;
-
- SynchronizedList(List list) {
- super(list);
- this.list = list;
- }
- SynchronizedList(List list, Object mutex) {
- super(list, mutex);
- this.list = list;
- }
-
- public boolean equals(Object o) {
- synchronized(mutex) {return list.equals(o);}
- }
- public int hashCode() {
- synchronized(mutex) {return list.hashCode();}
- }
-
- public Object get(int index) {
- synchronized(mutex) {return list.get(index);}
- }
- public Object set(int index, Object element) {
- synchronized(mutex) {return list.set(index, element);}
- }
- public void add(int index, Object element) {
- synchronized(mutex) {list.add(index, element);}
- }
- public Object remove(int index) {
- synchronized(mutex) {return list.remove(index);}
- }
-
- public int indexOf(Object o) {
- synchronized(mutex) {return list.indexOf(o);}
- }
- public int lastIndexOf(Object o) {
- synchronized(mutex) {return list.lastIndexOf(o);}
- }
-
- public boolean addAll(int index, Collection c) {
- synchronized(mutex) {return list.addAll(index, c);}
- }
-
- public ListIterator listIterator() {
- return list.listIterator(); // Must be manually synched by user
- }
-
- public ListIterator listIterator(int index) {
- return list.listIterator(index); // Must be manually synched by usr
- }
-
- public List subList(int fromIndex, int toIndex) {
- synchronized(mutex) {
- return new SynchronizedList(list.subList(fromIndex, toIndex),
- mutex);
- }
- }
- }
-
- /**
- * Returns a synchronized (thread-safe) map backed by the specified
- * map. In order to guarantee serial access, it is critical that
- * all access to the backing map is accomplished
- * through the returned map.
- *
- * It is imperative that the user manually synchronize on the returned
- * map when iterating over any of its collection views:
- * The returned map will be serializable if the specified map is
- * serializable.
- *
- * @param m the map to be "wrapped" in a synchronized map.
- * @return a synchronized view of the specified map.
- */
- public static Map synchronizedMap(Map m) {
- return new SynchronizedMap(m);
- }
-
- private static class SynchronizedMap implements Map, Serializable {
- private Map m; // Backing Map
- Object mutex; // Object on which to synchronize
-
- SynchronizedMap(Map m) {
- this.m = m; mutex = this;
- }
-
- SynchronizedMap(Map m, Object mutex) {
- this.m = m; this.mutex = mutex;
- }
-
- public int size() {
- synchronized(mutex) {return m.size();}
- }
- public boolean isEmpty(){
- synchronized(mutex) {return m.isEmpty();}
- }
- public boolean containsKey(Object key) {
- synchronized(mutex) {return m.containsKey(key);}
- }
- public boolean containsValue(Object value){
- synchronized(mutex) {return m.containsValue(value);}
- }
- public Object get(Object key) {
- synchronized(mutex) {return m.get(key);}
- }
-
- public Object put(Object key, Object value) {
- synchronized(mutex) {return m.put(key, value);}
- }
- public Object remove(Object key) {
- synchronized(mutex) {return m.remove(key);}
- }
- public void putAll(Map map) {
- synchronized(mutex) {m.putAll(map);}
- }
- public void clear() {
- synchronized(mutex) {m.clear();}
- }
-
- private transient Set keySet = null;
- private transient Set entrySet = null;
- private transient Collection values = null;
-
- public Set keySet() {
- synchronized(mutex) {
- if (keySet==null)
- keySet = new SynchronizedSet(m.keySet(), this);
- return keySet;
- }
- }
-
- public Set entrySet() {
- synchronized(mutex) {
- if (entrySet==null)
- entrySet = new SynchronizedSet(m.entrySet(), this);
- return entrySet;
- }
- }
-
- public Collection values() {
- synchronized(mutex) {
- if (values==null)
- values = new SynchronizedCollection(m.values(), this);
- return values;
- }
- }
-
- public boolean equals(Object o) {
- synchronized(mutex) {return m.equals(o);}
- }
- public int hashCode() {
- synchronized(mutex) {return m.hashCode();}
- }
- }
-
- /**
- * Returns a synchronized (thread-safe) sorted map backed by the specified
- * sorted map. In order to guarantee serial access, it is critical that
- * all access to the backing sorted map is accomplished
- * through the returned sorted map (or its views).
- *
- * It is imperative that the user manually synchronize on the returned
- * sorted map when iterating over any of its collection views, or the
- * collections views of any of its subMap, headMap or
- * tailMap views.
- * The returned sorted map will be serializable if the specified
- * sorted map is serializable.
- *
- * @param m the sorted map to be "wrapped" in a synchronized sorted map.
- * @return a synchronized view of the specified sorted map.
- */
- public static SortedMap synchronizedSortedMap(SortedMap m) {
- return new SynchronizedSortedMap(m);
- }
-
-
- static class SynchronizedSortedMap extends SynchronizedMap
- implements SortedMap
- {
- private SortedMap sm;
-
- SynchronizedSortedMap(SortedMap m) {
- super(m);
- sm = m;
- }
- SynchronizedSortedMap(SortedMap m, Object mutex) {
- super(m, mutex);
- sm = m;
- }
-
- public Comparator comparator() {
- synchronized(mutex) {return sm.comparator();}
- }
-
- public SortedMap subMap(Object fromKey, Object toKey) {
- synchronized(mutex) {
- return new SynchronizedSortedMap(
- sm.subMap(fromKey, toKey), mutex);
- }
- }
- public SortedMap headMap(Object toKey) {
- synchronized(mutex) {
- return new SynchronizedSortedMap(sm.headMap(toKey), mutex);
- }
- }
- public SortedMap tailMap(Object fromKey) {
- synchronized(mutex) {
- return new SynchronizedSortedMap(sm.tailMap(fromKey),mutex);
- }
- }
-
- public Object firstKey() {
- synchronized(mutex) {return sm.firstKey();}
- }
- public Object lastKey() {
- synchronized(mutex) {return sm.lastKey();}
- }
- }
-
-
- // Miscellaneous
-
- /**
- * The empty set (immutable). This set is serializable.
- */
- public static final Set EMPTY_SET = new EmptySet();
-
- private static class EmptySet extends AbstractSet implements Serializable {
- public Iterator iterator() {
- return new Iterator() {
- public boolean hasNext() {
- return false;
- }
- public Object next() {
- throw new NoSuchElementException();
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- public int size() {return 0;}
-
- public boolean contains(Object obj) {return false;}
- }
-
- /**
- * The empty list (immutable). This list is serializable.
- */
- public static final List EMPTY_LIST = new EmptyList();
-
- private static class EmptyList extends AbstractList
- implements Serializable {
- public int size() {return 0;}
-
- public boolean contains(Object obj) {return false;}
-
- public Object get(int index) {
- throw new IndexOutOfBoundsException("Index: "+index);
- }
+ return Collections.synchronizedList(list);
}
-
- /**
- * Returns an immutable set containing only the specified object.
- * The returned set is serializable.
- * @param o
- *
- * @return an immutable set containing only the specified object.
- */
- public static Set singleton(Object o) {
- return new SingletonSet(o);
+ public static Map synchronizedMap(Map map) {
+ return Collections.synchronizedMap(map);
}
-
- private static class SingletonSet extends AbstractSet
- implements Serializable
- {
- private Object element;
-
- SingletonSet(Object o) {element = o;}
-
- public Iterator iterator() {
- return new Iterator() {
- private boolean hasNext = true;
- public boolean hasNext() {
- return hasNext;
- }
- public Object next() {
- if (hasNext) {
- hasNext = false;
- return element;
- }
- throw new NoSuchElementException();
- }
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- public int size() {return 1;}
-
- public boolean contains(Object o) {return eq(o, element);}
+ public static SortedMap synchronizedSortedMap(SortedMap map) {
+ return Collections.synchronizedSortedMap(map);
}
-
- /**
- * Returns an immutable list consisting of n copies of the
- * specified object. The newly allocated data object is tiny (it contains
- * a single reference to the data object). This method is useful in
- * combination with the List.addAll method to grow lists.
- * The returned list is serializable.
- *
- * @param n the number of elements in the returned list.
- * @param o the element to appear repeatedly in the returned list.
- * @return an immutable list consisting of n copies of the
- * specified object.
- * @throws IllegalArgumentException if n < 0.
- * @see List#addAll(Collection)
- * @see List#addAll(int, Collection)
- */
- public static List nCopies(int n, Object o) {
- return new CopiesList(n, o);
+ public static Set singleton(Object value) {
+ return Collections.singleton(value);
}
-
- private static class CopiesList extends AbstractList
- implements Serializable
- {
- int n;
- Object element;
-
- CopiesList(int n, Object o) {
- if (n < 0)
- throw new IllegalArgumentException("List length = " + n);
- this.n = n;
- element = o;
- }
-
- public int size() {
- return n;
- }
-
- public boolean contains(Object obj) {
- return n != 0 && eq(obj, element);
- }
-
- public Object get(int index) {
- if (index<0 || index>=n)
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+n);
- return element;
- }
+ public static List nCopies(int count, Object value) {
+ return Collections.nCopies(count, value);
}
-
- /**
- * Returns a comparator that imposes the reverse of the natural
- * ordering on a collection of objects that implement the
- * Comparable interface. (The natural ordering is the ordering
- * imposed by the objects' own compareTo method.) This enables a
- * simple idiom for sorting (or maintaining) collections (or arrays) of
- * objects that implement the Comparable interface in
- * reverse-natural-order. For example, suppose a is an array of
- * strings. Then:
- *
- * The returned comparator is serializable.
- *
- * @return a comparator that imposes the reverse of the natural
- * ordering on a collection of objects that implement
- * the Comparable interface.
- * @see Comparable
- */
public static Comparator reverseOrder() {
- return REVERSE_ORDER;
- }
-
- private static final Comparator REVERSE_ORDER = new ReverseComparator();
-
- private static class ReverseComparator implements Comparator,Serializable {
- public int compare(Object o1, Object o2) {
- Comparable c1 = (Comparable)o1;
- Comparable c2 = (Comparable)o2;
- return -c1.compareTo(c2);
- }
- }
-
- /**
- * Returns an enumeration over the specified collection. This provides
- * interoperatbility with legacy APIs that require an enumeration
- * as input.
- *
- * @param c the collection for which an enumeration is to be returned.
- * @return an enumeration over the specified collection.
- */
- public static Enumeration enumeration(final Collection c) {
- return new Enumeration() {
- Iterator i = c.iterator();
-
- public boolean hasMoreElements() {
- return i.hasNext();
- }
-
- public Object nextElement() {
- return i.next();
- }
- };
+ return Collections.reverseOrder();
}
-
- /**
- * Returns true if the specified arguments are equal, or both null.
- */
- private static boolean eq(Object o1, Object o2) {
- return (o1==null ? o2==null : o1.equals(o2));
+ public static Enumeration enumeration(Collection collection) {
+ return Collections.enumeration(collection);
}
}
diff --git a/src/main/java/com/lambda/Debugger/StopButton.java b/src/main/java/com/lambda/Debugger/StopButton.java
index 902fe7f..d96015a 100644
--- a/src/main/java/com/lambda/Debugger/StopButton.java
+++ b/src/main/java/com/lambda/Debugger/StopButton.java
@@ -97,9 +97,16 @@ public void run() {
try {
SwingUtilities.invokeAndWait(r);
} catch (InterruptedException ie) {
- }// impossible
- catch (java.lang.reflect.InvocationTargetException ie) {
- }// impossible
+ if (IntegrationState.isActive()) {
+ Thread.currentThread().interrupt();
+ throw IntegrationState.internalFailed("ODB controller startup was interrupted.", ie);
+ }
+ } catch (java.lang.reflect.InvocationTargetException ie) {
+ if (IntegrationState.isActive()) {
+ Throwable cause = ie.getCause() == null ? ie : ie.getCause();
+ throw IntegrationState.internalFailed("Could not open the ODB controller.", cause);
+ }
+ }
}
public static void runButton(boolean startTarget, boolean paused,
diff --git a/src/main/java/com/lambda/Debugger/TimeStamp.java b/src/main/java/com/lambda/Debugger/TimeStamp.java
index 5e8b6b4..82ae37a 100644
--- a/src/main/java/com/lambda/Debugger/TimeStamp.java
+++ b/src/main/java/com/lambda/Debugger/TimeStamp.java
@@ -559,6 +559,7 @@ public final static int addStamp(int slIndex, int type, TraceLine tl) {
istamps[index] = type | threadIndexUnshifted | slIndex;
index++;
nTSCreated++;
+ IntegrationState.timestampAdded(nTSCreated, eott());
return index-1;
// return(addStamp(sl, type, threadIndexUnshifted));
@@ -600,6 +601,7 @@ public final static int addStamp(int slIndex, int type, int threadIndexUnshifted
istamps[index] = type | threadIndexUnshifted | slIndex;
index++;
nTSCreated++;
+ IntegrationState.timestampAdded(nTSCreated, eott());
return index-1;
}
@@ -645,6 +647,11 @@ public static int getThreadIndex(Thread tid) {
}
}
System.err.println("Too many threads. "+tid+" The debugger can only handle " + MAX_THREADS);
+ if (IntegrationState.isActive()) {
+ throw IntegrationState.internalFailed(
+ "ODB exceeded its supported thread count.",
+ new IllegalStateException("Maximum threads: " + MAX_THREADS));
+ }
System.exit(1);
return(-1);
}
diff --git a/src/main/java/com/lambda/Debugger/VectorD.java b/src/main/java/com/lambda/Debugger/VectorD.java
index 29b78a9..5c841b6 100644
--- a/src/main/java/com/lambda/Debugger/VectorD.java
+++ b/src/main/java/com/lambda/Debugger/VectorD.java
@@ -1,1026 +1,177 @@
-/* VectorD.java
-
- Copyright 2003, Bil Lewis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-/*
-
-Use a duplicate of Sun's Vector class so that the ODB can load
-an instrumented version of Vector &c without blowing up.
-
-And it's not synchronized. And it's final. (Faster)
-
-But some of the Java classes appear to use Vectors. :-(
-
-
- * @(#)VectorD.java 1.71 00/04/18
+ /*
+ * Copyright 2003, Bil Lewis
*
- * Copyright 1994-2000 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the proprietary information of Sun Microsystems, Inc.
- * Use is subject to license terms.
- *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
*/
-
-//package java.util;
package com.lambda.Debugger;
-import java.util.*;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Collection;
+import java.util.Vector;
/**
- * The
- *
- * Each vector tries to optimize storage management by maintaining a
- *
- *
- * As of the Java 2 platform v1.2, this class has been retrofitted to
- * implement List, so that it becomes a part of Java's collection framework.
- * Unlike the new collection implementations, VectorD is .
+ * ODB vector compatibility type.
*
- * The Iterators returned by VectorD's iterator and listIterator
- * methods are fail-fast: if the VectorD is structurally modified
- * at any time after the Iterator is created, in any way except through the
- * Iterator's own remove or add methods, the Iterator will throw a
- * ConcurrentModificationException. Thus, in the face of concurrent
- * modification, the Iterator fails quickly and cleanly, rather than risking
- * arbitrary, non-deterministic behavior at an undetermined time in the future.
- * The Enumerations returned by VectorD's elements method are not
- * fail-fast.
- *
- * @author Lee Boynton
- * @author Jonathan Payne
- * @version 1.71, 04/18/00
- * @see Collection
- * @see List
- * @see ArrayList
- * @see LinkedList
- * @since JDK1.0
+ * Java's Vector owns storage and synchronization. ODB's historic reference-
+ * identity search/removal and non-traversing debugger string are retained.
*/
-//public class VectorD extends MyAbstractList implements List, Cloneable, java.io.Serializable {
public final class VectorD extends Vector {
- /**
- * The array buffer into which the components of the vector are
- * stored. The capacity of the vector is the length of this array buffer,
- * and is at least large enough to contain all the vector's elements.
- *
- * Any array elements following the last element in the VectorD are null.
- *
- * @serial
- */
- protected Object elementData[];
-
- /**
- * The number of valid components in this VectorD object.
- * Components elementData[0] through
- * elementData[elementCount-1] are the actual items.
- *
- * @serial
- */
- protected int elementCount;
-
- /**
- * The amount by which the capacity of the vector is automatically
- * incremented when its size becomes greater than its capacity. If
- * the capacity increment is less than or equal to zero, the capacity
- * of the vector is doubled each time it needs to grow.
- *
- * @serial
- */
- protected int capacityIncrement;
-
- /** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -2767605614048989439L;
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("capacityIncrement", Integer.TYPE),
+ new ObjectStreamField("elementCount", Integer.TYPE),
+ new ObjectStreamField("id", Integer.TYPE),
+ new ObjectStreamField("idCounter", Integer.TYPE),
+ new ObjectStreamField("elementData", Object[].class)
+ };
+
+ protected int idCounter = 0;
+ protected int id = idCounter++;
+ private transient int legacyCapacityIncrement;
- /**
- * Constructs an empty vector with the specified initial capacity and
- * capacity increment.
- *
- * @param initialCapacity the initial capacity of the vector.
- * @param capacityIncrement the amount by which the capacity is
- * increased when the vector overflows.
- * @exception IllegalArgumentException if the specified initial capacity
- * is negative
- */
public VectorD(int initialCapacity, int capacityIncrement) {
- super();
- if (initialCapacity < 0)
- throw new IllegalArgumentException("Illegal Capacity: "+
- initialCapacity);
- this.elementData = new Object[initialCapacity];
- this.capacityIncrement = capacityIncrement;
+ super(initialCapacity, capacityIncrement);
+ legacyCapacityIncrement = capacityIncrement;
}
- /**
- * Constructs an empty vector with the specified initial capacity and
- * with its capacity increment equal to zero.
- *
- * @param initialCapacity the initial capacity of the vector.
- * @exception IllegalArgumentException if the specified initial capacity
- * is negative
- */
public VectorD(int initialCapacity) {
- this(initialCapacity, 0);
+ super(initialCapacity);
}
- /**
- * Constructs an empty vector so that its internal data array
- * has size 10 and its standard capacity increment is
- * zero.
- */
public VectorD() {
- this(10);
- }
-
- /**
- * Constructs a vector containing the elements of the specified
- * collection, in the order they are returned by the collection's
- * iterator.
- *
- * @param c the collection whose elements are to be placed into this
- * vector.
- * @since 1.2
- */
- public VectorD(Collection c) {
- elementCount = c.size();
- elementData = new Object[(elementCount*110)/100]; // 10% for growth
- c.toArray(elementData);
- }
-
- /**
- * Copies the components of this vector into the specified array. The
- * item at index k in this vector is copied into component
- * k of anArray. The array must be big enough to hold
- * all the objects in this vector, else an
- * IndexOutOfBoundsException is thrown.
- *
- * @param anArray the array into which the components get copied.
- */
- public void copyInto(Object anArray[]) {
- System.arraycopy(elementData, 0, anArray, 0, elementCount);
- }
-
- /**
- * Trims the capacity of this vector to be the vector's current
- * size. If the capacity of this cector is larger than its current
- * size, then the capacity is changed to equal the size by replacing
- * its internal data array, kept in the field elementData,
- * with a smaller one. An application can use this operation to
- * minimize the storage of a vector.
- */
- public void trimToSize() {
- modCount++;
- int oldCapacity = elementData.length;
- if (elementCount < oldCapacity) {
- Object oldData[] = elementData;
- elementData = new Object[elementCount];
- System.arraycopy(oldData, 0, elementData, 0, elementCount);
- }
- }
-
- /**
- * Increases the capacity of this vector, if necessary, to ensure
- * that it can hold at least the number of components specified by
- * the minimum capacity argument.
- *
- * If the current capacity of this vector is less than
- * minCapacity, then its capacity is increased by replacing its
- * internal data array, kept in the field elementData, with a
- * larger one. The size of the new data array will be the old size plus
- * capacityIncrement, unless the value of
- * capacityIncrement is less than or equal to zero, in which case
- * the new capacity will be twice the old capacity; but if this new size
- * is still smaller than minCapacity, then the new capacity will
- * be minCapacity.
- *
- * @param minCapacity the desired minimum capacity.
- */
- public void ensureCapacity(int minCapacity) {
- modCount++;
- ensureCapacityHelper(minCapacity);
- }
-
- /**
- * This implements the un semantics of ensureCapacity.
- * methods in this class can internally call this
- * method for ensuring capacity without incurring the cost of an
- * extra synchronization.
- *
- * @see java.util.VectorD#ensureCapacity(int)
- */
- private void ensureCapacityHelper(int minCapacity) {
- int oldCapacity = elementData.length;
- if (minCapacity > oldCapacity) {
- Object oldData[] = elementData;
- int newCapacity = (capacityIncrement > 0) ?
- (oldCapacity + capacityIncrement) : (oldCapacity * 4);
- if (newCapacity < minCapacity) {
- newCapacity = minCapacity;
- }
- elementData = new Object[newCapacity];
- System.arraycopy(oldData, 0, elementData, 0, elementCount);
- }
- }
-
- /**
- * Sets the size of this vector. If the new size is greater than the
- * current size, new
- *
- * This method is identical in functionality to the get method
- * (which is part of the List interface).
- *
- * @param index an index into this vector.
- * @return the component at the specified index.
- * @exception ArrayIndexOutOfBoundsException if the index
- * is negative or not less than the current size of this
- * VectorD object.
- * given.
- * @see #get(int)
- * @see List
- */
- public Object elementAt(int index) {
- if (index >= elementCount) {
- throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
- }
- /* Since try/catch is free, except when the exception is thrown,
- put in this extra try/catch to catch negative indexes and
- display a more informative error message. This might not
- be appropriate, especially if we have a decent debugging
- environment - JP. */
- try {
- return elementData[index];
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new ArrayIndexOutOfBoundsException(index + " < 0");
- }
- }
-
- /**
- * Returns the first component (the item at index 0) of
- * this vector.
- *
- * @return the first component of this vector.
- * @exception NoSuchElementException if this vector has no components.
- */
- public Object firstElement() {
- if (elementCount == 0) {
- throw new NoSuchElementException();
- }
- return elementData[0];
- }
-
- /**
- * Returns the last component of the vector.
- *
- * @return the last component of the vector, i.e., the component at index
- *
- *
- * The index must be a value greater than or equal to
- *
- * This method is identical in functionality to the set method
- * (which is part of the List interface). Note that the set method reverses
- * the order of the parameters, to more closely match array usage. Note
- * also that the set method returns the old value that was stored at the
- * specified position.
- *
- * @param obj what the component is to be set to.
- * @param index the specified index.
- * @exception ArrayIndexOutOfBoundsException if the index was invalid.
- * @see #size()
- * @see List
- * @see #set(int, java.lang.Object)
- */
- public void setElementAt(Object obj, int index) {
- if (index >= elementCount) {
- throw new ArrayIndexOutOfBoundsException(index + " >= " +
- elementCount);
- }
- elementData[index] = obj;
- }
-
- /**
- * Deletes the component at the specified index. Each component in
- * this vector with an index greater or equal to the specified
- *
- *
- * The index must be a value greater than or equal to
- *
- * This method is identical in functionality to the remove method
- * (which is part of the List interface). Note that the remove method
- * returns the old value that was stored at the specified position.
- *
- * @param index the index of the object to remove.
- * @exception ArrayIndexOutOfBoundsException if the index was invalid.
- * @see #size()
- * @see #remove(int)
- * @see List
- */
- public void removeElementAt(int index) {
- modCount++;
- if (index >= elementCount) {
- throw new ArrayIndexOutOfBoundsException(index + " >= " +
- elementCount);
- }
- else if (index < 0) {
- throw new ArrayIndexOutOfBoundsException(index);
- }
- int j = elementCount - index - 1;
- if (j > 0) {
- System.arraycopy(elementData, index + 1, elementData, index, j);
- }
- elementCount--;
- elementData[elementCount] = null; /* to let gc do its work */
- }
-
- /**
- * Inserts the specified object as a component in this vector at the
- * specified
- *
- * The index must be a value greater than or equal to
- *
- * This method is identical in functionality to the add(Object, int) method
- * (which is part of the List interface). Note that the add method reverses
- * the order of the parameters, to more closely match array usage.
- *
- * @param obj the component to insert.
- * @param index where to insert the new component.
- * @exception ArrayIndexOutOfBoundsException if the index was invalid.
- * @see #size()
- * @see #add(int, Object)
- * @see List
- */
- public void insertElementAt(Object obj, int index) {
- modCount++;
- if (index >= elementCount + 1) {
- throw new ArrayIndexOutOfBoundsException(index
- + " > " + elementCount);
- }
- ensureCapacityHelper(elementCount + 1);
- System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
- elementData[index] = obj;
- elementCount++;
- }
-
- /**
- * Adds the specified component to the end of this vector,
- * increasing its size by one. The capacity of this vector is
- * increased if its size becomes greater than its capacity.
- *
- * This method is identical in functionality to the add(Object) method
- * (which is part of the List interface).
- *
- * @param obj the component to be added.
- * @see #add(Object)
- * @see List
- */
- public void addElement(Object obj) {
- modCount++;
- ensureCapacityHelper(elementCount + 1);
- elementData[elementCount++] = obj;
+ super();
}
- /**
- * Removes the first (lowest-indexed) occurrence of the argument
- * from this vector. If the object is found in this vector, each
- * component in the vector with an index greater or equal to the
- * object's index is shifted downward to have an index one smaller
- * than the value it had previously.
- *
- * This method is identical in functionality to the remove(Object)
- * method (which is part of the List interface).
- *
- * @param obj the component to be removed.
- * @return
- *
- * This method is identical in functionality to the clear method
- * (which is part of the List interface).
- *
- * @see #clear
- * @see List
- */
- public void removeAllElements() {
- // Let gc do its work
-
- for (int i = 0; i < elementCount; i++)
- elementData[i] = null;
-
- elementCount = 0;
- }
-
- /**
- * Returns a clone of this vector. The copy will contain a
- * reference to a clone of the internal data array, not a reference
- * to the original internal data array of this VectorD object.
- *
- * @return a clone of this vector.
- public Object clone() {
- try {
- VectorD v = (VectorD)super.clone();
- v.elementData = new Object[elementCount];
- System.arraycopy(elementData, 0, v.elementData, 0, elementCount);
- v.modCount = 0;
- return v;
- } catch (CloneNotSupportedException e) {
- // this shouldn't happen, since we are Cloneable
- throw new InternalError();
- }
+ public synchronized boolean contains(Object value) {
+ return indexOf(value, 0) >= 0;
}
- */
- /**
- * Returns an array containing all of the elements in this VectorD
- * in the correct order.
- *
- * @since 1.2
- */
- public Object[] toArray() {
- Object[] result = new Object[elementCount];
- System.arraycopy(elementData, 0, result, 0, elementCount);
- return result;
+ public synchronized int indexOf(Object value) {
+ return indexOf(value, 0);
}
- /**
- * Returns an array containing all of the elements in this VectorD in the
- * correct order. The runtime type of the returned array is that of the
- * specified array. If the VectorD fits in the specified array, it is
- * returned therein. Otherwise, a new array is allocated with the runtime
- * type of the specified array and the size of this VectorD.
- *
- * If the VectorD fits in the specified array with room to spare
- * (i.e., the array has more elements than the VectorD),
- * the element in the array immediately following the end of the
- * VectorD is set to null. This is useful in determining the length
- * of the VectorD only if the caller knows that the VectorD
- * does not contain any null elements.
- *
- * @param a the array into which the elements of the VectorD are to
- * be stored, if it is big enough; otherwise, a new array of the
- * same runtime type is allocated for this purpose.
- * @return an array containing the elements of the VectorD.
- * @exception ArrayStoreException the runtime type of a is not a supertype
- * of the runtime type of every element in this VectorD.
- */
- public Object[] toArray(Object a[]) {
- if (a.length < elementCount)
- a = (Object[])java.lang.reflect.Array.newInstance(
- a.getClass().getComponentType(), elementCount);
-
- System.arraycopy(elementData, 0, a, 0, elementCount);
-
- if (a.length > elementCount)
- a[elementCount] = null;
-
- return a;
+ public synchronized int indexOf(Object value, int index) {
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Index: " + index);
+ }
+ for (int i = index; i < size(); i++) {
+ if (elementAt(i) == value) {
+ return i;
+ }
+ }
+ return -1;
}
- // Positional Access Operations
-
- /**
- * Returns the element at the specified position in this VectorD.
- *
- * @param index index of element to return.
- * @exception ArrayIndexOutOfBoundsException index is out of range (index
- * < 0 || index >= size()).
- * @since 1.2
- */
- public Object get(int index) {
- if (index >= elementCount)
- throw new ArrayIndexOutOfBoundsException(index);
-
- return elementData[index];
+ public synchronized int lastIndexOf(Object value) {
+ return lastIndexOf(value, size() - 1);
}
- /**
- * Replaces the element at the specified position in this VectorD with the
- * specified element.
- *
- * @param index index of element to replace.
- * @param element element to be stored at the specified position.
- * @return the element previously at the specified position.
- * @exception ArrayIndexOutOfBoundsException index out of range
- * (index < 0 || index >= size()).
- * @exception IllegalArgumentException fromIndex > toIndex.
- * @since 1.2
- */
- public Object set(int index, Object element) {
- if (index >= elementCount)
- throw new ArrayIndexOutOfBoundsException(index);
-
- Object oldValue = elementData[index];
- elementData[index] = element;
- return oldValue;
+ public synchronized int lastIndexOf(Object value, int index) {
+ if (index >= size()) {
+ throw new IndexOutOfBoundsException(index + " >= " + size());
+ }
+ for (int i = index; i >= 0; i--) {
+ if (elementAt(i) == value) {
+ return i;
+ }
+ }
+ return -1;
}
- /**
- * Appends the specified element to the end of this VectorD.
- *
- * @param o element to be appended to this VectorD.
- * @return true (as per the general contract of Collection.add).
- * @since 1.2
- */
- public boolean add(Object o) {
- modCount++;
- ensureCapacityHelper(elementCount + 1);
- elementData[elementCount++] = o;
+ public synchronized boolean removeElement(Object value) {
+ int index = indexOf(value);
+ if (index < 0) {
+ return false;
+ }
+ removeElementAt(index);
return true;
}
- /**
- * Removes the first occurrence of the specified element in this VectorD
- * If the VectorD does not contain the element, it is unchanged. More
- * formally, removes the element with the lowest index i such that
- *
- *
- * This method eliminates the need for explicit range operations (of
- * the sort that commonly exist for arrays). Any operation that expects
- * a List can be used as a range operation by operating on a subList view
- * instead of a whole List. For example, the following idiom
- * removes a range of elements from a List:
- *
- *
- * The semantics of the List returned by this method become undefined if
- * the backing list (i.e., this List) is structurally modified in
- * any way other than via the returned List. (Structural modifications are
- * those that change the size of the List, or otherwise perturb it in such
- * a fashion that iterations in progress may yield incorrect results.)
- *
- * @param fromIndex low endpoint (inclusive) of the subList.
- * @param toIndex high endpoint (exclusive) of the subList.
- * @return a view of the specified range within this List.
- * @throws IndexOutOfBoundsException endpoint index value out of range
- *
- * list.subList(from, to).clear();
- *
- * Similar idioms may be constructed for indexOf and
- * lastIndexOf, and all of the algorithms in the
- * Collections class can be applied to a subList.
- * Collection c = MyCollections.synchronizedCollection(myCollection);
- * ...
- * synchronized(c) {
- * Iterator i = c.iterator(); // Must be in the synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- *
- * Set s = MyCollections.synchronizedSet(new HashSet());
- * ...
- * synchronized(s) {
- * Iterator i = s.iterator(); // Must be in the synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- *
- * SortedSet s = MyCollections.synchronizedSortedSet(new HashSortedSet());
- * ...
- * synchronized(s) {
- * Iterator i = s.iterator(); // Must be in the synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * or:
- *
- * SortedSet s = MyCollections.synchronizedSortedSet(new HashSortedSet());
- * SortedSet s2 = s.headSet(foo);
- * ...
- * synchronized(s) { // Note: s, not s2!!!
- * Iterator i = s2.iterator(); // Must be in the synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- *
- * List list = MyCollections.synchronizedList(new ArrayList());
- * ...
- * synchronized(list) {
- * Iterator i = list.iterator(); // Must be in synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- *
- * Map m = MyCollections.synchronizedMap(new HashMap());
- * ...
- * Set s = m.keySet(); // Needn't be in synchronized block
- * ...
- * synchronized(m) { // Synchronizing on m, not s!
- * Iterator i = s.iterator(); // Must be in synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- *
- * SortedMap m = MyCollections.synchronizedSortedMap(new HashSortedMap());
- * ...
- * Set s = m.keySet(); // Needn't be in synchronized block
- * ...
- * synchronized(m) { // Synchronizing on m, not s!
- * Iterator i = s.iterator(); // Must be in synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * or:
- *
- * SortedMap m = MyCollections.synchronizedSortedMap(new HashSortedMap());
- * SortedMap m2 = m.subMap(foo, bar);
- * ...
- * Set s2 = m2.keySet(); // Needn't be in synchronized block
- * ...
- * synchronized(m) { // Synchronizing on m, not m2 or s2!
- * Iterator i = s.iterator(); // Must be in synchronized block
- * while (i.hasNext())
- * foo(i.next());
- * }
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- *
- * Arrays.sort(a, MyCollections.reverseOrder());
- *
sorts the array in reverse-lexicographic (alphabetical) order.VectorD class implements a growable array of
- * objects. Like an array, it contains components that can be
- * accessed using an integer index. However, the size of a
- * VectorD can grow or shrink as needed to accommodate
- * adding and removing items after the VectorD has been created.capacity and a capacityIncrement. The
- * capacity is always at least as large as the vector
- * size; it is usually larger because as components are added to the
- * vector, the vector's storage increases in chunks the size of
- * capacityIncrement. An application can increase the
- * capacity of a vector before inserting a large number of
- * components; this reduces the amount of incremental reallocation. null items are added to the end of
- * the vector. If the new size is less than the current size, all
- * components at index newSize and greater are discarded.
- *
- * @param newSize the new size of this vector.
- * @throws ArrayIndexOutOfBoundsException if new size is negative.
- */
- public void setSize(int newSize) {
- modCount++;
- if (newSize > elementCount) {
- ensureCapacityHelper(newSize);
- } else {
- for (int i = newSize ; i < elementCount ; i++) {
- elementData[i] = null;
- }
- }
- elementCount = newSize;
- }
-
- /**
- * Returns the current capacity of this vector.
- *
- * @return the current capacity (the length of its internal
- * data arary, kept in the field elementData
- * of this vector.
- */
- public int capacity() {
- return elementData.length;
- }
-
- /**
- * Returns the number of components in this vector.
- *
- * @return the number of components in this vector.
- */
- public int size() {
- return elementCount;
- }
-
- /**
- * Tests if this vector has no components.
- *
- * @return true if and only if this vector has
- * no components, that is, its size is zero;
- * false otherwise.
- */
- public boolean isEmpty() {
- return elementCount == 0;
- }
-
- /**
- * Returns an enumeration of the components of this vector. The
- * returned Enumeration object will generate all items in
- * this vector. The first item generated is the item at index 0,
- * then the item at index 1, and so on.
- *
- * @return an enumeration of the components of this vector.
- * @see Enumeration
- * @see Iterator
- */
- public Enumeration elements() {
- return new Enumeration() {
- int count = 0;
-
- public boolean hasMoreElements() {
- return count < elementCount;
- }
-
- public Object nextElement() {
- if (count < elementCount) {
- return elementData[count++];
- }
- throw new NoSuchElementException("VectorD Enumeration");
- }
- };
- }
-
- /**
- * Tests if the specified object is a component in this vector.
- *
- * @param elem an object.
- * @return true if and only if the specified object
- * is the same as a component in this vector, as determined by the
- * equals method; false otherwise.
- */
- public boolean contains(Object elem) {
- return indexOf(elem, 0) >= 0;
- }
-
- /**
- * Searches for the first occurence of the given argument, testing
- * for equality using the equals method.
- *
- * @param elem an object.
- * @return the index of the first occurrence of the argument in this
- * vector, that is, the smallest value k such that
- * elem.equals(elementData[k]) is true;
- * returns -1 if the object is not found.
- * @see Object#equals(Object)
- */
- public int indexOf(Object elem) {
- return indexOf(elem, 0);
- }
-
- /**
- * Searches for the first occurence of the given argument, beginning
- * the search at index, and testing for equality using
- * the equals method.
- *
- * @param elem an object.
- * @param index the non-negative index to start searching from.
- * @return the index of the first occurrence of the object argument in
- * this vector at position index or later in the
- * vector, that is, the smallest value k such that
- * elem.equals(elementData[k]) and (k >= index) is
- * true; returns -1 if the object is not
- * found. (Returns -1 if index >= the
- * current size of this VectorD.)
- * @exception IndexOutOfBoundsException if index is negative.
- * @see Object#equals(Object)
- */
- public int indexOf(Object elem, int index) {
- if (elem == null) {
- for (int i = index ; i < elementCount ; i++)
- if (elementData[i]==null)
- return i;
- } else {
- for (int i = index ; i < elementCount ; i++)
- if (elem == elementData[i])
- return i;
- }
- return -1;
- }
-
- /**
- * Returns the index of the last occurrence of the specified object in
- * this vector.
- *
- * @param elem the desired component.
- * @return the index of the last occurrence of the specified object in
- * this vector, that is, the largest value k such that
- * elem.equals(elementData[k]) is true;
- * returns -1 if the object is not found.
- */
- public int lastIndexOf(Object elem) {
- return lastIndexOf(elem, elementCount-1);
- }
-
- /**
- * Searches backwards for the specified object, starting from the
- * specified index, and returns an index to it.
- *
- * @param elem the desired component.
- * @param index the index to start searching from.
- * @return the index of the last occurrence of the specified object in this
- * vector at position less than or equal to index in
- * the vector, that is, the largest value k such that
- * elem.equals(elementData[k]) and (k <= index) is
- * true; -1 if the object is not found.
- * (Returns -1 if index is negative.)
- * @exception IndexOutOfBoundsException if index is greater
- * than or equal to the current size of this vector.
- */
- public int lastIndexOf(Object elem, int index) {
- if (index >= elementCount)
- throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
-
- if (elem == null) {
- for (int i = index; i >= 0; i--)
- if (elementData[i]==null)
- return i;
- } else {
- for (int i = index; i >= 0; i--)
- if (elem == elementData[i])
- return i;
- }
- return -1;
- }
-
- /**
- * Returns the component at the specified index.size() - 1.
- * @exception NoSuchElementException if this vector is empty.
- */
- public Object lastElement() {
- if (elementCount == 0) {
- throw new NoSuchElementException();
- }
- return elementData[elementCount - 1];
- }
-
- /**
- * Sets the component at the specified index of this
- * vector to be the specified object. The previous component at that
- * position is discarded.0
- * and less than the current size of the vector. index is shifted downward to have an index one
- * smaller than the value it had previously. The size of this vector
- * is decreased by 1.0
- * and less than the current size of the vector. index. Each component in this vector with
- * an index greater or equal to the specified index is
- * shifted upward to have an index one greater than the value it had
- * previously. 0
- * and less than or equal to the current size of the vector. (If the
- * index is equal to the current size of the vector, the new element
- * is appended to the VectorD.)true if the argument was a component of this
- * vector; false otherwise.
- * @see List#remove(Object)
- * @see List
- */
- public boolean removeElement(Object obj) {
- modCount++;
- int i = indexOf(obj);
- if (i >= 0) {
- removeElementAt(i);
- return true;
- }
- return false;
+ public VectorD(Collection collection) {
+ super(collection);
}
- /**
- * Removes all components from this vector and sets its size to zero.(o==null ? get(i)==null : o.equals(get(i))) (if such
- * an element exists).
- *
- * @param o element to be removed from this VectorD, if present.
- * @return true if the VectorD contained the specified element.
- * @since 1.2
- */
- public boolean remove(Object o) {
- return removeElement(o);
- }
-
- /**
- * Inserts the specified element at the specified position in this VectorD.
- * Shifts the element currently at that position (if any) and any
- * subsequent elements to the right (adds one to their indices).
- *
- * @param index index at which the specified element is to be inserted.
- * @param element element to be inserted.
- * @exception ArrayIndexOutOfBoundsException index is out of range
- * (index < 0 || index > size()).
- * @since 1.2
- */
- public void add(int index, Object element) {
- insertElementAt(element, index);
- }
-
- /**
- * Removes the element at the specified position in this VectorD.
- * shifts any subsequent elements to the left (subtracts one from their
- * indices). Returns the element that was removed from the VectorD.
- *
- * @exception ArrayIndexOutOfBoundsException index out of range (index
- * < 0 || index >= size()).
- * @since 1.2
- */
- public Object remove(int index) {
- modCount++;
- if (index >= elementCount)
- throw new ArrayIndexOutOfBoundsException(index);
- Object oldValue = elementData[index];
-
- int numMoved = elementCount - index - 1;
- if (numMoved > 0)
- System.arraycopy(elementData, index+1, elementData, index,
- numMoved);
- elementData[--elementCount] = null; // Let gc do its work
- return oldValue;
- }
-
- /**
- * Removes all of the elements from this VectorD. The VectorD will
- * be empty after this call returns (unless it throws an exception).
- *
- * @since 1.2
- */
- public void clear() {
- removeAllElements();
- }
-
- // Bulk Operations
-
- /**
- * Returns true if this VectorD contains all of the elements in the
- * specified Collection.
- *
- * @return true if this VectorD contains all of the elements in the
- * specified collection.
- */
- public boolean containsAll(Collection c) {
- return super.containsAll(c);
+ public synchronized boolean remove(Object value) {
+ return removeElement(value);
}
- /**
- * Appends all of the elements in the specified Collection to the end of
- * this VectorD, in the order that they are returned by the specified
- * Collection's Iterator. The behavior of this operation is undefined if
- * the specified Collection is modified while the operation is in progress.
- * (This implies that the behavior of this call is undefined if the
- * specified Collection is this VectorD, and this VectorD is nonempty.)
- *
- * @param c elements to be inserted into this VectorD.
- * @exception ArrayIndexOutOfBoundsException index out of range (index
- * < 0 || index > size()).
- * @since 1.2
- */
- public boolean addAll(Collection c) {
- modCount++;
- int numNew = c.size();
- ensureCapacityHelper(elementCount + numNew);
-
- Iterator e = c.iterator();
- for (int i=0; ie1 and
- * e2 are equal if (e1==null ? e2==null :
- * e1.equals(e2)).) In other words, two Lists are defined to be
- * equal if they contain the same elements in the same order.
- *
- * @param o the Object to be compared for equality with this VectorD.
- * @return true if the specified Object is equal to this VectorD
- */
- public boolean equals(Object o) {
- return super.equals(o);
- }
-
- /**
- * Returns the hash code value for this VectorD.
- */
- public int hashCode() {
- return super.hashCode();
+ return true;
}
- /**
- * Returns a string representation of this VectorD, containing
- * the String representation of each element.
- */
-
- protected int idCounter = 0;
- protected int id=idCounter++;
- public String toString() {
- return "
- * list.subList(from, to).clear();
- *
- * Similar idioms may be constructed for indexOf and lastIndexOf,
- * and all of the algorithms in the Collections class can be applied to
- * a subList.(fromIndex < 0 || toIndex > size)
- * @throws IllegalArgumentException endpoint indices out of order
- * (fromIndex > toIndex)
- */
- /*
- public List subList(int fromIndex, int toIndex) {
- return Collections.synchronizedList(super.subList(fromIndex, toIndex),
- this);
+ public synchronized boolean retainAll(Collection collection) {
+ boolean changed = false;
+ for (int i = size() - 1; i >= 0; i--) {
+ if (!collection.contains(elementAt(i))) {
+ removeElementAt(i);
+ changed = true;
+ }
+ }
+ return changed;
}
- */
-
- /**
- * Removes from this List all of the elements whose index is between
- * fromIndex, inclusive and toIndex, exclusive. Shifts any succeeding
- * elements to the left (reduces their index).
- * This call shortens the ArrayList by (toIndex - fromIndex) elements. (If
- * toIndex==fromIndex, this operation has no effect.)
- *
- * @param fromIndex index of first element to be removed.
- * @param toIndex index after last element to be removed.
- */
- protected void removeRange(int fromIndex, int toIndex) {
- modCount++;
- int numMoved = elementCount - toIndex;
- System.arraycopy(elementData, toIndex, elementData, fromIndex,
- numMoved);
- // Let gc do its work
- int newElementCount = elementCount - (toIndex-fromIndex);
- while (elementCount != newElementCount)
- elementData[--elementCount] = null;
+ private boolean containsEqual(Object target) {
+ for (Object value : this) {
+ if (target == null ? value == null : target.equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString() {
+ return "