1. /*
  2. * $Header: /home/cvs/jakarta-commons/primitives/src/java/org/apache/commons/collections/primitives/RandomAccessCharList.java,v 1.3 2003/10/16 20:49:36 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 CharList}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:36 $
  75. *
  76. * @author Rodney Waldhoff
  77. */
  78. public abstract class RandomAccessCharList extends AbstractCharCollection implements CharList {
  79. // constructors
  80. //-------------------------------------------------------------------------
  81. /** Constructs an empty list. */
  82. protected RandomAccessCharList() {
  83. }
  84. // fully abstract methods
  85. //-------------------------------------------------------------------------
  86. public abstract char 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 char 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 char set(int index, char 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, char element) {
  109. throw new UnsupportedOperationException();
  110. }
  111. //-------------------------------------------------------------------------
  112. // javadocs here are inherited
  113. public boolean add(char element) {
  114. add(size(),element);
  115. return true;
  116. }
  117. public boolean addAll(int index, CharCollection collection) {
  118. boolean modified = false;
  119. for(CharIterator iter = collection.iterator(); iter.hasNext(); ) {
  120. add(index++,iter.next());
  121. modified = true;
  122. }
  123. return modified;
  124. }
  125. public int indexOf(char element) {
  126. int i = 0;
  127. for(CharIterator 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(char element) {
  137. for(CharListIterator iter = listIterator(size()); iter.hasPrevious(); ) {
  138. if(iter.previous() == element) {
  139. return iter.nextIndex();
  140. }
  141. }
  142. return -1;
  143. }
  144. public CharIterator iterator() {
  145. return listIterator();
  146. }
  147. public CharListIterator listIterator() {
  148. return listIterator(0);
  149. }
  150. public CharListIterator listIterator(int index) {
  151. return new RandomAccessCharListIterator(this,index);
  152. }
  153. public CharList subList(int fromIndex, int toIndex) {
  154. return new RandomAccessCharSubList(this,fromIndex,toIndex);
  155. }
  156. public boolean equals(Object that) {
  157. if(this == that) {
  158. return true;
  159. } else if(that instanceof CharList) {
  160. CharList thatList = (CharList)that;
  161. if(size() != thatList.size()) {
  162. return false;
  163. }
  164. for(CharIterator 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(CharIterator iter = iterator(); iter.hasNext(); ) {
  177. hash = 31*hash + ((int)(iter.next()));
  178. }
  179. return hash;
  180. }
  181. public String toString() {
  182. // could cache these like StringBuffer does
  183. return new String(toArray());
  184. }
  185. // protected utilities
  186. //-------------------------------------------------------------------------
  187. /** Get my count of structural modifications. */
  188. protected int getModCount() {
  189. return _modCount;
  190. }
  191. /** Increment my count of structural modifications. */
  192. protected void incrModCount() {
  193. _modCount++;
  194. }
  195. // attributes
  196. //-------------------------------------------------------------------------
  197. private int _modCount = 0;
  198. // inner classes
  199. //-------------------------------------------------------------------------
  200. private static class ComodChecker {
  201. ComodChecker(RandomAccessCharList source) {
  202. _source = source;
  203. resyncModCount();
  204. }
  205. protected RandomAccessCharList getList() {
  206. return _source;
  207. }
  208. protected void assertNotComodified() throws ConcurrentModificationException {
  209. if(_expectedModCount != getList().getModCount()) {
  210. throw new ConcurrentModificationException();
  211. }
  212. }
  213. protected void resyncModCount() {
  214. _expectedModCount = getList().getModCount();
  215. }
  216. private RandomAccessCharList _source = null;
  217. private int _expectedModCount = -1;
  218. }
  219. protected static class RandomAccessCharListIterator extends ComodChecker implements CharListIterator {
  220. RandomAccessCharListIterator(RandomAccessCharList list, int index) {
  221. super(list);
  222. if(index < 0 || index > getList().size()) {
  223. throw new IndexOutOfBoundsException("Index " + index + " not in [0," + getList().size() + ")");
  224. } else {
  225. _nextIndex = index;
  226. resyncModCount();
  227. }
  228. }
  229. public boolean hasNext() {
  230. assertNotComodified();
  231. return _nextIndex < getList().size();
  232. }
  233. public boolean hasPrevious() {
  234. assertNotComodified();
  235. return _nextIndex > 0;
  236. }
  237. public int nextIndex() {
  238. assertNotComodified();
  239. return _nextIndex;
  240. }
  241. public int previousIndex() {
  242. assertNotComodified();
  243. return _nextIndex - 1;
  244. }
  245. public char next() {
  246. assertNotComodified();
  247. if(!hasNext()) {
  248. throw new NoSuchElementException();
  249. } else {
  250. char val = getList().get(_nextIndex);
  251. _lastReturnedIndex = _nextIndex;
  252. _nextIndex++;
  253. return val;
  254. }
  255. }
  256. public char previous() {
  257. assertNotComodified();
  258. if(!hasPrevious()) {
  259. throw new NoSuchElementException();
  260. } else {
  261. char val = getList().get(_nextIndex-1);
  262. _lastReturnedIndex = _nextIndex-1;
  263. _nextIndex--;
  264. return val;
  265. }
  266. }
  267. public void add(char value) {
  268. assertNotComodified();
  269. getList().add(_nextIndex,value);
  270. _nextIndex++;
  271. _lastReturnedIndex = -1;
  272. resyncModCount();
  273. }
  274. public void remove() {
  275. assertNotComodified();
  276. if(-1 == _lastReturnedIndex) {
  277. throw new IllegalStateException();
  278. } else {
  279. getList().removeElementAt(_lastReturnedIndex);
  280. _lastReturnedIndex = -1;
  281. _nextIndex--;
  282. resyncModCount();
  283. }
  284. }
  285. public void set(char value) {
  286. assertNotComodified();
  287. if(-1 == _lastReturnedIndex) {
  288. throw new IllegalStateException();
  289. } else {
  290. getList().set(_lastReturnedIndex,value);
  291. resyncModCount();
  292. }
  293. }
  294. private int _nextIndex = 0;
  295. private int _lastReturnedIndex = -1;
  296. }
  297. protected static class RandomAccessCharSubList extends RandomAccessCharList implements CharList {
  298. RandomAccessCharSubList(RandomAccessCharList list, int fromIndex, int toIndex) {
  299. if(fromIndex < 0 || toIndex > list.size()) {
  300. throw new IndexOutOfBoundsException();
  301. } else if(fromIndex > toIndex) {
  302. throw new IllegalArgumentException();
  303. } else {
  304. _list = list;
  305. _offset = fromIndex;
  306. _limit = toIndex - fromIndex;
  307. _comod = new ComodChecker(list);
  308. _comod.resyncModCount();
  309. }
  310. }
  311. public char get(int index) {
  312. checkRange(index);
  313. _comod.assertNotComodified();
  314. return _list.get(toUnderlyingIndex(index));
  315. }
  316. public char removeElementAt(int index) {
  317. checkRange(index);
  318. _comod.assertNotComodified();
  319. char val = _list.removeElementAt(toUnderlyingIndex(index));
  320. _limit--;
  321. _comod.resyncModCount();
  322. incrModCount();
  323. return val;
  324. }
  325. public char set(int index, char element) {
  326. checkRange(index);
  327. _comod.assertNotComodified();
  328. char val = _list.set(toUnderlyingIndex(index),element);
  329. incrModCount();
  330. _comod.resyncModCount();
  331. return val;
  332. }
  333. public void add(int index, char element) {
  334. checkRangeIncludingEndpoint(index);
  335. _comod.assertNotComodified();
  336. _list.add(toUnderlyingIndex(index),element);
  337. _limit++;
  338. _comod.resyncModCount();
  339. incrModCount();
  340. }
  341. public int size() {
  342. _comod.assertNotComodified();
  343. return _limit;
  344. }
  345. private void checkRange(int index) {
  346. if(index < 0 || index >= size()) {
  347. throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + ")");
  348. }
  349. }
  350. private void checkRangeIncludingEndpoint(int index) {
  351. if(index < 0 || index > size()) {
  352. throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + "]");
  353. }
  354. }
  355. private int toUnderlyingIndex(int index) {
  356. return (index + _offset);
  357. }
  358. private int _offset = 0;
  359. private int _limit = 0;
  360. private RandomAccessCharList _list = null;
  361. private ComodChecker _comod = null;
  362. }
  363. }