File: RList.java

package info (click to toggle)
rjava 1.0-14-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,188 kB
  • sloc: java: 13,223; ansic: 5,503; sh: 3,776; xml: 325; makefile: 250; perl: 33
file content (130 lines) | stat: -rw-r--r-- 4,376 bytes parent folder | download | duplicates (9)
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
129
130
package org.rosuda.JRI;

// JRclient library - client interface to Rserve, see http://www.rosuda.org/Rserve/
// Copyright (C) 2004 Simon Urbanek
// --- for licensing information see LICENSE file in the original JRclient distribution ---

import java.util.*;

/** implementation of R-lists<br>
    This is rather preliminary and may change in future since it's not really proper.
    The point is that the parser tries to interpret lists to be of the form entry=value,
    where entry is stored in the "head" part, and value is stored in the "body" part.
    Then using {@link #at(String)} it is possible to fetch "body" for a specific "head".
    The terminology used is partly from hash fields - "keys" are the elements in "head"
    and values are in "body" (see {@link #keys}).
    <p>
    On the other hand, R uses lists to store complex internal structures, which are not
    parsed according to the structure - in that case "head" and "body" have to be evaluated
    separately according to their meaning in that context.

    @version $Id: RList.java 2720 2007-03-15 17:35:42Z urbanek $
*/
public class RList extends Object {
    /** xpressions containing head, body and tag. 
	The terminology is a bit misleading (for historical reasons) - head corresponds to CAR, body to CDR and finally tag is TAG. */
    public REXP head, body, tag;

	/** cached keys (from TAG) */
    String[] keys = null;
	/** cached values(from CAR) */
	REXP[] values = null;
	/** flag denoting whether we need to re-fetch the cached values.<p><b.Note:</b> the current assumption is that the contents don't change after first retrieval - there is currently no recursive check! */
	boolean dirtyCache = true;
	
    /** constructs an empty list */
    public RList() { head=body=tag=null; }
    
	/** fake constructor to keep compatibility with Rserve (for now, will be gone soon) */
	public RList(RVector v) {
		Vector n = v.getNames();
		if (n != null) {
			keys = new String[n.size()];
			n.copyInto(keys);
		}
		values=new REXP[v.size()];
		v.copyInto(values);
		dirtyCache=false;
		// head,tail,tag are all invalid!
	}	

    /** constructs an initialized list
	@param h head xpression
	@param b body xpression */
    public RList(REXP h, REXP b) { head=h; body=b; tag=null; }

	/** constructs an initialized list
		@param h head xpression (CAR)
		@param t tag xpression (TAG)
		@param b body/tail xpression (CDR)
		*/
    public RList(REXP h, REXP t, REXP b) { head=h; body=b; tag=t; }
	
    /** get head xpression (CAR)
	@return head xpression */
    public REXP getHead() { return head; }
    
    /** get body xpression (CDR)
	@return body xpression */
    public REXP getBody() { return body; }

    /** get tag xpression
	@return tag xpression */
    public REXP getTag() { return tag; }

    /** internal function that updates cached vectors
        @return <code>true</code> if the conversion was successful */
    boolean updateVec() {
		if (!dirtyCache) return true;
		// we do NOT run it recursively, because in most cases only once instance is asked
		RList cur = this;
		int l = 0;
		while (cur!=null) {
			l++;
			REXP bd = cur.getBody();
			cur = (bd==null)?null:bd.asList();
		}
		keys=new String[l];
		values=new REXP[l];
		cur = this;
		l=0;
		while (cur != null) {
			REXP x = cur.getTag();
			if (x!=null) keys[l]=x.asSymbolName();
			values[l] = cur.getHead();
			REXP bd = cur.getBody();
			cur = (bd==null)?null:bd.asList();
			l++;
		}
		dirtyCache=false;
		return true;
    }

    /** get xpression given a key
		@param v key
		@return xpression which corresponds to the given key or
		<code>null</code> if list is not standartized or key not found */
    public REXP at(String v) {
		if (!updateVec() || keys==null || values==null) return null;
		int i=0;
		while (i<keys.length) {
			if (keys[i].compareTo(v)==0) return values[i];
			i++;
		}
		return null;
    }

    /** get element at the specified position
	@param i index
	@return xpression at the index or <code>null</code> if list is not standartized or
	        if index out of bounds */
    public REXP at(int i) {
		return (!updateVec() || values==null || i<0 || i>=values.length)?null:values[i];
    }

    /** returns all keys of the list
	@return array containing all keys or <code>null</code> if list is not standartized */
    public String[] keys() {
		return (!updateVec())?null:this.keys;
    }
}