0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.quercus.env;
0031:
0032: import com.caucho.quercus.Location;
0033: import com.caucho.quercus.function.Marshal;
0034: import com.caucho.quercus.function.MarshalFactory;
0035: import com.caucho.vfs.WriteStream;
0036:
0037: import java.io.IOException;
0038: import java.io.Serializable;
0039: import java.lang.reflect.Array;
0040: import java.util.*;
0041: import java.util.logging.Level;
0042: import java.util.logging.Logger;
0043:
0044: /**
0045: * Represents a PHP array value.
0046: */
0047: abstract public class ArrayValue extends Value {
0048: private static final Logger log = Logger.getLogger(ArrayValue.class
0049: .getName());
0050:
0051: protected static final StringValue KEY = new StringBuilderValue(
0052: "key");
0053: protected static final StringValue VALUE = new StringBuilderValue(
0054: "value");
0055:
0056: public static final GetKey GET_KEY = new GetKey();
0057: public static final GetValue GET_VALUE = new GetValue();
0058:
0059: protected Entry _current;
0060:
0061: protected ArrayValue() {
0062: }
0063:
0064: /**
0065: * Returns the type.
0066: */
0067: @Override
0068: public String getType() {
0069: return "array";
0070: }
0071:
0072: /**
0073: * Returns the ValueType.
0074: */
0075: @Override
0076: public ValueType getValueType() {
0077: return ValueType.ARRAY;
0078: }
0079:
0080: /**
0081: * Converts to a boolean.
0082: */
0083: @Override
0084: public boolean toBoolean() {
0085: return getSize() != 0;
0086: }
0087:
0088: /**
0089: * Converts to a string.
0090: */
0091: @Override
0092: public String toString() {
0093: return "Array";
0094: }
0095:
0096: /**
0097: * Converts to an object.
0098: */
0099: public Object toObject() {
0100: return null;
0101: }
0102:
0103: /**
0104: * Converts to a java object.
0105: */
0106: @Override
0107: public Object toJavaObject() {
0108: return this ;
0109: }
0110:
0111: //
0112: // Conversions
0113: //
0114:
0115: /**
0116: * Converts to an object.
0117: */
0118: @Override
0119: public Value toArray() {
0120: return this ;
0121: }
0122:
0123: /**
0124: * Converts to an array value
0125: */
0126: @Override
0127: public ArrayValue toArrayValue(Env env) {
0128: return this ;
0129: }
0130:
0131: /**
0132: * Converts to an object.
0133: */
0134: @Override
0135: public Value toObject(Env env) {
0136: Value obj = env.createObject();
0137:
0138: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0139: Value key = entry.getKey();
0140:
0141: if (key instanceof StringValue) {
0142: // XXX: intern?
0143: obj.putField(env, key.toString(), entry.getValue());
0144: }
0145: }
0146:
0147: return obj;
0148: }
0149:
0150: /**
0151: * Converts to a java List object.
0152: */
0153: @Override
0154: public Collection toJavaCollection(Env env, Class type) {
0155: Collection coll = null;
0156:
0157: if (type.isAssignableFrom(HashSet.class)) {
0158: coll = new HashSet();
0159: } else if (type.isAssignableFrom(TreeSet.class)) {
0160: coll = new TreeSet();
0161: } else {
0162: try {
0163: coll = (Collection) type.newInstance();
0164: } catch (Throwable e) {
0165: log.log(Level.FINE, e.toString(), e);
0166: env.warning(L.l("Can't assign array to {0}", type
0167: .getName()));
0168:
0169: return null;
0170: }
0171: }
0172:
0173: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0174: coll.add(entry.getValue().toJavaObject());
0175: }
0176:
0177: return coll;
0178: }
0179:
0180: /**
0181: * Converts to a java List object.
0182: */
0183: @Override
0184: public List toJavaList(Env env, Class type) {
0185: List list = null;
0186:
0187: if (type.isAssignableFrom(ArrayList.class)) {
0188: list = new ArrayList();
0189: } else if (type.isAssignableFrom(LinkedList.class)) {
0190: list = new LinkedList();
0191: } else if (type.isAssignableFrom(Vector.class)) {
0192: list = new Vector();
0193: } else {
0194: try {
0195: list = (List) type.newInstance();
0196: } catch (Throwable e) {
0197: log.log(Level.FINE, e.toString(), e);
0198: env.warning(L.l("Can't assign array to {0}", type
0199: .getName()));
0200:
0201: return null;
0202: }
0203: }
0204:
0205: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0206: list.add(entry.getValue().toJavaObject());
0207: }
0208:
0209: return list;
0210: }
0211:
0212: /**
0213: * Converts to a java object.
0214: */
0215: @Override
0216: public Map toJavaMap(Env env, Class type) {
0217: Map map = null;
0218:
0219: if (type.isAssignableFrom(TreeMap.class)) {
0220: map = new TreeMap();
0221: } else if (type.isAssignableFrom(LinkedHashMap.class)) {
0222: map = new LinkedHashMap();
0223: } else {
0224: try {
0225: map = (Map) type.newInstance();
0226: } catch (Throwable e) {
0227: log.log(Level.FINE, e.toString(), e);
0228:
0229: env.warning(L.l("Can't assign array to {0}", type
0230: .getName()));
0231:
0232: return null;
0233: }
0234: }
0235:
0236: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0237: map.put(entry.getKey().toJavaObject(), entry.getValue()
0238: .toJavaObject());
0239: }
0240:
0241: return map;
0242: }
0243:
0244: /**
0245: * Returns true for an array.
0246: */
0247: @Override
0248: public boolean isArray() {
0249: return true;
0250: }
0251:
0252: /**
0253: * Copy as a return value
0254: */
0255: @Override
0256: public Value copyReturn() {
0257: return copy(); // php/3a5e
0258: }
0259:
0260: /**
0261: * Copy for assignment.
0262: */
0263: @Override
0264: abstract public Value copy();
0265:
0266: /**
0267: * Copy for serialization
0268: */
0269: @Override
0270: abstract public Value copy(Env env,
0271: IdentityHashMap<Value, Value> map);
0272:
0273: /**
0274: * Returns the size.
0275: */
0276: @Override
0277: abstract public int getSize();
0278:
0279: /**
0280: * Returns the count().
0281: */
0282: @Override
0283: public int getCount(Env env) {
0284: return getSize();
0285: }
0286:
0287: /**
0288: * Returns the count().
0289: */
0290: @Override
0291: public int getCountRecursive(Env env) {
0292: env.stub("recursive count of array unimplemented");
0293:
0294: return getSize();
0295: }
0296:
0297: /**
0298: * Returns true if the value is empty
0299: */
0300: @Override
0301: public boolean isEmpty() {
0302: return getSize() == 0;
0303: }
0304:
0305: /**
0306: * Clears the array
0307: */
0308: abstract public void clear();
0309:
0310: @Override
0311: public int cmp(Value rValue) {
0312: return cmpImpl(rValue, 1);
0313: }
0314:
0315: private int cmpImpl(Value rValue, int resultIfKeyMissing) {
0316: // "if key from operand 1 is not found in operand 2 then
0317: // arrays are uncomparable, otherwise - compare value by value"
0318:
0319: // php/335h
0320:
0321: if (!rValue.isArray())
0322: return 1;
0323:
0324: int lSize = getSize();
0325: int rSize = rValue.toArray().getSize();
0326:
0327: if (lSize != rSize)
0328: return lSize < rSize ? -1 : 1;
0329:
0330: for (Map.Entry<Value, Value> entry : entrySet()) {
0331: Value lElementValue = entry.getValue();
0332: Value rElementValue = rValue.get(entry.getKey());
0333:
0334: if (!rElementValue.isset())
0335: return resultIfKeyMissing;
0336:
0337: int cmp = lElementValue.cmp(rElementValue);
0338:
0339: if (cmp != 0)
0340: return cmp;
0341: }
0342:
0343: return 0;
0344: }
0345:
0346: /**
0347: * Returns true for less than
0348: */
0349: @Override
0350: public boolean lt(Value rValue) {
0351: // php/335h
0352: return cmpImpl(rValue, 1) < 0;
0353: }
0354:
0355: /**
0356: * Returns true for less than or equal to
0357: */
0358: @Override
0359: public boolean leq(Value rValue) {
0360: // php/335h
0361: return cmpImpl(rValue, 1) <= 0;
0362: }
0363:
0364: /**
0365: * Returns true for greater than
0366: */
0367: @Override
0368: public boolean gt(Value rValue) {
0369: // php/335h
0370: return cmpImpl(rValue, -1) > 0;
0371: }
0372:
0373: /**
0374: * Returns true for greater than or equal to
0375: */
0376: @Override
0377: public boolean geq(Value rValue) {
0378: // php/335h
0379: return cmpImpl(rValue, -1) >= 0;
0380: }
0381:
0382: /**
0383: * Adds a new value.
0384: */
0385: @Override
0386: abstract public Value put(Value key, Value value);
0387:
0388: /**
0389: * Add
0390: */
0391: @Override
0392: abstract public Value put(Value value);
0393:
0394: /**
0395: * Add to front.
0396: */
0397: abstract public ArrayValue unshift(Value value);
0398:
0399: /**
0400: * Splices.
0401: */
0402: abstract public ArrayValue splice(int begin, int end,
0403: ArrayValue replace);
0404:
0405: /**
0406: * Returns the value as an array.
0407: */
0408: @Override
0409: public Value getArray(Value index) {
0410: Value value = get(index);
0411:
0412: Value array = value.toAutoArray();
0413:
0414: if (value != array) {
0415: value = array;
0416:
0417: put(index, value);
0418: }
0419:
0420: return value;
0421: }
0422:
0423: /**
0424: * Returns the value as an argument which may be a reference.
0425: */
0426: @Override
0427: abstract public Value getArg(Value index);
0428:
0429: /**
0430: * Returns the field value, creating an object if it's unset.
0431: */
0432: @Override
0433: public Value getObject(Env env, Value fieldName) {
0434: Value value = get(fieldName);
0435:
0436: Value object = value.toAutoObject(env);
0437: if (value != object) {
0438: value = object;
0439:
0440: put(fieldName, value);
0441: }
0442:
0443: return value;
0444: }
0445:
0446: /**
0447: * Sets the array ref.
0448: */
0449: @Override
0450: abstract public Value putRef();
0451:
0452: /**
0453: * Creatse a tail index.
0454: */
0455: abstract public Value createTailKey();
0456:
0457: /**
0458: * Returns a union of this array and the rValue as array.
0459: * If the rValue is not an array, the returned union contains the elements
0460: * of this array only.
0461: *
0462: * To append a value to this ArrayValue use the {@link #put(Value)} method.
0463: */
0464: @Override
0465: public Value add(Value rValue) {
0466: rValue = rValue.toValue();
0467:
0468: if (!(rValue instanceof ArrayValue))
0469: return copy();
0470:
0471: ArrayValue rArray = (ArrayValue) rValue;
0472:
0473: ArrayValue result = new ArrayValueImpl(rArray);
0474:
0475: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0476: result.put(entry.getKey(), entry.getValue());
0477: }
0478:
0479: return result;
0480: }
0481:
0482: @Override
0483: public Iterator<Map.Entry<Value, Value>> getIterator(Env env) {
0484: return new EntryIterator(getHead());
0485: }
0486:
0487: @Override
0488: public Iterator<Value> getKeyIterator(Env env) {
0489: return new KeyIterator(getHead());
0490: }
0491:
0492: @Override
0493: public Iterator<Value> getValueIterator(Env env) {
0494: return new ValueIterator(getHead());
0495: }
0496:
0497: /**
0498: * Gets a new value.
0499: */
0500: @Override
0501: abstract public Value get(Value key);
0502:
0503: /**
0504: * Returns the value in the array as-is.
0505: * (i.e. without calling toValue() on it).
0506: */
0507: public Value getRaw(Value key) {
0508: return get(key);
0509: }
0510:
0511: /**
0512: * Removes a value.
0513: */
0514: @Override
0515: abstract public Value remove(Value key);
0516:
0517: /**
0518: * Returns the array ref.
0519: */
0520: @Override
0521: abstract public Var getRef(Value index);
0522:
0523: /**
0524: * Returns an iterator of the entries.
0525: */
0526: public Set<Value> keySet() {
0527: return new KeySet();
0528: }
0529:
0530: /**
0531: * Returns a set of all the of the entries.
0532: */
0533: public Set<Map.Entry<Value, Value>> entrySet() {
0534: return new EntrySet();
0535: }
0536:
0537: /**
0538: * Returns a collection of the values.
0539: */
0540: public Collection<Value> values() {
0541: return new ValueCollection();
0542: }
0543:
0544: /**
0545: * Convenience for lib.
0546: */
0547: public void put(String key, String value) {
0548: // XXX: this needs an Env arg because of i18n
0549: // XXX: but some modules have arrays that are static constants
0550: put(StringValue.create(key), StringValue.create(value));
0551: }
0552:
0553: /**
0554: * Convenience for lib.
0555: */
0556: public void put(Env env, String key, String value) {
0557: put(env.createString(key), env.createString(value));
0558: }
0559:
0560: /**
0561: * Convenience for lib.
0562: */
0563: public void put(String key, char value) {
0564: // XXX: this needs an Env arg because of i18n
0565: put(StringValue.create(key), StringValue.create(value));
0566: }
0567:
0568: /**
0569: * Convenience for lib.
0570: */
0571: public void put(String key, long value) {
0572: // XXX: this needs an Env arg because of i18n
0573: put(StringValue.create(key), new LongValue(value));
0574: }
0575:
0576: /**
0577: * Convenience for lib.
0578: */
0579: public void put(Env env, String key, long value) {
0580: put(env.createString(key), new LongValue(value));
0581: }
0582:
0583: /**
0584: * Convenience for lib.
0585: */
0586: public void put(String key, double value) {
0587: // XXX: this needs an Env arg because of i18n
0588: put(StringValue.create(key), new DoubleValue(value));
0589: }
0590:
0591: /**
0592: * Convenience for lib.
0593: */
0594: public void put(String key, boolean value) {
0595: // XXX: this needs an Env arg because of i18n
0596: put(StringValue.create(key), value ? BooleanValue.TRUE
0597: : BooleanValue.FALSE);
0598: }
0599:
0600: /**
0601: * Convenience for lib.
0602: */
0603: public void put(Env env, String key, boolean value) {
0604: put(env.createString(key), value ? BooleanValue.TRUE
0605: : BooleanValue.FALSE);
0606: }
0607:
0608: /**
0609: * Convenience for lib.
0610: */
0611: public void put(String value) {
0612: // XXX: this needs an Env arg because of i18n
0613: put(StringValue.create(value));
0614: }
0615:
0616: /**
0617: * Convenience for lib.
0618: */
0619: public void put(long value) {
0620: put(new LongValue(value));
0621: }
0622:
0623: /**
0624: * Appends as an argument - only called from compiled code
0625: *
0626: * XXX: change name to appendArg
0627: */
0628: public ArrayValue append(Value key, Value value) {
0629: put(key, value);
0630:
0631: return this ;
0632: }
0633:
0634: /**
0635: * Appends as an argument - only called from compiled code
0636: *
0637: * XXX: change name to appendArg
0638: */
0639: public ArrayValue append(Value value) {
0640: put(value);
0641:
0642: return this ;
0643: }
0644:
0645: /**
0646: * Appends as an argument - only called from compiled code
0647: *
0648: * XXX: change name to appendArg
0649: */
0650: public void putAll(ArrayValue array) {
0651: for (Map.Entry<Value, Value> entry : array.entrySet())
0652: put(entry.getKey(), entry.getValue());
0653: }
0654:
0655: /**
0656: * Convert to an array.
0657: */
0658: public static Value toArray(Value value) {
0659: value = value.toValue();
0660:
0661: if (value instanceof ArrayValue)
0662: return value;
0663: else
0664: return new ArrayValueImpl().put(value);
0665: }
0666:
0667: /**
0668: * Prints the value.
0669: * @param env
0670: */
0671: @Override
0672: public void print(Env env) {
0673: env.print("Array");
0674: }
0675:
0676: /**
0677: * Pops the top value.
0678: */
0679: abstract public Value pop();
0680:
0681: /**
0682: * Shuffles the array
0683: */
0684: abstract public void shuffle();
0685:
0686: /**
0687: * Returns the head.
0688: */
0689: abstract public Entry getHead();
0690:
0691: /**
0692: * Returns the tail.
0693: */
0694: abstract protected Entry getTail();
0695:
0696: /**
0697: * Returns the current value.
0698: */
0699: @Override
0700: public Value current() {
0701: if (_current != null)
0702: return _current.getValue();
0703: else
0704: return BooleanValue.FALSE;
0705: }
0706:
0707: /**
0708: * Returns the current key
0709: */
0710: @Override
0711: public Value key() {
0712: if (_current != null)
0713: return _current.getKey();
0714: else
0715: return NullValue.NULL;
0716: }
0717:
0718: /**
0719: * Returns true if there are more elements.
0720: */
0721: @Override
0722: public boolean hasCurrent() {
0723: return _current != null;
0724: }
0725:
0726: /**
0727: * Returns the next value.
0728: */
0729: @Override
0730: public Value next() {
0731: if (_current != null)
0732: _current = _current._next;
0733:
0734: return current();
0735: }
0736:
0737: /**
0738: * Returns the previous value.
0739: */
0740: public Value prev() {
0741: if (_current != null)
0742: _current = _current._prev;
0743:
0744: return current();
0745: }
0746:
0747: /**
0748: * The each iterator
0749: */
0750: public Value each() {
0751: if (_current == null)
0752: return NullValue.NULL;
0753:
0754: ArrayValue result = new ArrayValueImpl();
0755:
0756: result.put(LongValue.ZERO, _current.getKey());
0757: result.put(KEY, _current.getKey());
0758:
0759: result.put(LongValue.ONE, _current.getValue());
0760: result.put(VALUE, _current.getValue());
0761:
0762: _current = _current._next;
0763:
0764: return result;
0765: }
0766:
0767: /**
0768: * Returns the first value.
0769: */
0770: public Value reset() {
0771: _current = getHead();
0772:
0773: return current();
0774: }
0775:
0776: /**
0777: * Returns the last value.
0778: */
0779: public Value end() {
0780: _current = getTail();
0781:
0782: return current();
0783: }
0784:
0785: /**
0786: * Returns the corresponding key if this array contains the given value
0787: *
0788: * @param value the value to search for in the array
0789: *
0790: * @return the key if it is found in the array, NULL otherwise
0791: *
0792: * @throws NullPointerException
0793: */
0794: public Value contains(Value value) {
0795: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0796: if (entry.getValue().eq(value))
0797: return entry.getKey();
0798: }
0799:
0800: return NullValue.NULL;
0801: }
0802:
0803: /**
0804: * Returns the corresponding key if this array contains the given value
0805: *
0806: * @param value the value to search for in the array
0807: *
0808: * @return the key if it is found in the array, NULL otherwise
0809: *
0810: * @throws NullPointerException
0811: */
0812: public Value containsStrict(Value value) {
0813: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0814: if (entry.getValue().eql(value))
0815: return entry.getKey();
0816: }
0817:
0818: return NullValue.NULL;
0819: }
0820:
0821: /**
0822: * Returns the corresponding valeu if this array contains the given key
0823: *
0824: * @param key the key to search for in the array
0825: *
0826: * @return the value if it is found in the array, NULL otherwise
0827: *
0828: * @throws NullPointerException
0829: */
0830: abstract public Value containsKey(Value key);
0831:
0832: /**
0833: * Returns an object array of this array. This is a copy of this object's
0834: * backing structure. Null elements are not included.
0835: *
0836: * @return an object array of this array
0837: */
0838: public Map.Entry<Value, Value>[] toEntryArray() {
0839: ArrayList<Map.Entry<Value, Value>> array = new ArrayList<Map.Entry<Value, Value>>(
0840: getSize());
0841:
0842: for (Entry entry = getHead(); entry != null; entry = entry._next)
0843: array.add(entry);
0844:
0845: Map.Entry<Value, Value>[] result = new Entry[array.size()];
0846:
0847: return array.toArray(result);
0848: }
0849:
0850: /**
0851: * Sorts this array based using the passed Comparator
0852: *
0853: * @param comparator the comparator for sorting the array
0854: * @param resetKeys true if the keys should not be preserved
0855: * @param strict true if alphabetic keys should not be preserved
0856: */
0857: public void sort(Comparator<Map.Entry<Value, Value>> comparator,
0858: boolean resetKeys, boolean strict) {
0859: Entry[] entries;
0860:
0861: entries = new Entry[getSize()];
0862:
0863: int i = 0;
0864: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0865: entries[i++] = entry;
0866: }
0867:
0868: Arrays.sort(entries, comparator);
0869:
0870: clear();
0871:
0872: long base = 0;
0873:
0874: if (!resetKeys)
0875: strict = false;
0876:
0877: for (int j = 0; j < entries.length; j++) {
0878: Value key = entries[j].getKey();
0879:
0880: if (resetKeys && (!(key instanceof StringValue) || strict))
0881: put(LongValue.create(base++), entries[j].getValue());
0882: else
0883: put(entries[j].getKey(), entries[j].getValue());
0884: }
0885: }
0886:
0887: /**
0888: * Serializes the value.
0889: */
0890: @Override
0891: public void serialize(StringBuilder sb) {
0892: sb.append("a:");
0893: sb.append(getSize());
0894: sb.append(":{");
0895:
0896: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0897: entry.getKey().serialize(sb);
0898: entry.getValue().serialize(sb);
0899: }
0900:
0901: sb.append("}");
0902: }
0903:
0904: /**
0905: * Exports the value.
0906: */
0907: @Override
0908: public void varExport(StringBuilder sb) {
0909: sb.append("array(");
0910:
0911: boolean isFirst = true;
0912: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0913: entry.getKey().varExport(sb);
0914: sb.append(" => ");
0915: entry.getValue().varExport(sb);
0916: sb.append(", ");
0917: }
0918:
0919: sb.append(")");
0920: }
0921:
0922: /**
0923: * Resets all numerical keys with the first index as base
0924: *
0925: * @param base the initial index
0926: * @param strict if true, string keys are also reset
0927: */
0928: public boolean keyReset(long base, boolean strict) {
0929: Entry[] entries;
0930:
0931: entries = new Entry[getSize()];
0932:
0933: int i = 0;
0934: for (Entry entry = getHead(); entry != null; entry = entry._next) {
0935: entries[i++] = entry;
0936: }
0937:
0938: clear();
0939:
0940: for (int j = 0; j < entries.length; j++) {
0941: Value key = entries[j].getKey();
0942:
0943: if (!(key instanceof StringValue) || strict)
0944: put(LongValue.create(base++), entries[j].getValue());
0945: else
0946: put(entries[j].getKey(), entries[j].getValue());
0947: }
0948:
0949: return true;
0950: }
0951:
0952: /**
0953: * Test for equality
0954: *
0955: * @param rValue rhs ArrayValue to compare to
0956: *
0957: * @return true if this is equal to rValue, false otherwise
0958: */
0959: @Override
0960: public boolean eq(Value rValue) {
0961: if (rValue == null)
0962: return false;
0963:
0964: for (Map.Entry<Value, Value> entry : entrySet()) {
0965: Value entryValue = entry.getValue();
0966:
0967: Value entryKey = entry.getKey();
0968:
0969: Value rEntryValue = rValue.get(entryKey);
0970:
0971: if ((rEntryValue instanceof ArrayValue)
0972: && !entryValue.eq((ArrayValue) rEntryValue))
0973: return false;
0974:
0975: if (!entryValue.eq(rEntryValue))
0976: return false;
0977: }
0978:
0979: return true;
0980: }
0981:
0982: /**
0983: * Test for ===
0984: *
0985: * @param rValue rhs ArrayValue to compare to
0986: *
0987: * @return true if this is equal to rValue, false otherwise
0988: */
0989: @Override
0990: public boolean eql(Value rValue) {
0991: if (rValue == null)
0992: return false;
0993: else if (getSize() != rValue.getSize())
0994: return false;
0995:
0996: rValue = rValue.toValue();
0997:
0998: if (!(rValue instanceof ArrayValue))
0999: return false;
1000:
1001: ArrayValue rArray = (ArrayValue) rValue;
1002:
1003: Iterator<Map.Entry<Value, Value>> iterA = entrySet().iterator();
1004: Iterator<Map.Entry<Value, Value>> iterB = rArray.entrySet()
1005: .iterator();
1006:
1007: while (iterA.hasNext() && iterB.hasNext()) {
1008: Map.Entry<Value, Value> entryA = iterA.next();
1009: Map.Entry<Value, Value> entryB = iterB.next();
1010:
1011: if (!entryA.getKey().eql(entryB.getKey()))
1012: return false;
1013:
1014: if (!entryA.getValue().eql(entryB.getValue()))
1015: return false;
1016: }
1017:
1018: if (iterA.hasNext() || iterB.hasNext())
1019: return false;
1020: else
1021: return true;
1022: }
1023:
1024: @Override
1025: public void varDumpImpl(Env env, WriteStream out, int depth,
1026: IdentityHashMap<Value, String> valueSet) throws IOException {
1027: out.println("array(" + getSize() + ") {");
1028:
1029: for (Map.Entry<Value, Value> mapEntry : entrySet()) {
1030: varDumpEntry(env, out, depth + 1, valueSet, mapEntry);
1031:
1032: out.println();
1033: }
1034:
1035: printDepth(out, 2 * depth);
1036:
1037: out.print("}");
1038: }
1039:
1040: protected void varDumpEntry(Env env, WriteStream out, int depth,
1041: IdentityHashMap<Value, String> valueSet,
1042: Map.Entry<Value, Value> mapEntry) throws IOException {
1043: ArrayValue.Entry entry = (ArrayValue.Entry) mapEntry;
1044:
1045: entry.varDumpImpl(env, out, depth, valueSet);
1046: }
1047:
1048: @Override
1049: protected void printRImpl(Env env, WriteStream out, int depth,
1050: IdentityHashMap<Value, String> valueSet) throws IOException {
1051: out.println("Array");
1052: printDepth(out, 8 * depth);
1053: out.println("(");
1054:
1055: for (Map.Entry<Value, Value> mapEntry : entrySet()) {
1056: printREntry(env, out, depth, valueSet, mapEntry);
1057: }
1058:
1059: printDepth(out, 8 * depth);
1060: out.println(")");
1061: }
1062:
1063: protected void printREntry(Env env, WriteStream out, int depth,
1064: IdentityHashMap<Value, String> valueSet,
1065: Map.Entry<Value, Value> mapEntry) throws IOException {
1066: ArrayValue.Entry entry = (ArrayValue.Entry) mapEntry;
1067:
1068: entry.printRImpl(env, out, depth, valueSet);
1069: }
1070:
1071: public final static class Entry implements Map.Entry<Value, Value>,
1072: Serializable {
1073: final Value _key;
1074: Value _value;
1075:
1076: Entry _prev;
1077: Entry _next;
1078:
1079: Entry _prevHash;
1080: Entry _nextHash;
1081:
1082: int _index;
1083:
1084: public Entry(Value key) {
1085: _key = key;
1086: _value = NullValue.NULL;
1087: }
1088:
1089: public Entry(Value key, Value value) {
1090: _key = key;
1091: _value = value;
1092: }
1093:
1094: public Entry getNext() {
1095: return _next;
1096: }
1097:
1098: public Value getRawValue() {
1099: return _value;
1100: }
1101:
1102: public Value getValue() {
1103: return _value.toValue();
1104: }
1105:
1106: public Value getKey() {
1107: return _key;
1108: }
1109:
1110: public Value toValue() {
1111: // The value may be a var
1112: // XXX: need test
1113: return _value.toValue();
1114: }
1115:
1116: /**
1117: * Argument used/declared as a ref.
1118: */
1119: public Var toRefVar() {
1120: // php/376a
1121:
1122: Value val = _value;
1123:
1124: if (val instanceof Var)
1125: return (Var) val;
1126: else {
1127: Var var = new Var(val);
1128:
1129: _value = var;
1130:
1131: return var;
1132: }
1133: }
1134:
1135: /**
1136: * Converts to an argument value.
1137: */
1138: public Value toArgValue() {
1139: return _value.toValue();
1140: }
1141:
1142: public Value setValue(Value value) {
1143: Value oldValue = _value;
1144:
1145: _value = value;
1146:
1147: return oldValue;
1148: }
1149:
1150: /**
1151: * Converts to a variable reference (for function arguments)
1152: */
1153: public Value toRef() {
1154: Value value = _value;
1155:
1156: if (value instanceof Var)
1157: return new RefVar((Var) value);
1158: else {
1159: _value = new Var(value);
1160:
1161: return new RefVar((Var) _value);
1162: }
1163: }
1164:
1165: /**
1166: * Converts to a variable reference (for function arguments)
1167: */
1168: public Value toArgRef() {
1169: Value value = _value;
1170:
1171: if (value instanceof Var)
1172: return new RefVar((Var) value);
1173: else {
1174: _value = new Var(_value);
1175:
1176: return new RefVar((Var) _value);
1177: }
1178: }
1179:
1180: public Value toArg() {
1181: // php/39a4
1182: Value value = _value;
1183:
1184: // php/39aj
1185: if (value instanceof Var)
1186: return value;
1187: else {
1188: _value = new Var(value);
1189:
1190: return _value;
1191: }
1192: }
1193:
1194: public void varDumpImpl(Env env, WriteStream out, int depth,
1195: IdentityHashMap<Value, String> valueSet)
1196: throws IOException {
1197: printDepth(out, 2 * depth);
1198: out.print("[");
1199:
1200: if (_key instanceof StringValue)
1201: out.print("\"" + _key + "\"");
1202: else
1203: out.print(_key);
1204:
1205: out.println("]=>");
1206:
1207: printDepth(out, 2 * depth);
1208:
1209: _value.varDump(env, out, depth, valueSet);
1210: }
1211:
1212: protected void printRImpl(Env env, WriteStream out, int depth,
1213: IdentityHashMap<Value, String> valueSet)
1214: throws IOException {
1215: printDepth(out, 8 * depth);
1216: out.print(" [");
1217: out.print(_key);
1218: out.print("] => ");
1219: if (_value != null)
1220: _value.printR(env, out, depth + 1, valueSet);
1221: out.println();
1222: }
1223:
1224: private void printDepth(WriteStream out, int depth)
1225: throws java.io.IOException {
1226: for (int i = depth; i > 0; i--)
1227: out.print(' ');
1228: }
1229:
1230: @Override
1231: public String toString() {
1232: return "ArrayValue.Entry[" + getKey() + "]";
1233: }
1234: }
1235:
1236: /**
1237: * Returns the field keys.
1238: */
1239: public Value[] getKeyArray(Env env) {
1240: int len = getSize();
1241: Value[] keys = new Value[len];
1242:
1243: Iterator<Value> iter = getKeyIterator(env);
1244:
1245: for (int i = 0; i < len; i++) {
1246: keys[i] = iter.next();
1247: }
1248:
1249: return keys;
1250: }
1251:
1252: /**
1253: * Returns the field values.
1254: */
1255: public Value[] getValueArray(Env env) {
1256: int len = getSize();
1257: Value[] values = new Value[len];
1258:
1259: Iterator<Value> iter = getValueIterator(env);
1260:
1261: for (int i = 0; i < len; i++) {
1262: values[i] = iter.next();
1263: }
1264:
1265: return values;
1266: }
1267:
1268: /**
1269: * Takes the values of this array and puts them in a java array
1270: */
1271: public Value[] valuesToArray() {
1272: Value[] values = new Value[getSize()];
1273:
1274: int i = 0;
1275: for (Entry ptr = getHead(); ptr != null; ptr = ptr.getNext()) {
1276: values[i++] = ptr.getValue();
1277: }
1278:
1279: return values;
1280: }
1281:
1282: /**
1283: * Takes the values of this array, unmarshals them to objects of type
1284: * <i>elementType</i>, and puts them in a java array.
1285: */
1286: @Override
1287: public Object valuesToArray(Env env, Class elementType) {
1288: int size = getSize();
1289:
1290: Object array = Array.newInstance(elementType, size);
1291:
1292: MarshalFactory factory = env.getModuleContext()
1293: .getMarshalFactory();
1294: Marshal elementMarshal = factory.create(elementType);
1295:
1296: int i = 0;
1297:
1298: for (Entry ptr = getHead(); ptr != null; ptr = ptr.getNext()) {
1299: Array.set(array, i++, elementMarshal.marshal(env, ptr
1300: .getValue(), elementType));
1301: }
1302:
1303: return array;
1304: }
1305:
1306: public class EntrySet extends AbstractSet<Map.Entry<Value, Value>> {
1307: EntrySet() {
1308: }
1309:
1310: @Override
1311: public int size() {
1312: return ArrayValue.this .getSize();
1313: }
1314:
1315: @Override
1316: public Iterator<Map.Entry<Value, Value>> iterator() {
1317: return new EntryIterator(getHead());
1318: }
1319: }
1320:
1321: public class KeySet extends AbstractSet<Value> {
1322: KeySet() {
1323: }
1324:
1325: @Override
1326: public int size() {
1327: return ArrayValue.this .getSize();
1328: }
1329:
1330: @Override
1331: public Iterator<Value> iterator() {
1332: return new KeyIterator(getHead());
1333: }
1334: }
1335:
1336: public class ValueCollection extends AbstractCollection<Value> {
1337: ValueCollection() {
1338: }
1339:
1340: @Override
1341: public int size() {
1342: return ArrayValue.this .getSize();
1343: }
1344:
1345: @Override
1346: public Iterator<Value> iterator() {
1347: return new ValueIterator(getHead());
1348: }
1349: }
1350:
1351: public static class EntryIterator implements
1352: Iterator<Map.Entry<Value, Value>> {
1353: private Entry _current;
1354:
1355: EntryIterator(Entry head) {
1356: _current = head;
1357: }
1358:
1359: public boolean hasNext() {
1360: return _current != null;
1361: }
1362:
1363: public Map.Entry<Value, Value> next() {
1364: if (_current != null) {
1365: Map.Entry<Value, Value> next = _current;
1366: _current = _current._next;
1367:
1368: return next;
1369: } else
1370: return null;
1371: }
1372:
1373: public void remove() {
1374: throw new UnsupportedOperationException();
1375: }
1376: }
1377:
1378: public static class KeyIterator implements Iterator<Value> {
1379: private Entry _current;
1380:
1381: KeyIterator(Entry head) {
1382: _current = head;
1383: }
1384:
1385: public boolean hasNext() {
1386: return _current != null;
1387: }
1388:
1389: public Value next() {
1390: if (_current != null) {
1391: Value next = _current.getKey();
1392: _current = _current._next;
1393:
1394: return next;
1395: } else
1396: return null;
1397: }
1398:
1399: public void remove() {
1400: throw new UnsupportedOperationException();
1401: }
1402: }
1403:
1404: public static class ValueIterator implements Iterator<Value> {
1405: private Entry _current;
1406:
1407: ValueIterator(Entry head) {
1408: _current = head;
1409: }
1410:
1411: public boolean hasNext() {
1412: return _current != null;
1413: }
1414:
1415: public Value next() {
1416: if (_current != null) {
1417: Value next = _current.getValue();
1418: _current = _current._next;
1419:
1420: return next;
1421: } else
1422: return null;
1423: }
1424:
1425: public void remove() {
1426: throw new UnsupportedOperationException();
1427: }
1428: }
1429:
1430: public static class ValueComparator implements
1431: Comparator<Map.Entry<Value, Value>> {
1432: public static final ValueComparator CMP = new ValueComparator();
1433:
1434: private ValueComparator() {
1435: }
1436:
1437: public int compare(Map.Entry<Value, Value> aEntry,
1438: Map.Entry<Value, Value> bEntry) {
1439: try {
1440: Value aValue = aEntry.getValue();
1441: Value bValue = bEntry.getValue();
1442:
1443: if (aValue.eq(bValue))
1444: return 0;
1445: else if (aValue.lt(bValue))
1446: return -1;
1447: else
1448: return 1;
1449: } catch (Throwable e) {
1450: throw new RuntimeException(e);
1451: }
1452: }
1453: }
1454:
1455: public static class KeyComparator implements
1456: Comparator<Map.Entry<Value, Value>> {
1457: public static final KeyComparator CMP = new KeyComparator();
1458:
1459: private KeyComparator() {
1460: }
1461:
1462: public int compare(Map.Entry<Value, Value> aEntry,
1463: Map.Entry<Value, Value> bEntry) {
1464: try {
1465: Value aKey = aEntry.getKey();
1466: Value bKey = bEntry.getKey();
1467:
1468: if (aKey.eq(bKey))
1469: return 0;
1470: else if (aKey.lt(bKey))
1471: return -1;
1472: else
1473: return 1;
1474: } catch (Throwable e) {
1475: throw new RuntimeException(e);
1476: }
1477: }
1478: }
1479:
1480: public static abstract class AbstractGet {
1481: public abstract Value get(Map.Entry<Value, Value> entry);
1482: }
1483:
1484: public static class GetKey extends AbstractGet {
1485: public static final GetKey GET = new GetKey();
1486:
1487: private GetKey() {
1488: }
1489:
1490: @Override
1491: public Value get(Map.Entry<Value, Value> entry) {
1492: return entry.getKey();
1493: }
1494: }
1495:
1496: public static class GetValue extends AbstractGet {
1497: public static final GetValue GET = new GetValue();
1498:
1499: private GetValue() {
1500: }
1501:
1502: @Override
1503: public Value get(Map.Entry<Value, Value> entry) {
1504: return entry.getValue();
1505: }
1506: }
1507: }
|