propane 3.8.0-java → 4.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +1 -1
  3. data/.mvn/wrapper/maven-wrapper.properties +1 -1
  4. data/.travis.yml +1 -1
  5. data/CHANGELOG.md +7 -1
  6. data/README.md +7 -7
  7. data/Rakefile +6 -5
  8. data/lib/propane/app.rb +10 -17
  9. data/lib/propane/helper_methods.rb +6 -6
  10. data/lib/propane/version.rb +1 -1
  11. data/lib/propane-4.0.0.jar +0 -0
  12. data/library/pdf/itextpdf-5.5.13.2.jar +0 -0
  13. data/library/pdf/pdf.rb +7 -0
  14. data/library/slider/slider.rb +1 -1
  15. data/library/svg/batik-all-1.14.jar +0 -0
  16. data/library/svg/svg.rb +7 -0
  17. data/mvnw +3 -3
  18. data/mvnw.cmd +2 -2
  19. data/pom.rb +35 -8
  20. data/pom.xml +60 -9
  21. data/propane.gemspec +9 -7
  22. data/src/main/java/monkstone/ColorUtil.java +1 -1
  23. data/src/main/java/monkstone/FastNoiseModuleJava.java +127 -0
  24. data/src/main/java/monkstone/MathToolModule.java +31 -31
  25. data/src/main/java/monkstone/PropaneLibrary.java +3 -1
  26. data/src/main/java/monkstone/SmoothNoiseModuleJava.java +127 -0
  27. data/src/main/java/monkstone/fastmath/DegLutTables.java +25 -26
  28. data/src/main/java/monkstone/fastmath/Deglut.java +1 -1
  29. data/src/main/java/monkstone/filechooser/Chooser.java +2 -2
  30. data/src/main/java/monkstone/noise/LICENSE +121 -0
  31. data/src/main/java/monkstone/noise/OpenSimplex2F.java +914 -0
  32. data/src/main/java/monkstone/noise/OpenSimplex2S.java +1138 -0
  33. data/src/main/java/monkstone/slider/CustomHorizontalSlider.java +1 -1
  34. data/src/main/java/monkstone/slider/CustomVerticalSlider.java +1 -1
  35. data/src/main/java/monkstone/slider/SimpleHorizontalSlider.java +1 -1
  36. data/src/main/java/monkstone/slider/SimpleVerticalSlider.java +1 -1
  37. data/src/main/java/monkstone/slider/SliderBar.java +1 -1
  38. data/src/main/java/monkstone/slider/SliderGroup.java +1 -1
  39. data/src/main/java/monkstone/slider/WheelHandler.java +2 -2
  40. data/src/main/java/monkstone/vecmath/JRender.java +6 -6
  41. data/src/main/java/monkstone/vecmath/package-info.java +1 -1
  42. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +103 -83
  43. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +27 -41
  44. data/src/main/java/monkstone/videoevent/CaptureEvent.java +1 -1
  45. data/src/main/java/monkstone/videoevent/MovieEvent.java +1 -1
  46. data/src/main/java/monkstone/videoevent/package-info.java +1 -1
  47. data/src/main/java/processing/awt/PGraphicsJava2D.java +11 -4
  48. data/src/main/java/processing/awt/PImageAWT.java +8 -8
  49. data/src/main/java/processing/core/PApplet.java +245 -254
  50. data/src/main/java/processing/core/PConstants.java +155 -163
  51. data/src/main/java/processing/core/PGraphics.java +116 -109
  52. data/src/main/java/processing/core/PImage.java +3025 -3047
  53. data/src/main/java/processing/core/PMatrix.java +5 -2
  54. data/src/main/java/processing/data/DoubleDict.java +72 -43
  55. data/src/main/java/processing/data/DoubleList.java +6 -2
  56. data/src/main/java/processing/data/FloatDict.java +744 -756
  57. data/src/main/java/processing/data/FloatList.java +68 -26
  58. data/src/main/java/processing/data/IntDict.java +72 -45
  59. data/src/main/java/processing/data/IntList.java +63 -26
  60. data/src/main/java/processing/data/JSONArray.java +892 -931
  61. data/src/main/java/processing/data/JSONObject.java +1169 -1262
  62. data/src/main/java/processing/data/JSONTokener.java +30 -49
  63. data/src/main/java/processing/data/LongDict.java +699 -712
  64. data/src/main/java/processing/data/LongList.java +676 -700
  65. data/src/main/java/processing/data/Sort.java +1 -0
  66. data/src/main/java/processing/data/Table.java +4040 -3661
  67. data/src/main/java/processing/data/TableRow.java +16 -0
  68. data/src/main/java/processing/data/XML.java +1041 -956
  69. data/src/main/java/processing/event/TouchEvent.java +1 -1
  70. data/src/main/java/processing/opengl/FontTexture.java +2 -2
  71. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +28 -31
  72. data/src/main/java/processing/opengl/PJOGL.java +8 -7
  73. data/src/main/java/processing/opengl/PShader.java +1 -6
  74. data/src/main/java/processing/opengl/PShapeOpenGL.java +23 -24
  75. data/src/main/java/processing/opengl/PSurfaceJOGL.java +6 -6
  76. data/src/main/java/processing/pdf/PGraphicsPDF.java +581 -0
  77. data/src/main/java/processing/svg/PGraphicsSVG.java +378 -0
  78. data/src/main/{java/processing/opengl → resources}/cursors/arrow.png +0 -0
  79. data/src/main/{java/processing/opengl → resources}/cursors/cross.png +0 -0
  80. data/src/main/{java/processing/opengl → resources}/cursors/hand.png +0 -0
  81. data/src/main/{java/processing/opengl → resources}/cursors/license.txt +0 -0
  82. data/src/main/{java/processing/opengl → resources}/cursors/move.png +0 -0
  83. data/src/main/{java/processing/opengl → resources}/cursors/text.png +0 -0
  84. data/src/main/{java/processing/opengl → resources}/cursors/wait.png +0 -0
  85. data/src/main/{java/processing/opengl → resources}/shaders/ColorFrag.glsl +0 -0
  86. data/src/main/{java/processing/opengl → resources}/shaders/ColorVert.glsl +0 -0
  87. data/src/main/{java/processing/opengl → resources}/shaders/LightFrag.glsl +0 -0
  88. data/src/main/{java/processing/opengl → resources}/shaders/LightVert.glsl +0 -0
  89. data/src/main/{java/processing/opengl → resources}/shaders/LineFrag.glsl +0 -0
  90. data/src/main/{java/processing/opengl → resources}/shaders/LineVert.glsl +0 -0
  91. data/src/main/{java/processing/opengl → resources}/shaders/MaskFrag.glsl +0 -0
  92. data/src/main/{java/processing/opengl → resources}/shaders/PointFrag.glsl +0 -0
  93. data/src/main/{java/processing/opengl → resources}/shaders/PointVert.glsl +0 -0
  94. data/src/main/{java/processing/opengl → resources}/shaders/TexFrag.glsl +0 -0
  95. data/src/main/{java/processing/opengl → resources}/shaders/TexLightFrag.glsl +0 -0
  96. data/src/main/{java/processing/opengl → resources}/shaders/TexLightVert.glsl +0 -0
  97. data/src/main/{java/processing/opengl → resources}/shaders/TexVert.glsl +0 -0
  98. data/test/test_helper.rb +1 -0
  99. data/test/vecmath_spec_test.rb +14 -3
  100. data/vendors/Rakefile +1 -1
  101. metadata +53 -53
  102. data/lib/propane-3.8.0.jar +0 -0
  103. data/src/main/java/monkstone/noise/Noise.java +0 -116
  104. data/src/main/java/monkstone/noise/NoiseGenerator.java +0 -63
  105. data/src/main/java/monkstone/noise/NoiseMode.java +0 -15
  106. data/src/main/java/monkstone/noise/SimplexNoise.java +0 -470
  107. data/src/main/java/monkstone/noise/ValueNoise.java +0 -170
@@ -7,7 +7,6 @@ import java.util.NoSuchElementException;
7
7
 
8
8
  import processing.core.PApplet;
9
9
 
10
-
11
10
  /**
12
11
  * A simple class to use a String as a lookup for an int value.
13
12
  *
@@ -17,786 +16,774 @@ import processing.core.PApplet;
17
16
  */
18
17
  public class LongDict {
19
18
 
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");
19
+ /**
20
+ * Number of elements in the table
21
+ */
22
+ protected int count;
23
+
24
+ protected String[] keys;
25
+ protected long[] values;
26
+
27
+ /**
28
+ * Internal implementation for faster lookups
29
+ */
30
+ private HashMap<String, Integer> indices = new HashMap<>();
31
+
32
+ public LongDict() {
33
+ count = 0;
34
+ keys = new String[10];
35
+ values = new long[10];
36
+ }
37
+
38
+ /**
39
+ * Create a new lookup with a specific size.This is more efficient than not
40
+ * specifying a size. Use it when you know the rough size of the thing
41
+ * you're creating.
42
+ *
43
+ * @param length
44
+ * @nowebref
45
+ */
46
+ public LongDict(int length) {
47
+ count = 0;
48
+ keys = new String[length];
49
+ values = new long[length];
50
+ }
51
+
52
+ /**
53
+ * Read a set of entries from a Reader that has each key/value pair on a
54
+ * single line, separated by a tab.
55
+ *
56
+ * @param reader
57
+ * @nowebref
58
+ */
59
+ public LongDict(BufferedReader reader) {
60
+ String[] lines = PApplet.loadStrings(reader);
61
+ keys = new String[lines.length];
62
+ values = new long[lines.length];
63
+
64
+ for (String line : lines) {
65
+ String[] pieces = PApplet.split(line, '\t');
66
+ if (pieces.length == 2) {
67
+ keys[count] = pieces[0];
68
+ values[count] = PApplet.parseInt(pieces[1]);
69
+ indices.put(pieces[0], count);
70
+ count++;
71
+ }
72
+ }
78
73
  }
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
74
 
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);
75
+ /**
76
+ * @param keys
77
+ * @param values
78
+ * @nowebref
79
+ */
80
+ public LongDict(String[] keys, long[] values) {
81
+ if (keys.length != values.length) {
82
+ throw new IllegalArgumentException("key and value arrays must be the same length");
83
+ }
84
+ this.keys = keys;
85
+ this.values = values;
86
+ count = keys.length;
87
+ for (int i = 0; i < count; i++) {
88
+ indices.put(keys[i], i);
89
+ }
105
90
  }
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
91
 
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");
92
+ /**
93
+ * Constructor to allow (more intuitive) inline initialization, e.g.:
94
+ * <pre>
95
+ * new FloatDict(new Object[][] {
96
+ * { "key1", 1 },
97
+ * { "key2", 2 }
98
+ * });
99
+ * </pre>
100
+ *
101
+ * @param pairs
102
+ */
103
+ public LongDict(Object[][] pairs) {
104
+ count = pairs.length;
105
+ this.keys = new String[count];
106
+ this.values = new long[count];
107
+ for (int i = 0; i < count; i++) {
108
+ keys[i] = (String) pairs[i][0];
109
+ values[i] = (Integer) pairs[i][1];
110
+ indices.put(keys[i], i);
111
+ }
130
112
  }
131
113
 
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);
114
+ /**
115
+ * Returns the number of key/value pairs
116
+ *
117
+ * @return
118
+ * @webref intdict:method
119
+ * @brief Returns the number of key/value pairs
120
+ */
121
+ public int size() {
122
+ return count;
159
123
  }
160
- }
161
-
162
-
163
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
164
-
165
124
 
166
- public class Entry {
167
- public String key;
168
- public long value;
125
+ /**
126
+ * Resize the internal data, this can only be used to shrink the
127
+ * list.Helpful for situations like sorting and then grabbing the top 50
128
+ * entries.
129
+ *
130
+ * @param length
131
+ */
132
+ public void resize(int length) {
133
+ if (length > count) {
134
+ throw new IllegalArgumentException("resize() can only be used to shrink the dictionary");
135
+ }
136
+ if (length < 1) {
137
+ throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher");
138
+ }
169
139
 
170
- Entry(String key, long value) {
171
- this.key = key;
172
- this.value = value;
140
+ String[] newKeys = new String[length];
141
+ long[] newValues = new long[length];
142
+ PApplet.arrayCopy(keys, newKeys, length);
143
+ PApplet.arrayCopy(values, newValues, length);
144
+ keys = newKeys;
145
+ values = newValues;
146
+ count = length;
147
+ resetIndices();
148
+ }
149
+
150
+ /**
151
+ * Remove all entries.
152
+ *
153
+ * @webref intdict:method
154
+ * @brief Remove all entries
155
+ */
156
+ public void clear() {
157
+ count = 0;
158
+ indices = new HashMap<>();
159
+ }
160
+
161
+ private void resetIndices() {
162
+ indices = new HashMap<>(count);
163
+ for (int i = 0; i < count; i++) {
164
+ indices.put(keys[i], i);
165
+ }
173
166
  }
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
167
 
196
- public Entry next() {
197
- ++index;
198
- Entry e = new Entry(keys[index], values[index]);
199
- return e;
200
- }
168
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
169
+ public class Entry {
201
170
 
202
- public boolean hasNext() {
203
- return index+1 < size();
204
- }
205
- };
206
- }
171
+ public String key;
172
+ public long value;
207
173
 
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);
174
+ Entry(String key, long value) {
175
+ this.key = key;
176
+ this.value = value;
177
+ }
221
178
  }
222
- }
223
-
224
-
225
- public Iterable<String> keys() {
226
- return new Iterable<String>() {
227
179
 
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
- }
180
+ public Iterable<Entry> entries() {
181
+ return () -> entryIterator();
182
+ }
255
183
 
184
+ public Iterator<Entry> entryIterator() {
185
+ return new Iterator<Entry>() {
186
+ int index = -1;
256
187
 
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
- }
188
+ @Override
189
+ public void remove() {
190
+ removeIndex(index);
191
+ index--;
192
+ }
267
193
 
194
+ @Override
195
+ public Entry next() {
196
+ ++index;
197
+ Entry e = new Entry(keys[index], values[index]);
198
+ return e;
199
+ }
268
200
 
269
- public String[] keyArray(String[] outgoing) {
270
- if (outgoing == null || outgoing.length != count) {
271
- outgoing = new String[count];
201
+ @Override
202
+ public boolean hasNext() {
203
+ return index + 1 < size();
204
+ }
205
+ };
272
206
  }
273
- System.arraycopy(keys, 0, outgoing, 0, count);
274
- return outgoing;
275
- }
276
207
 
208
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
209
+ public String key(int index) {
210
+ return keys[index];
211
+ }
277
212
 
278
- public long value(int index) {
279
- return values[index];
280
- }
281
-
213
+ protected void crop() {
214
+ if (count != keys.length) {
215
+ keys = PApplet.subset(keys, 0, count);
216
+ values = PApplet.subset(values, 0, count);
217
+ }
218
+ }
282
219
 
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>() {
220
+ public Iterable<String> keys() {
221
+ return () -> keyIterator();
222
+ }
289
223
 
290
- @Override
291
- public Iterator<Long> iterator() {
292
- return valueIterator();
293
- }
294
- };
295
- }
224
+ // Use this to iterate when you want to be able to remove elements along the way
225
+ public Iterator<String> keyIterator() {
226
+ return new Iterator<String>() {
227
+ int index = -1;
296
228
 
229
+ @Override
230
+ public void remove() {
231
+ removeIndex(index);
232
+ index--;
233
+ }
297
234
 
298
- public Iterator<Long> valueIterator() {
299
- return new Iterator<Long>() {
300
- int index = -1;
235
+ @Override
236
+ public String next() {
237
+ return key(++index);
238
+ }
301
239
 
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;
240
+ @Override
241
+ public boolean hasNext() {
242
+ return index + 1 < size();
243
+ }
244
+ };
456
245
  }
457
- }
458
-
459
246
 
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;
247
+ /**
248
+ * Return a copy of the internal keys array.This array can be modified.
249
+ *
250
+ * @return
251
+ * @webref intdict:method
252
+ * @brief Return a copy of the internal keys array
253
+ */
254
+ public String[] keyArray() {
255
+ crop();
256
+ return keyArray(null);
468
257
  }
469
- }
470
258
 
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);
259
+ public String[] keyArray(String[] outgoing) {
260
+ if (outgoing == null || outgoing.length != count) {
261
+ outgoing = new String[count];
262
+ }
263
+ System.arraycopy(keys, 0, outgoing, 0, count);
264
+ return outgoing;
265
+ }
266
+
267
+ public long value(int index) {
268
+ return values[index];
269
+ }
270
+
271
+ /**
272
+ * @return
273
+ * @webref intdict:method
274
+ * @brief Return the internal array being used to store the values
275
+ */
276
+ public Iterable<Long> values() {
277
+ return () -> valueIterator();
278
+ }
279
+
280
+ public Iterator<Long> valueIterator() {
281
+ return new Iterator<Long>() {
282
+ int index = -1;
283
+
284
+ @Override
285
+ public void remove() {
286
+ removeIndex(index);
287
+ index--;
288
+ }
289
+
290
+ @Override
291
+ public Long next() {
292
+ return value(++index);
293
+ }
294
+
295
+ @Override
296
+ public boolean hasNext() {
297
+ return index + 1 < size();
298
+ }
299
+ };
300
+ }
301
+
302
+ /**
303
+ * Create a new array and copy each of the values into it.
304
+ *
305
+ * @return
306
+ * @webref intdict:method
307
+ * @brief Create a new array and copy each of the values into it
308
+ */
309
+ public int[] valueArray() {
310
+ crop();
311
+ return valueArray(null);
312
+ }
313
+
314
+ /**
315
+ * Fill an already-allocated array with the values (more efficient than
316
+ * creating a new array each time).If 'array' is null, or not the same size
317
+ as the number of values, a new array will be allocated and returned.
318
+ *
319
+ * @param array values to copy into the array
320
+ * @return
321
+ */
322
+ public int[] valueArray(int[] array) {
323
+ if (array == null || array.length != size()) {
324
+ array = new int[count];
325
+ }
326
+ System.arraycopy(values, 0, array, 0, count);
327
+ return array;
328
+ }
329
+
330
+ /**
331
+ * Return a value for the specified key.
332
+ *
333
+ * @param key
334
+ * @return
335
+ * @webref intdict:method
336
+ * @brief Return a value for the specified key
337
+ */
338
+ public long get(String key) {
339
+ int index = index(key);
340
+ if (index == -1) {
341
+ throw new IllegalArgumentException("No key named '" + key + "'");
342
+ }
343
+ return values[index];
478
344
  }
479
- }
480
345
 
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
- }
346
+ public long get(String key, long alternate) {
347
+ int index = index(key);
348
+ if (index == -1) {
349
+ return alternate;
350
+ }
351
+ return values[index];
352
+ }
353
+
354
+ /**
355
+ * Create a new key/value pair or change the value of one.
356
+ *
357
+ * @param key
358
+ * @param amount
359
+ * @webref intdict:method
360
+ * @brief Create a new key/value pair or change the value of one
361
+ */
362
+ public void set(String key, long amount) {
363
+ int index = index(key);
364
+ if (index == -1) {
365
+ create(key, amount);
366
+ } else {
367
+ values[index] = amount;
368
+ }
494
369
  }
495
- return index;
496
- }
497
370
 
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;
371
+ public void setIndex(int index, String key, long value) {
372
+ if (index < 0 || index >= count) {
373
+ throw new ArrayIndexOutOfBoundsException(index);
374
+ }
375
+ keys[index] = key;
376
+ values[index] = value;
377
+ }
378
+
379
+ /**
380
+ * @param key
381
+ * @return
382
+ * @webref intdict:method
383
+ * @brief Check if a key is a part of the data structure
384
+ */
385
+ public boolean hasKey(String key) {
386
+ return index(key) != -1;
387
+ }
388
+
389
+ /**
390
+ * Increase the value associated with a specific key by 1.
391
+ *
392
+ * @param key
393
+ * @webref intdict:method
394
+ * @brief Increase the value of a specific key value by 1
395
+ */
396
+ public void increment(String key) {
397
+ add(key, 1);
398
+ }
399
+
400
+ /**
401
+ * Merge another dictionary into this one.Calling this increment() since it
402
+ doesn't make sense in practice for the other dictionary types, even
403
+ though it's technically an add().
404
+ * @param dict
405
+ */
406
+ public void increment(LongDict dict) {
407
+ for (int i = 0; i < dict.count; i++) {
408
+ add(dict.key(i), dict.value(i));
409
+ }
505
410
  }
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
411
 
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
- }
412
+ /**
413
+ * @param key
414
+ * @param amount
415
+ * @webref intdict:method
416
+ * @brief Add to a value
417
+ */
418
+ public void add(String key, long amount) {
419
+ int index = index(key);
420
+ if (index == -1) {
421
+ create(key, amount);
422
+ } else {
423
+ values[index] += amount;
424
+ }
530
425
  }
531
- return index;
532
- }
533
-
534
426
 
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;
427
+ /**
428
+ * @param key
429
+ * @param amount
430
+ * @webref intdict:method
431
+ * @brief Subtract from a value
432
+ */
433
+ public void sub(String key, long amount) {
434
+ add(key, -amount);
435
+ }
436
+
437
+ /**
438
+ * @param key
439
+ * @param amount
440
+ * @webref intdict:method
441
+ * @brief Multiply a value
442
+ */
443
+ public void mult(String key, long amount) {
444
+ int index = index(key);
445
+ if (index != -1) {
446
+ values[index] *= amount;
447
+ }
541
448
  }
542
- return keys[index];
543
- }
544
449
 
450
+ /**
451
+ * @param key
452
+ * @param amount
453
+ * @webref intdict:method
454
+ * @brief Divide a value
455
+ */
456
+ public void div(String key, long amount) {
457
+ int index = index(key);
458
+ if (index != -1) {
459
+ values[index] /= amount;
460
+ }
461
+ }
545
462
 
546
- // return the maximum value or throw an error if zero length
547
- public long maxValue() {
548
- checkMinMax("maxIndex");
549
- return values[maxIndex()];
550
- }
463
+ private void checkMinMax(String functionName) {
464
+ if (count == 0) {
465
+ String msg
466
+ = String.format("Cannot use %s() on an empty %s.",
467
+ functionName, getClass().getSimpleName());
468
+ throw new RuntimeException(msg);
469
+ }
470
+ }
551
471
 
472
+ // return the index of the minimum value
473
+ public int minIndex() {
474
+ //checkMinMax("minIndex");
475
+ if (count == 0) {
476
+ return -1;
477
+ }
552
478
 
553
- public long sum() {
554
- long sum = 0;
555
- for (int i = 0; i < count; i++) {
556
- sum += values[i];
479
+ int index = 0;
480
+ long value = values[0];
481
+ for (int i = 1; i < count; i++) {
482
+ if (values[i] < value) {
483
+ index = i;
484
+ value = values[i];
485
+ }
486
+ }
487
+ return index;
557
488
  }
558
- return sum;
559
- }
560
489
 
490
+ // return the key for the minimum value
491
+ public String minKey() {
492
+ checkMinMax("minKey");
493
+ int index = minIndex();
494
+ if (index == -1) {
495
+ return null;
496
+ }
497
+ return keys[index];
498
+ }
561
499
 
562
- public int index(String what) {
563
- Integer found = indices.get(what);
564
- return (found == null) ? -1 : found.intValue();
565
- }
566
-
500
+ // return the minimum value, or throw an error if there are no values
501
+ public long minValue() {
502
+ checkMinMax("minValue");
503
+ return values[minIndex()];
504
+ }
567
505
 
568
- protected void create(String what, long much) {
569
- if (count == keys.length) {
570
- keys = PApplet.expand(keys);
571
- values = PApplet.expand(values);
506
+ // return the index of the max value
507
+ public int maxIndex() {
508
+ //checkMinMax("maxIndex");
509
+ if (count == 0) {
510
+ return -1;
511
+ }
512
+ int index = 0;
513
+ long value = values[0];
514
+ for (int i = 1; i < count; i++) {
515
+ if (values[i] > value) {
516
+ index = i;
517
+ value = values[i];
518
+ }
519
+ }
520
+ return index;
521
+ }
522
+
523
+ /**
524
+ * return the key corresponding to the maximum value or null if no entries
525
+ * @return
526
+ */
527
+ public String maxKey() {
528
+ //checkMinMax("maxKey");
529
+ int index = maxIndex();
530
+ if (index == -1) {
531
+ return null;
532
+ }
533
+ return keys[index];
572
534
  }
573
- indices.put(what, Integer.valueOf(count));
574
- keys[count] = what;
575
- values[count] = much;
576
- count++;
577
- }
578
535
 
536
+ // return the maximum value or throw an error if zero length
537
+ public long maxValue() {
538
+ checkMinMax("maxIndex");
539
+ return values[maxIndex()];
540
+ }
579
541
 
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");
542
+ public long sum() {
543
+ long sum = 0;
544
+ for (int i = 0; i < count; i++) {
545
+ sum += values[i];
546
+ }
547
+ return sum;
588
548
  }
589
- long value = values[index];
590
- removeIndex(index);
591
- return value;
592
- }
593
549
 
550
+ public int index(String what) {
551
+ Integer found = indices.get(what);
552
+ return (found == null) ? -1 : found;
553
+ }
594
554
 
595
- public long removeIndex(int index) {
596
- if (index < 0 || index >= count) {
597
- throw new ArrayIndexOutOfBoundsException(index);
555
+ protected void create(String what, long much) {
556
+ if (count == keys.length) {
557
+ keys = PApplet.expand(keys);
558
+ values = PApplet.expand(values);
559
+ }
560
+ indices.put(what, count);
561
+ keys[count] = what;
562
+ values[count] = much;
563
+ count++;
598
564
  }
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);
565
+
566
+ /**
567
+ * @param key
568
+ * @return
569
+ * @webref intdict:method
570
+ * @brief Remove a key/value pair
571
+ */
572
+ public long remove(String key) {
573
+ int index = index(key);
574
+ if (index == -1) {
575
+ throw new NoSuchElementException("'" + key + "' not found");
576
+ }
577
+ long value = values[index];
578
+ removeIndex(index);
579
+ return value;
605
580
  }
606
- count--;
607
- keys[count] = null;
608
- values[count] = 0;
609
- return value;
610
- }
611
581
 
582
+ public long removeIndex(int index) {
583
+ if (index < 0 || index >= count) {
584
+ throw new ArrayIndexOutOfBoundsException(index);
585
+ }
586
+ long value = values[index];
587
+ indices.remove(keys[index]);
588
+ for (int i = index; i < count - 1; i++) {
589
+ keys[i] = keys[i + 1];
590
+ values[i] = values[i + 1];
591
+ indices.put(keys[i], i);
592
+ }
593
+ count--;
594
+ keys[count] = null;
595
+ values[count] = 0;
596
+ return value;
597
+ }
612
598
 
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;
599
+ public void swap(int a, int b) {
600
+ String tkey = keys[a];
601
+ long tvalue = values[a];
602
+ keys[a] = keys[b];
603
+ values[a] = values[b];
604
+ keys[b] = tkey;
605
+ values[b] = tvalue;
620
606
 
621
607
  // indices.put(keys[a], Integer.valueOf(a));
622
608
  // 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
609
  }
741
- return outgoing;
742
- }
743
610
 
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);
611
+ /**
612
+ * Sort the keys alphabetically (ignoring case). Uses the value as a
613
+ * tie-breaker (only really possible with a key that has a case change).
614
+ *
615
+ * @webref intdict:method
616
+ * @brief Sort the keys alphabetically
617
+ */
618
+ public void sortKeys() {
619
+ sortImpl(true, false, true);
620
+ }
621
+
622
+ /**
623
+ * Sort the keys alphabetically in reverse (ignoring case). Uses the value
624
+ * as a tie-breaker (only really possible with a key that has a case
625
+ * change).
626
+ *
627
+ * @webref intdict:method
628
+ * @brief Sort the keys alphabetically in reverse
629
+ */
630
+ public void sortKeysReverse() {
631
+ sortImpl(true, true, true);
632
+ }
633
+
634
+ /**
635
+ * Sort by values in ascending order. The smallest value will be at [0].
636
+ *
637
+ * @webref intdict:method
638
+ * @brief Sort by values in ascending order
639
+ */
640
+ public void sortValues() {
641
+ sortValues(true);
642
+ }
643
+
644
+ /**
645
+ * Set true to ensure that the order returned is identical. Slightly slower
646
+ * because the tie-breaker for identical values compares the keys.
647
+ *
648
+ * @param stable
649
+ */
650
+ public void sortValues(boolean stable) {
651
+ sortImpl(false, false, stable);
652
+ }
653
+
654
+ /**
655
+ * Sort by values in descending order. The largest value will be at [0].
656
+ *
657
+ * @webref intdict:method
658
+ * @brief Sort by values in descending order
659
+ */
660
+ public void sortValuesReverse() {
661
+ sortValuesReverse(true);
662
+ }
663
+
664
+ public void sortValuesReverse(boolean stable) {
665
+ sortImpl(false, true, stable);
666
+ }
667
+
668
+ protected void sortImpl(final boolean useKeys, final boolean reverse,
669
+ final boolean stable) {
670
+ Sort s = new Sort() {
671
+ @Override
672
+ public int size() {
673
+ return count;
674
+ }
675
+
676
+ @Override
677
+ public int compare(int a, int b) {
678
+ long diff = 0;
679
+ if (useKeys) {
680
+ diff = keys[a].compareToIgnoreCase(keys[b]);
681
+ if (diff == 0) {
682
+ diff = values[a] - values[b];
683
+ }
684
+ } else { // sort values
685
+ diff = values[a] - values[b];
686
+ if (diff == 0 && stable) {
687
+ diff = keys[a].compareToIgnoreCase(keys[b]);
688
+ }
689
+ }
690
+ if (diff == 0) {
691
+ return 0;
692
+ } else if (reverse) {
693
+ return diff < 0 ? 1 : -1;
694
+ } else {
695
+ return diff < 0 ? -1 : 1;
696
+ }
697
+ }
698
+
699
+ @Override
700
+ public void swap(int a, int b) {
701
+ LongDict.this.swap(a, b);
702
+ }
703
+ };
704
+ s.run();
705
+
706
+ // Set the indices after sort/swaps (performance fix 160411)
707
+ resetIndices();
708
+ }
709
+
710
+ /**
711
+ * Sum all of the values in this dictionary, then return a new FloatDict of
712
+ * each key, divided by the total sum. The total for all values will be
713
+ * ~1.0.
714
+ *
715
+ * @return an IntDict with the original keys, mapped to their pct of the
716
+ * total
717
+ */
718
+ public FloatDict getPercent() {
719
+ double sum = sum(); // a little more accuracy
720
+ FloatDict outgoing = new FloatDict();
721
+ for (int i = 0; i < size(); i++) {
722
+ double percent = value(i) / sum;
723
+ outgoing.set(key(i), (float) percent);
724
+ }
725
+ return outgoing;
726
+ }
727
+
728
+ /**
729
+ * Returns a duplicate copy of this object.
730
+ *
731
+ * @return
732
+ */
733
+ public LongDict copy() {
734
+ LongDict outgoing = new LongDict(count);
735
+ System.arraycopy(keys, 0, outgoing.keys, 0, count);
736
+ System.arraycopy(values, 0, outgoing.values, 0, count);
737
+ for (int i = 0; i < count; i++) {
738
+ outgoing.indices.put(keys[i], i);
739
+ }
740
+ outgoing.count = count;
741
+ return outgoing;
752
742
  }
753
- outgoing.count = count;
754
- return outgoing;
755
- }
756
-
757
743
 
758
- public void print() {
759
- for (int i = 0; i < size(); i++) {
760
- System.out.println(keys[i] + " = " + values[i]);
744
+ public void print() {
745
+ for (int i = 0; i < size(); i++) {
746
+ System.out.println(keys[i] + " = " + values[i]);
747
+ }
761
748
  }
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
749
 
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]);
750
+ /**
751
+ * Save tab-delimited entries to a file (TSV format, UTF-8 encoding)
752
+ * @param file
753
+ */
754
+ public void save(File file) {
755
+ try (PrintWriter writer = PApplet.createWriter(file)) {
756
+ write(writer);
757
+ }
781
758
  }
782
- writer.flush();
783
- }
784
759
 
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]);
760
+ /**
761
+ * Write tab-delimited entries to a PrintWriter
762
+ *
763
+ * @param writer
764
+ */
765
+ public void write(PrintWriter writer) {
766
+ for (int i = 0; i < count; i++) {
767
+ writer.println(keys[i] + "\t" + values[i]);
768
+ }
769
+ writer.flush();
770
+ }
771
+
772
+ /**
773
+ * Return this dictionary as a String in JSON format.
774
+ *
775
+ * @return
776
+ */
777
+ public String toJSON() {
778
+ StringList items = new StringList();
779
+ for (int i = 0; i < count; i++) {
780
+ items.append(JSONObject.quote(keys[i]) + ": " + values[i]);
781
+ }
782
+ return "{ " + items.join(", ") + " }";
793
783
  }
794
- return "{ " + items.join(", ") + " }";
795
- }
796
-
797
784
 
798
- @Override
799
- public String toString() {
800
- return getClass().getSimpleName() + " size=" + size() + " " + toJSON();
801
- }
785
+ @Override
786
+ public String toString() {
787
+ return getClass().getSimpleName() + " size=" + size() + " " + toJSON();
788
+ }
802
789
  }