001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj.cpp.std;
032
033import org.bridj.ann.Template;
034import org.bridj.cpp.CPPObject;
035
036
037import org.bridj.BridJ;
038import org.bridj.Pointer;
039import org.bridj.ann.Field;
040import org.bridj.ann.Struct;
041import org.bridj.cpp.CPPRuntime;
042
043import java.lang.reflect.Type;
044import java.util.NoSuchElementException;
045import org.bridj.BridJRuntime;
046import org.bridj.JNI;
047
048import static org.bridj.Pointer.*;
049import org.bridj.ann.Array;
050import org.bridj.ann.Library;
051import org.bridj.ann.Ptr;
052
053/**
054 * Binding for <a href="http://www.sgi.com/tech/stl/Vector.html">STL's
055 * std::vector</a> class.
056 *
057 * @author ochafik
058 * @param <T>
059 */
060@Template({Type.class})
061@Struct(customizer = STL.class)
062public class list<T> extends CPPObject {
063
064    @Library("c")
065    protected static native @Ptr
066    long malloc(@Ptr long size);
067
068    @Library("c")
069    protected static native void free(@Ptr long address);
070
071    @Template({Type.class})
072    public static class list_node<T> extends CPPObject {
073
074        @Deprecated
075        @Field(0)
076        public Pointer<list_node<T>> next() {
077            return io.getPointerField(this, 0);
078        }
079
080        @Deprecated
081        @Field(0)
082        public void next(Pointer<list_node<T>> value) {
083            io.setPointerField(this, 0, value);
084        }
085
086        @Deprecated
087        @Field(1)
088        public Pointer<list_node<T>> prev() {
089            return io.getPointerField(this, 1);
090        }
091
092        @Field(1)
093        public void prev(Pointer<list_node<T>> value) {
094            io.setPointerField(this, 1, value);
095        }
096
097        @Deprecated
098        @Field(2)
099        @Array(1)
100        public Pointer<T> data() {
101            return io.getPointerField(this, 2);
102        }
103
104        public list_node(Type t) {
105            super((Void) null, CPPRuntime.SKIP_CONSTRUCTOR, t);
106        }
107
108        public list_node(Pointer<? extends list_node> peer, Type t) {
109            super(peer, t);
110            if (!isValid()) {
111                throw new RuntimeException("Invalid list internal data ! Are you trying to use an unsupported version of the STL ?");
112            }
113        }
114
115        protected boolean isValid() {
116            long next = getPeer(next());
117            long prev = getPeer(prev());
118            if (next == 0 && prev == 0) {
119                return false;
120            }
121            return true; // TODO other checks?
122        }
123
124        public T get() {
125            return data().get();
126        }
127
128        public void set(T value) {
129            data().set(value);
130        }
131    }
132    protected volatile Type _T;
133
134    protected Type T() {
135        if (_T == null) {
136            _T = (Type) CPPRuntime.getInstance().getTemplateParameters(this, list.class)[0];
137        }
138        return _T;
139    }
140
141    protected list_node<T> createNode() {
142        Type T = T();
143        long size = BridJ.sizeOf(T);
144        return new list_node<T>((Pointer) pointerToAddress(malloc(size)), T);
145    }
146
147    protected void deleteNode(list_node<T> node) {
148        free(Pointer.getAddress(node, list_node.class));
149    }
150
151    @Deprecated
152    @Field(0)
153    public Pointer<list_node<T>> next() {
154        return io.getPointerField(this, 0);
155    }
156
157    @Deprecated
158    @Field(0)
159    public void next(Pointer<list_node<T>> value) {
160        io.setPointerField(this, 0, value);
161    }
162
163    @Deprecated
164    @Field(1)
165    public Pointer<list_node<T>> prev() {
166        return io.getPointerField(this, 1);
167    }
168
169    @Deprecated
170    @Field(1)
171        public void prev(Pointer<list_node<T>> value) {
172                io.setPointerField(this, 1, value);
173        }
174        //@Constructor(-1)
175        public list(Type t) {
176                super((Void)null, CPPRuntime.SKIP_CONSTRUCTOR, t);
177        }
178        public list(Pointer<? extends list<T>> peer, Type t) {
179                super(peer, t);
180        }
181        private void checkNotEmpty() {
182                if (isRoot(next()) && isRoot(prev())) 
183                        throw new NoSuchElementException();
184        }
185        public boolean empty() {
186                return next() != null;
187        }
188        public T front() {
189                checkNotEmpty();
190                return next().get().get();
191        }
192        public T back() {
193                checkNotEmpty();
194        Pointer<list_node<T>> prev = prev(), next = next();
195        Pointer<list_node<T>> nextPrev = next == null ? null : next.get().prev();
196        Pointer<list_node<T>> prevNext = prev == null ? null : prev.get().next();
197        int[] nextValues = next == null ? null : next.getInts(20);
198        int[] prevValues = prev == null ? null : prev.getInts(20);
199        
200        list_node<T> n = prev.get();
201        int[] values = pointerTo(n).getInts(20);
202        return n.get();
203//              return prev().get().get();
204        }
205
206    private boolean same(Pointer a, Pointer b) {
207        return getPeer(a) == getPeer(b);
208    }
209
210    private boolean isRoot(Pointer a) {
211        return same(a, getPointer(this));
212    }
213
214    protected void hook(Pointer<list_node<T>> prev, Pointer<list_node<T>> next, T value) {
215        list_node<T> tmp = createNode();
216        Pointer<list_node<T>> pTmp = getPointer(tmp);
217        tmp.set(value);
218        tmp.next(next);
219        tmp.prev(prev);
220        if (!isRoot(next)) {
221            next.get().prev(pTmp);
222        }
223        if (!isRoot(prev)) {
224            prev.get().next(pTmp);
225        }
226    }
227
228    public void push_back(T value) {
229        hook(prev(), null, value);
230    }
231
232    public void push_front(T value) {
233        hook(null, next(), value);
234    }
235}