package com.github.liblevenshtein.collection.dictionary; import java.io.Serializable; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Map; import it.unimi.dsi.fastutil.chars.CharIterator; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.extern.slf4j.Slf4j; /** * Provides common logic for all my Dawg implementations. Currently, there is * only the {@link SortedDawg} implementation, but I have plans for other kinds. * @author Dylon Edwards * @since 2.1.0 */ @Slf4j @EqualsAndHashCode(of = {"size", "root"}, callSuper = false) public abstract class Dawg extends AbstractSet<String> implements IFinalFunction<DawgNode>, ITransitionFunction<DawgNode>, Serializable { private static final long serialVersionUID = 1L; /** * Root node of this trie. */ @Getter protected DawgNode root = null; /** * Number of terms in this trie. * @return Number of terms in this trie. */ @Getter(onMethod = @__({@Override})) protected int size = 0; /** * Initializes an {@link Dawg}. * @param root Root node of this DAWG. * @param size Number of terms in the dictionary. */ protected Dawg( final DawgNode root, final int size) { this.root = root; this.size = size; } /** * Initializes an {@link Dawg}. */ public Dawg() { this(new DawgNode(), 0); } /** * {@inheritDoc} */ @Override public boolean at(final DawgNode node) { return node.isFinal(); } /** * {@inheritDoc} */ @Override public DawgNode of(final DawgNode node, final char label) { return node.transition(label); } /** * {@inheritDoc} */ @Override public CharIterator of(final DawgNode node) { return node.labels(); } /** * {@inheritDoc} */ @Override public abstract boolean add(final String term); /** * {@inheritDoc} */ @Override public synchronized boolean addAll(final Collection<? extends String> terms) { int counter = 0; for (final String term : terms) { if (!add(term)) { return false; } if (++counter % 10_000 == 0) { log.info("Added [{}] of [{}] terms", counter, terms.size()); } } return true; } /** * {@inheritDoc} */ @Override public abstract boolean remove(final Object term); /** * {@inheritDoc} */ @Override public boolean contains(final Object o) { if (!(o instanceof String)) { return false; } @SuppressWarnings("unchecked") final String term = (String) o; DawgNode node = root; for (int i = 0; i < term.length() && null != node; ++i) { final char label = term.charAt(i); node = node.transition(label); } return null != node && node.isFinal(); } /** * {@inheritDoc} */ @Override public Iterator<String> iterator() { return new DawgIterator(root, this); } /** * [Optional Operation] Replaces the String, current, with another. * @param current String in this DAWG to replace * @param replacement String to replace the current one with * @return Whether the replacement was successful. */ public boolean replace(final String current, final String replacement) { throw new UnsupportedOperationException("replace is not supported"); } /** * [Optional Operation] Replaces all instances of the term keys with their * values. * @param c Replacment mappings. * @return Whether all replacements were successful. */ public boolean replaceAll(final Collection<? extends Map.Entry<String, String>> c) { throw new UnsupportedOperationException("replaceAll is not supported"); } @Override public String toString() { return String.format("%s(size=%d)", getClass().getSimpleName(), size); } }