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

objectos.way.UtilSet Maven / Gradle / Ivy

Go to download

Objectos Way allows you to build full-stack web applications using only Java.

The newest version!
/*
 * Copyright (C) 2022-2023 Objectos Software LTDA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package objectos.way;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.RandomAccess;
import java.util.Set;

/**
 * A hash-based {@link Set} and {@link UtilGrowableCollection} implementation.
 *
 * @param  type of the elements in this set
 */
final class UtilSet extends UtilBaseCollection implements Set {

  private static final int MAX_POSITIVE_POWER_OF_TWO = 1 << 30;

  private static final float DEFAULT_LOAD_FACTOR = 0.75F;

  private static final int FIRST_RESIZE = 4;

  private static final int MAX_ARRAY_LENGTH = MAX_POSITIVE_POWER_OF_TWO;

  private Object[] array = Util.EMPTY_OBJECT_ARRAY;

  private final float loadFactor = DEFAULT_LOAD_FACTOR;

  private int rehashSize;

  private int size = 0;

  /**
   * Creates a new {@code GrowableSet} instance.
   */
  public UtilSet() {}

  /**
   * Adds the specified element to this set if it is not already present.
   *
   * @param e
   *        an element to be added to this set
   *
   * @return {@code true} if this set was modified as a result of this
   *         operation. {@code false} if the element was already present in this
   *         set
   *
   * @throws NullPointerException
   *         if the specified element is {@code null}
   */
  @Override
  public final boolean add(E e) {
    return addWithNullMessage(e, "e == null");
  }

  /**
   * Adds all of the elements in the specified collection to this set if they
   * are not already present.
   *
   * 

* The behavior of this operation is undefined if the specified collection is * modified while the operation is in progress. (This implies that the * behavior of this call is undefined if the specified collection is this * set, and this set is nonempty.) * * @param c * a collection containing the elements to be added to this set * * @return {@code true} if this set was modified as a result of this * operation. {@code false} if all of the elements were already * present in this set * * @throws NullPointerException * if the specified collection is {@code null} or if it contains any * element that is {@code null} */ @Override public final boolean addAll(Collection c) { Check.notNull(c, "c == null"); return addAll0(c, "c["); } /** * Adds all of the elements returned by the specified iterable's iterator to * this set if they are not already present. * *

* The behavior of this operation is undefined if the specified iterable is * modified while the operation is in progress. (This implies that the * behavior of this call is undefined if the specified iterable is this list, * and this list is nonempty.) * * @param iterable * {@code Iterable} containing elements to be added to this set * * @return {@code true} if this set was modified as a result of this * operation. {@code false} if all of the elements were already * present in this set * * @throws NullPointerException * if the specified iterable is {@code null} or if it provides any * element that is {@code null} */ public final boolean addAllIterable(Iterable iterable) { Check.notNull(iterable, "iterable == null"); return addAll0(iterable, "iterable["); } /** * Adds the specified element {@code e} to this set if it is not already * present. * *

* If a {@code NullPointerException} is to be thrown, the {@code nullMessage} * value is used as the exception's message. * *

* Typical usage: * *

   * set.addWithNullMessage(value, "value == null");
* * @param e * an element to be added to this set (if it not null) * @param nullMessage * the {@code NullPointerException} message * * @return {@code true} if this set was modified as a result of this * operation. {@code false} if the element was already present in this * set * * @throws NullPointerException * if the specified element is {@code null} * * @see Check#notNull(Object, Object) */ public final boolean addWithNullMessage(E e, Object nullMessage) { Check.notNull(e, nullMessage); return addUnchecked(e); } /** * Adds the specified element {@code e} to this set if it is not already * present. * *

* If a {@code NullPointerException} is to be thrown, the concatenation of * {@code nullMessageStart}, {@code index} and {@code nullMessageEnd} is * used as the exception's message. * *

* Typical usage: * *

   * set.addWithNullMessage(element, "elements[", index, "] == null");
* * @param e * an element to be added to this set (if it not null) * @param nullMessageStart * the first part of the {@code NullPointerException} message * @param index * the second part of the {@code NullPointerException} message * @param nullMessageEnd * the third part of the {@code NullPointerException} message * * @return {@code true} if this set was modified as a result of this * operation. {@code false} if the element was already present in this * set * * @see Check#notNull(Object, Object, int, Object) */ public final boolean addWithNullMessage( E e, Object nullMessageStart, int index, Object nullMessageEnd) { Check.notNull(e, nullMessageStart, index, nullMessageEnd); return addUnchecked(e); } /** * Removes all of the elements from this set. */ @Override public final void clear() { Arrays.fill(array, null); size = 0; } /** * Returns {@code true} if this set contains the specified element. More * formally, returns {@code true} if and only if this set contains at least * one element {@code e} such that {@code e.equals(o)}. * * @param o * an element to check for presence in this set * * @return {@code true} if this set contains the specified value */ @Override public final boolean contains(Object o) { return UtilSets.containsImpl(array, size, o); } /** *

* Compares the specified object with this set for equality. Returns * {@code true} if and only if * *

    *
  • the specified object is also a {@link Set};
  • *
  • both sets have same size; and
  • *
  • each element in this set is also present in the specified set.
  • *
* * @param obj * the object to be compared for equality with this set * * @return {@code true} if the specified object is equal to this set */ @Override public final boolean equals(Object obj) { return UtilSets.equalsImpl(this, obj); } /** * Returns the hash code value of this set. * * @return the hash code value of this set */ @Override public final int hashCode() { return UtilSets.hashCodeImpl(array); } /** * Returns an iterator over the elements in this set. The elements * are returned in no particular order. * * @return an iterator over the elements in this set */ @Override public final Util.UnmodifiableIterator iterator() { return new UtilSets.SetIterator<>(array); } /** * Returns the size of this set. The size of a set is equal to the number of * elements it contains. * * @return the size of this set */ @Override public final int size() { return size; } /** * Returns a new array instance containing all of the elements in this set. * The returned array length is equal to the size of this set. * * @return a new array instance containing all of the elements in this set */ @Override public final Object[] toArray() { return UtilSets.toArrayImpl(array, size); } /** * Returns an array, either the specified array or a new array instance, * containing all of the elements in this set. * *

* The specified array is used as the return value if it is large enough to * hold all of the elements in this set. Additionally, if the specified * array is such that {@code a.length > size()} then the position after the * last element is set to {@code null}. * *

* If the specified array is not large enough, then a new array is created, * with the same runtime type of the specified array, and used as the return * value. * * @param a * the array into which the elements of the set are to be stored, if * it is big enough; otherwise, a new array of the same runtime type is * allocated for this purpose. * * @return an array containing the elements of the set */ @Override public final T[] toArray(T[] a) { return UtilSets.toArrayImpl(array, size, a); } /** * Returns an {@link UtilUnmodifiableSet} copy of this set. * *

* The returned {@code UnmodifiableSet} will contain all of the elements from * this set. * *

* The returned set will be a copy in the sense that, after this method * returns, modifying this set will have no effect on the returned (copied) * one. * *

* Note, however, that the behaviour of this method is undefined if this set * is modified while the copy is being made. * * @return an {@link UtilUnmodifiableSet} copy of this set */ public final UtilUnmodifiableSet toUnmodifiableSet() { switch (size) { case 0: return UtilUnmodifiableSet.of(); default: Object[] copy; copy = Arrays.copyOf(array, array.length); return new UtilUnmodifiableSetN(copy, size); } } @Override public final String toString() { return UtilSets.toStringImpl(this, array); } final boolean addAll0(Iterable iterable, String nullMessageStart) { var mod = false; if (iterable instanceof RandomAccess && iterable instanceof List list) { for (int i = 0, size = list.size(); i < size; i++) { var element = list.get(i); Check.notNull(element, nullMessageStart, i, "] == null"); if (addUnchecked(element)) { mod = true; } } } else { int i = 0; for (E element : iterable) { Check.notNull(element, nullMessageStart, i, "] == null"); if (addUnchecked(element)) { mod = true; } i++; } } return mod; } final boolean addUnchecked(E e) { firstResizeIfNecessary(); int index, marker; index = marker = hashIndex(e); Object existing; while (index < array.length) { existing = array[index]; if (existing == null) { insert(index, e); return true; } else if (existing.equals(e)) { return false; } else { index++; } } index = 0; while (index < marker) { existing = array[index]; if (existing == null) { insert(index, e); return true; } else if (existing.equals(e)) { return false; } else { index++; } } throw new UnsupportedOperationException("Implement me"); } private void firstResizeIfNecessary() { if (array == Util.EMPTY_OBJECT_ARRAY) { resizeTo(FIRST_RESIZE); } } private int hashIndex(Object e) { int hc = e.hashCode(); int mask = array.length - 1; return hc & mask; } private void insert(int index, E e) { array[index] = e; size++; rehashIfNecessary(); } private void rehashIfNecessary() { if (size < rehashSize) { return; } if (array.length == MAX_ARRAY_LENGTH) { throw new OutOfMemoryError("backing array already at max allowed length"); } var previous = array; var newLength = array.length << 1; if (newLength < 0) { newLength = MAX_ARRAY_LENGTH; } resizeTo(newLength); outer: // for (Object e : previous) { if (e == null) { continue; } int probe, index; probe = index = hashIndex(e); Object existing; while (probe < array.length) { existing = array[probe]; if (existing == null) { array[probe] = e; continue outer; } else { probe++; } } probe = 0; while (probe < index) { existing = array[probe]; if (existing == null) { array[probe] = e; continue outer; } else { probe++; } } throw new UnsupportedOperationException("Implement me"); } } private void resizeTo(int newSize) { array = new Object[newSize]; rehashSize = (int) (array.length * loadFactor); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy