mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix code
This commit is contained in:
@@ -703,7 +703,7 @@ public class AnnotatedElementUtil {
|
||||
/**
|
||||
* 清空相关缓存,包括:
|
||||
* <ul>
|
||||
* <li>{@link AnnotatedElementUtil}中的{@link AnnotatedElement}及{@link AnnotationMapping}缓存;</li>
|
||||
* <li>{@code AnnotatedElementUtil}中的{@link AnnotatedElement}及{@link AnnotationMapping}缓存;</li>
|
||||
* <li>{@link AnnotationUtil}中的{@link AnnotatedElement}上直接声明的注解缓存;</li>
|
||||
* <li>{@link RepeatableAnnotationCollector}中单例的注解属性缓存;</li>
|
||||
* </ul>
|
||||
|
@@ -25,7 +25,7 @@ public interface RepeatableAnnotationCollector {
|
||||
/**
|
||||
* 空实现
|
||||
*
|
||||
* @return {@link RepeatableAnnotationCollector}实例
|
||||
* @return {@code RepeatableAnnotationCollector}实例
|
||||
*/
|
||||
static RepeatableAnnotationCollector none() {
|
||||
return None.INSTANCE;
|
||||
@@ -47,7 +47,7 @@ public interface RepeatableAnnotationCollector {
|
||||
* </code></pre>
|
||||
* 解析任意{@code Annotation}注解对象,则可以获得{@code value}属性中的{@code Item}注解对象
|
||||
*
|
||||
* @return {@link RepeatableAnnotationCollector}实例
|
||||
* @return {@code RepeatableAnnotationCollector}实例
|
||||
* @see Standard
|
||||
*/
|
||||
static RepeatableAnnotationCollector standard() {
|
||||
@@ -59,7 +59,7 @@ public interface RepeatableAnnotationCollector {
|
||||
* 收集器将返回所有匹配的属性中的可重复注解。
|
||||
*
|
||||
* @param predicate 是否为容纳可重复注解的属性的判断条件
|
||||
* @return {@link RepeatableAnnotationCollector}实例
|
||||
* @return {@code RepeatableAnnotationCollector}实例
|
||||
*/
|
||||
static RepeatableAnnotationCollector condition(final BiPredicate<Annotation, Method> predicate) {
|
||||
return new Condition(predicate);
|
||||
@@ -80,7 +80,7 @@ public interface RepeatableAnnotationCollector {
|
||||
* 则可以获得{@code items1}属性中的{@code Item1}注解对象,
|
||||
* 以及{@code items2}属性中的{@code Item2}注解对象,
|
||||
*
|
||||
* @return {@link RepeatableAnnotationCollector}实例
|
||||
* @return {@code RepeatableAnnotationCollector}实例
|
||||
*/
|
||||
static RepeatableAnnotationCollector full() {
|
||||
return Full.INSTANCE;
|
||||
@@ -189,7 +189,7 @@ public interface RepeatableAnnotationCollector {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link RepeatableAnnotationCollector}的基本实现
|
||||
* {@code RepeatableAnnotationCollector}的基本实现
|
||||
*/
|
||||
abstract class AbstractCollector implements RepeatableAnnotationCollector {
|
||||
|
||||
@@ -218,7 +218,7 @@ public interface RepeatableAnnotationCollector {
|
||||
* @return 容器注解中的可重复注解,若{@code annotation}不为容器注解,则数组中仅有其本身一个对象
|
||||
*/
|
||||
@Override
|
||||
public List<Annotation> getAllRepeatableAnnotations(Annotation annotation) {
|
||||
public List<Annotation> getAllRepeatableAnnotations(final Annotation annotation) {
|
||||
return find(annotation, null, true);
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ public interface RepeatableAnnotationCollector {
|
||||
final boolean isTarget = hasCondition && condition.test(source);
|
||||
if (CollUtil.isEmpty(repeatableMethods) || isTarget) {
|
||||
// 不是累加的,则仅当正在处理的注解不为可重复注解时才记录
|
||||
boolean shouldProcess = !accumulate && (!hasCondition || isTarget);
|
||||
final boolean shouldProcess = !accumulate && (!hasCondition || isTarget);
|
||||
if (shouldProcess) {
|
||||
results.add(source);
|
||||
}
|
||||
|
@@ -145,10 +145,10 @@ public class ResolvedAnnotationMapping implements AnnotationMapping<Annotation>
|
||||
* <ul>
|
||||
* <li>当{@code annotation}已经被代理过时抛出;</li>
|
||||
* <li>当{@code source}包装的注解对象与{@code annotation}相同时抛出;</li>
|
||||
* <li>当{@code annotation}包装的注解对象类型为{@link ResolvedAnnotationMapping}时抛出;</li>
|
||||
* <li>当{@code annotation}包装的注解对象类型为{@code ResolvedAnnotationMapping}时抛出;</li>
|
||||
* </ul>
|
||||
*/
|
||||
ResolvedAnnotationMapping(final ResolvedAnnotationMapping source, final Annotation annotation, boolean resolveAttribute) {
|
||||
ResolvedAnnotationMapping(final ResolvedAnnotationMapping source, final Annotation annotation, final boolean resolveAttribute) {
|
||||
Objects.requireNonNull(annotation);
|
||||
Assert.isFalse(AnnotationMappingProxy.isProxied(annotation), "annotation has been proxied");
|
||||
Assert.isFalse(annotation instanceof ResolvedAnnotationMapping, "annotation has been wrapped");
|
||||
@@ -254,7 +254,6 @@ public class ResolvedAnnotationMapping implements AnnotationMapping<Annotation>
|
||||
*
|
||||
* @return 所需的注解,若{@link ResolvedAnnotationMapping#isResolved()}为{@code false}则返回的是原始的注解对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Annotation getResolvedAnnotation() {
|
||||
if (!isResolved()) {
|
||||
@@ -399,7 +398,7 @@ public class ResolvedAnnotationMapping implements AnnotationMapping<Annotation>
|
||||
}
|
||||
// 获取除自己外的全部子注解
|
||||
final Deque<ResolvedAnnotationMapping> sources = new LinkedList<>();
|
||||
Set<Class<? extends Annotation>> accessed = new HashSet<>();
|
||||
final Set<Class<? extends Annotation>> accessed = new HashSet<>();
|
||||
accessed.add(this.annotationType());
|
||||
ResolvedAnnotationMapping sourceMapping = this.source;
|
||||
while (Objects.nonNull(sourceMapping)) {
|
||||
@@ -444,7 +443,7 @@ public class ResolvedAnnotationMapping implements AnnotationMapping<Annotation>
|
||||
* 更新需要覆写的属性的相关映射关系,若该属性存在别名,则将别名的映射关系一并覆写
|
||||
*/
|
||||
private void overwriteAttribute(
|
||||
final ResolvedAnnotationMapping overwriteMapping, final int overwriteIndex, final int targetIndex, boolean overwriteAliases) {
|
||||
final ResolvedAnnotationMapping overwriteMapping, final int overwriteIndex, final int targetIndex, final boolean overwriteAliases) {
|
||||
// 若目标属性已被覆写,则不允许再次覆写
|
||||
if (isOverwrittenAttribute(targetIndex)) {
|
||||
return;
|
||||
@@ -463,7 +462,7 @@ public class ResolvedAnnotationMapping implements AnnotationMapping<Annotation>
|
||||
/**
|
||||
* 判断该属性是否已被覆写
|
||||
*/
|
||||
private boolean isOverwrittenAttribute(int index) {
|
||||
private boolean isOverwrittenAttribute(final int index) {
|
||||
// 若属性未发生过解析,则必然未被覆写
|
||||
return NOT_FOUND_INDEX != resolvedAttributes[index]
|
||||
// 若属性发生过解析,且指向其他实例,则说明已被覆写
|
||||
@@ -567,14 +566,14 @@ public class ResolvedAnnotationMapping implements AnnotationMapping<Annotation>
|
||||
* @return 是否
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ResolvedAnnotationMapping that = (ResolvedAnnotationMapping)o;
|
||||
final ResolvedAnnotationMapping that = (ResolvedAnnotationMapping)o;
|
||||
return resolved == that.resolved && annotation.equals(that.annotation);
|
||||
}
|
||||
|
||||
@@ -671,8 +670,8 @@ public class ResolvedAnnotationMapping implements AnnotationMapping<Annotation>
|
||||
/**
|
||||
* 遍历下标
|
||||
*/
|
||||
void forEach(IntConsumer consumer) {
|
||||
for (int index : indexes) {
|
||||
void forEach(final IntConsumer consumer) {
|
||||
for (final int index : indexes) {
|
||||
consumer.accept(index);
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,13 @@ public abstract class AbsCopier<S, T> implements Copier<T> {
|
||||
*/
|
||||
protected final CopyOptions copyOptions;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param source 源对象
|
||||
* @param target 目标对象
|
||||
* @param copyOptions 拷贝选项
|
||||
*/
|
||||
public AbsCopier(final S source, final T target, final CopyOptions copyOptions) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
|
@@ -31,7 +31,7 @@ public class HexUtil {
|
||||
* @return 是否为16进制
|
||||
*/
|
||||
public static boolean isHexNumber(final String value) {
|
||||
if(StrUtil.startWith(value, '-')){
|
||||
if (StrUtil.startWith(value, '-')) {
|
||||
// issue#2875
|
||||
return false;
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public class HexUtil {
|
||||
if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
|
||||
index += 2;
|
||||
} else if (value.startsWith("#", index)) {
|
||||
index ++;
|
||||
index++;
|
||||
}
|
||||
try {
|
||||
new BigInteger(value.substring(index), 16);
|
||||
@@ -253,7 +253,7 @@ public class HexUtil {
|
||||
* 转换的字符串如果u后不足4位,则前面用0填充,例如:
|
||||
*
|
||||
* <pre>
|
||||
* '你' =》\u4f60
|
||||
* 你 =》 \u4f60
|
||||
* </pre>
|
||||
*
|
||||
* @param value int值,也可以是char
|
||||
@@ -278,7 +278,7 @@ public class HexUtil {
|
||||
* 转换的字符串如果u后不足4位,则前面用0填充,例如:
|
||||
*
|
||||
* <pre>
|
||||
* '你' =》'\u4f60'
|
||||
* 你 =》 \u4f60
|
||||
* </pre>
|
||||
*
|
||||
* @param ch char值
|
||||
|
@@ -81,7 +81,7 @@ public class Base16Codec implements Encoder<byte[], char[]>, Decoder<CharSequenc
|
||||
* 转换的字符串如果u后不足4位,则前面用0填充,例如:
|
||||
*
|
||||
* <pre>
|
||||
* '你' =》'\u4f60'
|
||||
* 你 =》\u4f60
|
||||
* </pre>
|
||||
*
|
||||
* @param ch char值
|
||||
|
@@ -7,7 +7,7 @@ import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Base32 - encodes and decodes RFC4648 Base32<br>
|
||||
* (see <a href="https://datatracker.ietf.org/doc/html/rfc4648#section-6">https://datatracker.ietf.org/doc/html/rfc4648#section-6</a> )<br>
|
||||
* (see <a href="https://datatracker.ietf.org/doc/html/rfc4648#section-6">https://datatracker.ietf.org/doc/html/rfc4648#section-6</a> )<br>
|
||||
* base32就是用32(2的5次方)个特定ASCII码来表示256个ASCII码。<br>
|
||||
* 所以,5个ASCII字符经过base32编码后会变为8个字符(公约数为40),长度增加3/5.不足8n用“=”补足。<br>
|
||||
* 根据RFC4648 Base32规范,支持两种模式:
|
||||
@@ -69,7 +69,13 @@ public class Base32Codec implements Encoder<byte[], String>, Decoder<CharSequenc
|
||||
private static final Character DEFAULT_PAD = '=';
|
||||
private static final int[] BASE32_FILL = {-1, 4, 1, 6, 3};
|
||||
|
||||
/**
|
||||
* 编码器
|
||||
*/
|
||||
public static final Base32Encoder ENCODER = new Base32Encoder(DEFAULT_ALPHABET, DEFAULT_PAD);
|
||||
/**
|
||||
* 16进制编码器
|
||||
*/
|
||||
public static final Base32Encoder HEX_ENCODER = new Base32Encoder(HEX_ALPHABET, DEFAULT_PAD);
|
||||
|
||||
private final char[] alphabet;
|
||||
@@ -145,7 +151,13 @@ public class Base32Codec implements Encoder<byte[], String>, Decoder<CharSequenc
|
||||
public static class Base32Decoder implements Decoder<CharSequence, byte[]> {
|
||||
private static final char BASE_CHAR = '0';
|
||||
|
||||
/**
|
||||
* 解码器
|
||||
*/
|
||||
public static final Base32Decoder DECODER = new Base32Decoder(Base32Encoder.DEFAULT_ALPHABET);
|
||||
/**
|
||||
* 16进制解码器
|
||||
*/
|
||||
public static final Base32Decoder HEX_DECODER = new Base32Decoder(Base32Encoder.HEX_ALPHABET);
|
||||
|
||||
private final byte[] lookupTable;
|
||||
@@ -166,7 +178,7 @@ public class Base32Codec implements Encoder<byte[], String>, Decoder<CharSequenc
|
||||
c = alphabet.charAt(i);
|
||||
lookupTable[c - BASE_CHAR] = (byte) i;
|
||||
// 支持小写字母解码
|
||||
if(c >= 'A' && c <= 'Z'){
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
lookupTable[Character.toLowerCase(c) - BASE_CHAR] = (byte) i;
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,9 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class Base58Codec implements Encoder<byte[], String>, Decoder<CharSequence, byte[]> {
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static Base58Codec INSTANCE = new Base58Codec();
|
||||
|
||||
/**
|
||||
@@ -48,6 +51,9 @@ public class Base58Codec implements Encoder<byte[], String>, Decoder<CharSequenc
|
||||
public static class Base58Encoder implements Encoder<byte[], String> {
|
||||
private static final String DEFAULT_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
/**
|
||||
* 编码器
|
||||
*/
|
||||
public static final Base58Encoder ENCODER = new Base58Encoder(DEFAULT_ALPHABET.toCharArray());
|
||||
|
||||
private final char[] alphabet;
|
||||
@@ -105,6 +111,9 @@ public class Base58Codec implements Encoder<byte[], String>, Decoder<CharSequenc
|
||||
*/
|
||||
public static class Base58Decoder implements Decoder<CharSequence, byte[]> {
|
||||
|
||||
/**
|
||||
* 解码器
|
||||
*/
|
||||
public static Base58Decoder DECODER = new Base58Decoder(Base58Encoder.DEFAULT_ALPHABET);
|
||||
|
||||
private final byte[] lookupTable;
|
||||
|
@@ -20,6 +20,9 @@ public class Base62Codec implements Encoder<byte[], byte[]>, Decoder<byte[], byt
|
||||
private static final int STANDARD_BASE = 256;
|
||||
private static final int TARGET_BASE = 62;
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static Base62Codec INSTANCE = new Base62Codec();
|
||||
|
||||
/**
|
||||
@@ -102,7 +105,13 @@ public class Base62Codec implements Encoder<byte[], byte[]>, Decoder<byte[], byt
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z' //
|
||||
};
|
||||
|
||||
/**
|
||||
* GMP风格编码器
|
||||
*/
|
||||
public static Base62Encoder GMP_ENCODER = new Base62Encoder(GMP);
|
||||
/**
|
||||
* 反转风格,即将GMP风格中的大小写做转换编码器
|
||||
*/
|
||||
public static Base62Encoder INVERTED_ENCODER = new Base62Encoder(INVERTED);
|
||||
|
||||
private final byte[] alphabet;
|
||||
@@ -130,7 +139,13 @@ public class Base62Codec implements Encoder<byte[], byte[]>, Decoder<byte[], byt
|
||||
*/
|
||||
public static class Base62Decoder implements Decoder<byte[], byte[]> {
|
||||
|
||||
/**
|
||||
* GMP风格解码器
|
||||
*/
|
||||
public static Base62Decoder GMP_DECODER = new Base62Decoder(Base62Encoder.GMP);
|
||||
/**
|
||||
* 反转风格,即将GMP风格中的大小写做转换解码器
|
||||
*/
|
||||
public static Base62Decoder INVERTED_DECODER = new Base62Decoder(Base62Encoder.INVERTED);
|
||||
|
||||
private final byte[] lookupTable;
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package cn.hutool.core.codec.hash;
|
||||
|
||||
import cn.hutool.core.codec.Number128;
|
||||
import cn.hutool.core.codec.hash.metro.MetroHash128;
|
||||
import cn.hutool.core.codec.hash.metro.MetroHash64;
|
||||
|
||||
/**
|
||||
* Hash算法大全<br>
|
||||
@@ -554,17 +556,7 @@ public class HashUtil {
|
||||
* @return hash值
|
||||
*/
|
||||
public static long metroHash64(final byte[] data, final long seed) {
|
||||
return MetroHash.INSTANCE.hash64(data, seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* MetroHash 算法64-bit实现
|
||||
*
|
||||
* @param data 数据
|
||||
* @return hash值
|
||||
*/
|
||||
public static long metroHash64(final byte[] data) {
|
||||
return MetroHash.INSTANCE.hash64(data);
|
||||
return MetroHash64.of(seed).hash64(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -575,17 +567,7 @@ public class HashUtil {
|
||||
* @return hash值,long[0]:低位,long[1]:高位
|
||||
*/
|
||||
public static long[] metroHash128(final byte[] data, final long seed) {
|
||||
return MetroHash.INSTANCE.hash128(data, seed).getLongArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* MetroHash 算法128-bit实现
|
||||
*
|
||||
* @param data 数据
|
||||
* @return hash值,long[0]:低位,long[1]:高位
|
||||
*/
|
||||
public static long[] metroHash128(final byte[] data) {
|
||||
return MetroHash.INSTANCE.hash128(data).getLongArray();
|
||||
return MetroHash128.of(seed).hash128(data).getLongArray();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,237 +0,0 @@
|
||||
package cn.hutool.core.codec.hash;
|
||||
|
||||
import cn.hutool.core.codec.Number128;
|
||||
import cn.hutool.core.util.ByteUtil;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Apache 发布的MetroHash算法,是一组用于非加密用例的最先进的哈希函数。
|
||||
* 除了卓越的性能外,他们还以算法生成而著称。
|
||||
*
|
||||
* <p>
|
||||
* 官方实现:https://github.com/jandrewrogers/MetroHash
|
||||
* 官方文档:http://www.jandrewrogers.com/2015/05/27/metrohash/
|
||||
* Go语言实现:https://github.com/linvon/cuckoo-filter/blob/main/vendor/github.com/dgryski/go-metro/
|
||||
*
|
||||
* @author li
|
||||
*/
|
||||
public class MetroHash implements Hash64<byte[]>, Hash128<byte[]> {
|
||||
public static MetroHash INSTANCE = new MetroHash();
|
||||
|
||||
@Override
|
||||
public Number encode(final byte[] bytes) {
|
||||
return hash64(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long hash64(final byte[] data) {
|
||||
return hash64(data, 1337);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算64位Hash值
|
||||
*
|
||||
* @param data 数据
|
||||
* @param seed 种子
|
||||
* @return hash64
|
||||
*/
|
||||
public long hash64(final byte[] data, final long seed) {
|
||||
final long k0_64 = 0xD6D018F5;
|
||||
final long k1_64 = 0xA2AA033B;
|
||||
final long k2_64 = 0x62992FC1;
|
||||
final long k3_64 = 0x30BC5B29;
|
||||
|
||||
byte[] buffer = data;
|
||||
long hash = (seed + k2_64) * k0_64;
|
||||
|
||||
long v0, v1, v2, v3;
|
||||
v0 = hash;
|
||||
v1 = hash;
|
||||
v2 = hash;
|
||||
v3 = hash;
|
||||
|
||||
if (buffer.length >= 32) {
|
||||
|
||||
while (buffer.length >= 32) {
|
||||
v0 += littleEndian64(buffer, 0) * k0_64;
|
||||
v0 = rotateLeft64(v0, -29) + v2;
|
||||
v1 += littleEndian64(buffer, 8) * k1_64;
|
||||
v1 = rotateLeft64(v1, -29) + v3;
|
||||
v2 += littleEndian64(buffer, 24) * k2_64;
|
||||
v2 = rotateLeft64(v2, -29) + v0;
|
||||
v3 += littleEndian64(buffer, 32) * k3_64;
|
||||
v3 = rotateLeft64(v3, -29) + v1;
|
||||
buffer = Arrays.copyOfRange(buffer, 32, buffer.length);
|
||||
}
|
||||
|
||||
v2 ^= rotateLeft64(((v0 + v3) * k0_64) + v1, -37) * k1_64;
|
||||
v3 ^= rotateLeft64(((v1 + v2) * k1_64) + v0, -37) * k0_64;
|
||||
v0 ^= rotateLeft64(((v0 + v2) * k0_64) + v3, -37) * k1_64;
|
||||
v1 ^= rotateLeft64(((v1 + v3) * k1_64) + v2, -37) * k0_64;
|
||||
hash += v0 ^ v1;
|
||||
}
|
||||
|
||||
if (buffer.length >= 16) {
|
||||
v0 = hash + littleEndian64(buffer, 0) * k2_64;
|
||||
v0 = rotateLeft64(v0, -29) * k3_64;
|
||||
v1 = hash + littleEndian64(buffer, 8) * k2_64;
|
||||
v1 = rotateLeft64(v1, -29) * k3_64;
|
||||
v0 ^= rotateLeft64(v0 * k0_64, -21) + v1;
|
||||
v1 ^= rotateLeft64(v1 * k3_64, -21) + v0;
|
||||
hash += v1;
|
||||
buffer = Arrays.copyOfRange(buffer, 16, buffer.length);
|
||||
}
|
||||
|
||||
if (buffer.length >= 8) {
|
||||
hash += littleEndian64(buffer, 0) * k3_64;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
hash ^= rotateLeft64(hash, -55) * k1_64;
|
||||
}
|
||||
|
||||
if (buffer.length >= 4) {
|
||||
hash += (long) littleEndian32(Arrays.copyOfRange(buffer, 0, 4)) * k3_64;
|
||||
hash ^= rotateLeft64(hash, -26) * k1_64;
|
||||
buffer = Arrays.copyOfRange(buffer, 4, buffer.length);
|
||||
}
|
||||
|
||||
if (buffer.length >= 2) {
|
||||
hash += (long) littleEndian16(Arrays.copyOfRange(buffer, 0, 2)) * k3_64;
|
||||
buffer = Arrays.copyOfRange(buffer, 2, buffer.length);
|
||||
hash ^= rotateLeft64(hash, -48) * k1_64;
|
||||
}
|
||||
|
||||
if (buffer.length >= 1) {
|
||||
hash += (long) buffer[0] * k3_64;
|
||||
hash ^= rotateLeft64(hash, -38) * k1_64;
|
||||
}
|
||||
|
||||
hash ^= rotateLeft64(hash, -28);
|
||||
hash *= k0_64;
|
||||
hash ^= rotateLeft64(hash, -29);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number128 hash128(final byte[] data) {
|
||||
return hash128(data, 1337);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算128位hash值
|
||||
*
|
||||
* @param data 数据
|
||||
* @param seed 种子
|
||||
* @return hash128
|
||||
*/
|
||||
public Number128 hash128(final byte[] data, final long seed) {
|
||||
final long k0_128 = 0xC83A91E1;
|
||||
final long k1_128 = 0x8648DBDB;
|
||||
final long k2_128 = 0x7BDEC03B;
|
||||
final long k3_128 = 0x2F5870A5;
|
||||
|
||||
byte[] buffer = data;
|
||||
|
||||
long v0, v1, v2, v3;
|
||||
|
||||
v0 = (seed - k0_128) * k3_128;
|
||||
v1 = (seed + k1_128) * k2_128;
|
||||
|
||||
if (buffer.length >= 32) {
|
||||
v2 = (seed + k0_128) * k2_128;
|
||||
v3 = (seed - k1_128) * k3_128;
|
||||
|
||||
while (buffer.length >= 32) {
|
||||
v0 += littleEndian64(buffer, 0) * k0_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
v0 = rotateRight(v0, 29) + v2;
|
||||
v1 += littleEndian64(buffer, 0) * k1_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
v1 = rotateRight(v1, 29) + v3;
|
||||
v2 += littleEndian64(buffer, 0) * k2_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
v2 = rotateRight(v2, 29) + v0;
|
||||
v3 = littleEndian64(buffer, 0) * k3_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
v3 = rotateRight(v3, 29) + v1;
|
||||
}
|
||||
|
||||
v2 ^= rotateRight(((v0 + v3) * k0_128) + v1, 21) * k1_128;
|
||||
v3 ^= rotateRight(((v1 + v2) * k1_128) + v0, 21) * k0_128;
|
||||
v0 ^= rotateRight(((v0 + v2) * k0_128) + v3, 21) * k1_128;
|
||||
v1 ^= rotateRight(((v1 + v3) * k1_128) + v2, 21) * k0_128;
|
||||
}
|
||||
|
||||
if (buffer.length >= 16) {
|
||||
v0 += littleEndian64(buffer, 0) * k2_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
v0 = rotateRight(v0, 33) * k3_128;
|
||||
v1 += littleEndian64(buffer, 0) * k2_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
v1 = rotateRight(v1, 33) * k3_128;
|
||||
v0 ^= rotateRight((v0 * k2_128) + v1, 45) + k1_128;
|
||||
v1 ^= rotateRight((v1 * k3_128) + v0, 45) + k0_128;
|
||||
}
|
||||
|
||||
if (buffer.length >= 8) {
|
||||
v0 += littleEndian64(buffer, 0) * k2_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 8, buffer.length);
|
||||
v0 = rotateRight(v0, 33) * k3_128;
|
||||
v0 ^= rotateRight((v0 * k2_128) + v1, 27) * k1_128;
|
||||
}
|
||||
|
||||
if (buffer.length >= 4) {
|
||||
v1 += (long) littleEndian32(buffer) * k2_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 4, buffer.length);
|
||||
v1 = rotateRight(v1, 33) * k3_128;
|
||||
v1 ^= rotateRight((v1 * k3_128) + v0, 46) * k0_128;
|
||||
}
|
||||
|
||||
if (buffer.length >= 2) {
|
||||
v0 += (long) littleEndian16(buffer) * k2_128;
|
||||
buffer = Arrays.copyOfRange(buffer, 2, buffer.length);
|
||||
v0 = rotateRight(v0, 33) * k3_128;
|
||||
v0 ^= rotateRight((v0 * k2_128) * v1, 22) * k1_128;
|
||||
}
|
||||
|
||||
if (buffer.length >= 1) {
|
||||
v1 += (long) buffer[0] * k2_128;
|
||||
v1 = rotateRight(v1, 33) * k3_128;
|
||||
v1 ^= rotateRight((v1 * k3_128) + v0, 58) * k0_128;
|
||||
}
|
||||
|
||||
v0 += rotateRight((v0 * k0_128) + v1, 13);
|
||||
v1 += rotateRight((v1 * k1_128) + v0, 37);
|
||||
v0 += rotateRight((v0 * k2_128) + v1, 13);
|
||||
v1 += rotateRight((v1 * k3_128) + v0, 37);
|
||||
|
||||
return new Number128(v0, v1);
|
||||
}
|
||||
|
||||
|
||||
// region =========== Private methods
|
||||
private static long littleEndian64(final byte[] b, final int start) {
|
||||
return ByteUtil.bytesToLong(b, start, ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
private static int littleEndian32(final byte[] b) {
|
||||
return (int) b[0] | (int) b[1] << 8 | (int) b[2] << 16 | (int) b[3] << 24;
|
||||
}
|
||||
|
||||
private static int littleEndian16(final byte[] b) {
|
||||
return ByteUtil.bytesToShort(b, ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
private static long rotateLeft64(final long x, final int k) {
|
||||
final int n = 64;
|
||||
final int s = k & (n - 1);
|
||||
return x << s | x >> (n - s);
|
||||
}
|
||||
|
||||
private static long rotateRight(final long val, final int shift) {
|
||||
return (val >> shift) | (val << (64 - shift));
|
||||
}
|
||||
// endregion =========== Private methods
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Apache 发布的MetroHash算法抽象实现,是一组用于非加密用例的最先进的哈希函数。
|
||||
* 除了卓越的性能外,他们还以算法生成而著称。
|
||||
*
|
||||
* <p>
|
||||
* 官方实现:https://github.com/jandrewrogers/MetroHash
|
||||
* 官方文档:http://www.jandrewrogers.com/2015/05/27/metrohash/
|
||||
* 来自:https://github.com/postamar/java-metrohash/
|
||||
*
|
||||
* @author Marius Posta
|
||||
* @param <R> 返回值类型,为this类型
|
||||
*/
|
||||
public abstract class AbstractMetroHash<R extends AbstractMetroHash<R>> implements MetroHash<R> {
|
||||
|
||||
final long seed;
|
||||
long v0, v1, v2, v3;
|
||||
long nChunks;
|
||||
|
||||
/**
|
||||
* 使用指定种子构造
|
||||
*
|
||||
* @param seed 种子
|
||||
*/
|
||||
public AbstractMetroHash(final long seed) {
|
||||
this.seed = seed;
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the instance's Metro hash function to the bytes in the given buffer.
|
||||
* This updates this instance's hashing state.
|
||||
*
|
||||
* @param input 内容
|
||||
* @return this
|
||||
*/
|
||||
public R apply(final ByteBuffer input) {
|
||||
reset();
|
||||
while (input.remaining() >= 32) {
|
||||
partialApply32ByteChunk(input);
|
||||
}
|
||||
return partialApplyRemaining(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes a 32-byte chunk from the byte buffer and updates the hashing state.
|
||||
*
|
||||
* @param partialInput byte buffer with at least 32 bytes remaining.
|
||||
* @return this
|
||||
*/
|
||||
abstract R partialApply32ByteChunk(ByteBuffer partialInput);
|
||||
|
||||
/**
|
||||
* Consumes the remaining bytes from the byte buffer and updates the hashing state.
|
||||
*
|
||||
* @param partialInput byte buffer with less than 32 bytes remaining.
|
||||
* @return this
|
||||
*/
|
||||
abstract R partialApplyRemaining(ByteBuffer partialInput);
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Apache 发布的MetroHash算法接口,是一组用于非加密用例的最先进的哈希函数。
|
||||
* 除了卓越的性能外,他们还以算法生成而著称。
|
||||
*
|
||||
* <p>
|
||||
* 官方实现:https://github.com/jandrewrogers/MetroHash
|
||||
* 官方文档:http://www.jandrewrogers.com/2015/05/27/metrohash/
|
||||
* 来自:https://github.com/postamar/java-metrohash/
|
||||
*
|
||||
* @param <R> 返回值类型,为this类型
|
||||
* @author Marius Posta
|
||||
*/
|
||||
public interface MetroHash<R extends MetroHash<R>> {
|
||||
|
||||
/**
|
||||
* 创建 {@code MetroHash}对象
|
||||
*
|
||||
* @param seed 种子
|
||||
* @param is128 是否128位
|
||||
* @return {@code MetroHash}对象
|
||||
*/
|
||||
static MetroHash<?> of(final long seed, final boolean is128) {
|
||||
return is128 ? new MetroHash128(seed) : new MetroHash64(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the instance's Metro hash function to the bytes in the given buffer.
|
||||
* This updates this instance's hashing state.
|
||||
*
|
||||
* @param input 内容
|
||||
* @return this
|
||||
*/
|
||||
R apply(final ByteBuffer input);
|
||||
|
||||
/**
|
||||
* Writes the current hash to the given byte buffer in big-endian order.
|
||||
* 将结果hash值写出到{@link ByteBuffer}中
|
||||
*
|
||||
* @param output 输出
|
||||
* @param byteOrder 端序
|
||||
* @return this
|
||||
*/
|
||||
R write(ByteBuffer output, final ByteOrder byteOrder);
|
||||
|
||||
/**
|
||||
* 重置,重置后可复用对象开启新的计算
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
R reset();
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
import cn.hutool.core.codec.Number128;
|
||||
import cn.hutool.core.codec.hash.Hash128;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Apache 发布的MetroHash算法的128位实现,是一组用于非加密用例的最先进的哈希函数。
|
||||
* 除了卓越的性能外,他们还以算法生成而著称。
|
||||
*
|
||||
* <p>
|
||||
* 官方实现:https://github.com/jandrewrogers/MetroHash
|
||||
* 官方文档:http://www.jandrewrogers.com/2015/05/27/metrohash/
|
||||
* 来自:https://github.com/postamar/java-metrohash/
|
||||
* @author Marius Posta
|
||||
*/
|
||||
public class MetroHash128 extends AbstractMetroHash<MetroHash128> implements Hash128<byte[]> {
|
||||
|
||||
/**
|
||||
* 创建 {@code MetroHash128}对象
|
||||
*
|
||||
* @param seed 种子
|
||||
* @return {@code MetroHash128}对象
|
||||
*/
|
||||
public static MetroHash128 of(final long seed) {
|
||||
return new MetroHash128(seed);
|
||||
}
|
||||
|
||||
private static final long K0 = 0xC83A91E1L;
|
||||
private static final long K1 = 0x8648DBDBL;
|
||||
private static final long K2 = 0x7BDEC03BL;
|
||||
private static final long K3 = 0x2F5870A5L;
|
||||
|
||||
/**
|
||||
* 使用指定种子构造
|
||||
*
|
||||
* @param seed 种子
|
||||
*/
|
||||
public MetroHash128(final long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetroHash128 reset() {
|
||||
v0 = (seed - K0) * K3;
|
||||
v1 = (seed + K1) * K2;
|
||||
v2 = (seed + K0) * K2;
|
||||
v3 = (seed - K1) * K3;
|
||||
nChunks = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取高64位结果hash值
|
||||
*
|
||||
* @return hash值
|
||||
*/
|
||||
public long getHigh() {
|
||||
return v0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取低64位结果hash值
|
||||
*
|
||||
* @return hash值
|
||||
*/
|
||||
public long getLow() {
|
||||
return v1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取结果hash值
|
||||
*
|
||||
* @return hash值
|
||||
*/
|
||||
public Number128 get() {
|
||||
return new Number128(v1, v0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number128 hash128(final byte[] bytes) {
|
||||
return apply(ByteBuffer.wrap(bytes)).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetroHash128 write(final ByteBuffer output, final ByteOrder byteOrder) {
|
||||
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||
MetroHashInternalUtil.writeLittleEndian(v0, output);
|
||||
MetroHashInternalUtil.writeLittleEndian(v1, output);
|
||||
} else {
|
||||
output.asLongBuffer().put(v1).put(v0);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
MetroHash128 partialApply32ByteChunk(final ByteBuffer partialInput) {
|
||||
assert partialInput.remaining() >= 32;
|
||||
v0 += MetroHashInternalUtil.grab8(partialInput) * K0;
|
||||
v0 = MetroHashInternalUtil.rotateRight64(v0, 29) + v2;
|
||||
v1 += MetroHashInternalUtil.grab8(partialInput) * K1;
|
||||
v1 = MetroHashInternalUtil.rotateRight64(v1, 29) + v3;
|
||||
v2 += MetroHashInternalUtil.grab8(partialInput) * K2;
|
||||
v2 = MetroHashInternalUtil.rotateRight64(v2, 29) + v0;
|
||||
v3 += MetroHashInternalUtil.grab8(partialInput) * K3;
|
||||
v3 = MetroHashInternalUtil.rotateRight64(v3, 29) + v1;
|
||||
++nChunks;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
MetroHash128 partialApplyRemaining(final ByteBuffer partialInput) {
|
||||
assert partialInput.remaining() < 32;
|
||||
if (nChunks > 0) {
|
||||
metroHash128_32();
|
||||
}
|
||||
if (partialInput.remaining() >= 16) {
|
||||
metroHash128_16(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 8) {
|
||||
metroHash128_8(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 4) {
|
||||
metroHash128_4(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 2) {
|
||||
metroHash128_2(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 1) {
|
||||
metroHash128_1(partialInput);
|
||||
}
|
||||
v0 += MetroHashInternalUtil.rotateRight64(v0 * K0 + v1, 13);
|
||||
v1 += MetroHashInternalUtil.rotateRight64(v1 * K1 + v0, 37);
|
||||
v0 += MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 13);
|
||||
v1 += MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 37);
|
||||
return this;
|
||||
}
|
||||
|
||||
// region ----- private methods
|
||||
private void metroHash128_32() {
|
||||
v2 ^= MetroHashInternalUtil.rotateRight64((v0 + v3) * K0 + v1, 21) * K1;
|
||||
v3 ^= MetroHashInternalUtil.rotateRight64((v1 + v2) * K1 + v0, 21) * K0;
|
||||
v0 ^= MetroHashInternalUtil.rotateRight64((v0 + v2) * K0 + v3, 21) * K1;
|
||||
v1 ^= MetroHashInternalUtil.rotateRight64((v1 + v3) * K1 + v2, 21) * K0;
|
||||
}
|
||||
|
||||
private void metroHash128_16(final ByteBuffer bb) {
|
||||
v0 += MetroHashInternalUtil.grab8(bb) * K2;
|
||||
v0 = MetroHashInternalUtil.rotateRight64(v0, 33) * K3;
|
||||
v1 += MetroHashInternalUtil.grab8(bb) * K2;
|
||||
v1 = MetroHashInternalUtil.rotateRight64(v1, 33) * K3;
|
||||
v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 45) * K1;
|
||||
v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 45) * K0;
|
||||
}
|
||||
|
||||
private void metroHash128_8(final ByteBuffer bb) {
|
||||
v0 += MetroHashInternalUtil.grab8(bb) * K2;
|
||||
v0 = MetroHashInternalUtil.rotateRight64(v0, 33) * K3;
|
||||
v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 27) * K1;
|
||||
}
|
||||
|
||||
private void metroHash128_4(final ByteBuffer bb) {
|
||||
v1 += MetroHashInternalUtil.grab4(bb) * K2;
|
||||
v1 = MetroHashInternalUtil.rotateRight64(v1, 33) * K3;
|
||||
v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 46) * K0;
|
||||
}
|
||||
|
||||
private void metroHash128_2(final ByteBuffer bb) {
|
||||
v0 += MetroHashInternalUtil.grab2(bb) * K2;
|
||||
v0 = MetroHashInternalUtil.rotateRight64(v0, 33) * K3;
|
||||
v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K2 + v1, 22) * K1;
|
||||
}
|
||||
|
||||
private void metroHash128_1(final ByteBuffer bb) {
|
||||
v1 += MetroHashInternalUtil.grab1(bb) * K2;
|
||||
v1 = MetroHashInternalUtil.rotateRight64(v1, 33) * K3;
|
||||
v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3 + v0, 58) * K0;
|
||||
}
|
||||
// endregion
|
||||
}
|
@@ -0,0 +1,158 @@
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
import cn.hutool.core.codec.hash.Hash64;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Apache 发布的MetroHash算法的64位实现,是一组用于非加密用例的最先进的哈希函数。
|
||||
* 除了卓越的性能外,他们还以算法生成而著称。
|
||||
*
|
||||
* <p>
|
||||
* 官方实现:https://github.com/jandrewrogers/MetroHash
|
||||
* 官方文档:http://www.jandrewrogers.com/2015/05/27/metrohash/
|
||||
* 来自:https://github.com/postamar/java-metrohash/
|
||||
* @author Marius Posta
|
||||
*/
|
||||
public class MetroHash64 extends AbstractMetroHash<MetroHash64> implements Hash64<byte[]> {
|
||||
|
||||
/**
|
||||
* 创建 {@code MetroHash64}对象
|
||||
*
|
||||
* @param seed 种子
|
||||
* @return {@code MetroHash64}对象
|
||||
*/
|
||||
public static MetroHash64 of(final long seed) {
|
||||
return new MetroHash64(seed);
|
||||
}
|
||||
|
||||
private static final long K0 = 0xD6D018F5L;
|
||||
private static final long K1 = 0xA2AA033BL;
|
||||
private static final long K2 = 0x62992FC1L;
|
||||
private static final long K3 = 0x30BC5B29L;
|
||||
|
||||
private long hash;
|
||||
|
||||
/**
|
||||
* 使用指定种子构造
|
||||
*
|
||||
* @param seed 种子
|
||||
*/
|
||||
public MetroHash64(final long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetroHash64 reset() {
|
||||
v0 = v1 = v2 = v3 = hash = (seed + K2) * K0;
|
||||
nChunks = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取计算结果hash值
|
||||
*
|
||||
* @return hash值
|
||||
*/
|
||||
public long get() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long hash64(final byte[] bytes) {
|
||||
return apply(ByteBuffer.wrap(bytes)).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetroHash64 write(final ByteBuffer output, final ByteOrder byteOrder) {
|
||||
if(ByteOrder.LITTLE_ENDIAN == byteOrder){
|
||||
MetroHashInternalUtil.writeLittleEndian(hash, output);
|
||||
} else{
|
||||
output.asLongBuffer().put(hash);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
MetroHash64 partialApply32ByteChunk(final ByteBuffer partialInput) {
|
||||
assert partialInput.remaining() >= 32;
|
||||
v0 += MetroHashInternalUtil.grab8(partialInput) * K0;
|
||||
v0 = MetroHashInternalUtil.rotateRight64(v0, 29) + v2;
|
||||
v1 += MetroHashInternalUtil.grab8(partialInput) * K1;
|
||||
v1 = MetroHashInternalUtil.rotateRight64(v1, 29) + v3;
|
||||
v2 += MetroHashInternalUtil.grab8(partialInput) * K2;
|
||||
v2 = MetroHashInternalUtil.rotateRight64(v2, 29) + v0;
|
||||
v3 += MetroHashInternalUtil.grab8(partialInput) * K3;
|
||||
v3 = MetroHashInternalUtil.rotateRight64(v3, 29) + v1;
|
||||
++nChunks;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
MetroHash64 partialApplyRemaining(final ByteBuffer partialInput) {
|
||||
assert partialInput.remaining() < 32;
|
||||
if (nChunks > 0) {
|
||||
metroHash64_32();
|
||||
}
|
||||
if (partialInput.remaining() >= 16) {
|
||||
metroHash64_16(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 8) {
|
||||
metroHash64_8(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 4) {
|
||||
metroHash64_4(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 2) {
|
||||
metroHash64_2(partialInput);
|
||||
}
|
||||
if (partialInput.remaining() >= 1) {
|
||||
metroHash64_1(partialInput);
|
||||
}
|
||||
hash ^= MetroHashInternalUtil.rotateRight64(hash, 28);
|
||||
hash *= K0;
|
||||
hash ^= MetroHashInternalUtil.rotateRight64(hash, 29);
|
||||
return this;
|
||||
}
|
||||
|
||||
// region ----- private methods
|
||||
private void metroHash64_32() {
|
||||
v2 ^= MetroHashInternalUtil.rotateRight64(((v0 + v3) * K0) + v1, 37) * K1;
|
||||
v3 ^= MetroHashInternalUtil.rotateRight64(((v1 + v2) * K1) + v0, 37) * K0;
|
||||
v0 ^= MetroHashInternalUtil.rotateRight64(((v0 + v2) * K0) + v3, 37) * K1;
|
||||
v1 ^= MetroHashInternalUtil.rotateRight64(((v1 + v3) * K1) + v2, 37) * K0;
|
||||
hash += v0 ^ v1;
|
||||
}
|
||||
|
||||
private void metroHash64_16(final ByteBuffer bb) {
|
||||
v0 = hash + MetroHashInternalUtil.grab8(bb) * K2;
|
||||
v0 = MetroHashInternalUtil.rotateRight64(v0, 29) * K3;
|
||||
v1 = hash + MetroHashInternalUtil.grab8(bb) * K2;
|
||||
v1 = MetroHashInternalUtil.rotateRight64(v1, 29) * K3;
|
||||
v0 ^= MetroHashInternalUtil.rotateRight64(v0 * K0, 21) + v1;
|
||||
v1 ^= MetroHashInternalUtil.rotateRight64(v1 * K3, 21) + v0;
|
||||
hash += v1;
|
||||
}
|
||||
|
||||
private void metroHash64_8(final ByteBuffer bb) {
|
||||
hash += MetroHashInternalUtil.grab8(bb) * K3;
|
||||
hash ^= MetroHashInternalUtil.rotateRight64(hash, 55) * K1;
|
||||
}
|
||||
|
||||
private void metroHash64_4(final ByteBuffer bb) {
|
||||
hash += MetroHashInternalUtil.grab4(bb) * K3;
|
||||
hash ^= MetroHashInternalUtil.rotateRight64(hash, 26) * K1;
|
||||
}
|
||||
|
||||
private void metroHash64_2(final ByteBuffer bb) {
|
||||
hash += MetroHashInternalUtil.grab2(bb) * K3;
|
||||
hash ^= MetroHashInternalUtil.rotateRight64(hash, 48) * K1;
|
||||
}
|
||||
|
||||
private void metroHash64_1(final ByteBuffer bb) {
|
||||
hash += MetroHashInternalUtil.grab1(bb) * K3;
|
||||
hash ^= MetroHashInternalUtil.rotateRight64(hash, 37) * K1;
|
||||
}
|
||||
// endregion
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
class MetroHashInternalUtil {
|
||||
|
||||
static void writeLittleEndian(final long hash, final ByteBuffer output) {
|
||||
output.put((byte) hash);
|
||||
output.put((byte) (hash >>> 8));
|
||||
output.put((byte) (hash >>> 16));
|
||||
output.put((byte) (hash >>> 24));
|
||||
output.put((byte) (hash >>> 32));
|
||||
output.put((byte) (hash >>> 40));
|
||||
output.put((byte) (hash >>> 48));
|
||||
output.put((byte) (hash >>> 56));
|
||||
}
|
||||
|
||||
static long rotateRight64(final long x, final int r) {
|
||||
return (x >>> r) | (x << (64 - r));
|
||||
}
|
||||
|
||||
static long grab1(final ByteBuffer bb) {
|
||||
return ((long) bb.get() & 0xFFL);
|
||||
}
|
||||
|
||||
static long grab2(final ByteBuffer bb) {
|
||||
final long v0 = bb.get();
|
||||
final long v1 = bb.get();
|
||||
return (v0 & 0xFFL) | (v1 & 0xFFL) << 8;
|
||||
}
|
||||
|
||||
static long grab4(final ByteBuffer bb) {
|
||||
final long v0 = bb.get();
|
||||
final long v1 = bb.get();
|
||||
final long v2 = bb.get();
|
||||
final long v3 = bb.get();
|
||||
return (v0 & 0xFFL) | (v1 & 0xFFL) << 8 | (v2 & 0xFFL) << 16 | (v3 & 0xFFL) << 24;
|
||||
}
|
||||
|
||||
static long grab8(final ByteBuffer bb) {
|
||||
final long v0 = bb.get();
|
||||
final long v1 = bb.get();
|
||||
final long v2 = bb.get();
|
||||
final long v3 = bb.get();
|
||||
final long v4 = bb.get();
|
||||
final long v5 = bb.get();
|
||||
final long v6 = bb.get();
|
||||
final long v7 = bb.get();
|
||||
return (v0 & 0xFFL) | (v1 & 0xFFL) << 8 | (v2 & 0xFFL) << 16 | (v3 & 0xFFL) << 24 | (v4 & 0xFFL) << 32 | (v5 & 0xFFL) << 40 | (v6 & 0xFFL) << 48 | (v7 & 0xFFL) << 56;
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* MetroHash算法实现<br>
|
||||
* <p>
|
||||
* 参考:https://github.com/postamar/java-metrohash
|
||||
*
|
||||
* @author postamar, looly
|
||||
*/
|
||||
package cn.hutool.core.codec.hash.metro;
|
@@ -95,6 +95,7 @@ public class LineIter extends ComputeIter<String> implements IterableIter<String
|
||||
* @param line 需要验证的行
|
||||
* @return 是否通过验证
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected boolean isValidLine(final String line) {
|
||||
return true;
|
||||
}
|
||||
|
@@ -3,13 +3,7 @@ package cn.hutool.core.comparator;
|
||||
import cn.hutool.core.lang.Chain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 比较器链。此链包装了多个比较器,最终比较结果按照比较器顺序综合多个比较器结果。<br>
|
||||
@@ -18,6 +12,7 @@ import java.util.Objects;
|
||||
*
|
||||
* @author looly
|
||||
* @since 3.0.7
|
||||
* @param <E> 被比较的对象
|
||||
*/
|
||||
public class ComparatorChain<E> implements Chain<Comparator<E>, ComparatorChain<E>>, Comparator<E>, Serializable {
|
||||
private static final long serialVersionUID = -2426725788913962429L;
|
||||
@@ -38,11 +33,11 @@ public class ComparatorChain<E> implements Chain<Comparator<E>, ComparatorChain<
|
||||
//------------------------------------------------------------------------------------- Static method start
|
||||
|
||||
/**
|
||||
* 构建 {@link ComparatorChain}
|
||||
* 构建 {@code ComparatorChain}
|
||||
*
|
||||
* @param <E> 被比较对象类型
|
||||
* @param comparator 比较器
|
||||
* @return {@link ComparatorChain}
|
||||
* @return {@code ComparatorChain}
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public static <E> ComparatorChain<E> of(final Comparator<E> comparator) {
|
||||
@@ -50,12 +45,12 @@ public class ComparatorChain<E> implements Chain<Comparator<E>, ComparatorChain<
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 {@link ComparatorChain}
|
||||
* 构建 {@code ComparatorChain}
|
||||
*
|
||||
* @param <E> 被比较对象类型
|
||||
* @param comparator 比较器
|
||||
* @param reverse 是否反向
|
||||
* @return {@link ComparatorChain}
|
||||
* @return {@code ComparatorChain}
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public static <E> ComparatorChain<E> of(final Comparator<E> comparator, final boolean reverse) {
|
||||
@@ -63,11 +58,11 @@ public class ComparatorChain<E> implements Chain<Comparator<E>, ComparatorChain<
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 {@link ComparatorChain}
|
||||
* 构建 {@code ComparatorChain}
|
||||
*
|
||||
* @param <E> 被比较对象类型
|
||||
* @param comparators 比较器数组
|
||||
* @return {@link ComparatorChain}
|
||||
* @return {@code ComparatorChain}
|
||||
* @since 5.4.3
|
||||
*/
|
||||
@SafeVarargs
|
||||
@@ -76,11 +71,11 @@ public class ComparatorChain<E> implements Chain<Comparator<E>, ComparatorChain<
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 {@link ComparatorChain}
|
||||
* 构建 {@code ComparatorChain}
|
||||
*
|
||||
* @param <E> 被比较对象类型
|
||||
* @param comparators 比较器列表
|
||||
* @return {@link ComparatorChain}
|
||||
* @return {@code ComparatorChain}
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public static <E> ComparatorChain<E> of(final List<Comparator<E>> comparators) {
|
||||
@@ -88,12 +83,12 @@ public class ComparatorChain<E> implements Chain<Comparator<E>, ComparatorChain<
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 {@link ComparatorChain}
|
||||
* 构建 {@code ComparatorChain}
|
||||
*
|
||||
* @param <E> 被比较对象类型
|
||||
* @param comparators 比较器列表
|
||||
* @param bits {@link Comparator} 列表对应的排序boolean值,true表示正序,false反序
|
||||
* @return {@link ComparatorChain}
|
||||
* @return {@code ComparatorChain}
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public static <E> ComparatorChain<E> of(final List<Comparator<E>> comparators, final BitSet bits) {
|
||||
|
@@ -830,6 +830,7 @@ public class Convert {
|
||||
* @param notConvertSet 不替换的字符集合
|
||||
* @return 替换后的字符
|
||||
*/
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
public static String toDBC(final String text, final Set<Character> notConvertSet) {
|
||||
if(StrUtil.isBlank(text)) {
|
||||
return text;
|
||||
|
@@ -24,6 +24,9 @@ import java.util.List;
|
||||
public class ArrayConverter extends AbstractConverter {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 单例
|
||||
*/
|
||||
public static final ArrayConverter INSTANCE = new ArrayConverter();
|
||||
|
||||
/**
|
||||
|
@@ -3,23 +3,29 @@ package cn.hutool.core.date;
|
||||
/**
|
||||
* 季度枚举
|
||||
*
|
||||
* @author zhfish(https : / / github.com / zhfish)
|
||||
* @see #Q1
|
||||
* @see #Q2
|
||||
* @see #Q3
|
||||
* @see #Q4
|
||||
*
|
||||
* @author zhfish(https://github.com/zhfish)
|
||||
*
|
||||
*/
|
||||
public enum Quarter {
|
||||
|
||||
/** 第一季度 */
|
||||
/**
|
||||
* 第一季度
|
||||
*/
|
||||
Q1(1),
|
||||
/** 第二季度 */
|
||||
/**
|
||||
* 第二季度
|
||||
*/
|
||||
Q2(2),
|
||||
/** 第三季度 */
|
||||
/**
|
||||
* 第三季度
|
||||
*/
|
||||
Q3(3),
|
||||
/** 第四季度 */
|
||||
/**
|
||||
* 第四季度
|
||||
*/
|
||||
Q4(4);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@@ -29,6 +35,11 @@ public enum Quarter {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取季度值
|
||||
*
|
||||
* @return 季度值
|
||||
*/
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
@@ -36,13 +47,12 @@ public enum Quarter {
|
||||
/**
|
||||
* 将 季度int转换为Season枚举对象<br>
|
||||
*
|
||||
* @param intValue 季度int表示
|
||||
* @return {@code Quarter}
|
||||
* @see #Q1
|
||||
* @see #Q2
|
||||
* @see #Q3
|
||||
* @see #Q4
|
||||
*
|
||||
* @param intValue 季度int表示
|
||||
* @return {@link Quarter}
|
||||
*/
|
||||
public static Quarter of(final int intValue) {
|
||||
switch (intValue) {
|
||||
|
@@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我还没测试过,有人说是100倍左右)
|
||||
* System.currentTimeMillis()之所以慢是因为去跟系统打了一次交道
|
||||
* 后台定时更新时钟,JVM退出时,线程自动回收
|
||||
*
|
||||
* <p>
|
||||
* see: <a href="http://git.oschina.net/yu120/sequence">http://git.oschina.net/yu120/sequence</a>
|
||||
* @author lry, looly
|
||||
*/
|
||||
|
@@ -573,17 +573,11 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return mValue.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
buffer.append(mValue);
|
||||
@@ -610,9 +604,6 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mValues = values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
int max = 0;
|
||||
@@ -625,9 +616,6 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
buffer.append(mValues[calendar.get(mField)]);
|
||||
@@ -651,25 +639,16 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mField = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
appendTo(buffer, calendar.get(mField));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
if (value < 10) {
|
||||
@@ -697,25 +676,16 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
UnpaddedMonthField() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
if (value < 10) {
|
||||
@@ -750,25 +720,16 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
appendTo(buffer, calendar.get(mField));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
appendFullDigits(buffer, value, mSize);
|
||||
@@ -792,25 +753,16 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mField = field;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
appendTo(buffer, calendar.get(mField));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
if (value < 100) {
|
||||
@@ -835,25 +787,16 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
TwoDigitYearField() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
appendTo(buffer, calendar.get(Calendar.YEAR) % 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
appendDigits(buffer, value);
|
||||
@@ -874,25 +817,16 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
TwoDigitMonthField() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
appendDigits(buffer, value);
|
||||
@@ -916,17 +850,11 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mRule = rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return mRule.estimateLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
int value = calendar.get(Calendar.HOUR);
|
||||
@@ -936,9 +864,6 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mRule.appendTo(buffer, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
mRule.appendTo(buffer, value);
|
||||
@@ -962,17 +887,11 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mRule = rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return mRule.estimateLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
int value = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
@@ -982,9 +901,6 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mRule.appendTo(buffer, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final int value) throws IOException {
|
||||
mRule.appendTo(buffer, value);
|
||||
@@ -1103,9 +1019,6 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
// We have no access to the Calendar object that will be passed to
|
||||
@@ -1114,9 +1027,6 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
return Math.max(mStandard.length(), mDaylight.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
final TimeZone zone = calendar.getTimeZone();
|
||||
@@ -1148,17 +1058,11 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mColon = colon;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
|
||||
@@ -1227,17 +1131,11 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int estimateLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
|
||||
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
|
||||
@@ -1298,17 +1196,11 @@ public class FastDatePrinter extends SimpleDateBasic implements DatePrinter {
|
||||
mLocale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (mStyle * 31 + mLocale.hashCode()) * 31 + mTimeZone.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
|
@@ -19,6 +19,11 @@ public class AppendableWriter extends Writer implements Appendable {
|
||||
private final boolean flushable;
|
||||
private boolean closed;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param appendable {@link Appendable}
|
||||
*/
|
||||
public AppendableWriter(final Appendable appendable) {
|
||||
this.appendable = appendable;
|
||||
this.flushable = appendable instanceof Flushable;
|
||||
|
@@ -1,7 +1,5 @@
|
||||
package cn.hutool.core.io.file.visitor;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
@@ -17,6 +15,9 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||
*/
|
||||
public class DelVisitor extends SimpleFileVisitor<Path> {
|
||||
|
||||
/**
|
||||
* 单例对象
|
||||
*/
|
||||
public static DelVisitor INSTANCE = new DelVisitor();
|
||||
|
||||
@Override
|
||||
|
@@ -33,7 +33,7 @@ public class DelayWatcher implements Watcher {
|
||||
//---------------------------------------------------------------------------------------------------------- Constructor start
|
||||
/**
|
||||
* 构造
|
||||
* @param watcher 实际处理触发事件的监视器{@link Watcher},不可以是{@link DelayWatcher}
|
||||
* @param watcher 实际处理触发事件的监视器{@link Watcher},不可以是{@code DelayWatcher}
|
||||
* @param delay 延迟时间,单位毫秒
|
||||
*/
|
||||
public DelayWatcher(final Watcher watcher, final long delay) {
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package cn.hutool.core.io.watch.watchers;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.io.watch.Watcher;
|
||||
import cn.hutool.core.lang.Chain;
|
||||
|
||||
@@ -23,9 +22,9 @@ public class WatcherChain implements Watcher, Chain<Watcher, WatcherChain>{
|
||||
final private List<Watcher> chain;
|
||||
|
||||
/**
|
||||
* 创建观察者链{@link WatcherChain}
|
||||
* 创建观察者链{@code WatcherChain}
|
||||
* @param watchers 观察者列表
|
||||
* @return {@link WatcherChain}
|
||||
* @return {@code WatcherChain}
|
||||
*/
|
||||
public static WatcherChain of(final Watcher... watchers) {
|
||||
return new WatcherChain(watchers);
|
||||
|
@@ -28,11 +28,10 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.func.SerSupplier;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Collection;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
@@ -39,7 +39,7 @@ public enum AnsiStyle implements AnsiElement {
|
||||
|
||||
private final int code;
|
||||
|
||||
AnsiStyle(int code) {
|
||||
AnsiStyle(final int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
@@ -41,12 +41,12 @@ public interface Bound<T extends Comparable<? super T>> extends Predicate<T>, Co
|
||||
/**
|
||||
* 无穷小的描述
|
||||
*/
|
||||
String INFINITE_MIN = "-\u221e";
|
||||
String INFINITE_MIN = "-∞";
|
||||
|
||||
/**
|
||||
* 无穷大的藐视
|
||||
*/
|
||||
String INFINITE_MAX = "+\u221e";
|
||||
String INFINITE_MAX = "+∞";
|
||||
|
||||
// region --------------- static methods
|
||||
/**
|
||||
|
@@ -54,12 +54,13 @@ class NoneLowerBound<T extends Comparable<? super T>> implements Bound<T> {
|
||||
* <ul>
|
||||
* <li>-1:<em>t1</em>在<em>t2</em>的左侧;</li>
|
||||
* <li>0:<em>t1</em>与<em>t2</em>的重合;</li>
|
||||
* <li>-1:<em>t1</em>在<em>t2</em>的右侧;</li>
|
||||
* <li>-1:<em>t1</em>在<em>t2</em>的右侧;(不存在)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param bound 边界
|
||||
* @return 位置
|
||||
*/
|
||||
@SuppressWarnings("ComparatorMethodParameterNotUsed")
|
||||
@Override
|
||||
public int compareTo(final Bound<T> bound) {
|
||||
return bound instanceof NoneLowerBound ? 0 : -1;
|
||||
@@ -102,7 +103,7 @@ class NoneLowerBound<T extends Comparable<? super T>> implements Bound<T> {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{x | x > -\u221e}";
|
||||
return "{x | x > -∞}";
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ class NoneUpperBound<T extends Comparable<? super T>> implements Bound<T> {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{x | x < +\u221e}";
|
||||
return "{x | x < +∞}";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -206,7 +206,7 @@ public class RowKeyTable<R, C, V> extends AbsTable<R, C, V> {
|
||||
final Collection<Map<C, V>> values = this.raw.values();
|
||||
final List<C> result = new ArrayList<>(values.size() * 16);
|
||||
for (final Map<C, V> map : values) {
|
||||
map.forEach((key, value)->{result.add(key);});
|
||||
map.forEach((key, value)-> result.add(key));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ package cn.hutool.core.math;
|
||||
/**
|
||||
* 通过位运算表示状态的工具类<br>
|
||||
* 参数必须是 `偶数` 且 `大于等于0`!
|
||||
*
|
||||
* <p>
|
||||
* 工具实现见博客:https://blog.starxg.com/2020/11/bit-status/
|
||||
*
|
||||
* @author huangxingguang,senssic
|
||||
|
@@ -121,7 +121,7 @@ public class MethodHandleUtil {
|
||||
* return "Quack";
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* <p>
|
||||
* Duck duck = (Duck) Proxy.newProxyInstance(
|
||||
* ClassLoaderUtil.getClassLoader(),
|
||||
* new Class[] { Duck.class },
|
||||
@@ -167,7 +167,7 @@ public class MethodHandleUtil {
|
||||
* return "Quack";
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* <p>
|
||||
* Duck duck = (Duck) Proxy.newProxyInstance(
|
||||
* ClassLoaderUtil.getClassLoader(),
|
||||
* new Class[] { Duck.class },
|
||||
@@ -193,7 +193,7 @@ public class MethodHandleUtil {
|
||||
* return "Quack";
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* <p>
|
||||
* Duck duck = (Duck) Proxy.newProxyInstance(
|
||||
* ClassLoaderUtil.getClassLoader(),
|
||||
* new Class[] { Duck.class },
|
||||
|
@@ -893,7 +893,7 @@ public class ReUtil {
|
||||
/**
|
||||
* 替换所有正则匹配的文本,并使用自定义函数决定如何替换<br>
|
||||
* replaceFun可以通过{@link Matcher}提取出匹配到的内容的不同部分,然后经过重新处理、组装变成新的内容放回原位。
|
||||
*
|
||||
* <p>
|
||||
* <pre class="code">
|
||||
* replaceAll(this.content, "(\\d+)", parameters -> "-" + parameters.group(1) + "-")
|
||||
* // 结果为:"ZZZaaabbbccc中文-1234-"
|
||||
@@ -912,7 +912,7 @@ public class ReUtil {
|
||||
/**
|
||||
* 替换所有正则匹配的文本,并使用自定义函数决定如何替换<br>
|
||||
* replaceFun可以通过{@link Matcher}提取出匹配到的内容的不同部分,然后经过重新处理、组装变成新的内容放回原位。
|
||||
*
|
||||
* <p>
|
||||
* <pre class="code">
|
||||
* replaceAll(this.content, "(\\d+)", parameters -> "-" + parameters.group(1) + "-")
|
||||
* // 结果为:"ZZZaaabbbccc中文-1234-"
|
||||
|
@@ -513,6 +513,13 @@ public class AntPathMatcher {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取参数
|
||||
*
|
||||
* @param pattern 模式
|
||||
* @param path 路径
|
||||
* @return 参数
|
||||
*/
|
||||
public Map<String, String> extractUriTemplateVariables(final String pattern, final String path) {
|
||||
final Map<String, String> variables = new LinkedHashMap<>();
|
||||
final boolean result = doMatch(pattern, path, true, variables);
|
||||
|
@@ -12,6 +12,7 @@ import cn.hutool.core.text.replacer.LookupReplacer;
|
||||
public class Html4Escape extends XmlEscape {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
protected static final String[][] ISO8859_1_ESCAPE = { //
|
||||
{ "\u00A0", " " }, // non-breaking space
|
||||
{ "\u00A1", "¡" }, // inverted exclamation mark
|
||||
@@ -111,6 +112,7 @@ public class Html4Escape extends XmlEscape {
|
||||
{ "\u00FF", "ÿ" }, // <20> - lowercase y, umlaut
|
||||
};
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
protected static final String[][] HTML40_EXTENDED_ESCAPE = {
|
||||
// <!-- Latin Extended-B -->
|
||||
{ "\u0192", "ƒ" }, // latin small f with hook = function= florin, U+0192 ISOtech -->
|
||||
@@ -308,6 +310,9 @@ public class Html4Escape extends XmlEscape {
|
||||
{ "\u20AC", "€" }, // -- euro sign, U+20AC NEW -->
|
||||
};
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public Html4Escape() {
|
||||
super();
|
||||
addChain(new LookupReplacer(ISO8859_1_ESCAPE));
|
||||
|
@@ -9,7 +9,7 @@ import java.util.function.Consumer;
|
||||
* 当任务队列过长时处于阻塞状态,直到添加到队列中
|
||||
* 如果阻塞过程中被中断,就会抛出{@link InterruptedException}异常<br>
|
||||
* 有时候在线程池内访问第三方接口,只希望固定并发数去访问,并且不希望丢弃任务时使用此策略,队列满的时候会处于阻塞状态(例如刷库的场景)
|
||||
*
|
||||
* <p>
|
||||
* 其他系统内置的拒绝策略,见hutool定义的枚举 {@link RejectPolicy} 线程拒绝策略枚举.
|
||||
*
|
||||
* @author luozongle
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package cn.hutool.core.util;
|
||||
|
||||
import cn.hutool.core.collection.SetUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
|
||||
import java.util.Set;
|
||||
|
@@ -298,12 +298,12 @@ public class ByteUtil {
|
||||
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||
for (int i = (Long.BYTES - 1); i >= 0; i--) {
|
||||
values <<= Byte.SIZE;
|
||||
values |= (bytes[i + start] & 0xff);
|
||||
values |= (bytes[i + start] & 0xffL);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < Long.BYTES; i++) {
|
||||
values <<= Byte.SIZE;
|
||||
values |= (bytes[i + start] & 0xff);
|
||||
values |= (bytes[i + start] & 0xffL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,119 @@
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
import cn.hutool.core.codec.HexUtil;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class MetroHash128Test {
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
Assert.assertEquals("5F3CA3D41D1CB4606B14684C65FB6", h128(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1Low() {
|
||||
Assert.assertEquals("E84D9EA70174C3184AC6E55552310F85", h128("a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1High() {
|
||||
Assert.assertEquals("9A5BCED4C3CA98CADE13388E3C14C215", h128("é"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2Palindrome() {
|
||||
Assert.assertEquals("3DDDF558587273E1FD034EC7CC917AC8", h128("aa"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
Assert.assertEquals("458E6A18B65C38AD2552335402A068A2", h128("ab"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3PalindromeLow() {
|
||||
Assert.assertEquals("19725A6E67A8DD1A84E3C844A20DA938", h128("aaa"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3PalindromeHigh() {
|
||||
Assert.assertEquals("1DD9CC1D29B5080D5F9F171FB2C50CBB", h128("ééé"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
Assert.assertEquals("89AB9CDB9FAF7BA71CD86385C1F801A5", h128("abc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4Palindrome() {
|
||||
Assert.assertEquals("AFD0BBB3764CA0539E46B914B8CB8911", h128("poop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4() {
|
||||
Assert.assertEquals("D11B6DB94FE20E3884F3829AD6613D19", h128("fart"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test5() {
|
||||
Assert.assertEquals("D45A3A74885F9C842081929D2E9A3A3B", h128("Hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test12() {
|
||||
Assert.assertEquals("A7CEC59B03A9053BA6009EEEC81E81F5", h128("Hello World!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test31() {
|
||||
Assert.assertEquals("980CA7496A1B26D24E529DFB2B3A870",
|
||||
h128("The Quick Brown Fox Jumped Over"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test32() {
|
||||
Assert.assertEquals("76663CEA442E22F86A6CB41FBA896B9B",
|
||||
h128("The Quick Brown Fox Jumped Over "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLonger() {
|
||||
Assert.assertEquals("7010B2D7C8A3515AE3CA4DBBD9ED30D0",
|
||||
h128("The Quick Brown Fox Jumped Over The Lazy Dog"));
|
||||
}
|
||||
|
||||
static final byte[] ENDIAN =
|
||||
StrUtil.utf8Bytes("012345678901234567890123456789012345678901234567890123456789012");
|
||||
|
||||
@Test
|
||||
public void testLittleEndian() {
|
||||
final ByteBuffer output = ByteBuffer.allocate(16);
|
||||
MetroHash128.of(0).apply(ByteBuffer.wrap(ENDIAN)).write(output, ByteOrder.LITTLE_ENDIAN);
|
||||
Assert.assertEquals("C77CE2BFA4ED9F9B0548B2AC5074A297", hex(output.array()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigEndian() {
|
||||
final ByteBuffer output = ByteBuffer.allocate(16);
|
||||
MetroHash128.of(0).apply(ByteBuffer.wrap(ENDIAN)).write(output, ByteOrder.BIG_ENDIAN);
|
||||
Assert.assertEquals("97A27450ACB248059B9FEDA4BFE27CC7", hex(output.array()));
|
||||
}
|
||||
|
||||
static String h128(final String input) {
|
||||
final MetroHash128 mh = MetroHash128.of(0).apply(ByteBuffer.wrap(StrUtil.utf8Bytes(input)));
|
||||
return hex(mh.getHigh()) + hex(mh.getLow());
|
||||
}
|
||||
|
||||
private static String hex(final long value){
|
||||
return HexUtil.toHex(value).toUpperCase();
|
||||
}
|
||||
|
||||
private static String hex(final byte[] bytes){
|
||||
return HexUtil.encodeHexStr(bytes).toUpperCase();
|
||||
}
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
import cn.hutool.core.codec.HexUtil;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* 来自:https://github.com/postamar/java-metrohash/blob/master/src/test/java/util/hash/MetroHashTest64.java
|
||||
*/
|
||||
public class MetroHash64Test {
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
Assert.assertEquals("705FB008071E967D", h64(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1Low() {
|
||||
Assert.assertEquals("AF6F242B7ED32BCB", h64("a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1High() {
|
||||
Assert.assertEquals("D51BA21D219C37B3", h64("é"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2Palindrome() {
|
||||
Assert.assertEquals("3CF3A8F204CAE1B6", h64("aa"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
Assert.assertEquals("CD2EA2738FC27D98", h64("ab"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3PalindromeLow() {
|
||||
Assert.assertEquals("E59031D8D046D241", h64("aaa"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3PalindromeHigh() {
|
||||
Assert.assertEquals("FE8325DC6F40511D", h64("ééé"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
Assert.assertEquals("ED4F5524E6FAFFBB", h64("abc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4Palindrome() {
|
||||
Assert.assertEquals("CD77F739885CCB2C", h64("poop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4() {
|
||||
Assert.assertEquals("B642DCB026D9573C", h64("fart"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test5() {
|
||||
Assert.assertEquals("A611009FEE6AF8B", h64("Hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test12() {
|
||||
Assert.assertEquals("14BCB49B74E3B404", h64("Hello World!"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test31() {
|
||||
Assert.assertEquals("D27A7BFACC320E2F",
|
||||
h64("The Quick Brown Fox Jumped Over"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test32() {
|
||||
Assert.assertEquals("C313A3A811EAB43B",
|
||||
h64("The Quick Brown Fox Jumped Over "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLonger() {
|
||||
Assert.assertEquals("C7047C2FCA234C05",
|
||||
h64("The Quick Brown Fox Jumped Over The Lazy Dog"));
|
||||
}
|
||||
|
||||
static final byte[] ENDIAN =
|
||||
StrUtil.utf8Bytes("012345678901234567890123456789012345678901234567890123456789012");
|
||||
|
||||
@Test
|
||||
public void testLittleEndian() {
|
||||
final ByteBuffer output = ByteBuffer.allocate(8);
|
||||
MetroHash64.of(0).apply(ByteBuffer.wrap(ENDIAN)).write(output, ByteOrder.LITTLE_ENDIAN);
|
||||
Assert.assertEquals("6B753DAE06704BAD", hex(output.array()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigEndian() {
|
||||
final ByteBuffer output = ByteBuffer.allocate(8);
|
||||
MetroHash64.of(0).apply(ByteBuffer.wrap(ENDIAN)).write(output, ByteOrder.BIG_ENDIAN);
|
||||
Assert.assertEquals("AD4B7006AE3D756B", hex(output.array()));
|
||||
}
|
||||
|
||||
private String h64(final String value) {
|
||||
return HexUtil.toHex(MetroHash64.of(0).hash64(StrUtil.utf8Bytes(value))).toUpperCase();
|
||||
}
|
||||
|
||||
private static String hex(final byte[] bytes){
|
||||
return HexUtil.encodeHexStr(bytes).toUpperCase();
|
||||
}
|
||||
}
|
@@ -1,10 +1,11 @@
|
||||
package cn.hutool.core.codec.hash;
|
||||
package cn.hutool.core.codec.hash.metro;
|
||||
|
||||
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.codec.HexUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.codec.hash.CityHash;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
@@ -16,22 +17,32 @@ public class MetroHashTest {
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
Assert.assertEquals("31290877cceaea29", HexUtil.toHex(MetroHash.INSTANCE.hash64(StrUtil.utf8Bytes(""), 0)));
|
||||
Assert.assertEquals("705fb008071e967d", HexUtil.toHex(MetroHash64.of(0).hash64(StrUtil.utf8Bytes(""))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1Low() {
|
||||
Assert.assertEquals("AF6F242B7ED32BCB", h64("a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1High() {
|
||||
Assert.assertEquals("D51BA21D219C37B3", h64("é"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metroHash64Test() {
|
||||
final byte[] str = "我是一段测试123".getBytes(CharsetUtil.UTF_8);
|
||||
final long hash64 = MetroHash.INSTANCE.hash64(str);
|
||||
Assert.assertEquals(62920234463891865L, hash64);
|
||||
final long hash64 = MetroHash64.of(0).hash64(str);
|
||||
Assert.assertEquals(147395857347476456L, hash64);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metroHash128Test() {
|
||||
final byte[] str = "我是一段测试123".getBytes(CharsetUtil.UTF_8);
|
||||
final long[] hash128 = MetroHash.INSTANCE.hash128(str).getLongArray();
|
||||
Assert.assertEquals(4956592424592439349L, hash128[0]);
|
||||
Assert.assertEquals(6301214698325086246L, hash128[1]);
|
||||
final long[] hash128 = MetroHash128.of(0).hash128(str).getLongArray();
|
||||
Assert.assertEquals(228255164667538345L, hash128[0]);
|
||||
Assert.assertEquals(-6394585948993412256L, hash128[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +60,7 @@ public class MetroHashTest {
|
||||
|
||||
final long startMetro = System.currentTimeMillis();
|
||||
for (final String s : strArray) {
|
||||
MetroHash.INSTANCE.hash64(StrUtil.utf8Bytes(s));
|
||||
MetroHash64.of(0).hash64(StrUtil.utf8Bytes(s));
|
||||
}
|
||||
final long endMetro = System.currentTimeMillis();
|
||||
|
||||
@@ -73,7 +84,7 @@ public class MetroHashTest {
|
||||
|
||||
final long startMetro = System.currentTimeMillis();
|
||||
for (final String s : strArray) {
|
||||
MetroHash.INSTANCE.hash128(StrUtil.utf8Bytes(s));
|
||||
MetroHash128.of(0).hash128(StrUtil.utf8Bytes(s));
|
||||
}
|
||||
final long endMetro = System.currentTimeMillis();
|
||||
|
||||
@@ -90,4 +101,8 @@ public class MetroHashTest {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String h64(final String value) {
|
||||
return HexUtil.toHex(MetroHash64.of(0).hash64(StrUtil.utf8Bytes(value))).toUpperCase();
|
||||
}
|
||||
}
|
@@ -7,13 +7,7 @@ import lombok.Data;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@link IterUtil} 单元测试
|
||||
|
@@ -4,7 +4,6 @@ import cn.hutool.core.collection.ListUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@@ -11,17 +11,7 @@ import cn.hutool.core.util.RandomUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PushbackReader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
public class IoUtilTest {
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package cn.hutool.core.builder;
|
||||
package cn.hutool.core.lang.builder;
|
||||
|
||||
import cn.hutool.core.lang.builder.GenericBuilder;
|
||||
import cn.hutool.core.text.StrUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
@@ -39,13 +39,13 @@ public class BoundTest {
|
||||
// getValue
|
||||
Assert.assertNull(bound.getValue());
|
||||
// toString
|
||||
Assert.assertEquals("(" + "-\u221e", bound.descBound());
|
||||
Assert.assertEquals("(" + "-∞", bound.descBound());
|
||||
// compareTo
|
||||
Assert.assertEquals(0, bound.compareTo(bound));
|
||||
Assert.assertEquals(-1, bound.compareTo(Bound.atMost(1)));
|
||||
|
||||
Assert.assertEquals(BoundedRange.all(), bound.toRange());
|
||||
Assert.assertEquals("{x | x > -\u221e}", bound.toString());
|
||||
Assert.assertEquals("{x | x > -∞}", bound.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -60,13 +60,13 @@ public class BoundTest {
|
||||
// getValue
|
||||
Assert.assertNull(bound.getValue());
|
||||
// toString
|
||||
Assert.assertEquals("+\u221e" + ")", bound.descBound());
|
||||
Assert.assertEquals("+∞" + ")", bound.descBound());
|
||||
// compareTo
|
||||
Assert.assertEquals(0, bound.compareTo(bound));
|
||||
Assert.assertEquals(1, bound.compareTo(Bound.atMost(1)));
|
||||
|
||||
Assert.assertEquals(BoundedRange.all(), bound.toRange());
|
||||
Assert.assertEquals("{x | x < +\u221e}", bound.toString());
|
||||
Assert.assertEquals("{x | x < +∞}", bound.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package cn.hutool.core.reflect;
|
||||
|
||||
import cn.hutool.core.reflect.ActualTypeMapperPool;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -9,7 +8,7 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 见:<a href="https://gitee.com/dromara/hutool/pulls/447/files">https://gitee.com/dromara/hutool/pulls/447/files</a>
|
||||
*
|
||||
* <p>
|
||||
* TODO 同时继承泛型和实现泛型接口需要解析,此处为F
|
||||
*/
|
||||
public class ActualTypeMapperPoolTest {
|
||||
|
@@ -591,9 +591,7 @@ public class AbstractEnhancedWrappedStreamTest {
|
||||
public void testMapMulti() {
|
||||
Assert.assertEquals(
|
||||
asList(1, 2, 3),
|
||||
wrap(1, 2, 3).mapMulti((t, builder) -> {
|
||||
builder.accept(t);
|
||||
}).toList()
|
||||
wrap(1, 2, 3).mapMulti((t, builder) -> builder.accept(t)).toList()
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -59,6 +59,7 @@ public class CharSequenceUtilTest {
|
||||
Assert.assertEquals("/", result);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
@Test
|
||||
public void normalizeTest() {
|
||||
// https://blog.csdn.net/oscar999/article/details/105326270
|
||||
@@ -155,6 +156,7 @@ public class CharSequenceUtilTest {
|
||||
Assert.assertNull(CharSequenceUtil.removeSuffixIgnoreCase(null, "ABCdef"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Test
|
||||
public void trimToNullTest(){
|
||||
String a = " ";
|
||||
|
@@ -8,7 +8,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class issueI5Q4HDTest {
|
||||
public class IssueI5Q4HDTest {
|
||||
|
||||
@Test
|
||||
public void matchAllTest(){
|
@@ -27,6 +27,7 @@ public class CharUtilTest {
|
||||
Assert.assertTrue(CharUtil.isChar(a));
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
@Test
|
||||
public void isBlankCharTest(){
|
||||
final char a = '\u00A0';
|
||||
@@ -56,6 +57,7 @@ public class CharUtilTest {
|
||||
Assert.assertEquals('⑳', CharUtil.toCloseByNumber(20));
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
@Test
|
||||
public void issueI5UGSQTest(){
|
||||
char c = '\u3164';
|
||||
|
Reference in New Issue
Block a user