001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library 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 GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.type;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023
024import lucee.commons.lang.SizeOf;
025import lucee.runtime.exp.ExpressionException;
026
027
028
029/**
030 * CFML array object
031 */
032public final class ArrayInt implements Sizeable,Serializable {
033        
034        private static final int NULL = 0;
035        private int[] arr;
036        private final int cap=32;
037        private int size=0;
038        private int offset=0;
039        private int offCount=0;
040        
041        /**
042         * constructor with default dimesnion (1)
043         */
044        public ArrayInt() {
045                arr=new int[offset+cap];
046        }
047        
048        /**
049         * constructor with to data to fill
050         * @param objects Objects array data to fill
051         */
052        public ArrayInt(int[] objects) {
053                arr=objects;
054                size=arr.length;
055                offset=0;
056        }
057        
058        public int get(int key, int defaultValue) {
059                if(key>size || key<1) {
060                        return defaultValue;
061                }
062                int o=arr[(offset+key)-1];
063                if(o==NULL) return defaultValue;
064                return o;
065        }
066        
067        public int get(int key) throws ExpressionException {
068                if(key<1 || key>size) {
069                        throw invalidPosition(key);
070                }
071                
072                int o=arr[(offset+key)-1];
073                
074                if(o==NULL) {
075                        throw invalidPosition(key);
076                }
077                return o;
078        }
079        
080        /**
081         * Exception method if key doesn't exist at given position
082         * @param pos
083         * @return exception
084         */
085        private ExpressionException invalidPosition(int pos) {
086                return new ExpressionException("Element at position ["+pos+"] doesn't exist in array");
087        }
088        
089        public int set(int key, int value) {
090                if(offset+key>arr.length)enlargeCapacity(key);
091                if(key>size)size=key;
092                return arr[(offset+key)-1]=value;
093        }       
094        
095        /**
096     * !!! all methods that use this method must be sync
097         * enlarge the inner array to given size
098         * @param key min size of the array
099         */
100        private synchronized void enlargeCapacity(int key) {
101                int diff=offCount-offset;
102                
103                int newSize=arr.length;
104                if(newSize<1) newSize=1;
105                while(newSize<key+offset+diff) {
106                        newSize*=2;
107                }
108                if(newSize>arr.length) {
109                        int[] na=new int[newSize];
110                        for(int i=offset;i<offset+size;i++) {
111                                na[i+diff]=arr[i];
112                        }
113                        arr=na;
114                        offset+=diff;
115                }
116        }
117        
118        /* *
119         * !!! all methods that use this method must be sync
120     * enlarge the offset if 0
121         * /
122        private void enlargeOffset() {
123                if(offset==0) {
124                        offCount=offCount==0?1:offCount*2;
125                        offset=offCount;
126                        int[] narr=new int[arr.length+offset];
127                        for(int i=0;i<size;i++) {
128                                narr[offset+i]=arr[i];
129                        }
130                        arr=narr;
131                }
132        }*/
133        
134        public int size() {
135                return size;
136        }
137        
138        public int[] keys() {
139                ArrayList lst=new ArrayList();          
140                int count=0;
141                for(int i=offset;i<offset+size;i++) {
142                        int o=arr[i];
143                        count++;
144                        if(o!=NULL) lst.add(Integer.valueOf(count));
145                }
146
147                int[] ints=new int[lst.size()];
148                
149                for(int i=0;i<ints.length;i++){
150                        ints[i]=((Integer)lst.get(i)).intValue();
151                }
152                return ints;
153        }
154        
155        public int remove(int key) throws ExpressionException {
156                if(key>size || key<1) throw invalidPosition(key);
157                int obj=get(key,NULL);
158                for(int i=(offset+key)-1;i<(offset+size)-1;i++) {
159                        arr[i]=arr[i+1];
160                }
161                size--;
162                return obj;
163        }
164        
165        public int removeEL(int key) {
166            if(key>size || key<1) return NULL;
167                int obj=get(key,NULL);
168            
169                for(int i=(offset+key)-1;i<(offset+size)-1;i++) {
170                        arr[i]=arr[i+1];
171                }
172                size--;
173                return obj;
174        }
175        
176        public void clear() {
177            if(size()>0) {
178                        arr=new int[cap];
179                        size=0;
180                        offCount=1;
181                        offset=0;
182            }
183        }
184        
185    public int add(int o) {
186        if(offset+size+1>arr.length)enlargeCapacity(size+1);
187        arr[offset+size]=o;
188        size++;
189        return o;
190    }
191        
192        public int[] toArray() {
193                int[] rtn=new int[size];
194                int count=0;
195                for(int i=offset;i<offset+size;i++) {
196                        rtn[count++]=arr[i];
197                }
198                return rtn;
199        }
200
201    public boolean contains(int key) {
202        return get(key,NULL)!=NULL;
203    }
204
205        @Override
206        public long sizeOf() {
207                return SizeOf.size(arr)
208                +SizeOf.size(cap)
209                +SizeOf.size(size)
210                +SizeOf.size(offset)
211                +SizeOf.size(offCount)
212                +SizeOf.REF_SIZE;
213        }
214
215}