All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmlpull.mxp1.MXParserCachingStrings Maven / Gradle / Ivy

The newest version!
/* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
/*
 * Copyright (c) 2002-2004 Extreme! Lab, Indiana University. All rights reserved.
 *
 * This software is open source. See the bottom of this file for the licence.
 *
 * $Id: MXParserCachingStrings.java,v 1.11 2006/10/23 13:36:27 aslom Exp $
 */

package org.xmlpull.mxp1;

import java.io.Reader;
import org.xmlpull.v1.XmlPullParserException;

/**
 * Extend MXP parser to use string cache of char[] to interned String
 * 

NOTE: it is not non-validaint parser as there is no supporting internal DTD parsing * no full XML 1.0 (or 1.1) character classes are supported. * * @author Aleksander Slominski */ public class MXParserCachingStrings extends MXParser implements Cloneable { protected final static boolean CACHE_STATISTICS = false; protected final static boolean TRACE_SIZING = false; protected final static int INITIAL_CAPACITY = 13; protected int cacheStatCalls; protected int cacheStatWalks; protected int cacheStatResets; protected int cacheStatRehash; /** NOTE: implemented as integers and not flot to allow to work on J2ME. */ protected static final int CACHE_LOAD = 77; //in % ie. 77% == 77/100 protected int cacheEntriesCount; protected int cacheEntriesThreshold; //entries are kept in a simple linear list protected char[][] keys; protected String[] values; // private boolean global; // // as it is shared state ALL access to those varaibles must be synchronized! // // global cache variables shadow per-instance variables for maximum performance // // as cache is alway growing the access is optimized for really fast unsychronized lookups // private static int globalCacheEntriesCount; // private static int globalCacheEntriesThreshold; // private static char[][] globalKeys; // private static String[] globalValues; public Object clone() throws CloneNotSupportedException { if(reader != null) { if(!(reader instanceof Cloneable)) { throw new CloneNotSupportedException("reader used in parser must implement Cloneable!"); } } MXParserCachingStrings cloned = (MXParserCachingStrings) super.clone(); //protected Reader reader; if(reader != null) { // why Cloneable has no clone() inside? good question and needs for stupid CloneableReader ... //cloned.reader = (Reader) ((Cloneable)reader).clone(); //BING BONG doe snot work ... //use reflection to call clone() -- this is getting ugly!!!! // more background on this in http://www.artima.com/intv/issues3.html "The clone Dilemma" try { Object o = reader.getClass().getMethod("clone", null).invoke(reader, null); cloned.reader = (Reader) o; } catch (Exception e) { //throw new CloneNotSupportedException("failed to call clone() on reader "+reader+e); CloneNotSupportedException ee = new CloneNotSupportedException("failed to call clone() on reader "+reader+":"+e); ee.initCause(e); throw ee; } } // NOTE: "A clone of a multidimensional array is shallow, which is to say that // "it creates only a single new array. Subarrays are shared, ..." // http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#64347 // protected char[][] keys; if(keys != null) { //TODO REVISIT: it seems cloneCCArr() is not needed cloned.keys = (char[][]) keys.clone(); } // protected String[] values; if(values != null) { cloned.values = (String[]) values.clone(); } //---- base class // protected char[] elRawName[]; if(elRawName != null) { cloned.elRawName = cloneCCArr(elRawName); } // protected int elRawNameEnd[]; if(elRawNameEnd != null) { cloned.elRawNameEnd = (int[]) elRawNameEnd.clone(); } // protected int elRawNameLine[]; if(elRawNameLine != null) { cloned.elRawNameLine = (int[]) elRawNameLine.clone(); } // protected String elName[]; if(elName != null) { cloned.elName = (String[]) elName.clone(); } // protected String elPrefix[]; if(elPrefix != null) { cloned.elPrefix = (String[]) elPrefix.clone(); } // protected String elUri[]; if(elUri != null) { cloned.elUri = (String[]) elUri.clone(); } // protected int elNamespaceCount[]; if(elNamespaceCount != null) { cloned.elNamespaceCount = (int[]) elNamespaceCount.clone(); } // protected String attributeName[]; if(attributeName != null) { cloned.attributeName = (String[]) attributeName.clone(); } // protected int attributeNameHash[]; if(attributeNameHash != null) { cloned.attributeNameHash = (int[]) attributeNameHash.clone(); } // protected String attributePrefix[]; if(attributePrefix != null) { cloned.attributePrefix = (String[]) attributePrefix.clone(); } // protected String attributeUri[]; if(attributeUri != null) { cloned.attributeUri = (String[]) attributeUri.clone(); } // protected String attributeValue[]; if(attributeValue != null) { cloned.attributeValue = (String[]) attributeValue.clone(); } // protected String namespacePrefix[]; if(namespacePrefix != null) { cloned.namespacePrefix = (String[]) namespacePrefix.clone(); } // protected int namespacePrefixHash[]; if(namespacePrefixHash != null) { cloned.namespacePrefixHash = (int[]) namespacePrefixHash.clone(); } // protected String namespaceUri[]; if(namespaceUri != null) { cloned.namespaceUri = (String[]) namespaceUri.clone(); } // protected String entityName[]; if(entityName != null) { cloned.entityName = (String[]) entityName.clone(); } // protected char[] entityNameBuf[]; if(entityNameBuf != null) { cloned.entityNameBuf = cloneCCArr(entityNameBuf); } // protected int entityNameHash[]; if(entityNameHash != null) { cloned.entityNameHash = (int[]) entityNameHash.clone(); } // protected char[] entityReplacementBuf[]; if(entityReplacementBuf != null) { cloned.entityReplacementBuf = cloneCCArr(entityReplacementBuf); } // protected String entityReplacement[]; if(entityReplacement != null) { cloned.entityReplacement = (String[]) entityReplacement.clone(); } // protected char buf[]; if(buf != null) { cloned.buf = (char[]) buf.clone(); } // protected char pc[]; if(pc != null) { cloned.pc = (char[]) pc.clone(); } // protected char[] charRefOneCharBuf; if(charRefOneCharBuf != null) { cloned.charRefOneCharBuf = (char[]) charRefOneCharBuf.clone(); } return cloned; } private char[][] cloneCCArr(char[][] ccarr) { char[][] cca = (char[][]) ccarr.clone(); for (int i = 0; i < cca.length; i++) { if(cca[i] != null) { cca[i] = (char[]) cca[i].clone(); } } return cca; } public MXParserCachingStrings() { super(); allStringsInterned = true; initStringCache(); } /** * This allows to change name iterning property in this enhanced impl. */ public void setFeature(String name, boolean state) throws XmlPullParserException { if(FEATURE_NAMES_INTERNED.equals(name)) { if(eventType != START_DOCUMENT) throw new XmlPullParserException( "interning names feature can only be changed before parsing", this, null); allStringsInterned = state; if(state == false) { if(keys != null) resetStringCache(); } } else { super.setFeature(name, state); } } public boolean getFeature(String name) { if(FEATURE_NAMES_INTERNED.equals(name)) { return allStringsInterned; } else { return super.getFeature(name); } } /** * Hook to GC finalization to print statistics about pool cache impl. perf. */ public void finalize() { if(CACHE_STATISTICS) { if( cacheStatCalls > 0) { System.out.println("statistics: average walk:"+cacheStatWalks+"/"+cacheStatCalls+ " ("+((double)cacheStatWalks)/cacheStatCalls+")"+ " resets="+cacheStatResets+" rehash="+cacheStatRehash); } else { System.out.println("statistics: cache was not used"); } } } /** * If feature name interning is enabled then this funtion * MUST return interned string. */ protected String newString(char[] cbuf, int off, int len) { if(allStringsInterned) { return newStringIntern(cbuf, off, len); } else { return super.newString(cbuf, off, len); } } /** * This is efficient implementation of pool that returns * interned String based on char[] input. */ protected String newStringIntern(char[] cbuf, int off, int len) { //return (new String(cbuf, off, len)).intern(); if(CACHE_STATISTICS) ++cacheStatCalls; if (cacheEntriesCount >= cacheEntriesThreshold) { rehash(); } int offset = fastHash(cbuf, off, len) % keys.length; char[] k = null; while( (k = keys[offset]) != null && !keysAreEqual(k, 0, k.length, cbuf, off, len)) { offset = (offset + 1) % keys.length; if(CACHE_STATISTICS) ++cacheStatWalks; } if (k != null) { return values[offset]; } else { k = new char[len]; System.arraycopy(cbuf, off, k, 0, len); final String v = new String(k).intern(); keys[offset] = k; values[offset] = v; ++cacheEntriesCount; return v; } } protected void initStringCache() { if(keys == null) { //int initialCapacity = 13; if(INITIAL_CAPACITY < 0) { throw new IllegalArgumentException("Illegal initial capacity: " + INITIAL_CAPACITY); } if(CACHE_LOAD < 0 || CACHE_LOAD > 99) { throw new IllegalArgumentException("Illegal load factor: " + CACHE_LOAD); } cacheEntriesThreshold = (int)((INITIAL_CAPACITY * CACHE_LOAD)/100); if(cacheEntriesThreshold >= INITIAL_CAPACITY) throw new RuntimeException( "internal error: threshold must be less than capacity: "+INITIAL_CAPACITY); keys = new char[INITIAL_CAPACITY][]; values = new String[INITIAL_CAPACITY]; cacheEntriesCount = 0; } } protected void resetStringCache() { //System.out.println("reset string cache()"); if(CACHE_STATISTICS) ++cacheStatResets; initStringCache(); } private void rehash() { if(CACHE_STATISTICS) ++cacheStatRehash; final int newSize = 2 * keys.length + 1; cacheEntriesThreshold = (int)((newSize * CACHE_LOAD)/100); if(cacheEntriesThreshold >= newSize) throw new RuntimeException( "internal error: threshold must be less than capacity: "+newSize); if(TRACE_SIZING) System.err.println("resized "+keys.length+" => "+newSize); final char[][] newKeys = new char[newSize][]; final String[] newValues = new String[newSize]; for(int i = 0; i < keys.length; i++) { final char[] k = keys[i]; keys[i] = null; final String v = values[i]; values[i] = null; if(k != null) { int newOffset = fastHash(k, 0, k.length) % newSize; char[] newk = null; while((newk = newKeys[newOffset]) != null) { if(keysAreEqual(newk, 0, newk.length, k, 0, k.length)) { throw new RuntimeException("internal cache error: duplicated keys: "+ new String(newk)+" and "+new String(k)); } newOffset = (newOffset + 1) % newSize; } newKeys[newOffset] = k; newValues[newOffset] = v; } } keys = newKeys; values = newValues; } private static final boolean keysAreEqual (char[] a, int astart, int alength, char[] b, int bstart, int blength) { if(alength != blength) { return false; } else { for(int i = 0; i < alength; i++) { if(a[astart + i] != b[bstart + i]) { return false; } } return true; } } } /* * Indiana University Extreme! Lab Software License, Version 1.2 * * Copyright (c) 2002-2004 The Trustees of Indiana University. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1) All redistributions of source code must retain the above * copyright notice, the list of authors in the original source * code, this list of conditions and the disclaimer listed in this * license; * * 2) All redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the disclaimer * listed in this license in the documentation and/or other * materials provided with the distribution; * * 3) Any documentation included with all redistributions must include * the following acknowledgement: * * "This product includes software developed by the Indiana * University Extreme! Lab. For further information please visit * http://www.extreme.indiana.edu/" * * Alternatively, this acknowledgment may appear in the software * itself, and wherever such third-party acknowledgments normally * appear. * * 4) The name "Indiana University" or "Indiana University * Extreme! Lab" shall not be used to endorse or promote * products derived from this software without prior written * permission from Indiana University. For written permission, * please contact http://www.extreme.indiana.edu/. * * 5) Products derived from this software may not use "Indiana * University" name nor may "Indiana University" appear in their name, * without prior written permission of the Indiana University. * * Indiana University provides no reassurances that the source code * provided does not infringe the patent or any other intellectual * property rights of any other entity. Indiana University disclaims any * liability to any recipient for claims brought by any other entity * based on infringement of intellectual property rights or otherwise. * * LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA * UNIVERSITY GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT * SOFTWARE IS FREE OF INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR * OTHER PROPRIETARY RIGHTS. INDIANA UNIVERSITY MAKES NO WARRANTIES THAT * SOFTWARE IS FREE FROM "BUGS", "VIRUSES", "TROJAN HORSES", "TRAP * DOORS", "WORMS", OR OTHER HARMFUL CODE. LICENSEE ASSUMES THE ENTIRE * RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR ASSOCIATED MATERIALS, * AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION GENERATED USING * SOFTWARE. */





© 2015 - 2025 Weber Informatics LLC | Privacy Policy