propane 3.9.0-java → 3.10.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +2 -2
- data/README.md +3 -3
- data/Rakefile +6 -6
- data/lib/java/japplemenubar/JAppleMenuBar.java +88 -0
- data/lib/java/japplemenubar/libjAppleMenuBar.jnilib +0 -0
- data/lib/java/monkstone/ColorUtil.java +127 -0
- data/lib/java/monkstone/MathToolModule.java +287 -0
- data/lib/java/monkstone/PropaneLibrary.java +46 -0
- data/lib/java/monkstone/core/LibraryProxy.java +136 -0
- data/lib/java/monkstone/fastmath/DegLutTables.java +111 -0
- data/lib/java/monkstone/fastmath/Deglut.java +71 -0
- data/lib/java/monkstone/fastmath/package-info.java +6 -0
- data/lib/java/monkstone/filechooser/Chooser.java +39 -0
- data/{src/main → lib}/java/monkstone/noise/FastTerrain.java +0 -0
- data/{src/main → lib}/java/monkstone/noise/Noise.java +0 -0
- data/{src/main → lib}/java/monkstone/noise/NoiseGenerator.java +0 -0
- data/{src/main → lib}/java/monkstone/noise/NoiseMode.java +0 -0
- data/lib/java/monkstone/noise/OpenSimplex2F.java +881 -0
- data/lib/java/monkstone/noise/OpenSimplex2S.java +1106 -0
- data/{src/main → lib}/java/monkstone/noise/SmoothTerrain.java +0 -0
- data/lib/java/monkstone/slider/CustomHorizontalSlider.java +164 -0
- data/lib/java/monkstone/slider/CustomVerticalSlider.java +178 -0
- data/lib/java/monkstone/slider/SimpleHorizontalSlider.java +145 -0
- data/lib/java/monkstone/slider/SimpleSlider.java +166 -0
- data/lib/java/monkstone/slider/SimpleVerticalSlider.java +157 -0
- data/lib/java/monkstone/slider/Slider.java +61 -0
- data/lib/java/monkstone/slider/SliderBar.java +245 -0
- data/lib/java/monkstone/slider/SliderGroup.java +56 -0
- data/lib/java/monkstone/slider/WheelHandler.java +35 -0
- data/lib/java/monkstone/vecmath/GfxRender.java +86 -0
- data/lib/java/monkstone/vecmath/JRender.java +56 -0
- data/lib/java/monkstone/vecmath/ShapeRender.java +87 -0
- data/lib/java/monkstone/vecmath/package-info.java +20 -0
- data/lib/java/monkstone/vecmath/vec2/Vec2.java +802 -0
- data/lib/java/monkstone/vecmath/vec2/package-info.java +6 -0
- data/lib/java/monkstone/vecmath/vec3/Vec3.java +727 -0
- data/lib/java/monkstone/vecmath/vec3/package-info.java +6 -0
- data/lib/java/monkstone/videoevent/CaptureEvent.java +27 -0
- data/lib/java/monkstone/videoevent/MovieEvent.java +32 -0
- data/lib/java/monkstone/videoevent/package-info.java +20 -0
- data/lib/java/processing/awt/PGraphicsJava2D.java +3040 -0
- data/lib/java/processing/awt/PImageAWT.java +377 -0
- data/lib/java/processing/awt/PShapeJava2D.java +387 -0
- data/lib/java/processing/awt/PSurfaceAWT.java +1581 -0
- data/lib/java/processing/awt/ShimAWT.java +581 -0
- data/lib/java/processing/core/PApplet.java +15156 -0
- data/lib/java/processing/core/PConstants.java +523 -0
- data/lib/java/processing/core/PFont.java +1126 -0
- data/lib/java/processing/core/PGraphics.java +8600 -0
- data/lib/java/processing/core/PImage.java +3377 -0
- data/lib/java/processing/core/PMatrix.java +208 -0
- data/lib/java/processing/core/PMatrix2D.java +562 -0
- data/lib/java/processing/core/PMatrix3D.java +890 -0
- data/lib/java/processing/core/PShape.java +3561 -0
- data/lib/java/processing/core/PShapeOBJ.java +483 -0
- data/lib/java/processing/core/PShapeSVG.java +2016 -0
- data/lib/java/processing/core/PStyle.java +63 -0
- data/lib/java/processing/core/PSurface.java +198 -0
- data/lib/java/processing/core/PSurfaceNone.java +431 -0
- data/lib/java/processing/core/PVector.java +1066 -0
- data/lib/java/processing/core/ThinkDifferent.java +115 -0
- data/lib/java/processing/data/DoubleDict.java +850 -0
- data/lib/java/processing/data/DoubleList.java +928 -0
- data/lib/java/processing/data/FloatDict.java +847 -0
- data/lib/java/processing/data/FloatList.java +936 -0
- data/lib/java/processing/data/IntDict.java +807 -0
- data/lib/java/processing/data/IntList.java +936 -0
- data/lib/java/processing/data/JSONArray.java +1260 -0
- data/lib/java/processing/data/JSONObject.java +2282 -0
- data/lib/java/processing/data/JSONTokener.java +435 -0
- data/lib/java/processing/data/LongDict.java +802 -0
- data/lib/java/processing/data/LongList.java +937 -0
- data/lib/java/processing/data/Sort.java +46 -0
- data/lib/java/processing/data/StringDict.java +613 -0
- data/lib/java/processing/data/StringList.java +800 -0
- data/lib/java/processing/data/Table.java +4936 -0
- data/lib/java/processing/data/TableRow.java +198 -0
- data/lib/java/processing/data/XML.java +1156 -0
- data/lib/java/processing/dxf/RawDXF.java +404 -0
- data/lib/java/processing/event/Event.java +125 -0
- data/lib/java/processing/event/KeyEvent.java +70 -0
- data/lib/java/processing/event/MouseEvent.java +114 -0
- data/lib/java/processing/event/TouchEvent.java +57 -0
- data/lib/java/processing/javafx/PGraphicsFX2D.java +32 -0
- data/lib/java/processing/javafx/PSurfaceFX.java +173 -0
- data/lib/java/processing/net/Client.java +744 -0
- data/lib/java/processing/net/Server.java +388 -0
- data/lib/java/processing/opengl/FontTexture.java +378 -0
- data/lib/java/processing/opengl/FrameBuffer.java +513 -0
- data/lib/java/processing/opengl/LinePath.java +627 -0
- data/lib/java/processing/opengl/LineStroker.java +681 -0
- data/lib/java/processing/opengl/PGL.java +3483 -0
- data/lib/java/processing/opengl/PGraphics2D.java +615 -0
- data/lib/java/processing/opengl/PGraphics3D.java +281 -0
- data/lib/java/processing/opengl/PGraphicsOpenGL.java +13753 -0
- data/lib/java/processing/opengl/PJOGL.java +2008 -0
- data/lib/java/processing/opengl/PShader.java +1484 -0
- data/lib/java/processing/opengl/PShapeOpenGL.java +5269 -0
- data/lib/java/processing/opengl/PSurfaceJOGL.java +1385 -0
- data/lib/java/processing/opengl/Texture.java +1696 -0
- data/lib/java/processing/opengl/VertexBuffer.java +88 -0
- data/lib/java/processing/opengl/cursors/arrow.png +0 -0
- data/lib/java/processing/opengl/cursors/cross.png +0 -0
- data/lib/java/processing/opengl/cursors/hand.png +0 -0
- data/lib/java/processing/opengl/cursors/license.txt +27 -0
- data/lib/java/processing/opengl/cursors/move.png +0 -0
- data/lib/java/processing/opengl/cursors/text.png +0 -0
- data/lib/java/processing/opengl/cursors/wait.png +0 -0
- data/lib/java/processing/opengl/shaders/ColorFrag.glsl +32 -0
- data/lib/java/processing/opengl/shaders/ColorVert.glsl +34 -0
- data/lib/java/processing/opengl/shaders/LightFrag.glsl +33 -0
- data/lib/java/processing/opengl/shaders/LightVert.glsl +151 -0
- data/lib/java/processing/opengl/shaders/LineFrag.glsl +32 -0
- data/lib/java/processing/opengl/shaders/LineVert.glsl +100 -0
- data/lib/java/processing/opengl/shaders/MaskFrag.glsl +40 -0
- data/lib/java/processing/opengl/shaders/PointFrag.glsl +32 -0
- data/lib/java/processing/opengl/shaders/PointVert.glsl +56 -0
- data/lib/java/processing/opengl/shaders/TexFrag.glsl +37 -0
- data/lib/java/processing/opengl/shaders/TexLightFrag.glsl +37 -0
- data/lib/java/processing/opengl/shaders/TexLightVert.glsl +157 -0
- data/lib/java/processing/opengl/shaders/TexVert.glsl +38 -0
- data/lib/java/processing/pdf/PGraphicsPDF.java +581 -0
- data/lib/java/processing/svg/PGraphicsSVG.java +378 -0
- data/lib/propane/app.rb +8 -13
- data/lib/propane/version.rb +1 -1
- data/mvnw +3 -3
- data/mvnw.cmd +2 -2
- data/pom.rb +7 -2
- data/pom.xml +14 -2
- data/propane.gemspec +2 -2
- data/src/main/java/monkstone/FastNoiseModuleJava.java +127 -0
- data/src/main/java/monkstone/MathToolModule.java +30 -30
- data/src/main/java/monkstone/PropaneLibrary.java +2 -0
- data/src/main/java/monkstone/SmoothNoiseModuleJava.java +127 -0
- data/src/main/java/monkstone/fastmath/DegLutTables.java +15 -15
- data/src/main/java/monkstone/filechooser/Chooser.java +1 -1
- data/src/main/java/monkstone/noise/OpenSimplex2F.java +752 -820
- data/src/main/java/monkstone/noise/OpenSimplex2S.java +1138 -1106
- data/src/main/java/monkstone/slider/WheelHandler.java +1 -1
- data/src/main/java/monkstone/vecmath/JRender.java +6 -6
- data/src/main/java/monkstone/vecmath/vec2/Vec2.java +20 -19
- data/src/main/java/monkstone/vecmath/vec3/Vec3.java +12 -12
- data/src/main/java/processing/awt/PGraphicsJava2D.java +11 -3
- data/src/main/java/processing/core/PApplet.java +89 -89
- data/src/main/java/processing/core/PConstants.java +155 -163
- data/src/main/java/processing/opengl/PJOGL.java +6 -5
- data/vendors/Rakefile +1 -1
- metadata +136 -19
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
package processing.data;
|
|
2
|
+
|
|
3
|
+
import java.io.BufferedReader;
|
|
4
|
+
import java.io.IOException;
|
|
5
|
+
import java.io.InputStream;
|
|
6
|
+
import java.io.InputStreamReader;
|
|
7
|
+
import java.io.Reader;
|
|
8
|
+
import java.io.StringReader;
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
Copyright (c) 2002 JSON.org
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
The Software shall be used for Good, not Evil.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A JSONTokener takes a source string and extracts characters and tokens from
|
|
36
|
+
* it. It is used by the JSONObject and JSONArray constructors to parse
|
|
37
|
+
* JSON source strings.
|
|
38
|
+
* @author JSON.org
|
|
39
|
+
* @version 2012-02-16
|
|
40
|
+
*/
|
|
41
|
+
class JSONTokener {
|
|
42
|
+
|
|
43
|
+
private long character;
|
|
44
|
+
private boolean eof;
|
|
45
|
+
private long index;
|
|
46
|
+
private long line;
|
|
47
|
+
private char previous;
|
|
48
|
+
private Reader reader;
|
|
49
|
+
private boolean usePrevious;
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Construct a JSONTokener from a Reader.
|
|
54
|
+
*
|
|
55
|
+
* @param reader A reader.
|
|
56
|
+
*/
|
|
57
|
+
public JSONTokener(Reader reader) {
|
|
58
|
+
this.reader = reader.markSupported()
|
|
59
|
+
? reader
|
|
60
|
+
: new BufferedReader(reader);
|
|
61
|
+
this.eof = false;
|
|
62
|
+
this.usePrevious = false;
|
|
63
|
+
this.previous = 0;
|
|
64
|
+
this.index = 0;
|
|
65
|
+
this.character = 1;
|
|
66
|
+
this.line = 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Construct a JSONTokener from an InputStream.
|
|
72
|
+
*/
|
|
73
|
+
public JSONTokener(InputStream inputStream) {
|
|
74
|
+
this(new InputStreamReader(inputStream));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Construct a JSONTokener from a string.
|
|
80
|
+
*
|
|
81
|
+
* @param s A source string.
|
|
82
|
+
*/
|
|
83
|
+
public JSONTokener(String s) {
|
|
84
|
+
this(new StringReader(s));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Back up one character. This provides a sort of lookahead capability,
|
|
90
|
+
* so that you can test for a digit or letter before attempting to parse
|
|
91
|
+
* the next number or identifier.
|
|
92
|
+
*/
|
|
93
|
+
public void back() {
|
|
94
|
+
if (this.usePrevious || this.index <= 0) {
|
|
95
|
+
throw new RuntimeException("Stepping back two steps is not supported");
|
|
96
|
+
}
|
|
97
|
+
this.index -= 1;
|
|
98
|
+
this.character -= 1;
|
|
99
|
+
this.usePrevious = true;
|
|
100
|
+
this.eof = false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get the hex value of a character (base16).
|
|
106
|
+
* @param c A character between '0' and '9' or between 'A' and 'F' or
|
|
107
|
+
* between 'a' and 'f'.
|
|
108
|
+
* @return An int between 0 and 15, or -1 if c was not a hex digit.
|
|
109
|
+
*/
|
|
110
|
+
public static int dehexchar(char c) {
|
|
111
|
+
if (c >= '0' && c <= '9') {
|
|
112
|
+
return c - '0';
|
|
113
|
+
}
|
|
114
|
+
if (c >= 'A' && c <= 'F') {
|
|
115
|
+
return c - ('A' - 10);
|
|
116
|
+
}
|
|
117
|
+
if (c >= 'a' && c <= 'f') {
|
|
118
|
+
return c - ('a' - 10);
|
|
119
|
+
}
|
|
120
|
+
return -1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public boolean end() {
|
|
124
|
+
return this.eof && !this.usePrevious;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Determine if the source string still contains characters that next()
|
|
130
|
+
* can consume.
|
|
131
|
+
* @return true if not yet at the end of the source.
|
|
132
|
+
*/
|
|
133
|
+
public boolean more() {
|
|
134
|
+
this.next();
|
|
135
|
+
if (this.end()) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
this.back();
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get the next character in the source string.
|
|
145
|
+
*
|
|
146
|
+
* @return The next character, or 0 if past the end of the source string.
|
|
147
|
+
*/
|
|
148
|
+
public char next() {
|
|
149
|
+
int c;
|
|
150
|
+
if (this.usePrevious) {
|
|
151
|
+
this.usePrevious = false;
|
|
152
|
+
c = this.previous;
|
|
153
|
+
} else {
|
|
154
|
+
try {
|
|
155
|
+
c = this.reader.read();
|
|
156
|
+
} catch (IOException exception) {
|
|
157
|
+
throw new RuntimeException(exception);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (c <= 0) { // End of stream
|
|
161
|
+
this.eof = true;
|
|
162
|
+
c = 0;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
this.index += 1;
|
|
166
|
+
if (this.previous == '\r') {
|
|
167
|
+
this.line += 1;
|
|
168
|
+
this.character = c == '\n' ? 0 : 1;
|
|
169
|
+
} else if (c == '\n') {
|
|
170
|
+
this.line += 1;
|
|
171
|
+
this.character = 0;
|
|
172
|
+
} else {
|
|
173
|
+
this.character += 1;
|
|
174
|
+
}
|
|
175
|
+
this.previous = (char) c;
|
|
176
|
+
return this.previous;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Consume the next character, and check that it matches a specified
|
|
182
|
+
* character.
|
|
183
|
+
* @param c The character to match.
|
|
184
|
+
* @return The character.
|
|
185
|
+
* @throws JSONException if the character does not match.
|
|
186
|
+
*/
|
|
187
|
+
public char next(char c) {
|
|
188
|
+
char n = this.next();
|
|
189
|
+
if (n != c) {
|
|
190
|
+
throw new RuntimeException("Expected '" + c + "' and instead saw '" + n + "'");
|
|
191
|
+
}
|
|
192
|
+
return n;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get the next n characters.
|
|
198
|
+
*
|
|
199
|
+
* @param n The number of characters to take.
|
|
200
|
+
* @return A string of n characters.
|
|
201
|
+
* @throws JSONException
|
|
202
|
+
* Substring bounds error if there are not
|
|
203
|
+
* n characters remaining in the source string.
|
|
204
|
+
*/
|
|
205
|
+
public String next(int n) {
|
|
206
|
+
if (n == 0) {
|
|
207
|
+
return "";
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
char[] chars = new char[n];
|
|
211
|
+
int pos = 0;
|
|
212
|
+
|
|
213
|
+
while (pos < n) {
|
|
214
|
+
chars[pos] = this.next();
|
|
215
|
+
if (this.end()) {
|
|
216
|
+
throw new RuntimeException("Substring bounds error");
|
|
217
|
+
}
|
|
218
|
+
pos += 1;
|
|
219
|
+
}
|
|
220
|
+
return new String(chars);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get the next char in the string, skipping whitespace.
|
|
226
|
+
* @throws JSONException
|
|
227
|
+
* @return A character, or 0 if there are no more characters.
|
|
228
|
+
*/
|
|
229
|
+
public char nextClean() {
|
|
230
|
+
for (;;) {
|
|
231
|
+
char c = this.next();
|
|
232
|
+
if (c == 0 || c > ' ') {
|
|
233
|
+
return c;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Return the characters up to the next close quote character.
|
|
241
|
+
* Backslash processing is done. The formal JSON format does not
|
|
242
|
+
* allow strings in single quotes, but an implementation is allowed to
|
|
243
|
+
* accept them.
|
|
244
|
+
* @param quote The quoting character, either
|
|
245
|
+
* <code>"</code> <small>(double quote)</small> or
|
|
246
|
+
* <code>'</code> <small>(single quote)</small>.
|
|
247
|
+
* @return A String.
|
|
248
|
+
* @throws JSONException Unterminated string.
|
|
249
|
+
*/
|
|
250
|
+
public String nextString(char quote) {
|
|
251
|
+
char c;
|
|
252
|
+
StringBuilder sb = new StringBuilder();
|
|
253
|
+
for (;;) {
|
|
254
|
+
c = this.next();
|
|
255
|
+
switch (c) {
|
|
256
|
+
case 0:
|
|
257
|
+
case '\n':
|
|
258
|
+
case '\r':
|
|
259
|
+
throw new RuntimeException("Unterminated string");
|
|
260
|
+
case '\\':
|
|
261
|
+
c = this.next();
|
|
262
|
+
switch (c) {
|
|
263
|
+
case 'b':
|
|
264
|
+
sb.append('\b');
|
|
265
|
+
break;
|
|
266
|
+
case 't':
|
|
267
|
+
sb.append('\t');
|
|
268
|
+
break;
|
|
269
|
+
case 'n':
|
|
270
|
+
sb.append('\n');
|
|
271
|
+
break;
|
|
272
|
+
case 'f':
|
|
273
|
+
sb.append('\f');
|
|
274
|
+
break;
|
|
275
|
+
case 'r':
|
|
276
|
+
sb.append('\r');
|
|
277
|
+
break;
|
|
278
|
+
case 'u':
|
|
279
|
+
sb.append((char)Integer.parseInt(this.next(4), 16));
|
|
280
|
+
break;
|
|
281
|
+
case '"':
|
|
282
|
+
case '\'':
|
|
283
|
+
case '\\':
|
|
284
|
+
case '/':
|
|
285
|
+
sb.append(c);
|
|
286
|
+
break;
|
|
287
|
+
default:
|
|
288
|
+
throw new RuntimeException("Illegal escape.");
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
default:
|
|
292
|
+
if (c == quote) {
|
|
293
|
+
return sb.toString();
|
|
294
|
+
}
|
|
295
|
+
sb.append(c);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get the text up but not including the specified character or the
|
|
303
|
+
* end of line, whichever comes first.
|
|
304
|
+
* @param delimiter A delimiter character.
|
|
305
|
+
* @return A string.
|
|
306
|
+
*/
|
|
307
|
+
public String nextTo(char delimiter) {
|
|
308
|
+
StringBuilder sb = new StringBuilder();
|
|
309
|
+
for (;;) {
|
|
310
|
+
char c = this.next();
|
|
311
|
+
if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
|
|
312
|
+
if (c != 0) {
|
|
313
|
+
this.back();
|
|
314
|
+
}
|
|
315
|
+
return sb.toString().trim();
|
|
316
|
+
}
|
|
317
|
+
sb.append(c);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Get the text up but not including one of the specified delimiter
|
|
324
|
+
* characters or the end of line, whichever comes first.
|
|
325
|
+
* @param delimiters A set of delimiter characters.
|
|
326
|
+
* @return A string, trimmed.
|
|
327
|
+
*/
|
|
328
|
+
public String nextTo(String delimiters) {
|
|
329
|
+
char c;
|
|
330
|
+
StringBuilder sb = new StringBuilder();
|
|
331
|
+
for (;;) {
|
|
332
|
+
c = this.next();
|
|
333
|
+
if (delimiters.indexOf(c) >= 0 || c == 0 ||
|
|
334
|
+
c == '\n' || c == '\r') {
|
|
335
|
+
if (c != 0) {
|
|
336
|
+
this.back();
|
|
337
|
+
}
|
|
338
|
+
return sb.toString().trim();
|
|
339
|
+
}
|
|
340
|
+
sb.append(c);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Get the next value. The value can be a Boolean, Double, Integer,
|
|
347
|
+
* JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
|
|
348
|
+
* @throws JSONException If syntax error.
|
|
349
|
+
*
|
|
350
|
+
* @return An object.
|
|
351
|
+
*/
|
|
352
|
+
public Object nextValue() {
|
|
353
|
+
char c = this.nextClean();
|
|
354
|
+
String string;
|
|
355
|
+
|
|
356
|
+
switch (c) {
|
|
357
|
+
case '"':
|
|
358
|
+
case '\'':
|
|
359
|
+
return this.nextString(c);
|
|
360
|
+
case '{':
|
|
361
|
+
this.back();
|
|
362
|
+
return new JSONObject(this);
|
|
363
|
+
case '[':
|
|
364
|
+
this.back();
|
|
365
|
+
return new JSONArray(this);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/*
|
|
369
|
+
* Handle unquoted text. This could be the values true, false, or
|
|
370
|
+
* null, or it can be a number. An implementation (such as this one)
|
|
371
|
+
* is allowed to also accept non-standard forms.
|
|
372
|
+
*
|
|
373
|
+
* Accumulate characters until we reach the end of the text or a
|
|
374
|
+
* formatting character.
|
|
375
|
+
*/
|
|
376
|
+
|
|
377
|
+
StringBuilder sb = new StringBuilder();
|
|
378
|
+
while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
|
|
379
|
+
sb.append(c);
|
|
380
|
+
c = this.next();
|
|
381
|
+
}
|
|
382
|
+
this.back();
|
|
383
|
+
|
|
384
|
+
string = sb.toString().trim();
|
|
385
|
+
if ("".equals(string)) {
|
|
386
|
+
throw new RuntimeException("Missing value");
|
|
387
|
+
}
|
|
388
|
+
return JSONObject.stringToValue(string);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Skip characters until the next character is the requested character.
|
|
394
|
+
* If the requested character is not found, no characters are skipped.
|
|
395
|
+
* @param to A character to skip to.
|
|
396
|
+
* @return The requested character, or zero if the requested character
|
|
397
|
+
* is not found.
|
|
398
|
+
*/
|
|
399
|
+
public char skipTo(char to) {
|
|
400
|
+
char c;
|
|
401
|
+
try {
|
|
402
|
+
long startIndex = this.index;
|
|
403
|
+
long startCharacter = this.character;
|
|
404
|
+
long startLine = this.line;
|
|
405
|
+
this.reader.mark(1000000);
|
|
406
|
+
do {
|
|
407
|
+
c = this.next();
|
|
408
|
+
if (c == 0) {
|
|
409
|
+
this.reader.reset();
|
|
410
|
+
this.index = startIndex;
|
|
411
|
+
this.character = startCharacter;
|
|
412
|
+
this.line = startLine;
|
|
413
|
+
return c;
|
|
414
|
+
}
|
|
415
|
+
} while (c != to);
|
|
416
|
+
} catch (IOException exc) {
|
|
417
|
+
throw new RuntimeException(exc);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this.back();
|
|
421
|
+
return c;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Make a printable string of this JSONTokener.
|
|
427
|
+
*
|
|
428
|
+
* @return " at {index} [character {character} line {line}]"
|
|
429
|
+
*/
|
|
430
|
+
@Override
|
|
431
|
+
public String toString() {
|
|
432
|
+
return " at " + this.index + " [character " + this.character + " line " +
|
|
433
|
+
this.line + "]";
|
|
434
|
+
}
|
|
435
|
+
}
|
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
package processing.data;
|
|
2
|
+
|
|
3
|
+
import java.io.*;
|
|
4
|
+
import java.util.HashMap;
|
|
5
|
+
import java.util.Iterator;
|
|
6
|
+
import java.util.NoSuchElementException;
|
|
7
|
+
|
|
8
|
+
import processing.core.PApplet;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A simple class to use a String as a lookup for an int value.
|
|
13
|
+
*
|
|
14
|
+
* @nowebref
|
|
15
|
+
* @see FloatDict
|
|
16
|
+
* @see StringDict
|
|
17
|
+
*/
|
|
18
|
+
public class LongDict {
|
|
19
|
+
|
|
20
|
+
/** Number of elements in the table */
|
|
21
|
+
protected int count;
|
|
22
|
+
|
|
23
|
+
protected String[] keys;
|
|
24
|
+
protected long[] values;
|
|
25
|
+
|
|
26
|
+
/** Internal implementation for faster lookups */
|
|
27
|
+
private HashMap<String, Integer> indices = new HashMap<>();
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
public LongDict() {
|
|
31
|
+
count = 0;
|
|
32
|
+
keys = new String[10];
|
|
33
|
+
values = new long[10];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create a new lookup with a specific size. This is more efficient than not
|
|
39
|
+
* specifying a size. Use it when you know the rough size of the thing you're creating.
|
|
40
|
+
*
|
|
41
|
+
* @nowebref
|
|
42
|
+
*/
|
|
43
|
+
public LongDict(int length) {
|
|
44
|
+
count = 0;
|
|
45
|
+
keys = new String[length];
|
|
46
|
+
values = new long[length];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Read a set of entries from a Reader that has each key/value pair on
|
|
52
|
+
* a single line, separated by a tab.
|
|
53
|
+
*
|
|
54
|
+
* @nowebref
|
|
55
|
+
*/
|
|
56
|
+
public LongDict(BufferedReader reader) {
|
|
57
|
+
String[] lines = PApplet.loadStrings(reader);
|
|
58
|
+
keys = new String[lines.length];
|
|
59
|
+
values = new long[lines.length];
|
|
60
|
+
|
|
61
|
+
for (int i = 0; i < lines.length; i++) {
|
|
62
|
+
String[] pieces = PApplet.split(lines[i], '\t');
|
|
63
|
+
if (pieces.length == 2) {
|
|
64
|
+
keys[count] = pieces[0];
|
|
65
|
+
values[count] = PApplet.parseInt(pieces[1]);
|
|
66
|
+
indices.put(pieces[0], count);
|
|
67
|
+
count++;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @nowebref
|
|
74
|
+
*/
|
|
75
|
+
public LongDict(String[] keys, long[] values) {
|
|
76
|
+
if (keys.length != values.length) {
|
|
77
|
+
throw new IllegalArgumentException("key and value arrays must be the same length");
|
|
78
|
+
}
|
|
79
|
+
this.keys = keys;
|
|
80
|
+
this.values = values;
|
|
81
|
+
count = keys.length;
|
|
82
|
+
for (int i = 0; i < count; i++) {
|
|
83
|
+
indices.put(keys[i], i);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Constructor to allow (more intuitive) inline initialization, e.g.:
|
|
90
|
+
* <pre>
|
|
91
|
+
* new FloatDict(new Object[][] {
|
|
92
|
+
* { "key1", 1 },
|
|
93
|
+
* { "key2", 2 }
|
|
94
|
+
* });
|
|
95
|
+
* </pre>
|
|
96
|
+
*/
|
|
97
|
+
public LongDict(Object[][] pairs) {
|
|
98
|
+
count = pairs.length;
|
|
99
|
+
this.keys = new String[count];
|
|
100
|
+
this.values = new long[count];
|
|
101
|
+
for (int i = 0; i < count; i++) {
|
|
102
|
+
keys[i] = (String) pairs[i][0];
|
|
103
|
+
values[i] = (Integer) pairs[i][1];
|
|
104
|
+
indices.put(keys[i], i);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns the number of key/value pairs
|
|
111
|
+
*
|
|
112
|
+
* @webref intdict:method
|
|
113
|
+
* @brief Returns the number of key/value pairs
|
|
114
|
+
*/
|
|
115
|
+
public int size() {
|
|
116
|
+
return count;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resize the internal data, this can only be used to shrink the list.
|
|
122
|
+
* Helpful for situations like sorting and then grabbing the top 50 entries.
|
|
123
|
+
*/
|
|
124
|
+
public void resize(int length) {
|
|
125
|
+
if (length > count) {
|
|
126
|
+
throw new IllegalArgumentException("resize() can only be used to shrink the dictionary");
|
|
127
|
+
}
|
|
128
|
+
if (length < 1) {
|
|
129
|
+
throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
String[] newKeys = new String[length];
|
|
133
|
+
long[] newValues = new long[length];
|
|
134
|
+
PApplet.arrayCopy(keys, newKeys, length);
|
|
135
|
+
PApplet.arrayCopy(values, newValues, length);
|
|
136
|
+
keys = newKeys;
|
|
137
|
+
values = newValues;
|
|
138
|
+
count = length;
|
|
139
|
+
resetIndices();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Remove all entries.
|
|
145
|
+
*
|
|
146
|
+
* @webref intdict:method
|
|
147
|
+
* @brief Remove all entries
|
|
148
|
+
*/
|
|
149
|
+
public void clear() {
|
|
150
|
+
count = 0;
|
|
151
|
+
indices = new HashMap<>();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
private void resetIndices() {
|
|
156
|
+
indices = new HashMap<>(count);
|
|
157
|
+
for (int i = 0; i < count; i++) {
|
|
158
|
+
indices.put(keys[i], i);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
public class Entry {
|
|
167
|
+
public String key;
|
|
168
|
+
public long value;
|
|
169
|
+
|
|
170
|
+
Entry(String key, long value) {
|
|
171
|
+
this.key = key;
|
|
172
|
+
this.value = value;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
public Iterable<Entry> entries() {
|
|
178
|
+
return new Iterable<Entry>() {
|
|
179
|
+
|
|
180
|
+
public Iterator<Entry> iterator() {
|
|
181
|
+
return entryIterator();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
public Iterator<Entry> entryIterator() {
|
|
188
|
+
return new Iterator<Entry>() {
|
|
189
|
+
int index = -1;
|
|
190
|
+
|
|
191
|
+
public void remove() {
|
|
192
|
+
removeIndex(index);
|
|
193
|
+
index--;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public Entry next() {
|
|
197
|
+
++index;
|
|
198
|
+
Entry e = new Entry(keys[index], values[index]);
|
|
199
|
+
return e;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public boolean hasNext() {
|
|
203
|
+
return index+1 < size();
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
public String key(int index) {
|
|
213
|
+
return keys[index];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
protected void crop() {
|
|
218
|
+
if (count != keys.length) {
|
|
219
|
+
keys = PApplet.subset(keys, 0, count);
|
|
220
|
+
values = PApplet.subset(values, 0, count);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
public Iterable<String> keys() {
|
|
226
|
+
return new Iterable<String>() {
|
|
227
|
+
|
|
228
|
+
@Override
|
|
229
|
+
public Iterator<String> iterator() {
|
|
230
|
+
return keyIterator();
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
// Use this to iterate when you want to be able to remove elements along the way
|
|
237
|
+
public Iterator<String> keyIterator() {
|
|
238
|
+
return new Iterator<String>() {
|
|
239
|
+
int index = -1;
|
|
240
|
+
|
|
241
|
+
public void remove() {
|
|
242
|
+
removeIndex(index);
|
|
243
|
+
index--;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public String next() {
|
|
247
|
+
return key(++index);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
public boolean hasNext() {
|
|
251
|
+
return index+1 < size();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Return a copy of the internal keys array. This array can be modified.
|
|
259
|
+
*
|
|
260
|
+
* @webref intdict:method
|
|
261
|
+
* @brief Return a copy of the internal keys array
|
|
262
|
+
*/
|
|
263
|
+
public String[] keyArray() {
|
|
264
|
+
crop();
|
|
265
|
+
return keyArray(null);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
public String[] keyArray(String[] outgoing) {
|
|
270
|
+
if (outgoing == null || outgoing.length != count) {
|
|
271
|
+
outgoing = new String[count];
|
|
272
|
+
}
|
|
273
|
+
System.arraycopy(keys, 0, outgoing, 0, count);
|
|
274
|
+
return outgoing;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
public long value(int index) {
|
|
279
|
+
return values[index];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @webref intdict:method
|
|
285
|
+
* @brief Return the internal array being used to store the values
|
|
286
|
+
*/
|
|
287
|
+
public Iterable<Long> values() {
|
|
288
|
+
return new Iterable<Long>() {
|
|
289
|
+
|
|
290
|
+
@Override
|
|
291
|
+
public Iterator<Long> iterator() {
|
|
292
|
+
return valueIterator();
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
public Iterator<Long> valueIterator() {
|
|
299
|
+
return new Iterator<Long>() {
|
|
300
|
+
int index = -1;
|
|
301
|
+
|
|
302
|
+
public void remove() {
|
|
303
|
+
removeIndex(index);
|
|
304
|
+
index--;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
public Long next() {
|
|
308
|
+
return value(++index);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
public boolean hasNext() {
|
|
312
|
+
return index+1 < size();
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Create a new array and copy each of the values into it.
|
|
320
|
+
*
|
|
321
|
+
* @webref intdict:method
|
|
322
|
+
* @brief Create a new array and copy each of the values into it
|
|
323
|
+
*/
|
|
324
|
+
public int[] valueArray() {
|
|
325
|
+
crop();
|
|
326
|
+
return valueArray(null);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Fill an already-allocated array with the values (more efficient than
|
|
332
|
+
* creating a new array each time). If 'array' is null, or not the same
|
|
333
|
+
* size as the number of values, a new array will be allocated and returned.
|
|
334
|
+
*
|
|
335
|
+
* @param array values to copy into the array
|
|
336
|
+
*/
|
|
337
|
+
public int[] valueArray(int[] array) {
|
|
338
|
+
if (array == null || array.length != size()) {
|
|
339
|
+
array = new int[count];
|
|
340
|
+
}
|
|
341
|
+
System.arraycopy(values, 0, array, 0, count);
|
|
342
|
+
return array;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Return a value for the specified key.
|
|
348
|
+
*
|
|
349
|
+
* @webref intdict:method
|
|
350
|
+
* @brief Return a value for the specified key
|
|
351
|
+
*/
|
|
352
|
+
public long get(String key) {
|
|
353
|
+
int index = index(key);
|
|
354
|
+
if (index == -1) {
|
|
355
|
+
throw new IllegalArgumentException("No key named '" + key + "'");
|
|
356
|
+
}
|
|
357
|
+
return values[index];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
public long get(String key, long alternate) {
|
|
362
|
+
int index = index(key);
|
|
363
|
+
if (index == -1) return alternate;
|
|
364
|
+
return values[index];
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Create a new key/value pair or change the value of one.
|
|
370
|
+
*
|
|
371
|
+
* @webref intdict:method
|
|
372
|
+
* @brief Create a new key/value pair or change the value of one
|
|
373
|
+
*/
|
|
374
|
+
public void set(String key, long amount) {
|
|
375
|
+
int index = index(key);
|
|
376
|
+
if (index == -1) {
|
|
377
|
+
create(key, amount);
|
|
378
|
+
} else {
|
|
379
|
+
values[index] = amount;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
public void setIndex(int index, String key, long value) {
|
|
385
|
+
if (index < 0 || index >= count) {
|
|
386
|
+
throw new ArrayIndexOutOfBoundsException(index);
|
|
387
|
+
}
|
|
388
|
+
keys[index] = key;
|
|
389
|
+
values[index] = value;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* @webref intdict:method
|
|
395
|
+
* @brief Check if a key is a part of the data structure
|
|
396
|
+
*/
|
|
397
|
+
public boolean hasKey(String key) {
|
|
398
|
+
return index(key) != -1;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Increase the value associated with a specific key by 1.
|
|
404
|
+
*
|
|
405
|
+
* @webref intdict:method
|
|
406
|
+
* @brief Increase the value of a specific key value by 1
|
|
407
|
+
*/
|
|
408
|
+
public void increment(String key) {
|
|
409
|
+
add(key, 1);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Merge another dictionary into this one. Calling this increment()
|
|
415
|
+
* since it doesn't make sense in practice for the other dictionary types,
|
|
416
|
+
* even though it's technically an add().
|
|
417
|
+
*/
|
|
418
|
+
public void increment(LongDict dict) {
|
|
419
|
+
for (int i = 0; i < dict.count; i++) {
|
|
420
|
+
add(dict.key(i), dict.value(i));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* @webref intdict:method
|
|
427
|
+
* @brief Add to a value
|
|
428
|
+
*/
|
|
429
|
+
public void add(String key, long amount) {
|
|
430
|
+
int index = index(key);
|
|
431
|
+
if (index == -1) {
|
|
432
|
+
create(key, amount);
|
|
433
|
+
} else {
|
|
434
|
+
values[index] += amount;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* @webref intdict:method
|
|
441
|
+
* @brief Subtract from a value
|
|
442
|
+
*/
|
|
443
|
+
public void sub(String key, long amount) {
|
|
444
|
+
add(key, -amount);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* @webref intdict:method
|
|
450
|
+
* @brief Multiply a value
|
|
451
|
+
*/
|
|
452
|
+
public void mult(String key, long amount) {
|
|
453
|
+
int index = index(key);
|
|
454
|
+
if (index != -1) {
|
|
455
|
+
values[index] *= amount;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* @webref intdict:method
|
|
462
|
+
* @brief Divide a value
|
|
463
|
+
*/
|
|
464
|
+
public void div(String key, long amount) {
|
|
465
|
+
int index = index(key);
|
|
466
|
+
if (index != -1) {
|
|
467
|
+
values[index] /= amount;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
private void checkMinMax(String functionName) {
|
|
473
|
+
if (count == 0) {
|
|
474
|
+
String msg =
|
|
475
|
+
String.format("Cannot use %s() on an empty %s.",
|
|
476
|
+
functionName, getClass().getSimpleName());
|
|
477
|
+
throw new RuntimeException(msg);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
// return the index of the minimum value
|
|
483
|
+
public int minIndex() {
|
|
484
|
+
//checkMinMax("minIndex");
|
|
485
|
+
if (count == 0) return -1;
|
|
486
|
+
|
|
487
|
+
int index = 0;
|
|
488
|
+
long value = values[0];
|
|
489
|
+
for (int i = 1; i < count; i++) {
|
|
490
|
+
if (values[i] < value) {
|
|
491
|
+
index = i;
|
|
492
|
+
value = values[i];
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return index;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
// return the key for the minimum value
|
|
500
|
+
public String minKey() {
|
|
501
|
+
checkMinMax("minKey");
|
|
502
|
+
int index = minIndex();
|
|
503
|
+
if (index == -1) {
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
return keys[index];
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
// return the minimum value, or throw an error if there are no values
|
|
511
|
+
public long minValue() {
|
|
512
|
+
checkMinMax("minValue");
|
|
513
|
+
return values[minIndex()];
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
// return the index of the max value
|
|
518
|
+
public int maxIndex() {
|
|
519
|
+
//checkMinMax("maxIndex");
|
|
520
|
+
if (count == 0) {
|
|
521
|
+
return -1;
|
|
522
|
+
}
|
|
523
|
+
int index = 0;
|
|
524
|
+
long value = values[0];
|
|
525
|
+
for (int i = 1; i < count; i++) {
|
|
526
|
+
if (values[i] > value) {
|
|
527
|
+
index = i;
|
|
528
|
+
value = values[i];
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return index;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
/** return the key corresponding to the maximum value or null if no entries */
|
|
536
|
+
public String maxKey() {
|
|
537
|
+
//checkMinMax("maxKey");
|
|
538
|
+
int index = maxIndex();
|
|
539
|
+
if (index == -1) {
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
return keys[index];
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
// return the maximum value or throw an error if zero length
|
|
547
|
+
public long maxValue() {
|
|
548
|
+
checkMinMax("maxIndex");
|
|
549
|
+
return values[maxIndex()];
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
public long sum() {
|
|
554
|
+
long sum = 0;
|
|
555
|
+
for (int i = 0; i < count; i++) {
|
|
556
|
+
sum += values[i];
|
|
557
|
+
}
|
|
558
|
+
return sum;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
public int index(String what) {
|
|
563
|
+
Integer found = indices.get(what);
|
|
564
|
+
return (found == null) ? -1 : found.intValue();
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
protected void create(String what, long much) {
|
|
569
|
+
if (count == keys.length) {
|
|
570
|
+
keys = PApplet.expand(keys);
|
|
571
|
+
values = PApplet.expand(values);
|
|
572
|
+
}
|
|
573
|
+
indices.put(what, Integer.valueOf(count));
|
|
574
|
+
keys[count] = what;
|
|
575
|
+
values[count] = much;
|
|
576
|
+
count++;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* @webref intdict:method
|
|
582
|
+
* @brief Remove a key/value pair
|
|
583
|
+
*/
|
|
584
|
+
public long remove(String key) {
|
|
585
|
+
int index = index(key);
|
|
586
|
+
if (index == -1) {
|
|
587
|
+
throw new NoSuchElementException("'" + key + "' not found");
|
|
588
|
+
}
|
|
589
|
+
long value = values[index];
|
|
590
|
+
removeIndex(index);
|
|
591
|
+
return value;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
public long removeIndex(int index) {
|
|
596
|
+
if (index < 0 || index >= count) {
|
|
597
|
+
throw new ArrayIndexOutOfBoundsException(index);
|
|
598
|
+
}
|
|
599
|
+
long value = values[index];
|
|
600
|
+
indices.remove(keys[index]);
|
|
601
|
+
for (int i = index; i < count-1; i++) {
|
|
602
|
+
keys[i] = keys[i+1];
|
|
603
|
+
values[i] = values[i+1];
|
|
604
|
+
indices.put(keys[i], i);
|
|
605
|
+
}
|
|
606
|
+
count--;
|
|
607
|
+
keys[count] = null;
|
|
608
|
+
values[count] = 0;
|
|
609
|
+
return value;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
public void swap(int a, int b) {
|
|
614
|
+
String tkey = keys[a];
|
|
615
|
+
long tvalue = values[a];
|
|
616
|
+
keys[a] = keys[b];
|
|
617
|
+
values[a] = values[b];
|
|
618
|
+
keys[b] = tkey;
|
|
619
|
+
values[b] = tvalue;
|
|
620
|
+
|
|
621
|
+
// indices.put(keys[a], Integer.valueOf(a));
|
|
622
|
+
// indices.put(keys[b], Integer.valueOf(b));
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Sort the keys alphabetically (ignoring case). Uses the value as a
|
|
628
|
+
* tie-breaker (only really possible with a key that has a case change).
|
|
629
|
+
*
|
|
630
|
+
* @webref intdict:method
|
|
631
|
+
* @brief Sort the keys alphabetically
|
|
632
|
+
*/
|
|
633
|
+
public void sortKeys() {
|
|
634
|
+
sortImpl(true, false, true);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Sort the keys alphabetically in reverse (ignoring case). Uses the value as a
|
|
639
|
+
* tie-breaker (only really possible with a key that has a case change).
|
|
640
|
+
*
|
|
641
|
+
* @webref intdict:method
|
|
642
|
+
* @brief Sort the keys alphabetically in reverse
|
|
643
|
+
*/
|
|
644
|
+
public void sortKeysReverse() {
|
|
645
|
+
sortImpl(true, true, true);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Sort by values in ascending order. The smallest value will be at [0].
|
|
651
|
+
*
|
|
652
|
+
* @webref intdict:method
|
|
653
|
+
* @brief Sort by values in ascending order
|
|
654
|
+
*/
|
|
655
|
+
public void sortValues() {
|
|
656
|
+
sortValues(true);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Set true to ensure that the order returned is identical. Slightly
|
|
662
|
+
* slower because the tie-breaker for identical values compares the keys.
|
|
663
|
+
* @param stable
|
|
664
|
+
*/
|
|
665
|
+
public void sortValues(boolean stable) {
|
|
666
|
+
sortImpl(false, false, stable);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Sort by values in descending order. The largest value will be at [0].
|
|
672
|
+
*
|
|
673
|
+
* @webref intdict:method
|
|
674
|
+
* @brief Sort by values in descending order
|
|
675
|
+
*/
|
|
676
|
+
public void sortValuesReverse() {
|
|
677
|
+
sortValuesReverse(true);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
public void sortValuesReverse(boolean stable) {
|
|
682
|
+
sortImpl(false, true, stable);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
protected void sortImpl(final boolean useKeys, final boolean reverse,
|
|
687
|
+
final boolean stable) {
|
|
688
|
+
Sort s = new Sort() {
|
|
689
|
+
@Override
|
|
690
|
+
public int size() {
|
|
691
|
+
return count;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
@Override
|
|
695
|
+
public int compare(int a, int b) {
|
|
696
|
+
long diff = 0;
|
|
697
|
+
if (useKeys) {
|
|
698
|
+
diff = keys[a].compareToIgnoreCase(keys[b]);
|
|
699
|
+
if (diff == 0) {
|
|
700
|
+
diff = values[a] - values[b];
|
|
701
|
+
}
|
|
702
|
+
} else { // sort values
|
|
703
|
+
diff = values[a] - values[b];
|
|
704
|
+
if (diff == 0 && stable) {
|
|
705
|
+
diff = keys[a].compareToIgnoreCase(keys[b]);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (diff == 0) {
|
|
709
|
+
return 0;
|
|
710
|
+
} else if (reverse) {
|
|
711
|
+
return diff < 0 ? 1 : -1;
|
|
712
|
+
} else {
|
|
713
|
+
return diff < 0 ? -1 : 1;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
@Override
|
|
718
|
+
public void swap(int a, int b) {
|
|
719
|
+
LongDict.this.swap(a, b);
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
s.run();
|
|
723
|
+
|
|
724
|
+
// Set the indices after sort/swaps (performance fix 160411)
|
|
725
|
+
resetIndices();
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Sum all of the values in this dictionary, then return a new FloatDict of
|
|
731
|
+
* each key, divided by the total sum. The total for all values will be ~1.0.
|
|
732
|
+
* @return an IntDict with the original keys, mapped to their pct of the total
|
|
733
|
+
*/
|
|
734
|
+
public FloatDict getPercent() {
|
|
735
|
+
double sum = sum(); // a little more accuracy
|
|
736
|
+
FloatDict outgoing = new FloatDict();
|
|
737
|
+
for (int i = 0; i < size(); i++) {
|
|
738
|
+
double percent = value(i) / sum;
|
|
739
|
+
outgoing.set(key(i), (float) percent);
|
|
740
|
+
}
|
|
741
|
+
return outgoing;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
/** Returns a duplicate copy of this object. */
|
|
746
|
+
public LongDict copy() {
|
|
747
|
+
LongDict outgoing = new LongDict(count);
|
|
748
|
+
System.arraycopy(keys, 0, outgoing.keys, 0, count);
|
|
749
|
+
System.arraycopy(values, 0, outgoing.values, 0, count);
|
|
750
|
+
for (int i = 0; i < count; i++) {
|
|
751
|
+
outgoing.indices.put(keys[i], i);
|
|
752
|
+
}
|
|
753
|
+
outgoing.count = count;
|
|
754
|
+
return outgoing;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
public void print() {
|
|
759
|
+
for (int i = 0; i < size(); i++) {
|
|
760
|
+
System.out.println(keys[i] + " = " + values[i]);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Save tab-delimited entries to a file (TSV format, UTF-8 encoding)
|
|
767
|
+
*/
|
|
768
|
+
public void save(File file) {
|
|
769
|
+
PrintWriter writer = PApplet.createWriter(file);
|
|
770
|
+
write(writer);
|
|
771
|
+
writer.close();
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Write tab-delimited entries to a PrintWriter
|
|
777
|
+
*/
|
|
778
|
+
public void write(PrintWriter writer) {
|
|
779
|
+
for (int i = 0; i < count; i++) {
|
|
780
|
+
writer.println(keys[i] + "\t" + values[i]);
|
|
781
|
+
}
|
|
782
|
+
writer.flush();
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Return this dictionary as a String in JSON format.
|
|
788
|
+
*/
|
|
789
|
+
public String toJSON() {
|
|
790
|
+
StringList items = new StringList();
|
|
791
|
+
for (int i = 0; i < count; i++) {
|
|
792
|
+
items.append(JSONObject.quote(keys[i])+ ": " + values[i]);
|
|
793
|
+
}
|
|
794
|
+
return "{ " + items.join(", ") + " }";
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
@Override
|
|
799
|
+
public String toString() {
|
|
800
|
+
return getClass().getSimpleName() + " size=" + size() + " " + toJSON();
|
|
801
|
+
}
|
|
802
|
+
}
|