Compare commits

...

22 Commits

Author SHA1 Message Date
Robinson 23b9a4f7ff
version 1.48 2023-11-22 22:09:01 +01:00
Robinson bc5c28ef08
Fixed cacheName errors when null. 2023-11-22 12:28:40 +01:00
Robinson 81588e2a8e
Updated build deps 2023-10-09 12:27:09 +02:00
Robinson da9c34b538
updated build deps, kotlin 1.9.0 2023-10-02 16:15:04 +02:00
Robinson efcdbf9559
Version 1.47 2023-09-14 17:54:29 +02:00
Robinson e13205166a
updated unit tests 2023-09-14 17:54:10 +02:00
Robinson 0ce4bb2e2e
Rename .java to .kt 2023-09-14 17:54:10 +02:00
Robinson dc1bfb8371
Cleaned up getTimePretty() output 2023-09-14 17:54:00 +02:00
Robinson 3bf845f355
version 1.46 2023-08-21 01:43:56 +02:00
Robinson 0ff5f377d1
updated license 2023-08-21 01:43:36 +02:00
Robinson 5fa2e2aff6
updated gradle 2023-08-21 01:42:39 +02:00
Robinson db0be638b4
Moved byte array utilities to byteUtils project 2023-08-21 01:41:15 +02:00
Robinson ed5d2d2f74
version 1.45 2023-08-20 11:11:50 +02:00
Robinson ff21f4353e
updated deps 2023-08-20 11:08:30 +02:00
Robinson 0561f66e8e
Added cc0 license 2023-08-07 23:02:41 -06:00
Robinson 869b3b4167
Moved LZMA to byte utils 2023-08-06 17:39:37 -06:00
Robinson a0d02c83fc
code cleanup 2023-08-06 17:22:04 -06:00
Robinson 11c30aed96
Updated classutils 2023-08-05 13:24:48 -06:00
Robinson d3a767806b
Version 1.44 2023-08-05 10:16:25 -06:00
Robinson 27921e22ff
Moved classutils to their own project 2023-08-05 10:15:55 -06:00
Robinson be2dfae824
Updated version 2023-07-12 17:21:29 +02:00
Robinson 9c8f6c97dc
Added mutex.safeUnlock 2023-07-12 17:20:48 +02:00
28 changed files with 490 additions and 1763 deletions

219
LICENSE
View File

@ -21,13 +21,6 @@
Lightweight Java Game Library Project
Riven
- Modified hex conversion utility methods -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Utilities
https://netty.io
Copyright 2014
The Netty Project
- Retrofit - A type-safe HTTP client for Android and Java
[The Apache Software License, Version 2.0]
https://github.com/square/retrofit
@ -54,6 +47,12 @@
Copyright 2018
Venkat Peri
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
[The Apache Software License, Version 2.0]
https://github.com/Kotlin/kotlinx.coroutines
Copyright 2023
JetBrains s.r.o.
- Java Uuid Generator - A set of Java classes for working with UUIDs
[The Apache Software License, Version 2.0]
https://github.com/cowtowncoder/java-uuid-generator
@ -61,26 +60,6 @@
Tatu Saloranta (tatu.saloranta@iki.fi)
Contributors. See source release-notes/CREDITS
- XZ for Java - Complete implementation of XZ data compression in pure Java
[Public Domain, per Creative Commons CC0]
https://tukaani.org/xz/java.html
Copyright 2023
Lasse Collin
Igor Pavlov
- Netty - An event-driven asynchronous network application framework
[The Apache Software License, Version 2.0]
https://netty.io
Copyright 2023
The Netty Project
Contributors. See source NOTICE
- TypeTools - A simple, zero-dependency library for working with types. Supports Java 1.6+ and Android.
[The Apache Software License, Version 2.0]
https://github.com/jhalterman/typetools
Copyright 2023
Jonathan Halterman and friends
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
@ -89,192 +68,6 @@
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
[The Apache Software License, Version 2.0]
https://github.com/Kotlin/kotlinx.coroutines
Copyright 2023
JetBrains s.r.o.
- Collections - Niche collections to augment what is already available.
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
Copyright 2023
Dorkbox LLC
Extra license information
- Bias, BinarySearch -
[MIT License]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/timboudreau/util
Copyright 2013
Tim Boudreau
- ConcurrentEntry -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
Copyright 2016
bennidi
dorkbox
- Collection Utilities (Array, ArrayMap, BooleanArray, ByteArray, CharArray, FloatArray, IdentityMap, IntArray, IntFloatMap, IntIntMap, IntMap, IntSet, LongArray, LongMap, ObjectFloatMap, ObjectIntMap, ObjectMap, ObjectSet, OrderedMap, OrderedSet) -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2011
LibGDX
Mario Zechner (badlogicgames@gmail.com)
Nathan Sweet (nathan.sweet@gmail.com)
- Predicate -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2011
LibGDX
Mario Zechner (badlogicgames@gmail.com)
Nathan Sweet (nathan.sweet@gmail.com)
xoppa
- Select, QuickSelect -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2011
LibGDX
Mario Zechner (badlogicgames@gmail.com)
Nathan Sweet (nathan.sweet@gmail.com)
Jon Renner
- TimSort, ComparableTimSort -
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Collections
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils
Copyright 2008
The Android Open Source Project
- ConcurrentWeakIdentityHashMap - Concurrent WeakIdentity HashMap
[The Apache Software License, Version 2.0]
https://github.com/spring-projects/spring-loaded/blob/master/springloaded/src/main/java/org/springsource/loaded/support/ConcurrentWeakIdentityHashMap.java
Copyright 2016
zhanhb
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- Updates - Software Update Management
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Updates
Copyright 2021
Dorkbox LLC
Extra license information
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- Executor - Shell, JVM, and SSH command execution on Linux, MacOS, or Windows for Java 8+
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Executor
Copyright 2023
Dorkbox LLC
Extra license information
- ZT Process Executor -
[The Apache Software License, Version 2.0]
https://github.com/zeroturnaround/zt-exec
Copyright 2014
ZeroTurnaround LLC
- Apache Commons Exec -
[The Apache Software License, Version 2.0]
https://commons.apache.org/proper/commons-exec/
Copyright 2014
The Apache Software Foundation
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- kotlinx.coroutines - Library support for Kotlin coroutines with multiplatform support
[The Apache Software License, Version 2.0]
https://github.com/Kotlin/kotlinx.coroutines
Copyright 2023
JetBrains s.r.o.
- SLF4J - Simple facade or abstraction for various logging frameworks
[MIT License]
https://www.slf4j.org
Copyright 2023
QOS.ch
- Logback - Logback is a logging framework for Java applications
[The Apache Software License, Version 2.0]
https://logback.qos.ch
Copyright 2023
QOS.ch
- SSHJ - SSHv2 library for Java
[The Apache Software License, Version 2.0]
https://github.com/hierynomus/sshj
Copyright 2023
Jeroen van Erp
SSHJ Contributors
Extra license information
- Apache MINA -
[The Apache Software License, Version 2.0]
https://mina.apache.org/sshd-project/
The Apache Software Foundation
- Apache Commons-Net -
[The Apache Software License, Version 2.0]
https://commons.apache.org/proper/commons-net/
The Apache Software Foundation
- JZlib -
[The Apache Software License, Version 2.0]
https://github.com/ymnk/jzlib
Atsuhiko Yamanaka
JCraft, Inc.
- Bouncy Castle Crypto -
[The Apache Software License, Version 2.0]
https://www.bouncycastle.org
The Legion of the Bouncy Castle Inc
- ed25519-java -
[Public Domain, per Creative Commons CC0]
https://github.com/str4d/ed25519-java
https://github.com/str4d
- Updates - Software Update Management
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/Updates
Copyright 2021
Dorkbox LLC
Extra license information
- Kotlin -
[The Apache Software License, Version 2.0]
https://github.com/JetBrains/kotlin
Copyright 2020
JetBrains s.r.o. and Kotlin Programming Language contributors
Kotlin Compiler, Test Data+Libraries, and Tools repository contain third-party code, to which different licenses may apply
See: https://github.com/JetBrains/kotlin/blob/master/license/README.md
- OS - Information about the system, Java runtime, OS, Window Manager, and Desktop Environment.
[The Apache Software License, Version 2.0]
https://git.dorkbox.com/dorkbox/OS

View File

@ -1,121 +0,0 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -1,21 +0,0 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -11,25 +11,25 @@ Please see the header of each file for the specific license that applies to it.
Maven Info
---------
````
```
<dependencies>
...
<dependency>
<groupId>com.dorkbox</groupId>
<artifactId>Utilities</artifactId>
<version>1.36</version>
<version>1.48</version>
</dependency>
</dependencies>
````
```
Gradle Info
---------
````
```
dependencies {
...
compile "com.dorkbox:Utilities:1.36"
compile "com.dorkbox:Utilities:1.48"
}
````
```
License

View File

@ -23,19 +23,19 @@
gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS // always show the stacktrace!
plugins {
id("com.dorkbox.GradleUtils") version "3.17"
id("com.dorkbox.Licensing") version "2.24"
id("com.dorkbox.GradleUtils") version "3.18"
id("com.dorkbox.Licensing") version "2.28"
id("com.dorkbox.VersionUpdate") version "2.8"
id("com.dorkbox.GradlePublish") version "1.18"
id("com.dorkbox.GradlePublish") version "1.20"
kotlin("jvm") version "1.8.0"
kotlin("jvm") version "1.9.0"
}
object Extras {
// set for the project
const val description = "Utilities for use within Java projects"
const val group = "com.dorkbox"
const val version = "1.42"
const val version = "1.48"
// set as project.ext
const val name = "Utilities"
@ -75,12 +75,6 @@ licensing {
author("Riven")
}
extra("Modified hex conversion utility methods", License.APACHE_2) {
url(Extras.url)
url("https://netty.io")
copyright(2014)
author("The Netty Project")
}
extra("Retrofit", License.APACHE_2) {
copyright(2020)
description("A type-safe HTTP client for Android and Java")
@ -127,11 +121,9 @@ tasks.jar.get().apply {
// NOTE: compileOnly is used because there are some classes/dependencies that ARE NOT necessary to be included, UNLESS the user
// is actually using that part of the library. If this happens, they will (or should) already be using the dependency)
dependencies {
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
api("com.dorkbox:Collections:1.6")
api("com.dorkbox:Executor:3.13")
api("com.dorkbox:OS:1.6")
api("com.dorkbox:OS:1.8")
api("com.dorkbox:Updates:1.1")
@ -143,20 +135,17 @@ dependencies {
// api("io.github.microutils:kotlin-logging:3.0.4")
// api("org.slf4j:slf4j-api:2.0.7")
api("org.tukaani:xz:1.9") // LZMA support
compileOnly("com.fasterxml.uuid:java-uuid-generator:4.1.0")
// api "com.koloboke:koloboke-api-jdk8:1.0.0"
// runtime "com.koloboke:koloboke-impl-jdk8:1.0.0"
compileOnly("io.netty:netty-buffer:4.1.94.Final")
compileOnly("net.jodah:typetools:0.6.3")
// compileOnly("io.netty:netty-buffer:4.1.96.Final")
testImplementation("com.dorkbox:Executor:3.13")
testImplementation("junit:junit:4.13.2")
// testImplementation("ch.qos.logback:logback-classic:1.4.5")
}
repositories {
mavenCentral()
// implementation(kotlin("stdlib-jdk8"))
}
publishToSonatype {

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

12
gradlew vendored Normal file → Executable file
View File

@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -80,10 +80,10 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
@ -143,12 +143,16 @@ fi
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac

1
gradlew.bat vendored
View File

@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

View File

@ -1,5 +1,5 @@
/*
* Copyright 2018 dorkbox, llc
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,3 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
rootProject.name = "Utilities"

View File

@ -138,11 +138,10 @@ class CacheUtil(private val tempDir: String = "cache") {
@Throws(IOException::class)
fun save(cacheName: String?, fileName: String): File {
// if we already have this fileName, reuse it
val newFile = if (cacheName == null) {
makeCacheFile(fileName)
} else {
makeCacheFile(cacheName)
}
@Suppress("NAME_SHADOWING")
val cacheName = cacheName ?: fileName
val newFile = makeCacheFile(cacheName)
// if this file already exists (via HASH), we just reuse what is saved on disk.
if (newFile.canRead() && newFile.isFile) {
@ -184,11 +183,10 @@ class CacheUtil(private val tempDir: String = "cache") {
@Throws(IOException::class)
fun save(cacheName: String?, fileResource: URL): File {
// if we already have this fileName, reuse it
val newFile = if (cacheName == null) {
makeCacheFile(fileResource.path)
} else {
makeCacheFile(cacheName)
}
@Suppress("NAME_SHADOWING")
val cacheName = cacheName ?: fileResource.path
val newFile = makeCacheFile(cacheName)
// if this file already exists (via HASH), we just reuse what is saved on disk.
if (newFile.canRead() && newFile.isFile) {
@ -218,11 +216,10 @@ class CacheUtil(private val tempDir: String = "cache") {
@Throws(IOException::class)
fun save(cacheName: String?, fileStream: InputStream): File {
// if we already have this fileName, reuse it
val newFile = if (cacheName == null) {
makeCacheFile(createNameAsHash(fileStream))
} else {
makeCacheFile(cacheName)
}
@Suppress("NAME_SHADOWING")
val cacheName = cacheName ?: createNameAsHash(fileStream)
val newFile = makeCacheFile(cacheName)
// if this file already exists (via HASH), we just reuse what is saved on disk.
return if (newFile.canRead() && newFile.isFile) {
@ -239,13 +236,7 @@ class CacheUtil(private val tempDir: String = "cache") {
* @return the full path of the resource copied to disk, or NULL if invalid
*/
@Throws(IOException::class)
private fun makeFileViaStream(cacheName: String?, resourceStream: InputStream?): File {
if (resourceStream == null) {
throw NullPointerException("resourceStream")
}
if (cacheName == null) {
throw NullPointerException("cacheName")
}
private fun makeFileViaStream(cacheName: String, resourceStream: InputStream): File {
val newFile = makeCacheFile(cacheName)
// if this file already exists (via HASH), we just reuse what is saved on disk.

View File

@ -66,6 +66,12 @@ inline fun ignoreExceptions(vararg blocks: () -> Unit) {
}
}
fun Mutex.safeUnlock() {
if (isLocked) {
unlock()
}
}
// From: https://elizarov.medium.com/phantom-of-the-coroutine-afc63b03a131
suspend inline fun <T> Mutex.withReentrantLock(crossinline block: suspend () -> T): T {
val key = ReentrantMutexContextKey(this)

View File

@ -556,7 +556,6 @@ object FileUtil {
/**
* Copies a files from one location to another. Overwriting any existing file at the destination.
*/
@JvmStatic
@Throws(IOException::class)
fun copyFile(`in`: File, out: File): File {
val normalizedIn = `in`.normalize().absolutePath
@ -756,7 +755,6 @@ object FileUtil {
*
* @return true IFF the file/dir was deleted or didn't exist at first
*/
@JvmStatic
fun delete(file: File, vararg namesToIgnore: String): Boolean {
if (!file.exists()) {
return true

View File

@ -162,7 +162,7 @@ class ImageUtil {
}
else {
// suck it out of a URL/Resource (with debugging if necessary)
final URL systemResource = LocationResolver.getResource(fileName);
final URL systemResource = LocationResolver.Companion.getResource(fileName);
image = new ImageIcon(systemResource).getImage();
}

View File

@ -1,52 +0,0 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util
import org.tukaani.xz.LZMA2Options
import org.tukaani.xz.LZMAInputStream
import org.tukaani.xz.LZMAOutputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
object LZMA {
// https://tukaani.org/xz/java.html
/**
* Gets the version number.
*/
val version = Sys.version
@Throws(IOException::class)
fun encode(input: InputStream, output: OutputStream) {
LZMAOutputStream(output, LZMA2Options(3), true).use { compressionStream ->
input.copyTo(compressionStream)
}
}
@Throws(IOException::class)
fun decode(input: InputStream): ByteArrayOutputStream {
val byteArrayOutputStream = ByteArrayOutputStream(8192)
LZMAInputStream(input).use { compressedStream -> compressedStream.copyTo(byteArrayOutputStream) }
return byteArrayOutputStream
}
@Throws(IOException::class)
fun decode(input: InputStream, output: OutputStream) {
LZMAInputStream(input).use { compressedStream -> compressedStream.copyTo(output) }
}
}

View File

@ -285,7 +285,6 @@ class LocationResolver {
*
* @return the URL for that given resource name
*/
@JvmStatic
fun getResource(resourceName: String): URL? {
var resourceName = resourceName
try {

View File

@ -1,20 +0,0 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
public interface Message {
}

View File

@ -15,7 +15,6 @@
*/
package dorkbox.util
import dorkbox.os.OS.LINE_SEPARATOR
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
@ -27,7 +26,7 @@ object Sys {
/**
* Gets the version number.
*/
val version = "1.42"
val version = "1.48"
init {
// Add this project to the updates system, which verifies this class + UUID + version information
@ -39,52 +38,7 @@ object Sys {
const val MEGABYTE = 1024 * KILOBYTE
const val GIGABYTE = 1024 * MEGABYTE
const val TERABYTE = 1024L * GIGABYTE
val HEX_CHARS = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
fun convertStringToChars(string: String): CharArray {
val charArray = string.toCharArray()
eraseString(string)
return charArray
}
fun eraseString(string: String?) {
// You can change the value of the inner char[] using reflection.
//
// You must be careful to either change it with an array of the same length,
// or to also update the count field.
//
// If you want to be able to use it as an entry in a set or as a value in map,
// you will need to recalculate the hash code and set the value of the hashCode field.
try {
val valueField = String::class.java.getDeclaredField("value")
valueField.isAccessible = true
val chars = valueField[string] as CharArray
Arrays.fill(chars, '*') // asterisk it out in case of GC not picking up the old char array.
valueField[string] = CharArray(0) // replace it.
// set count to 0
try {
// newer versions of java don't have this field
val countField = String::class.java.getDeclaredField("count")
countField.isAccessible = true
countField[string] = 0
} catch (ignored: Exception) {
}
// set hash to 0
val hashField = String::class.java.getDeclaredField("hash")
hashField.isAccessible = true
hashField[string] = 0
} catch (e: SecurityException) {
e.printStackTrace()
} catch (e: NoSuchFieldException) {
e.printStackTrace()
} catch (e: IllegalArgumentException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}
/**
* FROM: https://www.cqse.eu/en/blog/string-replace-performance/
@ -163,22 +117,22 @@ object Sys {
fun getTimePretty(nanoSeconds: Long): String {
val unit: TimeUnit
val text: String
if (TimeUnit.DAYS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
if (TimeUnit.DAYS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.DAYS
text = "d"
} else if (TimeUnit.HOURS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.HOURS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.HOURS
text = "h"
} else if (TimeUnit.MINUTES.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.MINUTES.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.MINUTES
text = "min"
} else if (TimeUnit.SECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
text = "m"
} else if (TimeUnit.SECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.SECONDS
text = "s"
} else if (TimeUnit.MILLISECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.MILLISECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.MILLISECONDS
text = "ms"
} else if (TimeUnit.MICROSECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.MICROSECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.MICROSECONDS
text = "\u03bcs" // μs
} else {
@ -188,7 +142,16 @@ object Sys {
// convert the unit into the largest time unit possible (since that is often what makes sense)
val value = nanoSeconds.toDouble() / TimeUnit.NANOSECONDS.convert(1, unit)
return String.format("%.4g$text", value)
return if (value < 10) {
String.format("%.1g $text", value)
} else if (value < 100) {
String.format("%.2g $text", value)
} else if (value < 1000) {
String.format("%.3g $text", value)
} else {
String.format("%.4g $text", value)
}
}
/**
@ -197,22 +160,22 @@ object Sys {
fun getTimePrettyFull(nanoSeconds: Long): String {
val unit: TimeUnit
var text: String
if (TimeUnit.DAYS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
if (TimeUnit.DAYS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.DAYS
text = "day"
} else if (TimeUnit.HOURS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.HOURS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.HOURS
text = "hour"
} else if (TimeUnit.MINUTES.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.MINUTES.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.MINUTES
text = "minute"
} else if (TimeUnit.SECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.SECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.SECONDS
text = "second"
} else if (TimeUnit.MILLISECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.MILLISECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.MILLISECONDS
text = "milli-second"
} else if (TimeUnit.MICROSECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0) {
} else if (TimeUnit.MICROSECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS) > 0L) {
unit = TimeUnit.MICROSECONDS
text = "micro-second"
} else {
@ -225,7 +188,16 @@ object Sys {
if (value > 1.0) {
text += "s"
}
return String.format("%.4g $text", value)
return if (value < 10) {
String.format("%.1g $text", value)
} else if (value < 100) {
String.format("%.2g $text", value)
} else if (value < 1000) {
String.format("%.3g $text", value)
} else {
String.format("%.4g $text", value)
}
}
private fun <T : Throwable> throwException0(t: Throwable) {
@ -245,6 +217,7 @@ object Sys {
*
* @return "" if there is no extension
*/
@Deprecated("Use kotlin")
fun getExtension(fileName: String): String {
val dot = fileName.lastIndexOf('.')
return if (dot > -1) {
@ -254,10 +227,10 @@ object Sys {
}
}
/**
* Convert the contents of the input stream to a byte array.
*/
@Deprecated("Use kotlin")
@Throws(IOException::class)
fun getBytesFromStream(inputStream: InputStream): ByteArray {
val baos = ByteArrayOutputStream(8192)
@ -271,6 +244,7 @@ object Sys {
return baos.toByteArray()
}
@Deprecated("Use kotlin")
@JvmOverloads
fun copyBytes(src: ByteArray, position: Int = 0): ByteArray {
val length = src.size - position
@ -279,7 +253,7 @@ object Sys {
return b
}
@JvmStatic
@Deprecated("Use kotlin")
fun concatBytes(vararg arrayBytes: ByteArray): ByteArray {
var length = 0
for (bytes in arrayBytes) {
@ -293,272 +267,46 @@ object Sys {
}
return concatBytes
}
@JvmOverloads
fun bytesToHex(bytes: ByteArray, startPosition: Int = 0, length: Int = bytes.size, padding: Boolean = false): String {
val endPosition = startPosition + length
return if (padding) {
val hexString = CharArray(3 * length)
var j = 0
for (i in startPosition until endPosition) {
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0xF0 shr 4]
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0x0F]
hexString[j++] = ' '
}
String(hexString)
} else {
val hexString = CharArray(2 * length)
var j = 0
for (i in startPosition until endPosition) {
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0xF0 shr 4]
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0x0F]
}
String(hexString)
}
}
/**
* Converts an ASCII character representing a hexadecimal
* value into its integer equivalent.
*/
fun hexByteToInt(b: Byte): Int {
return when (b.toInt()) {
'0'.code -> 0
'1'.code -> 1
'2'.code -> 2
'3'.code -> 3
'4'.code -> 4
'5'.code -> 5
'6'.code -> 6
'7'.code -> 7
'8'.code -> 8
'9'.code -> 9
'A'.code, 'a'.code -> 10
'B'.code, 'b'.code -> 11
'C'.code, 'c'.code -> 12
'D'.code, 'd'.code -> 13
'E'.code, 'e'.code -> 14
'F'.code, 'f'.code -> 15
else -> throw IllegalArgumentException("Error decoding byte")
}
}
/**
* Converts an ASCII character representing a hexadecimal
* value into its integer equivalent.
*/
fun hexCharToInt(b: Char): Int {
return when (b) {
'0' -> 0
'1' -> 1
'2' -> 2
'3' -> 3
'4' -> 4
'5' -> 5
'6' -> 6
'7' -> 7
'8' -> 8
'9' -> 9
'A', 'a' -> 10
'B', 'b' -> 11
'C', 'c' -> 12
'D', 'd' -> 13
'E', 'e' -> 14
'F', 'f' -> 15
else -> throw IllegalArgumentException("Error decoding byte")
}
}
/**
* A 4-digit hex result.
*/
fun hex4(c: Char, sb: StringBuilder) {
sb.append(HEX_CHARS[c.code and 0xF000 shr 12])
sb.append(HEX_CHARS[c.code and 0x0F00 shr 8])
sb.append(HEX_CHARS[c.code and 0x00F0 shr 4])
sb.append(HEX_CHARS[c.code and 0x000F])
}
/**
* Returns a string representation of the byte array as a series of
* hexadecimal characters.
*
* @param bytes byte array to convert
* @return a string representation of the byte array as a series of
* hexadecimal characters
*/
fun toHexString(bytes: ByteArray): String {
val hexString = CharArray(2 * bytes.size)
var j = 0
for (i in bytes.indices) {
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0xF0 shr 4]
hexString[j++] = HEX_CHARS[bytes[i].toInt() and 0x0F]
}
return String(hexString)
}
/**
* from netty 4.1, apache 2.0, https://netty.io
*/
fun hexToByte(s: CharSequence, pos: Int): Byte {
val hi = hexCharToInt(s[pos])
val lo = hexCharToInt(s[pos + 1])
require(!(hi == -1 || lo == -1)) {
String.format(
"invalid hex byte '%s' at index %d of '%s'", s.subSequence(pos, pos + 2), pos, s
)
}
return ((hi shl 4) + lo).toByte()
}
/**
* Decodes a string with [hex dump](http://en.wikipedia.org/wiki/Hex_dump)
*
* @param hex a [CharSequence] which contains the hex dump
*/
fun hexToBytes(hex: CharSequence): ByteArray {
return hexToBytes(hex, 0, hex.length)
}
/**
* Decodes part of a string with [hex dump](http://en.wikipedia.org/wiki/Hex_dump)
*
* from netty 4.1, apache 2.0, https://netty.io
*
* @param hexDump a [CharSequence] which contains the hex dump
* @param fromIndex start of hex dump in `hexDump`
* @param length hex string length
*/
fun hexToBytes(hexDump: CharSequence, fromIndex: Int, length: Int): ByteArray {
require(!(length < 0 || length and 1 != 0)) { "length: $length" }
if (length == 0) {
return ByteArray(0)
}
val bytes = ByteArray(length ushr 1)
var i = 0
while (i < length) {
bytes[i ushr 1] = hexToByte(hexDump, fromIndex + i)
i += 2
}
return bytes
}
fun encodeStringArray(array: List<String>): ByteArray {
var length = 0
for (s in array) {
val bytes = s.toByteArray()
length += bytes.size
}
if (length == 0) {
return ByteArray(0)
}
val bytes = ByteArray(length + array.size)
length = 0
for (s in array) {
val sBytes = s.toByteArray()
System.arraycopy(sBytes, 0, bytes, length, sBytes.size)
length += sBytes.size
bytes[length++] = 0x01.toByte()
}
return bytes
}
fun decodeStringArray(bytes: ByteArray): ArrayList<String> {
val length = bytes.size
var position = 0
val token = 0x01.toByte()
val list = ArrayList<String>(0)
var last = 0
while (last + position < length) {
val b = bytes[last + position++]
if (b == token) {
val xx = ByteArray(position - 1)
System.arraycopy(bytes, last, xx, 0, position - 1)
list.add(String(xx))
last += position
position = 0
}
}
return list
}
@JvmOverloads
fun printArrayRaw(bytes: ByteArray, lineLength: Int = 0): String {
return if (lineLength > 0) {
val length = bytes.size
val comma = length - 1
val builder = StringBuilder(length + length / lineLength)
for (i in 0 until length) {
builder.append(bytes[i].toInt())
if (i < comma) {
builder.append(",")
}
if (i > 0 && i % lineLength == 0) {
builder.append(LINE_SEPARATOR)
}
}
builder.toString()
} else {
val length = bytes.size
val comma = length - 1
val builder = StringBuilder(length + length)
for (i in 0 until length) {
builder.append(bytes[i].toInt())
if (i < comma) {
builder.append(",")
}
}
builder.toString()
}
}
@JvmOverloads
fun printArray(bytes: ByteArray, length: Int = bytes.size, includeByteCount: Boolean = true) {
printArray(bytes, 0, length, includeByteCount, 40, null)
}
@JvmOverloads
fun printArray(
bytes: ByteArray,
inputOffset: Int,
length: Int,
includeByteCount: Boolean,
lineLength: Int = 40,
header: String? = null
) {
val comma = length - 1
var builderLength = length + comma + 2
if (includeByteCount) {
builderLength += 7 + Integer.toString(length).length
}
if (lineLength > 0) {
builderLength += length / lineLength
}
if (header != null) {
builderLength += header.length + 2
}
val builder = StringBuilder(builderLength)
if (header != null) {
builder.append(header).append(LINE_SEPARATOR)
}
if (includeByteCount) {
builder.append("Bytes: ").append(length).append(LINE_SEPARATOR)
}
builder.append("{")
for (i in inputOffset until length) {
builder.append(bytes[i].toInt())
if (i < comma) {
builder.append(",")
}
if (i > inputOffset && lineLength > 0 && i % lineLength == 0) {
builder.append(LINE_SEPARATOR)
}
}
builder.append("}")
System.err.println(builder.toString())
}
}
/**
* Erase the contents of a string, in-memory. This has no effect if the string has been interned.
*/
fun String.eraseString() {
// You can change the value of the inner char[] using reflection.
//
// You must be careful to either change it with an array of the same length,
// or to also update the count field.
//
// If you want to be able to use it as an entry in a set or as a value in map,
// you will need to recalculate the hash code and set the value of the hashCode field.
try {
val valueField = String::class.java.getDeclaredField("value")
valueField.isAccessible = true
val chars = valueField[this] as CharArray
Arrays.fill(chars, '*') // asterisk it out in case of GC not picking up the old char array.
valueField[this] = CharArray(0) // replace it.
// set count to 0
try {
// newer versions of java don't have this field
val countField = String::class.java.getDeclaredField("count")
countField.isAccessible = true
countField[this] = 0
} catch (ignored: Exception) {
}
// set hash to 0
val hashField = String::class.java.getDeclaredField("hash")
hashField.isAccessible = true
hashField[this] = 0
} catch (e: SecurityException) {
e.printStackTrace()
} catch (e: NoSuchFieldException) {
e.printStackTrace()
} catch (e: IllegalArgumentException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}

View File

@ -1,199 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.classes;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Objects;
import net.jodah.typetools.TypeResolver;
public final
class ClassHelper {
/**
* Retrieves the generic type parameter for the PARENT (super) class of the specified class or lambda expression.
*
* Because of how type erasure works in java, this will work on lambda expressions and ONLY parent/super classes.
*
* @param genericTypeClass this class is what you are looking for
* @param classToCheck class to actually get the parameter from
* @param genericParameterToGet 0-based index of parameter as class to get
*
* @return null if the generic type could not be found.
*/
@SuppressWarnings({"StatementWithEmptyBody", "UnnecessaryLocalVariable"})
public static
Class<?> getGenericParameterAsClassForSuperClass(Class<?> genericTypeClass, Class<?> classToCheck, int genericParameterToGet) {
Class<?> loopClassCheck = classToCheck;
// this will ALWAYS return something, if it is unknown, it will return TypeResolver.Unknown.class
Class<?>[] classes = TypeResolver.resolveRawArguments(genericTypeClass, loopClassCheck);
if (classes.length > genericParameterToGet && classes[genericParameterToGet] != TypeResolver.Unknown.class) {
return classes[genericParameterToGet];
}
// case of multiple inheritance, we are trying to get the first available generic info
// don't check for Object.class (this is where superclass is null)
while (loopClassCheck != Object.class) {
// check to see if we have what we are looking for on our CURRENT class
Type superClassGeneric = loopClassCheck.getGenericSuperclass();
classes = TypeResolver.resolveRawArguments(superClassGeneric, loopClassCheck);
if (classes.length > genericParameterToGet) {
Class<?> aClass = classes[genericParameterToGet];
if (aClass != TypeResolver.Unknown.class) {
return classes[genericParameterToGet];
}
}
// NO MATCH, so walk up.
loopClassCheck = loopClassCheck.getSuperclass();
}
// NOTHING! now check interfaces!
loopClassCheck = classToCheck;
while (loopClassCheck != Object.class) {
// check to see if we have what we are looking for on our CURRENT class interfaces
Type[] genericInterfaces = loopClassCheck.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
classes = TypeResolver.resolveRawArguments(genericInterface, loopClassCheck);
if (classes.length > genericParameterToGet) {
Class<?> aClass = classes[genericParameterToGet];
if (aClass != TypeResolver.Unknown.class) {
return aClass;
}
}
}
// NO MATCH, so walk up.
loopClassCheck = loopClassCheck.getSuperclass();
}
// couldn't find it.
return null;
}
// from: https://github.com/square/retrofit/blob/108fe23964b986107aed352ba467cd2007d15208/retrofit/src/main/java/retrofit2/Utils.java
public static Class<?> getRawType(Type type) {
Objects.requireNonNull(type, "type == null");
if (type instanceof Class<?>) {
// Type is a normal class.
return (Class<?>) type;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but
// suspects some pathological case related to nested classes exists.
Type rawType = parameterizedType.getRawType();
if (!(rawType instanceof Class)) throw new IllegalArgumentException();
return (Class<?>) rawType;
}
if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
}
if (type instanceof TypeVariable) {
// We could use the variable's bounds, but that won't work if there are multiple. Having a raw
// type that's more general than necessary is okay.
return Object.class;
}
if (type instanceof WildcardType) {
return getRawType(((WildcardType) type).getUpperBounds()[0]);
}
throw new IllegalArgumentException(
"Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <"
+ type
+ "> is of type "
+ type.getClass().getName());
}
/**
* Check to see if clazz or interface directly has one of the interfaces defined by requiredClass
* <p/>
* If the class DOES NOT directly have the interface it will fail.
*/
public static
boolean hasInterface(Class<?> requiredClass, Class<?> clazz) {
if (requiredClass == clazz) {
return true;
}
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> iface : interfaces) {
if (iface == requiredClass) {
return true;
}
}
// now walk up to see if we can find it.
for (Class<?> iface : interfaces) {
boolean b = hasInterface(requiredClass, iface);
if (b) {
return b;
}
}
// nothing, so now we check the PARENT of this class
Class<?> superClass = clazz.getSuperclass();
// case of multiple inheritance, we are trying to get the first available generic info
// don't check for Object.class (this is where superclass is null)
while (superClass != null && superClass != Object.class) {
// check to see if we have what we are looking for on our CURRENT class
if (hasInterface(requiredClass, superClass)) {
return true;
}
// NO MATCH, so walk up.
superClass = superClass.getSuperclass();
}
// if we don't find it.
return false;
}
/**
* Checks to see if the clazz is a subclass of a parent class.
*/
@SuppressWarnings("SimplifiableIfStatement")
public static
boolean hasParentClass(Class<?> parentClazz, Class<?> clazz) {
Class<?> superClass = clazz.getSuperclass();
if (parentClazz == superClass) {
return true;
}
if (superClass != null && superClass != Object.class) {
return hasParentClass(parentClazz, superClass);
}
return false;
}
private
ClassHelper() {
}
}

View File

@ -1,187 +0,0 @@
/*
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.classes;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import dorkbox.collections.IdentityMap;
/**
* @author dorkbox
* Date: 4/1/15
*/
public final
class ClassHierarchy {
private volatile IdentityMap<Class<?>, Class<?>> arrayCache;
private volatile IdentityMap<Class<?>, Class<?>[]> superClassesCache;
// Recommended for best performance while adhering to the "single writer principle". Must be static-final
private static final AtomicReferenceFieldUpdater<ClassHierarchy, IdentityMap> arrayREF =
AtomicReferenceFieldUpdater.newUpdater(ClassHierarchy.class,
IdentityMap.class,
"arrayCache");
private static final AtomicReferenceFieldUpdater<ClassHierarchy, IdentityMap> superClassesREF =
AtomicReferenceFieldUpdater.newUpdater(ClassHierarchy.class,
IdentityMap.class,
"superClassesCache");
/**
* These data structures are never reset because the class hierarchy doesn't change at runtime. This class uses the "single writer
* principle" for storing data, EVEN THOUGH it's not accessed by a single writer. This DOES NOT MATTER because duplicates DO NOT matter
*/
public
ClassHierarchy(float loadFactor) {
this.arrayCache = new IdentityMap<Class<?>, Class<?>>(32, loadFactor);
this.superClassesCache = new IdentityMap<Class<?>, Class<?>[]>(32, loadFactor);
}
/**
* will return the class + parent classes as an array.
* if parameter clazz is of type array, then the super classes are of array type as well
* <p>
* race conditions will result in DUPLICATE answers, which we don't care if happens
* never returns null
* never reset (class hierarchy never changes during runtime)
*/
public
Class<?>[] getClassAndSuperClasses(final Class<?> clazz) {
// access a snapshot of the subscriptions (single-writer-principle)
final IdentityMap<Class<?>, Class<?>[]> cache = cast(superClassesREF.get(this));
Class<?>[] classes = cache.get(clazz);
// duplicates DO NOT MATTER
if (classes == null) {
// publish all super types of class
final Iterator<Class<?>> superTypesIterator = getSuperTypes(clazz);
final ArrayList<Class<?>> newList = new ArrayList<Class<?>>(16);
Class<?> c;
final boolean isArray = clazz.isArray();
// have to add the original class to the front of the list
newList.add(clazz);
if (isArray) {
// super-types for an array ALSO must be an array.
while (superTypesIterator.hasNext()) {
c = superTypesIterator.next();
c = getArrayClass(c);
if (c != clazz) {
newList.add(c);
}
}
}
else {
while (superTypesIterator.hasNext()) {
c = superTypesIterator.next();
if (c != clazz) {
newList.add(c);
}
}
}
classes = new Class<?>[newList.size()];
newList.toArray(classes);
cache.put(clazz, classes);
// save this snapshot back to the original (single writer principle)
superClassesREF.lazySet(this, cache);
}
return classes;
}
/**
* race conditions will result in DUPLICATE answers, which we don't care if happens
* never returns null
* never resets (class hierarchy never changes during runtime)
*
* https://bugs.openjdk.java.net/browse/JDK-6525802 (fixed this in 2007, so Array.newInstance is just as fast (via intrinsics) new [])
* Cache is in place to keep GC down.
*/
public
Class<?> getArrayClass(final Class<?> c) {
// access a snapshot of the subscriptions (single-writer-principle)
final IdentityMap<Class<?>, Class<?>> cache = cast(arrayREF.get(this));
Class<?> clazz = cache.get(c);
if (clazz == null) {
// messy, but the ONLY way to do it. Array super types are also arrays
final Object[] newInstance = (Object[]) Array.newInstance(c, 0);
clazz = newInstance.getClass();
cache.put(c, clazz);
// save this snapshot back to the original (single writer principle)
arrayREF.lazySet(this, cache);
}
return clazz;
}
/**
* Collect all directly and indirectly related super types (classes and interfaces) of a given class.
*
* @param from The root class to start with
* @return An array of classes, each representing a super type of the root class
*/
public static
Iterator<Class<?>> getSuperTypes(Class<?> from) {
// This must be a 'set' because there can be duplicates, depending on the object hierarchy
final IdentityMap<Class<?>, Boolean> superclasses = new IdentityMap<Class<?>, Boolean>();
collectInterfaces(from, superclasses);
while (!from.equals(Object.class) && !from.isInterface()) {
superclasses.put(from.getSuperclass(), Boolean.TRUE);
from = from.getSuperclass();
collectInterfaces(from, superclasses);
}
return superclasses.keys();
}
private static
void collectInterfaces(Class<?> from, IdentityMap<Class<?>, Boolean> accumulator) {
for (Class<?> intface : from.getInterfaces()) {
accumulator.put(intface, Boolean.TRUE);
collectInterfaces(intface, accumulator);
}
}
/**
* Clears the caches, should only be called on shutdown
*/
public
void shutdown() {
this.arrayCache.clear();
this.superClassesCache.clear();
}
@SuppressWarnings("unchecked")
private static
<T> T cast(Object obj) {
return (T) obj;
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.classes;
public abstract class ClassResolver {
/**
* A helper class to get the call context. It subclasses SecurityManager to make getClassContext() accessible. An instance of
* CallerResolver only needs to be created, not installed as an actual security manager.
*/
private static final class CallerResolver extends SecurityManager {
@Override
protected Class<?>[] getClassContext() {
return super.getClassContext();
}
}
private static final int CALL_CONTEXT_OFFSET = 3; // may need to change if this class is redesigned
private static final CallerResolver CALLER_RESOLVER;
static {
try {
// This can fail if the current SecurityManager does not allow
// RuntimePermission ("createSecurityManager"):
CALLER_RESOLVER = new CallerResolver();
} catch (SecurityException se) {
throw new RuntimeException("ClassLoaderResolver: could not create CallerResolver: " + se);
}
}
/**
* Indexes into the current method call context with a given offset.
*/
public static Class<?> getCallerClass(final int callerOffset) {
return CALLER_RESOLVER.getClassContext()[CALL_CONTEXT_OFFSET + callerOffset];
}
}

View File

@ -1,188 +0,0 @@
/*
* Copyright 2012 Benjamin Diedrichsen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.classes;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import dorkbox.collections.IdentityMap;
/**
* @author bennidi
* Date: 2/16/12
* Time: 12:14 PM
* @author dorkbox
* Date: 2/2/15
*/
public final
class ReflectionUtils {
private static final Method[] EMPTY_METHODS = new Method[0];
private
ReflectionUtils() {
}
/**
* Get methods annotated with the specified annotation.
*
* @param target the class that you are looking for the methods on
* @param annotationClass the annotations that define the method you are looking for
* @param <A> the annotation type
*
* @return the array of methods that match the target + annotation
*/
public static
<A extends Annotation> Method[] getMethods(Class<?> target, Class<A> annotationClass) {
ArrayList<Method> methods = new ArrayList<Method>();
getMethods(target, annotationClass, methods);
return methods.toArray(EMPTY_METHODS);
}
private static
<A extends Annotation> void getMethods(Class<?> target, Class<A> annotationClass, ArrayList<Method> methods) {
try {
for (Method method : target.getDeclaredMethods()) {
if (getAnnotation(method, annotationClass) != null) {
methods.add(method);
}
}
} catch (Exception ignored) {
}
// recursively go until root
if (!target.equals(Object.class)) {
getMethods(target.getSuperclass(), annotationClass, methods);
}
}
/**
* Traverses the class hierarchy upwards, starting at the given subclass, looking
* for an override of the given methods -> finds the bottom most override of the given
* method if any exists
*/
public static
Method getOverridingMethod(final Method overridingMethod, final Class<?> subclass) {
Class<?> current = subclass;
while (!current.equals(overridingMethod.getDeclaringClass())) {
try {
return current.getDeclaredMethod(overridingMethod.getName(), overridingMethod.getParameterTypes());
} catch (NoSuchMethodException e) {
current = current.getSuperclass();
}
}
return null;
}
public static
boolean containsOverridingMethod(final Method[] allMethods, final Method methodToCheck) {
final int length = allMethods.length;
Method method;
for (int i = 0; i < length; i++) {
method = allMethods[i];
if (isOverriddenBy(methodToCheck, method)) {
return true;
}
}
return false;
}
/**
* Searches for an Annotation of the given type on the class. Supports meta annotations.
*
* @param from AnnotatedElement (class, method...)
* @param annotationType Annotation class to look for.
* @param <A> Class of annotation type
* @return Annotation instance or null
*/
private static
<A extends Annotation> A getAnnotation(AnnotatedElement from, Class<A> annotationType, IdentityMap<AnnotatedElement, Boolean> visited) {
if (visited.containsKey(from)) {
return null;
}
visited.put(from, Boolean.TRUE);
A ann = from.getAnnotation(annotationType);
if (ann != null) {
return ann;
}
for (Annotation metaAnn : from.getAnnotations()) {
ann = getAnnotation(metaAnn.annotationType(), annotationType, visited);
if (ann != null) {
return ann;
}
}
return null;
}
public static
<A extends Annotation> A getAnnotation(AnnotatedElement from, Class<A> annotationType) {
return getAnnotation(from, annotationType, new IdentityMap<AnnotatedElement, Boolean>());
}
private static
boolean isOverriddenBy(final Method superclassMethod, final Method subclassMethod) {
// if the declaring classes are the same or the subclass method is not defined in the subclass
// hierarchy of the given superclass method or the method names are not the same then
// subclassMethod does not override superclassMethod
if (superclassMethod.getDeclaringClass().equals(subclassMethod.getDeclaringClass()) ||
!superclassMethod.getDeclaringClass().isAssignableFrom(subclassMethod.getDeclaringClass()) ||
!superclassMethod.getName().equals(subclassMethod.getName())) {
return false;
}
final Class<?>[] superClassMethodParameters = superclassMethod.getParameterTypes();
final Class<?>[] subClassMethodParameters = subclassMethod.getParameterTypes();
// method must specify the same number of parameters
//the parameters must occur in the exact same order
for (int i = 0; i < subClassMethodParameters.length; i++) {
if (!superClassMethodParameters[i].equals(subClassMethodParameters[i])) {
return false;
}
}
return true;
}
}

View File

@ -1,17 +0,0 @@
/*
* Copyright 2021 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.classes;

View File

@ -1,24 +0,0 @@
/*
* Copyright 2021 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.classes;
/**
* Required for intellij to not complain regarding `module-info` for a multi-release jar.
* This file is completely ignored by the gradle build process
*/
public
class EmptyClass {}

View File

@ -2,7 +2,6 @@ module dorkbox.utilities {
exports dorkbox.exit;
exports dorkbox.urlHandler;
exports dorkbox.util;
exports dorkbox.util.classes;
exports dorkbox.util.entropy;
exports dorkbox.util.exceptions;
exports dorkbox.util.gwt;
@ -10,7 +9,6 @@ module dorkbox.utilities {
exports dorkbox.util.sync;
exports dorkbox.util.userManagement;
requires transitive dorkbox.executor;
requires transitive dorkbox.updates;
requires transitive dorkbox.os;

View File

@ -1,277 +0,0 @@
/*
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util;
import java.io.IOException;
import java.util.Random;
import org.junit.Test;
public class MersenneTwisterFastTest {
@Test
public void mersenneTwisterTest() throws IOException {
int j;
MersenneTwisterFast r;
// CORRECTNESS TEST
// COMPARE WITH
// http://www.math.keio.ac.jp/matumoto/CODES/MT2002/mt19937ar.out
r = new MersenneTwisterFast(new int[] {0x123,0x234,0x345,0x456});
// System.out.println("Output of MersenneTwisterFast with new (2002/1/26) seeding mechanism");
for (j = 0; j < 1000; j++) {
// first, convert the int from signed to "unsigned"
long l = r.nextInt();
if (l < 0) {
l += 4294967296L; // max int value
}
String s = String.valueOf(l);
while (s.length() < 10) {
s = " " + s; // buffer
}
System.out.print(s + " ");
if (j % 5 == 4) {
System.out.println();
}
}
// SPEED TEST
final long SEED = 4357;
int xx;
long ms;
System.out.println("\nTime to test grabbing 100000000 ints");
Random rr = new Random(SEED);
xx = 0;
ms = System.currentTimeMillis();
for (j = 0; j < 100000000; j++) {
xx += rr.nextInt();
}
System.out.println("java.util.Random: " + (System.currentTimeMillis() - ms) + " Ignore this: " + xx);
r = new MersenneTwisterFast(SEED);
ms = System.currentTimeMillis();
xx = 0;
for (j = 0; j < 100000000; j++) {
xx += r.nextInt();
}
System.out.println("Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: "
+ xx);
// TEST TO COMPARE TYPE CONVERSION BETWEEN
// MersenneTwisterFast.java AND MersenneTwister.java
boolean test = false;
System.out.println("\nGrab the first 1000 booleans");
ms = System.currentTimeMillis();
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
// System.out.print(r.nextBoolean() + " ");
test = r.nextBoolean();
if (j % 8 == 7) {
// System.out.println();
test = false;
}
}
if (!(j % 8 == 7)) {
// System.out.println();
test = true;
}
System.out.println("Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: "
+ xx + "" + test);
System.out.println("\nGrab 1000 booleans of increasing probability using nextBoolean(double)");
r = new MersenneTwisterFast(SEED);
ms = System.currentTimeMillis();
for (j = 0; j < 1000; j++) {
// System.out.print(r.nextBoolean(j / 999.0) + " ");
test = r.nextBoolean(j / 999.0);
if (j % 8 == 7) {
// System.out.println();
test = false;
}
}
if (!(j % 8 == 7)) {
// System.out.println();
test = true;
}
System.out.println("Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: "
+ xx + "" + test);
System.out.println("\nGrab 1000 booleans of increasing probability using nextBoolean(float)");
r = new MersenneTwisterFast(SEED);
ms = System.currentTimeMillis();
for (j = 0; j < 1000; j++) {
// System.out.print(r.nextBoolean(j / 999.0f) + " ");
test = r.nextBoolean(j / 999.0f);
if (j % 8 == 7) {
test = false;
System.out.println();
}
}
if (!(j % 8 == 7)) {
// System.out.println();
test = true;
}
System.out.println("Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: "
+ xx + "" + test);
byte[] bytes = new byte[1000];
System.out.println("\nGrab the first 1000 bytes using nextBytes");
r = new MersenneTwisterFast(SEED);
r.nextBytes(bytes);
for (j = 0; j < 1000; j++) {
System.out.print(bytes[j] + " ");
if (j % 16 == 15) {
System.out.println();
}
}
if (!(j % 16 == 15)) {
System.out.println();
}
byte b;
System.out.println("\nGrab the first 1000 bytes -- must be same as nextBytes");
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
System.out.print((b = r.nextByte()) + " ");
if (b != bytes[j]) {
System.out.print("BAD ");
}
if (j % 16 == 15) {
System.out.println();
}
}
if (!(j % 16 == 15)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 shorts");
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
System.out.print(r.nextShort() + " ");
if (j % 8 == 7) {
System.out.println();
}
}
if (!(j % 8 == 7)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 ints");
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
System.out.print(r.nextInt() + " ");
if (j % 4 == 3) {
System.out.println();
}
}
if (!(j % 4 == 3)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 ints of different sizes");
r = new MersenneTwisterFast(SEED);
int max = 1;
for (j = 0; j < 1000; j++) {
System.out.print(r.nextInt(max) + " ");
max *= 2;
if (max <= 0) {
max = 1;
}
if (j % 4 == 3) {
System.out.println();
}
}
if (!(j % 4 == 3)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 longs");
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
System.out.print(r.nextLong() + " ");
if (j % 3 == 2) {
System.out.println();
}
}
if (!(j % 3 == 2)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 longs of different sizes");
r = new MersenneTwisterFast(SEED);
long max2 = 1;
for (j = 0; j < 1000; j++) {
System.out.print(r.nextLong(max2) + " ");
max2 *= 2;
if (max2 <= 0) {
max2 = 1;
}
if (j % 4 == 3) {
System.out.println();
}
}
if (!(j % 4 == 3)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 floats");
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
System.out.print(r.nextFloat() + " ");
if (j % 4 == 3) {
System.out.println();
}
}
if (!(j % 4 == 3)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 doubles");
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
System.out.print(r.nextDouble() + " ");
if (j % 3 == 2) {
System.out.println();
}
}
if (!(j % 3 == 2)) {
System.out.println();
}
System.out.println("\nGrab the first 1000 gaussian doubles");
r = new MersenneTwisterFast(SEED);
for (j = 0; j < 1000; j++) {
System.out.print(r.nextGaussian() + " ");
if (j % 3 == 2) {
System.out.println();
}
}
if (!(j % 3 == 2)) {
System.out.println();
}
}
}

View File

@ -0,0 +1,292 @@
/*
* Copyright 2015 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util
import org.junit.Test
import java.io.IOException
import java.util.*
class MersenneTwisterFastTest {
@Test
@Throws(IOException::class)
fun mersenneTwisterTest() {
var j: Int
var r: MersenneTwisterFast
// CORRECTNESS TEST
// COMPARE WITH
// http://www.math.keio.ac.jp/matumoto/CODES/MT2002/mt19937ar.out
r = MersenneTwisterFast(intArrayOf(0x123, 0x234, 0x345, 0x456))
// System.out.println("Output of MersenneTwisterFast with new (2002/1/26) seeding mechanism");
j = 0
while (j < 1000) {
// first, convert the int from signed to "unsigned"
var l = r.nextInt().toLong()
if (l < 0) {
l += 4294967296L // max int value
}
var s = l.toString()
while (s.length < 10) {
s = " $s" // buffer
}
print("$s ")
if (j % 5 == 4) {
println()
}
j++
}
// SPEED TEST
val SEED: Long = 4357
var xx: Int
var ms: Long
println("\nTime to test grabbing 100000000 ints")
val rr = Random(SEED)
xx = 0
ms = System.currentTimeMillis()
j = 0
while (j < 100000000) {
xx += rr.nextInt()
j++
}
println("java.util.Random: " + (System.currentTimeMillis() - ms) + " Ignore this: " + xx)
r = MersenneTwisterFast(SEED)
ms = System.currentTimeMillis()
xx = 0
j = 0
while (j < 100000000) {
xx += r.nextInt()
j++
}
println(
"Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: " + xx
)
// TEST TO COMPARE TYPE CONVERSION BETWEEN
// MersenneTwisterFast.java AND MersenneTwister.java
var test = false
println("\nGrab the first 1000 booleans")
ms = System.currentTimeMillis()
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
// System.out.print(r.nextBoolean() + " ");
test = r.nextBoolean()
if (j % 8 == 7) {
// System.out.println();
test = false
}
j++
}
if (j % 8 != 7) {
// System.out.println();
test = true
}
println(
"Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: " + xx + "" + test
)
println("\nGrab 1000 booleans of increasing probability using nextBoolean(double)")
r = MersenneTwisterFast(SEED)
ms = System.currentTimeMillis()
j = 0
while (j < 1000) {
// System.out.print(r.nextBoolean(j / 999.0) + " ");
test = r.nextBoolean(j / 999.0)
if (j % 8 == 7) {
// System.out.println();
test = false
}
j++
}
if (j % 8 != 7) {
// System.out.println();
test = true
}
println(
"Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: " + xx + "" + test
)
println("\nGrab 1000 booleans of increasing probability using nextBoolean(float)")
r = MersenneTwisterFast(SEED)
ms = System.currentTimeMillis()
j = 0
while (j < 1000) {
// System.out.print(r.nextBoolean(j / 999.0f) + " ");
test = r.nextBoolean(j / 999.0f)
if (j % 8 == 7) {
test = false
println()
}
j++
}
if (j % 8 != 7) {
// System.out.println();
test = true
}
println(
"Mersenne Twister Fast: " + (System.currentTimeMillis() - ms) + " Ignore this: " + xx + "" + test
)
val bytes = ByteArray(1000)
println("\nGrab the first 1000 bytes using nextBytes")
r = MersenneTwisterFast(SEED)
r.nextBytes(bytes)
j = 0
while (j < 1000) {
print(bytes[j].toString() + " ")
if (j % 16 == 15) {
println()
}
j++
}
if (j % 16 != 15) {
println()
}
var b: Byte
println("\nGrab the first 1000 bytes -- must be same as nextBytes")
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
print(r.nextByte().also { b = it }.toString() + " ")
if (b != bytes[j]) {
print("BAD ")
}
if (j % 16 == 15) {
println()
}
j++
}
if (j % 16 != 15) {
println()
}
println("\nGrab the first 1000 shorts")
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
print(r.nextShort().toString() + " ")
if (j % 8 == 7) {
println()
}
j++
}
if (j % 8 != 7) {
println()
}
println("\nGrab the first 1000 ints")
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
print(r.nextInt().toString() + " ")
if (j % 4 == 3) {
println()
}
j++
}
if (j % 4 != 3) {
println()
}
println("\nGrab the first 1000 ints of different sizes")
r = MersenneTwisterFast(SEED)
var max = 1
j = 0
while (j < 1000) {
print(r.nextInt(max).toString() + " ")
max *= 2
if (max <= 0) {
max = 1
}
if (j % 4 == 3) {
println()
}
j++
}
if (j % 4 != 3) {
println()
}
println("\nGrab the first 1000 longs")
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
print(r.nextLong().toString() + " ")
if (j % 3 == 2) {
println()
}
j++
}
if (j % 3 != 2) {
println()
}
println("\nGrab the first 1000 longs of different sizes")
r = MersenneTwisterFast(SEED)
var max2: Long = 1
j = 0
while (j < 1000) {
print(r.nextLong(max2).toString() + " ")
max2 *= 2
if (max2 <= 0) {
max2 = 1
}
if (j % 4 == 3) {
println()
}
j++
}
if (j % 4 != 3) {
println()
}
println("\nGrab the first 1000 floats")
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
print(r.nextFloat().toString() + " ")
if (j % 4 == 3) {
println()
}
j++
}
if (j % 4 != 3) {
println()
}
println("\nGrab the first 1000 doubles")
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
print(r.nextDouble().toString() + " ")
if (j % 3 == 2) {
println()
}
j++
}
if (j % 3 != 2) {
println()
}
println("\nGrab the first 1000 gaussian doubles")
r = MersenneTwisterFast(SEED)
j = 0
while (j < 1000) {
print(r.nextGaussian().toString() + " ")
if (j % 3 == 2) {
println()
}
j++
}
if (j % 3 != 2) {
println()
}
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util
import org.junit.Assert
import org.junit.Test
import java.util.concurrent.*
class TimeTest {
@Test
fun time() {
TimeUnit.DAYS.toNanos(3).also {
Assert.assertEquals("3 days", Sys.getTimePrettyFull(it))
}
TimeUnit.DAYS.toNanos(30).also {
Assert.assertEquals("30 days", Sys.getTimePrettyFull(it))
}
TimeUnit.DAYS.toNanos(300).also {
Assert.assertEquals("300 days", Sys.getTimePrettyFull(it))
}
TimeUnit.DAYS.toNanos(3000).also {
Assert.assertEquals("3000 days", Sys.getTimePrettyFull(it))
}
TimeUnit.HOURS.toNanos(3).also {
Assert.assertEquals("3 hours", Sys.getTimePrettyFull(it))
}
TimeUnit.MINUTES.toNanos(3).also {
Assert.assertEquals("3 minutes", Sys.getTimePrettyFull(it))
}
TimeUnit.SECONDS.toNanos(3).also {
Assert.assertEquals("3 seconds", Sys.getTimePrettyFull(it))
}
TimeUnit.MILLISECONDS.toNanos(3).also {
Assert.assertEquals("3 milli-seconds", Sys.getTimePrettyFull(it))
}
TimeUnit.MICROSECONDS.toNanos(3).also {
Assert.assertEquals("3 micro-seconds", Sys.getTimePrettyFull(it))
}
TimeUnit.NANOSECONDS.toNanos(3).also {
Assert.assertEquals("3 nano-seconds", Sys.getTimePrettyFull(it))
}
TimeUnit.NANOSECONDS.toNanos(1).also {
Assert.assertEquals("1 nano-second", Sys.getTimePrettyFull(it))
}
}
}