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 org.ocamljava.runtime.values.Value;
022
023/**
024 * The {@code OCamlOption} class is the wrapper class for OCaml values of
025 * type {@code 'a * 'b * 'c * 'd}.
026 *
027 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a>
028 * @version 2.0
029 * @since 2.0
030 */
031public final class OCamlTuple4<T0 extends OCamlValue,
032                               T1 extends OCamlValue,
033                               T2 extends OCamlValue,
034                               T3 extends OCamlValue> extends OCamlValue {
035
036    /** Wrapper for nested value. */
037    private final Wrapper<T0> wrapper0;
038
039    /** Wrapper for nested value. */
040    private final Wrapper<T1> wrapper1;
041
042    /** Wrapper for nested value. */
043    private final Wrapper<T2> wrapper2;
044
045    /** Wrapper for nested value. */
046    private final Wrapper<T3> wrapper3;
047
048    /**
049     * Constructs a new instance wrapping the passed value.
050     * @param w0 wrapper for nested value - should not be {@code null}
051     * @param w1 wrapper for nested value - should not be {@code null}
052     * @param w2 wrapper for nested value - should not be {@code null}
053     * @param w3 wrapper for nested value - should not be {@code null}
054     * @param v value to wrap - should not be {@code null}
055     */
056    private OCamlTuple4(final Wrapper<T0> w0,
057                        final Wrapper<T1> w1,
058                        final Wrapper<T2> w2,
059                        final Wrapper<T3> w3,
060                        final Value v) {
061        super(v);
062        assert w0 != null : "null w0";
063        assert w1 != null : "null w1";
064        assert w2 != null : "null w2";
065        assert w3 != null : "null w3";
066        this.wrapper0 = w0;
067        this.wrapper1 = w1;
068        this.wrapper2 = w2;
069        this.wrapper3 = w3;
070    } // end constructor(Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>, Value)
071
072    /**
073     * {@inheritDoc}
074     */
075    @Override
076    public Wrapper<? extends OCamlTuple4<T0, T1, T2, T3>> getWrapper() {
077        return OCamlTuple4.wrapper(this.wrapper0,
078                                   this.wrapper1,
079                                   this.wrapper2,
080                                   this.wrapper3);
081    } // end method 'getWrapper()'
082
083    /**
084     * {@inheritDoc}
085     */
086    @Override
087    public Wrapper<? extends OCamlValue> getWrapper(final int idx) {
088        switch (idx) {
089        case 0: return this.wrapper0;
090        case 1: return this.wrapper1;
091        case 2: return this.wrapper2;
092        case 3: return this.wrapper3;
093        default: return OCamlUnit.WRAPPER;
094        } // end switch
095    } // end method 'getWrapper(int)'
096
097    /**
098     * Returns the first element of the wrapped value.
099     * @return the first element of the wrapped value
100     */
101    public T0 get0() {
102        return this.wrapper0.wrap(this.value.get0());
103    } // end method 'get0()'
104
105    /**
106     * Returns the second element of the wrapped value.
107     * @return the second element of the wrapped value
108     */
109    public T1 get1() {
110        return this.wrapper1.wrap(this.value.get1());
111    } // end method 'get1()'
112
113    /**
114     * Returns the third element of the wrapped value.
115     * @return the third element of the wrapped value
116     */
117    public T2 get2() {
118        return this.wrapper2.wrap(this.value.get2());
119    } // end method 'get2()'
120
121    /**
122     * Returns the fourth element of the wrapped value.
123     * @return the fourth element of the wrapped value
124     */
125    public T3 get3() {
126        return this.wrapper3.wrap(this.value.get3());
127    } // end method 'get3()'
128
129    /**
130     * {@inheritDoc}
131     */
132    @Override
133    public int hashCode() {
134        return this.value.get0().hashCode()
135            + this.value.get1().hashCode()
136            + this.value.get2().hashCode()
137            + this.value.get3().hashCode();
138    } // end method 'hashCode()'
139
140    /**
141     * {@inheritDoc}
142     */
143    @Override
144    public boolean equals(final Object obj) {
145        if (obj instanceof OCamlTuple4) {
146            final OCamlTuple4<?, ?, ?, ?> that = (OCamlTuple4) obj;
147            return this.value.get0().equals(that.value.get0())
148                && this.value.get1().equals(that.value.get1())
149                && this.value.get2().equals(that.value.get2())
150                && this.value.get3().equals(that.value.get3());
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("OCamlTuple4(");
163        sb.append(this.wrapper0.wrap(this.value.get0()).toString());
164        sb.append(", ");
165        sb.append(this.wrapper1.wrap(this.value.get1()).toString());
166        sb.append(", ");
167        sb.append(this.wrapper2.wrap(this.value.get2()).toString());
168        sb.append(", ");
169        sb.append(this.wrapper3.wrap(this.value.get3()).toString());
170        sb.append(")");
171        return sb.toString();
172    } // end method 'toString()'
173
174    /**
175     * Constructs a new {@code 'a * 'b * 'c * 'c * 'd} value, and wraps it.
176     * @param v0 first element of value to wrap
177     * @param v1 second element of value to wrap
178     * @param v2 third element of value to wrap
179     * @param v3 fourth element of value to wrap
180     * @return a new {@code OCamlTuple4} instance wrapping the passed values
181     */
182    @SuppressWarnings("unchecked")
183    public static <T0 extends OCamlValue,
184                   T1 extends OCamlValue,
185                   T2 extends OCamlValue,
186                   T3 extends OCamlValue>
187        OCamlTuple4<T0, T1, T2, T3> create(final T0 v0,
188                                           final T1 v1,
189                                           final T2 v2,
190                                           final T3 v3) {
191        assert v0 != null : "null v0";
192        assert v1 != null : "null v1";
193        assert v2 != null : "null v2";
194        assert v3 != null : "null v3";
195        return new OCamlTuple4<T0, T1, T2, T3>((Wrapper<T0>) v0.getWrapper(),
196                                               (Wrapper<T1>) v1.getWrapper(),
197                                               (Wrapper<T2>) v2.getWrapper(),
198                                               (Wrapper<T3>) v3.getWrapper(),
199                                               Value.createBlock(0,
200                                                                 v0.value(),
201                                                                 v1.value(),
202                                                                 v2.value(),
203                                                                 v3.value()));
204    } // end method 'create(T0, T1, T2, T3)'
205
206    /**
207     * Wraps the passed value.
208     * @param w0 wrapper for nested value - should not be {@code null}
209     * @param w1 wrapper for nested value - should not be {@code null}
210     * @param w2 wrapper for nested value - should not be {@code null}
211     * @param w3 wrapper for nested value - should not be {@code null}
212     * @param v value to wrap - should not be {@code null}
213     * @return a new {@code OCamlTuple4} instance wrapping the passed value
214     */
215    public static <T0 extends OCamlValue,
216                   T1 extends OCamlValue,
217                   T2 extends OCamlValue,
218                   T3 extends OCamlValue>
219        OCamlTuple4<T0, T1, T2, T3> wrap(final Wrapper<T0> w0,
220                                         final Wrapper<T1> w1,
221                                         final Wrapper<T2> w2,
222                                         final Wrapper<T3> w3,
223                                         final Value v) {
224        assert w0 != null : "null w0";
225        assert w1 != null : "null w1";
226        assert w2 != null : "null w2";
227        assert w3 != null : "null w3";
228        assert v != null : "null v";
229        return new OCamlTuple4<T0, T1, T2, T3>(w0, w1, w2, w3, v);
230    } // end method 'wrap(Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>, Value)'
231
232    /**
233     * Returns a wrapper for {@code OCamlTuple4} values.
234     * @param w0 wrapper for nested value - should not be {@code null}
235     * @param w1 wrapper for nested value - should not be {@code null}
236     * @param w2 wrapper for nested value - should not be {@code null}
237     * @param w3 wrapper for nested value - should not be {@code null}
238     * @return a wrapper for {@code OCamlTuple4} values
239     */
240    @SuppressWarnings("unchecked")
241    public static <T0 extends OCamlValue,
242                   T1 extends OCamlValue,
243                   T2 extends OCamlValue,
244                   T3 extends OCamlValue>
245        Wrapper<? extends OCamlTuple4<T0, T1, T2, T3>> wrapper(final Wrapper<T0> w0,
246                                                               final Wrapper<T1> w1,
247                                                               final Wrapper<T2> w2,
248                                                               final Wrapper<T3> w3) {
249        return new ComposedWrapper<OCamlTuple4<T0, T1, T2, T3>>(w0, w1, w2, w3) {
250            /**
251             * {@inheritDoc}
252             */
253            @Override
254                public OCamlTuple4<T0, T1, T2, T3> wrap(final Value v) {
255                return new OCamlTuple4<T0, T1, T2, T3>(w0, w1, w2, w3, v);
256            } // end method 'wrap(Value)'
257        }; // end anonymous inner-class
258    } // end method 'wrapper(Wrapper<T0>, Wrapper<T1>, Wrapper<T2>, Wrapper<T3>)'
259
260} // end class 'OCamlTuple4'