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> list component type
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    private Pointer<list_node<T>> node() {
152        return (Pointer) Pointer.getPointer(this).as(list_node.class);
153    }
154    
155    @Deprecated
156    @Field(0)
157    public Pointer<list_node<T>> next() {
158        return io.getPointerField(this, 0);
159    }
160
161    @Deprecated
162    @Field(0)
163    public void next(Pointer<list_node<T>> value) {
164        io.setPointerField(this, 0, value);
165    }
166
167    @Deprecated
168    @Field(1)
169    public Pointer<list_node<T>> prev() {
170        return io.getPointerField(this, 1);
171    }
172
173    @Deprecated
174    @Field(1)
175        public void prev(Pointer<list_node<T>> value) {
176                io.setPointerField(this, 1, value);
177        }
178        //@Constructor(-1)
179        public list(Type t) {
180                super((Void)null, CPPRuntime.SKIP_CONSTRUCTOR, t);
181        }
182        public list(Pointer<? extends list<T>> peer, Type t) {
183                super(peer, t);
184        }
185        private void checkNotEmpty() {
186                if (isRoot(next()) && isRoot(prev())) 
187                        throw new NoSuchElementException();
188        }
189        public boolean empty() {
190        return Pointer.getPeer(next()) == Pointer.getPeer(node());
191        }
192        public T back() {
193                checkNotEmpty();
194                return next().get().get();
195        }
196        public T front() {
197                checkNotEmpty();
198        Pointer<list_node<T>> prev = prev(), next = next();
199        Pointer<list_node<T>> nextPrev = next == null ? null : next.get().prev();
200        Pointer<list_node<T>> prevNext = prev == null ? null : prev.get().next();
201        int[] nextValues = next == null ? null : next.getInts(20);
202        int[] prevValues = prev == null ? null : prev.getInts(20);
203        
204        list_node<T> n = prev.get();
205        int[] values = pointerTo(n).getInts(20);
206        return n.get();
207//              return prev().get().get();
208        }
209
210    private boolean same(Pointer a, Pointer b) {
211        return getPeer(a) == getPeer(b);
212    }
213
214    private boolean isRoot(Pointer a) {
215        return same(a, getPointer(this));
216    }
217
218    protected void hook(Pointer<list_node<T>> prev, Pointer<list_node<T>> next, T value) {
219        list_node<T> tmp = createNode();
220        Pointer<list_node<T>> pTmp = getPointer(tmp);
221        tmp.set(value);
222        tmp.next(next);
223        tmp.prev(prev);
224        if (!isRoot(next)) {
225            next.get().prev(pTmp);
226        }
227        if (!isRoot(prev)) {
228            prev.get().next(pTmp);
229        }
230    }
231
232    public void push_back(T value) {
233        hook(prev(), null, value);
234    }
235
236    public void push_front(T value) {
237        hook(null, next(), value);
238    }
239}