All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sx.blah.discord.util.cache.Cache Maven / Gradle / Ivy

Go to download

A Java binding for the official Discord API, forked from the inactive https://github.com/nerd/Discord4J. Copyright (c) 2017, Licensed under GNU LGPLv3

The newest version!
/*
 *     This file is part of Discord4J.
 *
 *     Discord4J is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     Discord4J is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with Discord4J.  If not, see .
 */

package sx.blah.discord.util.cache;

import com.koloboke.collect.set.LongSet;
import com.koloboke.function.LongObjConsumer;
import com.koloboke.function.LongObjFunction;
import com.koloboke.function.LongObjPredicate;
import sx.blah.discord.api.internal.DiscordClientImpl;
import sx.blah.discord.handle.obj.IIDLinkedObject;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 * An internal data structure for storing {@link IIDLinkedObject}s.
 *
 * @param  The type of object stored by the cache.
 */
public final class Cache implements Iterable {

	/**
	 * The default cache delegate provider used by Discord4J.
	 */
	public static final ICacheDelegateProvider DEFAULT_PROVIDER = new DefaultCacheDelegateProvider();
	/**
	 * A cache delegate provider which stores nothing.
	 */
	public static final ICacheDelegateProvider IGNORING_PROVIDER = new IgnoringCacheDelegateProvider();

	/**
	 * The cache's underlying delegate.
	 */
	private volatile ICacheDelegate delegate;

	public Cache(ICacheDelegate delegate) {
		this.delegate = delegate;
	}

	public Cache(DiscordClientImpl client, Class self) {
		this(client.getCacheProvider().provide(self));
	}

	/**
	 * Sets the cache's delegate.
	 *
	 * 

NOTE: No data is copied from the old delegate to the new one. * * @param delegate The new delegate. */ public void setDelegate(ICacheDelegate delegate) { this.delegate = delegate; } /** * Gets the cache's delegate. * * @return The cache delegate. */ public ICacheDelegate getDelegate() { return delegate; } /** * Gets the number of elements stored in the cache. * * @return The number of elements stored in the cache. */ public int size() { return delegate.size(); } /** * Gets whether the cache is empty. * * @return Whether the cache is empty. */ public boolean isEmpty() { return size() < 1; } /** * Gets whether the given key is present in the cache. * * @param key The key to search for. * @return Whether the given key is present in the cache. */ public boolean containsKey(Object key) { if (key instanceof String) { return delegate.contains((String) key); } else if (key instanceof Long) { return delegate.contains((Long) key); } else { return false; } } /** * Gets whether the given key is present in the cache. * * @param key The key to search for. * @return Whether the given key is present in the cache. */ public boolean containsKey(long key) { return delegate.contains(key); } /** * Gets whether the given value is present in the cache. * * @param value The value to search for. * @return Whether the given value is present in the cache. */ public boolean containsValue(Object value) { return value instanceof IIDLinkedObject && delegate.contains((T) value); } /** * Gets an object by its unique snowflake ID. * * @param key The ID of the desired object. * @return The object with the provided ID (or null if one was not found). */ public T get(Object key) { if (key instanceof String) { return delegate.retrieve((String) key).orElse(null); } else if (key instanceof Long) { return delegate.retrieve((Long) key).orElse(null); } else { return null; } } /** * Gets an object by its unique snowflake ID. * * @param key The ID of the desired object. * @return The object with the provided ID (or null if one was not found). */ public T get(long key) { return delegate.retrieve(key).orElse(null); } /** * Gets an object by its unique snowflake ID. If no object is found, the supplier must supply the object instead. * * @param key The ID of the desired object. * @param supplier The supplier to invoke if no object is found. * @return The object with provided ID (or the result of the supplier). */ public T getOrElseGet(Object key, Supplier supplier) { T val = get(key); return val == null ? supplier.get() : val; } /** * Gets an object by its unique snowflake ID. If no object is found, the supplier must supply the object instead. * * @param key The ID of the desired object. * @param supplier The supplier to invoke if no object is found. * @return The object with provided ID (or the result of the supplier). */ public T getOrElseGet(long key, Supplier supplier) { T val = get(key); return val == null ? supplier.get() : val; } /** * Puts an object into the cache. * * @param value The object to put. * @return The previous object that had the same ID or null if there was not one. */ public T put(T value) { return delegate.put(value).orElse(null); } /** * Puts an object into the cache if there is not already a value associated with the given key. * * @param id The ID to associate with the value. * @param valueSupplier The supplier to invoke if the key is absent. * @return Null. */ public T putIfAbsent(String id, Supplier valueSupplier) { if (containsKey(id)) return null; else return put(valueSupplier.get()); } /** * Puts an object into the cache if there is not already a value associated with the given key. * * @param id The ID to associate with the value. * @param valueSupplier The supplier to invoke if the key is absent. * @return Null. */ public T putIfAbsent(long id, Supplier valueSupplier) { if (containsKey(id)) return null; else return put(valueSupplier.get()); } /** * Removes an object from the cache. * * @param obj The ID of the object to remove or the object itself. * @return The object that was removed. */ public T remove(Object obj) { if (obj instanceof String) { return delegate.remove((String) obj).orElse(null); } else if (obj instanceof Long) { return delegate.remove((Long) obj).orElse(null); } else if (obj instanceof IIDLinkedObject) { return delegate.remove((T) obj).orElse(null); } else { return null; } } /** * Removes an object from the cache. * * @param key The ID of the object to remove. * @return The object that was removed. */ public T remove(long key) { return delegate.remove(key).orElse(null); } /** * Puts every element of the given cache into the cache. * * @param objs The objects to insert. * @return Any objects that were replaced by the operation. */ public Collection putAll(Cache objs) { return putAll(objs.values()); } /** * Puts every element of the given collection into the cache. * * @param objs The objects to insert. * @return Any objects that were replaced by the operation. */ public Collection putAll(Collection objs) { return delegate.putAll(objs); } /** * Clears the cache. */ public void clear() { delegate.clear(); } /** * Gets the IDs of every object in the cache. * * @return The IDs of every object in the cache. */ public Collection ids() { return delegate.ids(); } /** * Gets the IDs of every object in the cache. * * @return The IDs of every object in the cache. */ public Collection longIDs() { return delegate.longIDs(); } /** * Gets every value in the cache. * * @return Every value in the cache. */ public Collection values() { return delegate.values(); } /** * See {@link Collection#stream()}. */ public Stream stream() { return delegate.stream(); } /** * See {@link Collection#parallelStream()}. */ public Stream parallelStream() { return delegate.parallelStream(); } /** * Gets a copy of the cache. * * @return A copy of the cache. */ public Cache copy() { return new Cache<>(delegate.copy()); } /** * Gets a copy of the cache as a long map. * * @return A copy of the cache as a long map. */ public LongMap mapCopy() { return delegate.mapCopy(); } /** * Performs the given action for each pair of key and value in the cache. * * @param action The action to perform for each pair of key and value in the cache. */ public void forEach(LongObjConsumer action) { delegate.forEach(action); } /** * Performs the given action for each pair of key and value in the cache while the function returns true. * * @param predicate The action to perform for each pair of key and value in the cache. * @return Whether iterating was interrupted (whether the predicate ever returned false). */ public boolean forEachWhile(LongObjPredicate predicate) { return delegate.forEachWhile(predicate); } /** * Gets the first non-null value produced by the given function which is applied to every pair of keys and values * in the cache. * * @param function The function to apply to each pair. * @return The first non-null value produced by the given function */ public Z findResult(LongObjFunction function) { return delegate.findResult(function); } /** * {@inheritDoc} */ @Override public Iterator iterator() { return delegate.iterator(); } /** * A cache delegate which is backed by a map. */ public static class MapCacheDelegate implements ICacheDelegate { /** * The backing map. */ private final LongMap backing; /** * The lock used for read and write operations. */ private final ReadWriteLock lock = new ReentrantReadWriteLock(); public MapCacheDelegate() { this(LongMap.newMap()); } public MapCacheDelegate(LongMap backing) { this.backing = backing; } @Override public Optional retrieve(long id) { lock.readLock().lock(); try { return Optional.ofNullable(backing.get(id)); } finally { lock.readLock().unlock(); } } @Override public Optional put(T obj) { lock.writeLock().lock(); try { return Optional.ofNullable(backing.put(obj.getLongID(), obj)); } finally { lock.writeLock().unlock(); } } @Override public Optional remove(long id) { lock.writeLock().lock(); try { return Optional.ofNullable(backing.remove(id)); } finally { lock.writeLock().unlock(); } } @Override public Collection clear() { lock.writeLock().lock(); try { Collection cleared = values(); backing.clear(); return cleared; } finally { lock.writeLock().unlock(); } } @Override public boolean contains(long id) { lock.readLock().lock(); try { return backing.containsKey(id); } finally { lock.readLock().unlock(); } } @Override public int size() { lock.readLock().lock(); try { return backing.size(); } finally { lock.readLock().unlock(); } } @Override public Iterator iterator() { lock.readLock().lock(); try { return backing.values().iterator(); } finally { lock.readLock().unlock(); } } @Override public LongSet longIDs() { lock.readLock().lock(); try { return backing.keySet(); } finally { lock.readLock().unlock(); } } @Override public Collection values() { lock.readLock().lock(); try { return backing.values(); } finally { lock.readLock().unlock(); } } @Override public ICacheDelegate copy() { return new MapCacheDelegate<>(mapCopy()); } @Override public LongMap mapCopy() { lock.readLock().lock(); try { return LongMap.copyMap(backing); } finally { lock.readLock().unlock(); } } @Override public void forEach(LongObjConsumer action) { lock.readLock().lock(); try { backing.forEach(action); } finally { lock.readLock().unlock(); } } @Override public boolean forEachWhile(LongObjPredicate predicate) { lock.readLock().lock(); try { return backing.forEachWhile(predicate); } finally { lock.readLock().unlock(); } } @Override public Z findResult(LongObjFunction function) { AtomicReference result = new AtomicReference<>(); forEachWhile((key, value) -> { Z tmp = function.apply(key, value); if (tmp != null) { result.set(tmp); return false; } return true; }); return result.get(); } } /** * A cache delegate which stores nothing. */ public static class IgnoringCacheDelegate implements ICacheDelegate { /** * Returns an empty optional. * * @return An empty optional. */ @Override public Optional retrieve(long id) { return Optional.empty(); } /** * Returns an empty optional. * * @return An empty optional. */ @Override public Optional put(T obj) { return Optional.empty(); } /** * Returns an empty optional. * * @return An empty optional. */ @Override public Optional remove(long id) { return Optional.empty(); } /** * Returns an empty set. * * @return An empty set. */ @Override public Collection clear() { return Collections.emptySet(); } /** * Returns 0. * * @return 0. */ @Override public int size() { return 0; } /** * Returns an empty iterator. * * @return An empty iterator. */ @Override public Iterator iterator() { return Collections.emptyIterator(); } /** * Returns an empty long set. * * @return An empty long set. */ @Override public LongSet longIDs() { return LongMap.EmptyLongSet.INSTANCE; } /** * Returns an empty set. * * @return An empty set. */ @Override public Collection values() { return Collections.emptySet(); } /** * Returns the same cache delegate instance. * * @return The same cache delegate instance. */ @Override public ICacheDelegate copy() { return this; } /** * Returns an empty long map. * * @return An empty long map. */ @Override public LongMap mapCopy() { return LongMap.emptyMap(); } /** * No-op. Does nothing. */ @Override public void forEach(LongObjConsumer action) {} /** * No-op. Does nothing. * * @return True. */ @Override public boolean forEachWhile(LongObjPredicate predicate) { return true; } /** * No-op. Does nothing. * * @return Null. */ @Override public Z findResult(LongObjFunction function) { return null; } } } /** * The default cache delegate provider used by Discord4J. Always provides a {@link Cache.MapCacheDelegate}. */ class DefaultCacheDelegateProvider implements ICacheDelegateProvider { @Override public ICacheDelegate provide(Class clazz) { return new Cache.MapCacheDelegate<>(); } } /** * A cache delegate provider which always provides {@link Cache.IgnoringCacheDelegate}. */ class IgnoringCacheDelegateProvider implements ICacheDelegateProvider { @Override public ICacheDelegate provide(Class clazz) { return new Cache.IgnoringCacheDelegate<>(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy