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

org.htmlunit.xpath.xml.utils.SuballocatedIntVector Maven / Gradle / Ivy

There is a newer version: 4.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.htmlunit.xpath.xml.utils;

/**
 * A very simple table that stores a list of int. Very similar API to our IntVector class (same
 * API); different internal storage.
 *
 * 

This version uses an array-of-arrays solution. Read/write access is thus a bit slower than the * simple IntVector, and basic storage is a trifle higher due to the top-level array -- but * appending is O(1) fast rather than O(N**2) slow, which will swamp those costs in situations where * long vectors are being built up. * *

Known issues: * *

Some methods are private because they haven't yet been tested properly. * *

Retrieval performance is critical, since this is used at the core of the DTM model. (Append * performance is almost as important.) That's pushing me toward just letting reads from unset * indices throw exceptions or return stale data; safer behavior would have performance costs. */ public class SuballocatedIntVector { /** Size of blocks to allocate */ protected final int m_blocksize; /** Bitwise addressing (much faster than div/remainder */ protected int m_SHIFT; protected final int m_MASK; /** The default number of blocks to (over)allocate by */ protected static final int NUMBLOCKS_DEFAULT = 32; /** The number of blocks to (over)allocate by */ protected final int m_numblocks; /** Array of arrays of ints */ protected int[][] m_map; /** Number of ints in array */ protected int m_firstFree = 0; /** "Shortcut" handle to m_map[0]. Surprisingly helpful for short vectors. */ protected final int[] m_map0; /** "Shortcut" handle to most recently added row of m_map. Very helpful during construction. */ protected int[] m_buildCache; protected int m_buildCacheStartIndex; /** * Construct a IntVector, using the given block size and number of blocks. For efficiency, we will * round the requested size off to a power of two. * * @param blocksize Size of block to allocate * @param numblocks Number of blocks to allocate */ public SuballocatedIntVector(int blocksize, final int numblocks) { // m_blocksize = blocksize; for (m_SHIFT = 0; 0 != (blocksize >>>= 1); ++m_SHIFT) { } m_blocksize = 1 << m_SHIFT; m_MASK = m_blocksize - 1; m_numblocks = numblocks; m_map0 = new int[m_blocksize]; m_map = new int[numblocks][]; m_map[0] = m_map0; m_buildCache = m_map0; m_buildCacheStartIndex = 0; } /** * Construct a IntVector, using the given block size and the default number of blocks (32). * * @param blocksize Size of block to allocate */ public SuballocatedIntVector(final int blocksize) { this(blocksize, NUMBLOCKS_DEFAULT); } /** * Get the length of the list. * * @return length of the list */ public int size() { return m_firstFree; } /** * Append a int onto the vector. * * @param value Int to add to the list */ public void addElement(final int value) { final int indexRelativeToCache = m_firstFree - m_buildCacheStartIndex; // Is the new index an index into the cache row of m_map? if (indexRelativeToCache >= 0 && indexRelativeToCache < m_blocksize) { m_buildCache[indexRelativeToCache] = value; ++m_firstFree; } else { // Growing the outer array should be rare. We initialize to a // total of m_blocksize squared elements, which at the default // size is 4M integers... and we grow by at least that much each // time. However, attempts to microoptimize for this (assume // long enough and catch exceptions) yield no noticable // improvement. final int index = m_firstFree >>> m_SHIFT; final int offset = m_firstFree & m_MASK; if (index >= m_map.length) { final int newsize = index + m_numblocks; final int[][] newMap = new int[newsize][]; System.arraycopy(m_map, 0, newMap, 0, m_map.length); m_map = newMap; } int[] block = m_map[index]; if (null == block) { block = m_map[index] = new int[m_blocksize]; } block[offset] = value; // Cache the current row of m_map. Next m_blocksize-1 // values added will go to this row. m_buildCache = block; m_buildCacheStartIndex = m_firstFree - offset; ++m_firstFree; } } /** * Sets the component at the specified index of this vector to be the specified object. The * previous component at that position is discarded. * *

The index must be a value greater than or equal to 0 and less than the current size of the * vector. * * @param value object to set * @param at Index of where to set the object */ public void setElementAt(final int value, final int at) { if (at < m_blocksize) { m_map0[at] = value; } else { final int index = at >>> m_SHIFT; final int offset = at & m_MASK; if (index >= m_map.length) { final int newsize = index + m_numblocks; final int[][] newMap = new int[newsize][]; System.arraycopy(m_map, 0, newMap, 0, m_map.length); m_map = newMap; } int[] block = m_map[index]; if (null == block) { block = m_map[index] = new int[m_blocksize]; } block[offset] = value; } if (at >= m_firstFree) { m_firstFree = at + 1; } } /** * Get the nth element. This is often at the innermost loop of an application, so performance is * critical. * * @param i index of value to get * @return value at given index. If that value wasn't previously set, the result is undefined for * performance reasons. It may throw an exception (see below), may return zero, or (if setSize * has previously been used) may return stale data. * @throws ArrayIndexOutOfBoundsException if the index was _clearly_ unreasonable (negative, or * past the highest block). * @throws NullPointerException if the index points to a block that could have existed (based on * the highest index used) but has never had anything set into it. %REVIEW% Could add a catch * to create the block in that case, or return 0. Try/Catch is _supposed_ to be nearly free * when not thrown to. Do we believe that? Should we have a separate safeElementAt? */ public int elementAt(final int i) { // This is actually a significant optimization! if (i < m_blocksize) { return m_map0[i]; } return m_map[i >>> m_SHIFT][i & m_MASK]; } /** * Searches for the first occurence of the given argument, beginning the search at index, and * testing for equality using the equals method. * * @param elem object to look for * @param index Index of where to begin search * @return the index of the first occurrence of the object argument in this vector at position * index or later in the vector; returns -1 if the object is not found. */ public int indexOf(final int elem, final int index) { if (index >= m_firstFree) { return -1; } int bindex = index >>> m_SHIFT; int boffset = index & m_MASK; final int maxindex = m_firstFree >>> m_SHIFT; int[] block; for ( ; bindex < maxindex; ++bindex) { block = m_map[bindex]; if (block != null) { for (int offset = boffset; offset < m_blocksize; ++offset) { if (block[offset] == elem) { return offset + bindex * m_blocksize; } } } boffset = 0; // after first } // Last block may need to stop before end final int maxoffset = m_firstFree & m_MASK; block = m_map[maxindex]; for (int offset = boffset; offset < maxoffset; ++offset) { if (block[offset] == elem) { return offset + maxindex * m_blocksize; } } return -1; } /** * Searches for the first occurence of the given argument, beginning the search at index, and * testing for equality using the equals method. * * @param elem object to look for * @return the index of the first occurrence of the object argument in this vector at position * index or later in the vector; returns -1 if the object is not found. */ public int indexOf(final int elem) { return indexOf(elem, 0); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy