001: package org.jibx.binding.util;
002:
003: /**
004: * Wrapper for arrays of ordered strings. This verifies the arrays and supports
005: * efficient lookups.
006: *
007: * @author Dennis M. Sosnoski
008: */
009: public class StringArray {
010: /** Ordered array of strings. */
011: private final String[] m_list;
012:
013: /**
014: * Constructor from array of values. This checks the array values to make
015: * sure they're ordered and unique, and if they're not throws an exception.
016: * Once the array has been passed to this constructor it must not be
017: * modified by outside code.
018: *
019: * @param list array of values
020: */
021: public StringArray(String[] list) {
022: validateArray(list);
023: m_list = list;
024: }
025:
026: /**
027: * Constructor from array of values to be added to base instance. This
028: * merges the array values, making sure they're ordered and unique, and if
029: * they're not throws an exception.
030: *
031: * @param list array of values
032: * @param base base instance
033: */
034: public StringArray(String[] list, StringArray base) {
035: validateArray(list);
036: m_list = mergeArrays(list, base.m_list);
037: }
038:
039: /**
040: * Constructor from pair of base instances. This merges the values, making
041: * sure they're unique, and if they're not throws an exception.
042: *
043: * @param array1 first base array
044: * @param array2 second base array
045: */
046: public StringArray(StringArray array1, StringArray array2) {
047: m_list = mergeArrays(array1.m_list, array2.m_list);
048: }
049:
050: /**
051: * Constructor from array of values to be added to pair of base instances.
052: * This merges the array values, making sure they're ordered and unique, and
053: * if they're not throws an exception.
054: *
055: * @param list array of values
056: * @param array1 first base array
057: * @param array2 second base array
058: */
059: public StringArray(String[] list, StringArray array1,
060: StringArray array2) {
061: validateArray(list);
062: m_list = mergeArrays(list, mergeArrays(array1.m_list,
063: array2.m_list));
064: }
065:
066: /**
067: * Constructor from array of values to be added to three base instances.
068: * This merges the array values, making sure they're ordered and unique, and
069: * if they're not throws an exception.
070: *
071: * @param list array of values
072: * @param array1 first base array
073: * @param array2 second base array
074: * @param array3 third base array
075: */
076: public StringArray(String[] list, StringArray array1,
077: StringArray array2, StringArray array3) {
078: validateArray(list);
079: m_list = mergeArrays(list, mergeArrays(array1.m_list,
080: mergeArrays(array2.m_list, array3.m_list)));
081: }
082:
083: /**
084: * Constructor from array of values to be added to four base instances.
085: * This merges the array values, making sure they're ordered and unique, and
086: * if they're not throws an exception.
087: *
088: * @param list array of values
089: * @param array1 first base array
090: * @param array2 second base array
091: * @param array3 third base array
092: * @param array4 fourth base array
093: */
094: public StringArray(String[] list, StringArray array1,
095: StringArray array2, StringArray array3, StringArray array4) {
096: validateArray(list);
097: m_list = mergeArrays(list, mergeArrays(array1.m_list,
098: mergeArrays(array2.m_list, mergeArrays(array3.m_list,
099: array4.m_list))));
100: }
101:
102: /**
103: * Merge a pair of ordered arrays into a single array. The two source arrays
104: * must not contain any values in common.
105: *
106: * @param list1 first ordered array
107: * @param list2 second ordered array
108: * @return merged array
109: */
110: private String[] mergeArrays(String[] list1, String[] list2) {
111: String[] merge = new String[list1.length + list2.length];
112: int fill = 0;
113: int i = 0;
114: int j = 0;
115: while (i < list1.length && j < list2.length) {
116: int diff = list2[j].compareTo(list1[i]);
117: if (diff > 0) {
118: merge[fill++] = list1[i++];
119: } else if (diff < 0) {
120: merge[fill++] = list2[j++];
121: } else {
122: throw new IllegalArgumentException(
123: "Repeated value not allowed: \"" + list1[i]
124: + '"');
125: }
126: }
127: if (i < list1.length) {
128: System.arraycopy(list1, i, merge, fill, list1.length - i);
129: }
130: if (j < list2.length) {
131: System.arraycopy(list2, j, merge, fill, list2.length - j);
132: }
133: return merge;
134: }
135:
136: /**
137: * Make sure passed-in array contains values that are in order and without
138: * duplicate values.
139: *
140: * @param list
141: */
142: private void validateArray(String[] list) {
143: if (list.length > 0) {
144: String last = list[0];
145: int index = 0;
146: while (++index < list.length) {
147: String comp = list[index];
148: int diff = last.compareTo(comp);
149: if (diff > 0) {
150: throw new IllegalArgumentException(
151: "Array values are not ordered");
152: } else if (diff < 0) {
153: last = comp;
154: } else {
155: throw new IllegalArgumentException(
156: "Duplicate values in array");
157: }
158: }
159: }
160: }
161:
162: /**
163: * Get string at a particular index in the list.
164: *
165: * @param index list index to be returned
166: * @return string at that index position
167: */
168: public String get(int index) {
169: return m_list[index];
170: }
171:
172: /**
173: * Find index of a particular string in the array. This does
174: * a binary search through the array values, using a pair of
175: * index bounds to track the subarray of possible matches at
176: * each iteration.
177: *
178: * @param value string to be found in list
179: * @return index of string in array, or <code>-1</code> if
180: * not present
181: */
182: public int indexOf(String value) {
183: int base = 0;
184: int limit = m_list.length - 1;
185: while (base <= limit) {
186: int cur = (base + limit) >> 1;
187: int diff = value.compareTo(m_list[cur]);
188: if (diff < 0) {
189: limit = cur - 1;
190: } else if (diff > 0) {
191: base = cur + 1;
192: } else {
193: return cur;
194: }
195: }
196: return -1;
197: }
198:
199: /**
200: * Get number of values in array
201: *
202: * @return number of values in array
203: */
204: public int size() {
205: return m_list.length;
206: }
207: }
|