content: package zemberek.core.collections;
  
  /**
   * A Set-like data structure that allows looking up if an equivalent instance exists in it.
   */
  public class LookupSet<T> extends HashBase<T> implements Iterable<T> {
  
    public LookupSet() {
      this(INITIAL_SIZE);
    }
  
    public LookupSet(int size) {
      super(size);
    }
  
    private void expand() {
      LookupSet<T> h = new LookupSet<>(newSize());
      for (T key : keys) {
        if (key != null && key != TOMB_STONE) {
          h.set(key);
        }
      }
      expandCopyParameters(h);
    }
  
    /**
     * Adds this key to Set. If there is an equivalent exist, it overrides it. if there was an
     * equivalent key, it returns it. Otherwise returns null.
     *
     * @param key key
     */
    public T set(T key) {
      if (key == null) {
        throw new IllegalArgumentException("Key cannot be null.");
      }
      if (keyCount + removeCount == threshold) {
        expand();
      }
      int loc = locate(key);
      if (loc >= 0) {
        T old = keys[loc];
        keys[loc] = key;
        return old;
      } else {
        loc = -loc - 1;
        keys[loc] = key;
        keyCount++;
        return null;
      }
    }
  
    @SafeVarargs
    public final void addAll(T... t) {
      for (T t1 : t) {
        add(t1);
      }
    }
  
    public void addAll(Iterable<T> it) {
      for (T t1 : it) {
        add(t1);
      }
    }
  
    /**
     * If there is an equivalent object, it does nothing and returns false. Otherwise it adds the item
     * to set and returns true.
     *
     * @param key input
     */
    public boolean add(T key) {
      if (key == null) {
        throw new IllegalArgumentException("Key cannot be null.");
      }
      if (keyCount + removeCount == threshold) {
        expand();
      }
      int loc = locate(key);
      if (loc >= 0) {
        return false;
      } else {
        loc = -loc - 1;
        keys[loc] = key;
        keyCount++;
        return true;
      }
    }
  
    /**
     * If there is an equivalent object, returns it. Otherwise adds it and returns the input.
     *
     * @param key input.
     */
    public T getOrAdd(T key) {
      if (key == null) {
        throw new IllegalArgumentException("Key cannot be null.");
      }
      if (keyCount + removeCount == threshold) {
        expand();
      }
      int loc = locate(key);
      if (loc >= 0) {
        return keys[loc];
      } else {
        loc = -loc - 1;
        keys[loc] = key;
        keyCount++;
        return key;
      }
    }
  }
  