]> gerrit.simantics Code Review - simantics/r.git/blob - bundles/org.simantics.r.scl/src/org/rosuda/REngine/RList.java
Restructured R repository for Tycho POMless builds.
[simantics/r.git] / bundles / org.simantics.r.scl / src / org / rosuda / REngine / RList.java
1 package org.rosuda.REngine;
2
3 // REngine library - Java client interface to R
4 // Copyright (C) 2004,2007,2008 Simon Urbanek
5
6 import java.util.*;
7
8 /** implementation of R-lists<br>
9     All lists (dotted-pair lists, language lists, expressions and vectors) are regarded as named generic vectors. 
10     Note: This implementation has changed radically in Rserve 0.5!
11
12     This class inofficially implements the Map interface. Unfortunately a conflict in the Java iterface classes Map and List doesn't allow us to implement both officially. Most prominently the Map 'remove' method had to be renamed to removeByKey.
13
14     @version $Id$
15 */
16 public class RList extends Vector implements List {
17     public Vector names;
18
19     /** constructs an empty list */
20     public RList() { super(); names=null; }
21
22     /** constructs an initialized, unnamed list
23          * @param contents - an array of {@link REXP}s to use as contents of this list */
24     public RList(REXP[] contents) {
25         super(contents.length);
26         int i=0;
27         while (i<contents.length)
28             super.add(contents[i++]);
29         names=null;
30     }
31
32     public RList(int initSize, boolean hasNames) {
33         super(initSize);
34         names=null;
35         if (hasNames) names=new Vector(initSize);
36     }
37     
38     /** constructs an initialized, unnamed list
39          * @param contents - a {@link Collection} of {@link REXP}s to use as contents of this list */
40     public RList(Collection contents) {
41         super(contents);
42         names=null;
43     }
44
45     /** constructs an initialized, named list. The length of the contents vector determines the length of the list.
46          * @param contents - an array of {@link REXP}s to use as contents of this list
47          * @param names - an array of {@link String}s to use as names */
48     public RList(REXP[] contents, String[] names) {
49         this(contents);
50         if (names!=null && names.length>0) {
51             this.names=new Vector(names.length);
52             int i = 0;
53             while (i < names.length) this.names.add(names[i++]);
54             while (this.names.size()<size()) this.names.add(null);
55         }
56     }
57     
58     /** constructs an initialized, named list. The size of the contents collection determines the length of the list.
59          * @param contents - a {@link Collection} of {@link REXP}s to use as contents of this list
60          * @param names - an array of {@link String}s to use as names */
61     public RList(Collection contents, String[] names) {
62         this(contents);
63         if (names!=null && names.length>0) {
64             this.names=new Vector(names.length);
65             int i = 0;
66             while (i < names.length) this.names.add(names[i++]);
67             while (this.names.size()<size()) this.names.add(null);
68         }
69     }
70
71     /** constructs an initialized, named list. The size of the contents collection determines the length of the list.
72          * @param contents - a {@link Collection} of {@link REXP}s to use as contents of this list
73          * @param names - an {@link Collection} of {@link String}s to use as names */
74     public RList(Collection contents, Collection names) {
75         this(contents);
76         if (names!=null && names.size()>0) {
77             this.names=new Vector(names);
78             while (this.names.size()<size()) this.names.add(null);
79         }
80     }
81
82         /** checks whether this list is named or unnamed
83          * @return <code>true</code> if this list is named, <code>false</code> otherwise */
84     public boolean isNamed() {
85         return names!=null;
86     }
87
88     /** get xpression given a key
89         @param v key
90         @return value which corresponds to the given key or
91                 <code>null</code> if the list is unnamed or key not found */
92     public REXP at(String v) {
93         if (names==null) return null;
94         int i = names.indexOf(v);
95         if (i < 0) return null;
96         return (REXP)elementAt(i);
97     }
98
99     /** get element at the specified position
100         @param i index
101         @return value at the index or <code>null</code> if the index is out of bounds */
102     public REXP at(int i) {
103         return (i>=0 && i<size())?(REXP)elementAt(i):null;
104     }
105
106         /** return the key (name) at a given index
107          @param i index
108          @return ket at the index - can be <code>null</code> is the list is unnamed or the index is out of range */
109     public String keyAt(int i) {
110         return (names==null || i<0 || i>=names.size())?null:(String)names.get(i);
111     }
112
113         /** set key at the given index. Using this method automatically makes the list a named one even if the key is <code>null</code>. Out of range operations are undefined (currently no-ops)
114          @param i index
115          @param value key name */
116         public void setKeyAt(int i, String value) {
117                 if (i < 0) return;
118                 if (names==null)
119                         names = new Vector();
120                 if (names.size() < size()) names.setSize(size());
121                 if (i < size()) names.set(i, value);
122         }
123
124     /** returns all keys of the list
125          * @return array containing all keys or <code>null</code> if list unnamed */
126     public String[] keys() {
127         if (names==null) return null;
128         int i = 0;
129         String k[] = new String[names.size()];
130         while (i < k.length) { k[i] = keyAt(i); i++; };
131         return k;
132     }
133
134     // --- overrides that sync names
135
136     public void add(int index, Object element) {
137         super.add(index, element);
138         if (names==null) return;
139         names.add(index, null);
140     }
141
142         public boolean add(Object element) {
143                 super.add(element);
144                 if (names != null)
145                         names.add(null);
146                 return true;
147         }
148         
149     public boolean addAll(Collection c) {
150         boolean ch = super.addAll(c);
151         if (names==null) return ch;
152         int l = size();
153         while (names.size()<l) names.add(null);
154         return ch;
155     }
156
157     public boolean addAll(int index, Collection c) {
158         boolean ch = super.addAll(index, c);
159         if (names==null) return ch;
160         int l = c.size();
161         while (l-- > 0) names.add(index, null);
162         return ch;
163     }
164
165     public void clear() {
166         super.clear();
167         names=null;
168     }
169
170     public Object clone() {
171         return new RList(this, names);  
172     }
173
174     public Object remove(int index) {
175         Object o = super.remove(index);
176         if (names != null) {
177             names.remove(index);
178             if (size()==0) names=null;
179         }
180         return o;
181     }
182
183     public boolean remove(Object elem) {
184         int i = indexOf(elem);
185         if (i<0) return false;
186         remove(i);
187         if (size()==0) names=null;
188         return true;
189     }
190
191     public boolean removeAll(Collection c) {
192         if (names==null) return super.removeAll(c);
193         boolean changed=false;
194         Iterator it = c.iterator();
195         while (it.hasNext())
196             changed|=remove(it.next());
197         return changed;
198     }
199
200     public boolean retainAll(Collection c) {
201         if (names==null) return super.retainAll(c);
202         boolean rm[] = new boolean[size()];
203         boolean changed=false;
204         int i = 0;
205         while (i<rm.length) {
206             changed|=rm[i]=!c.contains(get(i));
207             i++;
208         }
209         while (i>0) {
210             i--;
211             if (rm[i]) remove(i);
212         }
213         return changed;
214     }
215
216     // --- old API mapping
217     public void removeAllElements() { clear(); }
218     public void insertElementAt(Object obj, int index) { add(index, obj); }
219     public void addElement(Object obj) { add(obj); }
220     public void removeElementAt(int index) { remove(index); }
221     public boolean removeElement(Object obj) { return remove(obj); }
222
223     // --- Map interface
224
225     public boolean containsKey(Object key) {
226         return (names==null)?false:names.contains(key);
227     }
228
229     public boolean containsValue(Object value) {
230         return contains(value);
231     }
232
233     /** NOTE: THIS IS UNIMPLEMENTED and always returns <code>null</code>! Due to the fact that R lists are not proper maps we canot maintain a set-view of the list */
234     public Set entrySet() {
235         return null;
236     }
237
238     public Object get(Object key) {
239         return at((String)key);
240     }
241
242     /** Note: sinde RList is not really a Map, the returned set is only an approximation as it cannot reference duplicate or null names that may exist in the list */
243     public Set keySet() {
244         if (names==null) return null;
245         return new HashSet(names);
246     }
247
248     public Object put(Object key, Object value) {
249         if (key==null) {
250             add(value);
251             return null;
252         }
253         if (names != null) {
254             int p = names.indexOf(key);
255             if (p >= 0)
256                 return super.set(p, value);
257         }
258         int i = size();
259         super.add(value);
260         if (names==null)
261             names = new Vector(i+1);
262         while (names.size() < i) names.add(null);
263         names.add(key);
264         return null;
265     }
266
267     public void putAll(Map t) {
268         if (t==null) return;
269         // NOTE: this if branch is dead since RList cannot inherit from Map
270         if (t instanceof RList) { // we need some more sophistication for RLists as they may have null-names which we append
271             RList l = (RList) t;
272             if (names==null) {
273                 addAll(l);
274                 return;
275             }
276             int n = l.size();
277             int i = 0;
278             while (i < n) {
279                 String key = l.keyAt(i);
280                 if (key==null)
281                     add(l.at(i));
282                 else
283                     put(key, l.at(i));
284                 i++;
285             }
286         } else {
287             Set ks = t.keySet();
288             Iterator i = ks.iterator();
289             while (i.hasNext()) {
290                 Object key = i.next();
291                 put(key, t.get(key));
292             }
293         }
294     }
295
296     public void putAll(RList t) {
297         if (t == null) return;
298         RList l = (RList) t;
299         if (names==null) {
300             addAll(l);
301             return;
302         }
303         int n = l.size();
304         int i = 0;
305         while (i < n) {
306             String key = l.keyAt(i);
307             if (key == null)
308                 add(l.at(i));
309             else
310                 put(key, l.at(i));
311             i++;
312         }
313     }
314     
315     public Object removeByKey(Object key) {
316         if (names==null) return null;
317         int i = names.indexOf(key);
318         if (i<0) return null;
319         Object o = elementAt(i);
320         removeElementAt(i);
321         names.removeElementAt(i);
322         return o;
323     }
324
325     public Collection values() {
326         return this;
327     }
328         
329         // other
330         public String toString() {
331                 return "RList"+super.toString()+"{"+(isNamed()?"named,":"")+size()+"}";
332         }
333 }