Compare commits

...

12 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
12 changed files with 465 additions and 657 deletions

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

View File

@ -17,7 +17,7 @@ Maven Info
<dependency>
<groupId>com.dorkbox</groupId>
<artifactId>Utilities</artifactId>
<version>1.45</version>
<version>1.48</version>
</dependency>
</dependencies>
```
@ -27,7 +27,7 @@ Gradle Info
```
dependencies {
...
compile "com.dorkbox:Utilities:1.45"
compile "com.dorkbox:Utilities:1.48"
}
```

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.45"
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")
@ -142,8 +136,6 @@ dependencies {
// api("org.slf4j:slf4j-api:2.0.7")
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"

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

@ -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

@ -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.45"
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,6 +253,7 @@ object Sys {
return b
}
@Deprecated("Use kotlin")
fun concatBytes(vararg arrayBytes: ByteArray): ByteArray {
var length = 0
for (bytes in arrayBytes) {
@ -292,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,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))
}
}
}