Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

357
LINES

< > BotCompany Repo | #1008806 // structure function (v13, with noStringSharing option)

JavaX fragment (include)

1  
static bool structure_showTiming, structure_checkTokenCount;
2  
3  
static S structure(O o) {
4  
  ret structure(o, new structure_Data);
5  
}
6  
7  
static S structure(O o, structure_Data d) {
8  
  new StringWriter sw;
9  
  d.out = new PrintWriter(sw);
10  
  structure_go(o, d);
11  
  S s = str(sw);
12  
  if (structure_checkTokenCount) {
13  
    print("token count=" + d.n);
14  
    assertEquals("token count", l(javaTokC(s)), d.n);
15  
  }
16  
  ret s;
17  
}
18  
19  
static void structure_go(O o, structure_Data d) {
20  
  structure_1(o, d);
21  
  while (nempty(d.stack))
22  
    popLast(d.stack).run();
23  
}
24  
25  
static void structureToPrintWriter(O o, PrintWriter out) {
26  
  new structure_Data d;
27  
  d.out = out;
28  
  structure_go(o, d);
29  
}
30  
31  
// leave to false, unless unstructure() breaks
32  
static boolean structure_allowShortening = false;
33  
34  
static class structure_Data {
35  
  PrintWriter out;
36  
  int stringSizeLimit;
37  
  int shareStringsLongerThan = 20;
38  
  bool noStringSharing;
39  
40  
  new IdentityHashMap<O, Integer> seen;
41  
  new BitSet refd;
42  
  new HashMap<S, Int> strings;
43  
  new HashSet<S> concepts;
44  
  HashMap<Class, L<Field>> fieldsByClass = new HashMap;
45  
  Class conceptClass = findClass("Concept");
46  
  int n; // token count
47  
  new L<Runnable> stack;
48  
  
49  
  // append single token
50  
  structure_Data append(S token) { out.print(token); ++n; ret this; }
51  
  structure_Data append(int i) { out.print(i); ++n; ret this; }
52  
  
53  
  // append multiple tokens
54  
  structure_Data append(S token, int tokCount) { out.print(token); n += tokCount; ret this; }
55  
  
56  
  // extend last token
57  
  structure_Data app(S token) { out.print(token); ret this; }
58  
  structure_Data app(int i) { out.print(i); ret this; }
59  
}
60  
61  
static void structure_1(final Object o, final structure_Data d) {
62  
  final PrintWriter out = d.out;
63  
  
64  
  if (o == null) { d.append("null"); ret; }
65  
  
66  
  Class c = o.getClass();
67  
  S name = c.getName();
68  
  S dynName = shortDynamicClassName(o);
69  
  bool concept = d.conceptClass != null && d.conceptClass.isInstance(o);
70  
  L<Field> lFields = d.fieldsByClass.get(c);
71  
  
72  
  if (lFields == null) {
73  
    // these are never back-referenced (for readability)
74  
    
75  
    if (o instanceof Number) {
76  
      if (o instanceof Integer) { int i = ((Int) o).intValue(); out.print(i); d.n += i < 0 ? 2 : 1; ret; }
77  
      if (o instanceof Long) { long l = ((Long) o).longValue(); out.print(l); out.print("L"); d.n += l < 0 ? 2 : 1; ret; }
78  
      if (o instanceof Float) { d.append("fl ", 2); quoteToPrintWriter(str(o), out); ret; }
79  
      if (o instanceof Double) { d.append("d(", 3); quoteToPrintWriter(str(o), out); d.append(")"); ret; }
80  
      if (o instanceof BigInteger) { out.print("bigint("); out.print(o); out.print(")"); d.n += ((BigInteger) o).signum() < 0 ? 5 : 4; ret; }
81  
    }
82  
  
83  
    if (o instanceof Boolean) {
84  
      d.append(((Boolean) o).booleanValue() ? "t" : "f"); ret;
85  
    }
86  
      
87  
    if (o instanceof Character) {
88  
      d.append(quoteCharacter((Character) o)); ret;
89  
    }
90  
      
91  
    if (o instanceof File) {
92  
      d.append("File ").append(quote(((File) o).getPath())); ret;
93  
    }
94  
      
95  
    // referencable objects follow
96  
    
97  
    Integer ref = d.seen.get(o);
98  
    if (o instanceof S && ref == null)
99  
      ref = d.strings.get((S) o);
100  
      
101  
    if (ref != null) {
102  
      d.refd.set(ref);
103  
      d.append("t").app(ref); ret;
104  
    }
105  
    
106  
    ref = d.n; //d.seen.size()+1;
107  
    if (!o instanceof S)
108  
      d.seen.put(o, ref);
109  
    else {
110  
      S s = d.stringSizeLimit != 0 ? shorten((S) o, d.stringSizeLimit) : (S) o;
111  
      if (!d.noStringSharing) {
112  
        if (d.shareStringsLongerThan == Int.MAX_VALUE)
113  
          d.seen.put(o, ref);
114  
        if (l(s) >= d.shareStringsLongerThan)
115  
          d.strings.put(s, ref);
116  
      }
117  
      quoteToPrintWriter(s, out); d.n++; ret;
118  
    }
119  
      
120  
    if (o instanceof HashSet) {
121  
      d.append("hashset ");
122  
      structure_1(new ArrayList((Set) o), d);
123  
      ret;
124  
    }
125  
  
126  
    if (o instanceof TreeSet) {
127  
      d.append("treeset ");
128  
      structure_1(new ArrayList((Set) o), d);
129  
      ret;
130  
    }
131  
    
132  
    if (o instanceof Collection && neq(name, "main$Concept$RefL")) {
133  
      d.append("[");
134  
      final int l = d.n;
135  
      final Iterator it = ((Collection) o).iterator();
136  
      d.stack.add(r {
137  
        if (!it.hasNext())
138  
          d.append("]");
139  
        else {
140  
          d.stack.add(this);
141  
          if (d.n != l) d.append(", ");
142  
          structure_1(it.next(), d);
143  
        }
144  
      });
145  
      ret;
146  
    }
147  
    
148  
    if (o instanceof Map) {
149  
      if (o instanceof LinkedHashMap) d.append("lhm");
150  
      else if (o instanceof HashMap) d.append("hm");
151  
      d.append("{");
152  
      final int l = d.n;
153  
      final Iterator it = ((Map) o).entrySet().iterator();
154  
      
155  
      d.stack.add(new Runnable() {
156  
        bool v;
157  
        Map.Entry e;
158  
        
159  
        public void run() {
160  
          if (v) {
161  
            d.append("=");
162  
            v = false;
163  
            d.stack.add(this);
164  
            structure_1(e.getValue(), d);
165  
          } else {
166  
            if (!it.hasNext())
167  
              d.append("}");
168  
            else {
169  
              e = (Map.Entry) it.next();
170  
              v = true;
171  
              d.stack.add(this);
172  
              if (d.n != l) d.append(", ");
173  
              structure_1(e.getKey(), d);
174  
            }
175  
          }
176  
        }
177  
      });
178  
      ret;
179  
    }
180  
    
181  
    if (c.isArray()) {
182  
      if (o instanceof byte[]) {
183  
        d.append("ba ").append(quote(bytesToHex((byte[]) o))); ret;
184  
      }
185  
  
186  
      final int n = Array.getLength(o);
187  
  
188  
      if (o instanceof bool[]) {
189  
        S hex = boolArrayToHex((bool[]) o);
190  
        int i = l(hex);
191  
        while (i > 0 && hex.charAt(i-1) == '0' && hex.charAt(i-2) == '0') i -= 2;
192  
        d.append("boolarray ").append(n).app(" ").append(quote(substring(hex, 0, i))); ret;
193  
      }
194  
      
195  
      S atype = "array", sep = ", ";
196  
  
197  
      if (o instanceof int[]) {
198  
        //ret "intarray " + quote(intArrayToHex((int[]) o));
199  
        atype = "intarray";
200  
        sep = " ";
201  
      }
202  
      
203  
      d.append(atype).append("{");
204  
      d.stack.add(new Runnable() {
205  
        int i;
206  
        public void run() {
207  
          if (i >= n)
208  
            d.append("}");
209  
          else {
210  
            d.stack.add(this);
211  
            if (i > 0) d.append(", ");
212  
            structure_1(Array.get(o, i++), d);
213  
          }
214  
        }
215  
      });
216  
      ret;
217  
    }
218  
  
219  
    if (o instanceof Class) {
220  
      d.append("class(", 2).append(quote(((Class) o).getName())).append(")"); ret;
221  
    }
222  
      
223  
    if (o instanceof Throwable) {
224  
      d.append("exception(", 2).append(quote(((Throwable) o).getMessage())).append(")"); ret;
225  
    }
226  
      
227  
    if (o instanceof BitSet) {
228  
      BitSet bs = (BitSet) o;
229  
      d.append("bitset{", 2);
230  
      int l = d.n;
231  
      for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
232  
        if (d.n != l) d.append(", ");
233  
        d.append(i);
234  
      }
235  
      d.append("}"); ret;
236  
    }
237  
      
238  
    // Need more cases? This should cover all library classes...
239  
    if (name.startsWith("java.") || name.startsWith("javax.")) {
240  
      d.append("j ").append(quote(str(o))); ret; // Hm. this is not unstructure-able
241  
    }
242  
    
243  
    ifclass Lisp
244  
      if (o << Lisp) {
245  
        d.append("l(", 2);
246  
        final Lisp lisp = cast o;
247  
        structure_1(lisp.head, d);
248  
        final Iterator it = lisp.args.iterator();
249  
        d.stack.add(r {
250  
          if (!it.hasNext())
251  
            d.append(")");
252  
          else {
253  
            d.stack.add(this);
254  
            d.append(", ");
255  
            structure_1(it.next(), d);
256  
          }
257  
        });
258  
        ret;
259  
      }
260  
    endif
261  
      
262  
    /*if (name.equals("main$Lisp")) {
263  
      fail("lisp not supported right now");
264  
    }*/
265  
    
266  
    if (concept && !d.concepts.contains(dynName)) {
267  
      d.concepts.add(dynName);
268  
      d.append("c ");
269  
    }
270  
    
271  
    // serialize an object with fields.
272  
    // first, collect all fields and values in fv.
273  
    
274  
    TreeSet<Field> fields = new TreeSet<Field>(new Comparator<Field>() {
275  
      public int compare(Field a, Field b) {
276  
        ret stdcompare(a.getName(), b.getName());
277  
      }
278  
    });
279  
    
280  
    while (c != Object.class) {
281  
      for (Field field : getDeclaredFields_cached(c)) {
282  
        if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0)
283  
          continue;
284  
        S fieldName = field.getName();
285  
        
286  
        fields.add(field);
287  
        
288  
        // put special cases here...
289  
      }
290  
        
291  
      c = c.getSuperclass();
292  
    }
293  
    
294  
    lFields = asList(fields);
295  
    
296  
    // Render this$1 first because unstructure needs it for constructor call.
297  
    
298  
    for (int i = 0; i < l(lFields); i++) {
299  
      Field f = lFields.get(i);
300  
      if (f.getName().equals("this$1")) {
301  
        lFields.remove(i);
302  
        lFields.add(0, f);
303  
        break;
304  
      }
305  
    }
306  
  
307  
    d.fieldsByClass.put(c, lFields);
308  
  }
309  
310  
  new LinkedHashMap<S, O> fv;
311  
  for (Field f : lFields) {
312  
    Object value;
313  
    try {
314  
      value = f.get(o);
315  
    } catch (Exception e) {
316  
      value = "?";
317  
    }
318  
      
319  
    if (value != null)
320  
      fv.put(f.getName(), value);
321  
  }
322  
  
323  
  String shortName = dropPrefix("main$", name);
324  
    
325  
  // Now we have fields & values. Process fieldValues if it's a DynamicObject.
326  
  
327  
  // omit field "className" if equal to class's name
328  
  if (concept && eq(fv.get("className"), shortName))
329  
    fv.remove("className");
330  
          
331  
  if (o instanceof DynamicObject) {
332  
    fv.putAll((Map) fv.get("fieldValues"));
333  
    fv.remove("fieldValues");
334  
    shortName = dynName;
335  
    fv.remove("className");
336  
  }
337  
  
338  
  S singleField = fv.size() == 1 ? first(fv.keySet()) : null;
339  
  
340  
  d.append(shortName);
341  
342  
  final int l = d.n;
343  
  final Iterator it = fv.entrySet().iterator();
344  
  
345  
  d.stack.add(r {
346  
    if (!it.hasNext()) {
347  
      if (d.n != l)
348  
        d.append(")");
349  
    } else {
350  
      Map.Entry e = (Map.Entry) it.next();
351  
      d.append(d.n == l ? "(" : ", ");
352  
      d.append((S) e.getKey()).append("=");
353  
      d.stack.add(this);
354  
      structure_1(e.getValue(), d);
355  
    }
356  
  });
357  
}

Author comment

Began life as a copy of #1005964

download  show line numbers  debug dex  old transpilations   

Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1008806
Snippet name: structure function (v13, with noStringSharing option)
Eternal ID of this version: #1008806/5
Text MD5: 9a31243283e59dadce3779a79d7589c7
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-07-31 20:31:28
Source code size: 10118 bytes / 357 lines
Pitched / IR pitched: No / No
Views / Downloads: 484 / 523
Version history: 4 change(s)
Referenced in: [show references]