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

src.java.com.ctc.wstx.sr.ElemAttrs Maven / Gradle / Ivy

package com.ctc.wstx.sr;

import javax.xml.namespace.QName;

/**
 * Container class that is constructed with enough raw attribute information,
 * to be able to lazily construct full attribute objects, to be accessed
 * via Iterator, or fully-qualified name.
 *

* Implementation note: code for using Map-like structure is unfortunately * cut'n pasted from {@link AttributeCollector}. Problem * with refactoring is that it's 90% the same code, but not 100%. *

* Although instances of this class are constructed by stream readers, * it is actually used by element event objects. */ public final class ElemAttrs { //private final static int OFFSET_LOCAL_NAME = 0; private final static int OFFSET_NS_URI = 1; //private final static int OFFSET_NS_PREFIX = 2; //private final static int OFFSET_VALUE = 3; /** * Array that contains 4 Strings for each attribute; * localName, URI, prefix, value. Can be used to lazily construct * structure(s) needed to return Iterator for accessing all * attributes. */ private final String[] mRawAttrs; /** * Raw offset (in mRawAttrs) of the first attribute * instance that was created through default value expansion. */ private final int mDefaultOffset; /* ////////////////////////////////////////////////////////////// // Information that defines "Map-like" data structure used for // quick access to attribute values by fully-qualified name // (only used for "long" lists) ////////////////////////////////////////////////////////////// */ // // // For full explanation, see source for AttributeCollector private final int[] mAttrMap; private final int mAttrHashSize; private final int mAttrSpillEnd; /** * Method called to create "short" attribute list; list that has * only few entries, and can thus be searched for attributes using * linear search, without using any kind of Map structure. *

* Currently the limit is 4 attributes; 1, 2 or 3 attribute lists are * considered short, 4 or more 'long'. * * @param rawAttrs Array that contains 4 Strings for each attribute; * localName, URI, prefix, value. Can be used to lazily construct * structure(s) needed to return Iterator for accessing all * attributes. * @param defOffset Index of the first default attribute, if any; * number of all attributes if none */ public ElemAttrs(String[] rawAttrs, int defOffset) { mRawAttrs = rawAttrs; mAttrMap = null; mAttrHashSize = 0; mAttrSpillEnd = 0; mDefaultOffset = (defOffset << 2); } /** * Method called to create "long" attribute list; list that has * a few entries, and efficient access by fully-qualified name should * not be done by linear search. * * @param rawAttrs Array that contains 4 Strings for each attribute; * localName, URI, prefix, value. Can be used to lazily construct * structure(s) needed to return Iterator for accessing all * attributes. */ public ElemAttrs(String[] rawAttrs, int defOffset, int[] attrMap, int hashSize, int spillEnd) { mRawAttrs = rawAttrs; mDefaultOffset = (defOffset << 2); mAttrMap = attrMap; mAttrHashSize = hashSize; mAttrSpillEnd = spillEnd; } /* //////////////////////////////////////////////////// // Public API //////////////////////////////////////////////////// */ public String[] getRawAttrs() { return mRawAttrs; } public int findIndex(QName name) { // Can/need to use linear search? if (mAttrMap == null) { String ln = name.getLocalPart(); String uri = name.getNamespaceURI(); boolean defaultNs = (uri == null || uri.length() == 0); String[] raw = mRawAttrs; for (int i = 0, len = raw.length; i < len; i += 4) { if (!ln.equals(raw[i])) { continue; } String thisUri = raw[i+OFFSET_NS_URI]; if (defaultNs) { if (thisUri == null || thisUri.length() == 0) { return i; } } else { // non-default NS if (thisUri != null && (thisUri == uri || thisUri.equals(uri))) { return i; } } } return -1; } // Ok, better use the Map... return findMapIndex(name.getNamespaceURI(), name.getLocalPart()); } public int getFirstDefaultOffset() { return mDefaultOffset; } public boolean isDefault(int ix) { return (ix >= mDefaultOffset); } /* //////////////////////////////////////////////////// // Internal methods //////////////////////////////////////////////////// */ /** *

* Note: this method is very similar to * {@link com.ctc.wstx.sr.AttributeCollector#getAttrValue}; basically * most of it was cut'n pasted. Would be nice to refactor, but it's * bit hard to do that since data structures are not 100% identical * (mostly attribute storage, not Map structure itself). */ private final int findMapIndex(String nsURI, String localName) { // Primary hit? int hash = localName.hashCode(); if (nsURI == null) { nsURI = ""; // just to simplify comparisons -- array contains nulls } else if (nsURI.length() > 0) { hash ^= nsURI.hashCode(); } int ix = mAttrMap[hash & (mAttrHashSize - 1)]; if (ix == 0) { // nothing in here; no spills either return -1; } // Index is "one off" (since 0 indicates 'null), 4 Strings per attr ix = (ix - 1) << 2; // Is primary candidate match? String[] raw = mRawAttrs; String thisName = raw[ix]; /* Equality first, since although equals() checks that too, it's * very likely to match (if interning Strings), and we can save * a method call. */ if (thisName == localName || thisName.equals(localName)) { String thisURI = raw[ix+OFFSET_NS_URI]; if (thisURI == nsURI) { return ix; } if (thisURI == null) { if (nsURI.length() == 0) { return ix; } } else if (thisURI.equals(nsURI)) { return ix; } } /* Nope, need to traverse spill list, which has 2 entries for * each spilled attribute id; first for hash value, second index. */ for (int i = mAttrHashSize, len = mAttrSpillEnd; i < len; i += 2) { if (mAttrMap[i] != hash) { continue; } /* Note: spill indexes are not off-by-one, since there's no need * to mask 0 */ ix = mAttrMap[i+1] << 2; // ... but there are 4 Strings for each attr thisName = raw[ix]; if (thisName == localName || thisName.equals(localName)) { String thisURI = raw[ix+1]; if (thisURI == nsURI) { return ix; } if (thisURI == null) { if (nsURI.length() == 0) { return ix; } } else if (thisURI.equals(nsURI)) { return ix; } } } return -1; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy