├── .github ├── dependabot.yaml └── workflows │ ├── deploy.yml │ └── test.yml ├── .gitignore ├── .idea ├── copyright │ ├── Apache.xml │ └── profiles_settings.xml └── scopes │ └── Only_source_and_tests.xml ├── LICENSE ├── README.md ├── agent ├── pom.xml └── src │ └── main │ └── java │ └── w │ └── agent │ ├── AgentInstrumentation.java │ └── AgentMain.java ├── asm-patcher ├── pom.xml └── src │ ├── main │ └── java │ │ └── w │ │ └── asm │ │ └── patcher │ │ ├── AsmPatcher.java │ │ ├── AsmRedefine.java │ │ ├── AsmRedefineMethod.java │ │ ├── ImmutableMethodInfo.java │ │ ├── Matcher.java │ │ ├── Matchers.java │ │ └── MethodInfo.java │ └── test │ └── java │ └── AsmPatcherTests.java ├── asm ├── pom.xml └── src │ ├── main │ └── java │ │ └── w │ │ └── asm │ │ ├── Asm.java │ │ ├── ClassMaker.java │ │ ├── MagicAccessorBridge.java │ │ └── MethodMaker.java │ └── test │ └── java │ └── w │ └── asm │ └── MakerTests.java ├── bom └── pom.xml ├── config ├── pom.xml └── src │ ├── main │ └── java │ │ └── w │ │ └── config │ │ ├── Config.java │ │ ├── ConfigMissingKeyException.java │ │ ├── ConfigProvider.java │ │ ├── FileConfig.java │ │ ├── InconvertibleMutableConfig.java │ │ ├── JacksonConfigProvider.java │ │ ├── MapBasedMutableConfig.java │ │ ├── MutableConfig.java │ │ ├── SimpleFileConfig.java │ │ ├── deserializer │ │ └── ConfigDeserializer.java │ │ ├── mapper │ │ ├── AbstractMapper.java │ │ ├── BooleanMapper.java │ │ ├── Mapper.java │ │ ├── NumberMapper.java │ │ └── StringMapper.java │ │ └── path │ │ ├── ConfigPath.java │ │ └── SimpleConfigPath.java │ └── test │ ├── java │ └── w │ │ └── config │ │ ├── ConfigProviderTests.java │ │ ├── ConfigTests.java │ │ └── FileConfigTests.java │ └── resources │ └── config.yml ├── deploy.sh ├── eventbus ├── pom.xml └── src │ ├── main │ └── java │ │ └── w │ │ └── eventbus │ │ ├── AbstractAsyncEvent.java │ │ ├── AsmDispatchWriter.java │ │ ├── AsmDispatchWriters.java │ │ ├── AsyncEvent.java │ │ ├── Cancellable.java │ │ ├── Event.java │ │ ├── EventBus.java │ │ ├── EventDispatcher.java │ │ ├── ImmutableRegisteredEventSubscription.java │ │ ├── NamespaceValidator.java │ │ ├── PostOrder.java │ │ ├── RegisteredSubscription.java │ │ ├── SimpleEventBus.java │ │ └── Subscribe.java │ └── test │ ├── java │ └── w │ │ └── eventbus │ │ └── EventBusTests.java │ └── resources │ └── simplelogger.properties ├── geo ├── pom.xml └── src │ └── main │ └── java │ └── w │ └── geo │ ├── GeoLocationLookupException.java │ ├── GeoLocationManager.java │ ├── cache │ ├── caffeine │ │ └── CachedGeoLocationManager.java │ └── guava │ │ └── CachedGeoLocationManager.java │ ├── maxmind │ ├── DatabaseProvider.java │ ├── DatabaseProviders.java │ └── MaxmindGeoLocationManager.java │ └── model │ ├── Country.java │ └── GeoLocation.java ├── pom.xml ├── settings.xml ├── unsafe ├── pom.xml └── src │ ├── main │ └── java │ │ └── w │ │ └── unsafe │ │ └── Unsafe.java │ └── test │ └── java │ └── UnsafeTests.java └── util ├── pom.xml └── src ├── main └── java │ └── w │ └── util │ ├── ByteAllocator.java │ ├── ByteSlice.java │ ├── ByteUnit.java │ ├── ClassLoaderUtils.java │ ├── Env.java │ ├── Iterables.java │ ├── Iterators.java │ ├── NumberUtils.java │ ├── ObjectCloner.java │ ├── ObjectUtils.java │ ├── RandomUtils.java │ ├── TypeUtils.java │ ├── buffering │ ├── Buffered.java │ └── Buffering.java │ ├── ci │ ├── CiString.java │ └── CiStrings.java │ ├── concurrent │ ├── Async.java │ └── ThreadFactories.java │ ├── function │ ├── ComponentConsumer.java │ └── ComponentPredicate.java │ ├── io │ ├── AbstractByteOutput.java │ ├── ByteOutput.java │ ├── ByteOutputStream.java │ ├── CappedByteOutput.java │ └── UncappedByteOutput.java │ ├── lazy │ ├── ConcurrentLazy.java │ ├── Lazy.java │ └── SimpleLazy.java │ ├── mutable │ ├── MutableInt.java │ ├── MutableLong.java │ ├── MutableOptionalInt.java │ ├── MutableOptionalLong.java │ ├── MutableOptionalReference.java │ ├── MutableReference.java │ └── Mutables.java │ ├── pair │ ├── MutablePair.java │ ├── Pair.java │ ├── Pairs.java │ └── UnorderedPair.java │ └── random │ ├── RandomStringGenerator.java │ ├── RandomStringGeneratorBuilder.java │ ├── SimpleRandomStringGenerator.java │ ├── SimpleWeightedRandomGenerator.java │ ├── WeightedRandomBuilder.java │ └── WeightedRandomGenerator.java └── test └── java └── w └── util ├── NumberUtilsTest.java ├── RandomUtilsTests.java ├── buffering └── BufferingTests.java ├── ci └── CiStringsTest.java ├── io ├── ByteOutputTests.java └── ByteUnitTest.java ├── lazy ├── ConcurrentLazyTests.java ├── LazyTests.java └── SimpleLazyTests.java ├── pair └── PairTests.java └── random ├── RandomStringGeneratorTests.java └── WeightedRandomGeneratorTests.java /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | target-branch: master 9 | reviewers: [ whilein ] 10 | labels: 11 | - dependencies 12 | - automatic -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: deploy 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v1 13 | - name: Set up JDK 17 14 | uses: actions/setup-java@v1 15 | with: 16 | java-version: 17 17 | - name: Cache local Maven repository 18 | uses: actions/cache@v2 19 | with: 20 | path: ~/.m2/repository 21 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 22 | restore-keys: | 23 | ${{ runner.os }}-maven- 24 | - name: Retrieve github tag 25 | id: github_tag 26 | run: echo ::set-output name=RESULT::$(echo $GITHUB_REF | cut -d / -f 3) 27 | - name: Prepare deploy 28 | run: | 29 | cat <(echo -e "${{ secrets.GPG_KEY_CONTENTS }}") | gpg --batch --import 30 | - name: Deploy with Maven 31 | run: mvn --no-transfer-progress --batch-mode -Drevision=${{ steps.github_tag.outputs.RESULT }} -Dgpg.passphrase=${{ secrets.SIGNING_PASSWORD }} -s settings.xml -T 1C -Pdeploy -DskipTests=true -Dmaven.test.skip clean deploy 32 | env: 33 | OSSRH_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 34 | OSSRH_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: [ push ] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: Set up JDK 17 12 | uses: actions/setup-java@v1 13 | with: 14 | java-version: 17 15 | - name: Cache local Maven repository 16 | uses: actions/cache@v2 17 | with: 18 | path: ~/.m2/repository 19 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 20 | restore-keys: | 21 | ${{ runner.os }}-maven- 22 | - name: Test with Maven 23 | run: mvn --no-transfer-progress -T 1C clean test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/** 2 | !/.idea/scopes/ 3 | !/.idea/copyright/ 4 | !/.idea/scopes/** 5 | !/.idea/copyright/** 6 | target/ 7 | *.iml 8 | .flattened-pom.xml -------------------------------------------------------------------------------- /.idea/copyright/Apache.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/scopes/Only_source_and_tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wcommons 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | ## Использование 26 | 27 | ```xml 28 | 29 | 30 | 31 | 32 | 33 | io.github.whilein.wcommons 34 | wcommons-bom 35 | ${wcommons.version} 36 | pom 37 | import 38 | 39 | 40 | 41 | 42 | 43 | 44 | io.github.whilein.wcommons 45 | wcommons-agent 46 | 47 | 48 | 49 | io.github.whilein.wcommons 50 | wcommons-asm 51 | 52 | 53 | 54 | io.github.whilein.wcommons 55 | wcommons-asm-patcher 56 | 57 | 58 | 59 | io.github.whilein.wcommons 60 | wcommons-util 61 | 62 | 63 | 64 | io.github.whilein.wcommons 65 | wcommons-config 66 | 67 | 68 | 69 | io.github.whilein.wcommons 70 | wcommons-eventbus 71 | 72 | 73 | 74 | io.github.whilein.wcommons 75 | wcommons-geo 76 | 77 | 78 | 79 | io.github.whilein.wcommons 80 | wcommons-util 81 | 82 | 83 | 84 | ``` 85 | 86 | ## Содержание 87 | 88 | - ["Шина событий"](eventbus) 89 | - [Изменение байткода в рантайме](asm-patcher) 90 | - [Java агент](agent) 91 | - [ASM](asm) 92 | - MagicAccessorImpl bridge 93 | - [Утилиты](util) 94 | - Lazy 95 | - Pair, MutablePair, UnorderedPair 96 | - MutableInt, MutableLong, MutableReference, MutableOptionalInt, MutableOptionalLong, MutableOptionalReference 97 | - Message 98 | - RandomUtils, RandomStringGenerator, WeightedRandom 99 | - ClassLoaderUtils 100 | - Async (Упрощенный вариант Future) 101 | - Buffering 102 | - Bytes, ByteSlice 103 | - Hex 104 | - Root 105 | - [Конфигурация](config) 106 | - [Геолокация](geo) 107 | -------------------------------------------------------------------------------- /agent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/agent 12 | wcommons-agent 13 | 14 | Attaches Java Agent in runtime and gives you access to Instrumentation 15 | 16 | 17 | 18 | 19 | org.apache.maven.plugins 20 | maven-jar-plugin 21 | 3.3.0 22 | 23 | 24 | 25 | 26 | true 27 | true 28 | w.agent.AgentMain 29 | w.agent.AgentMain 30 | w.agent.AgentMain 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /agent/src/main/java/w/agent/AgentMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.agent; 18 | 19 | import com.sun.tools.attach.VirtualMachine; 20 | import lombok.SneakyThrows; 21 | import lombok.experimental.UtilityClass; 22 | import lombok.val; 23 | 24 | import java.io.File; 25 | import java.lang.instrument.Instrumentation; 26 | 27 | /** 28 | * @author whilein 29 | */ 30 | @UtilityClass 31 | final class AgentMain { 32 | 33 | @SuppressWarnings("unused") 34 | private static Instrumentation instrumentation; 35 | 36 | @SneakyThrows 37 | public void main(final String[] args) { 38 | val vm = VirtualMachine.attach(args[0]); 39 | 40 | val jar = new File(AgentMain.class.getProtectionDomain().getCodeSource().getLocation().toURI()) 41 | .getPath(); 42 | 43 | vm.loadAgent(jar); 44 | } 45 | 46 | public void premain(final String args, final Instrumentation instrumentation) { 47 | System.setProperty("wcommons.agent.premain", "true"); 48 | AgentMain.instrumentation = instrumentation; 49 | } 50 | 51 | @SneakyThrows 52 | public void agentmain(final String args, final Instrumentation instrumentation) { 53 | AgentMain.instrumentation = instrumentation; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /asm-patcher/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/asm-patcher 12 | wcommons-asm-patcher 13 | Runtime bytecode modification 14 | 15 | 16 | 17 | io.github.whilein.wcommons 18 | wcommons-asm 19 | ${project.version} 20 | 21 | 22 | 23 | io.github.whilein.wcommons 24 | wcommons-agent 25 | ${project.version} 26 | 27 | 28 | -------------------------------------------------------------------------------- /asm-patcher/src/main/java/w/asm/patcher/AsmRedefine.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm.patcher; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.io.File; 22 | 23 | /** 24 | * @author whilein 25 | */ 26 | public interface AsmRedefine { 27 | 28 | @NotNull AsmRedefineMethod on(@NotNull Matcher matcher); 29 | 30 | void apply(); 31 | 32 | /** 33 | * Применить изменения с сохранением в папку 34 | * 35 | * @param file Папка 36 | */ 37 | void apply(@NotNull File file); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /asm-patcher/src/main/java/w/asm/patcher/AsmRedefineMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm.patcher; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | import org.objectweb.asm.MethodVisitor; 21 | 22 | import java.util.function.Function; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public interface AsmRedefineMethod { 28 | 29 | @NotNull AsmRedefine intercept(@NotNull Function<@NotNull MethodVisitor, @NotNull MethodVisitor> mv); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /asm-patcher/src/main/java/w/asm/patcher/ImmutableMethodInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm.patcher; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import lombok.val; 24 | import org.jetbrains.annotations.NotNull; 25 | import org.objectweb.asm.Type; 26 | 27 | /** 28 | * @author whilein 29 | */ 30 | @Getter 31 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 32 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 33 | public final class ImmutableMethodInfo implements MethodInfo { 34 | 35 | Type returnType; 36 | Type[] arguments; 37 | 38 | String name; 39 | 40 | public static @NotNull MethodInfo from(final @NotNull String name, final @NotNull String descriptor) { 41 | val type = Type.getMethodType(descriptor); 42 | 43 | return new ImmutableMethodInfo( 44 | type.getReturnType(), type.getArgumentTypes(), 45 | name 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /asm-patcher/src/main/java/w/asm/patcher/Matcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm.patcher; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public interface Matcher { 25 | 26 | boolean matches(@NotNull MethodInfo info); 27 | 28 | default @NotNull Matcher and(final @NotNull Matcher matcher) { 29 | return info -> matches(info) && matcher.matches(info); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /asm-patcher/src/main/java/w/asm/patcher/Matchers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm.patcher; 18 | 19 | import lombok.experimental.UtilityClass; 20 | import lombok.val; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.objectweb.asm.Type; 23 | 24 | import java.util.Arrays; 25 | 26 | /** 27 | * @author whilein 28 | */ 29 | @UtilityClass 30 | public class Matchers { 31 | 32 | public @NotNull Matcher named(final @NotNull String name) { 33 | return info -> info.getName().equals(name); 34 | } 35 | 36 | public @NotNull Matcher returns(final @NotNull Class returnType) { 37 | val type = Type.getType(returnType); 38 | 39 | return info -> info.getReturnType().equals(type); 40 | } 41 | 42 | public @NotNull Matcher takesArguments(final int count) { 43 | return info -> info.getArguments().length == count; 44 | } 45 | 46 | public @NotNull Matcher takesArguments(final @NotNull Class @NotNull ... parameters) { 47 | val parameterTypes = Arrays.stream(parameters) 48 | .map(Type::getType) 49 | .toArray(Type[]::new); 50 | 51 | return info -> Arrays.equals(parameterTypes, info.getArguments()); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /asm-patcher/src/main/java/w/asm/patcher/MethodInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm.patcher; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | import org.objectweb.asm.Type; 21 | 22 | /** 23 | * @author whilein 24 | */ 25 | public interface MethodInfo { 26 | 27 | @NotNull Type getReturnType(); 28 | 29 | @NotNull Type @NotNull [] getArguments(); 30 | 31 | @NotNull String getName(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /asm-patcher/src/test/java/AsmPatcherTests.java: -------------------------------------------------------------------------------- 1 | import org.junit.jupiter.api.Test; 2 | import org.objectweb.asm.MethodVisitor; 3 | import org.objectweb.asm.Opcodes; 4 | import w.asm.patcher.AsmPatcher; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | import static w.asm.patcher.Matchers.named; 8 | 9 | /** 10 | * @author whilein 11 | */ 12 | final class AsmPatcherTests { 13 | 14 | static final String BEFORE_REDEFINE = "Соси хуй"; 15 | static final String AFTER_REDEFINE = "Гей тупой"; 16 | 17 | @Test 18 | void testRedefineMethod() { 19 | assertEquals(BEFORE_REDEFINE, getText()); 20 | 21 | AsmPatcher.redefine(AsmPatcherTests.class) 22 | .on(named("getText")) 23 | .intercept(mv -> new MethodVisitor(Opcodes.ASM9, mv) { 24 | @Override 25 | public void visitLdcInsn(final Object value) { 26 | super.visitLdcInsn(value.equals(BEFORE_REDEFINE) ? AFTER_REDEFINE : value); 27 | } 28 | }) 29 | .apply(); 30 | 31 | assertEquals(AFTER_REDEFINE, getText()); 32 | } 33 | 34 | String getText() { 35 | return BEFORE_REDEFINE; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /asm/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/asm 12 | wcommons-asm 13 | Some useful tools for ow2 asm 14 | 15 | 16 | 17 | org.ow2.asm 18 | asm 19 | 20 | 21 | 22 | io.github.whilein.wcommons 23 | wcommons-util 24 | ${project.version} 25 | test 26 | 27 | 28 | 29 | io.github.whilein.wcommons 30 | wcommons-unsafe 31 | ${project.version} 32 | 33 | 34 | -------------------------------------------------------------------------------- /asm/src/main/java/w/asm/Asm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm; 18 | 19 | import lombok.experimental.UtilityClass; 20 | import lombok.val; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.objectweb.asm.Type; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | @UtilityClass 28 | public class Asm { 29 | 30 | public final @NotNull String 31 | OBJECT = "Ljava/lang/Object;", 32 | VOID = "V", 33 | BOOLEAN = "Z", 34 | BYTE = "B", 35 | SHORT = "S", 36 | INT = "I", 37 | LONG = "J", 38 | FLOAT = "F", 39 | DOUBLE = "D"; 40 | 41 | public final @NotNull String 42 | OBJECT_TYPE = "java/lang/Object", 43 | EXCEPTION_TYPE = "java/lang/Exception"; 44 | 45 | public @NotNull String methodDescriptor( 46 | final @NotNull Class returnType, 47 | final @NotNull Class @NotNull ... parameters 48 | ) { 49 | val result = new StringBuilder(); 50 | result.append('('); 51 | 52 | for (val parameter : parameters) { 53 | result.append(Type.getDescriptor(parameter)); 54 | } 55 | 56 | return result.append(')').append(Type.getDescriptor(returnType)).toString(); 57 | } 58 | 59 | public @NotNull String methodDescriptor( 60 | final @NotNull String returnType, 61 | final @NotNull String @NotNull ... parameters 62 | ) { 63 | val result = new StringBuilder(); 64 | result.append('('); 65 | 66 | for (val parameter : parameters) { 67 | result.append(parameter); 68 | } 69 | 70 | return result.append(')').append(returnType).toString(); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /asm/src/main/java/w/asm/ClassMaker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm; 18 | 19 | import lombok.val; 20 | import org.jetbrains.annotations.NotNull; 21 | import org.objectweb.asm.ClassVisitor; 22 | import org.objectweb.asm.ClassWriter; 23 | import org.objectweb.asm.Opcodes; 24 | import org.objectweb.asm.Type; 25 | 26 | import static org.objectweb.asm.Opcodes.*; 27 | 28 | /** 29 | * @author whilein 30 | */ 31 | public class ClassMaker extends ClassVisitor { 32 | 33 | public ClassWriter cw; 34 | 35 | public ClassMaker(final ClassVisitor cv) { 36 | super(Opcodes.ASM9, cv); 37 | 38 | if (cv instanceof ClassWriter) { 39 | this.cw = (ClassWriter) cv; 40 | } 41 | } 42 | 43 | public ClassMaker(final int flags) { 44 | super(Opcodes.ASM9, new ClassWriter(flags)); 45 | 46 | this.cw = (ClassWriter) super.cv; 47 | } 48 | 49 | public String name; 50 | public String superName; 51 | 52 | public byte[] toByteArray() { 53 | final ClassWriter cw; 54 | 55 | if ((cw = this.cw) == null) { 56 | throw new IllegalStateException("ClassMaker is not created from ClassWriter"); 57 | } 58 | 59 | return cw.toByteArray(); 60 | } 61 | 62 | @Override 63 | public void visit( 64 | final int version, 65 | final int access, 66 | final String name, 67 | final String signature, 68 | final String superName, 69 | final String[] interfaces 70 | ) { 71 | this.name = name; 72 | this.superName = superName; 73 | 74 | super.visit(version, access, name, signature, superName, interfaces); 75 | } 76 | 77 | public @NotNull MethodMaker visitEmptyConstructor( 78 | final int access, 79 | final @NotNull Class superType 80 | ) { 81 | return visitEmptyConstructor(access, Type.getInternalName(superType)); 82 | } 83 | 84 | public @NotNull MethodMaker visitEmptyConstructor( 85 | final int access, 86 | final @NotNull Type type 87 | ) { 88 | return visitEmptyConstructor(access, type.getInternalName()); 89 | } 90 | 91 | public @NotNull MethodMaker visitEmptyConstructor( 92 | final int access 93 | ) { 94 | final String superName; 95 | 96 | if ((superName = this.superName) == null) { 97 | throw new IllegalStateException("Cannot #visitEmptyConstructor before #visit"); 98 | } 99 | 100 | return visitEmptyConstructor(access, superName); 101 | } 102 | 103 | public @NotNull MethodMaker visitEmptyConstructor( 104 | final int access, 105 | final @NotNull String superName 106 | ) { 107 | val constructor = visitMethod(access, "", "()V", 108 | null, null); 109 | 110 | constructor.visitCode(); 111 | constructor.visitVarInsn(ALOAD, 0); 112 | constructor.visitMethodInsn(INVOKESPECIAL, superName, "", "()V", false); 113 | constructor.visitInsn(RETURN); 114 | 115 | constructor.visitMaxs(1, 1); 116 | 117 | return constructor; 118 | } 119 | 120 | @Override 121 | public MethodMaker visitMethod( 122 | final int access, 123 | final String name, 124 | final String descriptor, 125 | final String signature, 126 | final String[] exceptions 127 | ) { 128 | return new MethodMaker(super.visitMethod(access, name, descriptor, signature, exceptions)); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /asm/src/main/java/w/asm/MethodMaker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm; 18 | 19 | import org.objectweb.asm.MethodVisitor; 20 | import org.objectweb.asm.Opcodes; 21 | 22 | import static org.objectweb.asm.Opcodes.*; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public class MethodMaker extends MethodVisitor { 28 | public MethodMaker(final MethodVisitor methodVisitor) { 29 | super(Opcodes.ASM9, methodVisitor); 30 | } 31 | 32 | public void visitInt(final int value) { 33 | if (value >= -1 && value <= 5) { 34 | super.visitInsn(ICONST_0 + value); 35 | } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { 36 | super.visitIntInsn(BIPUSH, value); 37 | } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { 38 | super.visitIntInsn(SIPUSH, value); 39 | } else { 40 | super.visitLdcInsn(value); 41 | } 42 | } 43 | 44 | public void visitLong(final long value) { 45 | if (value == 0) { 46 | super.visitInsn(LCONST_0); 47 | } else if (value == 1) { 48 | super.visitInsn(LCONST_1); 49 | } else { 50 | super.visitLdcInsn(value); 51 | } 52 | } 53 | 54 | public void visitFloat(final float value) { 55 | if (value == 0) { 56 | super.visitInsn(FCONST_0); 57 | } else if (value == 1) { 58 | super.visitInsn(FCONST_1); 59 | } else if (value == 2) { 60 | super.visitInsn(FCONST_2); 61 | } else { 62 | super.visitLdcInsn(value); 63 | } 64 | } 65 | 66 | public void visitDouble(final double value) { 67 | if (value == 0) { 68 | super.visitInsn(DCONST_0); 69 | } else if (value == 1) { 70 | super.visitInsn(DCONST_1); 71 | } else { 72 | super.visitLdcInsn(value); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /asm/src/test/java/w/asm/MakerTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.asm; 18 | 19 | import lombok.SneakyThrows; 20 | import lombok.val; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | import org.objectweb.asm.Opcodes; 24 | import org.objectweb.asm.Type; 25 | import w.util.ClassLoaderUtils; 26 | import w.util.TypeUtils; 27 | 28 | import java.util.function.BiConsumer; 29 | 30 | import static org.junit.jupiter.api.Assertions.assertEquals; 31 | import static org.junit.jupiter.api.Assertions.assertNotNull; 32 | import static org.objectweb.asm.Opcodes.IRETURN; 33 | 34 | /** 35 | * @author whilein 36 | */ 37 | final class MakerTests { 38 | 39 | ClassMaker cm; 40 | 41 | @BeforeEach 42 | void tearUp() { 43 | cm = new ClassMaker(0); 44 | 45 | cm.visit( 46 | Opcodes.V1_1, Opcodes.ACC_PUBLIC, 47 | "Test", 48 | null, 49 | "java/lang/Object", null 50 | ); 51 | } 52 | 53 | private Class make() { 54 | val bytes = cm.toByteArray(); 55 | 56 | return ClassLoaderUtils.defineClass(this.getClass().getClassLoader(), cm.name, bytes); 57 | } 58 | 59 | @Test 60 | @SneakyThrows 61 | void testEmptyConstructor() { 62 | cm.visitEmptyConstructor(Opcodes.ACC_PUBLIC).visitEnd(); 63 | 64 | Object object = make().getConstructor().newInstance(); 65 | assertNotNull(object); 66 | } 67 | 68 | private String getNumber(final Number number) { 69 | return ("getNumber" + number).replace('-', 'M').replace('.', '_'); 70 | } 71 | 72 | @SneakyThrows 73 | void testNumbers(final T[] numbers, final BiConsumer maker) { 74 | for (val number : numbers) { 75 | val primitive = TypeUtils.getPrimitive(number.getClass()).orElseThrow(); 76 | val primitiveType = Type.getType(primitive); 77 | 78 | val mm = cm.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, 79 | getNumber(number), "()" + primitiveType.getDescriptor(), null, null); 80 | maker.accept(mm, number); 81 | mm.visitInsn(primitiveType.getOpcode(IRETURN)); 82 | 83 | mm.visitMaxs(2, 0); 84 | } 85 | 86 | val cls = make(); 87 | 88 | for (val test : numbers) { 89 | assertEquals(test, cls.getDeclaredMethod(getNumber(test)).invoke(null)); 90 | } 91 | } 92 | 93 | @Test 94 | @SneakyThrows 95 | void testVisitFloat() { 96 | testNumbers(new Float[]{0f, 1f, 1.1f, 100f}, MethodMaker::visitFloat); 97 | } 98 | 99 | @Test 100 | @SneakyThrows 101 | void testVisitDouble() { 102 | testNumbers(new Double[]{0d, 1d, 1.1d, 100d}, MethodMaker::visitDouble); 103 | } 104 | 105 | @Test 106 | @SneakyThrows 107 | void testVisitLong() { 108 | testNumbers(new Long[]{0L, 1L, 100L}, MethodMaker::visitLong); 109 | } 110 | 111 | @Test 112 | @SneakyThrows 113 | void testVisitInt() { 114 | testNumbers(new Integer[]{-1, 0, 1, 2, 3, 4, 5, 100, 1000, 10000}, MethodMaker::visitInt); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /bom/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/bom 12 | wcommons-bom 13 | pom 14 | 15 | wcommons (Bill of Materials) 16 | 17 | 18 | 19 | 20 | org.codehaus.mojo 21 | flatten-maven-plugin 22 | 1.6.0 23 | 24 | true 25 | bom 26 | 27 | 28 | 29 | flatten 30 | process-resources 31 | 32 | flatten 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | io.github.whilein.wcommons 44 | wcommons-agent 45 | ${project.version} 46 | 47 | 48 | 49 | io.github.whilein.wcommons 50 | wcommons-asm 51 | ${project.version} 52 | 53 | 54 | 55 | io.github.whilein.wcommons 56 | wcommons-asm-patcher 57 | ${project.version} 58 | 59 | 60 | 61 | io.github.whilein.wcommons 62 | wcommons-util 63 | ${project.version} 64 | 65 | 66 | 67 | io.github.whilein.wcommons 68 | wcommons-unsafe 69 | ${project.version} 70 | 71 | 72 | 73 | io.github.whilein.wcommons 74 | wcommons-config 75 | ${project.version} 76 | 77 | 78 | 79 | io.github.whilein.wcommons 80 | wcommons-eventbus 81 | ${project.version} 82 | 83 | 84 | 85 | io.github.whilein.wcommons 86 | wcommons-geo 87 | ${project.version} 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/config 12 | wcommons-config 13 | Adapter for json/yaml configurations 14 | 15 | 16 | 17 | com.fasterxml.jackson.core 18 | jackson-databind 19 | 20 | 21 | 22 | com.fasterxml.jackson.dataformat 23 | jackson-dataformat-yaml 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/ConfigMissingKeyException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public final class ConfigMissingKeyException extends RuntimeException { 23 | public ConfigMissingKeyException(String message) { 24 | super(message); 25 | } 26 | 27 | public ConfigMissingKeyException(String message, ConfigMissingKeyException delegate) { 28 | super(message); 29 | 30 | setStackTrace(delegate.getStackTrace()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/ConfigProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.io.File; 22 | import java.io.InputStream; 23 | import java.io.Reader; 24 | import java.nio.file.Path; 25 | import java.util.Map; 26 | 27 | /** 28 | * @author whilein 29 | */ 30 | public interface ConfigProvider { 31 | 32 | @NotNull MutableConfig newObject(); 33 | 34 | @NotNull MutableConfig parse(@NotNull File file); 35 | 36 | @NotNull MutableConfig parse(@NotNull Path path); 37 | 38 | @NotNull MutableConfig parse(@NotNull Reader reader); 39 | 40 | @NotNull MutableConfig parse(@NotNull InputStream stream); 41 | 42 | @NotNull MutableConfig parse(@NotNull String input); 43 | 44 | @NotNull MutableConfig parse(byte @NotNull [] input); 45 | 46 | @NotNull MutableConfig convert(@NotNull Map map); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/FileConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public interface FileConfig extends MutableConfig { 25 | 26 | void saveDefaults(@NotNull String resource); 27 | 28 | void saveDefaults(@NotNull ClassLoader classLoader, @NotNull String resource); 29 | 30 | void save(); 31 | 32 | void reload(); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/InconvertibleMutableConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.experimental.FieldDefaults; 21 | import org.jetbrains.annotations.NotNull; 22 | import w.config.mapper.Mapper; 23 | 24 | import java.io.OutputStream; 25 | import java.io.Writer; 26 | import java.util.LinkedHashMap; 27 | import java.util.Map; 28 | 29 | /** 30 | * @author whilein 31 | */ 32 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 33 | public final class InconvertibleMutableConfig extends MapBasedMutableConfig { 34 | 35 | private InconvertibleMutableConfig(Map map) { 36 | super(map); 37 | } 38 | 39 | public static @NotNull MutableConfig from(@NotNull Map<@NotNull String, @NotNull Object> map) { 40 | return new InconvertibleMutableConfig(map); 41 | } 42 | 43 | public static @NotNull MutableConfig create() { 44 | return new InconvertibleMutableConfig(new LinkedHashMap<>()); 45 | } 46 | 47 | @Override 48 | protected MutableConfig createObject(final Map map) { 49 | return new InconvertibleMutableConfig(map); 50 | } 51 | 52 | @Override 53 | public T asType(final @NotNull Class type) { 54 | throw new UnsupportedOperationException(); 55 | } 56 | 57 | @Override 58 | public @NotNull Mapper mapAs(final @NotNull Class type) { 59 | throw new UnsupportedOperationException(); 60 | } 61 | 62 | @Override 63 | public void writeTo(final @NotNull Writer writer) { 64 | throw new UnsupportedOperationException(); 65 | } 66 | 67 | @Override 68 | public void writeTo(final @NotNull OutputStream os) { 69 | throw new UnsupportedOperationException(); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/MutableConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | import org.jetbrains.annotations.Nullable; 21 | import org.jetbrains.annotations.Unmodifiable; 22 | import w.config.mapper.Mapper; 23 | 24 | import java.util.List; 25 | import java.util.Optional; 26 | 27 | /** 28 | * @author whilein 29 | */ 30 | public interface MutableConfig extends Config { 31 | @Unmodifiable @NotNull List getObjectList(@NotNull String key); 32 | 33 | @NotNull Optional findObject(@NotNull String key); 34 | 35 | @NotNull Mapper configMapper(); 36 | 37 | @NotNull MutableConfig getObject(@NotNull String key) throws ConfigMissingKeyException; 38 | 39 | @NotNull MutableConfig createObject(@NotNull String key); 40 | 41 | void set(@NotNull String key, @Nullable Object object); 42 | 43 | void setAll(@NotNull Config config); 44 | 45 | void remove(@NotNull String key); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/deserializer/ConfigDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config.deserializer; 18 | 19 | import com.fasterxml.jackson.core.JsonParser; 20 | import com.fasterxml.jackson.databind.DeserializationContext; 21 | import com.fasterxml.jackson.databind.JsonDeserializer; 22 | import lombok.AccessLevel; 23 | import lombok.RequiredArgsConstructor; 24 | import lombok.experimental.FieldDefaults; 25 | import w.config.Config; 26 | import w.config.ConfigProvider; 27 | 28 | import java.io.IOException; 29 | import java.util.Map; 30 | 31 | /** 32 | * @author whilein 33 | */ 34 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 35 | @RequiredArgsConstructor 36 | public final class ConfigDeserializer extends JsonDeserializer { 37 | 38 | ConfigProvider configProvider; 39 | 40 | @Override 41 | public Config deserialize(JsonParser jp, DeserializationContext dc) throws IOException { 42 | return configProvider.convert(jp.readValueAs(Map.class)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/mapper/AbstractMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config.mapper; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.RequiredArgsConstructor; 21 | import lombok.experimental.FieldDefaults; 22 | import lombok.val; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | /** 26 | * @author whilein 27 | */ 28 | @FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) 29 | @RequiredArgsConstructor(access = AccessLevel.PROTECTED) 30 | public abstract class AbstractMapper implements Mapper { 31 | 32 | Class type; 33 | 34 | protected abstract T doMap(Object o); 35 | 36 | private T map0(final Object o) { 37 | if (type.isAssignableFrom(o.getClass())) { 38 | return type.cast(o); 39 | } 40 | 41 | return doMap(o); 42 | } 43 | 44 | @Override 45 | public final @Nullable T map(@Nullable Object o) { 46 | return o == null ? null : map0(o); 47 | } 48 | 49 | @Override 50 | public final @Nullable T mapStrict(@Nullable Object o) { 51 | if (o == null) return null; 52 | 53 | val result = map0(o); 54 | 55 | if (result == null) { 56 | throw new IllegalStateException("Cannot map " + o + " to " + type.getSimpleName()); 57 | } 58 | 59 | return result; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/mapper/BooleanMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config.mapper; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public final class BooleanMapper extends AbstractMapper { 25 | 26 | private static final AbstractMapper INSTANCE = new BooleanMapper(); 27 | 28 | public BooleanMapper() { 29 | super(Boolean.class); 30 | } 31 | 32 | public static @NotNull AbstractMapper booleanMapper() { 33 | return INSTANCE; 34 | } 35 | 36 | @Override 37 | protected Boolean doMap(final Object o) { 38 | if (o instanceof String s) { 39 | return Boolean.valueOf(s); 40 | } 41 | 42 | if (o instanceof Number n) { 43 | return n.intValue() == 1; 44 | } 45 | 46 | return null; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/mapper/Mapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config.mapper; 18 | 19 | import org.jetbrains.annotations.Contract; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | /** 23 | * @author whilein 24 | */ 25 | public interface Mapper { 26 | 27 | @Contract("null -> null") 28 | @Nullable T map(@Nullable Object o); 29 | 30 | @Nullable T mapStrict(@Nullable Object o); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/mapper/NumberMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config.mapper; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.experimental.FieldDefaults; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | import java.util.function.Function; 24 | 25 | /** 26 | * @author whilein 27 | */ 28 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 29 | public final class NumberMapper extends AbstractMapper { 30 | 31 | private static final AbstractMapper BYTE = new NumberMapper<>( 32 | Byte.class, 33 | Byte::valueOf, 34 | Number::byteValue 35 | ); 36 | 37 | private static final AbstractMapper SHORT = new NumberMapper<>( 38 | Short.class, 39 | Short::valueOf, 40 | Number::shortValue 41 | ); 42 | 43 | private static final AbstractMapper INT = new NumberMapper<>( 44 | Integer.class, 45 | Integer::valueOf, 46 | Number::intValue 47 | ); 48 | 49 | private static final AbstractMapper LONG = new NumberMapper<>( 50 | Long.class, 51 | Long::valueOf, 52 | Number::longValue 53 | ); 54 | 55 | private static final AbstractMapper DOUBLE = new NumberMapper<>( 56 | Double.class, 57 | Double::valueOf, 58 | Number::doubleValue 59 | ); 60 | 61 | private static final AbstractMapper FLOAT = new NumberMapper<>( 62 | Float.class, 63 | Float::valueOf, 64 | Number::floatValue 65 | ); 66 | 67 | Function fromString; 68 | Function fromNumber; 69 | 70 | private NumberMapper( 71 | Class type, 72 | Function fromString, 73 | Function fromNumber 74 | ) { 75 | super(type); 76 | 77 | this.fromString = fromString; 78 | this.fromNumber = fromNumber; 79 | } 80 | 81 | public static @NotNull AbstractMapper shortMapper() { 82 | return SHORT; 83 | } 84 | 85 | public static @NotNull AbstractMapper byteMapper() { 86 | return BYTE; 87 | } 88 | 89 | public static @NotNull AbstractMapper intMapper() { 90 | return INT; 91 | } 92 | 93 | public static @NotNull AbstractMapper longMapper() { 94 | return LONG; 95 | } 96 | 97 | public static @NotNull AbstractMapper doubleMapper() { 98 | return DOUBLE; 99 | } 100 | 101 | public static @NotNull AbstractMapper floatMapper() { 102 | return FLOAT; 103 | } 104 | 105 | @Override 106 | protected T doMap(final Object o) { 107 | if (o instanceof String s) { 108 | try { 109 | return fromString.apply(s); 110 | } catch (final NumberFormatException e) { 111 | return null; 112 | } 113 | } 114 | 115 | if (o instanceof Number n) { 116 | return fromNumber.apply(n); 117 | } 118 | 119 | return null; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/mapper/StringMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config.mapper; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public final class StringMapper extends AbstractMapper { 28 | private static final AbstractMapper INSTANCE = new StringMapper(); 29 | 30 | private StringMapper() { 31 | super(String.class); 32 | } 33 | 34 | public static @NotNull AbstractMapper stringMapper() { 35 | return INSTANCE; 36 | } 37 | 38 | @Override 39 | protected String doMap(final Object o) { 40 | return o instanceof List || o instanceof Map ? null : o.toString(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /config/src/main/java/w/config/path/ConfigPath.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config.path; 18 | 19 | import org.jetbrains.annotations.Contract; 20 | import org.jetbrains.annotations.NotNull; 21 | import org.jetbrains.annotations.Nullable; 22 | import org.jetbrains.annotations.Unmodifiable; 23 | import w.config.Config; 24 | import w.config.ConfigMissingKeyException; 25 | 26 | import java.util.List; 27 | import java.util.Optional; 28 | import java.util.OptionalDouble; 29 | import java.util.OptionalInt; 30 | import java.util.OptionalLong; 31 | 32 | /** 33 | * @author whilein 34 | */ 35 | public interface ConfigPath { 36 | 37 | boolean isPresent(); 38 | 39 | @NotNull Optional<@NotNull String> asOptionalString(); 40 | 41 | @NotNull Optional asOptional(@NotNull Class type); 42 | 43 | @NotNull OptionalInt asOptionalInt(); 44 | 45 | @NotNull OptionalLong asOptionalLong(); 46 | 47 | @NotNull OptionalDouble asOptionalDouble(); 48 | 49 | T asType(@NotNull Class type) throws ConfigMissingKeyException; 50 | 51 | @NotNull String asString() throws ConfigMissingKeyException; 52 | 53 | @Contract("!null -> !null") 54 | @Nullable String asString(@Nullable String defaultValue); 55 | 56 | @NotNull Object asRaw() throws ConfigMissingKeyException; 57 | 58 | @Contract("!null -> !null") 59 | @Nullable Object asRaw(@Nullable Object defaultValue); 60 | 61 | boolean asBoolean(boolean defaultValue); 62 | 63 | boolean asBoolean() throws ConfigMissingKeyException; 64 | 65 | int asInt() throws ConfigMissingKeyException; 66 | 67 | double asDouble() throws ConfigMissingKeyException; 68 | 69 | long asLong() throws ConfigMissingKeyException; 70 | 71 | int asInt(int defaultValue); 72 | 73 | double asDouble(double defaultValue); 74 | 75 | long asLong(long defaultValue); 76 | 77 | @NotNull Config asObject() throws ConfigMissingKeyException; 78 | 79 | @Unmodifiable @NotNull List<@NotNull String> asStringList(); 80 | 81 | @Unmodifiable @NotNull List asObjectList(); 82 | 83 | @Contract("!null -> !null") 84 | @Unmodifiable @Nullable List<@NotNull Byte> asByteList(@Nullable List def); 85 | 86 | @Unmodifiable @NotNull List<@NotNull Byte> asByteList(); 87 | 88 | @Contract("!null -> !null") 89 | @Unmodifiable @Nullable List<@NotNull Integer> asIntList(@Nullable List def); 90 | 91 | @Unmodifiable @NotNull List<@NotNull Integer> asIntList(); 92 | 93 | @Contract("!null -> !null") 94 | @Unmodifiable @Nullable List<@NotNull Long> asLongList(@Nullable List def); 95 | 96 | @Unmodifiable @NotNull List<@NotNull Long> asLongList(); 97 | 98 | @Contract("!null -> !null") 99 | @Unmodifiable @Nullable List<@NotNull Short> asShortList(@Nullable List def); 100 | 101 | @Unmodifiable @NotNull List<@NotNull Short> asShortList(); 102 | 103 | @Contract("!null -> !null") 104 | @Unmodifiable @Nullable List<@NotNull Double> asDoubleList(@Nullable List def); 105 | 106 | @Unmodifiable @NotNull List<@NotNull Double> asDoubleList(); 107 | 108 | @Contract("!null -> !null") 109 | @Unmodifiable @Nullable List<@NotNull Float> asFloatList(@Nullable List def); 110 | 111 | @Unmodifiable @NotNull List<@NotNull Float> asFloatList(); 112 | 113 | @Contract("!null -> !null") 114 | @Unmodifiable @Nullable List<@NotNull Boolean> asBooleanList(@Nullable List def); 115 | 116 | @Unmodifiable @NotNull List<@NotNull Boolean> asBooleanList(); 117 | 118 | } 119 | -------------------------------------------------------------------------------- /config/src/test/java/w/config/FileConfigTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.config; 18 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 21 | import org.junit.jupiter.api.AfterEach; 22 | import org.junit.jupiter.api.BeforeEach; 23 | import org.junit.jupiter.api.Test; 24 | 25 | import java.io.File; 26 | 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | 29 | /** 30 | * @author whilein 31 | */ 32 | final class FileConfigTests { 33 | 34 | File file; 35 | 36 | FileConfig object; 37 | 38 | @BeforeEach 39 | void before() { 40 | file = new File("config.yml"); 41 | 42 | object = SimpleFileConfig.create(file, JacksonConfigProvider.create(new ObjectMapper(new YAMLFactory()))); 43 | object.saveDefaults("/config.yml"); 44 | } 45 | 46 | @AfterEach 47 | void after() { 48 | file.delete(); 49 | } 50 | 51 | @Test 52 | void save() { 53 | assertEquals("foo bar", object.getString("text")); 54 | object.set("text", "baz qux"); 55 | assertEquals("baz qux", object.getString("text")); 56 | object.save(); 57 | object.reload(); 58 | assertEquals("baz qux", object.getString("text")); 59 | } 60 | 61 | @Test 62 | void reload() { 63 | assertEquals("foo bar", object.getString("text")); 64 | object.set("text", "baz qux"); 65 | assertEquals("baz qux", object.getString("text")); 66 | object.reload(); 67 | assertEquals("foo bar", object.getString("text")); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /config/src/test/resources/config.yml: -------------------------------------------------------------------------------- 1 | text: 'foo bar' -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mvn --no-transfer-progress --batch-mode -T 1C -Pdeploy -DskipTests=true -Dmaven.test.skip clean deploy -------------------------------------------------------------------------------- /eventbus/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/eventbus 12 | wcommons-eventbus 13 | Blazing fast eventbus 14 | 15 | 16 | 17 | org.slf4j 18 | slf4j-api 19 | 20 | 21 | 22 | org.slf4j 23 | slf4j-simple 24 | test 25 | 26 | 27 | 28 | io.github.whilein.wcommons 29 | wcommons-asm 30 | ${project.version} 31 | 32 | 33 | 34 | io.github.whilein.wcommons 35 | wcommons-util 36 | ${project.version} 37 | 38 | 39 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/AbstractAsyncEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Getter; 21 | import lombok.NoArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import lombok.experimental.NonFinal; 24 | import lombok.val; 25 | import org.jetbrains.annotations.NotNull; 26 | import w.util.mutable.MutableInt; 27 | import w.util.mutable.Mutables; 28 | 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | import java.util.concurrent.CompletableFuture; 32 | 33 | /** 34 | * @author whilein 35 | */ 36 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 37 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 38 | public abstract class AbstractAsyncEvent implements AsyncEvent { 39 | 40 | Map intents = new HashMap<>(); 41 | 42 | @Getter 43 | CompletableFuture doneFuture = new CompletableFuture<>(); 44 | 45 | Object mutex = new Object[0]; 46 | 47 | @NonFinal 48 | volatile boolean fired; 49 | 50 | @NonFinal 51 | volatile int latch; 52 | 53 | @Override 54 | public void postDispatch() { 55 | synchronized (mutex) { 56 | if (latch == 0) { 57 | doneFuture.complete(this); 58 | } 59 | 60 | fired = true; 61 | } 62 | } 63 | 64 | @Override 65 | public void registerIntent(final @NotNull Object namespace) { 66 | synchronized (mutex) { 67 | if (fired) { 68 | throw new IllegalStateException("Event " + this + " has already been fired"); 69 | } 70 | 71 | intents.computeIfAbsent(namespace, __ -> Mutables.newInt()) 72 | .incrementAndGet(); 73 | latch++; 74 | } 75 | } 76 | 77 | @Override 78 | public void completeIntent(final @NotNull Object namespace) { 79 | synchronized (mutex) { 80 | val intentCount = intents.get(namespace); 81 | 82 | if (intentCount == null || intentCount.get() == 0) { 83 | throw new IllegalStateException("Plugin " + namespace + " has not registered intents for event " + this); 84 | } 85 | 86 | intentCount.decrementAndGet(); 87 | 88 | val remaining = --latch; 89 | 90 | if (fired && remaining == 0) { 91 | doneFuture.complete(this); 92 | } 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/AsmDispatchWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | import org.objectweb.asm.MethodVisitor; 21 | import org.objectweb.asm.Type; 22 | 23 | /** 24 | * @author whilein 25 | */ 26 | public interface AsmDispatchWriter { 27 | 28 | /** 29 | * Получить тип объекта, которому принадлежит метод. 30 | * 31 | * @return Тип объекта (asm) 32 | */ 33 | @NotNull Type getOwnerType(); 34 | 35 | /** 36 | * Получить имя метода. 37 | * 38 | * @return Имя метода 39 | */ 40 | @NotNull String getName(); 41 | 42 | /** 43 | * Записать выполнение метод в {@code mv} 44 | * 45 | * @param mv Метод визитор, в который будет записано выполнение метода 46 | */ 47 | void write(@NotNull MethodVisitor mv); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/AsmDispatchWriters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import lombok.experimental.UtilityClass; 24 | import org.jetbrains.annotations.NotNull; 25 | import org.jetbrains.annotations.Nullable; 26 | import org.objectweb.asm.MethodVisitor; 27 | import org.objectweb.asm.Type; 28 | import w.asm.MagicAccessorBridge; 29 | 30 | import java.lang.reflect.Method; 31 | import java.util.function.Consumer; 32 | 33 | import static org.objectweb.asm.Opcodes.*; 34 | import static w.asm.Asm.methodDescriptor; 35 | 36 | /** 37 | * @author whilein 38 | */ 39 | @UtilityClass 40 | public class AsmDispatchWriters { 41 | 42 | /** 43 | * Создать врайтер из консумера. 44 | * 45 | * @param consumer Консумер 46 | * @return Врайтер 47 | */ 48 | public static @NotNull AsmDispatchWriter fromConsumer(final @NotNull Consumer consumer) { 49 | return new ConsumerWriter(consumer); 50 | } 51 | 52 | /** 53 | * Создать врайтер из метода. 54 | * 55 | * @param owner Владелец метода 56 | * @param method Метод 57 | * @return Врайтер 58 | */ 59 | public static @NotNull AsmDispatchWriter fromMethod( 60 | final @Nullable Object owner, 61 | final @NotNull Method method 62 | ) { 63 | return new MethodWriter( 64 | Type.getType(method.getDeclaringClass()), 65 | Type.getInternalName(method.getParameterTypes()[0]), 66 | method.getName(), 67 | Type.getMethodDescriptor(method), 68 | owner == null ? INVOKESTATIC : 69 | MagicAccessorBridge.isMagicAccessorAvailable() 70 | ? INVOKESPECIAL 71 | : INVOKEVIRTUAL 72 | ); 73 | } 74 | 75 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 76 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 77 | private static final class MethodWriter implements AsmDispatchWriter { 78 | 79 | @Getter 80 | Type ownerType; 81 | 82 | String eventType; 83 | 84 | String methodName; 85 | String methodDescriptor; 86 | 87 | int opcode; 88 | 89 | @Override 90 | public @NotNull String getName() { 91 | return ownerType.getClassName() + " " + methodName 92 | + "(" + eventType.replace('/', '.') + ")"; 93 | } 94 | 95 | @Override 96 | public void write(final @NotNull MethodVisitor mv) { 97 | mv.visitVarInsn(ALOAD, 1); 98 | 99 | mv.visitMethodInsn(opcode, ownerType.getInternalName(), methodName, 100 | methodDescriptor, false); 101 | } 102 | } 103 | 104 | 105 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 106 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 107 | private static final class ConsumerWriter implements AsmDispatchWriter { 108 | 109 | private static final Type TYPE = Type.getType(Consumer.class); 110 | 111 | Consumer handle; 112 | 113 | @Override 114 | public @NotNull Type getOwnerType() { 115 | return TYPE; 116 | } 117 | 118 | @Override 119 | public @NotNull String getName() { 120 | return handle.toString(); 121 | } 122 | 123 | @Override 124 | public void write(final @NotNull MethodVisitor mv) { 125 | mv.visitVarInsn(ALOAD, 1); 126 | 127 | mv.visitMethodInsn(INVOKEINTERFACE, TYPE.getInternalName(), "accept", 128 | methodDescriptor(void.class, Object.class), true); 129 | } 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/AsyncEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.concurrent.CompletableFuture; 22 | 23 | /** 24 | * @author whilein 25 | */ 26 | public interface AsyncEvent extends Event { 27 | 28 | @NotNull CompletableFuture<@NotNull AsyncEvent> getDoneFuture(); 29 | 30 | void registerIntent(@NotNull Object namespace); 31 | 32 | void completeIntent(@NotNull Object namespace); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/Cancellable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public interface Cancellable { 23 | 24 | /** 25 | * Получить, отменено ли событие. 26 | * 27 | * @return {@code true}, если событие отменено 28 | */ 29 | boolean isCancelled(); 30 | 31 | /** 32 | * Изменить статус отмены события. 33 | * 34 | * @param cancelled Новое значение отмены события. 35 | */ 36 | void setCancelled(boolean cancelled); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/Event.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public interface Event { 23 | 24 | default void postDispatch() { 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/EventDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public interface EventDispatcher { 25 | 26 | /** 27 | * Отправляет событие на все слушатели, если в одном из них 28 | * произойдёт ошибка, то она будет выведена в логгер и выполнение 29 | * не приостановится. 30 | * 31 | * @param event Событие 32 | */ 33 | void dispatch(@NotNull Event event); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/ImmutableRegisteredEventSubscription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import lombok.*; 20 | import lombok.experimental.FieldDefaults; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.jetbrains.annotations.Nullable; 23 | 24 | import java.util.Set; 25 | 26 | /** 27 | * @author whilein 28 | */ 29 | @Getter 30 | @ToString 31 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 32 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 33 | public final class ImmutableRegisteredEventSubscription implements RegisteredSubscription { 34 | AsmDispatchWriter dispatchWriter; 35 | 36 | Object owner; 37 | 38 | Class ownerType; 39 | 40 | PostOrder postOrder; 41 | 42 | boolean ignoreCancelled; 43 | 44 | Object namespace; 45 | 46 | Set> events; 47 | 48 | /** 49 | * Создать иммутабельную подписку на события {@code events} 50 | * 51 | * @param dispatchWriter Врайтер 52 | * @param owner Владелец 53 | * @param ownerType Класс владельца 54 | * @param postOrder Порядок выполнения 55 | * @param ignoreCancelled Игнорировать отменённые события 56 | * @param namespace Неймспейс 57 | * @param events Типы событий 58 | * @return Новая иммутабельная побписка на события 59 | */ 60 | public static @NotNull RegisteredSubscription create( 61 | final @NotNull AsmDispatchWriter dispatchWriter, 62 | final @Nullable Object owner, 63 | final @NotNull Class ownerType, 64 | final @NotNull PostOrder postOrder, 65 | final boolean ignoreCancelled, 66 | final @NotNull Object namespace, 67 | final @NotNull Set> events 68 | ) { 69 | return new ImmutableRegisteredEventSubscription(dispatchWriter, owner, ownerType, 70 | postOrder, ignoreCancelled, namespace, events); 71 | } 72 | 73 | @Override 74 | public int compareTo(final @NotNull RegisteredSubscription o) { 75 | val compareOrder = postOrder.compareTo(o.getPostOrder()); 76 | 77 | if (compareOrder != 0) { 78 | return compareOrder; 79 | } 80 | 81 | return Boolean.compare(ignoreCancelled, o.isIgnoreCancelled()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/NamespaceValidator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.NoArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | /** 26 | * @author whilein 27 | */ 28 | public interface NamespaceValidator { 29 | 30 | boolean isValid(@NotNull Object object); 31 | 32 | static @NotNull NamespaceValidator permitAll() { 33 | return PermitAll.INSTANCE; 34 | } 35 | 36 | static @NotNull NamespaceValidator permitInstanceOf(final @NotNull Class type) { 37 | return new PermitInstanceOf(type); 38 | } 39 | 40 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 41 | final class PermitAll implements NamespaceValidator { 42 | 43 | private static final NamespaceValidator INSTANCE = new PermitAll(); 44 | 45 | @Override 46 | public boolean isValid(final @NotNull Object object) { 47 | return true; 48 | } 49 | 50 | } 51 | 52 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 53 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 54 | final class PermitInstanceOf implements NamespaceValidator { 55 | Class type; 56 | 57 | @Override 58 | public boolean isValid(final @NotNull Object object) { 59 | return type.isAssignableFrom(object.getClass()); 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/PostOrder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public enum PostOrder { 23 | 24 | /** 25 | * Выполняется раньше всех 26 | */ 27 | LOWEST, 28 | 29 | /** 30 | * Выполняется после {@link #LOWEST} 31 | */ 32 | LOW, 33 | 34 | /** 35 | * Выполняется после {@link #LOW}, используется по умолчанию 36 | */ 37 | NORMAL, 38 | 39 | /** 40 | * Выполняется после {@link #NORMAL} 41 | */ 42 | HIGH, 43 | 44 | /** 45 | * Выполняется позже всех 46 | */ 47 | HIGHEST, 48 | 49 | /** 50 | * Выполняется для отслеживания финальных состояний событий, не рекомендуется 51 | * изменять событие в данном приоритете, поскольку 52 | */ 53 | MONITOR 54 | 55 | } 56 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/RegisteredSubscription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | import org.jetbrains.annotations.Nullable; 21 | import org.jetbrains.annotations.Unmodifiable; 22 | 23 | import java.util.Set; 24 | 25 | /** 26 | * @author whilein 27 | */ 28 | public interface RegisteredSubscription extends Comparable { 29 | 30 | /** 31 | * Получить объект, которому принадлежит обработчик. 32 | * 33 | * @return Объект, если обработчик это статичный метод, то {@code null} 34 | */ 35 | @Nullable Object getOwner(); 36 | 37 | /** 38 | * Получить класс, которому принадлежит обработчик. 39 | * 40 | * @return Класс 41 | */ 42 | @NotNull Class getOwnerType(); 43 | 44 | /** 45 | * Получить порядок выполнения. 46 | * 47 | * @return Порядок выполнения 48 | */ 49 | @NotNull PostOrder getPostOrder(); 50 | 51 | /** 52 | * Получить врайтер байткода. 53 | * 54 | * @return Врайтер байткода. 55 | */ 56 | @NotNull AsmDispatchWriter getDispatchWriter(); 57 | 58 | /** 59 | * Получить неймспейс. 60 | * 61 | * @return Неймспейс 62 | */ 63 | @NotNull Object getNamespace(); 64 | 65 | /** 66 | * Получить статус игнорирования отменённых событий. 67 | * 68 | * @return Статус игнорирования отменённых событий 69 | */ 70 | boolean isIgnoreCancelled(); 71 | 72 | /** 73 | * Получить типы событий, на которые действует данная подписка. 74 | * 75 | * @return Типы событий 76 | */ 77 | @Unmodifiable @NotNull Set<@NotNull Class> getEvents(); 78 | 79 | } 80 | -------------------------------------------------------------------------------- /eventbus/src/main/java/w/eventbus/Subscribe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.eventbus; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.lang.annotation.Target; 25 | 26 | /** 27 | * @author whilein 28 | */ 29 | @Target(ElementType.METHOD) 30 | @Retention(RetentionPolicy.RUNTIME) 31 | public @interface Subscribe { 32 | 33 | /** 34 | * Получить порядок выполнения. 35 | * 36 | * @return Порядок выполнения 37 | */ 38 | @NotNull PostOrder order() default PostOrder.NORMAL; 39 | 40 | /** 41 | * Получить статус игнорирования отменённых событий. 42 | * 43 | * @return Статус игнорирования отменённых событий 44 | */ 45 | boolean ignoreCancelled() default false; 46 | 47 | /** 48 | * Здесь можно указать типы событий, которые нужно слушать дополнительно. 49 | *

50 | * Допустим метод принимает {@link Event}, здесь можно указать например {@link AsyncEvent} и тогда 51 | * {@link AsyncEvent} и {@link Event} будут отправляться в этот метод. 52 | * 53 | * @return Типы событий 54 | */ 55 | @NotNull Class[] types() default {}; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /eventbus/src/test/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=debug -------------------------------------------------------------------------------- /geo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/geo 12 | wcommons-geo 13 | Geolocation lookup 14 | 15 | 16 | 17 | com.fasterxml.jackson.core 18 | jackson-databind 19 | 20 | 21 | 22 | org.kamranzafar 23 | jtar 24 | 25 | 26 | 27 | com.google.guava 28 | guava 29 | provided 30 | 31 | 32 | 33 | com.github.ben-manes.caffeine 34 | caffeine 35 | provided 36 | 37 | 38 | 39 | com.maxmind.geoip2 40 | geoip2 41 | 42 | 43 | 44 | com.fasterxml.jackson.core 45 | jackson-databind 46 | 47 | 48 | com.fasterxml.jackson.core 49 | jackson-core 50 | 51 | 52 | com.fasterxml.jackson.core 53 | jackson-annotations 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/GeoLocationLookupException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public final class GeoLocationLookupException extends RuntimeException { 23 | 24 | public GeoLocationLookupException(String message) { 25 | super(message); 26 | } 27 | 28 | public GeoLocationLookupException(String message, Throwable cause) { 29 | super(message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/GeoLocationManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | import w.geo.model.GeoLocation; 21 | 22 | import java.net.InetAddress; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public interface GeoLocationManager { 28 | 29 | @NotNull GeoLocationManager NOOP = address -> GeoLocation.unknown(); 30 | 31 | @NotNull GeoLocation lookup(@NotNull InetAddress address) throws GeoLocationLookupException; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/cache/caffeine/CachedGeoLocationManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo.cache.caffeine; 18 | 19 | import com.github.benmanes.caffeine.cache.Caffeine; 20 | import com.github.benmanes.caffeine.cache.LoadingCache; 21 | import lombok.AccessLevel; 22 | import lombok.RequiredArgsConstructor; 23 | import lombok.experimental.FieldDefaults; 24 | import lombok.val; 25 | import org.jetbrains.annotations.NotNull; 26 | import w.geo.GeoLocationManager; 27 | import w.geo.model.GeoLocation; 28 | 29 | import java.net.InetAddress; 30 | import java.util.concurrent.TimeUnit; 31 | import java.util.function.Consumer; 32 | 33 | /** 34 | * @author whilein 35 | */ 36 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 37 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 38 | public final class CachedGeoLocationManager implements GeoLocationManager { 39 | 40 | LoadingCache cache; 41 | 42 | public static @NotNull GeoLocationManager create( 43 | @NotNull GeoLocationManager delegate 44 | ) { 45 | return new CachedGeoLocationManager( 46 | Caffeine.newBuilder() 47 | .softValues() 48 | .expireAfterAccess(24, TimeUnit.HOURS) 49 | .build(delegate::lookup) 50 | ); 51 | } 52 | 53 | public static @NotNull GeoLocationManager create( 54 | @NotNull GeoLocationManager delegate, 55 | @NotNull Consumer<@NotNull Caffeine> builderInitializer 56 | ) { 57 | val builder = Caffeine.newBuilder(); 58 | builderInitializer.accept(builder); 59 | 60 | return new CachedGeoLocationManager(builder.build(delegate::lookup)); 61 | } 62 | 63 | @Override 64 | public @NotNull GeoLocation lookup(final @NotNull InetAddress address) { 65 | return cache.get(address); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/cache/guava/CachedGeoLocationManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo.cache.guava; 18 | 19 | import com.google.common.cache.CacheBuilder; 20 | import com.google.common.cache.CacheLoader; 21 | import com.google.common.cache.LoadingCache; 22 | import lombok.AccessLevel; 23 | import lombok.RequiredArgsConstructor; 24 | import lombok.SneakyThrows; 25 | import lombok.experimental.FieldDefaults; 26 | import lombok.val; 27 | import org.jetbrains.annotations.NotNull; 28 | import w.geo.GeoLocationManager; 29 | import w.geo.model.GeoLocation; 30 | 31 | import java.net.InetAddress; 32 | import java.util.concurrent.TimeUnit; 33 | import java.util.function.Consumer; 34 | 35 | /** 36 | * @author whilein 37 | */ 38 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 39 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 40 | public final class CachedGeoLocationManager implements GeoLocationManager { 41 | 42 | LoadingCache cache; 43 | 44 | public static @NotNull GeoLocationManager create( 45 | @NotNull GeoLocationManager delegate 46 | ) { 47 | return new CachedGeoLocationManager( 48 | CacheBuilder.newBuilder() 49 | .softValues() 50 | .expireAfterAccess(24, TimeUnit.HOURS) 51 | .build(new CacheLoaderImpl(delegate)) 52 | ); 53 | } 54 | 55 | public static @NotNull GeoLocationManager create( 56 | @NotNull GeoLocationManager delegate, 57 | @NotNull Consumer<@NotNull CacheBuilder> builderInitializer 58 | ) { 59 | val builder = CacheBuilder.newBuilder(); 60 | builderInitializer.accept(builder); 61 | 62 | return new CachedGeoLocationManager(builder.build(new CacheLoaderImpl(delegate))); 63 | } 64 | 65 | @Override 66 | @SneakyThrows 67 | public @NotNull GeoLocation lookup(final @NotNull InetAddress address) { 68 | return cache.get(address); 69 | } 70 | 71 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 72 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 73 | private static final class CacheLoaderImpl extends CacheLoader { 74 | GeoLocationManager delegate; 75 | 76 | @Override 77 | public @NotNull GeoLocation load(final @NotNull InetAddress key) { 78 | return delegate.lookup(key); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/maxmind/DatabaseProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo.maxmind; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public interface DatabaseProvider { 28 | 29 | @NotNull InputStream openStream() throws IOException; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/maxmind/MaxmindGeoLocationManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo.maxmind; 18 | 19 | import com.maxmind.db.NoCache; 20 | import com.maxmind.geoip2.DatabaseReader; 21 | import com.maxmind.geoip2.exception.GeoIp2Exception; 22 | import com.maxmind.geoip2.model.CityResponse; 23 | import com.maxmind.geoip2.record.AbstractNamedRecord; 24 | import lombok.AccessLevel; 25 | import lombok.RequiredArgsConstructor; 26 | import lombok.experimental.FieldDefaults; 27 | import lombok.val; 28 | import org.jetbrains.annotations.NotNull; 29 | import w.geo.GeoLocationLookupException; 30 | import w.geo.GeoLocationManager; 31 | import w.geo.model.Country; 32 | import w.geo.model.GeoLocation; 33 | 34 | import java.io.IOException; 35 | import java.net.InetAddress; 36 | import java.util.Collections; 37 | 38 | /** 39 | * @author whilein 40 | */ 41 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 42 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 43 | public final class MaxmindGeoLocationManager implements GeoLocationManager { 44 | 45 | private static final String DEFAULT_LOCALE = "en"; 46 | 47 | String locale; 48 | DatabaseReader reader; 49 | 50 | public static @NotNull GeoLocationManager create(@NotNull DatabaseProvider provider) 51 | throws IOException { 52 | return create(DEFAULT_LOCALE, provider); 53 | } 54 | 55 | public static @NotNull GeoLocationManager create(@NotNull String locale, @NotNull DatabaseProvider provider) 56 | throws IOException { 57 | DatabaseReader reader; 58 | 59 | try (val is = provider.openStream()) { 60 | reader = new DatabaseReader.Builder(is) 61 | .locales(Collections.singletonList(locale)) 62 | .withCache(NoCache.getInstance()) 63 | .build(); 64 | } 65 | 66 | return new MaxmindGeoLocationManager(locale, reader); 67 | } 68 | 69 | private static String resolveNamed(AbstractNamedRecord record, String locale) { 70 | val names = record.getNames(); 71 | if (names.isEmpty()) return null; 72 | 73 | String name = names.get(locale); 74 | if (name == null && !locale.equals(DEFAULT_LOCALE)) { 75 | name = names.get(DEFAULT_LOCALE); 76 | } 77 | 78 | return name; 79 | } 80 | 81 | private GeoLocation mapResponse(CityResponse response) { 82 | val mmCountry = response.getCountry(); 83 | val mmCity = response.getCity(); 84 | 85 | val countryName = resolveNamed(mmCountry, locale); 86 | val country = countryName == null ? null : new Country(countryName, mmCountry.getIsoCode()); 87 | 88 | val city = resolveNamed(mmCity, locale); 89 | 90 | return new GeoLocation(city, country); 91 | } 92 | 93 | @Override 94 | public @NotNull GeoLocation lookup(@NotNull InetAddress address) throws GeoLocationLookupException { 95 | try { 96 | return reader.tryCity(address) 97 | .map(this::mapResponse) 98 | .orElse(GeoLocation.unknown()); 99 | } catch (IOException | GeoIp2Exception e) { 100 | throw new GeoLocationLookupException("Failed lookup: " + address, e); 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/model/Country.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo.model; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public record Country(@NotNull String name, @NotNull String isoCode) { 25 | } 26 | -------------------------------------------------------------------------------- /geo/src/main/java/w/geo/model/GeoLocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.geo.model; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | /** 23 | * @author whilein 24 | */ 25 | public record GeoLocation(@Nullable String city, @Nullable Country country) { 26 | 27 | private static final GeoLocation UNKNOWN = new GeoLocation(null, null); 28 | 29 | public static @NotNull GeoLocation unknown() { 30 | return UNKNOWN; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /settings.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | ossrh 6 | ${env.OSSRH_USERNAME} 7 | ${env.OSSRH_PASSWORD} 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /unsafe/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.github.whilein.wcommons 9 | wcommons-parent 10 | ${revision} 11 | 12 | 13 | wcommons/unsafe 14 | wcommons-unsafe 15 | Unsafe operations in JVM 16 | 17 | 18 | 19 | io.github.whilein.wcommons 20 | wcommons-agent 21 | ${project.version} 22 | provided 23 | 24 | 25 | -------------------------------------------------------------------------------- /unsafe/src/test/java/UnsafeTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import lombok.RequiredArgsConstructor; 18 | import lombok.SneakyThrows; 19 | import lombok.val; 20 | import org.junit.jupiter.api.BeforeEach; 21 | import org.junit.jupiter.api.Test; 22 | import w.unsafe.Unsafe; 23 | 24 | import java.lang.invoke.VarHandle; 25 | 26 | import static org.junit.jupiter.api.Assertions.*; 27 | import static org.junit.jupiter.api.Assumptions.assumeTrue; 28 | 29 | /** 30 | * @author whilein 31 | */ 32 | class UnsafeTests { 33 | 34 | Unsafe unsafe; 35 | 36 | @BeforeEach 37 | void setup() { 38 | unsafe = Unsafe.getUnsafe(); 39 | 40 | assertTrue(unsafe.isAvailable()); 41 | } 42 | 43 | @Test 44 | @SneakyThrows 45 | void putStaticField() { 46 | assertEquals("Old Value", Dummy.STATIC_VALUE); 47 | 48 | unsafe.putStaticField(Dummy.class.getDeclaredField("STATIC_VALUE"), "New Value"); 49 | 50 | assertEquals("New Value", Dummy.STATIC_VALUE); 51 | } 52 | 53 | @Test 54 | @SneakyThrows 55 | void allocateInstance() { 56 | val lookup = unsafe.trustedLookup(); 57 | val vh = lookup.findVarHandle(Dummy.class, "objectValue", String.class); 58 | 59 | val dummy = (Dummy) unsafe.allocateInstance(Dummy.class); 60 | assertNull(dummy.objectValue); 61 | vh.set(dummy, "321"); 62 | assertEquals("321", dummy.objectValue); 63 | } 64 | 65 | @Test 66 | @SneakyThrows 67 | void putField() { 68 | val dummy = new Dummy("Old Value"); 69 | 70 | assertEquals("Old Value", dummy.objectValue); 71 | 72 | unsafe.putField(Dummy.class.getDeclaredField("objectValue"), dummy, "New Value"); 73 | 74 | assertEquals("New Value", dummy.objectValue); 75 | } 76 | 77 | @RequiredArgsConstructor 78 | private static final class Dummy { 79 | private static final Object STATIC_VALUE; 80 | 81 | private final String objectValue; 82 | 83 | static { 84 | STATIC_VALUE = "Old Value"; 85 | } 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /util/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.github.whilein.wcommons 7 | wcommons-parent 8 | ${revision} 9 | 10 | 11 | wcommons/util 12 | wcommons-util 13 | Some useful tools for Java core like pair, lazy and etc 14 | 15 | 16 | 17 | io.github.whilein.wcommons 18 | wcommons-unsafe 19 | ${project.version} 20 | 21 | 22 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/ByteAllocator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.NoArgsConstructor; 21 | import org.jetbrains.annotations.NotNull; 22 | import w.unsafe.Unsafe; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public interface ByteAllocator { 28 | 29 | @NotNull ByteAllocator INSTANCE = Unsafe.isUnsafeAvailable() 30 | ? new UnsafeByteAllocator() 31 | : new SafeByteAllocator(); 32 | 33 | byte @NotNull [] allocate(int length); 34 | 35 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 36 | final class SafeByteAllocator implements ByteAllocator { 37 | 38 | @Override 39 | public byte @NotNull [] allocate(final int length) { 40 | return new byte[length]; 41 | } 42 | 43 | } 44 | 45 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 46 | final class UnsafeByteAllocator implements ByteAllocator { 47 | 48 | @Override 49 | public byte @NotNull [] allocate(final int length) { 50 | return (byte[]) Unsafe.getUnsafe().allocateUninitializedArray(byte.class, length); 51 | } 52 | 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/ByteSlice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | import java.math.BigInteger; 26 | import java.util.Arrays; 27 | 28 | /** 29 | * @author whilein 30 | */ 31 | public interface ByteSlice { 32 | 33 | static @NotNull ByteSlice wrap(final byte[] array) { 34 | return new Default(array, 0, array.length); 35 | } 36 | 37 | static @NotNull ByteSlice wrap(final byte[] array, final int off, final int len) { 38 | return new Default(array, off, len); 39 | } 40 | 41 | int getOffset(); 42 | 43 | int getLength(); 44 | 45 | byte get(int position); 46 | 47 | @NotNull ByteSlice slice(int off, int len); 48 | 49 | byte @NotNull [] getSlice(); 50 | 51 | byte @NotNull [] getArray(); 52 | 53 | @NotNull String toString(); 54 | 55 | @NotNull BigInteger toBigInt(); 56 | 57 | @Getter 58 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 59 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 60 | final class Default implements ByteSlice { 61 | 62 | byte[] array; 63 | int offset; 64 | int length; 65 | 66 | @Override 67 | public byte get(final int position) { 68 | return array[position + offset]; 69 | } 70 | 71 | @Override 72 | public @NotNull ByteSlice slice(final int off, final int len) { 73 | return new Default(array, offset + off, len); 74 | } 75 | 76 | @Override 77 | public byte @NotNull [] getSlice() { 78 | return Arrays.copyOfRange(array, offset, offset + length); 79 | } 80 | 81 | @Override 82 | public @NotNull String toString() { 83 | return new String(array, offset, length); 84 | } 85 | 86 | @Override 87 | public @NotNull BigInteger toBigInt() { 88 | return new BigInteger(1, array, offset, length); 89 | } 90 | 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/ByteUnit.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.experimental.FieldDefaults; 21 | 22 | /** 23 | * @author whilein 24 | */ 25 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 26 | public enum ByteUnit { 27 | 28 | UNO(1L), 29 | KIBI(1024L), 30 | MEBI(1024L * 1024L), 31 | GIBI(1024L * 1024L * 1024L), 32 | TEBI(1024L * 1024L * 1024L * 1024L); 33 | //PEBI, EXBI, ZEBI, YOBI; 34 | 35 | long scale; 36 | 37 | ByteUnit(final long scale) { 38 | this.scale = scale; 39 | } 40 | 41 | public double toUno(final double bytes) { 42 | return bytes * scale; 43 | } 44 | 45 | public double toKibi(final double bytes) { 46 | return convert(bytes, KIBI); 47 | } 48 | 49 | public double toMebi(final double bytes) { 50 | return convert(bytes, MEBI); 51 | } 52 | 53 | public double toGibi(final double bytes) { 54 | return convert(bytes, GIBI); 55 | } 56 | 57 | public double toTebi(final double bytes) { 58 | return convert(bytes, TEBI); 59 | } 60 | 61 | public long toUno(final long bytes) { 62 | return bytes * scale; 63 | } 64 | 65 | public long toKibi(final long bytes) { 66 | return convert(bytes, KIBI); 67 | } 68 | 69 | public long toMebi(final long bytes) { 70 | return convert(bytes, MEBI); 71 | } 72 | 73 | public long toGibi(final long bytes) { 74 | return convert(bytes, GIBI); 75 | } 76 | 77 | public long toTebi(final long bytes) { 78 | return convert(bytes, TEBI); 79 | } 80 | 81 | public double convert(final double bytes, final ByteUnit to) { 82 | return to == this ? bytes : (bytes * scale) / to.scale; 83 | } 84 | 85 | public long convert(final long bytes, final ByteUnit to) { 86 | return to == this ? bytes : (bytes * scale) / to.scale; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/Env.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.NonNull; 20 | import lombok.experimental.UtilityClass; 21 | import lombok.val; 22 | import org.jetbrains.annotations.Contract; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.jetbrains.annotations.Nullable; 25 | import org.jetbrains.annotations.Unmodifiable; 26 | 27 | import java.util.Arrays; 28 | import java.util.Collections; 29 | import java.util.List; 30 | import java.util.Optional; 31 | 32 | /** 33 | * @author whilein 34 | */ 35 | @UtilityClass 36 | public class Env { 37 | 38 | public @NotNull String getString(final @NonNull String key) { 39 | return findString(key).orElseThrow(() -> new IllegalStateException("Cannot find environment entry: " + key)); 40 | } 41 | 42 | @Contract("_, !null -> !null") 43 | public @Nullable String getString(final @NonNull String key, final @Nullable String defaultValue) { 44 | return findString(key).orElse(defaultValue); 45 | } 46 | 47 | public @NotNull Optional<@NotNull String> findString(final @NonNull String key) { 48 | return Optional.ofNullable(System.getenv(key)); 49 | } 50 | 51 | public int getInt(final @NonNull String key, final int defaultValue) { 52 | val value = System.getenv(key); 53 | 54 | if (value == null) { 55 | return defaultValue; 56 | } 57 | 58 | try { 59 | return Integer.parseInt(value); 60 | } catch (final Exception e) { 61 | return defaultValue; 62 | } 63 | } 64 | 65 | public @Unmodifiable @NotNull List<@NotNull String> getStringList( 66 | final @NonNull String key, 67 | final @NonNull String delimiter 68 | ) { 69 | return getStringList(key, delimiter, Collections.emptyList()); 70 | } 71 | 72 | @Contract("_, _, !null -> !null") 73 | public @Unmodifiable @Nullable List getStringList( 74 | final @NonNull String key, 75 | final @NonNull String delimiter, 76 | final @Nullable List defaultValue 77 | ) { 78 | val value = System.getenv(key); 79 | 80 | if (value == null) { 81 | return defaultValue; 82 | } 83 | 84 | return List.of(value.split(delimiter)); 85 | } 86 | 87 | public @Unmodifiable @NotNull List<@NotNull Integer> getIntList( 88 | final @NonNull String key, 89 | final @NonNull String delimiter 90 | ) { 91 | return getIntList(key, delimiter, Collections.emptyList()); 92 | } 93 | 94 | @Contract("_, _, !null -> !null") 95 | public @Unmodifiable @Nullable List<@NotNull Integer> getIntList( 96 | final @NonNull String key, 97 | final @NonNull String delimiter, 98 | final @Nullable List defaultValue 99 | ) { 100 | val value = System.getenv(key); 101 | 102 | if (value == null) { 103 | return defaultValue; 104 | } 105 | 106 | return Arrays.stream(value.split(delimiter)) 107 | .map(Integer::valueOf) 108 | .toList(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/Iterables.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.NonNull; 20 | import lombok.experimental.UtilityClass; 21 | import lombok.val; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | import java.util.Optional; 26 | 27 | /** 28 | * @author whilein 29 | */ 30 | @UtilityClass 31 | public class Iterables { 32 | 33 | public @NotNull Optional<@NotNull T> getFirst(final @NonNull Iterable<@Nullable T> iterable) { 34 | val iterator = iterable.iterator(); 35 | 36 | return iterator.hasNext() 37 | ? Optional.ofNullable(iterator.next()) 38 | : Optional.empty(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/Iterators.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.AllArgsConstructor; 21 | import lombok.experimental.FieldDefaults; 22 | import lombok.experimental.NonFinal; 23 | import lombok.experimental.UtilityClass; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | import java.util.ListIterator; 27 | 28 | /** 29 | * @author whilein 30 | */ 31 | @UtilityClass 32 | public class Iterators { 33 | 34 | public @NotNull ListIterator forArray(final E @NotNull [] array) { 35 | return forArray(array, 0, array.length); 36 | } 37 | 38 | public @NotNull ListIterator forArray(final E @NotNull [] array, final int offset, final int length) { 39 | return new OverArray<>(array, offset, length, offset); 40 | } 41 | 42 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 43 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 44 | private static final class OverArray implements ListIterator { 45 | 46 | E[] array; 47 | 48 | int off; 49 | 50 | int len; 51 | 52 | @NonFinal 53 | int index; 54 | 55 | @Override 56 | public boolean hasNext() { 57 | return index - off != len; 58 | } 59 | 60 | @Override 61 | public E next() { 62 | return array[index++]; 63 | } 64 | 65 | @Override 66 | public boolean hasPrevious() { 67 | return index != off; 68 | } 69 | 70 | @Override 71 | public E previous() { 72 | return array[--index]; 73 | } 74 | 75 | @Override 76 | public int nextIndex() { 77 | return index - off == len ? len : index + 1; 78 | } 79 | 80 | @Override 81 | public int previousIndex() { 82 | return index == off ? -1 : index - 1; 83 | } 84 | 85 | @Override 86 | public void remove() { 87 | throw new UnsupportedOperationException(); 88 | } 89 | 90 | @Override 91 | public void set(final E e) { 92 | this.array[index] = e; 93 | } 94 | 95 | @Override 96 | public void add(final E e) { 97 | throw new UnsupportedOperationException(); 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/ObjectCloner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.NoArgsConstructor; 21 | import lombok.SneakyThrows; 22 | import lombok.val; 23 | import org.jetbrains.annotations.NotNull; 24 | import w.unsafe.Unsafe; 25 | 26 | import java.lang.invoke.MethodHandle; 27 | import java.lang.invoke.MethodType; 28 | 29 | /** 30 | * @author whilein 31 | */ 32 | public interface ObjectCloner { 33 | 34 | @NotNull ObjectCloner INSTANCE = Unsafe.isUnsafeAvailable() 35 | ? new UnsafeObjectCloner() 36 | : new SafeObjectCloner(); 37 | 38 | @NotNull Object clone(@NotNull Object object); 39 | 40 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 41 | final class SafeObjectCloner implements ObjectCloner { 42 | 43 | @Override 44 | @SneakyThrows 45 | public @NotNull Object clone(final @NotNull Object object) { 46 | val method = object.getClass().getDeclaredMethod("clone"); 47 | return method.invoke(object); 48 | } 49 | } 50 | 51 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 52 | final class UnsafeObjectCloner implements ObjectCloner { 53 | private static final MethodHandle CLONE; 54 | 55 | static { 56 | try { 57 | val lookup = Unsafe.getUnsafe().trustedLookupIn(Object.class); 58 | 59 | CLONE = lookup.findVirtual(Object.class, "clone", MethodType.methodType(Object.class)); 60 | } catch (final Exception e) { 61 | throw new RuntimeException(e); 62 | } 63 | } 64 | 65 | @Override 66 | @SneakyThrows 67 | public @NotNull Object clone(final @NotNull Object object) { 68 | return CLONE.invokeExact(object); 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/ObjectUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.experimental.UtilityClass; 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | /** 23 | * @author whilein 24 | */ 25 | @UtilityClass 26 | public class ObjectUtils { 27 | 28 | private final Object EMPTY = new Object[0]; 29 | 30 | 31 | @SuppressWarnings("unchecked") 32 | public @NotNull T empty() { 33 | return (T) EMPTY; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/TypeUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.experimental.UtilityClass; 20 | import lombok.val; 21 | import org.jetbrains.annotations.NotNull; 22 | import org.jetbrains.annotations.Unmodifiable; 23 | 24 | import java.util.Collections; 25 | import java.util.LinkedHashSet; 26 | import java.util.Optional; 27 | import java.util.Set; 28 | 29 | /** 30 | * @author whilein 31 | */ 32 | @UtilityClass 33 | public class TypeUtils { 34 | 35 | private final Class[] WRAPPERS = new Class[]{ 36 | Boolean.class, Character.class, Byte.class, Short.class, 37 | Integer.class, Long.class, Float.class, Double.class 38 | }; 39 | 40 | private final Class[] PRIMITIVES = new Class[]{ 41 | boolean.class, char.class, byte.class, short.class, 42 | int.class, long.class, float.class, double.class 43 | }; 44 | 45 | public @NotNull Optional<@NotNull Class> getPrimitive(final @NotNull Class wrapperType) { 46 | for (int i = 0, j = WRAPPERS.length; i < j; i++) { 47 | if (WRAPPERS[i] == wrapperType) { 48 | return Optional.of(PRIMITIVES[i]); 49 | } 50 | } 51 | 52 | return Optional.empty(); 53 | } 54 | 55 | public @NotNull Optional<@NotNull Class> getWrapper(final @NotNull Class primitiveType) { 56 | for (int i = 0, j = PRIMITIVES.length; i < j; i++) { 57 | if (PRIMITIVES[i] == primitiveType) { 58 | return Optional.of(WRAPPERS[i]); 59 | } 60 | } 61 | 62 | return Optional.empty(); 63 | } 64 | 65 | public @Unmodifiable @NotNull Set<@NotNull Class> findTypes(final @NotNull Class type) { 66 | if (type == Object.class || type.isPrimitive()) { 67 | return Set.of(type); 68 | } 69 | 70 | val result = new LinkedHashSet>(); 71 | result.add(type); 72 | 73 | findTypes(type, result); 74 | 75 | return Collections.unmodifiableSet(result); 76 | } 77 | 78 | private void findTypes(final Class type, final Set> result) { 79 | result.add(type); 80 | 81 | if (!type.isInterface()) { 82 | val superType = type.getSuperclass(); 83 | 84 | if (superType != Object.class) { 85 | findTypes(superType, result); 86 | } 87 | } 88 | 89 | for (val interfaceType : type.getInterfaces()) { 90 | findTypes(interfaceType, result); 91 | } 92 | } 93 | 94 | public boolean isWrapper(final @NotNull Class wrapperType) { 95 | for (val wrapper : WRAPPERS) { 96 | if (wrapper == wrapperType) { 97 | return true; 98 | } 99 | } 100 | 101 | return false; 102 | } 103 | 104 | public boolean isPrimitive(final @NotNull Class primitiveType) { 105 | for (val primitive : PRIMITIVES) { 106 | if (primitive == primitiveType) { 107 | return true; 108 | } 109 | } 110 | 111 | return false; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/buffering/Buffered.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.buffering; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public interface Buffered extends AutoCloseable { 23 | 24 | T get(); 25 | 26 | void release(); 27 | 28 | default void close() { 29 | release(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/buffering/Buffering.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.buffering; 18 | 19 | import lombok.AllArgsConstructor; 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import lombok.experimental.NonFinal; 24 | import lombok.experimental.UtilityClass; 25 | import lombok.val; 26 | import org.jetbrains.annotations.NotNull; 27 | import w.util.io.ByteOutput; 28 | import w.util.io.UncappedByteOutput; 29 | 30 | import java.util.function.Consumer; 31 | import java.util.function.Supplier; 32 | 33 | /** 34 | * @author whilein 35 | */ 36 | @UtilityClass 37 | public class Buffering { 38 | 39 | private final ThreadLocal BUFFERS = ThreadLocal.withInitial(Buffers::init); 40 | 41 | public @NotNull Buffered<@NotNull StringBuilder> getStringBuilder() { 42 | return BUFFERS.get().getStringBuilderBuffer().pop(); 43 | } 44 | 45 | public @NotNull Buffered<@NotNull ByteOutput> getBytes() { 46 | return BUFFERS.get().getBytesBuffer().pop(); 47 | } 48 | 49 | @FieldDefaults(makeFinal = true) 50 | @AllArgsConstructor 51 | private static final class Node { 52 | 53 | T value; 54 | 55 | @NonFinal 56 | Node next; 57 | 58 | } 59 | 60 | @FieldDefaults(makeFinal = true) 61 | @AllArgsConstructor 62 | private static final class BufferedImpl implements Buffered { 63 | 64 | Buffering.Buffer buffer; 65 | 66 | @NonFinal 67 | T value; 68 | 69 | @Override 70 | public T get() { 71 | return value; 72 | } 73 | 74 | @Override 75 | public void release() { 76 | buffer.push(value); 77 | value = null; 78 | } 79 | } 80 | 81 | @FieldDefaults(makeFinal = true) 82 | @RequiredArgsConstructor 83 | private static final class Buffer { 84 | 85 | @NonFinal 86 | Node root; 87 | 88 | Supplier factory; 89 | Consumer release; 90 | 91 | public void push(final T value) { 92 | release.accept(value); 93 | 94 | root = new Node<>(value, root); 95 | } 96 | 97 | public Buffered pop() { 98 | final T result; 99 | 100 | if (root != null) { 101 | val value = root.value; 102 | root = root.next; 103 | result = value; 104 | } else { 105 | result = factory.get(); 106 | } 107 | 108 | return new BufferedImpl<>(this, result); 109 | } 110 | 111 | } 112 | 113 | @Getter 114 | @FieldDefaults(makeFinal = true) 115 | @RequiredArgsConstructor 116 | private static final class Buffers { 117 | 118 | Buffering.Buffer stringBuilderBuffer; 119 | Buffering.Buffer bytesBuffer; 120 | 121 | public static Buffers init() { 122 | return new Buffers( 123 | new Buffering.Buffer<>(StringBuilder::new, builder -> builder.setLength(0)), 124 | new Buffering.Buffer<>(UncappedByteOutput::create, bytes -> bytes.setLength(0))); 125 | } 126 | 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/ci/CiString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.ci; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * Не чувствительная к регистру строка 23 | * 24 | * @author whilein 25 | */ 26 | public interface CiString { 27 | 28 | int length(); 29 | 30 | boolean equals(byte coder, byte[] value); 31 | 32 | boolean equals(Object object); 33 | 34 | boolean equals(CiString another); 35 | 36 | boolean equals(String another); 37 | 38 | /** 39 | * Получить {@code hashCode} строки в нижнем регистре, согласно спецификации {@link String} 40 | * 41 | * @return {@code hashCode} строки в нижнем регистре 42 | */ 43 | int hashCode(); 44 | 45 | /** 46 | * Получить оригинальную строку (с изначальным регистром) 47 | * 48 | * @return Оригинальная строка 49 | */ 50 | @NotNull String toString(); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/concurrent/ThreadFactories.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.concurrent; 18 | 19 | import lombok.RequiredArgsConstructor; 20 | import lombok.experimental.FieldDefaults; 21 | import lombok.experimental.UtilityClass; 22 | import lombok.val; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | import java.util.concurrent.ThreadFactory; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | 28 | /** 29 | * @author whilein 30 | */ 31 | @UtilityClass 32 | public class ThreadFactories { 33 | 34 | public static @NotNull ThreadFactory named(final @NotNull String format) { 35 | return new Named(new AtomicInteger(), format, Thread::new); 36 | } 37 | 38 | public static @NotNull ThreadFactory named(final @NotNull String format, final @NotNull ThreadFactory parent) { 39 | return new Named(new AtomicInteger(), format, parent); 40 | } 41 | 42 | @FieldDefaults(makeFinal = true) 43 | @RequiredArgsConstructor 44 | private static final class Named implements ThreadFactory { 45 | AtomicInteger counter; 46 | String format; 47 | ThreadFactory factory; 48 | 49 | @Override 50 | public Thread newThread(final @NotNull Runnable r) { 51 | val thread = factory.newThread(r); 52 | thread.setName(String.format(format, counter.getAndIncrement())); 53 | 54 | return thread; 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/function/ComponentConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.function; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.AllArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import lombok.val; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | import java.util.concurrent.atomic.AtomicReference; 27 | import java.util.function.Consumer; 28 | 29 | /** 30 | * @author whilein 31 | */ 32 | public interface ComponentConsumer extends Consumer { 33 | 34 | void add(@NotNull Consumer consumer); 35 | 36 | @FieldDefaults(level = AccessLevel.PRIVATE) 37 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 38 | final class Simple implements ComponentConsumer { 39 | 40 | Consumer consumer; 41 | 42 | public static @NotNull ComponentConsumer create() { 43 | return new Simple<>(null); 44 | } 45 | 46 | public static @NotNull ComponentConsumer create(final @NotNull Consumer initial) { 47 | return new Simple<>(initial); 48 | } 49 | 50 | @Override 51 | public void add(final @NotNull Consumer consumer) { 52 | val oldConsumer = this.consumer; 53 | 54 | this.consumer = oldConsumer == null ? consumer : oldConsumer.andThen(consumer); 55 | } 56 | 57 | @Override 58 | public void accept(final T t) { 59 | if (consumer != null) { 60 | consumer.accept(t); 61 | } 62 | } 63 | } 64 | 65 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 66 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 67 | final class Atomic implements ComponentConsumer { 68 | 69 | AtomicReference> consumer; 70 | 71 | public static @NotNull ComponentConsumer create() { 72 | return new Atomic<>(new AtomicReference<>()); 73 | } 74 | 75 | public static @NotNull ComponentConsumer create(final @NotNull Consumer initial) { 76 | return new Atomic<>(new AtomicReference<>(initial)); 77 | } 78 | 79 | @Override 80 | public void add(final @NotNull Consumer consumer) { 81 | this.consumer.getAndUpdate(oldConsumer -> oldConsumer == null ? consumer : oldConsumer.andThen(consumer)); 82 | } 83 | 84 | @Override 85 | public void accept(final T t) { 86 | val consumer = this.consumer.get(); 87 | 88 | if (consumer != null) { 89 | consumer.accept(t); 90 | } 91 | } 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/function/ComponentPredicate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.function; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.AllArgsConstructor; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.experimental.FieldDefaults; 23 | import lombok.val; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | import java.util.concurrent.atomic.AtomicReference; 27 | import java.util.function.Predicate; 28 | 29 | /** 30 | * @author whilein 31 | */ 32 | public interface ComponentPredicate extends Predicate { 33 | 34 | void addAnd(@NotNull Predicate predicate); 35 | 36 | void addOr(@NotNull Predicate predicate); 37 | 38 | @FieldDefaults(level = AccessLevel.PRIVATE) 39 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 40 | final class Simple implements ComponentPredicate { 41 | 42 | Predicate predicate; 43 | 44 | public static @NotNull ComponentPredicate create() { 45 | return new Simple<>(null); 46 | } 47 | 48 | public static @NotNull ComponentPredicate create(final @NotNull Predicate initial) { 49 | return new Simple<>(initial); 50 | } 51 | 52 | @Override 53 | public void addAnd(final @NotNull Predicate predicate) { 54 | val oldPredicate = this.predicate; 55 | this.predicate = oldPredicate == null ? predicate : oldPredicate.and(this.predicate); 56 | } 57 | 58 | @Override 59 | public void addOr(final @NotNull Predicate predicate) { 60 | val oldPredicate = this.predicate; 61 | this.predicate = oldPredicate == null ? predicate : oldPredicate.or(this.predicate); 62 | } 63 | 64 | @Override 65 | public boolean test(final T t) { 66 | return predicate != null && predicate.test(t); 67 | } 68 | } 69 | 70 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 71 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 72 | final class Atomic implements ComponentPredicate { 73 | 74 | AtomicReference> predicate; 75 | 76 | public static @NotNull ComponentPredicate create() { 77 | return new Atomic<>(new AtomicReference<>()); 78 | } 79 | 80 | public static @NotNull ComponentPredicate create(final @NotNull Predicate initial) { 81 | return new Atomic<>(new AtomicReference<>(initial)); 82 | } 83 | 84 | @Override 85 | public void addAnd(final @NotNull Predicate predicate) { 86 | this.predicate.getAndUpdate(oldPredicate -> oldPredicate == null ? predicate : oldPredicate.and(predicate)); 87 | } 88 | 89 | @Override 90 | public void addOr(final @NotNull Predicate predicate) { 91 | this.predicate.getAndUpdate(oldPredicate -> oldPredicate == null ? predicate : oldPredicate.and(predicate)); 92 | } 93 | 94 | @Override 95 | public boolean test(final T t) { 96 | val consumer = this.predicate.get(); 97 | return consumer != null && consumer.test(t); 98 | } 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/io/AbstractByteOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.io; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Getter; 21 | import lombok.Setter; 22 | import lombok.experimental.FieldDefaults; 23 | import lombok.val; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | /** 27 | * @author whilein 28 | */ 29 | @FieldDefaults(level = AccessLevel.PROTECTED) 30 | public abstract class AbstractByteOutput implements ByteOutput { 31 | 32 | byte[] array; 33 | 34 | @Getter 35 | @Setter 36 | int position; 37 | 38 | protected AbstractByteOutput(final byte[] array) { 39 | this.array = array; 40 | } 41 | 42 | protected abstract void ensure(int count); 43 | 44 | @Override 45 | public @NotNull ByteOutput write(final int i) { 46 | ensure(1); 47 | this.array[position++] = (byte) i; 48 | 49 | return this; 50 | } 51 | 52 | @Override 53 | public @NotNull ByteOutput write(final @NotNull String text) { 54 | for (int i = 0, j = text.length(); i < j; i++) { 55 | val ch = text.charAt(i); 56 | 57 | if (ch < 0x80 && ch != 0) { 58 | ensure(1); 59 | 60 | this.array[position++] = (byte) ch; 61 | } else if (ch >= 0x800) { 62 | ensure(3); 63 | 64 | this.array[position++] = (byte) (0xE0 | ((ch >> 12) & 0x0F)); 65 | this.array[position++] = (byte) (0x80 | ((ch >> 6) & 0x3F)); 66 | this.array[position++] = (byte) (0x80 | (ch & 0x3F)); 67 | } else { 68 | ensure(2); 69 | 70 | this.array[position++] = (byte) (0xC0 | ((ch >> 6) & 0x1F)); 71 | this.array[position++] = (byte) (0x80 | (ch & 0x3F)); 72 | } 73 | } 74 | 75 | return this; 76 | } 77 | 78 | @Override 79 | public @NotNull ByteOutput write(final byte @NotNull [] bytes) { 80 | return write(bytes, 0, bytes.length); 81 | } 82 | 83 | @Override 84 | public @NotNull ByteOutput write(final byte @NotNull [] bytes, final int off, final int len) { 85 | ensure(len); 86 | System.arraycopy(bytes, off, array, position, len); 87 | position += len; 88 | 89 | return this; 90 | } 91 | 92 | @Override 93 | public int getCapacity() { 94 | return array.length; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/io/ByteOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.io; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public interface ByteOutput { 25 | 26 | @NotNull ByteOutput write(int i); 27 | 28 | @NotNull ByteOutput write(@NotNull String text); 29 | 30 | @NotNull ByteOutput write(byte @NotNull [] bytes); 31 | 32 | @NotNull ByteOutput write(byte @NotNull [] bytes, int off, int len); 33 | 34 | void setPosition(int position); 35 | 36 | void setLength(int size); 37 | 38 | int getPosition(); 39 | 40 | int getLength(); 41 | 42 | int getCapacity(); 43 | 44 | byte @NotNull [] toByteArray(); 45 | 46 | @NotNull String toString(); 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/io/ByteOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.io; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.RequiredArgsConstructor; 21 | import lombok.experimental.FieldDefaults; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.io.OutputStream; 25 | 26 | /** 27 | * @author whilein 28 | */ 29 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 30 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 31 | public final class ByteOutputStream extends OutputStream { 32 | 33 | ByteOutput byteOutput; 34 | 35 | public static @NotNull OutputStream wrap(final @NotNull ByteOutput byteOutput) { 36 | return new ByteOutputStream(byteOutput); 37 | } 38 | 39 | @Override 40 | public void write(final byte @NotNull [] b, final int off, final int len) { 41 | byteOutput.write(b, off, len); 42 | } 43 | 44 | @Override 45 | public void write(final int b) { 46 | byteOutput.write(b); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/io/CappedByteOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.io; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.experimental.FieldDefaults; 21 | import org.jetbrains.annotations.NotNull; 22 | import w.util.ByteAllocator; 23 | 24 | import java.util.Arrays; 25 | 26 | /** 27 | * @author whilein 28 | */ 29 | @FieldDefaults(level = AccessLevel.PRIVATE) 30 | public final class CappedByteOutput extends AbstractByteOutput { 31 | 32 | int position; 33 | 34 | private CappedByteOutput(final byte[] array) { 35 | super(array); 36 | } 37 | 38 | public static @NotNull ByteOutput create(final int cap) { 39 | return new CappedByteOutput(ByteAllocator.INSTANCE.allocate(cap)); 40 | } 41 | 42 | @Override 43 | public @NotNull ByteOutput write(final int i) { 44 | ensure(1); 45 | 46 | this.array[position++] = (byte) i; 47 | return this; 48 | } 49 | 50 | @Override 51 | public void setLength(final int length) { 52 | this.array = Arrays.copyOf(array, length); 53 | } 54 | 55 | @Override 56 | public int getLength() { 57 | return array.length; 58 | } 59 | 60 | protected void ensure(final int count) { 61 | if (position + count >= array.length) { 62 | throw new IllegalStateException("buffer cannot fit " + count + " bytes"); 63 | } 64 | } 65 | 66 | @Override 67 | public @NotNull String toString() { 68 | return new String(array); 69 | } 70 | 71 | @Override 72 | public byte @NotNull [] toByteArray() { 73 | return Arrays.copyOf(array, array.length); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/io/UncappedByteOutput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.io; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.experimental.FieldDefaults; 21 | import lombok.val; 22 | import org.jetbrains.annotations.NotNull; 23 | import w.util.ByteAllocator; 24 | 25 | import java.util.Arrays; 26 | 27 | /** 28 | * @author whilein 29 | */ 30 | @FieldDefaults(level = AccessLevel.PRIVATE) 31 | public final class UncappedByteOutput extends AbstractByteOutput { 32 | 33 | int length; 34 | 35 | private UncappedByteOutput(final byte[] array) { 36 | super(array); 37 | } 38 | 39 | public static @NotNull ByteOutput create(final int initialCap) { 40 | return new UncappedByteOutput(ByteAllocator.INSTANCE.allocate(initialCap)); 41 | } 42 | 43 | public static @NotNull ByteOutput create() { 44 | return create(8192); 45 | } 46 | 47 | @Override 48 | protected void ensure(final int count) { 49 | val newPosition = position + count; 50 | 51 | if (newPosition > array.length) { 52 | array = Arrays.copyOf(array, Math.max(newPosition, array.length * 2)); 53 | } 54 | 55 | length = Math.max(length, newPosition); 56 | } 57 | 58 | @Override 59 | public void setLength(final int length) { 60 | this.length = length; 61 | this.position = Math.min(length, position); 62 | } 63 | 64 | @Override 65 | public int getLength() { 66 | return length; 67 | } 68 | 69 | @Override 70 | public @NotNull String toString() { 71 | return new String(array, 0, length); 72 | } 73 | 74 | @Override 75 | public byte @NotNull [] toByteArray() { 76 | return Arrays.copyOf(array, length); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/lazy/ConcurrentLazy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.lazy; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.AllArgsConstructor; 21 | import lombok.experimental.FieldDefaults; 22 | import lombok.experimental.NonFinal; 23 | import lombok.val; 24 | import org.jetbrains.annotations.NotNull; 25 | import w.util.ObjectUtils; 26 | 27 | import java.util.function.Supplier; 28 | 29 | /** 30 | * Потоко-безопасная реализация {@link Lazy}, которая гарантированно инициализирует 31 | * значение только один раз, 32 | *

33 | * Если вы используете {@link Lazy#clear()} и {@link Lazy#get()}, то 34 | * некоторые потоки могут вернуть старое значение. 35 | * 36 | * @author whilein 37 | */ 38 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 39 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 40 | public final class ConcurrentLazy implements Lazy { 41 | 42 | Supplier supplier; 43 | 44 | T empty; 45 | 46 | @NonFinal 47 | volatile T value; 48 | 49 | Object mutex; 50 | 51 | public static @NotNull Lazy create( 52 | final @NotNull Supplier supplier, 53 | final @NotNull Object mutex 54 | ) { 55 | val empty = ObjectUtils.empty(); 56 | return new ConcurrentLazy<>(supplier, empty, empty, mutex); 57 | } 58 | 59 | public static @NotNull Lazy create( 60 | final @NotNull Supplier supplier 61 | ) { 62 | val empty = ObjectUtils.empty(); 63 | return new ConcurrentLazy<>(supplier, empty, empty, new Object[0]); 64 | } 65 | 66 | @Override 67 | public void clear() { 68 | synchronized (mutex) { 69 | value = empty; 70 | } 71 | } 72 | 73 | @Override 74 | public T clearAndGet() { 75 | synchronized (mutex) { 76 | return value = supplier.get(); 77 | } 78 | } 79 | 80 | @Override 81 | public T get() { 82 | T result = value; 83 | 84 | if (result == empty) { 85 | synchronized (mutex) { 86 | result = value; 87 | 88 | if (result == empty) { 89 | result = value = supplier.get(); 90 | } 91 | } 92 | } 93 | 94 | return result; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/lazy/Lazy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.lazy; 18 | 19 | import java.util.function.Supplier; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public interface Lazy extends Supplier { 25 | 26 | /** 27 | * Очистить сохраненное значение 28 | */ 29 | void clear(); 30 | 31 | /** 32 | * Очистить и получить новое значение 33 | * 34 | * @return новое значение 35 | */ 36 | T clearAndGet(); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/lazy/SimpleLazy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.lazy; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.AllArgsConstructor; 21 | import lombok.experimental.FieldDefaults; 22 | import lombok.experimental.NonFinal; 23 | import lombok.val; 24 | import org.jetbrains.annotations.NotNull; 25 | import w.util.ObjectUtils; 26 | 27 | import java.util.function.Supplier; 28 | 29 | /** 30 | * Простейшая реализация {@link Lazy}. 31 | *

32 | * Если {@link Lazy#get()} выполняется в разных потоках, то 33 | * следует использовать {@link ConcurrentLazy}. 34 | * 35 | * @author whilein 36 | */ 37 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 38 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 39 | public final class SimpleLazy implements Lazy { 40 | 41 | Supplier supplier; 42 | 43 | T empty; 44 | 45 | @NonFinal 46 | T value; 47 | 48 | public static @NotNull Lazy create(final @NotNull Supplier supplier) { 49 | val empty = ObjectUtils.empty(); 50 | return new SimpleLazy<>(supplier, empty, empty); 51 | } 52 | 53 | @Override 54 | public void clear() { 55 | value = empty; 56 | } 57 | 58 | @Override 59 | public T clearAndGet() { 60 | return value = supplier.get(); 61 | } 62 | 63 | @Override 64 | public T get() { 65 | T result = value; 66 | 67 | if (result == empty) { 68 | value = result = supplier.get(); 69 | } 70 | 71 | return result; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/mutable/MutableInt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.mutable; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public interface MutableInt { 23 | 24 | int incrementAndGet(); 25 | 26 | int getAndIncrement(); 27 | 28 | int decrementAndGet(); 29 | 30 | int getAndDecrement(); 31 | 32 | int get(); 33 | 34 | void set(int value); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/mutable/MutableLong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.mutable; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public interface MutableLong { 23 | 24 | long incrementAndGet(); 25 | 26 | long getAndIncrement(); 27 | 28 | long decrementAndGet(); 29 | 30 | long getAndDecrement(); 31 | 32 | long get(); 33 | 34 | void set(long value); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/mutable/MutableOptionalInt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.mutable; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.function.IntSupplier; 22 | import java.util.function.Supplier; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public interface MutableOptionalInt extends MutableInt { 28 | 29 | void clear(); 30 | 31 | int orElseThrow(@NotNull X cause) throws X; 32 | 33 | int orElseThrow(@NotNull Supplier supplier) throws X; 34 | 35 | int orElse(int value); 36 | 37 | int orElseGet(@NotNull IntSupplier value); 38 | 39 | boolean isEmpty(); 40 | 41 | boolean isPresent(); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/mutable/MutableOptionalLong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.mutable; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.function.LongSupplier; 22 | import java.util.function.Supplier; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public interface MutableOptionalLong extends MutableLong { 28 | 29 | void clear(); 30 | 31 | long orElseThrow(@NotNull X cause) throws X; 32 | 33 | long orElseThrow(@NotNull Supplier supplier) throws X; 34 | 35 | long orElse(long value); 36 | 37 | long orElseGet(@NotNull LongSupplier value); 38 | 39 | boolean isEmpty(); 40 | 41 | boolean isPresent(); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/mutable/MutableOptionalReference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.mutable; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.function.Supplier; 22 | 23 | /** 24 | * @author whilein 25 | */ 26 | public interface MutableOptionalReference extends MutableReference { 27 | 28 | void clear(); 29 | 30 | T orElseThrow(@NotNull X cause) throws X; 31 | 32 | T orElseThrow(@NotNull Supplier supplier) throws X; 33 | 34 | T orElse(T value); 35 | 36 | T orElseGet(@NotNull Supplier value); 37 | 38 | boolean isEmpty(); 39 | 40 | boolean isPresent(); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/mutable/MutableReference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.mutable; 18 | 19 | /** 20 | * @author whilein 21 | */ 22 | public interface MutableReference { 23 | 24 | T get(); 25 | 26 | void set(T value); 27 | 28 | boolean isNull(); 29 | 30 | boolean isNotNull(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/pair/MutablePair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.pair; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.Map; 22 | 23 | /** 24 | * Мутабельная пара значений, можно изменять левое и правое значение. 25 | *

26 | * Недостаток этой реализации от обычной иммутабельной пары в том, что hashCode 27 | * не кешируется. 28 | * 29 | * @author whilein 30 | */ 31 | public interface MutablePair extends Pair { 32 | 33 | static @NotNull MutablePair of(final L left, final R right) { 34 | return Pairs.mutableOf(left, right); 35 | } 36 | 37 | static @NotNull MutablePair of(final @NotNull Map.Entry entry) { 38 | return Pairs.mutableOf(entry.getKey(), entry.getValue()); 39 | } 40 | 41 | void setLeft(L value); 42 | 43 | void setRight(R value); 44 | 45 | @NotNull MutablePair withLeft(L1 newValue); 46 | 47 | @NotNull MutablePair withRight(R1 newValue); 48 | 49 | @NotNull MutablePair clone(); 50 | 51 | @NotNull MutablePair deepClone(); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/pair/Pair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.pair; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.Map; 22 | 23 | /** 24 | * Иммутабельная пара значений. 25 | * 26 | * @author whilein 27 | */ 28 | public interface Pair extends Cloneable { 29 | 30 | static @NotNull Pair of(final L left, final R right) { 31 | return Pairs.immutableOf(left, right); 32 | } 33 | 34 | static @NotNull Pair of(final @NotNull Map.Entry entry) { 35 | return Pairs.immutableOf(entry.getKey(), entry.getValue()); 36 | } 37 | 38 | boolean equals(@NotNull Pair pair); 39 | 40 | L getLeft(); 41 | 42 | R getRight(); 43 | 44 | @NotNull Pair withLeft(L1 newValue); 45 | 46 | @NotNull Pair withRight(R1 newValue); 47 | 48 | /** 49 | * Склонировать пару. 50 | * 51 | * @return новая склонированая пара 52 | */ 53 | @NotNull Pair clone(); 54 | 55 | /** 56 | * Склонировать пару. 57 | *

58 | * Также, в отличие от {@link #clone()}, клонируется {@code L} и {@code R}, если 59 | * они наследуют Cloneable. 60 | * 61 | * @return новая склонированая пара 62 | */ 63 | @NotNull Pair deepClone(); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/pair/UnorderedPair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.pair; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.Map; 22 | 23 | /** 24 | * Иммутабельная пара значений. 25 | *

26 | * В реализации {@link Object#hashCode()} возвращает одно и то же число, 27 | * когда L и R перепутаны местами. Т.е хешкод пары (A, B) равен хешкоду пары (B, A). 28 | *

29 | * {@link Object#equals(Object)} также возвращает {@code true}, если значения в разном порядке. 30 | * 31 | * @author whilein 32 | */ 33 | public interface UnorderedPair extends Pair { 34 | 35 | int LEFT_GREATER = 1; 36 | int RIGHT_GREATER = 2; 37 | 38 | static @NotNull UnorderedPair of(final L left, final R right) { 39 | return Pairs.unorderedOf(left, right); 40 | } 41 | 42 | static @NotNull UnorderedPair of(final @NotNull Map.Entry entry) { 43 | return Pairs.unorderedOf(entry.getKey(), entry.getValue()); 44 | } 45 | 46 | @NotNull UnorderedPair reverse(); 47 | 48 | /** 49 | * @return {@link #LEFT_GREATER} или {@link #RIGHT_GREATER} 50 | */ 51 | int getOrder(); 52 | 53 | @NotNull Object getGreater(); 54 | 55 | @NotNull Object getLower(); 56 | 57 | @NotNull UnorderedPair withLeft(L1 newValue); 58 | 59 | @NotNull UnorderedPair withRight(R1 newValue); 60 | 61 | @NotNull UnorderedPair clone(); 62 | 63 | @NotNull UnorderedPair deepClone(); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/random/RandomStringGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.random; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public interface RandomStringGenerator { 25 | 26 | static @NotNull RandomStringGeneratorBuilder builder() { 27 | return SimpleRandomStringGenerator.builder(); 28 | } 29 | 30 | @NotNull String nextString(int length); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/random/RandomStringGeneratorBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.random; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | import java.util.Random; 22 | import java.util.function.Supplier; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | public interface RandomStringGeneratorBuilder { 28 | 29 | /** 30 | * Установить рандом, по умолчанию используется {@link Random} из {@link w.util.RandomUtils#getRandom()}. 31 | * 32 | * @param randomFactory Фабрика {@link Random} 33 | * @return {@code this} 34 | */ 35 | @NotNull RandomStringGeneratorBuilder randomFactory(@NotNull Supplier<@NotNull Random> randomFactory); 36 | 37 | /** 38 | * Установить рандом, по умолчанию используется {@link Random} из {@link w.util.RandomUtils#getRandom()}. 39 | * 40 | * @param random {@link Random} 41 | * @return {@code this} 42 | */ 43 | @NotNull RandomStringGeneratorBuilder random(@NotNull Random random); 44 | 45 | /** 46 | * Установить {@link w.util.RandomUtils#getSecureRandom()} как рандом, по умолчанию 47 | * используется {@link Random} из {@link w.util.RandomUtils#getRandom()}. 48 | * 49 | * @return {@code this} 50 | */ 51 | @NotNull RandomStringGeneratorBuilder randomSecure(); 52 | 53 | /** 54 | * Установить {@link java.util.concurrent.ThreadLocalRandom} как рандом, по умолчанию 55 | * используется {@link Random} из {@link w.util.RandomUtils#getRandom()}. 56 | * 57 | * @return {@code this} 58 | */ 59 | @NotNull RandomStringGeneratorBuilder randomThreadLocal(); 60 | 61 | @NotNull RandomStringGeneratorBuilder addLetters(); 62 | 63 | @NotNull RandomStringGeneratorBuilder addUpperLetters(); 64 | 65 | @NotNull RandomStringGeneratorBuilder addLowerLetters(); 66 | 67 | @NotNull RandomStringGeneratorBuilder addNumbers(); 68 | 69 | @NotNull RandomStringGeneratorBuilder setDictionary(@NotNull String dictionary); 70 | 71 | @NotNull RandomStringGeneratorBuilder addDictionary(@NotNull String dictionary); 72 | 73 | @NotNull RandomStringGenerator build(); 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/random/SimpleWeightedRandomGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.random; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.RequiredArgsConstructor; 21 | import lombok.experimental.FieldDefaults; 22 | import lombok.experimental.NonFinal; 23 | import lombok.val; 24 | import org.jetbrains.annotations.NotNull; 25 | 26 | import java.util.Collection; 27 | import java.util.Map; 28 | import java.util.function.Function; 29 | import java.util.function.ToDoubleFunction; 30 | 31 | /** 32 | * @author whilein 33 | */ 34 | @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) 35 | @RequiredArgsConstructor(access = AccessLevel.PRIVATE) 36 | public class SimpleWeightedRandomGenerator implements WeightedRandomGenerator { 37 | 38 | double sum; 39 | 40 | Collection collection; 41 | Function objectFunction; 42 | ToDoubleFunction weightFunction; 43 | 44 | T defaultValue; 45 | 46 | public static @NotNull WeightedRandomBuilder builder(@NotNull Map map) { 47 | return new Builder<>(map.entrySet(), Map.Entry::getKey, Map.Entry::getValue); 48 | } 49 | 50 | public static @NotNull WeightedRandomBuilder builder( 51 | @NotNull Collection collection, 52 | @NotNull ToDoubleFunction weightFunction 53 | ) { 54 | return new Builder<>(collection, Function.identity(), weightFunction); 55 | } 56 | 57 | public static @NotNull WeightedRandomBuilder builder( 58 | @NotNull Collection collection, 59 | @NotNull Function objectFunction, 60 | @NotNull ToDoubleFunction weightFunction 61 | ) { 62 | return new Builder<>(collection, objectFunction, weightFunction); 63 | } 64 | 65 | @Override 66 | public T nextObject() { 67 | val collection = this.collection; 68 | 69 | if (collection.isEmpty()) { 70 | throw new IllegalStateException("Collection is empty"); 71 | } 72 | 73 | val randomizedSum = Math.random() * sum; 74 | 75 | double from = 0.0; 76 | 77 | for (val element : collection) { 78 | val itemWeight = weightFunction.applyAsDouble(element); 79 | 80 | if (randomizedSum >= from && randomizedSum < from + itemWeight) { 81 | return objectFunction.apply(element); 82 | } 83 | 84 | from += itemWeight; 85 | } 86 | 87 | return defaultValue; 88 | } 89 | 90 | @FieldDefaults(makeFinal = true) 91 | @RequiredArgsConstructor 92 | private static final class Builder implements WeightedRandomBuilder { 93 | Collection collection; 94 | Function objectFunction; 95 | ToDoubleFunction weightFunction; 96 | 97 | @NonFinal 98 | boolean manualSum; 99 | 100 | @NonFinal 101 | double sum; 102 | 103 | @NonFinal 104 | T defaultValue; 105 | 106 | @Override 107 | public @NotNull WeightedRandomBuilder sum(double value, T defaultValue) { 108 | this.manualSum = true; 109 | 110 | this.sum = value; 111 | this.defaultValue = defaultValue; 112 | 113 | return this; 114 | } 115 | 116 | @Override 117 | public @NotNull WeightedRandomBuilder autoSum() { 118 | manualSum = false; 119 | 120 | return this; 121 | } 122 | 123 | @Override 124 | public @NotNull WeightedRandomGenerator build() { 125 | if (collection.isEmpty()) { 126 | throw new IllegalStateException("Collection is empty"); 127 | } 128 | 129 | val sum = manualSum ? this.sum : collection.stream().mapToDouble(weightFunction).sum(); 130 | 131 | return new SimpleWeightedRandomGenerator<>(sum, collection, objectFunction, weightFunction, defaultValue); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/random/WeightedRandomBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.random; 18 | 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * @author whilein 23 | */ 24 | public interface WeightedRandomBuilder { 25 | 26 | 27 | /** 28 | * Установить фиксированную сумму для рандома. 29 | * 30 | * @return {@code this} 31 | */ 32 | @NotNull WeightedRandomBuilder sum(double value, T defaultValue); 33 | 34 | /** 35 | * Автоматически посчитать сумму всех весов перед созданием рандома 36 | * 37 | * @return {@code this} 38 | */ 39 | @NotNull WeightedRandomBuilder autoSum(); 40 | 41 | @NotNull WeightedRandomGenerator build(); 42 | } 43 | -------------------------------------------------------------------------------- /util/src/main/java/w/util/random/WeightedRandomGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.random; 18 | 19 | import java.util.stream.Stream; 20 | 21 | /** 22 | * Заранее подготовленный рандом с весами. 23 | * 24 | * @author whilein 25 | */ 26 | public interface WeightedRandomGenerator { 27 | 28 | T nextObject(); 29 | 30 | default Stream nextObjects() { 31 | return Stream.generate(this::nextObject); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/NumberUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | 23 | /** 24 | * @author whilein 25 | */ 26 | final class NumberUtilsTest { 27 | 28 | @Test 29 | void formatNumber_long() { 30 | assertEquals("-1", NumberUtils.formatNumber(-1)); 31 | assertEquals("0", NumberUtils.formatNumber(0)); 32 | assertEquals("1", NumberUtils.formatNumber(1L)); 33 | assertEquals("1,000", NumberUtils.formatNumber(1000L)); 34 | assertEquals("1,000,000", NumberUtils.formatNumber(1000000L)); 35 | assertEquals("1,000,000,000", NumberUtils.formatNumber(1000000000L)); 36 | assertEquals("1,000,000,000,000", NumberUtils.formatNumber(1000000000000L)); 37 | } 38 | 39 | @Test 40 | void formatNumber_double() { 41 | assertEquals("-0.12", NumberUtils.formatNumber(-0.123)); 42 | assertEquals("0.12", NumberUtils.formatNumber(0.123)); 43 | assertEquals("1.12", NumberUtils.formatNumber(1.123)); 44 | assertEquals("1,000.12", NumberUtils.formatNumber(1000.123)); 45 | assertEquals("1,000,000.12", NumberUtils.formatNumber(1000000.123)); 46 | assertEquals("1,000,000,000.12", NumberUtils.formatNumber(1000000000.123)); 47 | assertEquals("1,000,000,000,000.12", NumberUtils.formatNumber(1000000000000.123)); 48 | } 49 | } -------------------------------------------------------------------------------- /util/src/test/java/w/util/RandomUtilsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.BeforeEach; 21 | import org.junit.jupiter.api.Test; 22 | 23 | import java.util.List; 24 | import java.util.UUID; 25 | import java.util.stream.Collectors; 26 | import java.util.stream.Stream; 27 | 28 | import static org.junit.jupiter.api.Assertions.assertEquals; 29 | import static org.junit.jupiter.api.Assertions.assertTrue; 30 | 31 | /** 32 | * @author whilein 33 | */ 34 | final class RandomUtilsTests { 35 | 36 | List randomUuids; 37 | 38 | @BeforeEach 39 | void setup() { 40 | randomUuids = Stream.generate(UUID::randomUUID) 41 | .limit(100) 42 | .collect(Collectors.toList()); 43 | } 44 | 45 | @Test 46 | void testGetRandomElements_notDistinct() { 47 | assertTrue(randomUuids.containsAll(RandomUtils.getRandomElements(randomUuids, 50, false))); 48 | } 49 | 50 | @Test 51 | void testGetRandomElements_distinct() { 52 | val randomElements = RandomUtils.getRandomElements(randomUuids, 50, true); 53 | assertEquals(randomElements.size(), 50); 54 | assertEquals(randomUuids.size(), 100); // чтобы remove не удалял из оригинального списка 55 | 56 | assertEquals(50L, randomElements.stream() 57 | .distinct() 58 | .count()); 59 | 60 | assertTrue(randomUuids.containsAll(randomElements)); 61 | } 62 | 63 | @Test 64 | void testGetRandomElement() { 65 | assertTrue(randomUuids.contains(RandomUtils.getRandomElement(randomUuids))); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/buffering/BufferingTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.buffering; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | import static org.junit.jupiter.api.Assertions.assertSame; 24 | 25 | /** 26 | * @author whilein 27 | */ 28 | final class BufferingTests { 29 | 30 | @Test 31 | void test() { 32 | final StringBuilder x, y; 33 | 34 | try (val result = Buffering.getStringBuilder()) { 35 | x = result.get(); 36 | 37 | try (val nested = Buffering.getStringBuilder()) { 38 | y = nested.get(); 39 | } 40 | } 41 | 42 | try (val result = Buffering.getStringBuilder()) { 43 | assertSame(x, result.get()); 44 | 45 | try (val nested = Buffering.getStringBuilder()) { 46 | assertSame(y, nested.get()); 47 | } 48 | } 49 | } 50 | 51 | @Test 52 | void testNested() { 53 | try (val first = Buffering.getStringBuilder()) { 54 | first.get().append("A"); 55 | 56 | try (val second = Buffering.getStringBuilder()) { 57 | second.get().append("B"); 58 | 59 | try (val third = Buffering.getStringBuilder()) { 60 | third.get().append("C"); 61 | 62 | assertEquals("A", first.get().toString()); 63 | assertEquals("B", second.get().toString()); 64 | assertEquals("C", third.get().toString()); 65 | } 66 | } 67 | } 68 | } 69 | 70 | @Test 71 | void testRelease() { 72 | try (val result = Buffering.getStringBuilder()) { 73 | val builder = result.get(); 74 | builder.append("Hello world!"); 75 | 76 | assertEquals("Hello world!", builder.toString()); 77 | } 78 | 79 | try (val result = Buffering.getStringBuilder()) { 80 | assertEquals(0, result.get().length()); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/ci/CiStringsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.ci; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import java.util.HashMap; 23 | 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | 26 | /** 27 | * @author whilein 28 | */ 29 | class CiStringsTest { 30 | 31 | @Test 32 | void testInMap() { 33 | final String[] array = { 34 | "A a A", 35 | "a A a" 36 | }; 37 | 38 | val x = CiStrings.from(array[0]); 39 | val y = CiStrings.from(array[1]); 40 | 41 | assertEquals(x, y); 42 | 43 | val map = new HashMap(); 44 | map.put(x, 123); 45 | map.put(y, 321); 46 | 47 | assertEquals(map.get(x), Integer.valueOf(321)); 48 | assertEquals(map.get(y), Integer.valueOf(321)); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /util/src/test/java/w/util/io/ByteOutputTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.io; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 23 | import static org.junit.jupiter.api.Assertions.assertEquals; 24 | 25 | /** 26 | * @author whilein 27 | */ 28 | final class ByteOutputTests { 29 | 30 | @Test 31 | void uncapped_setLength() { 32 | val uncapped = UncappedByteOutput.create(); 33 | assertEquals(0, uncapped.getLength()); 34 | assertEquals(0, uncapped.getPosition()); 35 | uncapped.write(1); 36 | uncapped.write(2); 37 | assertEquals(2, uncapped.getLength()); 38 | assertEquals(2, uncapped.getPosition()); 39 | assertArrayEquals(new byte[]{1, 2}, uncapped.toByteArray()); 40 | uncapped.setPosition(0); 41 | assertEquals(2, uncapped.getLength()); 42 | assertEquals(0, uncapped.getPosition()); 43 | assertArrayEquals(new byte[]{1, 2}, uncapped.toByteArray()); 44 | uncapped.setLength(0); 45 | assertEquals(0, uncapped.getLength()); 46 | assertEquals(0, uncapped.getPosition()); 47 | assertArrayEquals(new byte[0], uncapped.toByteArray()); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/io/ByteUnitTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.io; 18 | 19 | import org.junit.jupiter.api.Test; 20 | import w.util.ByteUnit; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertEquals; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | final class ByteUnitTest { 28 | 29 | @Test 30 | void convert() { 31 | assertEquals(0L, ByteUnit.UNO.toKibi(1L)); 32 | assertEquals(0.5, ByteUnit.UNO.toKibi(512.0)); 33 | 34 | assertEquals(1024L, ByteUnit.KIBI.toUno(1L)); 35 | assertEquals(1024L, ByteUnit.MEBI.toKibi(1L)); 36 | assertEquals(1024L, ByteUnit.GIBI.toMebi(1L)); 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /util/src/test/java/w/util/lazy/ConcurrentLazyTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.lazy; 18 | 19 | import lombok.SneakyThrows; 20 | import lombok.val; 21 | import org.junit.jupiter.api.BeforeEach; 22 | import org.junit.jupiter.api.Test; 23 | 24 | import java.util.Set; 25 | import java.util.UUID; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | import java.util.concurrent.CountDownLatch; 28 | import java.util.concurrent.Executors; 29 | 30 | import static org.junit.jupiter.api.Assertions.assertEquals; 31 | 32 | /** 33 | * @author whilein 34 | */ 35 | final class ConcurrentLazyTests extends LazyTests { 36 | 37 | private static final int ITERATIONS = 1024; 38 | 39 | @BeforeEach 40 | void setup() { 41 | lazy = ConcurrentLazy.create(UUID::randomUUID); 42 | } 43 | 44 | @Test 45 | @SneakyThrows 46 | void testAtomic() { 47 | val threadPool = Executors.newFixedThreadPool(8); 48 | val latch = new CountDownLatch(ITERATIONS); 49 | 50 | final Set uniqueResults = ConcurrentHashMap.newKeySet(); 51 | 52 | for (int i = 0; i < ITERATIONS; i++) { 53 | threadPool.execute(() -> { 54 | uniqueResults.add(lazy.clearAndGet()); 55 | latch.countDown(); 56 | }); 57 | } 58 | 59 | latch.await(); 60 | 61 | assertEquals(ITERATIONS, uniqueResults.size()); 62 | } 63 | 64 | @Test 65 | @SneakyThrows 66 | void testConcurrency() { 67 | val threadPool = Executors.newFixedThreadPool(8); 68 | 69 | val latch = new CountDownLatch(64); 70 | 71 | final Set uniqueResults = ConcurrentHashMap.newKeySet(); 72 | 73 | for (int i = 0; i < 64; i++) { 74 | threadPool.execute(() -> { 75 | uniqueResults.add(lazy.get()); 76 | latch.countDown(); 77 | }); 78 | } 79 | 80 | latch.await(); 81 | 82 | assertEquals(1, uniqueResults.size()); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/lazy/LazyTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.lazy; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import java.util.UUID; 23 | 24 | import static org.junit.jupiter.api.Assertions.assertEquals; 25 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 26 | import static org.junit.jupiter.api.Assertions.assertNotNull; 27 | 28 | /** 29 | * @author whilein 30 | */ 31 | abstract class LazyTests { 32 | 33 | protected Lazy lazy; 34 | 35 | @Test 36 | void testBasics() { 37 | val firstValue = lazy.get(); 38 | assertNotNull(firstValue); 39 | val secondValue = lazy.get(); 40 | assertEquals(firstValue, secondValue); 41 | 42 | lazy.clear(); 43 | 44 | val thirdValue = lazy.get(); 45 | assertNotEquals(firstValue, thirdValue); 46 | 47 | assertNotEquals(thirdValue, lazy.clearAndGet()); 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/lazy/SimpleLazyTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.lazy; 18 | 19 | import org.junit.jupiter.api.BeforeEach; 20 | 21 | import java.util.UUID; 22 | 23 | /** 24 | * @author whilein 25 | */ 26 | final class SimpleLazyTests extends LazyTests { 27 | 28 | @BeforeEach 29 | void setup() { 30 | lazy = SimpleLazy.create(UUID::randomUUID); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/pair/PairTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.pair; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import static org.junit.jupiter.api.Assertions.assertEquals; 26 | import static org.junit.jupiter.api.Assertions.assertNotEquals; 27 | 28 | /** 29 | * @author whilein 30 | */ 31 | final class PairTests { 32 | 33 | @Test 34 | void testClone() { 35 | val pair = Pair.of("foo", "bar"); 36 | val clonedPair = pair.clone(); 37 | 38 | assertNotEquals(System.identityHashCode(pair), System.identityHashCode(clonedPair)); 39 | } 40 | 41 | @Test 42 | void testUnordered() { 43 | val xxxyyy = UnorderedPair.of("xxx", "yyy"); 44 | val yyyxxx = UnorderedPair.of("yyy", "xxx"); 45 | assertEquals(xxxyyy.hashCode(), yyyxxx.hashCode()); 46 | assertEquals(xxxyyy, yyyxxx); 47 | 48 | val xxxyyy2 = UnorderedPair.of("xxx", "yyy"); 49 | val yyyxxx2 = UnorderedPair.of("yyy", "xxx"); 50 | 51 | assertEquals(xxxyyy, xxxyyy2); 52 | assertEquals(yyyxxx, yyyxxx2); 53 | assertEquals(xxxyyy2, xxxyyy); 54 | assertEquals(yyyxxx2, yyyxxx); 55 | } 56 | 57 | @Test 58 | void testDeepClone() { 59 | val left = new ArrayList<>(List.of("foo", "bar", "baz")); 60 | val right = new ArrayList<>(List.of("foo", "bar", "baz")); 61 | 62 | val pair = Pair.of(left, right); 63 | val clonedPair = pair.deepClone(); 64 | 65 | assertNotEquals(System.identityHashCode(pair), System.identityHashCode(clonedPair)); 66 | assertNotEquals(System.identityHashCode(pair.getLeft()), System.identityHashCode(clonedPair.getLeft())); 67 | assertNotEquals(System.identityHashCode(pair.getRight()), System.identityHashCode(clonedPair.getRight())); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/random/RandomStringGeneratorTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.random; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import static org.junit.jupiter.api.Assertions.assertTrue; 23 | 24 | /** 25 | * @author whilein 26 | */ 27 | final class RandomStringGeneratorTests { 28 | 29 | @Test 30 | void testNumbers() { 31 | val generator = RandomStringGenerator.builder() 32 | .addNumbers() 33 | .build(); 34 | 35 | for (int i = 0; i < 1000; i++) { 36 | assertTrue(generator.nextString(100).matches("\\d{100}")); 37 | } 38 | } 39 | 40 | @Test 41 | void testLetters() { 42 | val generator = RandomStringGenerator.builder() 43 | .addLetters() 44 | .build(); 45 | 46 | for (int i = 0; i < 1000; i++) { 47 | assertTrue(generator.nextString(100).matches("\\w{100}")); 48 | } 49 | } 50 | 51 | @Test 52 | void testCustomDictionary_0() { 53 | val generator = RandomStringGenerator.builder() 54 | .setDictionary("хуй") 55 | .build(); 56 | 57 | for (int i = 0; i < 1000; i++) { 58 | assertTrue(generator.nextString(100).matches("[хуй]{100}")); 59 | } 60 | } 61 | 62 | @Test 63 | void testCustomDictionary_1() { 64 | val generator = RandomStringGenerator.builder() 65 | .addDictionary("хуй") 66 | .addDictionary("пизда") 67 | .build(); 68 | 69 | for (int i = 0; i < 1000; i++) { 70 | assertTrue(generator.nextString(100).matches("[хуйпизда]{100}")); 71 | } 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /util/src/test/java/w/util/random/WeightedRandomGeneratorTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Whilein 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package w.util.random; 18 | 19 | import lombok.val; 20 | import org.junit.jupiter.api.Test; 21 | 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | import static org.junit.jupiter.api.Assertions.assertEquals; 26 | 27 | /** 28 | * @author whilein 29 | */ 30 | public class WeightedRandomGeneratorTests { 31 | 32 | @Test 33 | public void testSum() { 34 | val values = Map.of( 35 | "123", 0.2, 36 | "321", 0.4, 37 | "333", 0.1 38 | ); 39 | 40 | val counts = new HashMap(); 41 | 42 | val weightedRandom = SimpleWeightedRandomGenerator.builder(values) 43 | .sum(1.0, "666") 44 | .build(); 45 | 46 | final int iterations = 100_000; 47 | 48 | for (int i = 0; i < iterations; i++) { 49 | val object = weightedRandom.nextObject(); 50 | counts.merge(object, 1, Integer::sum); 51 | } 52 | 53 | for (val count : counts.entrySet()) { 54 | assertEquals(values.getOrDefault(count.getKey(), 0.3), 55 | count.getValue() / (double) iterations, 0.1); 56 | } 57 | } 58 | 59 | 60 | @Test 61 | public void testAutoSum() { 62 | val values = Map.of( 63 | "123", 0.2, 64 | "321", 0.4, 65 | "333", 0.1, 66 | "666", 0.3 67 | ); 68 | 69 | val counts = new HashMap(); 70 | 71 | val weightedRandom = SimpleWeightedRandomGenerator.builder(values) 72 | .build(); 73 | 74 | final int iterations = 100_000; 75 | 76 | for (int i = 0; i < iterations; i++) { 77 | val object = weightedRandom.nextObject(); 78 | counts.merge(object, 1, Integer::sum); 79 | } 80 | 81 | for (val count : counts.entrySet()) { 82 | assertEquals(values.get(count.getKey()), count.getValue() / (double) iterations, 0.1); 83 | } 84 | } 85 | 86 | } 87 | --------------------------------------------------------------------------------