1 | sbool structure_showTiming; |
2 | |
3 | static String structure(Object o) { |
4 | new structure_Data d; |
5 | structure_1(o, d); |
6 | long time = now(); |
7 | S s = str(d.out); |
8 | int nOrig = l(s); |
9 | d.out = null; |
10 | s = structure_2(s, d.refd); |
11 | if (structure_showTiming) |
12 | done_always("structure_2 (" + nOrig + " => " + l(s) + ")", time); |
13 | ret s; |
14 | } |
15 | |
16 | // leave to false, unless unstructure() breaks |
17 | static boolean structure_allowShortening = false; |
18 | |
19 | static int structure_shareStringsLongerThan = 20; |
20 | |
21 | static class structure_Data { |
22 | new StringBuilder out; |
23 | int stringSizeLimit; |
24 | new IdentityHashMap<O, Integer> seen; |
25 | new BitSet refd; |
26 | new HashMap<S, Int> strings; |
27 | new HashSet<S> concepts; |
28 | HashMap<Class, L<Field>> fieldsByClass = new HashMap; |
29 | Class conceptClass = findClass("Concept"); |
30 | } |
31 | |
32 | static void structure_1(Object o, structure_Data d) { |
33 | StringBuilder out = d.out; |
34 | |
35 | if (o == null) { out.append("null"); ret; } |
36 | |
37 | Class c = o.getClass(); |
38 | S name = c.getName(); |
39 | S dynName = shortDynamicClassName(o); |
40 | bool concept = d.conceptClass != null && d.conceptClass.isInstance(o); |
41 | L<Field> lFields = d.fieldsByClass.get(c); |
42 | |
43 | if (lFields == null) { |
44 | // these are never back-referenced (for readability) |
45 | |
46 | if (o instanceof Number) { |
47 | if (o instanceof Integer) { out.append((int) o); ret; } |
48 | if (o instanceof Long) { out.append((long) o).append("L"); ret; } |
49 | if (o instanceof Float) { out.append("fl "); quote_impl(str(o), out); ret; } |
50 | if (o instanceof Double) { out.append("d("); quote_impl(str(o), out); out.append(")"); ret; } |
51 | if (o instanceof BigInteger) { out.append("bigint(").append(o).append(")"); ret; } |
52 | } |
53 | |
54 | if (o instanceof Boolean) { |
55 | out.append(((Boolean) o).booleanValue() ? "t" : "f"); ret; |
56 | } |
57 | |
58 | if (o instanceof Character) { |
59 | out.append(quoteCharacter((Character) o)); ret; |
60 | } |
61 | |
62 | if (o instanceof File) { |
63 | out.append("File ").append(quote(((File) o).getPath())); ret; |
64 | } |
65 | |
66 | // referencable objects follow |
67 | |
68 | Integer ref = null; |
69 | if (!(o instanceof S)) { |
70 | ref = d.seen.get(o); |
71 | if (ref != null) { |
72 | d.refd.set(ref); |
73 | out.append("r").append(ref); ret; |
74 | } |
75 | } |
76 | |
77 | if (o instanceof S && (ref = d.strings.get((S) o)) != null) { |
78 | d.refd.set(ref); |
79 | out.append("r").append(ref); ret; |
80 | } |
81 | |
82 | ref = d.seen.size()+1; |
83 | d.seen.put(o, ref); |
84 | out.append("m").append(ref).append(" "); // marker |
85 | |
86 | if (o instanceof S) { |
87 | S s = d.stringSizeLimit != 0 ? shorten((S) o, d.stringSizeLimit) : (S) o; |
88 | if (l(s) >= structure_shareStringsLongerThan) |
89 | d.strings.put(s, ref); |
90 | quote_impl(s, out); ret; |
91 | } |
92 | |
93 | if (o instanceof HashSet) { |
94 | out.append("hashset "); |
95 | structure_1(new ArrayList((Set) o), d); |
96 | ret; |
97 | } |
98 | |
99 | if (o instanceof TreeSet) { |
100 | out.append("treeset "); |
101 | structure_1(new ArrayList((Set) o), d); |
102 | ret; |
103 | } |
104 | |
105 | if (o instanceof Collection && neq(name, "main$Concept$RefL")) { |
106 | out.append("["); |
107 | int l = out.length(); |
108 | for (Object x : (Collection) o) { |
109 | if (out.length() != l) out.append(", "); |
110 | structure_1(x, d); |
111 | } |
112 | out.append("]"); |
113 | ret; |
114 | } |
115 | |
116 | if (o instanceof Map) { |
117 | if (o instanceof HashMap) out.append("hm"); |
118 | out.append("{"); |
119 | int l = out.length(); |
120 | for (Object e : ((Map) o).entrySet()) { |
121 | if (out.length() != l) out.append(", "); |
122 | structure_1(((Map.Entry) e).getKey(), d); |
123 | out.append("="); |
124 | structure_1(((Map.Entry) e).getValue(), d); |
125 | } |
126 | out.append("}"); |
127 | ret; |
128 | } |
129 | |
130 | if (c.isArray()) { |
131 | if (o instanceof byte[]) { |
132 | out.append("ba ").append(quote(bytesToHex((byte[]) o))); ret; |
133 | } |
134 | |
135 | int n = Array.getLength(o); |
136 | |
137 | if (o instanceof bool[]) { |
138 | S hex = boolArrayToHex((bool[]) o); |
139 | int i = l(hex); |
140 | while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2; |
141 | out.append("boolarray ").append(n).append(" ").append(quote(substring(hex, 0, i))); ret; |
142 | } |
143 | |
144 | S atype = "array", sep = ", "; |
145 | |
146 | if (o instanceof int[]) { |
147 | //ret "intarray " + quote(intArrayToHex((int[]) o)); |
148 | atype = "intarray"; |
149 | sep = " "; |
150 | } |
151 | |
152 | out.append(atype).append("{"); |
153 | for (int i = 0; i < n; i++) { |
154 | if (i != 0) out.append(sep); |
155 | structure_1(Array.get(o, i), d); |
156 | } |
157 | out.append("}"); ret; |
158 | } |
159 | |
160 | if (o instanceof Class) { |
161 | out.append("class(").append(quote(((Class) o).getName())).append(")"); ret; |
162 | } |
163 | |
164 | if (o instanceof Throwable) { |
165 | out.append("exception(").append(quote(((Throwable) o).getMessage())).append(")"); ret; |
166 | } |
167 | |
168 | if (o instanceof BitSet) { |
169 | BitSet bs = (BitSet) o; |
170 | out.append("bitset{"); |
171 | int l = out.length(); |
172 | for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { |
173 | if (out.length() != l) out.append(", "); |
174 | out.append(i); |
175 | } |
176 | out.append("}"); ret; |
177 | } |
178 | |
179 | // Need more cases? This should cover all library classes... |
180 | if (name.startsWith("java.") || name.startsWith("javax.")) { |
181 | out.append(str(o)); ret; |
182 | } |
183 | |
184 | if (name.equals("main$Lisp")) { |
185 | out.append("l("); |
186 | structure_1(getOpt(o, "head"), d); |
187 | L args = cast getOpt(o, "args"); |
188 | if (nempty(args)) |
189 | for (int i = 0; i < l(args); i++) { |
190 | out.append(", "); |
191 | O arg = args.get(i); |
192 | |
193 | // sweet shortening |
194 | if (arg != null && eq(arg.getClass().getName(), "main$Lisp") && isTrue(call(arg, "isEmpty"))) |
195 | arg = get(arg, "head"); |
196 | |
197 | structure_1(arg, d); |
198 | } |
199 | out.append(")"); ret; |
200 | } |
201 | |
202 | if (concept && !d.concepts.contains(dynName)) { |
203 | d.concepts.add(dynName); |
204 | out.append("c "); |
205 | } |
206 | |
207 | // serialize an object with fields. |
208 | // first, collect all fields and values in fv. |
209 | |
210 | TreeSet<Field> fields = new TreeSet<Field>(new Comparator<Field>() { |
211 | public int compare(Field a, Field b) { |
212 | ret stdcompare(a.getName(), b.getName()); |
213 | } |
214 | }); |
215 | |
216 | while (c != Object.class) { |
217 | for (Field field : getDeclaredFields_cached(c)) { |
218 | if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) |
219 | continue; |
220 | S fieldName = field.getName(); |
221 | |
222 | fields.add(field); |
223 | |
224 | // put special cases here... |
225 | } |
226 | |
227 | c = c.getSuperclass(); |
228 | } |
229 | |
230 | lFields = asList(fields); |
231 | |
232 | // put this$1 first |
233 | for (int i = 0; i < l(lFields); i++) { |
234 | Field f = lFields.get(i); |
235 | if (f.getName().equals("this$1")) { |
236 | lFields.remove(i); |
237 | lFields.add(0, f); |
238 | break; |
239 | } |
240 | } |
241 | |
242 | d.fieldsByClass.put(c, lFields); |
243 | } |
244 | |
245 | new LinkedHashMap<S, O> fv; |
246 | for (Field f : lFields) { |
247 | Object value; |
248 | try { |
249 | value = f.get(o); |
250 | } catch (Exception e) { |
251 | value = "?"; |
252 | } |
253 | |
254 | if (value != null) |
255 | fv.put(f.getName(), value); |
256 | } |
257 | |
258 | String shortName = dropPrefix("main$", name); |
259 | |
260 | // Now we have fields & values. Process fieldValues if it's a DynamicObject. |
261 | |
262 | // omit field "className" if equal to class's name |
263 | if (concept && eq(fv.get("className"), shortName)) |
264 | fv.remove("className"); |
265 | |
266 | if (o instanceof DynamicObject) { |
267 | fv.putAll((Map) fv.get("fieldValues")); |
268 | fv.remove("fieldValues"); |
269 | shortName = dynName; |
270 | fv.remove("className"); |
271 | } |
272 | |
273 | S singleField = fv.size() == 1 ? first(fv.keySet()) : null; |
274 | |
275 | // Render this$1 first because unstructure needs it for constructor call. |
276 | |
277 | out.append(shortName).append("("); |
278 | int l = out.length(); |
279 | |
280 | for (S fieldName : fv.keySet()) { |
281 | if (out.length() != l) out.append(", "); |
282 | out.append(fieldName).append("="); |
283 | structure_1(fv.get(fieldName), d); |
284 | } |
285 | |
286 | if (out.length() == l) out.setLength(l-1); // drop "(" |
287 | else out.append(")"); |
288 | } |
289 | |
290 | // drop unused markers |
291 | static S structure_2(final S s, final BitSet refd) { |
292 | final new StringBuilder out; |
293 | |
294 | javaTok_streaming(s, new JavaTok_Stream { |
295 | int n = -1; |
296 | bool drop; |
297 | |
298 | void add(int i, int j) { |
299 | ++n; |
300 | if ((n & 1) != 0 && structure_isMarker(s, i, j)) { |
301 | S t = s.substring(i+1, j); |
302 | if (!refd.get(parseInt(t))) { |
303 | drop = true; |
304 | ret; |
305 | } |
306 | } |
307 | if (drop) |
308 | drop = false; |
309 | else |
310 | out.append(s, i, j); |
311 | } |
312 | }); |
313 | |
314 | ret str(out); |
315 | } |
Began life as a copy of #1005593
download show line numbers debug dex old transpilations
Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1005596 |
Snippet name: | structure function (v9, caching fields by class) |
Eternal ID of this version: | #1005596/1 |
Text MD5: | ce89801c9777447ba357a99b22d4072c |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-11-29 15:50:17 |
Source code size: | 8844 bytes / 315 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 646 / 642 |
Referenced in: | [show references] |