KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xmlpull > mxp1 > MXParserCachingStrings


1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
2 /*
3  * Copyright (c) 2002 Extreme! Lab, Indiana University. All rights reserved.
4  *
5  * This software is open source. See the bottom of this file for the licence.
6  *
7  * $Id: MXParserCachingStrings.java,v 1.3 2002/08/23 19:50:54 aslom Exp $
8  */

9
10 package org.xmlpull.mxp1;
11
12 import org.xmlpull.v1.XmlPullParserException;
13
14 /**
15  * Extend MXP parser to use string cache of char[] to interned String
16  * <p>NOTE: it is not non-validaint parser as there is no supporting internal DTD parsing
17  * no full XML 1.0 (or 1.1) character classes are supported.
18  *
19  * @author <a HREF="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
20  */

21
22 public class MXParserCachingStrings extends MXParser
23 {
24     private final static boolean CACHE_STATISTICS = false;
25     private final static boolean TRACE_SIZING = false;
26     private int cacheStatCalls;
27     private int cacheStatWalks;
28     private int cacheStatResets;
29     private int cacheStatRehash;
30
31     /** NOTE: implemented as integers and not flot to allow to work on J2ME. */
32     private static final int CACHE_LOAD = 77; //in % ie. 77% == 77/100
33
private int cacheEntriesCount;
34     private int cacheEntriesThreshold;
35
36     //entries are kept in a simple linear list
37
private char[][] keys;
38     private String JavaDoc[] values;
39
40     private boolean global;
41     // as it is shared state ALL access to those varaibles must be synchronized!
42
// global cache variables shadow per-instance variables for maximum performance
43
// as cache is alway growing the access is optimized for really fast unsychronized lookups
44
private static int globalCacheEntriesCount;
45     private static int globalCacheEntriesThreshold;
46     private static char[][] globalKeys;
47     private static String JavaDoc[] globalValues;
48
49
50     public MXParserCachingStrings() {
51         super();
52         allStringsInterned = true;
53     }
54
55     /**
56      * This allows to change name iterning property in this enhanced impl.
57      */

58     public void setFeature(String JavaDoc name,
59                            boolean state) throws XmlPullParserException
60     {
61         if(FEATURE_NAMES_INTERNED.equals(name)) {
62             if(eventType != START_DOCUMENT) throw new XmlPullParserException(
63                     "interning names feature can only be changed before parsing", this, null);
64             allStringsInterned = state;
65             if(state == false) {
66                 if(keys != null) resetStringCache();
67             }
68         } else {
69             super.setFeature(name, state);
70         }
71     }
72
73     public boolean getFeature(String JavaDoc name)
74     {
75         if(FEATURE_NAMES_INTERNED.equals(name)) {
76             return allStringsInterned;
77         } else {
78             return super.getFeature(name);
79         }
80     }
81
82
83     /**
84      * Hook to GC finalization to print statistics about pool cache impl. perf.
85      */

86     public void finalize() {
87         if(CACHE_STATISTICS) {
88             if( cacheStatCalls > 0) {
89                 System.out.println("statistics: average walk:"+cacheStatWalks+"/"+cacheStatCalls+
90                                        " ("+((double)cacheStatWalks)/cacheStatCalls+")"+
91                                        " resets="+cacheStatResets+" rehash="+cacheStatRehash);
92             } else {
93                 System.out.println("statistics: cache was not used");
94             }
95         }
96     }
97
98     /**
99      * If feature name interning is enabled then this funtion
100      * MUST return interned string.
101      */

102     protected String JavaDoc newString(char[] cbuf, int off, int len) {
103         if(allStringsInterned) {
104             return newStringIntern(cbuf, off, len);
105         } else {
106             return super.newString(cbuf, off, len);
107         }
108     }
109
110     /**
111      * This is <b>efficient</b> implementation of pool that returns
112      * interned String based on char[] input.
113      */

114     protected String JavaDoc newStringIntern(char[] cbuf, int off, int len) {
115         //return (new String(cbuf, off, len)).intern();
116
if(CACHE_STATISTICS) ++cacheStatCalls;
117         if (cacheEntriesCount >= cacheEntriesThreshold) {
118             rehash();
119         }
120         int offset = fastHash(cbuf, off, len) % keys.length;
121         char[] k = null;
122         while( (k = keys[offset]) != null
123               && !keysAreEqual(k, 0, k.length,
124                                cbuf, off, len))
125         {
126             offset = (offset + 1) % keys.length;
127             if(CACHE_STATISTICS) ++cacheStatWalks;
128         }
129         if (k != null) {
130             return values[offset];
131         } else {
132             k = new char[len];
133             System.arraycopy(cbuf, off, k, 0, len);
134             String JavaDoc v = new String JavaDoc(k).intern();
135             keys[offset] = k;
136             values[offset] = v;
137             ++cacheEntriesCount;
138             return v;
139         }
140
141     }
142
143     protected void initStringCache() {
144         if(keys == null) {
145             int initialCapacity = 13;
146             if(initialCapacity < 0) {
147                 throw new IllegalArgumentException JavaDoc("Illegal initial capacity: " + initialCapacity);
148             }
149             if(CACHE_LOAD < 0 || CACHE_LOAD > 99) {
150                 throw new IllegalArgumentException JavaDoc("Illegal load factor: " + CACHE_LOAD);
151             }
152             cacheEntriesThreshold = (int)((initialCapacity * CACHE_LOAD)/100);
153             if(cacheEntriesThreshold >= initialCapacity) throw new RuntimeException JavaDoc(
154                     "internal error: threshold must be less than capacity: "+initialCapacity);
155             keys = new char[initialCapacity][];
156             values = new String JavaDoc[initialCapacity];
157             cacheEntriesCount = 0;
158         }
159     }
160
161     protected void resetStringCache() {
162         //System.out.println("reset string cache()");
163
if(CACHE_STATISTICS) ++cacheStatResets;
164         initStringCache();
165     }
166
167     private void rehash() {
168         if(CACHE_STATISTICS) ++cacheStatRehash;
169         int newSize = 2 * keys.length + 1;
170         cacheEntriesThreshold = (int)((newSize * CACHE_LOAD)/100);
171         if(cacheEntriesThreshold >= newSize) throw new RuntimeException JavaDoc(
172                 "internal error: threshold must be less than capacity: "+newSize);
173         if(TRACE_SIZING) System.err.println("resized "+keys.length+" => "+newSize);
174         char[][] newKeys = new char[newSize][];
175         String JavaDoc[] newValues = new String JavaDoc[newSize];
176         for(int i = 0; i < keys.length; i++) {
177             char[] k = keys[i];
178             keys[i] = null;
179             String JavaDoc v = values[i];
180             values[i] = null;
181             if(k != null) {
182                 int newOffset = fastHash(k, 0, k.length) % newSize;
183                 char[] newk = null;
184                 while((newk = newKeys[newOffset]) != null) {
185                     if(keysAreEqual(newk, 0, newk.length,
186                                     k, 0, k.length)) {
187                         throw new RuntimeException JavaDoc("internal cache error: duplicated keys: "+
188                                                        new String JavaDoc(newk)+" and "+new String JavaDoc(k));
189                     }
190                     newOffset = (newOffset + 1) % newSize;
191                 }
192
193                 newKeys[newOffset] = k;
194                 newValues[newOffset] = v;
195             }
196         }
197         keys = newKeys;
198         values = newValues;
199     }
200
201     private static final boolean keysAreEqual (char[] a, int astart, int alength,
202                                                char[] b, int bstart, int blength) {
203         if(alength != blength) {
204             return false;
205         } else {
206             for(int i = 0; i < alength; i++) {
207                 if(a[astart + i] != b[bstart + i]) {
208                     return false;
209                 }
210             }
211             return true;
212         }
213     }
214
215 }
216
217
218 /*
219  * Indiana University Extreme! Lab Software License, Version 1.1.1
220  *
221  *
222  * Copyright (c) 2002 Extreme! Lab, Indiana University. All rights
223  * reserved.
224  *
225  * Redistribution and use in source and binary forms, with or without
226  * modification, are permitted provided that the following conditions
227  * are met:
228  *
229  * 1. Redistributions of source code must retain the above copyright
230  * notice, this list of conditions and the following disclaimer.
231  *
232  * 2. Redistributions in binary form must reproduce the above copyright
233  * notice, this list of conditions and the following disclaimer in
234  * the documentation and/or other materials provided with the
235  * distribution.
236  *
237  * 3. The end-user documentation included with the redistribution,
238  * if any, must include the following acknowledgment:
239  * "This product includes software developed by the Indiana
240  * University Extreme! Lab (http://www.extreme.indiana.edu/)."
241  * Alternately, this acknowledgment may appear in the software itself,
242  * if and wherever such third-party acknowledgments normally appear.
243  *
244  * 4. The names "Indiana University" and "Indiana University
245  * Extreme! Lab" must not be used to endorse or promote products
246  * derived from this software without prior written permission. For
247  * written permission, please contact http://www.extreme.indiana.edu/.
248  *
249  * 5. Products derived from this software may not use "Indiana
250  * University" name nor may "Indiana University" appear in their name,
251  * without prior written permission of the Indiana University.
252  *
253  *
254  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
255  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
256  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
257  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
258  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
259  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
260  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
261  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
262  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
263  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
264  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265  * SUCH DAMAGE.
266  */

267
268
Popular Tags