Skip to main content
summaryrefslogtreecommitdiffstats
blob: d5c0a6f992eab73d54e037a736d78aa7f5300eda (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package org.eclipse.osee.ote.core;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;

/**
 * This class is useful for cases where frequent looping and thread safety happen. 
 * It forces you to get a reference to the backing array and expects you to do a 
 * non Iterator based loop so that no Iterator objects are created to minimized GC churn. 
 * 
 * @author Andrew M Finkbeiner
 *
 * @param <E>
 */
public class CopyOnWriteNoIteratorList<E> {
   
   private ReentrantLock lock = new ReentrantLock(); 
   private AtomicReference<E[]> data = new AtomicReference<>();
   private Class<E> type;
   
   public CopyOnWriteNoIteratorList(Class<E> type){
      this.type = type;
      data.set(newArray(0));
   }
   
   @SuppressWarnings("unchecked")
   private E[] newArray(int size){
      return (E[]) Array.newInstance(type, size);
   }
   
   public void add(E item){
      try{
         lock.lock();
         E[] ref = data.get();
         E[] newdata = newArray(ref.length + 1);
         System.arraycopy(ref, 0, newdata, 0, ref.length);
         newdata[newdata.length-1] = item;
         data.set(newdata);
      } finally{
         lock.unlock();
      }
   }
   
   public boolean remove(E item){
      boolean returnvalue = false;
      try{
         lock.lock();
         int index = -1;
         E[] ref = data.get();
         for(int i = 0; i < ref.length; i++){
            if(item.equals(ref[i])){
               index = i;
               break;
            }
         }
         if(index > -1){
            E[] newdata = newArray(ref.length - 1);
            if(index == 0){
               System.arraycopy(ref, 1, newdata, 0, newdata.length);   
            } else if (index == (ref.length - 1)){
               System.arraycopy(ref, 0, newdata, 0, newdata.length);
            } else {
               System.arraycopy(ref, 0, newdata, 0, index);
               System.arraycopy(ref, index+1, newdata, index, ref.length - (index + 1));
            }
            data.set(newdata);
            returnvalue = true;
         }
      } finally {
         lock.unlock();
      }
      return returnvalue;
   }
   
   public boolean contains(E item){
      boolean returnValue = false;
      try{
         lock.lock();
         int index = -1;
         E[] ref = data.get();
         for(int i = 0; i < ref.length; i++){
            if(item.equals(ref[i])){
               index = i;
               break;
            }
         }
         if(index > -1){
           returnValue = true;
         }
      } finally {
         lock.unlock();
      } 
      return returnValue;
   }
   
   public E[] get(){
      return data.get();
   }

   public int length() {
      return data.get().length;
   }

   public void clear() {
      try{
         lock.lock();
         data.set(newArray(0));
      } finally{
         lock.unlock();
      }
   }

   public Collection<E> fillCollection(Collection<E> arrayList) {
      try{
         lock.lock();
         E[] ref = data.get();
         for(int i = 0; i < ref.length; i++){
            arrayList.add(ref[i]);
         }
      } finally {
         lock.unlock();
      }
      return arrayList;
   }
   
}

Back to the top