-
Notifications
You must be signed in to change notification settings - Fork 182
Expand file tree
/
Copy pathCollectionManager.java
More file actions
243 lines (224 loc) · 11.2 KB
/
CollectionManager.java
File metadata and controls
243 lines (224 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*****************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
* *
* *
* This file is part of the BeanShell Java Scripting distribution. *
* Documentation and updates may be found at http://www.beanshell.org/ *
* Patrick Niemeyer ([email protected]) *
* Author of Learning Java, O'Reilly & Associates *
* *
*****************************************************************************/
package bsh;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/** The default CollectionManager supports iteration over objects of type:
* Enumeration, Iterator, Iterable, CharSequence, and array. */
public final class CollectionManager {
/** The Constant manager. */
private static final CollectionManager manager = new CollectionManager();
/** Gets the collection manager.
* @return the collection manager */
public static synchronized CollectionManager getCollectionManager() {
return manager;
}
/** An empty iterator with hasNext always false.
* @param <T> generic type,
* since java can't infer it will be Object
* @return the null iterator */
private <T> Iterator<T> emptyIt() {
return new Iterator<T>() {
@Override
public boolean hasNext() {
return false;
}
@Override
public T next() {
return null;
}
};
}
/** Obfuscated Object type or primitive array iterator.
* @param array the object array
* @return the iterator */
private Iterator<Object> arrayIt(final Object array) {
return new Iterator<Object>() {
private int index = 0;
private final int length = Array.getLength(array);
@Override
public boolean hasNext() {
return this.index < this.length;
}
@Override
public Object next() {
try {
return Array.get(array, this.index++);
} catch (Throwable t) {
throw new NoSuchElementException(t.getMessage());
}
}
};
}
/** Apply reflection to supplied value returning an
* iterable stream of strings. Allows iteration over
* true string representations of the class and member
* definitions. For generated classes the true or bsh
* definitions are retrieved and not the java reflection
* of the mock instances.
* @param obj the type to reflect
* @return an iterable stream of String definitions */
private Stream<String> reflectNames(Object obj) {
Class<?> type = obj.getClass();
if (obj instanceof Class<?>)
type = (Class<?>) obj;
if (obj instanceof ClassIdentifier)
type = ((ClassIdentifier)obj).getTargetClass();
if (Reflect.isGeneratedClass(type))
return Stream.concat(Stream.concat(
Stream.of(StringUtil.classString(type)),
Stream.concat(
Stream.of(Reflect.getDeclaredVariables(type))
.map(StringUtil::variableString)
.map(" "::concat),
Stream.of(Reflect.getDeclaredMethods(type))
.map(StringUtil::methodString)
.map(" "::concat))), Stream.of("}"));
else
return Stream.concat(Stream.concat(
Stream.of(StringUtil.classString(type)),
Stream.concat(
Stream.of(type.getFields())
.map(StringUtil::variableString)
.map(" "::concat),
Stream.of(type.getMethods())
.map(StringUtil::methodString)
.map(" "::concat))), Stream.of("}"));
}
/** Gets iterator for enumerated elements.
* @param obj the enumerated elements
* @return the bsh iterator */
public <T> Iterator<T> getBshIterator(final Enumeration<T> obj) {
return Collections.list(obj).iterator();
}
/** Returns iterator from supplied iterable collection.
* @param obj an iterable collection instance
* @return the bsh iterator */
public <T> Iterator<T> getBshIterator(final Iterable<T> obj) {
return obj.iterator();
}
/** Returns iterator from supplied iterator.
* @param obj the iterator
* @return the bsh iterator */
public <T> Iterator<T> getBshIterator(final Iterator<T> obj) {
return obj;
}
/** Collect a char array iterator from supplied char sequence.
* @param obj the char sequence value
* @return the bsh iterator */
public Iterator<Object> getBshIterator(final CharSequence obj) {
return this.arrayIt(obj.toString().toCharArray());
}
/** Collect a char array sequence iterator from supplied string.
* @param obj the string value
* @return the bsh iterator */
public Iterator<Object> getBshIterator(final String obj) {
return this.arrayIt(obj.toCharArray());
}
/** Iterator from T[] method bound type Object array as value.
* @param obj the T[] generic typed Object array.
* @return the iterator */
public <T> Iterator<T> getBshIterator(final T[] obj) {
return Arrays.asList(obj).iterator();
}
/** Gets iterator for Number range from 0.
* Range from 0 up to number or 0 down to number inclusive.
* Empty Iterator if number is 0.
* @param obj the top range number value
* @return the bsh iterator */
public Iterator<Integer> getBshIterator(final Number obj) {
int number = obj.intValue();
if (number == 0)
return this.emptyIt();
if (number > 0)
return IntStream.rangeClosed(0, number).iterator();
return IntStream.rangeClosed(number, 0).map(i -> number - i).iterator();
}
/** Starting positions of unicode block sets */
private static final int[] unicodeBlockStarts = new int[] {48,58,65,91,97,123,129,256,384,592,688,768,880,1024,
1329,1425,1536,1792,1872,1920,1984,2048,2112,2144,2208,2304,2432,2561,2689,2817,2946,3072,3200,3328,3458,3584,
3712,3840,4096,2256,4352,4608,5024,5120,5760,5792,5888,5920,5952,5984,6016,6144,6320,6400,6480,6528,6624,6656,
6688,6832,6912,7040,7104,7168,7248,7296,7360,7376,7424,7616,7680,7936,8192,8304,8352,8400,8448,8528,8592,8704,
8960,9216,9280,9312,9472,9600,9632,9728,9984,10176,10224,10240,10496,10624,10752,11008,11264,11360,11392,11520,
11568,11648,11744,11776,11904,12032,12272,12288,12352,12448,12544,12592,12688,12704,12736,12784,12800,13056,
13312,19904,19968,40960,42128,42192,42240,42560,42656,42752,42784,43008,43056,43072,43136,43232,43264,43312,
43360,43392,43488,43520,43616,43648,43744,43776,43824,43888,43968,44032,55216,55296,56320,57344,63744,64256,
64336,65024,65040,65056,65072,65104,65136,65280,65520,65536,65664,65792,65856,65936,66000,66176,66208,66272,
66304,66352,66384,66432,66464,66560,66640,66688,66736,66816,66864,67072,67584,67648,67680,67712,67808,67840,
67872,67968,68000,68096,68192,68224,68288,68352,68416,68448,68480,68608,68736,69216,69632,69760,69840,69888,
69968,70016,70112,70144,70272,70320,70400,70656,70784,71040,71168,71264,71296,71424,71840,72192,72272,72384,
72704,72816,72960,73728,74752,74880,77824,82944,92160,92736,92880,92928,93952,94176,94208,100352,110592,110848,
110960,113664,113824,118784,119040,119296,119552,119648,119808,120832,122880,124928,125184,126464,126976,127024,
127136,127232,127488,127744,128512,128592,128640,128768,128896,129024,129280,131072,173824,177984,178208,183984,
194560,917504,917760,983040,1048576};
/** Gets iterator for character range from highest unicode block set starting position.
* Range from highest starting position which is less than supplied value code point.
* @param obj the top of the character range
* @return the bsh iterator */
public Iterator<String> getBshIterator(final Character obj) {
Integer value = Integer.valueOf(obj.charValue());
int check = 33, start = 0;
for (int i : unicodeBlockStarts) if (check <= value) {
start = check;
check = i;
} else break;
return IntStream.rangeClosed(start, value).boxed()
.map(Character::toChars)
.map(String::valueOf).iterator();
}
/** Inspect the supplied object and cast type to delegates.
* @param obj the value to iterate of unknown type.
* @return the bsh iterator */
public Iterator<?> getBshIterator(final Object obj) {
if (obj == null)
return this.emptyIt();
if (obj instanceof Primitive)
return this.getBshIterator(Primitive.unwrap(obj));
if (obj.getClass().isArray())
return this.arrayIt(obj);
if (obj instanceof Iterable)
return this.getBshIterator((Iterable<?>) obj);
if (obj instanceof Iterator)
return this.getBshIterator((Iterator<?>) obj);
if (obj instanceof Enumeration)
return this.getBshIterator((Enumeration<?>) obj);
if (obj instanceof CharSequence)
return this.getBshIterator((CharSequence) obj);
if (obj instanceof Number)
return this.getBshIterator((Number) obj);
if (obj instanceof Character)
return this.getBshIterator((Character) obj);
if (obj instanceof String)
return this.getBshIterator((String) obj);
return this.reflectNames(obj).iterator();
}
}