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

arez.TaskQueue Maven / Gradle / Ivy

There is a newer version: 0.213
Show newest version
package arez;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.realityforge.braincheck.Guards.*;

/**
 * A queue of "pending" or "scheduled" tasks that supports priority based queuing of tasks.
 */
final class TaskQueue
{
  /**
   * A buffer per priority containing tasks that have been scheduled but are not executing.
   */
  @Nonnull
  private final CircularBuffer[] _buffers;

  /**
   * Construct queue with specified priority count where each priority is backed by a buffer with specified size.
   *
   * @param priorityCount   the number of priorities supported.
   * @param initialCapacity the initial size of buffer for each priority.
   */
  @SuppressWarnings( { "unchecked", "rawtypes", "RedundantSuppression" } )
  TaskQueue( final int priorityCount, final int initialCapacity )
  {
    assert priorityCount > 0;
    assert initialCapacity > 0;
    _buffers = (CircularBuffer[]) new CircularBuffer[ priorityCount ];
    for ( int i = 0; i < priorityCount; i++ )
    {
      _buffers[ i ] = new CircularBuffer<>( initialCapacity );
    }
  }

  /**
   * Return the number of priorities handled by the queue.
   *
   * @return the number of priorities handled by the queue.
   */
  int getPriorityCount()
  {
    return _buffers.length;
  }

  /**
   * Return the number of tasks inside the queue.
   *
   * @return the number of tasks inside the queue.
   */
  int getQueueSize()
  {
    int count = 0;
    //noinspection ForLoopReplaceableByForEach
    for ( int i = 0; i < _buffers.length; i++ )
    {
      count += _buffers[ i ].size();
    }
    return count;
  }

  /**
   * Return true if queue has any tasks in it.
   *
   * @return true if queue has any tasks in it.
   */
  boolean hasTasks()
  {
    //noinspection ForLoopReplaceableByForEach
    for ( int i = 0; i < _buffers.length; i++ )
    {
      if ( _buffers[ i ].isNotEmpty() )
      {
        return true;
      }
    }
    return false;
  }

  /**
   * Add the specified task to the queue.
   * The task must not already be in the queue.
   *
   * @param task the task.
   */
  void queueTask( @Nonnull final Task task )
  {
    queueTask( task.getPriorityIndex(), task );
  }

  /**
   * Add the specified task to the queue.
   * The task must not already be in the queue.
   *
   * @param priority the task priority.
   * @param task     the task.
   */
  void queueTask( final int priority, @Nonnull final Task task )
  {
    if ( Arez.shouldCheckInvariants() )
    {
      invariant( () -> Arrays.stream( _buffers ).noneMatch( b -> b.contains( task ) ),
                 () -> "Arez-0099: Attempting to queue task named '" + task.getName() +
                       "' when task is already queued." );
      invariant( () -> priority >= 0 && priority < _buffers.length,
                 () -> "Arez-0215: Attempting to queue task named '" + task.getName() +
                       "' but passed an invalid priority " + priority + "." );
    }
    Objects.requireNonNull( task ).markAsQueued();
    _buffers[ priority ].add( Objects.requireNonNull( task ) );
  }

  /**
   * Remove and return the next task in queue.
   * This may return null if there is no tasks in the quue.
   *
   * @return the next task in queue.
   */
  @Nullable
  Task dequeueTask()
  {
    // Return the highest priority taskQueue that has tasks in it and return task.
    //noinspection ForLoopReplaceableByForEach
    for ( int i = 0; i < _buffers.length; i++ )
    {
      final CircularBuffer taskQueue = _buffers[ i ];
      if ( taskQueue.isNotEmpty() )
      {
        final Task task = taskQueue.pop();
        assert null != task;
        return task;
      }
    }
    return null;
  }

  /**
   * Clear all tasks from queue and return any tasks removed.
   *
   * @return tasks removed from the queue.
   */
  @Nonnull
  Collection clear()
  {
    final List tasks = new ArrayList<>();
    //noinspection ForLoopReplaceableByForEach
    for ( int i = 0; i < _buffers.length; i++ )
    {
      final CircularBuffer buffer = _buffers[ i ];
      Task task;
      while ( null != ( task = buffer.pop() ) )
      {
        tasks.add( task );
        task.markAsIdle();
      }
    }
    return tasks;
  }

  /**
   * Return a stream containing tasks ordered as they would be executed.
   * This method may be very slow and should not be invoked during production compiles.
   * It is only expected to be called from invariant checking code.
   *
   * @return a stream containing tasks ordered as they would be executed.
   */
  @Nonnull
  Stream getOrderedTasks()
  {
    assert Arez.shouldCheckInvariants() || Arez.shouldCheckApiInvariants();
    return Stream.of( _buffers ).flatMap( CircularBuffer::stream );
  }

  @Nonnull
  CircularBuffer getBufferByPriority( final int priority )
  {
    return _buffers[ priority ];
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy