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'