1. /*
  2. * $Header: /home/cvs/jakarta-commons/primitives/src/java/org/apache/commons/collections/primitives/RandomAccessByteList.java,v 1.3 2003/10/16 20:49:35 scolebourne Exp $
  3. * ====================================================================
  4. * The Apache Software License, Version 1.1
  5. *
  6. * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
  7. * reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. *
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in
  18. * the documentation and/or other materials provided with the
  19. * distribution.
  20. *
  21. * 3. The end-user documentation included with the redistribution, if
  22. * any, must include the following acknowledgement:
  23. * "This product includes software developed by the
  24. * Apache Software Foundation (http://www.apache.org/)."
  25. * Alternately, this acknowledgement may appear in the software itself,
  26. * if and wherever such third-party acknowledgements normally appear.
  27. *
  28. * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  29. * Foundation" must not be used to endorse or promote products derived
  30. * from this software without prior written permission. For written
  31. * permission, please contact apache@apache.org.
  32. *
  33. * 5. Products derived from this software may not be called "Apache"
  34. * nor may "Apache" appear in their names without prior written
  35. * permission of the Apache Software Foundation.
  36. *
  37. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  38. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  39. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  40. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  41. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  42. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  43. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  44. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  45. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  46. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  47. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  48. * SUCH DAMAGE.
  49. * ====================================================================
  50. *
  51. * This software consists of voluntary contributions made by many
  52. * individuals on behalf of the Apache Software Foundation. For more
  53. * information on the Apache Software Foundation, please see
  54. * <http://www.apache.org/>.
  55. *
  56. */
  57. package org.apache.commons.collections.primitives;
  58. import java.util.ConcurrentModificationException;
  59. import java.util.NoSuchElementException;
  60. /**
  61. * Abstract base class for {@link ByteList}s backed
  62. * by random access structures like arrays.
  63. * <p />
  64. * Read-only subclasses must override {@link #get}
  65. * and {@link #size}. Mutable subclasses
  66. * should also override {@link #set}. Variably-sized
  67. * subclasses should also override {@link #add}
  68. * and {@link #removeElementAt}. All other methods
  69. * have at least some base implementation derived from
  70. * these. Subclasses may choose to override these methods
  71. * to provide a more efficient implementation.
  72. *
  73. * @since Commons Primitives 1.0
  74. * @version $Revision: 1.3 $ $Date: 2003/10/16 20:49:35 $
  75. *
  76. * @author Rodney Waldhoff
  77. */
  78. public abstract class RandomAccessByteList extends AbstractByteCollection implements ByteList {
  79. // constructors
  80. //-------------------------------------------------------------------------
  81. /** Constructs an empty list. */
  82. protected RandomAccessByteList() {
  83. }
  84. // fully abstract methods
  85. //-------------------------------------------------------------------------
  86. public abstract byte get(int index);
  87. public abstract int size();
  88. // unsupported in base
  89. //-------------------------------------------------------------------------
  90. /**
  91. * Unsupported in this implementation.
  92. * @throws UnsupportedOperationException since this method is not supported
  93. */
  94. public byte removeElementAt(int index) {
  95. throw new UnsupportedOperationException();
  96. }
  97. /**
  98. * Unsupported in this implementation.
  99. * @throws UnsupportedOperationException since this method is not supported
  100. */
  101. public byte set(int index, byte element) {
  102. throw new UnsupportedOperationException();
  103. }
  104. /**
  105. * Unsupported in this implementation.
  106. * @throws UnsupportedOperationException since this method is not supported
  107. */
  108. public void add(int index, byte element) {
  109. throw new UnsupportedOperationException();
  110. }
  111. //-------------------------------------------------------------------------
  112. // javadocs here are inherited
  113. public boolean add(byte element) {
  114. add(size(),element);
  115. return true;
  116. }
  117. public boolean addAll(int index, ByteCollection collection) {
  118. boolean modified = false;
  119. for(ByteIterator iter = collection.iterator(); iter.hasNext(); ) {
  120. add(index++,iter.next());
  121. modified = true;
  122. }
  123. return modified;
  124. }
  125. public int indexOf(byte element) {
  126. int i = 0;
  127. for(ByteIterator iter = iterator(); iter.hasNext(); ) {
  128. if(iter.next() == element) {
  129. return i;
  130. } else {
  131. i++;
  132. }
  133. }
  134. return -1;
  135. }
  136. public int lastIndexOf(byte element) {
  137. for(ByteListIterator iter = listIterator(size()); iter.hasPrevious(); ) {
  138. if(iter.previous() == element) {
  139. return iter.nextIndex();
  140. }
  141. }
  142. return -1;
  143. }
  144. public ByteIterator iterator() {
  145. return listIterator();
  146. }
  147. public ByteListIterator listIterator() {
  148. return listIterator(0);
  149. }
  150. public ByteListIterator listIterator(int index) {
  151. return new RandomAccessByteListIterator(this,index);
  152. }
  153. public ByteList subList(int fromIndex, int toIndex) {
  154. return new RandomAccessByteSubList(this,fromIndex,toIndex);
  155. }
  156. public boolean equals(Object that) {
  157. if(this == that) {
  158. return true;
  159. } else if(that instanceof ByteList) {
  160. ByteList thatList = (ByteList)that;
  161. if(size() != thatList.size()) {
  162. return false;
  163. }
  164. for(ByteIterator thatIter = thatList.iterator(), thisIter = iterator(); thisIter.hasNext();) {
  165. if(thisIter.next() != thatIter.next()) {
  166. return false;
  167. }
  168. }
  169. return true;
  170. } else {
  171. return false;
  172. }
  173. }
  174. public int hashCode() {
  175. int hash = 1;
  176. for(ByteIterator iter = iterator(); iter.hasNext(); ) {
  177. hash = 31*hash + ((int)(iter.next()));
  178. }
  179. return hash;
  180. }
  181. public String toString() {
  182. StringBuffer buf = new StringBuffer();
  183. buf.append("[");
  184. for(ByteIterator iter = iterator(); iter.hasNext();) {
  185. buf.append(iter.next());
  186. if(iter.hasNext()) {
  187. buf.append(", ");
  188. }
  189. }
  190. buf.append("]");
  191. return buf.toString();
  192. }
  193. // protected utilities
  194. //-------------------------------------------------------------------------
  195. /** Get my count of structural modifications. */
  196. protected int getModCount() {
  197. return _modCount;
  198. }
  199. /** Increment my count of structural modifications. */
  200. protected void incrModCount() {
  201. _modCount++;
  202. }
  203. // attributes
  204. //-------------------------------------------------------------------------
  205. private int _modCount = 0;
  206. // inner classes
  207. //-------------------------------------------------------------------------
  208. private static class ComodChecker {
  209. ComodChecker(RandomAccessByteList source) {
  210. _source = source;
  211. resyncModCount();
  212. }
  213. protected RandomAccessByteList getList() {
  214. return _source;
  215. }
  216. protected void assertNotComodified() throws ConcurrentModificationException {
  217. if(_expectedModCount != getList().getModCount()) {
  218. throw new ConcurrentModificationException();
  219. }
  220. }
  221. protected void resyncModCount() {
  222. _expectedModCount = getList().getModCount();
  223. }
  224. private RandomAccessByteList _source = null;
  225. private int _expectedModCount = -1;
  226. }
  227. protected static class RandomAccessByteListIterator extends ComodChecker implements ByteListIterator {
  228. RandomAccessByteListIterator(RandomAccessByteList list, int index) {
  229. super(list);
  230. if(index < 0 || index > getList().size()) {
  231. throw new IndexOutOfBoundsException("Index " + index + " not in [0," + getList().size() + ")");
  232. } else {
  233. _nextIndex = index;
  234. resyncModCount();
  235. }
  236. }
  237. public boolean hasNext() {
  238. assertNotComodified();
  239. return _nextIndex < getList().size();
  240. }
  241. public boolean hasPrevious() {
  242. assertNotComodified();
  243. return _nextIndex > 0;
  244. }
  245. public int nextIndex() {
  246. assertNotComodified();
  247. return _nextIndex;
  248. }
  249. public int previousIndex() {
  250. assertNotComodified();
  251. return _nextIndex - 1;
  252. }
  253. public byte next() {
  254. assertNotComodified();
  255. if(!hasNext()) {
  256. throw new NoSuchElementException();
  257. } else {
  258. byte val = getList().get(_nextIndex);
  259. _lastReturnedIndex = _nextIndex;
  260. _nextIndex++;
  261. return val;
  262. }
  263. }
  264. public byte previous() {
  265. assertNotComodified();
  266. if(!hasPrevious()) {
  267. throw new NoSuchElementException();
  268. } else {
  269. byte val = getList().get(_nextIndex-1);
  270. _lastReturnedIndex = _nextIndex-1;
  271. _nextIndex--;
  272. return val;
  273. }
  274. }
  275. public void add(byte value) {
  276. assertNotComodified();
  277. getList().add(_nextIndex,value);
  278. _nextIndex++;
  279. _lastReturnedIndex = -1;
  280. resyncModCount();
  281. }
  282. public void remove() {
  283. assertNotComodified();
  284. if(-1 == _lastReturnedIndex) {
  285. throw new IllegalStateException();
  286. } else {
  287. getList().removeElementAt(_lastReturnedIndex);
  288. _lastReturnedIndex = -1;
  289. _nextIndex--;
  290. resyncModCount();
  291. }
  292. }
  293. public void set(byte value) {
  294. assertNotComodified();
  295. if(-1 == _lastReturnedIndex) {
  296. throw new IllegalStateException();
  297. } else {
  298. getList().set(_lastReturnedIndex,value);
  299. resyncModCount();
  300. }
  301. }
  302. private int _nextIndex = 0;
  303. private int _lastReturnedIndex = -1;
  304. }
  305. protected static class RandomAccessByteSubList extends RandomAccessByteList implements ByteList {
  306. RandomAccessByteSubList(RandomAccessByteList list, int fromIndex, int toIndex) {
  307. if(fromIndex < 0 || toIndex > list.size()) {
  308. throw new IndexOutOfBoundsException();
  309. } else if(fromIndex > toIndex) {
  310. throw new IllegalArgumentException();
  311. } else {
  312. _list = list;
  313. _offset = fromIndex;
  314. _limit = toIndex - fromIndex;
  315. _comod = new ComodChecker(list);
  316. _comod.resyncModCount();
  317. }
  318. }
  319. public byte get(int index) {
  320. checkRange(index);
  321. _comod.assertNotComodified();
  322. return _list.get(toUnderlyingIndex(index));
  323. }
  324. public byte removeElementAt(int index) {
  325. checkRange(index);
  326. _comod.assertNotComodified();
  327. byte val = _list.removeElementAt(toUnderlyingIndex(index));
  328. _limit--;
  329. _comod.resyncModCount();
  330. incrModCount();
  331. return val;
  332. }
  333. public byte set(int index, byte element) {
  334. checkRange(index);
  335. _comod.assertNotComodified();
  336. byte val = _list.set(toUnderlyingIndex(index),element);
  337. incrModCount();
  338. _comod.resyncModCount();
  339. return val;
  340. }
  341. public void add(int index, byte element) {
  342. checkRangeIncludingEndpoint(index);
  343. _comod.assertNotComodified();
  344. _list.add(toUnderlyingIndex(index),element);
  345. _limit++;
  346. _comod.resyncModCount();
  347. incrModCount();
  348. }
  349. public int size() {
  350. _comod.assertNotComodified();
  351. return _limit;
  352. }
  353. private void checkRange(int index) {
  354. if(index < 0 || index >= size()) {
  355. throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + ")");
  356. }
  357. }
  358. private void checkRangeIncludingEndpoint(int index) {
  359. if(index < 0 || index > size()) {
  360. throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + "]");
  361. }
  362. }
  363. private int toUnderlyingIndex(int index) {
  364. return (index + _offset);
  365. }
  366. private int _offset = 0;
  367. private int _limit = 0;
  368. private RandomAccessByteList _list = null;
  369. private ComodChecker _comod = null;
  370. }
  371. }