1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: SuballocatedByteVector.java,v 1.6 2004/02/17 04:21:14 minchau Exp $
  18. */
  19. package com.sun.org.apache.xml.internal.utils;
  20. /**
  21. * A very simple table that stores a list of byte. Very similar API to our
  22. * IntVector class (same API); different internal storage.
  23. *
  24. * This version uses an array-of-arrays solution. Read/write access is thus
  25. * a bit slower than the simple IntVector, and basic storage is a trifle
  26. * higher due to the top-level array -- but appending is O(1) fast rather
  27. * than O(N**2) slow, which will swamp those costs in situations where
  28. * long vectors are being built up.
  29. *
  30. * Known issues:
  31. *
  32. * Some methods are private because they haven't yet been tested properly.
  33. *
  34. * If an element has not been set (because we skipped it), its value will
  35. * initially be 0. Shortening the vector does not clear old storage; if you
  36. * then skip values and setElementAt a higher index again, you may see old data
  37. * reappear in the truncated-and-restored section. Doing anything else would
  38. * have performance costs.
  39. * @xsl.usage internal
  40. */
  41. public class SuballocatedByteVector
  42. {
  43. /** Size of blocks to allocate */
  44. protected int m_blocksize;
  45. /** Number of blocks to (over)allocate by */
  46. protected int m_numblocks=32;
  47. /** Array of arrays of bytes */
  48. protected byte m_map[][];
  49. /** Number of bytes in array */
  50. protected int m_firstFree = 0;
  51. /** "Shortcut" handle to m_map[0] */
  52. protected byte m_map0[];
  53. /**
  54. * Default constructor. Note that the default
  55. * block size is very small, for small lists.
  56. */
  57. public SuballocatedByteVector()
  58. {
  59. this(2048);
  60. }
  61. /**
  62. * Construct a ByteVector, using the given block size.
  63. *
  64. * @param blocksize Size of block to allocate
  65. */
  66. public SuballocatedByteVector(int blocksize)
  67. {
  68. m_blocksize = blocksize;
  69. m_map0=new byte[blocksize];
  70. m_map = new byte[m_numblocks][];
  71. m_map[0]=m_map0;
  72. }
  73. /**
  74. * Construct a ByteVector, using the given block size.
  75. *
  76. * @param blocksize Size of block to allocate
  77. */
  78. public SuballocatedByteVector(int blocksize, int increaseSize)
  79. {
  80. // increaseSize not currently used.
  81. this(blocksize);
  82. }
  83. /**
  84. * Get the length of the list.
  85. *
  86. * @return length of the list
  87. */
  88. public int size()
  89. {
  90. return m_firstFree;
  91. }
  92. /**
  93. * Set the length of the list.
  94. *
  95. * @return length of the list
  96. */
  97. private void setSize(int sz)
  98. {
  99. if(m_firstFree<sz)
  100. m_firstFree = sz;
  101. }
  102. /**
  103. * Append a byte onto the vector.
  104. *
  105. * @param value Byte to add to the list
  106. */
  107. public void addElement(byte value)
  108. {
  109. if(m_firstFree<m_blocksize)
  110. m_map0[m_firstFree++]=value;
  111. else
  112. {
  113. int index=m_firstFreem_blocksize;
  114. int offset=m_firstFree%m_blocksize;
  115. ++m_firstFree;
  116. if(index>=m_map.length)
  117. {
  118. int newsize=index+m_numblocks;
  119. byte[][] newMap=new byte[newsize][];
  120. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  121. m_map=newMap;
  122. }
  123. byte[] block=m_map[index];
  124. if(null==block)
  125. block=m_map[index]=new byte[m_blocksize];
  126. block[offset]=value;
  127. }
  128. }
  129. /**
  130. * Append several byte values onto the vector.
  131. *
  132. * @param value Byte to add to the list
  133. */
  134. private void addElements(byte value, int numberOfElements)
  135. {
  136. if(m_firstFree+numberOfElements<m_blocksize)
  137. for (int i = 0; i < numberOfElements; i++)
  138. {
  139. m_map0[m_firstFree++]=value;
  140. }
  141. else
  142. {
  143. int index=m_firstFreem_blocksize;
  144. int offset=m_firstFree%m_blocksize;
  145. m_firstFree+=numberOfElements;
  146. while( numberOfElements>0)
  147. {
  148. if(index>=m_map.length)
  149. {
  150. int newsize=index+m_numblocks;
  151. byte[][] newMap=new byte[newsize][];
  152. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  153. m_map=newMap;
  154. }
  155. byte[] block=m_map[index];
  156. if(null==block)
  157. block=m_map[index]=new byte[m_blocksize];
  158. int copied=(m_blocksize-offset < numberOfElements)
  159. ? m_blocksize-offset : numberOfElements;
  160. numberOfElements-=copied;
  161. while(copied-- > 0)
  162. block[offset++]=value;
  163. ++index;offset=0;
  164. }
  165. }
  166. }
  167. /**
  168. * Append several slots onto the vector, but do not set the values.
  169. * Note: "Not Set" means the value is unspecified.
  170. *
  171. * @param value Byte to add to the list
  172. */
  173. private void addElements(int numberOfElements)
  174. {
  175. int newlen=m_firstFree+numberOfElements;
  176. if(newlen>m_blocksize)
  177. {
  178. int index=m_firstFree%m_blocksize;
  179. int newindex=(m_firstFree+numberOfElements)%m_blocksize;
  180. for(int i=index+1;i<=newindex;++i)
  181. m_map[i]=new byte[m_blocksize];
  182. }
  183. m_firstFree=newlen;
  184. }
  185. /**
  186. * Inserts the specified node in this vector at the specified index.
  187. * Each component in this vector with an index greater or equal to
  188. * the specified index is shifted upward to have an index one greater
  189. * than the value it had previously.
  190. *
  191. * Insertion may be an EXPENSIVE operation!
  192. *
  193. * @param value Byte to insert
  194. * @param at Index of where to insert
  195. */
  196. private void insertElementAt(byte value, int at)
  197. {
  198. if(at==m_firstFree)
  199. addElement(value);
  200. else if (at>m_firstFree)
  201. {
  202. int index=atm_blocksize;
  203. if(index>=m_map.length)
  204. {
  205. int newsize=index+m_numblocks;
  206. byte[][] newMap=new byte[newsize][];
  207. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  208. m_map=newMap;
  209. }
  210. byte[] block=m_map[index];
  211. if(null==block)
  212. block=m_map[index]=new byte[m_blocksize];
  213. int offset=at%m_blocksize;
  214. block[offset]=value;
  215. m_firstFree=offset+1;
  216. }
  217. else
  218. {
  219. int index=atm_blocksize;
  220. int maxindex=m_firstFree+1/m_blocksize;
  221. ++m_firstFree;
  222. int offset=at%m_blocksize;
  223. byte push;
  224. // ***** Easier to work down from top?
  225. while(index<=maxindex)
  226. {
  227. int copylen=m_blocksize-offset-1;
  228. byte[] block=m_map[index];
  229. if(null==block)
  230. {
  231. push=0;
  232. block=m_map[index]=new byte[m_blocksize];
  233. }
  234. else
  235. {
  236. push=block[m_blocksize-1];
  237. System.arraycopy(block, offset , block, offset+1, copylen);
  238. }
  239. block[offset]=value;
  240. value=push;
  241. offset=0;
  242. ++index;
  243. }
  244. }
  245. }
  246. /**
  247. * Wipe it out.
  248. */
  249. public void removeAllElements()
  250. {
  251. m_firstFree = 0;
  252. }
  253. /**
  254. * Removes the first occurrence of the argument from this vector.
  255. * If the object is found in this vector, each component in the vector
  256. * with an index greater or equal to the object's index is shifted
  257. * downward to have an index one smaller than the value it had
  258. * previously.
  259. *
  260. * @param s Byte to remove from array
  261. *
  262. * @return True if the byte was removed, false if it was not found
  263. */
  264. private boolean removeElement(byte s)
  265. {
  266. int at=indexOf(s,0);
  267. if(at<0)
  268. return false;
  269. removeElementAt(at);
  270. return true;
  271. }
  272. /**
  273. * Deletes the component at the specified index. Each component in
  274. * this vector with an index greater or equal to the specified
  275. * index is shifted downward to have an index one smaller than
  276. * the value it had previously.
  277. *
  278. * @param at index of where to remove a byte
  279. */
  280. private void removeElementAt(int at)
  281. {
  282. // No point in removing elements that "don't exist"...
  283. if(at<m_firstFree)
  284. {
  285. int index=atm_blocksize;
  286. int maxindex=m_firstFreem_blocksize;
  287. int offset=at%m_blocksize;
  288. while(index<=maxindex)
  289. {
  290. int copylen=m_blocksize-offset-1;
  291. byte[] block=m_map[index];
  292. if(null==block)
  293. block=m_map[index]=new byte[m_blocksize];
  294. else
  295. System.arraycopy(block, offset+1, block, offset, copylen);
  296. if(index<maxindex)
  297. {
  298. byte[] next=m_map[index+1];
  299. if(next!=null)
  300. block[m_blocksize-1]=(next!=null) ? next[0] : 0;
  301. }
  302. else
  303. block[m_blocksize-1]=0;
  304. offset=0;
  305. ++index;
  306. }
  307. }
  308. --m_firstFree;
  309. }
  310. /**
  311. * Sets the component at the specified index of this vector to be the
  312. * specified object. The previous component at that position is discarded.
  313. *
  314. * The index must be a value greater than or equal to 0 and less
  315. * than the current size of the vector.
  316. *
  317. * @param node object to set
  318. * @param index Index of where to set the object
  319. */
  320. public void setElementAt(byte value, int at)
  321. {
  322. if(at<m_blocksize)
  323. {
  324. m_map0[at]=value;
  325. return;
  326. }
  327. int index=atm_blocksize;
  328. int offset=at%m_blocksize;
  329. if(index>=m_map.length)
  330. {
  331. int newsize=index+m_numblocks;
  332. byte[][] newMap=new byte[newsize][];
  333. System.arraycopy(m_map, 0, newMap, 0, m_map.length);
  334. m_map=newMap;
  335. }
  336. byte[] block=m_map[index];
  337. if(null==block)
  338. block=m_map[index]=new byte[m_blocksize];
  339. block[offset]=value;
  340. if(at>=m_firstFree)
  341. m_firstFree=at+1;
  342. }
  343. /**
  344. * Get the nth element. This is often at the innermost loop of an
  345. * application, so performance is critical.
  346. *
  347. * @param i index of value to get
  348. *
  349. * @return value at given index. If that value wasn't previously set,
  350. * the result is undefined for performance reasons. It may throw an
  351. * exception (see below), may return zero, or (if setSize has previously
  352. * been used) may return stale data.
  353. *
  354. * @throw ArrayIndexOutOfBoundsException if the index was _clearly_
  355. * unreasonable (negative, or past the highest block).
  356. *
  357. * @throw NullPointerException if the index points to a block that could
  358. * have existed (based on the highest index used) but has never had anything
  359. * set into it.
  360. * %REVIEW% Could add a catch to create the block in that case, or return 0.
  361. * Try/Catch is _supposed_ to be nearly free when not thrown to. Do we
  362. * believe that? Should we have a separate safeElementAt?
  363. */
  364. public byte elementAt(int i)
  365. {
  366. // %OPT% Does this really buy us anything? Test versus division for small,
  367. // test _plus_ division for big docs.
  368. if(i<m_blocksize)
  369. return m_map0[i];
  370. return m_map[im_blocksize][i%m_blocksize];
  371. }
  372. /**
  373. * Tell if the table contains the given node.
  374. *
  375. * @param s object to look for
  376. *
  377. * @return true if the object is in the list
  378. */
  379. private boolean contains(byte s)
  380. {
  381. return (indexOf(s,0) >= 0);
  382. }
  383. /**
  384. * Searches for the first occurence of the given argument,
  385. * beginning the search at index, and testing for equality
  386. * using the equals method.
  387. *
  388. * @param elem object to look for
  389. * @param index Index of where to begin search
  390. * @return the index of the first occurrence of the object
  391. * argument in this vector at position index or later in the
  392. * vector; returns -1 if the object is not found.
  393. */
  394. public int indexOf(byte elem, int index)
  395. {
  396. if(index>=m_firstFree)
  397. return -1;
  398. int bindex=indexm_blocksize;
  399. int boffset=index%m_blocksize;
  400. int maxindex=m_firstFreem_blocksize;
  401. byte[] block;
  402. for(;bindex<maxindex;++bindex)
  403. {
  404. block=m_map[bindex];
  405. if(block!=null)
  406. for(int offset=boffset;offset<m_blocksize;++offset)
  407. if(block[offset]==elem)
  408. return offset+bindex*m_blocksize;
  409. boffset=0; // after first
  410. }
  411. // Last block may need to stop before end
  412. int maxoffset=m_firstFree%m_blocksize;
  413. block=m_map[maxindex];
  414. for(int offset=boffset;offset<maxoffset;++offset)
  415. if(block[offset]==elem)
  416. return offset+maxindex*m_blocksize;
  417. return -1;
  418. }
  419. /**
  420. * Searches for the first occurence of the given argument,
  421. * beginning the search at index, and testing for equality
  422. * using the equals method.
  423. *
  424. * @param elem object to look for
  425. * @return the index of the first occurrence of the object
  426. * argument in this vector at position index or later in the
  427. * vector; returns -1 if the object is not found.
  428. */
  429. public int indexOf(byte elem)
  430. {
  431. return indexOf(elem,0);
  432. }
  433. /**
  434. * Searches for the first occurence of the given argument,
  435. * beginning the search at index, and testing for equality
  436. * using the equals method.
  437. *
  438. * @param elem Object to look for
  439. * @return the index of the first occurrence of the object
  440. * argument in this vector at position index or later in the
  441. * vector; returns -1 if the object is not found.
  442. */
  443. private int lastIndexOf(byte elem)
  444. {
  445. int boffset=m_firstFree%m_blocksize;
  446. for(int index=m_firstFreem_blocksize;
  447. index>=0;
  448. --index)
  449. {
  450. byte[] block=m_map[index];
  451. if(block!=null)
  452. for(int offset=boffset; offset>=0; --offset)
  453. if(block[offset]==elem)
  454. return offset+index*m_blocksize;
  455. boffset=0; // after first
  456. }
  457. return -1;
  458. }
  459. }