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.NoSuchElementException; 023 024import org.ocamljava.runtime.values.Value; 025 026/** 027 * The {@code OCamlArray} class is the wrapper class for OCaml values of 028 * type {@code 'a array}. 029 * 030 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a> 031 * @version 2.0 032 * @since 2.0 033 */ 034public final class OCamlArray<T extends OCamlValue> extends OCamlValue implements Iterable<T> { 035 036 /** Wrapper for elements. */ 037 private final Wrapper<T> wrapper; 038 039 /** 040 * Constructs a new instance wrapping the passed value. 041 * @param w wrapper for elements - should not be {@code null} 042 * @param v value to wrap - should not be {@code null} 043 */ 044 private OCamlArray(final Wrapper<T> w, final Value v) { 045 super(v); 046 assert w != null : "null w"; 047 this.wrapper = w; 048 } // end constructor(Wrapper<T>, Value) 049 050 /** 051 * {@inheritDoc} 052 */ 053 @Override 054 public Wrapper<? extends OCamlArray<T>> getWrapper() { 055 return OCamlArray.wrapper(this.wrapper); 056 } // end method 'getWrapper()' 057 058 /** 059 * {@inheritDoc} 060 */ 061 @Override 062 public Wrapper<? extends OCamlValue> getWrapper(final int idx) { 063 switch (idx) { 064 case 0: return this.wrapper; 065 default: return OCamlUnit.WRAPPER; 066 } // end switch 067 } // end method 'getWrapper(int)' 068 069 /** 070 * Returns the value at the specified index. 071 * @param idx index of value 072 * @return the value at the specified index 073 */ 074 public T get(final int idx) { 075 return this.wrapper.wrap(this.value.get(idx)); 076 } // end method 'get(int)' 077 078 /** 079 * Changes the value at the specified index. 080 * @param idx index of value to modify 081 * @param v new value 082 */ 083 public void set(final int idx, final T v) { 084 this.value.set(idx, v.value()); 085 } // end method 'set(int, T)' 086 087 /** 088 * Returns the array length. 089 * @return the array length 090 */ 091 public long length() { 092 return this.value.sizeValues(); 093 } // end method 'length()' 094 095 /** 096 * {@inheritDoc} 097 */ 098 @Override 099 public Iterator<T> iterator() { 100 return new Iterator<T>() { 101 /** Index of next element to return. */ 102 private long next = 0L; 103 104 /** 105 * {@inheritDoc} 106 */ 107 @Override 108 public boolean hasNext() { 109 return this.next < OCamlArray.this.value.sizeValues(); 110 } // end method 'hasNext()' 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override 116 public T next() { 117 if (hasNext()) { 118 final Value res = OCamlArray.this.value.get(this.next++); 119 return OCamlArray.this.wrapper.wrap(res); 120 } else { 121 throw new NoSuchElementException(); 122 } // end if/else 123 } // end method 'next()' 124 125 /** 126 * {@inheritDoc} 127 */ 128 @Override 129 public void remove() { 130 throw new UnsupportedOperationException(); 131 } // end method 'remove()' 132 }; // end anonymous inner-class 133 } // end method 'iterator()' 134 135 /** 136 * {@inheritDoc} 137 */ 138 @Override 139 public int hashCode() { 140 return this.value.hashCode(); 141 } // end method 'hashCode()' 142 143 /** 144 * {@inheritDoc} 145 */ 146 @Override 147 public boolean equals(final Object obj) { 148 if (obj instanceof OCamlArray) { 149 final OCamlArray<?> that = (OCamlArray) obj; 150 return this == that; 151 } else { 152 return false; 153 } // end if/else 154 } // end method 'equals(Object)' 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override 160 public String toString() { 161 final StringBuilder sb = new StringBuilder(); 162 sb.append("OCamlArray("); 163 int i = 0; 164 final int sz = (int) this.value.sizeValues(); 165 while ((i < sz) && (sb.length() < 256)) { 166 if (i > 0) { 167 sb.append(", "); 168 } // end if 169 final Value v = this.value.get(i++); 170 final T w = this.wrapper.wrap(v); 171 sb.append(w.toString()); 172 } // end while 173 if (i < sz) { 174 sb.append("..."); 175 } // end if 176 sb.append(")"); 177 return sb.toString(); 178 } // end method 'toString()' 179 180 /** 181 * Constructs a new {@code 'a array} value, and wraps it. 182 * @param sz array size - should not be negative 183 * @param v initial value for each array element - should not be {@code null} 184 * @return a new {@code OCamlArray} instance wrapping the passed value 185 */ 186 @SuppressWarnings("unchecked") 187 public static <T extends OCamlValue> OCamlArray<T> create(final int sz, 188 final T v) { 189 assert sz >= 0 : "negative sz"; 190 assert v != null : "null v"; 191 if (v instanceof OCamlFloat) { 192 final double d = ((OCamlFloat) v).doubleValue(); 193 final Value wrapped = Value.createDoubleArray(sz); // XXX definir Value.createDoubleArray(tag, sz, initvalue) 194 for (int i = 0; i < sz; i++) { 195 wrapped.setDouble(i, d); 196 } // end for 197 return new OCamlArray<T>((Wrapper<T>) v.getWrapper(), wrapped); 198 } else { 199 final Value wrapped = Value.createBlock(0, sz); // XXX definir Value.createBlock(tag, sz, initvalue) 200 for (int i = 0; i < sz; i++) { 201 wrapped.set(i, v.value()); 202 } // end for 203 return new OCamlArray<T>((Wrapper<T>) v.getWrapper(), wrapped); 204 } // end if/else 205 } // end method 'create(int, T)' 206 207 /** 208 * Constructs a new {@code 'a array} value, and wraps it. <br/> 209 * The passed array is copied and hence its modification are not 210 * reflected by the wrapped value. 211 * @param w wrapper for elements - should not be {@code null} 212 * @param v array to wrap - should not be {@code null} 213 * @return a new {@code OCamlArray} instance wrapping the passed value 214 */ 215 @SuppressWarnings("unchecked") 216 public static <T extends OCamlValue> OCamlArray<T> create(final Wrapper<T> w, 217 final T[] v) { 218 assert w != null : "null w"; 219 assert v != null : "null v"; 220 final int sz = v.length; 221 if ((sz > 0) && (v[0] instanceof OCamlFloat)) { 222 final Value wrapped = Value.createDoubleArray(sz); 223 for (int i = 0; i < sz; i++) { 224 wrapped.setDouble(i, ((OCamlFloat) v[i]).doubleValue()); 225 } // end for 226 return new OCamlArray<T>(w, wrapped); 227 } else { 228 final Value wrapped = Value.createBlock(0, sz); 229 for (int i = 0; i < sz; i++) { 230 wrapped.set(i, v[i].value()); 231 } // end for 232 return new OCamlArray<T>(w, wrapped); 233 } // end if/else 234 } // end method 'create(T[])' 235 236 /** 237 * Wraps the passed value. 238 * @param w wrapper for elements - should not be {@code null} 239 * @param v value to wrap - should not be {@code null} 240 * @return a new {@code OCamlArray} instance wrapping the passed value 241 */ 242 public static <T extends OCamlValue> OCamlArray<T> wrap(final Wrapper<T> w, 243 final Value v) { 244 assert v != null : "null v"; 245 return new OCamlArray<T>(w, v); 246 } // end method 'wrap(Wrapper<T>, Value)' 247 248 /** 249 * Returns a wrapper for {@code OCamlArray} values. 250 * @param w wrapper for elements - should not be {@code null} 251 * @return a wrapper for {@code OCamlArray} values 252 */ 253 @SuppressWarnings("unchecked") 254 public static <T extends OCamlValue> Wrapper<? extends OCamlArray<T>> wrapper(final Wrapper<T> w) { 255 return new ComposedWrapper<OCamlArray<T>>(w) { 256 /** 257 * {@inheritDoc} 258 */ 259 @Override 260 public OCamlArray<T> wrap(final Value v) { 261 return new OCamlArray<T>(w, v); 262 } // end method 'wrap(Value)' 263 }; // end anonymous inner-class 264 } // end method 'wrapper()' 265 266} // end class 'OCamlArray'