1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.millscript.commons.util.list;
22
23 import java.io.Serializable;
24
25 import org.millscript.commons.alert.alerts.Fault;
26 import org.millscript.commons.util.IList;
27 import org.millscript.commons.util.ListIterator;
28 import org.millscript.commons.util.alerts.ListIndexOutOfBoundsAlert;
29 import org.millscript.commons.util.iterator.AbstractListIterator;
30
31 /**
32 * This class provides an immutable <code>List</code> implementation which is
33 * backed by a String(i.e. a list of characters).
34 */
35 public class IStringList extends AbstractIList< Character > implements Cloneable, Serializable {
36
37 /**
38 * This is the ID from the release 0.1.0 for future compatibility.
39 */
40 private static final long serialVersionUID = 1025372624400670L;
41
42 /**
43 * This class provides a map interator implementation which iterates over
44 * the characters in a string and their position in the string.
45 */
46 public static class StringListIterator extends AbstractListIterator< Character > {
47
48 /**
49 * The backing string for this iterator.
50 */
51 private final String string;
52
53 /**
54 * Constructs a new string map iterator to iterate over the characters
55 * in the specified string and their position in the string.
56 *
57 * @param obj the string whose characters to iterate over
58 */
59 public StringListIterator( final String s ) {
60 this.string = s;
61 }
62
63 /**
64 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
65 */
66 @Override
67 protected Character getValue() {
68 return new Character( this.string.charAt( super.position - 1 ) );
69 }
70
71 /**
72 * @see org.millscript.commons.util.MapIterator#hasNext()
73 */
74 public boolean hasNext() {
75 return super.position < this.string.length();
76 }
77
78 /**
79 * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
80 */
81 @Override
82 protected boolean outOfBounds() {
83 return super.position == 0 || super.position > this.string.length();
84 }
85
86 }
87
88 /**
89 * The backing store string.
90 */
91 private final String store;
92
93 /**
94 * Constructs a new empty immutable string list.
95 */
96 public IStringList() {
97 this.store = "";
98 }
99
100 /**
101 * Constructs a new immutable string list with the specified backing
102 * string.
103 *
104 * @param objects the backing string
105 */
106 public IStringList( final String string ) {
107 this.store = string;
108 }
109
110 /**
111 * Constructs a new immutable string list with a copy of the specified
112 * backing string, starting and ending at the specified indices.
113 *
114 * @param objects the backing string to copy
115 * @param start the index of the first element in the slice
116 * @param end the index of the last element in the slice. If end <
117 * start, the new list will be empty
118 */
119 public IStringList( final String string, final int start, final int end ) {
120 if ( start > end ) {
121 this.store = "";
122 } else if ( start < 1 || start > string.length() ) {
123 throw new ListIndexOutOfBoundsAlert(
124 "First index in slice must be between 1 and the length of the string"
125 ).culprit(
126 "index",
127 start
128 ).decorate( string ).mishap();
129 } else if ( end > string.length() ) {
130 throw new ListIndexOutOfBoundsAlert(
131 "Last index in slice must not be greater than the length of the string"
132 ).culprit(
133 "index",
134 end
135 ).decorate( string ).mishap();
136 } else if ( start == 1 && end == string.length() ){
137
138
139 this.store = string;
140 } else {
141 try {
142 final StringBuffer temp = new StringBuffer( end - start + 1 );
143 temp.append( string.substring( start - 1, end ) );
144 this.store = temp.toString();
145 } catch ( Exception ex ) {
146 throw new Fault(
147 "Failed to take a copy of the specified string slice"
148 ).setParentThrowable( ex ).mishap();
149 }
150 }
151 }
152
153 /**
154 * @see java.lang.Object#clone()
155 */
156 @Override
157 public Object clone() throws CloneNotSupportedException {
158
159 return super.clone();
160 }
161
162 /**
163 * @see org.millscript.commons.util.list.AbstractIList#doGet(int)
164 */
165 @Override
166 protected Character doGet( final int pos ) {
167 return new Character( this.store.charAt( pos - 1 ) );
168 }
169
170 /**
171 * @see org.millscript.commons.util.list.AbstractIList#doSlice(int, int, boolean)
172 */
173 @Override
174 protected IList< Character > doSlice( final int first, final int last, final boolean share ) {
175 if ( share ) {
176 return new IStringList(
177 this.store.substring( first - 1, last )
178 );
179 } else {
180
181 return new IStringList( this.store, first, last );
182 }
183 }
184
185 /**
186 * @see org.millscript.commons.util.IList#indexOf(java.lang.Object)
187 */
188 public int indexOf( final Character value ) {
189 if ( value != null ) {
190 return this.store.indexOf( value.charValue() ) + 1;
191 }
192 return 0;
193 }
194
195 /**
196 * @see org.millscript.commons.util.IMap#iterator(boolean)
197 */
198 public ListIterator< Character > iterator( final boolean share ) {
199
200
201 return new StringListIterator( this.store );
202 }
203
204 /**
205 * @see org.millscript.commons.util.IMap#size()
206 */
207 public int size() {
208 return this.store.length();
209 }
210
211 }