Speed up toString() for XML elements
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / codec / xml / RandomPrefix.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.BiMap;
13 import com.google.common.collect.HashBiMap;
14
15 import java.net.URI;
16 import java.util.Map;
17
18 import javax.xml.XMLConstants;
19 import javax.xml.namespace.NamespaceContext;
20
21 class RandomPrefix {
22     // 32 characters, carefully chosen
23     private static final String LOOKUP = "abcdefghiknoprstABCDEFGHIKNOPRST";
24     private static final int MASK = 0x1f;
25     private static final int SHIFT = 5;
26
27     private int counter = 0;
28
29     // BiMap to make values lookup faster
30     private final BiMap<URI, String> prefixes = HashBiMap.create();
31     private final NamespaceContext context;
32
33     RandomPrefix() {
34         this.context = null;
35     }
36
37     RandomPrefix(final NamespaceContext context) {
38         this.context = Preconditions.checkNotNull(context);
39     }
40
41     Iterable<Map.Entry<URI, String>> getPrefixes() {
42         return prefixes.entrySet();
43     }
44
45     String encodePrefix(final URI namespace) {
46         String prefix = prefixes.get(namespace);
47         if (prefix != null) {
48             return prefix;
49         }
50
51         do {
52             prefix = encode(counter);
53             counter++;
54         } while (alreadyUsedPrefix(prefix));
55
56         prefixes.put(namespace, prefix);
57         return prefix;
58     }
59
60     private boolean alreadyUsedPrefix(final String prefix) {
61         if (context == null) {
62             return false;
63         }
64
65         final String str = context.getNamespaceURI(prefix);
66         return !XMLConstants.NULL_NS_URI.equals(str);
67     }
68
69     @VisibleForTesting
70     static int decode(final String str) {
71         int ret = 0;
72         for (char c : str.toCharArray()) {
73             int idx = LOOKUP.indexOf(c);
74             Preconditions.checkArgument(idx != -1, "Invalid string %s", str);
75             ret = (ret << SHIFT) + idx;
76         }
77
78         return ret;
79     }
80
81     @VisibleForTesting
82     static String encode(int num) {
83         final StringBuilder sb = new StringBuilder();
84
85         do {
86             sb.append(LOOKUP.charAt(num & MASK));
87             num >>>= SHIFT;
88         } while (num != 0);
89
90         return sb.reverse().toString();
91     }
92 }