View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.ds;
33  
34  import java.util.Collection;
35  import java.util.Iterator;
36  import java.util.List;
37  import java.util.ListIterator;
38  import java.util.Objects;
39  import javax.annotation.ParametersAreNullableByDefault;
40  import org.spf4j.base.Arrays;
41  
42  /**
43   * A simple stack implementation that supports null elements.
44   * @author Zoltan Farkas
45   * @param <T>
46   */
47  @ParametersAreNullableByDefault
48  @SuppressWarnings("checkstyle:VisibilityModifier")
49  public class SimpleStackNullSupport<T>
50          implements List<T> {
51  
52    /**
53     * stack default initial size
54     */
55    private static final int DEFAULT_SIZE = 32;
56  
57    /**
58     * the stack storage
59     */
60    T[] elems;
61  
62    /**
63     * the top element position
64     */
65    int top;
66  
67    /**
68     * construct a stack with specified size
69     */
70    public SimpleStackNullSupport(final int size) {
71      elems = (T[]) new Object[size];
72      top = 0;
73    }
74  
75    /**
76     * Construct a stack, default size is 20
77     */
78    public SimpleStackNullSupport() {
79      this(DEFAULT_SIZE);
80    }
81  
82    /**
83     * check if stack is empty
84     *
85     * @return boolean
86     */
87    @Override
88    public final boolean isEmpty() {
89      return top == 0;
90    }
91  
92    /**
93     * push object into stack
94     *
95     * @param o Object
96     */
97    public final void push(final T o) {
98      int t = top + 1;
99      ensureCapacity(t);
100     elems[top] = o;
101     top = t;
102   }
103 
104   /**
105    * pushes a null on top of stack.
106    * cane be overridden to prohibit operation.
107    */
108   public void pushNull() {
109     int t = top + 1;
110     ensureCapacity(t);
111     top = t;
112   }
113 
114   public final int pushAndGetIdx(final T o) {
115     int t = top;
116     top++;
117     ensureCapacity(top);
118     elems[t] = o;
119     return t;
120   }
121 
122   final void ensureCapacity(final int minCapacity) {
123     int oldCapacity = elems.length;
124     if (minCapacity > oldCapacity) {
125       int newCapacity = (oldCapacity * 3) / 2 + 1;
126       if (newCapacity < minCapacity) {
127         newCapacity = minCapacity;
128       }
129       // minCapacity is usually close to size, so this is a win:
130       elems = java.util.Arrays.copyOf(elems, newCapacity);
131     }
132   }
133 
134   /**
135    * Push more objects into the stack
136    *
137    * @param args
138    */
139   public final void pushAll(final T... args) {
140     if (args.length == 0) {
141       return;
142     }
143     int newTop = top + args.length;
144     ensureCapacity(newTop);
145     System.arraycopy(args, 0, elems, top, args.length);
146     top = newTop;
147   }
148 
149   /**
150    * pops object out of stack
151    *
152    * @return Object
153    */
154   public final T pop() {
155     final T o = elems[--top];
156     elems[top] = null;
157     return o;
158   }
159 
160 
161   public final void remove() {
162     elems[--top] = null;
163   }
164 
165   public final T[] pop(final int n) {
166     int ot = top;
167     top -= n;
168     T[] result = (T[]) new Object[n];
169     for (int i = top, j = 0; i < ot; i++, j++) {
170       result[j] = elems[i];
171       elems[i] = null;
172     }
173     return result;
174   }
175 
176   public final void popTo(final T[] to, final int n) {
177     int ot = top;
178     top -= n;
179     for (int i = top, j = 0; i < ot; i++, j++) {
180       to[j] = elems[i];
181       elems[i] = null;
182     }
183   }
184 
185   public final void removeFromTop(final int n) {
186     int ot = top;
187     top -= n;
188     for (int i = top; i < ot; i++) {
189       elems[i] = null;
190     }
191   }
192 
193   public final T[] popUntil(final T until) {
194     int i = top - 1;
195     while (elems[i] != until) {
196       i--;
197     }
198     T[] result = java.util.Arrays.copyOfRange(elems, i + 1, top);
199     java.util.Arrays.fill(elems, i, top, null);
200     top = i;
201     return result;
202   }
203 
204   public final boolean hasElements() {
205     return top > 0;
206   }
207 
208   /**
209    * take a look at the top of stack.
210    * Throws exception if there is no element.
211    *
212    * @return Object
213    */
214   public T peek() {
215     return elems[top - 1];
216   }
217 
218   public final T peekFromTop(final int n) {
219     return elems[top - 1 - n];
220   }
221 
222   public final void replaceFromTop(final int n, final T value) {
223     elems[top - 1 - n] = value;
224   }
225 
226   public final T[] peek(final int n) {
227     return java.util.Arrays.copyOfRange(elems, top - n, top);
228   }
229 
230   public final T[] peekUntil(final T until) {
231     int i = top - 1;
232     while (elems[i] != until) {
233       i--;
234     }
235     return java.util.Arrays.copyOfRange(elems, i + 1, top);
236   }
237 
238   public final T peekElemAfter(final T until) {
239     int i = top - 1;
240     while (elems[i] != until) {
241       i--;
242     }
243     return elems[i - 1];
244   }
245 
246   /**
247    * Clear the stack - also makes sure the stack objects are not referenced anymore
248    */
249   @Override
250   public final void clear() {
251     for (int i = 0; i < top; i++) {
252       elems[i] = null;
253     }
254     top = 0;
255   }
256 
257   /**
258    * get the curent stack pos relative to base
259    *
260    * @return
261    */
262   public final int getPtr() {
263     return top;
264   }
265 
266   /**
267    * get element from stack at index relative to base
268    *
269    * @param ptr
270    * @return
271    */
272   public final T getFromPtr(final int ptr) {
273     if (ptr < 0 || ptr >= top) {
274       throw new IndexOutOfBoundsException(
275               "Trying to get from invalid index: " + ptr + " from: " + this);
276     }
277     return elems[ptr];
278   }
279 
280   /**
281    * returns a character separated string with the stack elements
282    *
283    * @param separator
284    * @return String
285    */
286   public final String toString(final char separator) {
287     if (top == 0) {
288       return "";
289     }
290     final StringBuilder result = new StringBuilder(32);
291     result.append(elems[0]);
292     for (int i = 1; i < top; i++) {
293       result.append(separator);
294       result.append(elems[i]);
295     }
296     return result.toString();
297   }
298 
299   /**
300    * to string representation. can be subclassed.
301    */
302   @Override
303   public String toString() {
304     return toString('.');
305   }
306 
307   @Override
308   public final int size() {
309     return top;
310   }
311 
312   /**
313    *  can be overwritten to optimize.
314    */
315   @Override
316   public boolean contains(final Object o) {
317     for (int i = 0; i < top; i++) {
318       if (Objects.equals(elems[i], o)) {
319         return true;
320       }
321     }
322     return false;
323   }
324 
325   /**
326    * Not implemented, can be overwritten.
327    */
328   @Override
329   public Iterator<T> iterator() {
330     throw new UnsupportedOperationException();
331   }
332 
333   @Override
334   public final Object[] toArray() {
335     return java.util.Arrays.copyOf(elems, top);
336   }
337 
338   /**
339    * Not implemented, can be overwritten.
340    */
341   @Override
342   public <T> T[] toArray(final T[] a) {
343     throw new UnsupportedOperationException();
344   }
345 
346   @Override
347   public final boolean add(final T e) {
348     push(e);
349     return true;
350   }
351 
352   /**
353    * Can be overwritten for better implementation.
354    * @param o element to remove.
355    * @return
356    */
357   @Override
358   public boolean remove(final Object o) {
359     if (o == null) {
360       for (int i = 0; i < top; i++) {
361         if (elems[i] == null) {
362           fastRemove(i);
363           return true;
364         }
365       }
366     } else {
367       for (int i = 0; i < top; i++) {
368         if (o.equals(elems[i])) {
369           fastRemove(i);
370           return true;
371         }
372       }
373     }
374     return false;
375   }
376 
377   /**
378    * Not implemented, can be overwritten.
379    */
380   @Override
381   public boolean containsAll(final Collection<?> c) {
382     throw new UnsupportedOperationException();
383   }
384 
385   /**
386    * Not implemented, can be overwritten.
387    */
388   @Override
389   public boolean addAll(final Collection<? extends T> c) {
390     throw new UnsupportedOperationException();
391   }
392 
393   /**
394    * Not implemented, can be overwritten.
395    */
396   @Override
397   public boolean removeAll(final Collection<?> c) {
398     throw new UnsupportedOperationException();
399   }
400 
401   /**
402    * Not implemented, can be overwritten.
403    */
404   @Override
405   public boolean retainAll(final Collection<?> c) {
406     throw new UnsupportedOperationException();
407   }
408 
409 
410   @Override
411   public final boolean equals(final Object obj) {
412     if (obj == null) {
413       return false;
414     }
415     if (getClass() != obj.getClass()) {
416       return false;
417     }
418     final SimpleStackNullSupport<T> other = (SimpleStackNullSupport<T>) obj;
419     if (this.top != other.top) {
420       return false;
421     }
422     return Arrays.deepEquals(this.elems, other.elems, 0, top);
423   }
424 
425   /**
426    * can be overwritten for better implementation.
427    */
428   @Override
429   public int hashCode() {
430     int hashCode = 7;
431     for (int i = 0; i < top; i++) {
432       Object obj = elems[i];
433       hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
434     }
435     return hashCode;
436   }
437 
438   /**
439    * Not implemented, can be overwritten.
440    */
441   @Override
442   public boolean addAll(final int index, final Collection<? extends T> c) {
443     throw new UnsupportedOperationException();
444   }
445 
446   @Override
447   public final T get(final int index) {
448     return elems[index];
449   }
450 
451   @Override
452   public final T set(final int index, final T element) {
453     ensureCapacity(index);
454     T result = elems[index];
455     elems[index] = element;
456     return result;
457   }
458 
459   /**
460    * Not implemented, can be overwritten.
461    */
462   @Override
463   public void add(final int index, final T element) {
464     throw new UnsupportedOperationException();
465   }
466 
467   @Override
468   public final T remove(final int index) {
469     if (index >= top && index < 0) {
470       throw new IndexOutOfBoundsException("Invalid index " + index + ", current size " + top);
471     }
472     T result = elems[index];
473     int next = index + 1;
474     int numMoved = top - next;
475     if (numMoved > 0) {
476       System.arraycopy(elems, next, elems, index, numMoved);
477     }
478     elems[--top] = null;
479     return result;
480   }
481 
482   final void fastRemove(final int index) {
483     int next = index + 1;
484     int numMoved = top - next;
485     if (numMoved > 0) {
486       System.arraycopy(elems, next, elems, index, numMoved);
487     }
488     elems[--top] = null;
489   }
490 
491   /**
492    * Not implemented, can be overwritten.
493    */
494   @Override
495   public int indexOf(final Object o) {
496     throw new UnsupportedOperationException();
497   }
498 
499   /**
500    * Not implemented, can be overwritten.
501    */
502   @Override
503   public int lastIndexOf(final Object o) {
504     throw new UnsupportedOperationException();
505   }
506 
507   /**
508    * Not implemented, can be overwritten.
509    */
510   @Override
511   public ListIterator<T> listIterator() {
512     throw new UnsupportedOperationException();
513   }
514 
515   /**
516    * Not implemented, can be overwritten.
517    */
518   @Override
519   public ListIterator<T> listIterator(final int index) {
520     throw new UnsupportedOperationException();
521   }
522 
523   /**
524    * Not implemented, can be overwritten.
525    */
526   @Override
527   public List<T> subList(final int fromIndex, final int toIndex) {
528     throw new UnsupportedOperationException();
529   }
530 }