1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xml.utils;
  58. /**
  59. * <meta name="usage" content="internal"/>
  60. * A very simple table that stores a list of int. Very similar API to our
  61. * IntVector class (same API); different internal storage.
  62. *
  63. * This version uses an array-of-arrays solution. Read/write access is thus
  64. * a bit slower than the simple IntVector, and basic storage is a trifle
  65. * higher due to the top-level array -- but appending is O(1) fast rather
  66. * than O(N**2) slow, which will swamp those costs in situations where
  67. * long vectors are being built up.
  68. *
  69. * Known issues:
  70. *
  71. * Some methods are private because they haven't yet been tested properly.
  72. *
  73. * Retrieval performance is critical, since this is used at the core
  74. * of the DTM model. (Append performance is almost as important.)
  75. * That's pushing me toward just letting reads from unset indices
  76. * throw exceptions or return stale data; safer behavior would have
  77. * performance costs.
  78. * */
  79. public class SuballocatedIntVector
  80. {
  81. /** Size of blocks to allocate */
  82. protected int m_blocksize;
  83. /** Bitwise addressing (much faster than div/remainder */
  84. protected int m_SHIFT, m_MASK;
  85. /** Number of blocks to (over)allocate by */
  86. protected int m_numblocks=32;
  87. /** Array of arrays of ints */
  88. protected int m_map[][];
  89. /** Number of ints in array */
  90. protected int m_firstFree = 0;
  91. /** "Shortcut" handle to m_map[0]. Surprisingly helpful for short vectors. */
  92. protected int m_map0[];
  93. /**
  94. * Default constructor. Note that the default
  95. * block size is currently 2K, which may be overkill for
  96. * small lists and undershootng for large ones.
  97. */
  98. public SuballocatedIntVector()
  99. {
  100. this(2048);
  101. }
  102. /**
  103. * Construct a IntVector, using the given block size. For
  104. * efficiency, we will round the requested size off to a power of
  105. * two.
  106. *
  107. * @param blocksize Size of block to allocate
  108. * */
  109. public SuballocatedIntVector(int blocksize)
  110. {
  111. //m_blocksize = blocksize;
  112. for(m_SHIFT=0;0!=(blocksize>>>=1);++m_SHIFT)
  113. ;
  114. m_blocksize=1<<m_SHIFT;
  115. m_MASK=m_blocksize-1;
  116. m_map0=new int[m_blocksize];
  117. m_map = new int[m_numblocks][];
  118. m_map[0]=m_map0;
  119. }
  120. /** We never _did_ use the increasesize parameter, so I'm phasing
  121. * this constructor out.
  122. *
  123. * @deprecated use SuballocatedIntVector(int)
  124. * @see SuballocatedIntVector(int)
  125. * */
  126. public SuballocatedIntVector(int blocksize,int increasesize)
  127. {
  128. this(blocksize);
  129. }
  130. /**
  131. * Get the length of the list.
  132. *
  133. * @return length of the list
  134. */
  135. public int size()
  136. {
  137. return m_firstFree;
  138. }
  139. /**
  140. * Set the length of the list. This will only work to truncate the list, and
  141. * even then it has not been heavily tested and may not be trustworthy.
  142. *
  143. * @return length of the list
  144. */
  145. public void setSize(int sz)
  146. {
  147. if(m_firstFree>sz) // Whups; had that backward!
  148. m_firstFree = sz;
  149. }
  150. /**
  151. * Append a int onto the vector.
  152. *
  153. * @param value Int to add to the list
  154. */
  155. public void addElement(int value)
  156. {
  157. if(m_firstFree<m_blocksize)
  158. m_map0[m_firstFree++]=value;
  159. else
  160. {
  161. // Growing the outer array should be rare. We initialize to a
  162. // total of m_blocksize squared elements, which at the default
  163. // size is 4M integers... and we grow by at least that much each
  164. // time. However, attempts to microoptimize for this (assume
  165. // long enough and catch exceptions) yield no noticable
  166. // improvement.
  167. int index=m_firstFree>>>m_SHIFT;
  168. int offset=m_firstFree&m_MASK;
  169. if(index>=m_map.length)
  170. {
  171. int newsize=index+m_numblocks;
  172. int[][] newMap=new int[newsize][];
  173. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  174. m_map=newMap;
  175. }
  176. int[] block=m_map[index];
  177. if(null==block)
  178. block=m_map[index]=new int[m_blocksize];
  179. block[offset]=value;
  180. ++m_firstFree;
  181. }
  182. }
  183. /**
  184. * Append several int values onto the vector.
  185. *
  186. * @param value Int to add to the list
  187. */
  188. private void addElements(int value, int numberOfElements)
  189. {
  190. if(m_firstFree+numberOfElements<m_blocksize)
  191. for (int i = 0; i < numberOfElements; i++)
  192. {
  193. m_map0[m_firstFree++]=value;
  194. }
  195. else
  196. {
  197. int index=m_firstFree>>>m_SHIFT;
  198. int offset=m_firstFree&m_MASK;
  199. m_firstFree+=numberOfElements;
  200. while( numberOfElements>0)
  201. {
  202. if(index>=m_map.length)
  203. {
  204. int newsize=index+m_numblocks;
  205. int[][] newMap=new int[newsize][];
  206. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  207. m_map=newMap;
  208. }
  209. int[] block=m_map[index];
  210. if(null==block)
  211. block=m_map[index]=new int[m_blocksize];
  212. int copied=(m_blocksize-offset < numberOfElements)
  213. ? m_blocksize-offset : numberOfElements;
  214. numberOfElements-=copied;
  215. while(copied-- > 0)
  216. block[offset++]=value;
  217. ++index;offset=0;
  218. }
  219. }
  220. }
  221. /**
  222. * Append several slots onto the vector, but do not set the values.
  223. * Note: "Not Set" means the value is unspecified.
  224. *
  225. * @param value Int to add to the list
  226. */
  227. private void addElements(int numberOfElements)
  228. {
  229. int newlen=m_firstFree+numberOfElements;
  230. if(newlen>m_blocksize)
  231. {
  232. int index=m_firstFree>>>m_SHIFT;
  233. int newindex=(m_firstFree+numberOfElements)>>>m_SHIFT;
  234. for(int i=index+1;i<=newindex;++i)
  235. m_map[i]=new int[m_blocksize];
  236. }
  237. m_firstFree=newlen;
  238. }
  239. /**
  240. * Inserts the specified node in this vector at the specified index.
  241. * Each component in this vector with an index greater or equal to
  242. * the specified index is shifted upward to have an index one greater
  243. * than the value it had previously.
  244. *
  245. * Insertion may be an EXPENSIVE operation!
  246. *
  247. * @param value Int to insert
  248. * @param at Index of where to insert
  249. */
  250. private void insertElementAt(int value, int at)
  251. {
  252. if(at==m_firstFree)
  253. addElement(value);
  254. else if (at>m_firstFree)
  255. {
  256. int index=at>>>m_SHIFT;
  257. if(index>=m_map.length)
  258. {
  259. int newsize=index+m_numblocks;
  260. int[][] newMap=new int[newsize][];
  261. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  262. m_map=newMap;
  263. }
  264. int[] block=m_map[index];
  265. if(null==block)
  266. block=m_map[index]=new int[m_blocksize];
  267. int offset=at&m_MASK;
  268. block[offset]=value;
  269. m_firstFree=offset+1;
  270. }
  271. else
  272. {
  273. int index=at>>>m_SHIFT;
  274. int maxindex=m_firstFree>>>m_SHIFT; // %REVIEW% (m_firstFree+1?)
  275. ++m_firstFree;
  276. int offset=at&m_MASK;
  277. int push;
  278. // ***** Easier to work down from top?
  279. while(index<=maxindex)
  280. {
  281. int copylen=m_blocksize-offset-1;
  282. int[] block=m_map[index];
  283. if(null==block)
  284. {
  285. push=0;
  286. block=m_map[index]=new int[m_blocksize];
  287. }
  288. else
  289. {
  290. push=block[m_blocksize-1];
  291. System.arraycopy(block, offset , block, offset+1, copylen);
  292. }
  293. block[offset]=value;
  294. value=push;
  295. offset=0;
  296. ++index;
  297. }
  298. }
  299. }
  300. /**
  301. * Wipe it out. Currently defined as equivalent to setSize(0).
  302. */
  303. public void removeAllElements()
  304. {
  305. m_firstFree = 0;
  306. }
  307. /**
  308. * Removes the first occurrence of the argument from this vector.
  309. * If the object is found in this vector, each component in the vector
  310. * with an index greater or equal to the object's index is shifted
  311. * downward to have an index one smaller than the value it had
  312. * previously.
  313. *
  314. * @param s Int to remove from array
  315. *
  316. * @return True if the int was removed, false if it was not found
  317. */
  318. private boolean removeElement(int s)
  319. {
  320. int at=indexOf(s,0);
  321. if(at<0)
  322. return false;
  323. removeElementAt(at);
  324. return true;
  325. }
  326. /**
  327. * Deletes the component at the specified index. Each component in
  328. * this vector with an index greater or equal to the specified
  329. * index is shifted downward to have an index one smaller than
  330. * the value it had previously.
  331. *
  332. * @param i index of where to remove and int
  333. */
  334. private void removeElementAt(int at)
  335. {
  336. // No point in removing elements that "don't exist"...
  337. if(at<m_firstFree)
  338. {
  339. int index=at>>>m_SHIFT;
  340. int maxindex=m_firstFree>>>m_SHIFT;
  341. int offset=at&m_MASK;
  342. while(index<=maxindex)
  343. {
  344. int copylen=m_blocksize-offset-1;
  345. int[] block=m_map[index];
  346. if(null==block)
  347. block=m_map[index]=new int[m_blocksize];
  348. else
  349. System.arraycopy(block, offset+1, block, offset, copylen);
  350. if(index<maxindex)
  351. {
  352. int[] next=m_map[index+1];
  353. if(next!=null)
  354. block[m_blocksize-1]=(next!=null) ? next[0] : 0;
  355. }
  356. else
  357. block[m_blocksize-1]=0;
  358. offset=0;
  359. ++index;
  360. }
  361. }
  362. --m_firstFree;
  363. }
  364. /**
  365. * Sets the component at the specified index of this vector to be the
  366. * specified object. The previous component at that position is discarded.
  367. *
  368. * The index must be a value greater than or equal to 0 and less
  369. * than the current size of the vector.
  370. *
  371. * @param node object to set
  372. * @param index Index of where to set the object
  373. */
  374. public void setElementAt(int value, int at)
  375. {
  376. if(at<m_blocksize)
  377. m_map0[at]=value;
  378. else
  379. {
  380. int index=at>>>m_SHIFT;
  381. int offset=at&m_MASK;
  382. if(index>=m_map.length)
  383. {
  384. int newsize=index+m_numblocks;
  385. int[][] newMap=new int[newsize][];
  386. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  387. m_map=newMap;
  388. }
  389. int[] block=m_map[index];
  390. if(null==block)
  391. block=m_map[index]=new int[m_blocksize];
  392. block[offset]=value;
  393. }
  394. if(at>=m_firstFree)
  395. m_firstFree=at+1;
  396. }
  397. /**
  398. * Get the nth element. This is often at the innermost loop of an
  399. * application, so performance is critical.
  400. *
  401. * @param i index of value to get
  402. *
  403. * @return value at given index. If that value wasn't previously set,
  404. * the result is undefined for performance reasons. It may throw an
  405. * exception (see below), may return zero, or (if setSize has previously
  406. * been used) may return stale data.
  407. *
  408. * @throw ArrayIndexOutOfBoundsException if the index was _clearly_
  409. * unreasonable (negative, or past the highest block).
  410. *
  411. * @throw NullPointerException if the index points to a block that could
  412. * have existed (based on the highest index used) but has never had anything
  413. * set into it.
  414. * %REVIEW% Could add a catch to create the block in that case, or return 0.
  415. * Try/Catch is _supposed_ to be nearly free when not thrown to. Do we
  416. * believe that? Should we have a separate safeElementAt?
  417. */
  418. public int elementAt(int i)
  419. {
  420. // This is actually a significant optimization!
  421. if(i<m_blocksize)
  422. return m_map0[i];
  423. return m_map[i>>>m_SHIFT][i&m_MASK];
  424. }
  425. /**
  426. * Tell if the table contains the given node.
  427. *
  428. * @param s object to look for
  429. *
  430. * @return true if the object is in the list
  431. */
  432. private boolean contains(int s)
  433. {
  434. return (indexOf(s,0) >= 0);
  435. }
  436. /**
  437. * Searches for the first occurence of the given argument,
  438. * beginning the search at index, and testing for equality
  439. * using the equals method.
  440. *
  441. * @param elem object to look for
  442. * @param index Index of where to begin search
  443. * @return the index of the first occurrence of the object
  444. * argument in this vector at position index or later in the
  445. * vector; returns -1 if the object is not found.
  446. */
  447. public int indexOf(int elem, int index)
  448. {
  449. if(index>=m_firstFree)
  450. return -1;
  451. int bindex=index>>>m_SHIFT;
  452. int boffset=index&m_MASK;
  453. int maxindex=m_firstFree>>>m_SHIFT;
  454. int[] block;
  455. for(;bindex<maxindex;++bindex)
  456. {
  457. block=m_map[bindex];
  458. if(block!=null)
  459. for(int offset=boffset;offset<m_blocksize;++offset)
  460. if(block[offset]==elem)
  461. return offset+bindex*m_blocksize;
  462. boffset=0; // after first
  463. }
  464. // Last block may need to stop before end
  465. int maxoffset=m_firstFree&m_MASK;
  466. block=m_map[maxindex];
  467. for(int offset=boffset;offset<maxoffset;++offset)
  468. if(block[offset]==elem)
  469. return offset+maxindex*m_blocksize;
  470. return -1;
  471. }
  472. /**
  473. * Searches for the first occurence of the given argument,
  474. * beginning the search at index, and testing for equality
  475. * using the equals method.
  476. *
  477. * @param elem object to look for
  478. * @return the index of the first occurrence of the object
  479. * argument in this vector at position index or later in the
  480. * vector; returns -1 if the object is not found.
  481. */
  482. public int indexOf(int elem)
  483. {
  484. return indexOf(elem,0);
  485. }
  486. /**
  487. * Searches for the first occurence of the given argument,
  488. * beginning the search at index, and testing for equality
  489. * using the equals method.
  490. *
  491. * @param elem Object to look for
  492. * @return the index of the first occurrence of the object
  493. * argument in this vector at position index or later in the
  494. * vector; returns -1 if the object is not found.
  495. */
  496. private int lastIndexOf(int elem)
  497. {
  498. int boffset=m_firstFree&m_MASK;
  499. for(int index=m_firstFree>>>m_SHIFT;
  500. index>=0;
  501. --index)
  502. {
  503. int[] block=m_map[index];
  504. if(block!=null)
  505. for(int offset=boffset; offset>=0; --offset)
  506. if(block[offset]==elem)
  507. return offset+index*m_blocksize;
  508. boffset=0; // after first
  509. }
  510. return -1;
  511. }
  512. }