1 // Copyright (c) 2001, 2003 Per M.A. Bothner and Brainfood Inc. 2 // This is free software; for terms and warranty disclaimer see ./COPYING. 3 4 package gnu.lists; 5 6 import java.io.*; 7 8 /** A "pair" object, as used in Lisp-like languages. 9 * When used to implement a list, the 'car' field contains an 10 * element's value, and the 'cdr' field points to either the next Pair 11 * or LList.Empty (which represents the end of the list). (The names 12 * "car" and "cdr" [pronounced "coulder"] are historical; better names 13 * might be "value" and "next".) While a Pair is normally usued to 14 * implement a linked list, sometimes the 'cdr' field points to some 15 * other non-list object; this is traditionally callled a "dotted list". 16 */ 17 18 public class Pair extends LList implements Externalizable 19 { 20 protected Object car; 21 protected Object cdr; 22 23 /** A special pair used to indicate incomplete input. */ 24 public static final Pair incompleteListMarker 25 = new ImmutablePair("<incomplete>", LList.Empty); 26 Pair(Object carval, Object cdrval)27 public Pair (Object carval, Object cdrval) 28 { 29 car = carval; 30 cdr = cdrval; 31 } 32 Pair()33 public Pair () 34 { 35 } 36 getCar()37 public Object getCar () { return car; } getCdr()38 public Object getCdr () { return cdr; } setCar(Object car)39 public void setCar(Object car) { this.car = car; } setCdr(Object cdr)40 public void setCdr(Object cdr) { this.cdr = cdr; } 41 42 /** May go away soon. */ setCarBackdoor(Object car)43 public void setCarBackdoor (Object car) { this.car = car; } setCdrBackdoor(Object cdr)44 public void setCdrBackdoor (Object cdr) { this.cdr = cdr; } 45 size()46 public int size() 47 { 48 int n = listLength(this, true); 49 if (n >= 0) 50 return n; 51 if (n == -1) 52 return Integer.MAX_VALUE; 53 throw new RuntimeException("not a true list"); 54 } 55 isEmpty()56 public boolean isEmpty() 57 { 58 return false; 59 } 60 61 // A generalization of LList.list_length 62 // FIXME is this needed, given listLength? length()63 public int length () 64 { 65 // Based on list-length implementation in 66 // Guy L Steele jr: "Common Lisp: The Language", 2nd edition, page 414 67 int n = 0; 68 Object slow = this; 69 Object fast = this; 70 for (;;) 71 { 72 if (fast == Empty) 73 return n; 74 if (! (fast instanceof Pair)) 75 { 76 if (fast instanceof Sequence) 77 { 78 int j = ((Sequence) fast).size(); 79 return j >= 0 ? n + j : j; 80 } 81 return -2; 82 } 83 Pair fast_pair = (Pair) fast; 84 Object fast_pair_cdr = fast_pair.getCdr(); 85 if (fast_pair_cdr == Empty) 86 return n+1; 87 if (fast == slow && n > 0) 88 return -1; 89 if (! (fast_pair_cdr instanceof Pair)) 90 { 91 n++; 92 fast = fast_pair_cdr; 93 continue; 94 } 95 if (!(slow instanceof Pair)) 96 return -2; 97 slow = ((Pair)slow).getCdr(); 98 fast = ((Pair)fast_pair_cdr).getCdr(); 99 n += 2; 100 } 101 } 102 hasNext(int ipos)103 public boolean hasNext (int ipos) 104 { 105 if (ipos <= 0) 106 return ipos == 0; 107 return PositionManager.getPositionObject(ipos).hasNext(); 108 } 109 nextPos(int ipos)110 public int nextPos (int ipos) 111 { 112 if (ipos <= 0) 113 { 114 if (ipos < 0) 115 return 0; 116 return PositionManager.manager 117 .register(new LListPosition(this, 1, true)); 118 } 119 LListPosition it = (LListPosition) PositionManager.getPositionObject(ipos); 120 return it.gotoNext() ? ipos : 0; 121 } 122 getPosNext(int ipos)123 public Object getPosNext (int ipos) 124 { 125 if (ipos <= 0) 126 return ipos == 0 ? getCar() : eofValue; 127 return PositionManager.getPositionObject(ipos).getNext(); 128 } 129 getPosPrevious(int ipos)130 public Object getPosPrevious (int ipos) 131 { 132 if (ipos <= 0) 133 return ipos == 0 ? eofValue : lastPair().getCar(); 134 return PositionManager.getPositionObject(ipos).getPrevious(); 135 } 136 lastPair()137 public Pair lastPair() 138 { 139 Pair pair = this; 140 for (;;) 141 { 142 Object next = pair.getCdr(); 143 if (next instanceof Pair) 144 pair = (Pair) next; 145 else 146 return pair; 147 } 148 } 149 150 /* 151 public void print(java.io.PrintWriter ps) 152 { 153 ps.print("("); 154 printNoParen(this, ps); 155 ps.print(")"); 156 } 157 */ 158 equals(Pair pair1, Pair pair2)159 static public boolean equals (Pair pair1, Pair pair2) 160 { 161 if (pair1 == pair2) 162 return true; 163 if (pair1 == null || pair2 == null) 164 return false; 165 for (;;) 166 { 167 Object x1 = pair1.getCar(); 168 Object x2 = pair2.getCar(); 169 if (x1 != x2 && (x1 == null || ! x1.equals(x2))) 170 return false; 171 x1 = pair1.getCdr(); 172 x2 = pair2.getCdr(); 173 if (x1 == x2) 174 return true; 175 if (x1 == null || x2 == null) 176 return false; 177 if (! (x1 instanceof Pair) || !(x2 instanceof Pair)) 178 return x1.equals(x2); 179 pair1 = (Pair) x1; 180 pair2 = (Pair) x2; 181 182 } 183 } 184 185 /* #ifdef JAVA2 */ compareTo(Pair pair1, Pair pair2)186 static public int compareTo (Pair pair1, Pair pair2) 187 { 188 if (pair1 == pair2) 189 return 0; 190 if (pair1 == null ) 191 return -1; 192 if (pair2 == null) 193 return 1; 194 for (;;) 195 { 196 Object x1 = pair1.getCar(); 197 Object x2 = pair2.getCar(); 198 int d = ((Comparable) x1).compareTo((Comparable) x2); 199 if (d != 0) 200 return d; 201 x1 = pair1.cdr; 202 x2 = pair2.cdr; 203 if (x1 == x2) 204 return 0; 205 if (x1 == null) 206 return -1; 207 if (x2 == null) 208 return 1; 209 if (! (x1 instanceof Pair) || !(x2 instanceof Pair)) 210 return ((Comparable) x1).compareTo((Comparable) x2); 211 pair1 = (Pair) x1; 212 pair2 = (Pair) x2; 213 } 214 } 215 compareTo(Object obj)216 public int compareTo(Object obj) 217 { 218 if (obj == Empty) 219 return 1; 220 else 221 return compareTo(this, (Pair) obj); 222 } 223 /* #endif */ 224 get(int index)225 public Object get (int index) 226 { 227 Pair pair = this; 228 int i = index; 229 while (i > 0) 230 { 231 i--; 232 Object pair_cdr = pair.getCdr(); 233 if (pair_cdr instanceof Pair) 234 pair = (Pair)pair_cdr; 235 else if (pair_cdr instanceof Sequence) 236 return ((Sequence)pair_cdr).get(i); 237 else 238 break; 239 } 240 if (i == 0) 241 return pair.getCar(); 242 else 243 throw new IndexOutOfBoundsException (); 244 } 245 equals(Object obj)246 public boolean equals (Object obj) 247 { 248 if ((obj != null) && (obj instanceof Pair)) 249 return equals (this, (Pair) obj); 250 else 251 return false; 252 } 253 make(Object car, Object cdr)254 public static Pair make (Object car, Object cdr) 255 { 256 return new Pair (car, cdr); 257 } 258 toArray()259 public Object[] toArray() 260 { 261 int len = size(); // size() 262 Object[] arr = new Object[len]; 263 int i = 0; 264 Sequence rest = this; 265 for ( ; i < len && rest instanceof Pair; i++) 266 { 267 Pair pair = (Pair) rest; 268 arr[i] = pair.getCar(); 269 rest = (Sequence) pair.getCdr(); 270 } 271 int prefix = i; 272 for ( ; i < len; i++) 273 { 274 arr[i] = rest.get(i - prefix); 275 } 276 return arr; 277 } 278 toArray(Object[] arr)279 public Object[] toArray(Object[] arr) 280 { 281 int alen = arr.length; 282 int len = length(); 283 if (len > alen) 284 { 285 // FIXME Collection spec requires arr to keep same run-time type 286 arr = new Object[len]; 287 alen = len; 288 } 289 int i = 0; 290 Sequence rest = this; 291 for ( ; i < len && rest instanceof Pair; i++) 292 { 293 Pair pair = (Pair) rest; 294 arr[i] = pair.getCar(); 295 rest = (Sequence) pair.getCdr(); 296 } 297 int prefix = i; 298 for ( ; i < len; i++) 299 { 300 arr[i] = rest.get(i - prefix); 301 } 302 if (len < alen) 303 arr[len] = null; 304 return arr; 305 } 306 307 /** 308 * @serialData Write the car followed by the cdr. 309 */ writeExternal(ObjectOutput out)310 public void writeExternal(ObjectOutput out) throws IOException 311 { 312 out.writeObject(car); 313 out.writeObject(cdr); 314 } 315 readExternal(ObjectInput in)316 public void readExternal(ObjectInput in) 317 throws IOException, ClassNotFoundException 318 { 319 car = in.readObject(); 320 cdr = in.readObject(); 321 } 322 323 /** Needed to override readResolve in LList. */ readResolve()324 public Object readResolve() throws ObjectStreamException 325 { 326 return this; 327 } 328 329 }; 330