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 byte. 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. * If an element has not been set (because we skipped it), its value will
  74. * initially be 0. Shortening the vector does not clear old storage; if you
  75. * then skip values and setElementAt a higher index again, you may see old data
  76. * reappear in the truncated-and-restored section. Doing anything else would
  77. * have performance costs.
  78. */
  79. public class SuballocatedByteVector
  80. {
  81. /** Size of blocks to allocate */
  82. protected int m_blocksize;
  83. /** Number of blocks to (over)allocate by */
  84. protected int m_numblocks=32;
  85. /** Array of arrays of bytes */
  86. protected byte m_map[][];
  87. /** Number of bytes in array */
  88. protected int m_firstFree = 0;
  89. /** "Shortcut" handle to m_map[0] */
  90. protected byte m_map0[];
  91. /**
  92. * Default constructor. Note that the default
  93. * block size is very small, for small lists.
  94. */
  95. public SuballocatedByteVector()
  96. {
  97. this(2048);
  98. }
  99. /**
  100. * Construct a ByteVector, using the given block size.
  101. *
  102. * @param blocksize Size of block to allocate
  103. */
  104. public SuballocatedByteVector(int blocksize)
  105. {
  106. m_blocksize = blocksize;
  107. m_map0=new byte[blocksize];
  108. m_map = new byte[m_numblocks][];
  109. m_map[0]=m_map0;
  110. }
  111. /**
  112. * Construct a ByteVector, using the given block size.
  113. *
  114. * @param blocksize Size of block to allocate
  115. */
  116. public SuballocatedByteVector(int blocksize, int increaseSize)
  117. {
  118. // increaseSize not currently used.
  119. this(blocksize);
  120. }
  121. /**
  122. * Get the length of the list.
  123. *
  124. * @return length of the list
  125. */
  126. public int size()
  127. {
  128. return m_firstFree;
  129. }
  130. /**
  131. * Set the length of the list.
  132. *
  133. * @return length of the list
  134. */
  135. private void setSize(int sz)
  136. {
  137. if(m_firstFree<sz)
  138. m_firstFree = sz;
  139. }
  140. /**
  141. * Append a byte onto the vector.
  142. *
  143. * @param value Byte to add to the list
  144. */
  145. public void addElement(byte value)
  146. {
  147. if(m_firstFree<m_blocksize)
  148. m_map0[m_firstFree++]=value;
  149. else
  150. {
  151. int index=m_firstFreem_blocksize;
  152. int offset=m_firstFree%m_blocksize;
  153. ++m_firstFree;
  154. if(index>=m_map.length)
  155. {
  156. int newsize=index+m_numblocks;
  157. byte[][] newMap=new byte[newsize][];
  158. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  159. m_map=newMap;
  160. }
  161. byte[] block=m_map[index];
  162. if(null==block)
  163. block=m_map[index]=new byte[m_blocksize];
  164. block[offset]=value;
  165. }
  166. }
  167. /**
  168. * Append several byte values onto the vector.
  169. *
  170. * @param value Byte to add to the list
  171. */
  172. private void addElements(byte value, int numberOfElements)
  173. {
  174. if(m_firstFree+numberOfElements<m_blocksize)
  175. for (int i = 0; i < numberOfElements; i++)
  176. {
  177. m_map0[m_firstFree++]=value;
  178. }
  179. else
  180. {
  181. int index=m_firstFreem_blocksize;
  182. int offset=m_firstFree%m_blocksize;
  183. m_firstFree+=numberOfElements;
  184. while( numberOfElements>0)
  185. {
  186. if(index>=m_map.length)
  187. {
  188. int newsize=index+m_numblocks;
  189. byte[][] newMap=new byte[newsize][];
  190. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  191. m_map=newMap;
  192. }
  193. byte[] block=m_map[index];
  194. if(null==block)
  195. block=m_map[index]=new byte[m_blocksize];
  196. int copied=(m_blocksize-offset < numberOfElements)
  197. ? m_blocksize-offset : numberOfElements;
  198. numberOfElements-=copied;
  199. while(copied-- > 0)
  200. block[offset++]=value;
  201. ++index;offset=0;
  202. }
  203. }
  204. }
  205. /**
  206. * Append several slots onto the vector, but do not set the values.
  207. * Note: "Not Set" means the value is unspecified.
  208. *
  209. * @param value Byte to add to the list
  210. */
  211. private void addElements(int numberOfElements)
  212. {
  213. int newlen=m_firstFree+numberOfElements;
  214. if(newlen>m_blocksize)
  215. {
  216. int index=m_firstFree%m_blocksize;
  217. int newindex=(m_firstFree+numberOfElements)%m_blocksize;
  218. for(int i=index+1;i<=newindex;++i)
  219. m_map[i]=new byte[m_blocksize];
  220. }
  221. m_firstFree=newlen;
  222. }
  223. /**
  224. * Inserts the specified node in this vector at the specified index.
  225. * Each component in this vector with an index greater or equal to
  226. * the specified index is shifted upward to have an index one greater
  227. * than the value it had previously.
  228. *
  229. * Insertion may be an EXPENSIVE operation!
  230. *
  231. * @param value Byte to insert
  232. * @param at Index of where to insert
  233. */
  234. private void insertElementAt(byte value, int at)
  235. {
  236. if(at==m_firstFree)
  237. addElement(value);
  238. else if (at>m_firstFree)
  239. {
  240. int index=atm_blocksize;
  241. if(index>=m_map.length)
  242. {
  243. int newsize=index+m_numblocks;
  244. byte[][] newMap=new byte[newsize][];
  245. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  246. m_map=newMap;
  247. }
  248. byte[] block=m_map[index];
  249. if(null==block)
  250. block=m_map[index]=new byte[m_blocksize];
  251. int offset=at%m_blocksize;
  252. block[offset]=value;
  253. m_firstFree=offset+1;
  254. }
  255. else
  256. {
  257. int index=atm_blocksize;
  258. int maxindex=m_firstFree+1/m_blocksize;
  259. ++m_firstFree;
  260. int offset=at%m_blocksize;
  261. byte push;
  262. // ***** Easier to work down from top?
  263. while(index<=maxindex)
  264. {
  265. int copylen=m_blocksize-offset-1;
  266. byte[] block=m_map[index];
  267. if(null==block)
  268. {
  269. push=0;
  270. block=m_map[index]=new byte[m_blocksize];
  271. }
  272. else
  273. {
  274. push=block[m_blocksize-1];
  275. System.arraycopy(block, offset , block, offset+1, copylen);
  276. }
  277. block[offset]=value;
  278. value=push;
  279. offset=0;
  280. ++index;
  281. }
  282. }
  283. }
  284. /**
  285. * Wipe it out.
  286. */
  287. public void removeAllElements()
  288. {
  289. m_firstFree = 0;
  290. }
  291. /**
  292. * Removes the first occurrence of the argument from this vector.
  293. * If the object is found in this vector, each component in the vector
  294. * with an index greater or equal to the object's index is shifted
  295. * downward to have an index one smaller than the value it had
  296. * previously.
  297. *
  298. * @param s Byte to remove from array
  299. *
  300. * @return True if the byte was removed, false if it was not found
  301. */
  302. private boolean removeElement(byte s)
  303. {
  304. int at=indexOf(s,0);
  305. if(at<0)
  306. return false;
  307. removeElementAt(at);
  308. return true;
  309. }
  310. /**
  311. * Deletes the component at the specified index. Each component in
  312. * this vector with an index greater or equal to the specified
  313. * index is shifted downward to have an index one smaller than
  314. * the value it had previously.
  315. *
  316. * @param at index of where to remove a byte
  317. */
  318. private void removeElementAt(int at)
  319. {
  320. // No point in removing elements that "don't exist"...
  321. if(at<m_firstFree)
  322. {
  323. int index=atm_blocksize;
  324. int maxindex=m_firstFreem_blocksize;
  325. int offset=at%m_blocksize;
  326. while(index<=maxindex)
  327. {
  328. int copylen=m_blocksize-offset-1;
  329. byte[] block=m_map[index];
  330. if(null==block)
  331. block=m_map[index]=new byte[m_blocksize];
  332. else
  333. System.arraycopy(block, offset+1, block, offset, copylen);
  334. if(index<maxindex)
  335. {
  336. byte[] next=m_map[index+1];
  337. if(next!=null)
  338. block[m_blocksize-1]=(next!=null) ? next[0] : 0;
  339. }
  340. else
  341. block[m_blocksize-1]=0;
  342. offset=0;
  343. ++index;
  344. }
  345. }
  346. --m_firstFree;
  347. }
  348. /**
  349. * Sets the component at the specified index of this vector to be the
  350. * specified object. The previous component at that position is discarded.
  351. *
  352. * The index must be a value greater than or equal to 0 and less
  353. * than the current size of the vector.
  354. *
  355. * @param node object to set
  356. * @param index Index of where to set the object
  357. */
  358. public void setElementAt(byte value, int at)
  359. {
  360. if(at<m_blocksize)
  361. {
  362. m_map0[at]=value;
  363. return;
  364. }
  365. int index=atm_blocksize;
  366. int offset=at%m_blocksize;
  367. if(index>=m_map.length)
  368. {
  369. int newsize=index+m_numblocks;
  370. byte[][] newMap=new byte[newsize][];
  371. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  372. m_map=newMap;
  373. }
  374. byte[] block=m_map[index];
  375. if(null==block)
  376. block=m_map[index]=new byte[m_blocksize];
  377. block[offset]=value;
  378. if(at>=m_firstFree)
  379. m_firstFree=at+1;
  380. }
  381. /**
  382. * Get the nth element. This is often at the innermost loop of an
  383. * application, so performance is critical.
  384. *
  385. * @param i index of value to get
  386. *
  387. * @return value at given index. If that value wasn't previously set,
  388. * the result is undefined for performance reasons. It may throw an
  389. * exception (see below), may return zero, or (if setSize has previously
  390. * been used) may return stale data.
  391. *
  392. * @throw ArrayIndexOutOfBoundsException if the index was _clearly_
  393. * unreasonable (negative, or past the highest block).
  394. *
  395. * @throw NullPointerException if the index points to a block that could
  396. * have existed (based on the highest index used) but has never had anything
  397. * set into it.
  398. * %REVIEW% Could add a catch to create the block in that case, or return 0.
  399. * Try/Catch is _supposed_ to be nearly free when not thrown to. Do we
  400. * believe that? Should we have a separate safeElementAt?
  401. */
  402. public byte elementAt(int i)
  403. {
  404. // %OPT% Does this really buy us anything? Test versus division for small,
  405. // test _plus_ division for big docs.
  406. if(i<m_blocksize)
  407. return m_map0[i];
  408. return m_map[im_blocksize][i%m_blocksize];
  409. }
  410. /**
  411. * Tell if the table contains the given node.
  412. *
  413. * @param s object to look for
  414. *
  415. * @return true if the object is in the list
  416. */
  417. private boolean contains(byte s)
  418. {
  419. return (indexOf(s,0) >= 0);
  420. }
  421. /**
  422. * Searches for the first occurence of the given argument,
  423. * beginning the search at index, and testing for equality
  424. * using the equals method.
  425. *
  426. * @param elem object to look for
  427. * @param index Index of where to begin search
  428. * @return the index of the first occurrence of the object
  429. * argument in this vector at position index or later in the
  430. * vector; returns -1 if the object is not found.
  431. */
  432. public int indexOf(byte elem, int index)
  433. {
  434. if(index>=m_firstFree)
  435. return -1;
  436. int bindex=indexm_blocksize;
  437. int boffset=index%m_blocksize;
  438. int maxindex=m_firstFreem_blocksize;
  439. byte[] block;
  440. for(;bindex<maxindex;++bindex)
  441. {
  442. block=m_map[bindex];
  443. if(block!=null)
  444. for(int offset=boffset;offset<m_blocksize;++offset)
  445. if(block[offset]==elem)
  446. return offset+bindex*m_blocksize;
  447. boffset=0; // after first
  448. }
  449. // Last block may need to stop before end
  450. int maxoffset=m_firstFree%m_blocksize;
  451. block=m_map[maxindex];
  452. for(int offset=boffset;offset<maxoffset;++offset)
  453. if(block[offset]==elem)
  454. return offset+maxindex*m_blocksize;
  455. return -1;
  456. }
  457. /**
  458. * Searches for the first occurence of the given argument,
  459. * beginning the search at index, and testing for equality
  460. * using the equals method.
  461. *
  462. * @param elem object to look for
  463. * @return the index of the first occurrence of the object
  464. * argument in this vector at position index or later in the
  465. * vector; returns -1 if the object is not found.
  466. */
  467. public int indexOf(byte elem)
  468. {
  469. return indexOf(elem,0);
  470. }
  471. /**
  472. * Searches for the first occurence of the given argument,
  473. * beginning the search at index, and testing for equality
  474. * using the equals method.
  475. *
  476. * @param elem Object to look for
  477. * @return the index of the first occurrence of the object
  478. * argument in this vector at position index or later in the
  479. * vector; returns -1 if the object is not found.
  480. */
  481. private int lastIndexOf(byte elem)
  482. {
  483. int boffset=m_firstFree%m_blocksize;
  484. for(int index=m_firstFreem_blocksize;
  485. index>=0;
  486. --index)
  487. {
  488. byte[] block=m_map[index];
  489. if(block!=null)
  490. for(int offset=boffset; offset>=0; --offset)
  491. if(block[offset]==elem)
  492. return offset+index*m_blocksize;
  493. boffset=0; // after first
  494. }
  495. return -1;
  496. }
  497. }