content: package org.allaymc.server.command.selector.args;
  
  import com.github.benmanes.caffeine.cache.Cache;
  import com.github.benmanes.caffeine.cache.Caffeine;
  import com.google.common.collect.Sets;
  import org.allaymc.api.command.CommandSender;
  import org.allaymc.api.command.selector.SelectorArgument;
  import org.allaymc.api.command.selector.SelectorSyntaxException;
  import org.allaymc.api.command.selector.SelectorType;
  import org.allaymc.api.entity.Entity;
  import org.allaymc.api.math.location.Location3d;
  import org.allaymc.api.math.location.Location3dc;
  
  import java.util.Set;
  import java.util.concurrent.TimeUnit;
  import java.util.function.Predicate;
  
  /**
   * Cachable base class for target selector arguments
   * <p>
   * If a selector argument returns {@code List<Predicate<Entity>>} without expiration, you can inherit from this class to cache the parsing results for better performance.
   */
  public abstract class CachedSimpleSelectorArgument implements SelectorArgument {
      private final Cache<Set<String>, Predicate<Entity>> cache;
  
      public CachedSimpleSelectorArgument() {
          this.cache = provideCacheService();
      }
  
      @Override
      public Predicate<Entity> getPredicate(SelectorType selectorType, CommandSender sender, Location3d basePos, String... arguments) throws SelectorSyntaxException {
          var value = cache.getIfPresent(Sets.newHashSet(arguments));
          if (value == null) {
              value = cache(selectorType, sender, basePos, arguments);
              cache.put(Sets.newHashSet(arguments), value);
          }
          return value;
      }
  
      /**
       * Called when the predicate for a given set of arguments is not present in the cache.
       * <p>
       * Subclasses must implement this method to define how the predicate is computed based on the arguments.
       *
       * @param selectorType the type of selector (e.g., {@code @p}, {@code @e})
       * @param sender       the command sender who issued the selector
       * @param basePos      the base position used for relative coordinate parsing
       * @param arguments    the arguments used for the selector
       * @return a {@code Predicate<Entity>} that filters entities
       * @throws SelectorSyntaxException if the arguments cannot be parsed
       */
      protected abstract Predicate<Entity> cache(SelectorType selectorType, CommandSender sender, Location3dc basePos, String... arguments) throws SelectorSyntaxException;
  
      /**
       * Provides the cache service used to store predicates.
       * <p>
       * This method initializes a cache with a maximum size of 65,535 entries and an expiration time
       * of 1 minute after the last access. Subclasses may override this method if they need a different cache configuration.
       *
       * @return a {@code Cache<Set<String>, Predicate<Entity>>} for caching predicates
       */
      protected Cache<Set<String>, Predicate<Entity>> provideCacheService() {
          return Caffeine.newBuilder().maximumSize(65535).expireAfterAccess(1, TimeUnit.MINUTES).build();
      }
  }