-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTuple.java
More file actions
197 lines (185 loc) · 7.9 KB
/
Tuple.java
File metadata and controls
197 lines (185 loc) · 7.9 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package linda;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.StringTokenizer;
/** Representation of a tuple.
* @author philippe.queinnec@enseeiht.fr
*/
public class Tuple extends LinkedList<Serializable> implements Serializable {
private static final long serialVersionUID = 1L;
/** Creates a new tuple.
* Example :
* new Tuple(4, 5, "foo", true) -> [ 4 5 "foo" true ]
* new Tuple(4, Integer.class, "foo".getclass(), Boolean.class) -> [ 4 ?Integer ?String ?Boolean ]
*/
public Tuple(Serializable... components) {
for (Serializable c : components) {
this.add(c);
}
}
private static boolean matches(Serializable thiscomponent, Serializable templatecomponent) {
if (templatecomponent instanceof Tuple) {
if (! (thiscomponent instanceof Tuple))
return false;
else
return ((Tuple)thiscomponent).matches((Tuple)templatecomponent);
} else if (templatecomponent instanceof Class) {
if (thiscomponent instanceof Class)
return ((Class<?>)templatecomponent).isAssignableFrom((Class<?>)thiscomponent);
else
return ((Class<?>) templatecomponent).isInstance(thiscomponent);
} else {
return thiscomponent.equals(templatecomponent);
}
}
/** Returns true if this tuple matches the given template.
* Matching rules : a tuple matches a template if all their components match two by two.
* Two components match :
* - if they are both values and are equals;
* - if the template component is a class/interface, and the tuple component is an instance/implementation of this class/interface (Class.isInstance);
* - if the template component is a class/interface, and the tuple component is a subclass/subinterface of this class/interface (Class.isAsssignableFrom);
* - recursively if both are tuples.
*
* Examples:
* [ 3 5 "foo" ] matches [ 3 5 "foo" ], [ ?Integer 5 "foo" ], [ ?Integer ?Integer ?String ]
* [ 3 ?Integer [ 6 7 ] [ 7 8 ] ] matches [ ?Integer ?Integer [ ?Integer 7 ] ?Tuple ], [3 ?Integer ?Tuple ?Tuple ]
*
* @param template the template which this tuple is compared to.
*/
public boolean matches(Tuple template) {
if (this.size() != template.size())
return false;
Iterator<Serializable> itthis = this.iterator();
Iterator<Serializable> itmotif = template.iterator();
while (itthis.hasNext()) {
Serializable othis = itthis.next();
Serializable omotif = itmotif.next();
if (! matches(othis, omotif))
return false;
}
return true;
}
/** Returns true if this tuple (seen as a template) contains <code>t</code>.
* This is the reverse of {@link #matches(Tuple)}. */
public boolean contains(Tuple t) {
return t.matches(this);
}
/**
* Returns a deep copy of the tuple.
* @return a deep copy of this object
*/
/* Les éléments types sont représentés par des instances de Class, qui n'est pas cloneable.
* Le plus simple de passer par une sérialisation/desérialisation ce qui marche pour toutes les classes qui implantent serializable.
*/
public Tuple deepclone() {
Tuple copy = null;
try {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream (buf);
out.writeObject (this);
ObjectInputStream in = new ObjectInputStream (new ByteArrayInputStream (buf.toByteArray()));
copy = (Tuple) in.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return copy;
}
/** Returns a string representation of this tuple.
* @return a string representation of this tuple.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (Object o : this) {
if (o instanceof Class) {
sb.append(" ?" + ((Class<?>)o).getName());
} else if (o instanceof String) {
sb.append(" \"" + o + "\"");
} else if (o instanceof Character) {
sb.append(" '" + o + "'");
} else {
sb.append(" " + o.toString());
}
}
sb.append(" ]");
return sb.toString();
}
/** Parses a sequence of words to form a tuple.
* The initial [ must be missing.
* @param stk
* @return
* @throws TupleFormatException
*/
private static Tuple valueOf(StringTokenizer stk) throws TupleFormatException {
Tuple res = new Tuple();
while (stk.hasMoreTokens()) {
String token = stk.nextToken();
if (token.equals("]"))
return res; // BEWARE
if (token.startsWith("\"") && token.endsWith("\"")) {
String val = token.substring(1, token.length()-1);
res.add(val);
} else if (token.startsWith("'") && token.endsWith("'") && (token.length() > 2)) {
res.add(Character.valueOf(token.charAt(1)));
} else if (token.startsWith("?")) {
String classname = token.substring(1);
Class<?> c = null;
final String[] prefixes = { "", "java.lang.", "linda." };
for (String prefix : prefixes) {
try {
c = Class.forName(prefix + classname);
break; // oh !
} catch (ClassNotFoundException e) {
// ignore and try next prefix
}
}
if (c != null)
res.add(c);
else
throw new TupleFormatException("Unknown class ?"+classname);
} else if ("-0123456789".indexOf(token.charAt(0)) != -1) {
int val;
try {
val = Integer.valueOf(token);
} catch (NumberFormatException e) {
throw new TupleFormatException("NumberFormatException on '"+token+"'");
}
res.add(val);
} else if (token.equals("true")) {
res.add(true);
} else if (token.equals("false")) {
res.add(false);
} else if (token.equals("[")) {
Tuple val = valueOf(stk); // yeepi!
res.add(val);
} else {
throw new TupleFormatException("Unhandled chars: '"+token+"'");
}
}
throw new TupleFormatException("Missing closing ']'");
}
/** Returns a Tuple with a value represented by the specified String.
* Known values: integer (45, -67), boolean (true, false), string ("toto"), classname (?Integer, ?java.awt.Rectangle), recursive tuple.
* Examples: [ 3 4 ], [ ?Integer "toto" true 78 ?Boolean ], [ ?Integer ?Tuple ], [ [ true 78 ] [ 3 4 [ 5 6 ] 7 ] ]
* For these components, the parsable strings are identical to the printed strings.
* Note: do not expect the parser to be resilient to arbitrary strings.
*
* @param s the string to be parsed.
* @return a Tuple object holding the value represented by the string argument.
* @throws TupleFormatException
*/
public static Tuple valueOf(String s) throws TupleFormatException {
StringTokenizer stk = new StringTokenizer(s);
if (! stk.hasMoreTokens() || !stk.nextToken().equals("["))
throw new TupleFormatException("Missing initial '['");
Tuple res = valueOf(stk);
if (stk.hasMoreTokens())
throw new TupleFormatException("Trailing chars after ']'");
return res;
}
}