Package com.edugility.objexj.engine

Source Code of com.edugility.objexj.engine.Engine

/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil -*-
*
* Copyright (c) 2013 Edugility LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* The original copy of this license is available at
* http://www.opensource.org/license/mit-license.html.
*/
package com.edugility.objexj.engine;

import java.io.IOException;
import java.io.PushbackReader;
import java.io.StringReader;

import java.util.LinkedList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

import java.util.concurrent.atomic.AtomicInteger;

import java.util.logging.Level;
import java.util.logging.Logger;

import com.edugility.objexj.parser.Parser;

/**
* A stateless regular-expression-processing virtual machine made to
* run {@link Program}s against {@link List}s of input using {@link
* com.edugility.objexj.engine.Thread}s.
*
* @param <T> the type of {@link Object}s that {@link List}s supplied
* to the {@link #run(Program, List)} method will consist of
*
* @author <a href="http://about.me/lairdnelson"
* target="_parent">Laird Nelson</a>
*
* @see #run(Program, List)
*
* @see <a
* href="http://swtch.com/~rsc/regexp/regexp2.html" target="_parent">R. S. Cox. (2009,
* December). <span style="font-style: italic;">Regular Expression Matching: the Virtual Machine
* Approach</span> [Online]. Available:
* http://swtch.com/~rsc/regexp/regexp2.html</a>
*/
public class Engine<T> {


  /*
   * Constructors.
   */


  /**
   * Creates a new {@link Engine}.
   */
  public Engine() {
    super();
  }


  /*
   * Instance methods.
   */


  /**
   * Runs the supplied {@link Program} against the supplied {@link
   * List} and returns a (possibly {@code null}) {@link MatchResult}
   * describing the run result.
   *
   * @param program the {@link Program} to run; must not be {@code
   * null}
   *
   * @param items the input {@link List}; may be {@code null}
   *
   * @return a {@link MatchResult}, or {@code null} if no match
   * occurred
   *
   * @exception IllegalArgumentException if {@code program} is {@code
   * null}
   */
  public MatchResult<? extends T> run(final Program<T> program, final List<? extends T> items) {
    if (program == null) {
      throw new IllegalArgumentException("program", new NullPointerException("program"));
    }
    final AtomicInteger idGenerator = new AtomicInteger();
    final Queue<Thread<T>> threads = new LinkedList<Thread<T>>();
    final Scheduler<T> scheduler = new Scheduler<T>(threads, idGenerator);

    scheduler.schedule(scheduler.newThread(String.format("T%d", idGenerator.getAndIncrement()),
                                           new ProgramCounter<T>(program),
                                           items,
                                           0,
                                           null,
                                           null));
    MatchResult<? extends T> result = null;
    while (!threads.isEmpty()) {
      final Thread<T> thread = threads.remove();
      if (thread != null) {
        thread.run();
        if (Thread.State.MATCH == thread.getState()) {
          result = new MatchResult<T>(thread);
          break;
        }
      }
    }
    return result;
  }


  /*
   * Inner and nested classes.
   */


  /**
   * A {@link ThreadScheduler} that schedules {@link Thread}s in a
   * simplistic, sequential manner.
   *
   * @author <a href="http://about.me/lairdnelson"
   * target="_parent">Laird Nelson</a>
   */
  private static final class Scheduler<T> implements ThreadScheduler<T> {

    /**
     * A {@link Queue} of scheduled {@link Thread}s.  This field may
     * be {@code null}.
     */
    private final Queue<Thread<T>> threads;

    /**
     * An {@link AtomicInteger} used to generate {@link Thread}
     * identifiers.  This field is never {@code null}.
     */
    private final AtomicInteger idGenerator;

    /**
     * Creates a new {@link Scheduler}.
     *
     * @param threads a {@lik Queue} of {@link Thread}s; may be {@code
     * null}
     */
    private Scheduler(final Queue<Thread<T>> threads) {
      this(threads, new AtomicInteger());
    }

    /**
     * Creates a new {@link Scheduler}.
     *
     * @param threads a {@link Queue} of {@link Thread}s; may be
     * {@code null}
     *
     * @param idGenerator an {@link AtomicInteger} to help with {@link
     * Thread} identifier generation; may be {@code null}
     */
    private Scheduler(final Queue<Thread<T>> threads, final AtomicInteger idGenerator) {
      super();
      this.threads = threads;
      if (idGenerator == null) {
        this.idGenerator = new AtomicInteger();
      } else {
        this.idGenerator = idGenerator;
      }
    }

    /**
     * Creates a new {@link Thread}.
     *
     * @param id the identifier for the new {@link Thread}; may be
     * {@code null} in which case a default identifier will be used
     * instead
     *
     * @param programCounter a {@link ProgramCounter}; must not be {@code null}
     *
     * @param items the input {@link List} to read from; may be {@code
     * null} in which case the supplied {@code itemPointer} must be
     * equal to {@code 0} or {@link Thread#VALID_NO_INPUT_POINTER}
     *
     * @param itemPointer the index within the supplied {@code items}
     * {@link List} from which to begin {@linkplain Thread#read()
     * reading}; must be zero or a positive integer less than the
     * supplied {@code items} {@linkplain Collection#size() size}, or
     * must be equal to {@link Thrad#VALID_NO_INPUT_POINTER} provided
     * that the {@code items} {@link List} is {@code null} or
     * {@linkplain Collection#isEmpty() empty}
     *
     * @param captureGroups a {@link Map} of {@link CaptureGroup}s
     * indexed by key that this new {@link Thread} will use to store
     * {@linkplain Thread#getSubmatches() submatches}; may be {@code
     * null}
     *
     * @param variables a {@link Map} of variables the new {@link
     * Thread} will be initialized with; may be {@code null}
     *
     * @exception IllegalArgumentException if any of the preconditions
     * outlined as part of the parameter descriptions is not fulfilled
     */
    @Override
    public final Thread<T> newThread(Object id, final ProgramCounter<T> programCounter, final List<? extends T> items, final int itemPointer, final Map<Object, CaptureGroup<T>> captureGroups, final Map<Object, Object> variables) {
      final String className = this.getClass().getName();
      final Logger logger = Logger.getLogger(className);
      final boolean finer = logger != null && logger.isLoggable(Level.FINER);
      if (finer) {
        logger.entering(className, "newThread", new Object[] { id, programCounter, items, itemPointer, captureGroups, variables });
      }     
      if (id == null) {
        id = String.format("T%d", this.idGenerator.getAndIncrement());
      }
      final Thread<T> returnValue = new Thread<T>(id, programCounter, items, itemPointer, captureGroups, variables, this);
      if (finer) {
        logger.exiting(className, "newThread", returnValue);
      }
      return returnValue;
    }
     
    /**
     * Schedules the supplied {@link Thread} for execution.  This
     * implementation of the {@link ThreadScheduler#schedule(Thread)}
     * method adds the supplied {@link Thread} to the end of a
     * first-in-last-out {@link Queue} of scheduled {@link Thread}s.
     *
     * @param t the {@link Thread} to schedule; must not be {@code
     * null}
     *
     * @return {@code true} if the supplied {@link Thread} was
     * actually scheduled; {@code false} if this {@link Scheduler}
     * concluded that&mdash;for whatever reason&mdash;that the
     * supplied {@link Thread} could not be scheduled
     *
     * @exception IllegalArgumentException if {@code t} is {@code
     * null}
     */
    @Override
    public final boolean schedule(final Thread<T> t) {
      final String className = this.getClass().getName();
      final Logger logger = Logger.getLogger(className);
      final boolean finer = logger != null && logger.isLoggable(Level.FINER);
      if (finer) {
        logger.entering(className, "schedule", t);
      }
      if (t == null) {
        throw new IllegalArgumentException("t", new NullPointerException("t"));
      }
      if (finer) {
        logger.logp(Level.FINER, className, "schedule", "Scheduling thread {0}", t);
      }
      final boolean returnValue = this.threads != null && this.threads.add(t);
      if (finer) {
        logger.exiting(className, "schedule", Boolean.valueOf(returnValue));
      }
      return returnValue;
    }
  }

}
TOP

Related Classes of com.edugility.objexj.engine.Engine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.