001/* 002 * This file is part of OCaml-Java runtime. 003 * Copyright (C) 2007-2013 Xavier Clerc. 004 * 005 * OCaml-Java runtime is free software; you can redistribute it and/or modify 006 * it under the terms of the GNU Lesser General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * OCaml-Java runtime is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.ocamljava.runtime.wrappers; 020 021import java.util.Iterator; 022import java.util.List; 023import java.util.ListIterator; 024import java.util.NoSuchElementException; 025 026import org.ocamljava.runtime.values.BlockValue; 027import org.ocamljava.runtime.values.Value; 028 029/** 030 * The {@code OCamlList} class is the wrapper class for OCaml values of 031 * type {@code 'a list}. 032 * 033 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a> 034 * @version 2.0 035 * @since 2.0 036 */ 037public final class OCamlList<T extends OCamlValue> extends OCamlValue implements Iterable<T> { 038 039 /** Wrapper for elements. */ 040 private final Wrapper<T> wrapper; 041 042 /** 043 * Constructs a new instance wrapping the passed value. 044 * @param w wrapper for elements - should not be {@code null} 045 * @param v value to wrap - should not be {@code null} 046 */ 047 private OCamlList(final Wrapper<T> w, final Value v) { 048 super(v); 049 assert w != null : "null w"; 050 this.wrapper = w; 051 } // end constructor(Wrapper<T>, Value) 052 053 /** 054 * {@inheritDoc} 055 */ 056 @Override 057 public Wrapper<? extends OCamlList<T>> getWrapper() { 058 return OCamlList.wrapper(this.wrapper); 059 } // end method 'getWrapper()' 060 061 /** 062 * {@inheritDoc} 063 */ 064 @Override 065 public Wrapper<? extends OCamlValue> getWrapper(final int idx) { 066 switch (idx) { 067 case 0: return this.wrapper; 068 default: return OCamlUnit.WRAPPER; 069 } // end switch 070 } // end method 'getWrapper(int)' 071 072 /** 073 * Tests whether the list is empty. 074 * @return {@code true} if the list is empty, {@code false} otherwise 075 */ 076 public boolean isEmpty() { 077 return this.value.isLong(); 078 } // end method 'isEmpty()' 079 080 /** 081 * Returns the list length. 082 * @return the list length 083 */ 084 public long length() { 085 long res = 0L; 086 Value curr = this.value; 087 while (curr.isBlock()) { 088 res++; 089 curr = curr.get1(); 090 } // end while 091 return res; 092 } // end method 'length()' 093 094 /** 095 * Returns the head of the list. 096 * @return the head of the list, of {@code null} if the list is empty 097 */ 098 public T head() { 099 if (this.value.isBlock()) { 100 return this.wrapper.wrap(this.value.get0()); 101 } else { 102 return null; 103 } // end if/else 104 } // end method 'head()' 105 106 /** 107 * Returns the tail of the list. 108 * @return the tail of the list, of {@code null} if the list is empty 109 */ 110 public OCamlList<T> tail() { 111 if (this.value.isBlock()) { 112 return new OCamlList<T>(this.wrapper, this.value.get1()); 113 } else { 114 return null; 115 } // end if/else 116 } // end method 'tail()' 117 118 /** 119 * {@inheritDoc} 120 */ 121 @Override 122 public Iterator<T> iterator() { 123 return new Iterator<T>() { 124 /** Index of next element to return. */ 125 private Value next = OCamlList.this.value; 126 127 /** 128 * {@inheritDoc} 129 */ 130 @Override 131 public boolean hasNext() { 132 return this.next.isBlock(); 133 } // end method 'hasNext()' 134 135 /** 136 * {@inheritDoc} 137 */ 138 @Override 139 public T next() { 140 if (hasNext()) { 141 final Value res = this.next.get0(); 142 this.next = this.next.get1(); 143 return OCamlList.this.wrapper.wrap(res); 144 } else { 145 throw new NoSuchElementException(); 146 } // end if/else 147 } // end method 'next()' 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public void remove() { 154 throw new UnsupportedOperationException(); 155 } // end method 'remove()' 156 }; // end anonymous inner-class 157 } // end method 'iterator()' 158 159 /** 160 * {@inheritDoc} 161 */ 162 @Override 163 public int hashCode() { 164 return this.value.hashCode(); 165 } // end method 'hashCode()' 166 167 /** 168 * {@inheritDoc} 169 */ 170 @Override 171 public boolean equals(final Object obj) { 172 if (obj instanceof OCamlList) { 173 final OCamlList<?> that = (OCamlList) obj; 174 return this == that; 175 } else { 176 return false; 177 } // end if/else 178 } // end method 'equals(Object)' 179 180 /** 181 * {@inheritDoc} 182 */ 183 @Override 184 public String toString() { 185 final StringBuilder sb = new StringBuilder(); 186 sb.append("OCamlList("); 187 Value curr = this.value; 188 while (curr.isBlock() && (sb.length() < 256)) { 189 if (curr != this.value) { 190 sb.append(", "); 191 } // end if 192 final Value v = curr.get0(); 193 curr = curr.get1(); 194 final T w = this.wrapper.wrap(v); 195 sb.append(w.toString()); 196 } // end while 197 if (curr.isBlock()) { 198 sb.append("..."); 199 } // end if 200 sb.append(")"); 201 return sb.toString(); 202 } // end method 'toString()' 203 204 /** 205 * Constructs a new {@code 'a list} value, and wraps it. <br/> 206 * The passed list is copied and hence its modification are not 207 * reflected by the wrapped value. 208 * @param w wrapper for elements - should not be {@code null} 209 * @param v list to wrap - should not be {@code null} 210 * @return a new {@code OCamlList} instance wrapping the passed value 211 */ 212 @SuppressWarnings("unchecked") 213 public static <T extends OCamlValue> OCamlList<T> create(final Wrapper<T> w, 214 final List<T> v) { 215 assert w != null : "null w"; 216 assert v != null : "null v"; 217 Value wrapped = Value.EMPTY_LIST; 218 final ListIterator<T> it = v.listIterator(v.size()); 219 T e = null; 220 while (it.hasPrevious()) { 221 e = it.previous(); 222 wrapped = Value.createBlock(BlockValue.TAG_CONS, 223 e.value(), 224 wrapped); 225 } // end while 226 return new OCamlList<T>(w, wrapped); 227 } // end method 'create(Wrapper<T>, List<T>)' 228 229 // XXX should be removed -- unsafe as wrapper is unknown if list is empty 230 // XXX BUT SEEMS TO BE USED IN OCAMLWRAP 231 @SuppressWarnings("unchecked") 232 public static <T extends OCamlValue> OCamlList<T> create(final List<T> v) { 233 assert v != null : "null v"; 234 if (v.size() == 0) { 235 return create((Wrapper<T>) OCamlUnit.WRAPPER, v); 236 } else { 237 return create((Wrapper<T>) v.get(0).getWrapper(), v); 238 } // end if/else 239 } // end method 'create(List<T>)' 240 241 /** 242 * Constructs a new {@code 'a list} value. 243 * @param w wrapper for elements - should not be {@code null} 244 * @return a new {@code OCamlList} instance wrapping the empty list 245 */ 246 @SuppressWarnings("unchecked") 247 public static <T extends OCamlValue> OCamlList<T> create(final Wrapper<T> w) { 248 assert w != null : "null w"; 249 return new OCamlList<T>(w, Value.EMPTY_LIST); 250 } // end method 'create()' 251 252 /** 253 * Constructs a new {@code 'a list} value. 254 * @param hd list head - should not be {@code null} 255 * @param tl list tail - should not be {@code null} 256 * @return a new {@code OCamlList} instance wrapping the empty list 257 */ 258 @SuppressWarnings("unchecked") 259 public static <T extends OCamlValue> OCamlList<T> create(final T hd, 260 final OCamlList<T> tl) { 261 assert hd != null : "null hd"; 262 assert tl != null : "null tl"; 263 final Value v = Value.createBlock(BlockValue.TAG_CONS, hd.value(), tl.value()); 264 return new OCamlList<T>((Wrapper<T>) hd.getWrapper(), v); 265 } // end method 'create(T, OCamlList<T>)' 266 267 /** 268 * Wraps the passed value. 269 * @param w wrapper for elements - should not be {@code null} 270 * @param v value to wrap - should not be {@code null} 271 * @return a new {@code OCamlList} instance wrapping the passed value 272 */ 273 public static <T extends OCamlValue> OCamlList<T> wrap(final Wrapper<T> w, 274 final Value v) { 275 assert w != null : "null w"; 276 assert v != null : "null v"; 277 return new OCamlList<T>(w, v); 278 } // end method 'wrap(Wrapper<T>, Value)' 279 280 /** 281 * Returns a wrapper for {@code OCamlList} values. 282 * @param w wrapper for elements - should not be {@code null} 283 * @return a wrapper for {@code OCamlList} values 284 */ 285 @SuppressWarnings("unchecked") 286 public static <T extends OCamlValue> Wrapper<? extends OCamlList<T>> wrapper(final Wrapper<T> w) { 287 return new ComposedWrapper<OCamlList<T>>(w) { 288 /** 289 * {@inheritDoc} 290 */ 291 @Override 292 public OCamlList<T> wrap(final Value v) { 293 return new OCamlList<T>(w, v); 294 } // end method 'wrap(Value)' 295 }; // end anonymous inner-class 296 } // end method 'wrapper()' 297 298} // end class 'OCamlList'