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

com.igormaznitsa.mistack.impl.AbstractMiStackList Maven / Gradle / Ivy

/*
 * Copyright 2022 Igor Maznitsa
 *
 * 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 com.igormaznitsa.mistack.impl;

import static java.util.Objects.requireNonNull;

import com.igormaznitsa.mistack.MiStack;
import com.igormaznitsa.mistack.MiStackItem;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Predicate;


/**
 * Class allows to build MiStacks based on java.util.List collections.
 *
 * @param  type of values placed on stack
 * @see java.util.List
 * @since 1.0.0
 */
public abstract class AbstractMiStackList implements MiStack {

  protected final List> list;
  private final String name;
  private boolean closed = false;

  /**
   * Constructor for name and list collection which will be used as the store for items.
   *
   * @param name name of the stack, can't be null
   * @param list internal storage for items, can't be null
   * @since 1.0.0
   */
  public AbstractMiStackList(final String name, final List> list) {
    this.name = requireNonNull(name);
    this.list = requireNonNull(list);
  }

  /**
   * Get the list used as store for items.
   *
   * @return the base list store, can't be null
   * @since 1.0.0
   */
  protected List> getList() {
    return this.list;
  }

  @Override
  public MiStack push(final MiStackItem item) {
    this.assertNotClosed();
    this.list.add(requireNonNull(item));
    return this;
  }

  @Override
  public Optional> pop(final Predicate> predicate) {
    this.assertNotClosed();
    var iterator = this.makeItemIterator(this.list);
    MiStackItem result = null;
    while (iterator.hasNext() && result == null) {
      result = iterator.next();
      if (predicate.test(result)) {
        iterator.remove();
      } else {
        result = null;
      }
    }
    return Optional.ofNullable(result);
  }

  @Override
  public Iterator> iterator(final Predicate> predicate,
                                           final Predicate> takeWhile) {

    var listIterator = this.makeItemIterator(this.list);
    return new Iterator<>() {

      private boolean completed = false;
      private MiStackItem foundItem = null;

      @Override
      public boolean hasNext() {
        if (isClosed()) {
          this.foundItem = null;
          this.completed = true;
          return false;
        }
        if (this.foundItem == null) {
          this.foundItem = findNext();
        }
        return this.foundItem != null;
      }

      private MiStackItem findNext() {
        assertNotClosed();
        if (this.completed) {
          return null;
        }
        MiStackItem result = null;
        while (result == null && listIterator.hasNext()) {
          result = listIterator.next();
          if (predicate.test(result)) {
            if (!takeWhile.test(result)) {
              result = null;
              this.completed = true;
              break;
            }
          } else {
            result = null;
          }
        }
        return result;
      }

      @Override
      public MiStackItem next() {
        assertNotClosed();
        if (this.foundItem == null) {
          this.foundItem = this.findNext();
          if (this.foundItem == null) {
            throw new NoSuchElementException();
          }
        }
        var result = this.foundItem;
        this.foundItem = null;
        return result;
      }

      @Override
      public void remove() {
        assertNotClosed();
        listIterator.remove();
      }
    };
  }

  @Override
  public boolean isClosed() {
    return this.closed;
  }

  @Override
  public String getName() {
    return this.name;
  }

  @Override
  public Optional> peek(final Predicate> predicate,
                                       final long depth) {
    this.assertNotClosed();
    return this.stream(predicate).skip(depth).findFirst();
  }

  @Override
  public Optional> remove(final Predicate> predicate, long depth) {
    this.assertNotClosed();
    MiStackItem result = null;
    var iterator = this.iterator(predicate);
    while (depth >= 0 && iterator.hasNext()) {
      result = iterator.next();
      if (depth == 0) {
        depth = -1L;
        iterator.remove();
      } else {
        depth--;
      }
    }
    return Optional.ofNullable(result);
  }

  @Override
  public void clear() {
    this.assertNotClosed();
    this.list.clear();
    this.afterClear();
  }

  @Override
  public void clear(final Predicate> predicate) {
    this.assertNotClosed();
    final Iterator> iterator = this.iterator(predicate);
    while (iterator.hasNext()) {
      iterator.next();
      iterator.remove();
    }
    this.afterClear();
  }

  @Override
  public boolean isEmpty() {
    this.assertNotClosed();
    return this.list.isEmpty();
  }

  /**
   * Find number of all elements on the stack.
   *
   * @return number of all elements on the stack.
   * @throws IllegalStateException if stack is closed
   * @since 1.0.0
   */
  @Override
  public long size() {
    this.assertNotClosed();
    return this.list.size();
  }

  /**
   * Dispose the stack and free its resources.
   *
   * @throws IllegalStateException if stack is closed
   * @since 1.0.0
   */
  @Override
  public void close() {
    this.assertNotClosed();
    this.closed = true;
    this.list.clear();
    this.afterClear();
  }

  /**
   * Method is called after clear operations. Allow for instance to trim collection.
   *
   * @since 1.0.0
   */
  protected void afterClear() {

  }

  /**
   * Make iterator for stack items in appropriate order for stack.
   *
   * @param list list to be sourced for the iterator, must not be null
   * @return created iterator for the list, must not be null
   * @since 1.0.0
   */
  protected abstract Iterator> makeItemIterator(final List> list);

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy