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

315
LINES

< > BotCompany Repo | #1005596 // structure function (v9, caching fields by class)

JavaX fragment (include)

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  
}

Author comment

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: 574 / 560
Referenced in: [show references]