001: // ============================================================================
002: // $Id: FindIterator.java,v 1.17 2005/08/02 23:45:22 davidahall Exp $
003: // Copyright (c) 2002-2005 David A. Hall
004: // ============================================================================
005: // The contents of this file are subject to the Common Development and
006: // Distribution License (CDDL), Version 1.0 (the License); you may not use this
007: // file except in compliance with the License. You should have received a copy
008: // of the the License along with this file: if not, a copy of the License is
009: // available from Sun Microsystems, Inc.
010: //
011: // http://www.sun.com/cddl/cddl.html
012: //
013: // From time to time, the license steward (initially Sun Microsystems, Inc.) may
014: // publish revised and/or new versions of the License. You may not use,
015: // distribute, or otherwise make this file available under subsequent versions
016: // of the License.
017: //
018: // Alternatively, the contents of this file may be used under the terms of the
019: // GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
020: // case the provisions of the LGPL are applicable instead of those above. If you
021: // wish to allow use of your version of this file only under the terms of the
022: // LGPL, and not to allow others to use your version of this file under the
023: // terms of the CDDL, indicate your decision by deleting the provisions above
024: // and replace them with the notice and other provisions required by the LGPL.
025: // If you do not delete the provisions above, a recipient may use your version
026: // of this file under the terms of either the CDDL or the LGPL.
027: //
028: // This library is distributed in the hope that it will be useful,
029: // but WITHOUT ANY WARRANTY; without even the implied warranty of
030: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
031: // ============================================================================
032:
033: package net.sf.jga.util;
034:
035: import java.util.Iterator;
036: import java.util.NoSuchElementException;
037: import net.sf.jga.fn.UnaryFunctor;
038:
039: /**
040: * Iterator that provides the ability to skip to the first/next element that
041: * meets a particular criteria.
042: * <p>
043: * Copyright © 2003-2005 David A. Hall
044: *
045: * @author <a href="mailto:davidahall@users.sourceforge.net">David A. Hall</a>
046: **/
047:
048: public class FindIterator<T> implements Iterator<T>, Iterable<T> {
049:
050: // The next element in the base iterator to be returned
051: private T _next;
052:
053: // The base iterator
054: private Iterator<? extends T> _base;
055:
056: // Flag indicating that there is an element ready to be returned.
057: private Boolean _baseHasNext;
058:
059: /**
060: * Builds a FindIterator for the given iterator.
061: */
062: public FindIterator(Iterator<? extends T> iter) {
063: _base = (iter != null) ? iter : new EmptyIterator<T>();
064: }
065:
066: /**
067: * Returns true if at least one instance remaining in the iteration yields
068: * true when passed to the filter. This operation can advance the base
069: * iterator. It will not, however, advance the base iterator if it is
070: * called multiple times in succession without having retrieved the value.
071: */
072: public boolean findNext(UnaryFunctor<T, Boolean> filter) {
073: if (filter == null)
074: return hasNext();
075:
076: // test if we've already advanced via hasNext or foundNext
077: if (_baseHasNext != null) {
078: // if there is at least one more element to test
079: if (_baseHasNext) {
080: // if the next value to return passes the filter, then
081: // we already have the next item to be found.
082: if (filter.fn(_next)) {
083: return true;
084: }
085:
086: // otherwise fall through -- the current 'next' object doesn't
087: // pass the selection criteria, so we need to discard it
088: } else {
089: return false;
090: }
091: }
092:
093: // we don't know if there is another element that passes the filter,
094: // so we advance the base iterator and test every item until we fall
095: // off the end or find an item that passes
096: while (_base.hasNext()) {
097: T elem = _base.next();
098: if (filter.fn(elem)) {
099: _next = elem;
100: _baseHasNext = Boolean.TRUE;
101: return true;
102: }
103: }
104:
105: _next = null;
106: _baseHasNext = Boolean.FALSE;
107: return false;
108: }
109:
110: // - - - - - - - - - - -
111: // Iterable<T> interface
112: // - - - - - - - - - - -
113:
114: public Iterator<T> iterator() {
115: return this ;
116: }
117:
118: // - - - - - - - - - - - - -
119: // ListIterator<T> interface
120: // - - - - - - - - - - - - -
121:
122: /**
123: * Returns true if there is at least one instance remaining in the
124: * iteration. This operation can advance the base iterator. It will not,
125: * however, advance the base iterator if it is called multiple times in
126: * succession without having retrieved the value.
127: */
128: public boolean hasNext() {
129: // test if we've already advanced via hasNext or foundNext
130: if (_baseHasNext != null) {
131: return _baseHasNext;
132: }
133:
134: // set our internal flag to the value of base.hasNext().
135: // since our internal flag is now non-null, further tests of hasNext()
136: // will return without consulting the base iterator.
137: boolean b = _base.hasNext();
138: _baseHasNext = Boolean.valueOf(b);
139:
140: // stash the next value returned by the base iterator, if any.
141: // User might intermix tests of hasNext() and findNext(): we'll
142: // need to stash these the consistently with the way that findNext()
143: // does, in order that they may interoperate correctly
144: if (b) {
145: _next = _base.next();
146: }
147:
148: return b;
149: }
150:
151: public T next() {
152: // If the user hasn't checked, then we will and throw NSE if there;s
153: // nothing left.
154: if (_baseHasNext == null) {
155: if (!hasNext()) {
156: throw new NoSuchElementException();
157: }
158: }
159:
160: // If he did check and there's nothing left and he called this method
161: // anyway, throw NSE
162: else {
163: if (!_baseHasNext) {
164: throw new NoSuchElementException();
165: }
166: }
167:
168: // Return the next value, and reset everything
169: T val = _next;
170: _next = null;
171: _baseHasNext = null;
172: return val;
173: }
174:
175: public void remove() {
176: throw new UnsupportedOperationException();
177: }
178: }
|