001: /*
002: * Copyright (c) 1998-2007 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Sam
028: */
029:
030: package com.caucho.quercus.lib.spl;
031:
032: import com.caucho.quercus.env.TraversableDelegate;
033: import com.caucho.quercus.env.Env;
034: import com.caucho.quercus.env.Value;
035: import com.caucho.quercus.env.ObjectValue;
036: import com.caucho.quercus.program.AbstractFunction;
037:
038: import com.caucho.util.L10N;
039:
040: import java.util.Iterator;
041: import java.util.Map;
042:
043: /**
044: * A delegate that intercepts requests for iterator's and calls methods on
045: * target objects that implement
046: * the {@link com.caucho.quercus.lib.spl.Iterator} interface.
047: */
048: public class IteratorDelegate implements TraversableDelegate {
049: private static final L10N L = new L10N(IteratorDelegate.class);
050:
051: public Iterator<Map.Entry<Value, Value>> getIterator(Env env,
052: ObjectValue qThis) {
053: return new EntryIterator(env, qThis);
054: }
055:
056: public Iterator<Value> getKeyIterator(Env env, ObjectValue qThis) {
057: // doesn't belong here
058: // php/4ar3
059: //env.error(L.l("An iterator cannot be used with foreach by reference"));
060:
061: return new KeyIterator(env, qThis);
062: }
063:
064: public Iterator<Value> getValueIterator(Env env, ObjectValue qThis) {
065: return new ValueIterator(env, qThis);
066: }
067:
068: abstract public static class AbstractIteratorImpl<T> implements
069: Iterator<T> {
070: protected final Env _env;
071: protected final ObjectValue _obj;
072:
073: private final AbstractFunction _nextFun;
074: private final AbstractFunction _currentFun;
075: private final AbstractFunction _keyFun;
076: private final AbstractFunction _rewindFun;
077: private final AbstractFunction _validFun;
078: private boolean _needNext;
079:
080: public AbstractIteratorImpl(Env env, ObjectValue obj) {
081: _env = env;
082: _obj = obj;
083:
084: _currentFun = _obj.findFunction("current");
085: _keyFun = _obj.findFunction("key");
086: _nextFun = _obj.findFunction("next");
087: _rewindFun = _obj.findFunction("rewind");
088: _validFun = _obj.findFunction("valid");
089:
090: _rewindFun.callMethod(_env, _obj);
091: _needNext = false;
092: }
093:
094: public boolean hasNext() {
095: if (_needNext)
096: _nextFun.callMethod(_env, _obj);
097:
098: _needNext = true;
099:
100: return _validFun.callMethod(_env, _obj).toBoolean();
101: }
102:
103: public T next() {
104: return getCurrent();
105: }
106:
107: abstract protected T getCurrent();
108:
109: protected Value getCurrentKey() {
110: return _keyFun.callMethod(_env, _obj);
111: }
112:
113: protected Value getCurrentValue() {
114: return _currentFun.callMethod(_env, _obj);
115: }
116:
117: public void remove() {
118: throw new UnsupportedOperationException();
119: }
120: }
121:
122: public static class EntryIterator<T> extends
123: AbstractIteratorImpl<Map.Entry<Value, Value>> {
124: public EntryIterator(Env env, ObjectValue obj) {
125: super (env, obj);
126: }
127:
128: @Override
129: protected Map.Entry<Value, Value> getCurrent() {
130: // php/4ar2
131: Value value = getCurrentValue();
132: Value key = getCurrentKey();
133:
134: return new EntryImpl(key, value);
135: }
136: }
137:
138: public static class EntryImpl implements Map.Entry<Value, Value> {
139: private final Value _key;
140: private final Value _value;
141:
142: public EntryImpl(Value key, Value value) {
143: _key = key;
144: _value = value;
145: }
146:
147: public Value getKey() {
148: return _key;
149: }
150:
151: public Value getValue() {
152: return _value;
153: }
154:
155: public Value setValue(Value value) {
156: throw new UnsupportedOperationException();
157: }
158: }
159:
160: public static class KeyIterator<T> extends
161: AbstractIteratorImpl<Value> {
162: public KeyIterator(Env env, ObjectValue obj) {
163: super (env, obj);
164: }
165:
166: @Override
167: protected Value getCurrent() {
168: return getCurrentKey();
169: }
170: }
171:
172: public static class ValueIterator<T> extends
173: AbstractIteratorImpl<Value> {
174: public ValueIterator(Env env, ObjectValue obj) {
175: super (env, obj);
176: }
177:
178: @Override
179: protected Value getCurrent() {
180: return getCurrentValue();
181: }
182: }
183: }
|