You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/05/19 14:08:18 UTC
[1/7] groovy git commit: GROOVY-8379: Rework groovy-json
FastStringUtils (closes #667)
Repository: groovy
Updated Branches:
refs/heads/GROOVY_2_5_X 3fbd0b6f6 -> 25e2a3866
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy
new file mode 100644
index 0000000..607ad73
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/LazyMapTest.groovy
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal
+
+class LazyMapTest extends GroovyTestCase {
+
+ // GROOVY-7302
+ void testSizeWhenNoBackingMapCreated() {
+ def map = new LazyMap()
+ map.someProperty = "1"
+ map.someProperty = "2"
+ map.someProperty = "3"
+ assert map.size() == 1
+ map.someProperty2 = "4"
+ assert map.size() == 2
+ }
+
+ void testSizeWhenLazyCreated() {
+ def map = new LazyMap()
+ map.someProperty1 = '1'
+ assert map.@map == null
+ map.someProperty2 = '2'
+ assert map.@map == null
+ map.someProperty3 = '3'
+ assert map.@map == null
+ map.someProperty4 = '4'
+ assert map.@map == null
+ map.someProperty5 = '5'
+ assert map.@map == null
+ map.someProperty6 = '6'
+ assert map.@map == null
+ map.someProperty7 = '7'
+ assert map.someProperty6 == '6'
+ assert map.@map?.size() == 7
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy
new file mode 100644
index 0000000..f45a0ef
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ReaderCharacterSourceTest.groovy
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal
+
+import org.apache.groovy.json.internal.Exceptions.JsonInternalException
+
+class ReaderCharacterSourceTest extends GroovyTestCase {
+
+ public static final int QUOTE_CHAR = (int)'"'.charAt(0)
+ public static final int BACKSLASH_CHAR = (int)'\\'.charAt(0)
+
+ void testFindNextChar() {
+ def testCases = [
+ [ input: '""', expected: '' ],
+ [ input: '"word"', expected: 'word' ],
+ [ input: '"\\u0026value"', expected: '\\u0026value' ],
+ [ input: '"value\\u0026"', expected: 'value\\u0026' ],
+ [ input: '"double\\"quote"', expected: 'double\\"quote' ],
+ [ input: '"\\"\\"\\"\\""', expected: '\\"\\"\\"\\"' ],
+ [ input: '"\\\\\\\\\\\\"', expected: '\\\\\\\\\\\\' ]
+ ]
+
+ testCases.each {
+ boolean containsEscape = it.input.contains('\\')
+ // Test all possible buffer sizes
+ for (int i = 1; i < it.input.length() + 1; i++) {
+ ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader(it.input), i)
+ rcs.nextChar() // Read the first double quote as if JSON parsing
+
+ String result = new String(rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR))
+
+ assertEquals("Buffer size ${i}", it.expected, result)
+ assertEquals("Expected escape character in ${it.input}, buffer size ${i}", containsEscape, rcs.hadEscape())
+ }
+ }
+ }
+
+ void testFindNextCharException() {
+ shouldFail(JsonInternalException) {
+ ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote'))
+ rcs.nextChar() // Read the first double quote as if JSON parsing
+ rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
+ }
+ }
+
+ void testFindNextCharExceptionWithEscapedEnding() {
+ shouldFail(JsonInternalException) {
+ ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote ending with escape \\'))
+ rcs.nextChar() // Read the first double quote as if JSON parsing
+ rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
+ }
+ }
+
+ void testFindNextCharExceptionWithEscapedQuote() {
+ shouldFail(JsonInternalException) {
+ ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote with escaped quote \\"'))
+ rcs.nextChar() // Read the first double quote as if JSON parsing
+ rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
+ }
+ }
+}
[7/7] groovy git commit: GROOVY-8379: Rework groovy-json
FastStringUtils (closes #667)
Posted by pa...@apache.org.
GROOVY-8379: Rework groovy-json FastStringUtils (closes #667)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/25e2a386
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/25e2a386
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/25e2a386
Branch: refs/heads/GROOVY_2_5_X
Commit: 25e2a3866de4d11a3d9681863db3c19fef91fd22
Parents: 3fbd0b6
Author: paulk <pa...@asert.com.au>
Authored: Sun Feb 25 20:11:03 2018 +1000
Committer: Paul King <pa...@asert.com.au>
Committed: Sun May 20 00:08:03 2018 +1000
----------------------------------------------------------------------
gradle/binarycompatibility.gradle | 2 +-
settings.gradle | 1 +
subprojects/groovy-json-direct/build.gradle | 22 +
.../jsondirect/DirectFastStringService.java | 47 ++
.../DirectFastStringServiceFactory.java | 86 ++
....apache.groovy.json.FastStringServiceFactory | 19 +
.../DirectFastStringServiceTest.groovy | 39 +
.../java/groovy/json/DefaultJsonGenerator.java | 4 +-
.../src/main/java/groovy/json/JsonOutput.java | 4 +-
.../src/main/java/groovy/json/JsonSlurper.java | 8 +-
.../java/groovy/json/internal/ArrayUtils.java | 32 -
.../groovy/json/internal/BaseJsonParser.java | 228 -----
.../java/groovy/json/internal/ByteScanner.java | 70 --
.../main/java/groovy/json/internal/Cache.java | 40 -
.../java/groovy/json/internal/CacheType.java | 30 -
.../main/java/groovy/json/internal/CharBuf.java | 842 -------------------
.../java/groovy/json/internal/CharScanner.java | 512 -----------
.../groovy/json/internal/CharSequenceValue.java | 278 ------
.../groovy/json/internal/CharacterSource.java | 81 --
.../src/main/java/groovy/json/internal/Chr.java | 213 -----
.../main/java/groovy/json/internal/Dates.java | 184 ----
.../java/groovy/json/internal/Exceptions.java | 178 ----
.../groovy/json/internal/FastStringUtils.java | 191 -----
.../src/main/java/groovy/json/internal/IO.java | 91 --
.../groovy/json/internal/JsonFastParser.java | 334 --------
.../json/internal/JsonParserCharArray.java | 386 ---------
.../groovy/json/internal/JsonParserLax.java | 677 ---------------
.../JsonParserUsingCharacterSource.java | 298 -------
.../groovy/json/internal/JsonStringDecoder.java | 38 -
.../main/java/groovy/json/internal/LazyMap.java | 205 -----
.../java/groovy/json/internal/LazyValueMap.java | 247 ------
.../java/groovy/json/internal/MapItemValue.java | 80 --
.../java/groovy/json/internal/NumberValue.java | 216 -----
.../json/internal/ReaderCharacterSource.java | 264 ------
.../java/groovy/json/internal/SimpleCache.java | 72 --
.../src/main/java/groovy/json/internal/Sys.java | 84 --
.../main/java/groovy/json/internal/Type.java | 28 -
.../main/java/groovy/json/internal/Value.java | 63 --
.../groovy/json/internal/ValueContainer.java | 174 ----
.../java/groovy/json/internal/ValueList.java | 123 ---
.../java/groovy/json/internal/ValueMap.java | 46 -
.../java/groovy/json/internal/ValueMapImpl.java | 147 ----
.../groovy/json/DefaultFastStringService.java | 36 +
.../json/DefaultFastStringServiceFactory.java | 26 +
.../apache/groovy/json/FastStringService.java | 33 +
.../groovy/json/FastStringServiceFactory.java | 28 +
.../apache/groovy/json/internal/ArrayUtils.java | 32 +
.../groovy/json/internal/BaseJsonParser.java | 228 +++++
.../groovy/json/internal/ByteScanner.java | 70 ++
.../org/apache/groovy/json/internal/Cache.java | 40 +
.../apache/groovy/json/internal/CacheType.java | 30 +
.../apache/groovy/json/internal/CharBuf.java | 842 +++++++++++++++++++
.../groovy/json/internal/CharScanner.java | 512 +++++++++++
.../groovy/json/internal/CharSequenceValue.java | 278 ++++++
.../groovy/json/internal/CharacterSource.java | 81 ++
.../org/apache/groovy/json/internal/Chr.java | 213 +++++
.../org/apache/groovy/json/internal/Dates.java | 184 ++++
.../apache/groovy/json/internal/Exceptions.java | 178 ++++
.../groovy/json/internal/FastStringUtils.java | 85 ++
.../org/apache/groovy/json/internal/IO.java | 91 ++
.../groovy/json/internal/JsonFastParser.java | 334 ++++++++
.../json/internal/JsonParserCharArray.java | 386 +++++++++
.../groovy/json/internal/JsonParserLax.java | 677 +++++++++++++++
.../JsonParserUsingCharacterSource.java | 298 +++++++
.../groovy/json/internal/JsonStringDecoder.java | 38 +
.../apache/groovy/json/internal/LazyMap.java | 205 +++++
.../groovy/json/internal/LazyValueMap.java | 247 ++++++
.../groovy/json/internal/MapItemValue.java | 80 ++
.../groovy/json/internal/NumberValue.java | 219 +++++
.../json/internal/ReaderCharacterSource.java | 264 ++++++
.../groovy/json/internal/SimpleCache.java | 72 ++
.../org/apache/groovy/json/internal/Sys.java | 84 ++
.../org/apache/groovy/json/internal/Type.java | 28 +
.../org/apache/groovy/json/internal/Value.java | 63 ++
.../groovy/json/internal/ValueContainer.java | 174 ++++
.../apache/groovy/json/internal/ValueList.java | 123 +++
.../apache/groovy/json/internal/ValueMap.java | 46 +
.../groovy/json/internal/ValueMapImpl.java | 147 ++++
....apache.groovy.json.FastStringServiceFactory | 19 +
.../test/groovy/groovy/json/CharBufTest.groovy | 2 +-
.../groovy/json/CustomJsonGeneratorTest.groovy | 2 +-
.../src/test/groovy/groovy/json/IOTest.groovy | 4 +-
.../groovy/groovy/json/JsonSlurperTest.groovy | 2 +-
.../groovy/json/internal/ArrayUtilsTest.groovy | 27 -
.../groovy/json/internal/CharScannerTest.groovy | 288 -------
.../groovy/groovy/json/internal/ChrTest.groovy | 152 ----
.../groovy/json/internal/DatesTest.groovy | 48 --
.../json/internal/FastStringUtilsTest.groovy | 54 --
.../FastStringUtilsUnsafeDisabledTest.groovy | 60 --
.../groovy/json/internal/LazyMapTest.groovy | 52 --
.../internal/ReaderCharacterSourceTest.groovy | 77 --
.../json/DefaultFastStringServiceTest.groovy | 35 +
.../groovy/json/internal/ArrayUtilsTest.groovy | 27 +
.../groovy/json/internal/CharScannerTest.groovy | 288 +++++++
.../apache/groovy/json/internal/ChrTest.groovy | 152 ++++
.../groovy/json/internal/DatesTest.groovy | 47 ++
.../groovy/json/internal/LazyMapTest.groovy | 52 ++
.../internal/ReaderCharacterSourceTest.groovy | 77 ++
98 files changed, 7397 insertions(+), 7224 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/gradle/binarycompatibility.gradle
----------------------------------------------------------------------
diff --git a/gradle/binarycompatibility.gradle b/gradle/binarycompatibility.gradle
index 43713aa..274838b 100644
--- a/gradle/binarycompatibility.gradle
+++ b/gradle/binarycompatibility.gradle
@@ -35,7 +35,7 @@ task checkBinaryCompatibility {
check.dependsOn(checkBinaryCompatibility)
// for comparing between versions with different modules, set excludeModules to differing modules, e.g.
-def excludeModules = ['groovy-cli-picocli', 'groovy-cli-commons', 'groovy-dateutil', 'groovy-datetime', 'performance', 'groovy-macro', 'tests-vm8']
+def excludeModules = ['groovy-cli-picocli', 'groovy-cli-commons', 'groovy-dateutil', 'groovy-datetime', 'performance', 'groovy-macro', 'tests-vm8', 'groovy-json-direct']
//def excludeModules = []
Set projectsToCheck = allprojects.findAll{ !(it.name in excludeModules) }
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 651936d..d9c4fa6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -27,6 +27,7 @@ def subprojects = ['groovy-ant',
'groovy-groovysh',
'groovy-jmx',
'groovy-json',
+ 'groovy-json-direct',
'groovy-jsr223',
'groovy-nio',
'groovy-servlet',
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/build.gradle
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/build.gradle b/subprojects/groovy-json-direct/build.gradle
new file mode 100644
index 0000000..68b6ed2
--- /dev/null
+++ b/subprojects/groovy-json-direct/build.gradle
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+dependencies {
+ compile project(':groovy-json')
+ testCompile project(':groovy-test')
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java
new file mode 100644
index 0000000..0d7d4ad
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringService.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.jsondirect;
+
+import org.apache.groovy.json.FastStringService;
+
+import static org.apache.groovy.jsondirect.DirectFastStringServiceFactory.STRING_VALUE_FIELD_OFFSET;
+import static org.apache.groovy.jsondirect.DirectFastStringServiceFactory.WRITE_TO_FINAL_FIELDS;
+import static org.apache.groovy.jsondirect.DirectFastStringServiceFactory.UNSAFE;
+
+/**
+ * Internal class for fast processing of Strings during JSON parsing - direct field writing version.
+ * Works for JDK 7 and 8 but uses the Unsafe mechanism of Java.
+ */
+public class DirectFastStringService implements FastStringService {
+ @Override
+ public char[] toCharArray(String string) {
+ return (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
+ }
+
+ @Override
+ public String noCopyStringFromChars(char[] chars) {
+ if (WRITE_TO_FINAL_FIELDS) {
+ String string = new String();
+ UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
+ return string;
+ } else {
+ return new String(chars);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java
new file mode 100644
index 0000000..90f0626
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/main/java/org/apache/groovy/jsondirect/DirectFastStringServiceFactory.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.jsondirect;
+
+import org.apache.groovy.json.FastStringService;
+import org.apache.groovy.json.FastStringServiceFactory;
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+public class DirectFastStringServiceFactory implements FastStringServiceFactory {
+ static final Unsafe UNSAFE;
+ static final long STRING_VALUE_FIELD_OFFSET;
+ private static final boolean ENABLED;
+
+ static final boolean WRITE_TO_FINAL_FIELDS = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.write.to.final.fields", "false"));
+ private static final boolean DISABLE = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.disable", "false"));
+
+ private static Unsafe loadUnsafe() {
+ try {
+ Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
+ unsafeField.setAccessible(true);
+ return (Unsafe) unsafeField.get(null);
+
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ static {
+ UNSAFE = DISABLE ? null : loadUnsafe();
+ ENABLED = UNSAFE != null;
+ }
+
+ private static long getFieldOffset(String fieldName) {
+ if (ENABLED) {
+ try {
+ return UNSAFE.objectFieldOffset(String.class.getDeclaredField(fieldName));
+ } catch (NoSuchFieldException e) {
+ // field undefined
+ }
+ }
+ return -1L;
+ }
+
+ static {
+ STRING_VALUE_FIELD_OFFSET = getFieldOffset("value");
+ }
+
+ @Override
+ public FastStringService getService() {
+ if (STRING_VALUE_FIELD_OFFSET != -1L && valueFieldIsCharArray()) {
+ return new DirectFastStringService();
+ }
+ // safe to return null here because then we'll get the default provider
+ return null;
+ }
+
+ /**
+ * JDK9 Compat Strings enhancement changed the internal representation of the value field from a char[]
+ * to a byte[] (see http://openjdk.java.net/jeps/254).
+ *
+ * @return true if internal String value field is a char[], otherwise false
+ */
+ private static boolean valueFieldIsCharArray() {
+ Object o = UNSAFE.getObject("", STRING_VALUE_FIELD_OFFSET);
+ return (o instanceof char[]);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory b/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
new file mode 100644
index 0000000..cbb3713
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.groovy.jsondirect.DirectFastStringServiceFactory
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy b/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy
new file mode 100644
index 0000000..fe05828
--- /dev/null
+++ b/subprojects/groovy-json-direct/src/test/groovy/org/apache/groovy/jsondirect/DirectFastStringServiceTest.groovy
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.jsondirect
+
+import org.apache.groovy.json.FastStringService
+
+class DirectFastStringServiceTest extends GroovyTestCase {
+
+ FastStringService service = new DirectFastStringServiceFactory().service
+
+ void testToCharArray() {
+ if (!service) return
+ def str = "some test"
+ assert service.toCharArray(str) == str.toCharArray()
+ }
+
+ void testNoCopyStringFromChars() {
+ if (!service) return
+ def source = "äöüliu"
+ def chars = source.toCharArray()
+ assert service.noCopyStringFromChars(chars) == source
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java b/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
index 6510d4d..1e530e2 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/DefaultJsonGenerator.java
@@ -18,8 +18,8 @@
*/
package groovy.json;
-import groovy.json.internal.CharBuf;
-import groovy.json.internal.Chr;
+import org.apache.groovy.json.internal.CharBuf;
+import org.apache.groovy.json.internal.Chr;
import groovy.lang.Closure;
import groovy.util.Expando;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
index 63bbf1d..a650915 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
@@ -18,8 +18,8 @@
*/
package groovy.json;
-import groovy.json.internal.CharBuf;
-import groovy.json.internal.Chr;
+import org.apache.groovy.json.internal.CharBuf;
+import org.apache.groovy.json.internal.Chr;
import groovy.lang.Closure;
import groovy.util.Expando;
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
index 8808a05..dd931f0 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
@@ -18,10 +18,10 @@
*/
package groovy.json;
-import groovy.json.internal.JsonFastParser;
-import groovy.json.internal.JsonParserCharArray;
-import groovy.json.internal.JsonParserLax;
-import groovy.json.internal.JsonParserUsingCharacterSource;
+import org.apache.groovy.json.internal.JsonFastParser;
+import org.apache.groovy.json.internal.JsonParserCharArray;
+import org.apache.groovy.json.internal.JsonParserLax;
+import org.apache.groovy.json.internal.JsonParserUsingCharacterSource;
import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
import org.codehaus.groovy.runtime.ResourceGroovyMethods;
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java
deleted file mode 100644
index 7bd54a5..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ArrayUtils.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public class ArrayUtils {
-
- public static char[] copyRange(char[] source, int startIndex, int endIndex) {
- int len = endIndex - startIndex;
- char[] copy = new char[len];
- System.arraycopy(source, startIndex, copy, 0, Math.min(source.length - startIndex, len));
- return copy;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
deleted file mode 100644
index 10facaf..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-import groovy.json.JsonParser;
-import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
-import org.codehaus.groovy.runtime.ResourceGroovyMethods;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Base JSON parser.
- * Scaled down version of Boon JsonParser with features
- * removed that are JDK 1.7 dependent or Groovy duplicated functionality.
- *
- * @author Rick Hightower
- */
-public abstract class BaseJsonParser implements JsonParser {
-
- protected static final int COLON = ':';
- protected static final int COMMA = ',';
- protected static final int CLOSED_CURLY = '}';
- protected static final int CLOSED_BRACKET = ']';
-
- protected static final int LETTER_E = 'e';
- protected static final int LETTER_BIG_E = 'E';
-
- protected static final int MINUS = '-';
- protected static final int PLUS = '+';
-
- protected static final int DECIMAL_POINT = '.';
-
- protected static final int ALPHA_0 = '0';
- protected static final int ALPHA_1 = '1';
- protected static final int ALPHA_2 = '2';
- protected static final int ALPHA_3 = '3';
- protected static final int ALPHA_4 = '4';
- protected static final int ALPHA_5 = '5';
- protected static final int ALPHA_6 = '6';
- protected static final int ALPHA_7 = '7';
- protected static final int ALPHA_8 = '8';
- protected static final int ALPHA_9 = '9';
-
- protected static final int DOUBLE_QUOTE = '"';
-
- protected static final int ESCAPE = '\\';
-
- protected static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.internKeys", "false"));
- protected static ConcurrentHashMap<String, String> internedKeysCache;
-
- private static final Charset UTF_8 = Charset.forName("UTF-8");
-
- protected String charset = UTF_8.name();
-
- private CharBuf fileInputBuf;
-
- protected int bufSize = 256;
-
- static {
- if (internKeys) {
- internedKeysCache = new ConcurrentHashMap<String, String>();
- }
- }
-
- protected String charDescription(int c) {
- String charString;
- if (c == ' ') {
- charString = "[SPACE]";
- } else if (c == '\t') {
- charString = "[TAB]";
-
- } else if (c == '\n') {
- charString = "[NEWLINE]";
-
- } else {
- charString = "'" + (char) c + "'";
- }
-
- charString = charString + " with an int value of " + ((int) c);
- return charString;
- }
-
- public void setCharset(String charset) {
- this.charset = charset;
- }
-
- public Object parse(String jsonString) {
- return parse(FastStringUtils.toCharArray(jsonString));
- }
-
- public Object parse(byte[] bytes) {
- return parse(bytes, charset);
- }
-
- public Object parse(byte[] bytes, String charset) {
- try {
- return parse(new String(bytes, charset));
- } catch (UnsupportedEncodingException e) {
- return Exceptions.handle(Object.class, e);
- }
- }
-
- public Object parse(CharSequence charSequence) {
- return parse(FastStringUtils.toCharArray(charSequence));
- }
-
- public Object parse(Reader reader) {
- fileInputBuf = IO.read(reader, fileInputBuf, bufSize);
- return parse(fileInputBuf.readForRecycle());
- }
-
- public Object parse(InputStream input) {
- return parse(input, charset);
- }
-
- public Object parse(InputStream input, String charset) {
- try {
- return parse(new InputStreamReader(input, charset));
- } catch (UnsupportedEncodingException e) {
- return Exceptions.handle(Object.class, e);
- }
- }
-
- public Object parse(File file, String charset) {
- Reader reader = null;
- try {
- if (charset == null || charset.length() == 0) {
- reader = ResourceGroovyMethods.newReader(file);
- } else {
- reader = ResourceGroovyMethods.newReader(file, charset);
- }
- return parse(reader);
- } catch (IOException ioe) {
- throw new JsonException("Unable to process file: " + file.getPath(), ioe);
- } finally {
- if (reader != null) {
- DefaultGroovyMethodsSupport.closeWithWarning(reader);
- }
- }
- }
-
- protected static boolean isDecimalChar(int currentChar) {
- switch (currentChar) {
- case MINUS:
- case PLUS:
- case LETTER_E:
- case LETTER_BIG_E:
- case DECIMAL_POINT:
- return true;
- }
- return false;
- }
-
- protected static boolean isDelimiter(int c) {
- return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
- }
-
- protected static final boolean isNumberDigit(int c) {
- return c >= ALPHA_0 && c <= ALPHA_9;
- }
-
- protected static final boolean isDoubleQuote(int c) {
- return c == DOUBLE_QUOTE;
- }
-
- protected static final boolean isEscape(int c) {
- return c == ESCAPE;
- }
-
- protected static boolean hasEscapeChar(char[] array, int index, int[] indexHolder) {
- char currentChar;
- for (; index < array.length; index++) {
- currentChar = array[index];
- if (isDoubleQuote(currentChar)) {
- indexHolder[0] = index;
- return false;
- } else if (isEscape(currentChar)) {
- indexHolder[0] = index;
- return true;
- }
- }
-
- indexHolder[0] = index;
- return false;
- }
-
- int[] indexHolder = new int[1];
-
- protected static int findEndQuote(final char[] array, int index) {
- char currentChar;
- boolean escape = false;
-
- for (; index < array.length; index++) {
- currentChar = array[index];
- if (isDoubleQuote(currentChar)) {
- if (!escape) {
- break;
- }
- }
- escape = isEscape(currentChar) && !escape;
- }
- return index;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
deleted file mode 100644
index 51219b2..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * @author Richard Hightower
- */
-public class ByteScanner {
-
- /**
- * Turns a single nibble into an ascii HEX digit.
- *
- * @param nibble the nibble to serializeObject.
- * @return the encoded nibble (1/2 byte).
- */
- protected static int encodeNibbleToHexAsciiCharByte(final int nibble) {
- switch (nibble) {
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x08:
- case 0x09:
- return nibble + 0x30; // 0x30('0') - 0x39('9')
- case 0x0A:
- case 0x0B:
- case 0x0C:
- case 0x0D:
- case 0x0E:
- case 0x0F:
- return nibble + 0x57; // 0x41('a') - 0x46('f')
- default:
- die("illegal nibble: " + nibble);
- return -1;
- }
- }
-
- /**
- * Turn a single bytes into two hex character representation.
- *
- * @param decoded the byte to serializeObject.
- * @param encoded the array to which each encoded nibbles are now ascii hex representations.
- */
- public static void encodeByteIntoTwoAsciiCharBytes(final int decoded, final byte[] encoded) {
- encoded[0] = (byte) encodeNibbleToHexAsciiCharByte((decoded >> 4) & 0x0F);
- encoded[1] = (byte) encodeNibbleToHexAsciiCharByte(decoded & 0x0F);
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
deleted file mode 100644
index 9eff815..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-/**
- * Cache
- *
- * @param <KEY> key
- * @param <VALUE> value
- * @author Rick Hightower
- */
-public interface Cache<KEY, VALUE> {
-
- void put(KEY key, VALUE value);
-
- VALUE get(KEY key);
-
- VALUE getSilent(KEY key);
-
- void remove(KEY key);
-
- int size();
-}
-
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java
deleted file mode 100644
index 8ecf99b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CacheType.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Rick Hightower
- */
-public enum CacheType {
-
- LRU,
- LFU,
- FIFO
-}
-
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
deleted file mode 100644
index f7e1b29..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-/**
- * @author Rick Hightower
- */
-public class CharBuf extends Writer implements CharSequence {
-
- protected int capacity = 16;
- protected int location = 0;
-
- protected char[] buffer;
-
- public CharBuf(char[] buffer) {
- __init__(buffer);
- }
-
- private void __init__(char[] buffer) {
- this.buffer = buffer;
- this.capacity = buffer.length;
- }
-
- public CharBuf(byte[] bytes) {
- this.buffer = null;
- try {
- String str = new String(bytes, "UTF-8");
- __init__(FastStringUtils.toCharArray(str));
- } catch (UnsupportedEncodingException e) {
- Exceptions.handle(e);
- }
- }
-
- public static CharBuf createExact(final int capacity) {
- return new CharBuf(capacity) {
- public CharBuf add(char[] chars) {
- Chr._idx(buffer, location, chars);
- location += chars.length;
- return this;
- }
- };
- }
-
- public static CharBuf create(int capacity) {
- return new CharBuf(capacity);
- }
-
- public static CharBuf create(char[] buffer) {
- return new CharBuf(buffer);
- }
-
- protected CharBuf(int capacity) {
- this.capacity = capacity;
- init();
- }
-
- protected CharBuf() {
- init();
- }
-
- public void write(char[] cbuf, int off, int len) {
- if (off == 0 && cbuf.length == len) {
- this.add(cbuf);
- } else {
- char[] buffer = ArrayUtils.copyRange(cbuf, off, off + len);
- this.add(buffer);
- }
- }
-
- public void flush() throws IOException {
- }
-
- public void close() throws IOException {
- }
-
- public void init() {
- buffer = new char[capacity];
- }
-
- public final CharBuf add(String str) {
- add(FastStringUtils.toCharArray(str));
- return this;
- }
-
- public final CharBuf addString(String str) {
- add(FastStringUtils.toCharArray(str));
- return this;
- }
-
- public final CharBuf add(int i) {
- add(Integer.toString(i));
- return this;
- }
-
- private Cache<Integer, char[]> icache;
-
- public final CharBuf addInt(int i) {
- switch (i) {
- case 0:
- addChar('0');
- return this;
- case 1:
- addChar('1');
- return this;
- case -1:
- addChar('-');
- addChar('1');
- return this;
- }
-
- addInt(Integer.valueOf(i));
- return this;
- }
-
- public final CharBuf addInt(Integer key) {
- if (icache == null) {
- icache = new SimpleCache<Integer, char[]>(20);
- }
- char[] chars = icache.get(key);
-
- if (chars == null) {
- String str = Integer.toString(key);
- chars = FastStringUtils.toCharArray(str);
- icache.put(key, chars);
- }
-
- addChars(chars);
- return this;
- }
-
- final char[] trueChars = "true".toCharArray();
- final char[] falseChars = "false".toCharArray();
-
- public final CharBuf add(boolean b) {
- addChars(b ? trueChars : falseChars);
- return this;
- }
-
- public final CharBuf addBoolean(boolean b) {
- add(Boolean.toString(b));
- return this;
- }
-
- public final CharBuf add(byte i) {
- add(Byte.toString(i));
- return this;
- }
-
- public final CharBuf addByte(byte i) {
- addInt(i);
- return this;
- }
-
- public final CharBuf add(short i) {
- add(Short.toString(i));
- return this;
- }
-
- public final CharBuf addShort(short i) {
- addInt(i);
- return this;
- }
-
- public final CharBuf add(long l) {
- add(Long.toString(l));
- return this;
- }
-
- public final CharBuf add(double d) {
- add(Double.toString(d));
- return this;
- }
-
- private Cache<Double, char[]> dcache;
-
- public final CharBuf addDouble(double d) {
- addDouble(Double.valueOf(d));
- return this;
- }
-
- public final CharBuf addDouble(Double key) {
- if (dcache == null) {
- dcache = new SimpleCache<Double, char[]>(20);
- }
- char[] chars = dcache.get(key);
-
- if (chars == null) {
- String str = Double.toString(key);
- chars = FastStringUtils.toCharArray(str);
- dcache.put(key, chars);
- }
-
- add(chars);
- return this;
- }
-
- public final CharBuf add(float d) {
- add(Float.toString(d));
- return this;
- }
-
- private Cache<Float, char[]> fcache;
-
- public final CharBuf addFloat(float d) {
- addFloat(Float.valueOf(d));
- return this;
- }
-
- public final CharBuf addFloat(Float key) {
- if (fcache == null) {
- fcache = new SimpleCache<Float, char[]>(20);
- }
- char[] chars = fcache.get(key);
-
- if (chars == null) {
- String str = Float.toString(key);
- chars = FastStringUtils.toCharArray(str);
- fcache.put(key, chars);
- }
-
- add(chars);
-
- return this;
- }
-
- public final CharBuf addChar(byte i) {
- add((char) i);
- return this;
- }
-
- public final CharBuf addChar(int i) {
- add((char) i);
- return this;
- }
-
- public final CharBuf addChar(short i) {
- add((char) i);
- return this;
- }
-
- public final CharBuf addChar(final char ch) {
- int _location = location;
- char[] _buffer = buffer;
- int _capacity = capacity;
-
- if (1 + _location > _capacity) {
- _buffer = Chr.grow(_buffer);
- _capacity = _buffer.length;
- }
-
- _buffer[_location] = ch;
- _location++;
-
- location = _location;
- buffer = _buffer;
- capacity = _capacity;
- return this;
- }
-
- public CharBuf addLine(String str) {
- add(str.toCharArray());
- add('\n');
- return this;
- }
-
- public CharBuf addLine(CharSequence str) {
- add(str.toString());
- add('\n');
- return this;
- }
-
- public CharBuf add(char[] chars) {
- if (chars.length + location > capacity) {
- buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
- capacity = buffer.length;
- }
-
- Chr._idx(buffer, location, chars);
- location += chars.length;
- return this;
- }
-
- public final CharBuf addChars(char[] chars) {
- if (chars.length + location > capacity) {
- buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
- capacity = buffer.length;
- }
-
- System.arraycopy(chars, 0, buffer, location, chars.length);
- location += chars.length;
- return this;
- }
-
- public final CharBuf addQuoted(char[] chars) {
- int _location = location;
- char[] _buffer = buffer;
- int _capacity = capacity;
-
- int sizeNeeded = chars.length + 2 + _location;
- if (sizeNeeded > _capacity) {
- _buffer = Chr.grow(_buffer, sizeNeeded * 2);
- _capacity = _buffer.length;
- }
- _buffer[_location] = '"';
- _location++;
-
- System.arraycopy(chars, 0, _buffer, _location, chars.length);
-
- _location += (chars.length);
- _buffer[_location] = '"';
- _location++;
-
- location = _location;
- buffer = _buffer;
- capacity = _capacity;
- return this;
- }
-
- public final CharBuf addJsonEscapedString(String jsonString) {
- return addJsonEscapedString(jsonString, false);
- }
-
- public final CharBuf addJsonEscapedString(String jsonString, boolean disableUnicodeEscaping) {
- char[] charArray = FastStringUtils.toCharArray(jsonString);
- return addJsonEscapedString(charArray, disableUnicodeEscaping);
- }
-
- private static boolean shouldEscape(int c, boolean disableUnicodeEscaping) {
- if (c < 32) { /* less than space is a control char */
- return true;
- } else if (c == 34) { /* double quote */
- return true;
- } else if (c == 92) { /* backslash */
- return true;
- } else if (!disableUnicodeEscaping && c > 126) { /* non-ascii char range */
- return true;
- }
-
- return false;
- }
-
- private static boolean hasAnyJSONControlChars(final char[] charArray, boolean disableUnicodeEscaping) {
- int index = 0;
- char c;
- while (true) {
- c = charArray[index];
- if (shouldEscape(c, disableUnicodeEscaping)) {
- return true;
- }
- if (++index >= charArray.length) return false;
- }
- }
-
- public final CharBuf addJsonEscapedString(final char[] charArray) {
- return addJsonEscapedString(charArray, false);
- }
-
- public final CharBuf addJsonEscapedString(final char[] charArray, boolean disableUnicodeEscaping) {
- if (charArray.length == 0) return this;
- if (hasAnyJSONControlChars(charArray, disableUnicodeEscaping)) {
- return doAddJsonEscapedString(charArray, disableUnicodeEscaping);
- } else {
- return this.addQuoted(charArray);
- }
- }
-
- final byte[] encoded = new byte[2];
-
- final byte[] charTo = new byte[2];
-
- private CharBuf doAddJsonEscapedString(char[] charArray, boolean disableUnicodeEscaping) {
- char[] _buffer = buffer;
- int _location = this.location;
-
- final byte[] _encoded = encoded;
-
- final byte[] _charTo = charTo;
- /* We are making a bet that not all chars will be unicode. */
- int ensureThisMuch = charArray.length * 6 + 2;
-
- int sizeNeeded = (ensureThisMuch) + _location;
- if (sizeNeeded > capacity) {
- int growBy = (_buffer.length * 2) < sizeNeeded ? sizeNeeded : (_buffer.length * 2);
- _buffer = Chr.grow(buffer, growBy);
- capacity = _buffer.length;
- }
-
- _buffer[_location] = '"';
- _location++;
-
- int index = 0;
- while (true) {
- char c = charArray[index];
-
- if (shouldEscape(c, disableUnicodeEscaping)) {
- /* We are covering our bet with a safety net.
- otherwise we would have to have 5x buffer
- allocated for control chars */
- if (_location + 5 > _buffer.length) {
- _buffer = Chr.grow(_buffer, 20);
- }
-
- switch (c) {
- case '\"':
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = '"';
- _location++;
- break;
- case '\\':
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = '\\';
- _location++;
- break;
- //There is not requirement to escape solidus so we will not.
-// case '/':
-// _buffer[_location] = '\\';
-// _location ++;
-// _buffer[_location] = '/';
-// _location ++;
-// break;
-
- case '\b':
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = 'b';
- _location++;
- break;
- case '\f':
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = 'f';
- _location++;
- break;
- case '\n':
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = 'n';
- _location++;
- break;
- case '\r':
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = 'r';
- _location++;
- break;
- case '\t':
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = 't';
- _location++;
- break;
- default:
- _buffer[_location] = '\\';
- _location++;
- _buffer[_location] = 'u';
- _location++;
- if (c <= 255) {
- _buffer[_location] = '0';
- _location++;
- _buffer[_location] = '0';
- _location++;
- ByteScanner.encodeByteIntoTwoAsciiCharBytes(c, _encoded);
- for (int b : _encoded) {
- _buffer[_location] = (char) b;
- _location++;
- }
- } else {
- _charTo[1] = (byte) (c);
- _charTo[0] = (byte) (c >>> 8);
-
- for (int charByte : _charTo) {
- ByteScanner.encodeByteIntoTwoAsciiCharBytes(charByte, _encoded);
- for (int b : _encoded) {
- _buffer[_location] = (char) b;
- _location++;
- }
- }
- }
- }
- } else {
- _buffer[_location] = c;
- _location++;
- }
-
- if (++index >= charArray.length) break;
- }
- _buffer[_location] = '"';
- _location++;
-
- buffer = _buffer;
- location = _location;
-
- return this;
- }
-
- public final CharBuf addJsonFieldName(String str) {
- return addJsonFieldName(str, false);
- }
-
- public final CharBuf addJsonFieldName(String str, boolean disableUnicodeEscaping) {
- return addJsonFieldName(FastStringUtils.toCharArray(str), disableUnicodeEscaping);
- }
-
- private static final char[] EMPTY_STRING_CHARS = Chr.array('"', '"');
-
- public final CharBuf addJsonFieldName(char[] chars) {
- return addJsonFieldName(chars, false);
- }
-
- public final CharBuf addJsonFieldName(char[] chars, boolean disableUnicodeEscaping) {
- if (chars.length > 0) {
- addJsonEscapedString(chars, disableUnicodeEscaping);
- } else {
- addChars(EMPTY_STRING_CHARS);
- }
- addChar(':');
- return this;
- }
-
- public final CharBuf addQuoted(String str) {
- final char[] chars = FastStringUtils.toCharArray(str);
- addQuoted(chars);
- return this;
- }
-
- public CharBuf add(char[] chars, final int length) {
- if (length + location < capacity) {
- Chr._idx(buffer, location, chars, length);
- } else {
- buffer = Chr.grow(buffer, buffer.length * 2 + length);
- Chr._idx(buffer, location, chars);
- capacity = buffer.length;
- }
- location += length;
- return this;
- }
-
- public CharBuf add(byte[] chars) {
- if (chars.length + location < capacity) {
- Chr._idx(buffer, location, chars);
- } else {
- buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
- Chr._idx(buffer, location, chars);
- capacity = buffer.length;
- }
- location += chars.length;
- return this;
- }
-
- public CharBuf add(byte[] bytes, int start, int end) {
- int charsLength = end - start;
- if (charsLength + location > capacity) {
- buffer = Chr.grow(buffer, buffer.length * 2 + charsLength);
- }
- Chr._idx(buffer, location, bytes, start, end);
- capacity = buffer.length;
- location += charsLength;
- return this;
- }
-
- public final CharBuf add(char ch) {
- if (1 + location < capacity) {
- buffer[location] = ch;
- } else {
- buffer = Chr.grow(buffer);
- buffer[location] = ch;
- capacity = buffer.length;
- }
- location += 1;
- return this;
- }
-
- public int length() {
- return len();
- }
-
- public char charAt(int index) {
- return buffer[index];
- }
-
- public CharSequence subSequence(int start, int end) {
- return new String(buffer, start, end - start);
- }
-
- public String toString() {
- return new String(buffer, 0, location);
- }
-
- public String toDebugString() {
- return "CharBuf{" +
- "capacity=" + capacity +
- ", location=" + location +
- '}';
- }
-
- public String toStringAndRecycle() {
- String str = new String(buffer, 0, location);
- location = 0;
- return str;
- }
-
- public int len() {
- return location;
- }
-
- public char[] toCharArray() {
- return this.buffer;
- }
-
- public void _len(int location) {
- this.location = location;
- }
-
- public char[] readForRecycle() {
- this.location = 0;
- return this.buffer;
- }
-
- public void recycle() {
- this.location = 0;
- }
-
- public double doubleValue() {
- return CharScanner.parseDouble(this.buffer, 0, location);
- }
-
- public float floatValue() {
- return CharScanner.parseFloat(this.buffer, 0, location);
- }
-
- public int intValue() {
- return CharScanner.parseIntFromTo(buffer, 0, location);
- }
-
- public long longValue() {
- return CharScanner.parseLongFromTo(buffer, 0, location);
- }
-
- public byte byteValue() {
- return (byte) intValue();
- }
-
- public short shortValue() {
- return (short) intValue();
- }
-
- public Number toIntegerWrapper() {
- if (CharScanner.isInteger(buffer, 0, location)) {
- return intValue();
- } else {
- return longValue();
- }
- }
-
- static final char[] nullChars = "null".toCharArray();
-
- public final void addNull() {
- this.add(nullChars);
- }
-
- public void removeLastChar() {
- if (location > 0) {
- location--;
- }
- }
-
- public void removeLastChar(char expect) {
- if (location == 0 || buffer[location-1] != expect) {
- return;
- }
- removeLastChar();
- }
-
- private Cache<BigDecimal, char[]> bigDCache;
-
- public CharBuf addBigDecimal(BigDecimal key) {
- if (bigDCache == null) {
- bigDCache = new SimpleCache<BigDecimal, char[]>(20);
- }
- char[] chars = bigDCache.get(key);
-
- if (chars == null) {
- String str = key.toString();
- chars = FastStringUtils.toCharArray(str);
- bigDCache.put(key, chars);
- }
-
- add(chars);
-
- return this;
- }
-
- private Cache<BigInteger, char[]> bigICache;
-
- public CharBuf addBigInteger(BigInteger key) {
- if (bigICache == null) {
- bigICache = new SimpleCache<BigInteger, char[]>(20);
- }
- char[] chars = bigICache.get(key);
-
- if (chars == null) {
- String str = key.toString();
- chars = FastStringUtils.toCharArray(str);
- bigICache.put(key, chars);
- }
-
- add(chars);
-
- return this;
- }
-
- private Cache<Long, char[]> lcache;
-
- public final CharBuf addLong(long l) {
- addLong(Long.valueOf(l));
- return this;
- }
-
- public final CharBuf addLong(Long key) {
- if (lcache == null) {
- lcache = new SimpleCache<Long, char[]>(20);
- }
- char[] chars = lcache.get(key);
-
- if (chars == null) {
- String str = Long.toString(key);
- chars = FastStringUtils.toCharArray(str);
- lcache.put(key, chars);
- }
-
- add(chars);
-
- return this;
- }
-
- public final CharBuf decodeJsonString(char[] chars) {
- return decodeJsonString(chars, 0, chars.length);
- }
-
- public final CharBuf decodeJsonString(char[] chars, int start, int to) {
- int len = to - start;
-
- char[] buffer = this.buffer;
- int location = this.location;
-
- if (len > capacity) {
- buffer = Chr.grow(buffer, buffer.length * 2 + len);
- capacity = buffer.length;
- }
-
- for (int index = start; index < to; index++) {
- char c = chars[index];
- if (c == '\\') {
- if (index < to) {
- index++;
- c = chars[index];
- switch (c) {
-
- case 'n':
- buffer[location++] = '\n';
- break;
-
- case '/':
- buffer[location++] = '/';
- break;
-
- case '"':
- buffer[location++] = '"';
- break;
-
- case 'f':
- buffer[location++] = '\f';
- break;
-
- case 't':
- buffer[location++] = '\t';
- break;
-
- case '\\':
- buffer[location++] = '\\';
- break;
-
- case 'b':
- buffer[location++] = '\b';
- break;
-
- case 'r':
- buffer[location++] = '\r';
- break;
-
- case 'u':
- if (index + 4 < to) {
- String hex = new String(chars, index + 1, 4);
- char unicode = (char) Integer.parseInt(hex, 16);
- buffer[location++] = unicode;
- index += 4;
- }
- break;
-
- default:
- throw new JsonException("Unable to decode string");
- }
- }
- } else {
- buffer[location++] = c;
- }
- }
-
- this.buffer = buffer;
- this.location = location;
-
- return this;
- }
-}
-
-
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
deleted file mode 100644
index 596c648..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-
-import static groovy.json.internal.Exceptions.die;
-import static groovy.json.internal.Exceptions.handle;
-
-/**
- * @author Richard Hightower
- */
-public class CharScanner {
-
- protected static final int COMMA = ',';
- protected static final int CLOSED_CURLY = '}';
- protected static final int CLOSED_BRACKET = ']';
- protected static final int LETTER_E = 'e';
- protected static final int LETTER_BIG_E = 'E';
- protected static final int DECIMAL_POINT = '.';
- protected static final int ALPHA_0 = '0';
- protected static final int ALPHA_9 = '9';
- protected static final int MINUS = '-';
- protected static final int PLUS = '+';
-
- static final String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE);
- static final String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE);
- static final String MIN_INT_STR_NO_SIGN = String.valueOf(Integer.MIN_VALUE);
- static final String MAX_INT_STR = String.valueOf(Integer.MAX_VALUE);
-
- private static double powersOf10[] = {
- 1.0,
- 10.0,
- 100.0,
- 1000.0,
- 10000.0,
- 100000.0,
- 1000000.0,
- 10000000.0,
- 100000000.0,
- 1000000000.0,
- 10000000000.0,
- 100000000000.0,
- 1000000000000.0,
- 10000000000000.0,
- 100000000000000.0,
- 1000000000000000.0,
- 10000000000000000.0,
- 100000000000000000.0,
- 1000000000000000000.0,
- };
-
- public static boolean isDigit(int c) {
- return c >= ALPHA_0 && c <= ALPHA_9;
- }
-
- public static boolean isDecimalDigit(int c) {
- return isDigit(c) || isDecimalChar(c);
- }
-
- public static boolean isDecimalChar(int currentChar) {
- switch (currentChar) {
- case MINUS:
- case PLUS:
- case LETTER_E:
- case LETTER_BIG_E:
- case DECIMAL_POINT:
- return true;
- }
- return false;
- }
-
- public static boolean hasDecimalChar(char[] chars, boolean negative) {
- int index = 0;
-
- if (negative) index++;
-
- for (; index < chars.length; index++) {
- switch (chars[index]) {
- case MINUS:
- case PLUS:
- case LETTER_E:
- case LETTER_BIG_E:
- case DECIMAL_POINT:
- return true;
- }
- }
- return false;
- }
-
- public static boolean isLong(char[] digitChars) {
- return isLong(digitChars, 0, digitChars.length);
- }
-
- public static boolean isLong(char[] digitChars, int offset, int len) {
- String cmpStr = digitChars[offset] == '-' ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
- int cmpLen = cmpStr.length();
- if (len < cmpLen) return true;
- if (len > cmpLen) return false;
-
- for (int i = 0; i < cmpLen; ++i) {
- int diff = digitChars[offset + i] - cmpStr.charAt(i);
- if (diff != 0) {
- return (diff < 0);
- }
- }
- return true;
- }
-
- public static boolean isInteger(char[] digitChars) {
- return isInteger(digitChars, 0, digitChars.length);
- }
-
- public static boolean isInteger(char[] digitChars, int offset, int len) {
- String cmpStr = (digitChars[offset] == '-') ? MIN_INT_STR_NO_SIGN : MAX_INT_STR;
- int cmpLen = cmpStr.length();
- if (len < cmpLen) return true;
- if (len > cmpLen) return false;
-
- for (int i = 0; i < cmpLen; ++i) {
- int diff = digitChars[offset + i] - cmpStr.charAt(i);
- if (diff != 0) {
- return (diff < 0);
- }
- }
- return true;
- }
-
- public static int parseInt(char[] digitChars) {
- return parseIntFromTo(digitChars, 0, digitChars.length);
- }
-
- public static int parseIntFromTo(char[] digitChars, int offset, int to) {
- try {
- int num;
- boolean negative = false;
- char c = digitChars[offset];
- if (c == '-') {
- offset++;
- negative = true;
- }
- if (offset >= to) {
- die();
- }
- num = (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- if (++offset < to) {
- num = (num * 10) + (digitChars[offset] - '0');
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return negative ? num * -1 : num;
- } catch (Exception ex) {
- return handle(int.class, ex);
- }
- }
-
- public static int parseIntFromToIgnoreDot(char[] digitChars, int offset, int to) {
- int num;
- boolean negative = false;
- char c = digitChars[offset];
- if (c == '-') {
- offset++;
- negative = true;
- }
- if (offset >= to) {
- die();
- }
- c = digitChars[offset];
- num = (c - '0');
- offset++;
-
- for (; offset < to; offset++) {
- c = digitChars[offset];
- if (c != '.') {
- num = (num * 10) + (c - '0');
- }
- }
-
- return negative ? num * -1 : num;
- }
-
- public static long parseLongFromToIgnoreDot(char[] digitChars, int offset, int to) {
- long num;
- boolean negative = false;
- char c = digitChars[offset];
- if (c == '-') {
- offset++;
- negative = true;
- }
- if (offset >= to) {
- die();
- }
- c = digitChars[offset];
- num = (c - '0');
- offset++;
-
- for (; offset < to; offset++) {
- c = digitChars[offset];
- if (c != '.') {
- num = (num * 10) + (c - '0');
- }
- }
-
- return negative ? num * -1 : num;
- }
-
- public static long parseLongFromTo(char[] digitChars, int offset, int to) {
- long num;
- boolean negative = false;
- char c = digitChars[offset];
- if (c == '-') {
- offset++;
- negative = true;
- }
- if (offset >= to) {
- die();
- }
- c = digitChars[offset];
- num = (c - '0');
- offset++;
-
- long digit;
-
- for (; offset < to; offset++) {
- c = digitChars[offset];
- digit = (c - '0');
- num = (num * 10) + digit;
- }
-
- return negative ? num * -1 : num;
- }
-
- public static long parseLong(char[] digitChars) {
- return parseLongFromTo(digitChars, 0, digitChars.length);
- }
-
- public static Number parseJsonNumber(char[] buffer) {
- return parseJsonNumber(buffer, 0, buffer.length);
- }
-
- public static Number parseJsonNumber(char[] buffer, int from, int to) {
- return parseJsonNumber(buffer, from, to, null);
- }
-
- public static boolean isNumberDigit(int c) {
- return c >= ALPHA_0 && c <= ALPHA_9;
- }
-
- protected static boolean isDelimiter(int c) {
- return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
- }
-
- public static Number parseJsonNumber(char[] buffer, int from, int max, int size[]) {
- Number value = null;
- boolean simple = true;
- int digitsPastPoint = 0;
-
- int index = from;
-
- if (buffer[index] == '-') {
- index++;
- }
- if (index >= max) {
- die();
- }
-
- boolean foundDot = false;
- for (; index < max; index++) {
- char ch = buffer[index];
- if (isNumberDigit(ch)) {
- if (foundDot) {
- digitsPastPoint++;
- }
- } else if (ch <= 32 || isDelimiter(ch)) {
- break;
- } else if (ch == '.') {
- if (foundDot) {
- die("unexpected character " + ch);
- }
- foundDot = true;
- } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
- simple = false;
- } else {
- die("unexpected character " + ch);
- }
- }
-
- if (digitsPastPoint >= powersOf10.length - 1) {
- simple = false;
- }
-
- final int length = index - from;
-
- if (!foundDot && simple) {
- if (isInteger(buffer, from, length)) {
- value = parseIntFromTo(buffer, from, index);
- } else {
- value = parseLongFromTo(buffer, from, index);
- }
- } else {
- value = new BigDecimal(buffer, from, length);
- }
-
- if (size != null) {
- size[0] = index;
- }
-
- return value;
- }
-
- public static BigDecimal parseBigDecimal(char[] buffer) {
- return new BigDecimal(buffer);
- }
-
- public static float parseFloat(char[] buffer, int from, int to) {
- return (float) parseDouble(buffer, from, to);
- }
-
- public static double parseDouble(char[] buffer, int from, int to) {
- double value;
- boolean simple = true;
- int digitsPastPoint = 0;
-
- int index = from;
-
- if (buffer[index] == '-') {
- index++;
- }
-
- boolean foundDot = false;
- for (; index < to; index++) {
- char ch = buffer[index];
- if (isNumberDigit(ch)) {
- if (foundDot) {
- digitsPastPoint++;
- }
- } else if (ch == '.') {
- if (foundDot) {
- die("unexpected character " + ch);
- }
- foundDot = true;
- } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
- simple = false;
- } else {
- die("unexpected character " + ch);
- }
- }
-
- if (digitsPastPoint >= powersOf10.length - 1) {
- simple = false;
- }
-
- final int length = index - from;
-
- if (!foundDot && simple) {
- if (isInteger(buffer, from, length)) {
- value = parseIntFromTo(buffer, from, index);
- } else {
- value = parseLongFromTo(buffer, from, index);
- }
- } else if (foundDot && simple) {
- long lvalue;
-
- if (length < powersOf10.length) {
- if (isInteger(buffer, from, length)) {
- lvalue = parseIntFromToIgnoreDot(buffer, from, index);
- } else {
- lvalue = parseLongFromToIgnoreDot(buffer, from, index);
- }
-
- double power = powersOf10[digitsPastPoint];
- value = lvalue / power;
- } else {
- value = Double.parseDouble(new String(buffer, from, length));
- }
- } else {
- value = Double.parseDouble(new String(buffer, from, index - from));
- }
-
- return value;
- }
-
- public static int skipWhiteSpace(char[] array, int index, final int length) {
- int c;
- for (; index < length; index++) {
- c = array[index];
- if (c > 32) {
- return index;
- }
- }
- return index;
- }
-
- public static char[] readNumber(char[] array, int idx, final int len) {
- final int startIndex = idx;
-
- while (true) {
- if (!CharScanner.isDecimalDigit(array[idx])) {
- break;
- } else {
- idx++;
- if (idx >= len) break;
- }
- }
-
- return ArrayUtils.copyRange(array, startIndex, idx);
- }
-
- public static String errorDetails(String message, char[] array, int index, int ch) {
- CharBuf buf = CharBuf.create(255);
-
- buf.addLine(message);
-
- buf.addLine("");
- buf.addLine("The current character read is " + debugCharDescription(ch));
-
- buf.addLine(message);
-
- int line = 0;
- int lastLineIndex = 0;
-
- for (int i = 0; i < index && i < array.length; i++) {
- if (array[i] == '\n') {
- line++;
- lastLineIndex = i + 1;
- }
- }
-
- int count = 0;
-
- for (int i = lastLineIndex; i < array.length; i++, count++) {
- if (array[i] == '\n') {
- break;
- }
- }
-
- buf.addLine("line number " + (line + 1));
- buf.addLine("index number " + index);
-
- try {
- buf.addLine(new String(array, lastLineIndex, count));
- } catch (Exception ex) {
- try {
- int start = index = (index - 10 < 0) ? 0 : index - 10;
-
- buf.addLine(new String(array, start, index));
- } catch (Exception ex2) {
- buf.addLine(new String(array, 0, array.length));
- }
- }
- for (int i = 0; i < (index - lastLineIndex); i++) {
- buf.add('.');
- }
- buf.add('^');
-
- return buf.toString();
- }
-
- public static String debugCharDescription(int c) {
- String charString;
- if (c == ' ') {
- charString = "[SPACE]";
- } else if (c == '\t') {
- charString = "[TAB]";
- } else if (c == '\n') {
- charString = "[NEWLINE]";
- } else {
- charString = "'" + (char) c + "'";
- }
-
- charString = charString + " with an int value of " + ((int) c);
- return charString;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
deleted file mode 100644
index 6b0477f..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Date;
-
-import static groovy.json.internal.CharScanner.isInteger;
-import static groovy.json.internal.CharScanner.parseIntFromTo;
-import static groovy.json.internal.CharScanner.parseLongFromTo;
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * @author Rick Hightower
- */
-public class CharSequenceValue implements Value, CharSequence {
-
- private final Type type;
- private final boolean checkDate;
- private final boolean decodeStrings;
-
- private char[] buffer;
- private boolean chopped;
- private int startIndex;
- private int endIndex;
- private Object value;
-
- public CharSequenceValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer,
- boolean encoded, boolean checkDate) {
- this.type = type;
- this.checkDate = checkDate;
- this.decodeStrings = encoded;
-
- if (chop) {
- try {
- this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
- } catch (Exception ex) {
- Exceptions.handle(ex);
- }
- this.startIndex = 0;
- this.endIndex = this.buffer.length;
- this.chopped = true;
- } else {
- this.startIndex = startIndex;
- this.endIndex = endIndex;
- this.buffer = buffer;
- }
- }
-
- public String toString() {
- if (startIndex == 0 && endIndex == buffer.length) {
- return FastStringUtils.noCopyStringFromChars(buffer);
- } else {
- return new String(buffer, startIndex, (endIndex - startIndex));
- }
- }
-
- public final Object toValue() {
- return value != null ? value : (value = doToValue());
- }
-
- public <T extends Enum> T toEnum(Class<T> cls) {
- switch (type) {
- case STRING:
- return toEnum(cls, stringValue());
- case INTEGER:
- return toEnum(cls, intValue());
- case NULL:
- return null;
- }
- die("toEnum " + cls + " value was " + stringValue());
- return null;
- }
-
- public static <T extends Enum> T toEnum(Class<T> cls, String value) {
- try {
- return (T) Enum.valueOf(cls, value);
- } catch (Exception ex) {
- return (T) Enum.valueOf(cls, value.toUpperCase().replace('-', '_'));
- }
- }
-
- public static <T extends Enum> T toEnum(Class<T> cls, int value) {
- T[] enumConstants = cls.getEnumConstants();
- for (T e : enumConstants) {
- if (e.ordinal() == value) {
- return e;
- }
- }
- die("Can't convert ordinal value " + value + " into enum of type " + cls);
- return null;
- }
-
- public boolean isContainer() {
- return false;
- }
-
- private Object doToValue() {
- switch (type) {
- case DOUBLE:
- return doubleValue();
- case INTEGER:
- if (isInteger(buffer, startIndex, endIndex - startIndex)) {
- return intValue();
- } else {
- return longValue();
- }
- case STRING:
- if (checkDate) {
- Date date = null;
- if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
- if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
- date = Dates.fromJsonDate(buffer, startIndex, endIndex);
- } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
- date = Dates.fromISO8601(buffer, startIndex, endIndex);
- } else {
- return stringValue();
- }
-
- if (date == null) {
- return stringValue();
- } else {
- return date;
- }
- }
- }
- return stringValue();
- }
- die();
- return null;
- }
-
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof Value)) return false;
-
- CharSequenceValue value1 = (CharSequenceValue) o;
-
- if (endIndex != value1.endIndex) return false;
- if (startIndex != value1.startIndex) return false;
- if (!Arrays.equals(buffer, value1.buffer)) return false;
- if (type != value1.type) return false;
- return value != null ? value.equals(value1.value) : value1.value == null;
-
- }
-
- public int hashCode() {
- int result = type != null ? type.hashCode() : 0;
- result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
- result = 31 * result + startIndex;
- result = 31 * result + endIndex;
- result = 31 * result + (value != null ? value.hashCode() : 0);
- return result;
- }
-
- public final int length() {
- return buffer.length;
- }
-
- public final char charAt(int index) {
- return buffer[index];
- }
-
- public final CharSequence subSequence(int start, int end) {
- return new CharSequenceValue(false, type, start, end, buffer, decodeStrings, checkDate);
- }
-
- public BigDecimal bigDecimalValue() {
- return new BigDecimal(buffer, startIndex, endIndex - startIndex);
- }
-
- public BigInteger bigIntegerValue() {
- return new BigInteger(toString());
- }
-
- public String stringValue() {
- if (this.decodeStrings) {
- return JsonStringDecoder.decodeForSure(buffer, startIndex, endIndex);
- } else {
- return toString();
- }
- }
-
- public String stringValueEncoded() {
- return JsonStringDecoder.decode(buffer, startIndex, endIndex);
- }
-
- public Date dateValue() {
- if (type == Type.STRING) {
-
- if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
-
- if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
- return Dates.fromJsonDate(buffer, startIndex, endIndex);
-
- } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
- return Dates.fromISO8601(buffer, startIndex, endIndex);
- } else {
- throw new JsonException("Unable to convert " + stringValue() + " to date ");
- }
- } else {
- throw new JsonException("Unable to convert " + stringValue() + " to date ");
- }
- } else {
- return new Date(Dates.utc(longValue()));
- }
- }
-
- public int intValue() {
- int sign = 1;
- if (buffer[startIndex] == '-') {
- startIndex++;
- sign = -1;
- }
- return parseIntFromTo(buffer, startIndex, endIndex) * sign;
- }
-
- public long longValue() {
- if (isInteger(buffer, startIndex, endIndex - startIndex)) {
- return parseIntFromTo(buffer, startIndex, endIndex);
- } else {
- return parseLongFromTo(buffer, startIndex, endIndex);
- }
- }
-
- public byte byteValue() {
- return (byte) intValue();
- }
-
- public short shortValue() {
- return (short) intValue();
- }
-
- public double doubleValue() {
- return CharScanner.parseDouble(this.buffer, startIndex, endIndex);
- }
-
- public boolean booleanValue() {
- return Boolean.parseBoolean(toString());
- }
-
- public float floatValue() {
- return CharScanner.parseFloat(this.buffer, startIndex, endIndex);
- }
-
- public final void chop() {
- if (!chopped) {
- this.chopped = true;
- this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
- this.startIndex = 0;
- this.endIndex = this.buffer.length;
- }
- }
-
- public char charValue() {
- return buffer[startIndex];
- }
-}
[5/7] groovy git commit: GROOVY-8379: Rework groovy-json
FastStringUtils (closes #667)
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
deleted file mode 100644
index cffcd34..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public class JsonStringDecoder {
-
- public static String decode(char[] chars, int start, int to) {
- if (!Chr.contains(chars, '\\', start, to - start)) {
- return new String(chars, start, to - start);
- }
- return decodeForSure(chars, start, to);
- }
-
- public static String decodeForSure(char[] chars, int start, int to) {
- CharBuf builder = CharBuf.create(to - start);
- builder.decodeJsonString(chars, start, to);
- return builder.toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
deleted file mode 100644
index 6d14ed1..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.lang.reflect.Array;
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-/**
- * This maps only builds once you ask for a key for the first time.
- * It is designed to not incur the overhead of creating a map unless needed.
- *
- * @author Rick Hightower
- */
-public class LazyMap extends AbstractMap<String, Object> {
-
- static final String JDK_MAP_ALTHASHING_SYSPROP = System.getProperty("jdk.map.althashing.threshold");
-
- /* Holds the actual map that will be lazily created. */
- private Map<String, Object> map;
- /* The size of the map. */
- private int size;
- /* The keys stored in the map. */
- private String[] keys;
- /* The values stored in the map. */
- private Object[] values;
-
- public LazyMap() {
- keys = new String[5];
- values = new Object[5];
- }
-
- public LazyMap(int initialSize) {
- keys = new String[initialSize];
- values = new Object[initialSize];
- }
-
- public Object put(String key, Object value) {
- if (map == null) {
- for (int i = 0; i < size; i++) {
- String curKey = keys[i];
- if ((key == null && curKey == null)
- || (key != null && key.equals(curKey))) {
- Object val = values[i];
- keys[i] = key;
- values[i] = value;
- return val;
- }
- }
- keys[size] = key;
- values[size] = value;
- size++;
- if (size == keys.length) {
- keys = grow(keys);
- values = grow(values);
- }
- return null;
- } else {
- return map.put(key, value);
- }
- }
-
- public Set<Entry<String, Object>> entrySet() {
- buildIfNeeded();
- return map.entrySet();
- }
-
- public int size() {
- if (map == null) {
- return size;
- } else {
- return map.size();
- }
- }
-
- public boolean isEmpty() {
- if (map == null) {
- return size == 0;
- } else {
- return map.isEmpty();
- }
- }
-
- public boolean containsValue(Object value) {
- buildIfNeeded();
- return map.containsValue(value);
- }
-
- public boolean containsKey(Object key) {
- buildIfNeeded();
- return map.containsKey(key);
- }
-
- public Object get(Object key) {
- buildIfNeeded();
- return map.get(key);
- }
-
- private void buildIfNeeded() {
- if (map == null) {
- // added to avoid hash collision attack
- if (Sys.is1_8OrLater() || (Sys.is1_7() && JDK_MAP_ALTHASHING_SYSPROP != null)) {
- map = new LinkedHashMap<String, Object>(size, 0.01f);
- } else {
- map = new TreeMap<String, Object>();
- }
-
- for (int index = 0; index < size; index++) {
- map.put(keys[index], values[index]);
- }
- this.keys = null;
- this.values = null;
- }
- }
-
- public Object remove(Object key) {
- buildIfNeeded();
- return map.remove(key);
- }
-
- public void putAll(Map m) {
- buildIfNeeded();
- map.putAll(m);
- }
-
- public void clear() {
- if (map == null) {
- size = 0;
- } else {
- map.clear();
- }
- }
-
- public Set<String> keySet() {
- buildIfNeeded();
- return map.keySet();
- }
-
- public Collection<Object> values() {
- buildIfNeeded();
- return map.values();
- }
-
- public boolean equals(Object o) {
- buildIfNeeded();
- return map.equals(o);
- }
-
- public int hashCode() {
- buildIfNeeded();
- return map.hashCode();
- }
-
- public String toString() {
- buildIfNeeded();
- return map.toString();
- }
-
- protected Object clone() throws CloneNotSupportedException {
- if (map == null) {
- return null;
- } else {
- if (map instanceof LinkedHashMap) {
- return ((LinkedHashMap) map).clone();
- } else {
- return new LinkedHashMap(this);
- }
- }
- }
-
- public LazyMap clearAndCopy() {
- LazyMap map = new LazyMap();
- for (int index = 0; index < size; index++) {
- map.put(keys[index], values[index]);
- }
- size = 0;
- return map;
- }
-
- public static <V> V[] grow(V[] array) {
- Object newArray = Array.newInstance(array.getClass().getComponentType(), array.length * 2);
- System.arraycopy(array, 0, newArray, 0, array.length);
- return (V[]) newArray;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
deleted file mode 100644
index 364a76e..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * This class is important to the performance of the parser.
- * It stores Value objects in a map where they are evaluated lazily.
- * This is great for JSONPath types of application, and Object Serialization but not for maps that are going to be stored in a cache.
- * <p/>
- * This is because the Value construct is a type of index overlay that merely tracks where the token is located in the buffer,
- * and what if any thing we noted about it (like can be converted to a decimal number, etc.).
- * <p/>
- * To mitigate memory leaks this class along with CharSequenceValue implement two constructs, namely,
- * chop, and lazyChop.
- * <p/>
- * A chop is when we convert backing buffer of a Value object into a smaller buffer.
- * A lazyChop is when we do a chop but only when a get operation is called.
- * <p/>
- * The lazyChop is performed on the tree that is touched by the JSONPath expression or its ilk.
- * <p/>
- * The chop operation can be done during parsing or lazily by storing the values in this construct.
- *
- * @author Rick Hightower (insane chipmonk)
- */
-public class LazyValueMap extends AbstractMap<String, Object> implements ValueMap<String, Object> {
-
- /**
- * holds the map that gets lazily created on first access.
- */
- private Map<String, Object> map = null;
- /**
- * holds the list of items that we are managing.
- */
- private Entry<String, Value>[] items;
- /**
- * Holds the current number mapping managed by this map.
- */
- private int len = 0;
- /**
- * Holds whether or not we ae in lazy chop mode or not.
- */
- private final boolean lazyChop;
-
- /**
- * Keep track if this map has already been chopped so we don't waste time trying to chop it again.
- */
- boolean mapChopped = false;
-
- public LazyValueMap(boolean lazyChop) {
- this.items = new Entry[5];
- this.lazyChop = lazyChop;
- }
-
- public LazyValueMap(boolean lazyChop, int initialSize) {
- this.items = new Entry[initialSize];
- this.lazyChop = lazyChop;
- }
-
- /**
- * Adds a new MapItemValue to the mapping.
- *
- * @param miv miv we are adding.
- */
- public final void add(MapItemValue miv) {
- if (len >= items.length) {
- items = LazyMap.grow(items);
- }
- items[len] = miv;
- len++;
- }
-
- /**
- * Gets the item by key from the mapping.
- *
- * @param key to lookup
- * @return the item for the given key
- */
- public final Object get(Object key) {
- Object object = null;
-
- /* if the map is null, then we create it. */
- if (map == null) {
- buildMap();
- }
- object = map.get(key);
-
- lazyChopIfNeeded(object);
- return object;
- }
-
- /**
- * If in lazy chop mode, and the object is a Lazy Value Map or a ValueList
- * then we force a chop operation for each of its items.
- */
- private void lazyChopIfNeeded(Object object) {
- if (lazyChop) {
- if (object instanceof LazyValueMap) {
- LazyValueMap m = (LazyValueMap) object;
- m.chopMap();
- } else if (object instanceof ValueList) {
- ValueList list = (ValueList) object;
- list.chopList();
- }
- }
- }
-
- /**
- * Chop this map.
- */
- public final void chopMap() {
- /* if it has been chopped then you have to return. */
- if (mapChopped) {
- return;
- }
- mapChopped = true;
-
- /* If the internal map was not create yet, don't. We can chop the value w/o creating the internal map.*/
- if (this.map == null) {
- for (int index = 0; index < len; index++) {
- MapItemValue entry = (MapItemValue) items[index];
-
- Value value = entry.getValue();
- if (value == null) continue;
- if (value.isContainer()) {
- chopContainer(value);
- } else {
- value.chop();
- }
- }
- } else {
- /* Iterate through the map and do the same thing. Make sure children and children of children are chopped. */
- for (Map.Entry<String, Object> entry : map.entrySet()) {
-
- Object object = entry.getValue();
- if (object instanceof Value) {
- Value value = (Value) object;
- if (value.isContainer()) {
- chopContainer(value);
- } else {
- value.chop();
- }
- } else if (object instanceof LazyValueMap) {
- LazyValueMap m = (LazyValueMap) object;
- m.chopMap();
- } else if (object instanceof ValueList) {
- ValueList list = (ValueList) object;
- list.chopList();
- }
- }
- }
- }
-
- /* We need to chop up this child container. */
- private static void chopContainer(Value value) {
- Object obj = value.toValue();
- if (obj instanceof LazyValueMap) {
- LazyValueMap map = (LazyValueMap) obj;
- map.chopMap();
- } else if (obj instanceof ValueList) {
- ValueList list = (ValueList) obj;
- list.chopList();
- }
- }
-
- public Value put(String key, Object value) {
- die("Not that kind of map");
- return null;
- }
-
- public Set<Entry<String, Object>> entrySet() {
- if (map == null) {
- buildMap();
- }
- return map.entrySet();
- }
-
- private void buildMap() {
- // added to avoid hash collision attack
- if (Sys.is1_8OrLater() || (Sys.is1_7() && LazyMap.JDK_MAP_ALTHASHING_SYSPROP != null)) {
- map = new HashMap<String, Object>(items.length);
- } else {
- map = new TreeMap<String, Object>();
- }
-
- for (Entry<String, Value> miv : items) {
- if (miv == null) {
- break;
- }
- map.put(miv.getKey(), miv.getValue().toValue());
- }
-
- len = 0;
- items = null;
- }
-
- public Collection<Object> values() {
- if (map == null) buildMap();
- return map.values();
- }
-
- public int size() {
- if (map == null) buildMap();
- return map.size();
- }
-
- public String toString() {
- if (map == null) buildMap();
- return map.toString();
- }
-
- public int len() {
- return len;
- }
-
- public boolean hydrated() {
- return map != null;
- }
-
- public Entry<String, Value>[] items() {
- return items;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
deleted file mode 100644
index 0047ae7..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * This holds a mapping from value key to value value to maximize laziness.
- *
- * @author Rick Hightower
- */
-public class MapItemValue implements Map.Entry<String, Value> {
-
- final Value name;
- final Value value;
-
- private String key = null;
-
- private static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.implementation.internKeys", "false"));
-
- protected static ConcurrentHashMap<String, String> internedKeysCache;
-
- static {
- if (internKeys) {
- internedKeysCache = new ConcurrentHashMap<String, String>();
- }
- }
-
- public MapItemValue(Value name, Value value) {
- this.name = name;
- this.value = value;
- }
-
- public String getKey() {
- if (key == null) {
- if (internKeys) {
- key = name.toString();
-
- String keyPrime = internedKeysCache.get(key);
- if (keyPrime == null) {
- key = key.intern();
- internedKeysCache.put(key, key);
- } else {
- key = keyPrime;
- }
- } else {
- key = name.toString();
- }
- }
- return key;
- }
-
- public Value getValue() {
- return value;
- }
-
- public Value setValue(Value value) {
- die("not that kind of Entry");
- return null;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
deleted file mode 100644
index 800431a..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Date;
-
-import static groovy.json.internal.CharScanner.isInteger;
-import static groovy.json.internal.CharScanner.parseIntFromTo;
-import static groovy.json.internal.CharScanner.parseLongFromTo;
-import static groovy.json.internal.Exceptions.die;
-import static groovy.json.internal.Exceptions.sputs;
-
-/**
- * @author Rick Hightower
- */
-public class NumberValue extends java.lang.Number implements Value {
-
- private char[] buffer;
- private boolean chopped;
- private int startIndex;
- private int endIndex;
- private final Type type;
- private Object value;
-
- public NumberValue(Type type) {
- this.type = type;
- }
-
- public NumberValue() {
- this.type = null;
- }
-
- public NumberValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer) {
- this.type = type;
-
- try {
- if (chop) {
- this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
- this.startIndex = 0;
- this.endIndex = this.buffer.length;
- chopped = true;
- } else {
- this.startIndex = startIndex;
- this.endIndex = endIndex;
- this.buffer = buffer;
- }
- } catch (Exception ex) {
- Exceptions.handle(sputs("exception", ex, "start", startIndex, "end", endIndex), ex);
- }
-
- // Check for a single minus now, rather than finding out later during lazy parsing.
- if (this.endIndex - this.startIndex == 1 && this.buffer[this.startIndex] == '-') {
- die("A single minus is not a valid number");
- }
-
- }
-
- public String toString() {
- if (startIndex == 0 && endIndex == buffer.length) {
- return FastStringUtils.noCopyStringFromChars(buffer);
- } else {
- return new String(buffer, startIndex, (endIndex - startIndex));
- }
- }
-
- public final Object toValue() {
- return value != null ? value : (value = doToValue());
- }
-
- public <T extends Enum> T toEnum(Class<T> cls) {
- return toEnum(cls, intValue());
- }
-
- public static <T extends Enum> T toEnum(Class<T> cls, int value) {
- T[] enumConstants = cls.getEnumConstants();
- for (T e : enumConstants) {
- if (e.ordinal() == value) {
- return e;
- }
- }
- die("Can't convert ordinal value " + value + " into enum of type " + cls);
- return null;
- }
-
- public boolean isContainer() {
- return false;
- }
-
- private Object doToValue() {
- switch (type) {
- case DOUBLE:
- return bigDecimalValue();
- case INTEGER:
- if (isInteger(buffer, startIndex, endIndex - startIndex)) {
- return intValue();
- } else {
- return longValue();
- }
- }
- die();
- return null;
- }
-
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof Value)) return false;
-
- NumberValue value1 = (NumberValue) o;
-
- if (endIndex != value1.endIndex) return false;
- if (startIndex != value1.startIndex) return false;
- if (!Arrays.equals(buffer, value1.buffer)) return false;
- if (type != value1.type) return false;
- return value != null ? value.equals(value1.value) : value1.value == null;
-
- }
-
- public int hashCode() {
- int result = type != null ? type.hashCode() : 0;
- result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
- result = 31 * result + startIndex;
- result = 31 * result + endIndex;
- result = 31 * result + (value != null ? value.hashCode() : 0);
- return result;
- }
-
- public BigDecimal bigDecimalValue() {
- try {
- return new BigDecimal(buffer, startIndex, endIndex - startIndex);
- } catch (NumberFormatException e) {
- throw new JsonException("unable to parse " + new String(buffer, startIndex, endIndex - startIndex), e);
- }
- }
-
- public BigInteger bigIntegerValue() {
- return new BigInteger(toString());
- }
-
- public String stringValue() {
- return toString();
- }
-
- public String stringValueEncoded() {
- return toString();
- }
-
- public Date dateValue() {
- return new Date(Dates.utc(longValue()));
- }
-
- public int intValue() {
- return parseIntFromTo(buffer, startIndex, endIndex);
- }
-
- public long longValue() {
- if (isInteger(buffer, startIndex, endIndex - startIndex)) {
- return parseIntFromTo(buffer, startIndex, endIndex);
- } else {
- return parseLongFromTo(buffer, startIndex, endIndex);
- }
- }
-
- public byte byteValue() {
- return (byte) intValue();
- }
-
- public short shortValue() {
- return (short) intValue();
- }
-
- public double doubleValue() {
- return CharScanner.parseDouble(this.buffer, startIndex, endIndex);
- }
-
- public boolean booleanValue() {
- return Boolean.parseBoolean(toString());
- }
-
- public float floatValue() {
- return CharScanner.parseFloat(this.buffer, startIndex, endIndex);
- }
-
- public final void chop() {
- if (!chopped) {
- this.chopped = true;
- this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
- this.startIndex = 0;
- this.endIndex = this.buffer.length;
- }
- }
-
- public char charValue() {
- return buffer[startIndex];
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
deleted file mode 100644
index 22976bd..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-
-/**
- * @author Richard Hightower
- */
-public class ReaderCharacterSource implements CharacterSource {
-
- private static final int MAX_TOKEN_SIZE = 5;
-
- private final Reader reader;
- private final int readAheadSize;
- private int ch = -2;
-
- private boolean foundEscape;
-
- private final char[] readBuf;
-
- private int index;
-
- private int length;
-
- boolean more = true;
- private boolean done = false;
-
- public ReaderCharacterSource(final Reader reader, final int readAheadSize) {
- this.reader = reader;
- this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
- this.readAheadSize = readAheadSize;
- }
-
- public ReaderCharacterSource(final Reader reader) {
- this.reader = reader;
- this.readAheadSize = 10000;
- this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
- }
-
- public ReaderCharacterSource(final String string) {
- this(new StringReader(string));
- }
-
- private void readForToken() {
- try {
- length += reader.read(readBuf, readBuf.length - MAX_TOKEN_SIZE, MAX_TOKEN_SIZE);
- } catch (IOException e) {
- Exceptions.handle(e);
- }
- }
-
- private void ensureBuffer() {
- try {
- if (index >= length && !done) {
- readNextBuffer();
- } else {
- more = !(done && index >= length);
- }
- } catch (Exception ex) {
- String str = CharScanner.errorDetails("ensureBuffer issue", readBuf, index, ch);
- Exceptions.handle(str, ex);
- }
- }
-
- private void readNextBuffer() throws IOException {
- length = reader.read(readBuf, 0, readAheadSize);
-
- index = 0;
- if (length == -1) {
- ch = -1;
- length = 0;
- more = false;
- done = true;
- } else {
- more = true;
- }
- }
-
- public final int nextChar() {
- ensureBuffer();
- return ch = readBuf[index++];
- }
-
- public final int currentChar() {
- ensureBuffer();
- return readBuf[index];
- }
-
- public final boolean hasChar() {
- ensureBuffer();
- return more;
- }
-
- public final boolean consumeIfMatch(char[] match) {
- try {
- char[] _chars = readBuf;
- int i = 0;
- int idx = index;
- boolean ok = true;
-
- if (idx + match.length > length) {
- readForToken();
- }
-
- for (; i < match.length; i++, idx++) {
- ok &= (match[i] == _chars[idx]);
- if (!ok) break;
- }
-
- if (ok) {
- index = idx;
- return true;
- } else {
- return false;
- }
- } catch (Exception ex) {
- String str = CharScanner.errorDetails("consumeIfMatch issue", readBuf, index, ch);
- return Exceptions.handle(boolean.class, str, ex);
- }
- }
-
- public final int location() {
- return index;
- }
-
- public final int safeNextChar() {
- try {
- ensureBuffer();
- return index + 1 < readBuf.length ? readBuf[index++] : -1;
- } catch (Exception ex) {
- String str = CharScanner.errorDetails("safeNextChar issue", readBuf, index, ch);
- return Exceptions.handle(int.class, str, ex);
- }
- }
-
- private static final char[] EMPTY_CHARS = new char[0];
-
- public char[] findNextChar(int match, int esc) {
- try {
- ensureBuffer();
-
- foundEscape = false;
- if (readBuf[index] == '"') {
- index++;
- return EMPTY_CHARS;
- }
-
- int start = index;
-
- char[] results = null;
- boolean foundEnd = false;
- boolean wasEscaped = false;
- while (!foundEnd) {
- for (; index < length; index++) {
- ch = readBuf[index];
- if (wasEscaped) {
- wasEscaped = false;
- } else if (ch == match) {
- foundEnd = true;
- break;
- } else if (ch == esc) {
- foundEscape = true;
- wasEscaped = true;
- }
- }
-
- if (results != null) {
- results = Chr.add(results, ArrayUtils.copyRange(readBuf, start, index));
- }
- else {
- results = ArrayUtils.copyRange(readBuf, start, index);
- }
-
- ensureBuffer();
-
- // Reset start if new buffer
- if (index == 0) {
- start = 0;
- }
-
- // Exit early if we run out of data
- if (done) {
- break;
- }
- }
-
- // done will only be true if we ran out of data without seeing the match character
- if (done) {
- return Exceptions.die(char[].class, "Unable to find close char " + (char)match + ": " + new String(results));
- } else {
- index++;
- return results;
- }
- } catch (Exception ex) {
- String str = CharScanner.errorDetails("findNextChar issue", readBuf, index, ch);
- return Exceptions.handle(char[].class, str, ex);
- }
- }
-
- public boolean hadEscape() {
- return foundEscape;
- }
-
- public void skipWhiteSpace() {
- try {
- index = CharScanner.skipWhiteSpace(readBuf, index, length);
- if (index >= length && more) {
- ensureBuffer();
-
- skipWhiteSpace();
- }
- } catch (Exception ex) {
- String str = CharScanner.errorDetails("skipWhiteSpace issue", readBuf, index, ch);
- Exceptions.handle(str, ex);
- }
- }
-
- public char[] readNumber() {
- try {
- ensureBuffer();
-
- char[] results = CharScanner.readNumber(readBuf, index, length);
- index += results.length;
-
- if (index >= length && more) {
- ensureBuffer();
- if (length != 0) {
- char results2[] = readNumber();
- return Chr.add(results, results2);
- } else {
- return results;
- }
- } else {
- return results;
- }
- } catch (Exception ex) {
- String str = CharScanner.errorDetails("readNumber issue", readBuf, index, ch);
- return Exceptions.handle(char[].class, str, ex);
- }
- }
-
- public String errorDetails(String message) {
- return CharScanner.errorDetails(message, readBuf, index, ch);
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
deleted file mode 100644
index 92bb400..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import org.codehaus.groovy.runtime.memoize.CommonCache;
-import org.codehaus.groovy.runtime.memoize.EvictableCache;
-
-/**
- * @author Richard Hightower
- */
-public class SimpleCache<K, V> implements Cache<K, V> {
- private EvictableCache<K, V> cache;
-
- public SimpleCache(final int limit, CacheType type) {
- if (type.equals(CacheType.LRU)) {
- cache = new CommonCache<K, V>(limit);
- } else {
- cache = new CommonCache<K, V>(CommonCache.DEFAULT_INITIAL_CAPACITY, limit, EvictableCache.EvictionStrategy.FIFO);
- }
- }
-
- public SimpleCache(final int limit) {
- this(limit, CacheType.LRU);
- }
-
- public void put(K key, V value) {
- cache.put(key, value);
- }
-
- public V get(K key) {
- return cache.get(key);
- }
-
- //For testing only
-
- public V getSilent(K key) {
- V value = cache.get(key);
- if (value != null) {
- cache.remove(key);
- cache.put(key, value);
- }
- return value;
- }
-
- public void remove(K key) {
- cache.remove(key);
- }
-
- public int size() {
- return cache.size();
- }
-
- public String toString() {
- return cache.toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
deleted file mode 100644
index 4d8c3ed..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-class Sys {
-
- private static final boolean is1_8OrLater;
- private static final boolean is1_7;
- private static final boolean is1_8;
-
- static {
- BigDecimal v = new BigDecimal("-1");
- String sversion = System.getProperty("java.version");
- if (sversion.indexOf("_") != -1) {
- final String[] split = sversion.split("_");
- try {
- String ver = split[0];
-
- if (ver.startsWith("1.7")) {
- v = new BigDecimal("1.7");
- }
-
- if (ver.startsWith("1.8")) {
- v = new BigDecimal("1.8");
- }
-
- if (ver.startsWith("1.9")) {
- v = new BigDecimal("1.9");
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- System.err.println("Unable to determine build number or version");
- }
- } else if ("1.8.0".equals(sversion)) {
- v = new BigDecimal("1.8");
- } else {
- Pattern p = Pattern.compile("^([1-9]\\.[0-9]+)");
- Matcher matcher = p.matcher(sversion);
- if (matcher.find()) {
- v = new BigDecimal(matcher.group(0));
- }
- }
-
- is1_8OrLater = v.compareTo(new BigDecimal("1.8")) >= 0;
- is1_7 = v.compareTo(new BigDecimal("1.7")) == 0;
- is1_8 = v.compareTo(new BigDecimal("1.8")) == 0;
- }
-
- public static boolean is1_7OrLater() {
- return true;
- }
-
- public static boolean is1_8OrLater() {
- return is1_8OrLater;
- }
-
- public static boolean is1_7() {
- return is1_7;
- }
-
- public static boolean is1_8() {
- return is1_8;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java
deleted file mode 100644
index b37d4eb..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Type.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public enum Type {
-
- INTEGER, STRING, DOUBLE, TRUE, FALSE, NULL, MAP, LIST
-
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java
deleted file mode 100644
index 095609b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Value.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Date;
-
-/**
- * @author Rick Hightower
- */
-public interface Value {
-
- byte byteValue();
-
- short shortValue();
-
- int intValue();
-
- long longValue();
-
- BigDecimal bigDecimalValue();
-
- BigInteger bigIntegerValue();
-
- float floatValue();
-
- double doubleValue();
-
- boolean booleanValue();
-
- Date dateValue();
-
- String stringValue();
-
- String stringValueEncoded();
-
- Object toValue();
-
- <T extends Enum> T toEnum(Class<T> cls);
-
- boolean isContainer(); //either a map or a collection
-
- void chop();
-
- char charValue();
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
deleted file mode 100644
index a173ea5..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-import static groovy.json.internal.Exceptions.die;
-import static groovy.json.internal.Exceptions.sputs;
-
-/**
- * @author Rick Hightower
- */
-public class ValueContainer implements CharSequence, Value {
-
- public static final Value TRUE = new ValueContainer(Type.TRUE);
- public static final Value FALSE = new ValueContainer(Type.FALSE);
- public static final Value NULL = new ValueContainer(Type.NULL);
-
- public Object value;
-
- public Type type;
- private boolean container;
-
- public boolean decodeStrings;
-
- public ValueContainer(Object value, Type type, boolean decodeStrings) {
- this.value = value;
- this.type = type;
- this.decodeStrings = decodeStrings;
- }
-
- public ValueContainer(Type type) {
- this.type = type;
- }
-
- public ValueContainer(Map<String, Object> map) {
- this.value = map;
- this.type = Type.MAP;
- this.container = true;
- }
-
- public ValueContainer(List<Object> list) {
- this.value = list;
- this.type = Type.LIST;
- this.container = true;
- }
-
- public int intValue() {
- return die(int.class, sputs("intValue not supported for type ", type));
- }
-
- public long longValue() {
- return die(int.class, sputs("intValue not supported for type ", type));
- }
-
- public boolean booleanValue() {
- switch (type) {
- case FALSE:
- return false;
- case TRUE:
- return true;
- }
- die();
- return false;
- }
-
- public String stringValue() {
- if (type == Type.NULL) {
- return null;
- } else {
- return type.toString();
- }
- }
-
- public String stringValueEncoded() {
- return toString();
- }
-
- public String toString() {
- return type.toString();
- }
-
- public Object toValue() {
- if (value != null) {
- return value;
- }
- switch (type) {
- case FALSE:
- return (value = false);
-
- case TRUE:
- return (value = true);
- case NULL:
- return null;
- }
- die();
- return null;
- }
-
- public <T extends Enum> T toEnum(Class<T> cls) {
- return (T) value;
- }
-
- public boolean isContainer() {
- return container;
- }
-
- public void chop() {
- }
-
- public char charValue() {
- return 0;
- }
-
- public int length() {
- return 0;
- }
-
- public char charAt(int index) {
- return '0';
- }
-
- public CharSequence subSequence(int start, int end) {
- return "";
- }
-
- public Date dateValue() {
- return null;
- }
-
- public byte byteValue() {
- return 0;
- }
-
- public short shortValue() {
- return 0;
- }
-
- public BigDecimal bigDecimalValue() {
- return null;
- }
-
- public BigInteger bigIntegerValue() {
- return null;
- }
-
- public double doubleValue() {
- return 0;
- }
-
- public float floatValue() {
- return 0;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
deleted file mode 100644
index 0320791..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * @author Rick Hightower
- */
-public class ValueList extends AbstractList<Object> {
-
- List<Object> list = new ArrayList<Object>(5);
-
- private final boolean lazyChop;
- boolean converted = false;
-
- public ValueList(boolean lazyChop) {
- this.lazyChop = lazyChop;
- }
-
- public Object get(int index) {
- Object obj = list.get(index);
-
- if (obj instanceof Value) {
- obj = convert((Value) obj);
- list.set(index, obj);
- }
-
- chopIfNeeded(obj);
- return obj;
- }
-
- private static Object convert(Value value) {
- return value.toValue();
- }
-
- public int size() {
- return list.size();
- }
-
- public Iterator<Object> iterator() {
- convertAllIfNeeded();
- return list.iterator();
- }
-
- private void convertAllIfNeeded() {
- if (!converted) {
- converted = true;
- for (int index = 0; index < list.size(); index++) {
- this.get(index);
- }
- }
- }
-
- public void clear() {
- list.clear();
- }
-
- public boolean add(Object obj) {
- return list.add(obj);
- }
-
- public void chopList() {
- for (Object obj : list) {
- if (obj == null) continue;
-
- if (obj instanceof Value) {
- Value value = (Value) obj;
- if (value.isContainer()) {
- chopContainer(value);
- } else {
- value.chop();
- }
- }
- }
- }
-
- private void chopIfNeeded(Object object) {
- if (lazyChop) {
- if (object instanceof LazyValueMap) {
- LazyValueMap m = (LazyValueMap) object;
- m.chopMap();
- } else if (object instanceof ValueList) {
- ValueList list = (ValueList) object;
- list.chopList();
- }
- }
- }
-
- static void chopContainer(Value value) {
- Object obj = value.toValue();
- if (obj instanceof LazyValueMap) {
- LazyValueMap map = (LazyValueMap) obj;
- map.chopMap();
- } else if (obj instanceof ValueList) {
- ValueList list = (ValueList) obj;
- list.chopList();
- }
- }
-
- public List<Object> list() {
- return this.list;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
deleted file mode 100644
index f9d1482..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.Map;
-
-/**
- * @author Richard Hightower
- */
-public interface ValueMap<K, V> extends Map<K, V> {
-
- /* add a map item value. */
- void add(MapItemValue miv);
-
- /**
- * Return size w/o hydrating the map.
- */
- int len();
-
- /**
- * Has the map been hydrated.
- */
- boolean hydrated();
-
- /**
- * Give me the items in the map without hydrating the map.
- * Realize that the array is likely larger than the length so array items can be null.
- */
- Entry<String, Value>[] items();
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
deleted file mode 100644
index 31a7b2c..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import static groovy.json.internal.Exceptions.die;
-
-/**
- * This map is for object serialization mainly.
- * The idea is the final conversion of
- * the Value objects are delayed until the last possible moment, i.e., just before injected into a bean.
- *
- * @author Rick Hightower
- */
-public class ValueMapImpl extends AbstractMap<String, Value> implements ValueMap<String, Value> {
-
- /**
- * The internal map to hold the Value map.
- */
- private Map<String, Value> map = null;
-
- /**
- * The items held in the map.
- */
- private Entry<String, Value>[] items = new Entry[20];
-
- /* The current length of the map. */
- private int len = 0;
-
- /**
- * Add a MapItemValue to the map.
- *
- * @param miv map value item.
- */
-
- public void add(MapItemValue miv) {
- if (len >= items.length) {
- items = LazyMap.grow(items);
- }
- items[len] = miv;
- len++;
- }
-
- public int len() {
- return len;
- }
-
- public boolean hydrated() {
- return map != null;
- }
-
- public Entry<String, Value>[] items() {
- return items;
- }
-
- /**
- * Get the items for the key.
- *
- * @param key
- * @return the items for the given key
- */
-
- public Value get(Object key) {
- /* If the length is under and we are asking for the key, then just look for the key. Don't build the map. */
- if (map == null && items.length < 20) {
- for (Object item : items) {
- MapItemValue miv = (MapItemValue) item;
- if (key.equals(miv.name.toValue())) {
- return miv.value;
- }
- }
- return null;
- } else {
- if (map == null) buildIfNeededMap();
- return map.get(key);
- }
- }
-
- public Value put(String key, Value value) {
- die("Not that kind of map");
- return null;
- }
-
- /**
- * If the map has not been built yet, then we just return a fake entry set.
- */
-
- public Set<Entry<String, Value>> entrySet() {
- buildIfNeededMap();
- return map.entrySet();
- }
-
- /**
- * Build the map if requested to, it does this lazily.
- */
- private void buildIfNeededMap() {
- if (map == null) {
- map = new HashMap<String, Value>(items.length);
-
- for (Entry<String, Value> miv : items) {
- if (miv == null) {
- break;
- }
- map.put(miv.getKey(), miv.getValue());
- }
- }
- }
-
- /**
- * Return a collection of values.
- */
- public Collection<Value> values() {
- this.buildIfNeededMap();
- return map.values();
- }
-
- /**
- * Return the size of the map. Use the map if it has already been created.
- *
- * @return size
- */
- public int size() {
- this.buildIfNeededMap();
- return map.size();
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java
new file mode 100644
index 0000000..3e96459
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringService.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json;
+
+import org.apache.groovy.json.FastStringService;
+
+/**
+ * Internal class for fast processing of Strings during JSON parsing - default version
+ */
+public class DefaultFastStringService implements FastStringService {
+ @Override
+ public char[] toCharArray(String string) {
+ return string.toCharArray();
+ }
+
+ @Override
+ public String noCopyStringFromChars(char[] chars) {
+ return new String(chars);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java
new file mode 100644
index 0000000..46d8a34
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/DefaultFastStringServiceFactory.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json;
+
+public class DefaultFastStringServiceFactory implements FastStringServiceFactory {
+ @Override
+ public FastStringService getService() {
+ return new DefaultFastStringService();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java
new file mode 100644
index 0000000..4381383
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringService.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json;
+
+public interface FastStringService {
+ /**
+ * @param string string to grab array from.
+ * @return char array from string
+ */
+ char[] toCharArray(String string);
+
+ /**
+ * @param chars to shove array into.
+ * @return new string with chars copied into it
+ */
+ String noCopyStringFromChars(char[] chars);
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java
new file mode 100644
index 0000000..6568793
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/FastStringServiceFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json;
+
+/**
+ * Factory method to create the service. Should return null if the particular implementation
+ * isn't suitable because of the JDK environment (e.g. JVM version) or config settings otherwise
+ * disable the service.
+ */
+public interface FastStringServiceFactory {
+ FastStringService getService();
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java
new file mode 100644
index 0000000..4894f08
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ArrayUtils.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public class ArrayUtils {
+
+ public static char[] copyRange(char[] source, int startIndex, int endIndex) {
+ int len = endIndex - startIndex;
+ char[] copy = new char[len];
+ System.arraycopy(source, startIndex, copy, 0, Math.min(source.length - startIndex, len));
+ return copy;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java
new file mode 100644
index 0000000..c2e58b2
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/BaseJsonParser.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+import groovy.json.JsonParser;
+import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
+import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Base JSON parser.
+ * Scaled down version of Boon JsonParser with features
+ * removed that are JDK 1.7 dependent or Groovy duplicated functionality.
+ *
+ * @author Rick Hightower
+ */
+public abstract class BaseJsonParser implements JsonParser {
+
+ protected static final int COLON = ':';
+ protected static final int COMMA = ',';
+ protected static final int CLOSED_CURLY = '}';
+ protected static final int CLOSED_BRACKET = ']';
+
+ protected static final int LETTER_E = 'e';
+ protected static final int LETTER_BIG_E = 'E';
+
+ protected static final int MINUS = '-';
+ protected static final int PLUS = '+';
+
+ protected static final int DECIMAL_POINT = '.';
+
+ protected static final int ALPHA_0 = '0';
+ protected static final int ALPHA_1 = '1';
+ protected static final int ALPHA_2 = '2';
+ protected static final int ALPHA_3 = '3';
+ protected static final int ALPHA_4 = '4';
+ protected static final int ALPHA_5 = '5';
+ protected static final int ALPHA_6 = '6';
+ protected static final int ALPHA_7 = '7';
+ protected static final int ALPHA_8 = '8';
+ protected static final int ALPHA_9 = '9';
+
+ protected static final int DOUBLE_QUOTE = '"';
+
+ protected static final int ESCAPE = '\\';
+
+ protected static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.internKeys", "false"));
+ protected static ConcurrentHashMap<String, String> internedKeysCache;
+
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ protected String charset = UTF_8.name();
+
+ private CharBuf fileInputBuf;
+
+ protected int bufSize = 256;
+
+ static {
+ if (internKeys) {
+ internedKeysCache = new ConcurrentHashMap<String, String>();
+ }
+ }
+
+ protected String charDescription(int c) {
+ String charString;
+ if (c == ' ') {
+ charString = "[SPACE]";
+ } else if (c == '\t') {
+ charString = "[TAB]";
+
+ } else if (c == '\n') {
+ charString = "[NEWLINE]";
+
+ } else {
+ charString = "'" + (char) c + "'";
+ }
+
+ charString = charString + " with an int value of " + ((int) c);
+ return charString;
+ }
+
+ public void setCharset(String charset) {
+ this.charset = charset;
+ }
+
+ public Object parse(String jsonString) {
+ return parse(FastStringUtils.toCharArray(jsonString));
+ }
+
+ public Object parse(byte[] bytes) {
+ return parse(bytes, charset);
+ }
+
+ public Object parse(byte[] bytes, String charset) {
+ try {
+ return parse(new String(bytes, charset));
+ } catch (UnsupportedEncodingException e) {
+ return Exceptions.handle(Object.class, e);
+ }
+ }
+
+ public Object parse(CharSequence charSequence) {
+ return parse(FastStringUtils.toCharArray(charSequence));
+ }
+
+ public Object parse(Reader reader) {
+ fileInputBuf = IO.read(reader, fileInputBuf, bufSize);
+ return parse(fileInputBuf.readForRecycle());
+ }
+
+ public Object parse(InputStream input) {
+ return parse(input, charset);
+ }
+
+ public Object parse(InputStream input, String charset) {
+ try {
+ return parse(new InputStreamReader(input, charset));
+ } catch (UnsupportedEncodingException e) {
+ return Exceptions.handle(Object.class, e);
+ }
+ }
+
+ public Object parse(File file, String charset) {
+ Reader reader = null;
+ try {
+ if (charset == null || charset.length() == 0) {
+ reader = ResourceGroovyMethods.newReader(file);
+ } else {
+ reader = ResourceGroovyMethods.newReader(file, charset);
+ }
+ return parse(reader);
+ } catch (IOException ioe) {
+ throw new JsonException("Unable to process file: " + file.getPath(), ioe);
+ } finally {
+ if (reader != null) {
+ DefaultGroovyMethodsSupport.closeWithWarning(reader);
+ }
+ }
+ }
+
+ protected static boolean isDecimalChar(int currentChar) {
+ switch (currentChar) {
+ case MINUS:
+ case PLUS:
+ case LETTER_E:
+ case LETTER_BIG_E:
+ case DECIMAL_POINT:
+ return true;
+ }
+ return false;
+ }
+
+ protected static boolean isDelimiter(int c) {
+ return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
+ }
+
+ protected static final boolean isNumberDigit(int c) {
+ return c >= ALPHA_0 && c <= ALPHA_9;
+ }
+
+ protected static final boolean isDoubleQuote(int c) {
+ return c == DOUBLE_QUOTE;
+ }
+
+ protected static final boolean isEscape(int c) {
+ return c == ESCAPE;
+ }
+
+ protected static boolean hasEscapeChar(char[] array, int index, int[] indexHolder) {
+ char currentChar;
+ for (; index < array.length; index++) {
+ currentChar = array[index];
+ if (isDoubleQuote(currentChar)) {
+ indexHolder[0] = index;
+ return false;
+ } else if (isEscape(currentChar)) {
+ indexHolder[0] = index;
+ return true;
+ }
+ }
+
+ indexHolder[0] = index;
+ return false;
+ }
+
+ int[] indexHolder = new int[1];
+
+ protected static int findEndQuote(final char[] array, int index) {
+ char currentChar;
+ boolean escape = false;
+
+ for (; index < array.length; index++) {
+ currentChar = array[index];
+ if (isDoubleQuote(currentChar)) {
+ if (!escape) {
+ break;
+ }
+ }
+ escape = isEscape(currentChar) && !escape;
+ }
+ return index;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java
new file mode 100644
index 0000000..8ddfb96
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ByteScanner.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * @author Richard Hightower
+ */
+public class ByteScanner {
+
+ /**
+ * Turns a single nibble into an ascii HEX digit.
+ *
+ * @param nibble the nibble to serializeObject.
+ * @return the encoded nibble (1/2 byte).
+ */
+ protected static int encodeNibbleToHexAsciiCharByte(final int nibble) {
+ switch (nibble) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ return nibble + 0x30; // 0x30('0') - 0x39('9')
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x0E:
+ case 0x0F:
+ return nibble + 0x57; // 0x41('a') - 0x46('f')
+ default:
+ die("illegal nibble: " + nibble);
+ return -1;
+ }
+ }
+
+ /**
+ * Turn a single bytes into two hex character representation.
+ *
+ * @param decoded the byte to serializeObject.
+ * @param encoded the array to which each encoded nibbles are now ascii hex representations.
+ */
+ public static void encodeByteIntoTwoAsciiCharBytes(final int decoded, final byte[] encoded) {
+ encoded[0] = (byte) encodeNibbleToHexAsciiCharByte((decoded >> 4) & 0x0F);
+ encoded[1] = (byte) encodeNibbleToHexAsciiCharByte(decoded & 0x0F);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java
new file mode 100644
index 0000000..f5cfaaa
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Cache.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * Cache
+ *
+ * @param <KEY> key
+ * @param <VALUE> value
+ * @author Rick Hightower
+ */
+public interface Cache<KEY, VALUE> {
+
+ void put(KEY key, VALUE value);
+
+ VALUE get(KEY key);
+
+ VALUE getSilent(KEY key);
+
+ void remove(KEY key);
+
+ int size();
+}
+
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java
new file mode 100644
index 0000000..8d25bff
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CacheType.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Rick Hightower
+ */
+public enum CacheType {
+
+ LRU,
+ LFU,
+ FIFO
+}
+
[4/7] groovy git commit: GROOVY-8379: Rework groovy-json
FastStringUtils (closes #667)
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java
new file mode 100644
index 0000000..db850e1
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharBuf.java
@@ -0,0 +1,842 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * @author Rick Hightower
+ */
+public class CharBuf extends Writer implements CharSequence {
+
+ protected int capacity = 16;
+ protected int location = 0;
+
+ protected char[] buffer;
+
+ public CharBuf(char[] buffer) {
+ __init__(buffer);
+ }
+
+ private void __init__(char[] buffer) {
+ this.buffer = buffer;
+ this.capacity = buffer.length;
+ }
+
+ public CharBuf(byte[] bytes) {
+ this.buffer = null;
+ try {
+ String str = new String(bytes, "UTF-8");
+ __init__(FastStringUtils.toCharArray(str));
+ } catch (UnsupportedEncodingException e) {
+ Exceptions.handle(e);
+ }
+ }
+
+ public static CharBuf createExact(final int capacity) {
+ return new CharBuf(capacity) {
+ public CharBuf add(char[] chars) {
+ Chr._idx(buffer, location, chars);
+ location += chars.length;
+ return this;
+ }
+ };
+ }
+
+ public static CharBuf create(int capacity) {
+ return new CharBuf(capacity);
+ }
+
+ public static CharBuf create(char[] buffer) {
+ return new CharBuf(buffer);
+ }
+
+ protected CharBuf(int capacity) {
+ this.capacity = capacity;
+ init();
+ }
+
+ protected CharBuf() {
+ init();
+ }
+
+ public void write(char[] cbuf, int off, int len) {
+ if (off == 0 && cbuf.length == len) {
+ this.add(cbuf);
+ } else {
+ char[] buffer = ArrayUtils.copyRange(cbuf, off, off + len);
+ this.add(buffer);
+ }
+ }
+
+ public void flush() throws IOException {
+ }
+
+ public void close() throws IOException {
+ }
+
+ public void init() {
+ buffer = new char[capacity];
+ }
+
+ public final CharBuf add(String str) {
+ add(FastStringUtils.toCharArray(str));
+ return this;
+ }
+
+ public final CharBuf addString(String str) {
+ add(FastStringUtils.toCharArray(str));
+ return this;
+ }
+
+ public final CharBuf add(int i) {
+ add(Integer.toString(i));
+ return this;
+ }
+
+ private Cache<Integer, char[]> icache;
+
+ public final CharBuf addInt(int i) {
+ switch (i) {
+ case 0:
+ addChar('0');
+ return this;
+ case 1:
+ addChar('1');
+ return this;
+ case -1:
+ addChar('-');
+ addChar('1');
+ return this;
+ }
+
+ addInt(Integer.valueOf(i));
+ return this;
+ }
+
+ public final CharBuf addInt(Integer key) {
+ if (icache == null) {
+ icache = new SimpleCache<Integer, char[]>(20);
+ }
+ char[] chars = icache.get(key);
+
+ if (chars == null) {
+ String str = Integer.toString(key);
+ chars = FastStringUtils.toCharArray(str);
+ icache.put(key, chars);
+ }
+
+ addChars(chars);
+ return this;
+ }
+
+ final char[] trueChars = "true".toCharArray();
+ final char[] falseChars = "false".toCharArray();
+
+ public final CharBuf add(boolean b) {
+ addChars(b ? trueChars : falseChars);
+ return this;
+ }
+
+ public final CharBuf addBoolean(boolean b) {
+ add(Boolean.toString(b));
+ return this;
+ }
+
+ public final CharBuf add(byte i) {
+ add(Byte.toString(i));
+ return this;
+ }
+
+ public final CharBuf addByte(byte i) {
+ addInt(i);
+ return this;
+ }
+
+ public final CharBuf add(short i) {
+ add(Short.toString(i));
+ return this;
+ }
+
+ public final CharBuf addShort(short i) {
+ addInt(i);
+ return this;
+ }
+
+ public final CharBuf add(long l) {
+ add(Long.toString(l));
+ return this;
+ }
+
+ public final CharBuf add(double d) {
+ add(Double.toString(d));
+ return this;
+ }
+
+ private Cache<Double, char[]> dcache;
+
+ public final CharBuf addDouble(double d) {
+ addDouble(Double.valueOf(d));
+ return this;
+ }
+
+ public final CharBuf addDouble(Double key) {
+ if (dcache == null) {
+ dcache = new SimpleCache<Double, char[]>(20);
+ }
+ char[] chars = dcache.get(key);
+
+ if (chars == null) {
+ String str = Double.toString(key);
+ chars = FastStringUtils.toCharArray(str);
+ dcache.put(key, chars);
+ }
+
+ add(chars);
+ return this;
+ }
+
+ public final CharBuf add(float d) {
+ add(Float.toString(d));
+ return this;
+ }
+
+ private Cache<Float, char[]> fcache;
+
+ public final CharBuf addFloat(float d) {
+ addFloat(Float.valueOf(d));
+ return this;
+ }
+
+ public final CharBuf addFloat(Float key) {
+ if (fcache == null) {
+ fcache = new SimpleCache<Float, char[]>(20);
+ }
+ char[] chars = fcache.get(key);
+
+ if (chars == null) {
+ String str = Float.toString(key);
+ chars = FastStringUtils.toCharArray(str);
+ fcache.put(key, chars);
+ }
+
+ add(chars);
+
+ return this;
+ }
+
+ public final CharBuf addChar(byte i) {
+ add((char) i);
+ return this;
+ }
+
+ public final CharBuf addChar(int i) {
+ add((char) i);
+ return this;
+ }
+
+ public final CharBuf addChar(short i) {
+ add((char) i);
+ return this;
+ }
+
+ public final CharBuf addChar(final char ch) {
+ int _location = location;
+ char[] _buffer = buffer;
+ int _capacity = capacity;
+
+ if (1 + _location > _capacity) {
+ _buffer = Chr.grow(_buffer);
+ _capacity = _buffer.length;
+ }
+
+ _buffer[_location] = ch;
+ _location++;
+
+ location = _location;
+ buffer = _buffer;
+ capacity = _capacity;
+ return this;
+ }
+
+ public CharBuf addLine(String str) {
+ add(str.toCharArray());
+ add('\n');
+ return this;
+ }
+
+ public CharBuf addLine(CharSequence str) {
+ add(str.toString());
+ add('\n');
+ return this;
+ }
+
+ public CharBuf add(char[] chars) {
+ if (chars.length + location > capacity) {
+ buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
+ capacity = buffer.length;
+ }
+
+ Chr._idx(buffer, location, chars);
+ location += chars.length;
+ return this;
+ }
+
+ public final CharBuf addChars(char[] chars) {
+ if (chars.length + location > capacity) {
+ buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
+ capacity = buffer.length;
+ }
+
+ System.arraycopy(chars, 0, buffer, location, chars.length);
+ location += chars.length;
+ return this;
+ }
+
+ public final CharBuf addQuoted(char[] chars) {
+ int _location = location;
+ char[] _buffer = buffer;
+ int _capacity = capacity;
+
+ int sizeNeeded = chars.length + 2 + _location;
+ if (sizeNeeded > _capacity) {
+ _buffer = Chr.grow(_buffer, sizeNeeded * 2);
+ _capacity = _buffer.length;
+ }
+ _buffer[_location] = '"';
+ _location++;
+
+ System.arraycopy(chars, 0, _buffer, _location, chars.length);
+
+ _location += (chars.length);
+ _buffer[_location] = '"';
+ _location++;
+
+ location = _location;
+ buffer = _buffer;
+ capacity = _capacity;
+ return this;
+ }
+
+ public final CharBuf addJsonEscapedString(String jsonString) {
+ return addJsonEscapedString(jsonString, false);
+ }
+
+ public final CharBuf addJsonEscapedString(String jsonString, boolean disableUnicodeEscaping) {
+ char[] charArray = FastStringUtils.toCharArray(jsonString);
+ return addJsonEscapedString(charArray, disableUnicodeEscaping);
+ }
+
+ private static boolean shouldEscape(int c, boolean disableUnicodeEscaping) {
+ if (c < 32) { /* less than space is a control char */
+ return true;
+ } else if (c == 34) { /* double quote */
+ return true;
+ } else if (c == 92) { /* backslash */
+ return true;
+ } else if (!disableUnicodeEscaping && c > 126) { /* non-ascii char range */
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean hasAnyJSONControlChars(final char[] charArray, boolean disableUnicodeEscaping) {
+ int index = 0;
+ char c;
+ while (true) {
+ c = charArray[index];
+ if (shouldEscape(c, disableUnicodeEscaping)) {
+ return true;
+ }
+ if (++index >= charArray.length) return false;
+ }
+ }
+
+ public final CharBuf addJsonEscapedString(final char[] charArray) {
+ return addJsonEscapedString(charArray, false);
+ }
+
+ public final CharBuf addJsonEscapedString(final char[] charArray, boolean disableUnicodeEscaping) {
+ if (charArray.length == 0) return this;
+ if (hasAnyJSONControlChars(charArray, disableUnicodeEscaping)) {
+ return doAddJsonEscapedString(charArray, disableUnicodeEscaping);
+ } else {
+ return this.addQuoted(charArray);
+ }
+ }
+
+ final byte[] encoded = new byte[2];
+
+ final byte[] charTo = new byte[2];
+
+ private CharBuf doAddJsonEscapedString(char[] charArray, boolean disableUnicodeEscaping) {
+ char[] _buffer = buffer;
+ int _location = this.location;
+
+ final byte[] _encoded = encoded;
+
+ final byte[] _charTo = charTo;
+ /* We are making a bet that not all chars will be unicode. */
+ int ensureThisMuch = charArray.length * 6 + 2;
+
+ int sizeNeeded = (ensureThisMuch) + _location;
+ if (sizeNeeded > capacity) {
+ int growBy = (_buffer.length * 2) < sizeNeeded ? sizeNeeded : (_buffer.length * 2);
+ _buffer = Chr.grow(buffer, growBy);
+ capacity = _buffer.length;
+ }
+
+ _buffer[_location] = '"';
+ _location++;
+
+ int index = 0;
+ while (true) {
+ char c = charArray[index];
+
+ if (shouldEscape(c, disableUnicodeEscaping)) {
+ /* We are covering our bet with a safety net.
+ otherwise we would have to have 5x buffer
+ allocated for control chars */
+ if (_location + 5 > _buffer.length) {
+ _buffer = Chr.grow(_buffer, 20);
+ }
+
+ switch (c) {
+ case '\"':
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = '"';
+ _location++;
+ break;
+ case '\\':
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = '\\';
+ _location++;
+ break;
+ //There is not requirement to escape solidus so we will not.
+// case '/':
+// _buffer[_location] = '\\';
+// _location ++;
+// _buffer[_location] = '/';
+// _location ++;
+// break;
+
+ case '\b':
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = 'b';
+ _location++;
+ break;
+ case '\f':
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = 'f';
+ _location++;
+ break;
+ case '\n':
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = 'n';
+ _location++;
+ break;
+ case '\r':
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = 'r';
+ _location++;
+ break;
+ case '\t':
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = 't';
+ _location++;
+ break;
+ default:
+ _buffer[_location] = '\\';
+ _location++;
+ _buffer[_location] = 'u';
+ _location++;
+ if (c <= 255) {
+ _buffer[_location] = '0';
+ _location++;
+ _buffer[_location] = '0';
+ _location++;
+ ByteScanner.encodeByteIntoTwoAsciiCharBytes(c, _encoded);
+ for (int b : _encoded) {
+ _buffer[_location] = (char) b;
+ _location++;
+ }
+ } else {
+ _charTo[1] = (byte) (c);
+ _charTo[0] = (byte) (c >>> 8);
+
+ for (int charByte : _charTo) {
+ ByteScanner.encodeByteIntoTwoAsciiCharBytes(charByte, _encoded);
+ for (int b : _encoded) {
+ _buffer[_location] = (char) b;
+ _location++;
+ }
+ }
+ }
+ }
+ } else {
+ _buffer[_location] = c;
+ _location++;
+ }
+
+ if (++index >= charArray.length) break;
+ }
+ _buffer[_location] = '"';
+ _location++;
+
+ buffer = _buffer;
+ location = _location;
+
+ return this;
+ }
+
+ public final CharBuf addJsonFieldName(String str) {
+ return addJsonFieldName(str, false);
+ }
+
+ public final CharBuf addJsonFieldName(String str, boolean disableUnicodeEscaping) {
+ return addJsonFieldName(FastStringUtils.toCharArray(str), disableUnicodeEscaping);
+ }
+
+ private static final char[] EMPTY_STRING_CHARS = Chr.array('"', '"');
+
+ public final CharBuf addJsonFieldName(char[] chars) {
+ return addJsonFieldName(chars, false);
+ }
+
+ public final CharBuf addJsonFieldName(char[] chars, boolean disableUnicodeEscaping) {
+ if (chars.length > 0) {
+ addJsonEscapedString(chars, disableUnicodeEscaping);
+ } else {
+ addChars(EMPTY_STRING_CHARS);
+ }
+ addChar(':');
+ return this;
+ }
+
+ public final CharBuf addQuoted(String str) {
+ final char[] chars = FastStringUtils.toCharArray(str);
+ addQuoted(chars);
+ return this;
+ }
+
+ public CharBuf add(char[] chars, final int length) {
+ if (length + location < capacity) {
+ Chr._idx(buffer, location, chars, length);
+ } else {
+ buffer = Chr.grow(buffer, buffer.length * 2 + length);
+ Chr._idx(buffer, location, chars);
+ capacity = buffer.length;
+ }
+ location += length;
+ return this;
+ }
+
+ public CharBuf add(byte[] chars) {
+ if (chars.length + location < capacity) {
+ Chr._idx(buffer, location, chars);
+ } else {
+ buffer = Chr.grow(buffer, buffer.length * 2 + chars.length);
+ Chr._idx(buffer, location, chars);
+ capacity = buffer.length;
+ }
+ location += chars.length;
+ return this;
+ }
+
+ public CharBuf add(byte[] bytes, int start, int end) {
+ int charsLength = end - start;
+ if (charsLength + location > capacity) {
+ buffer = Chr.grow(buffer, buffer.length * 2 + charsLength);
+ }
+ Chr._idx(buffer, location, bytes, start, end);
+ capacity = buffer.length;
+ location += charsLength;
+ return this;
+ }
+
+ public final CharBuf add(char ch) {
+ if (1 + location < capacity) {
+ buffer[location] = ch;
+ } else {
+ buffer = Chr.grow(buffer);
+ buffer[location] = ch;
+ capacity = buffer.length;
+ }
+ location += 1;
+ return this;
+ }
+
+ public int length() {
+ return len();
+ }
+
+ public char charAt(int index) {
+ return buffer[index];
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ return new String(buffer, start, end - start);
+ }
+
+ public String toString() {
+ return new String(buffer, 0, location);
+ }
+
+ public String toDebugString() {
+ return "CharBuf{" +
+ "capacity=" + capacity +
+ ", location=" + location +
+ '}';
+ }
+
+ public String toStringAndRecycle() {
+ String str = new String(buffer, 0, location);
+ location = 0;
+ return str;
+ }
+
+ public int len() {
+ return location;
+ }
+
+ public char[] toCharArray() {
+ return this.buffer;
+ }
+
+ public void _len(int location) {
+ this.location = location;
+ }
+
+ public char[] readForRecycle() {
+ this.location = 0;
+ return this.buffer;
+ }
+
+ public void recycle() {
+ this.location = 0;
+ }
+
+ public double doubleValue() {
+ return CharScanner.parseDouble(this.buffer, 0, location);
+ }
+
+ public float floatValue() {
+ return CharScanner.parseFloat(this.buffer, 0, location);
+ }
+
+ public int intValue() {
+ return CharScanner.parseIntFromTo(buffer, 0, location);
+ }
+
+ public long longValue() {
+ return CharScanner.parseLongFromTo(buffer, 0, location);
+ }
+
+ public byte byteValue() {
+ return (byte) intValue();
+ }
+
+ public short shortValue() {
+ return (short) intValue();
+ }
+
+ public Number toIntegerWrapper() {
+ if (CharScanner.isInteger(buffer, 0, location)) {
+ return intValue();
+ } else {
+ return longValue();
+ }
+ }
+
+ static final char[] nullChars = "null".toCharArray();
+
+ public final void addNull() {
+ this.add(nullChars);
+ }
+
+ public void removeLastChar() {
+ if (location > 0) {
+ location--;
+ }
+ }
+
+ public void removeLastChar(char expect) {
+ if (location == 0 || buffer[location-1] != expect) {
+ return;
+ }
+ removeLastChar();
+ }
+
+ private Cache<BigDecimal, char[]> bigDCache;
+
+ public CharBuf addBigDecimal(BigDecimal key) {
+ if (bigDCache == null) {
+ bigDCache = new SimpleCache<BigDecimal, char[]>(20);
+ }
+ char[] chars = bigDCache.get(key);
+
+ if (chars == null) {
+ String str = key.toString();
+ chars = FastStringUtils.toCharArray(str);
+ bigDCache.put(key, chars);
+ }
+
+ add(chars);
+
+ return this;
+ }
+
+ private Cache<BigInteger, char[]> bigICache;
+
+ public CharBuf addBigInteger(BigInteger key) {
+ if (bigICache == null) {
+ bigICache = new SimpleCache<BigInteger, char[]>(20);
+ }
+ char[] chars = bigICache.get(key);
+
+ if (chars == null) {
+ String str = key.toString();
+ chars = FastStringUtils.toCharArray(str);
+ bigICache.put(key, chars);
+ }
+
+ add(chars);
+
+ return this;
+ }
+
+ private Cache<Long, char[]> lcache;
+
+ public final CharBuf addLong(long l) {
+ addLong(Long.valueOf(l));
+ return this;
+ }
+
+ public final CharBuf addLong(Long key) {
+ if (lcache == null) {
+ lcache = new SimpleCache<Long, char[]>(20);
+ }
+ char[] chars = lcache.get(key);
+
+ if (chars == null) {
+ String str = Long.toString(key);
+ chars = FastStringUtils.toCharArray(str);
+ lcache.put(key, chars);
+ }
+
+ add(chars);
+
+ return this;
+ }
+
+ public final CharBuf decodeJsonString(char[] chars) {
+ return decodeJsonString(chars, 0, chars.length);
+ }
+
+ public final CharBuf decodeJsonString(char[] chars, int start, int to) {
+ int len = to - start;
+
+ char[] buffer = this.buffer;
+ int location = this.location;
+
+ if (len > capacity) {
+ buffer = Chr.grow(buffer, buffer.length * 2 + len);
+ capacity = buffer.length;
+ }
+
+ for (int index = start; index < to; index++) {
+ char c = chars[index];
+ if (c == '\\') {
+ if (index < to) {
+ index++;
+ c = chars[index];
+ switch (c) {
+
+ case 'n':
+ buffer[location++] = '\n';
+ break;
+
+ case '/':
+ buffer[location++] = '/';
+ break;
+
+ case '"':
+ buffer[location++] = '"';
+ break;
+
+ case 'f':
+ buffer[location++] = '\f';
+ break;
+
+ case 't':
+ buffer[location++] = '\t';
+ break;
+
+ case '\\':
+ buffer[location++] = '\\';
+ break;
+
+ case 'b':
+ buffer[location++] = '\b';
+ break;
+
+ case 'r':
+ buffer[location++] = '\r';
+ break;
+
+ case 'u':
+ if (index + 4 < to) {
+ String hex = new String(chars, index + 1, 4);
+ char unicode = (char) Integer.parseInt(hex, 16);
+ buffer[location++] = unicode;
+ index += 4;
+ }
+ break;
+
+ default:
+ throw new JsonException("Unable to decode string");
+ }
+ }
+ } else {
+ buffer[location++] = c;
+ }
+ }
+
+ this.buffer = buffer;
+ this.location = location;
+
+ return this;
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java
new file mode 100644
index 0000000..2dfacf9
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharScanner.java
@@ -0,0 +1,512 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+import static org.apache.groovy.json.internal.Exceptions.handle;
+
+/**
+ * @author Richard Hightower
+ */
+public class CharScanner {
+
+ protected static final int COMMA = ',';
+ protected static final int CLOSED_CURLY = '}';
+ protected static final int CLOSED_BRACKET = ']';
+ protected static final int LETTER_E = 'e';
+ protected static final int LETTER_BIG_E = 'E';
+ protected static final int DECIMAL_POINT = '.';
+ protected static final int ALPHA_0 = '0';
+ protected static final int ALPHA_9 = '9';
+ protected static final int MINUS = '-';
+ protected static final int PLUS = '+';
+
+ static final String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE);
+ static final String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE);
+ static final String MIN_INT_STR_NO_SIGN = String.valueOf(Integer.MIN_VALUE);
+ static final String MAX_INT_STR = String.valueOf(Integer.MAX_VALUE);
+
+ private static double powersOf10[] = {
+ 1.0,
+ 10.0,
+ 100.0,
+ 1000.0,
+ 10000.0,
+ 100000.0,
+ 1000000.0,
+ 10000000.0,
+ 100000000.0,
+ 1000000000.0,
+ 10000000000.0,
+ 100000000000.0,
+ 1000000000000.0,
+ 10000000000000.0,
+ 100000000000000.0,
+ 1000000000000000.0,
+ 10000000000000000.0,
+ 100000000000000000.0,
+ 1000000000000000000.0,
+ };
+
+ public static boolean isDigit(int c) {
+ return c >= ALPHA_0 && c <= ALPHA_9;
+ }
+
+ public static boolean isDecimalDigit(int c) {
+ return isDigit(c) || isDecimalChar(c);
+ }
+
+ public static boolean isDecimalChar(int currentChar) {
+ switch (currentChar) {
+ case MINUS:
+ case PLUS:
+ case LETTER_E:
+ case LETTER_BIG_E:
+ case DECIMAL_POINT:
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean hasDecimalChar(char[] chars, boolean negative) {
+ int index = 0;
+
+ if (negative) index++;
+
+ for (; index < chars.length; index++) {
+ switch (chars[index]) {
+ case MINUS:
+ case PLUS:
+ case LETTER_E:
+ case LETTER_BIG_E:
+ case DECIMAL_POINT:
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isLong(char[] digitChars) {
+ return isLong(digitChars, 0, digitChars.length);
+ }
+
+ public static boolean isLong(char[] digitChars, int offset, int len) {
+ String cmpStr = digitChars[offset] == '-' ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
+ int cmpLen = cmpStr.length();
+ if (len < cmpLen) return true;
+ if (len > cmpLen) return false;
+
+ for (int i = 0; i < cmpLen; ++i) {
+ int diff = digitChars[offset + i] - cmpStr.charAt(i);
+ if (diff != 0) {
+ return (diff < 0);
+ }
+ }
+ return true;
+ }
+
+ public static boolean isInteger(char[] digitChars) {
+ return isInteger(digitChars, 0, digitChars.length);
+ }
+
+ public static boolean isInteger(char[] digitChars, int offset, int len) {
+ String cmpStr = (digitChars[offset] == '-') ? MIN_INT_STR_NO_SIGN : MAX_INT_STR;
+ int cmpLen = cmpStr.length();
+ if (len < cmpLen) return true;
+ if (len > cmpLen) return false;
+
+ for (int i = 0; i < cmpLen; ++i) {
+ int diff = digitChars[offset + i] - cmpStr.charAt(i);
+ if (diff != 0) {
+ return (diff < 0);
+ }
+ }
+ return true;
+ }
+
+ public static int parseInt(char[] digitChars) {
+ return parseIntFromTo(digitChars, 0, digitChars.length);
+ }
+
+ public static int parseIntFromTo(char[] digitChars, int offset, int to) {
+ try {
+ int num;
+ boolean negative = false;
+ char c = digitChars[offset];
+ if (c == '-') {
+ offset++;
+ negative = true;
+ }
+ if (offset >= to) {
+ die();
+ }
+ num = (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ if (++offset < to) {
+ num = (num * 10) + (digitChars[offset] - '0');
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return negative ? num * -1 : num;
+ } catch (Exception ex) {
+ return handle(int.class, ex);
+ }
+ }
+
+ public static int parseIntFromToIgnoreDot(char[] digitChars, int offset, int to) {
+ int num;
+ boolean negative = false;
+ char c = digitChars[offset];
+ if (c == '-') {
+ offset++;
+ negative = true;
+ }
+ if (offset >= to) {
+ die();
+ }
+ c = digitChars[offset];
+ num = (c - '0');
+ offset++;
+
+ for (; offset < to; offset++) {
+ c = digitChars[offset];
+ if (c != '.') {
+ num = (num * 10) + (c - '0');
+ }
+ }
+
+ return negative ? num * -1 : num;
+ }
+
+ public static long parseLongFromToIgnoreDot(char[] digitChars, int offset, int to) {
+ long num;
+ boolean negative = false;
+ char c = digitChars[offset];
+ if (c == '-') {
+ offset++;
+ negative = true;
+ }
+ if (offset >= to) {
+ die();
+ }
+ c = digitChars[offset];
+ num = (c - '0');
+ offset++;
+
+ for (; offset < to; offset++) {
+ c = digitChars[offset];
+ if (c != '.') {
+ num = (num * 10) + (c - '0');
+ }
+ }
+
+ return negative ? num * -1 : num;
+ }
+
+ public static long parseLongFromTo(char[] digitChars, int offset, int to) {
+ long num;
+ boolean negative = false;
+ char c = digitChars[offset];
+ if (c == '-') {
+ offset++;
+ negative = true;
+ }
+ if (offset >= to) {
+ die();
+ }
+ c = digitChars[offset];
+ num = (c - '0');
+ offset++;
+
+ long digit;
+
+ for (; offset < to; offset++) {
+ c = digitChars[offset];
+ digit = (c - '0');
+ num = (num * 10) + digit;
+ }
+
+ return negative ? num * -1 : num;
+ }
+
+ public static long parseLong(char[] digitChars) {
+ return parseLongFromTo(digitChars, 0, digitChars.length);
+ }
+
+ public static Number parseJsonNumber(char[] buffer) {
+ return parseJsonNumber(buffer, 0, buffer.length);
+ }
+
+ public static Number parseJsonNumber(char[] buffer, int from, int to) {
+ return parseJsonNumber(buffer, from, to, null);
+ }
+
+ public static boolean isNumberDigit(int c) {
+ return c >= ALPHA_0 && c <= ALPHA_9;
+ }
+
+ protected static boolean isDelimiter(int c) {
+ return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
+ }
+
+ public static Number parseJsonNumber(char[] buffer, int from, int max, int size[]) {
+ Number value = null;
+ boolean simple = true;
+ int digitsPastPoint = 0;
+
+ int index = from;
+
+ if (buffer[index] == '-') {
+ index++;
+ }
+ if (index >= max) {
+ die();
+ }
+
+ boolean foundDot = false;
+ for (; index < max; index++) {
+ char ch = buffer[index];
+ if (isNumberDigit(ch)) {
+ if (foundDot) {
+ digitsPastPoint++;
+ }
+ } else if (ch <= 32 || isDelimiter(ch)) {
+ break;
+ } else if (ch == '.') {
+ if (foundDot) {
+ die("unexpected character " + ch);
+ }
+ foundDot = true;
+ } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
+ simple = false;
+ } else {
+ die("unexpected character " + ch);
+ }
+ }
+
+ if (digitsPastPoint >= powersOf10.length - 1) {
+ simple = false;
+ }
+
+ final int length = index - from;
+
+ if (!foundDot && simple) {
+ if (isInteger(buffer, from, length)) {
+ value = parseIntFromTo(buffer, from, index);
+ } else {
+ value = parseLongFromTo(buffer, from, index);
+ }
+ } else {
+ value = new BigDecimal(buffer, from, length);
+ }
+
+ if (size != null) {
+ size[0] = index;
+ }
+
+ return value;
+ }
+
+ public static BigDecimal parseBigDecimal(char[] buffer) {
+ return new BigDecimal(buffer);
+ }
+
+ public static float parseFloat(char[] buffer, int from, int to) {
+ return (float) parseDouble(buffer, from, to);
+ }
+
+ public static double parseDouble(char[] buffer, int from, int to) {
+ double value;
+ boolean simple = true;
+ int digitsPastPoint = 0;
+
+ int index = from;
+
+ if (buffer[index] == '-') {
+ index++;
+ }
+
+ boolean foundDot = false;
+ for (; index < to; index++) {
+ char ch = buffer[index];
+ if (isNumberDigit(ch)) {
+ if (foundDot) {
+ digitsPastPoint++;
+ }
+ } else if (ch == '.') {
+ if (foundDot) {
+ die("unexpected character " + ch);
+ }
+ foundDot = true;
+ } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
+ simple = false;
+ } else {
+ die("unexpected character " + ch);
+ }
+ }
+
+ if (digitsPastPoint >= powersOf10.length - 1) {
+ simple = false;
+ }
+
+ final int length = index - from;
+
+ if (!foundDot && simple) {
+ if (isInteger(buffer, from, length)) {
+ value = parseIntFromTo(buffer, from, index);
+ } else {
+ value = parseLongFromTo(buffer, from, index);
+ }
+ } else if (foundDot && simple) {
+ long lvalue;
+
+ if (length < powersOf10.length) {
+ if (isInteger(buffer, from, length)) {
+ lvalue = parseIntFromToIgnoreDot(buffer, from, index);
+ } else {
+ lvalue = parseLongFromToIgnoreDot(buffer, from, index);
+ }
+
+ double power = powersOf10[digitsPastPoint];
+ value = lvalue / power;
+ } else {
+ value = Double.parseDouble(new String(buffer, from, length));
+ }
+ } else {
+ value = Double.parseDouble(new String(buffer, from, index - from));
+ }
+
+ return value;
+ }
+
+ public static int skipWhiteSpace(char[] array, int index, final int length) {
+ int c;
+ for (; index < length; index++) {
+ c = array[index];
+ if (c > 32) {
+ return index;
+ }
+ }
+ return index;
+ }
+
+ public static char[] readNumber(char[] array, int idx, final int len) {
+ final int startIndex = idx;
+
+ while (true) {
+ if (!CharScanner.isDecimalDigit(array[idx])) {
+ break;
+ } else {
+ idx++;
+ if (idx >= len) break;
+ }
+ }
+
+ return ArrayUtils.copyRange(array, startIndex, idx);
+ }
+
+ public static String errorDetails(String message, char[] array, int index, int ch) {
+ CharBuf buf = CharBuf.create(255);
+
+ buf.addLine(message);
+
+ buf.addLine("");
+ buf.addLine("The current character read is " + debugCharDescription(ch));
+
+ buf.addLine(message);
+
+ int line = 0;
+ int lastLineIndex = 0;
+
+ for (int i = 0; i < index && i < array.length; i++) {
+ if (array[i] == '\n') {
+ line++;
+ lastLineIndex = i + 1;
+ }
+ }
+
+ int count = 0;
+
+ for (int i = lastLineIndex; i < array.length; i++, count++) {
+ if (array[i] == '\n') {
+ break;
+ }
+ }
+
+ buf.addLine("line number " + (line + 1));
+ buf.addLine("index number " + index);
+
+ try {
+ buf.addLine(new String(array, lastLineIndex, count));
+ } catch (Exception ex) {
+ try {
+ int start = index = (index - 10 < 0) ? 0 : index - 10;
+
+ buf.addLine(new String(array, start, index));
+ } catch (Exception ex2) {
+ buf.addLine(new String(array, 0, array.length));
+ }
+ }
+ for (int i = 0; i < (index - lastLineIndex); i++) {
+ buf.add('.');
+ }
+ buf.add('^');
+
+ return buf.toString();
+ }
+
+ public static String debugCharDescription(int c) {
+ String charString;
+ if (c == ' ') {
+ charString = "[SPACE]";
+ } else if (c == '\t') {
+ charString = "[TAB]";
+ } else if (c == '\n') {
+ charString = "[NEWLINE]";
+ } else {
+ charString = "'" + (char) c + "'";
+ }
+
+ charString = charString + " with an int value of " + ((int) c);
+ return charString;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java
new file mode 100644
index 0000000..40ebc16
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharSequenceValue.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Date;
+
+import static org.apache.groovy.json.internal.CharScanner.isInteger;
+import static org.apache.groovy.json.internal.CharScanner.parseIntFromTo;
+import static org.apache.groovy.json.internal.CharScanner.parseLongFromTo;
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * @author Rick Hightower
+ */
+public class CharSequenceValue implements Value, CharSequence {
+
+ private final Type type;
+ private final boolean checkDate;
+ private final boolean decodeStrings;
+
+ private char[] buffer;
+ private boolean chopped;
+ private int startIndex;
+ private int endIndex;
+ private Object value;
+
+ public CharSequenceValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer,
+ boolean encoded, boolean checkDate) {
+ this.type = type;
+ this.checkDate = checkDate;
+ this.decodeStrings = encoded;
+
+ if (chop) {
+ try {
+ this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+ } catch (Exception ex) {
+ Exceptions.handle(ex);
+ }
+ this.startIndex = 0;
+ this.endIndex = this.buffer.length;
+ this.chopped = true;
+ } else {
+ this.startIndex = startIndex;
+ this.endIndex = endIndex;
+ this.buffer = buffer;
+ }
+ }
+
+ public String toString() {
+ if (startIndex == 0 && endIndex == buffer.length) {
+ return FastStringUtils.noCopyStringFromChars(buffer);
+ } else {
+ return new String(buffer, startIndex, (endIndex - startIndex));
+ }
+ }
+
+ public final Object toValue() {
+ return value != null ? value : (value = doToValue());
+ }
+
+ public <T extends Enum> T toEnum(Class<T> cls) {
+ switch (type) {
+ case STRING:
+ return toEnum(cls, stringValue());
+ case INTEGER:
+ return toEnum(cls, intValue());
+ case NULL:
+ return null;
+ }
+ die("toEnum " + cls + " value was " + stringValue());
+ return null;
+ }
+
+ public static <T extends Enum> T toEnum(Class<T> cls, String value) {
+ try {
+ return (T) Enum.valueOf(cls, value);
+ } catch (Exception ex) {
+ return (T) Enum.valueOf(cls, value.toUpperCase().replace('-', '_'));
+ }
+ }
+
+ public static <T extends Enum> T toEnum(Class<T> cls, int value) {
+ T[] enumConstants = cls.getEnumConstants();
+ for (T e : enumConstants) {
+ if (e.ordinal() == value) {
+ return e;
+ }
+ }
+ die("Can't convert ordinal value " + value + " into enum of type " + cls);
+ return null;
+ }
+
+ public boolean isContainer() {
+ return false;
+ }
+
+ private Object doToValue() {
+ switch (type) {
+ case DOUBLE:
+ return doubleValue();
+ case INTEGER:
+ if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+ return intValue();
+ } else {
+ return longValue();
+ }
+ case STRING:
+ if (checkDate) {
+ Date date = null;
+ if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
+ if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
+ date = Dates.fromJsonDate(buffer, startIndex, endIndex);
+ } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
+ date = Dates.fromISO8601(buffer, startIndex, endIndex);
+ } else {
+ return stringValue();
+ }
+
+ if (date == null) {
+ return stringValue();
+ } else {
+ return date;
+ }
+ }
+ }
+ return stringValue();
+ }
+ die();
+ return null;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Value)) return false;
+
+ CharSequenceValue value1 = (CharSequenceValue) o;
+
+ if (endIndex != value1.endIndex) return false;
+ if (startIndex != value1.startIndex) return false;
+ if (!Arrays.equals(buffer, value1.buffer)) return false;
+ if (type != value1.type) return false;
+ return value != null ? value.equals(value1.value) : value1.value == null;
+
+ }
+
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
+ result = 31 * result + startIndex;
+ result = 31 * result + endIndex;
+ result = 31 * result + (value != null ? value.hashCode() : 0);
+ return result;
+ }
+
+ public final int length() {
+ return buffer.length;
+ }
+
+ public final char charAt(int index) {
+ return buffer[index];
+ }
+
+ public final CharSequence subSequence(int start, int end) {
+ return new CharSequenceValue(false, type, start, end, buffer, decodeStrings, checkDate);
+ }
+
+ public BigDecimal bigDecimalValue() {
+ return new BigDecimal(buffer, startIndex, endIndex - startIndex);
+ }
+
+ public BigInteger bigIntegerValue() {
+ return new BigInteger(toString());
+ }
+
+ public String stringValue() {
+ if (this.decodeStrings) {
+ return JsonStringDecoder.decodeForSure(buffer, startIndex, endIndex);
+ } else {
+ return toString();
+ }
+ }
+
+ public String stringValueEncoded() {
+ return JsonStringDecoder.decode(buffer, startIndex, endIndex);
+ }
+
+ public Date dateValue() {
+ if (type == Type.STRING) {
+
+ if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
+
+ if (Dates.isJsonDate(buffer, startIndex, endIndex)) {
+ return Dates.fromJsonDate(buffer, startIndex, endIndex);
+
+ } else if (Dates.isISO8601(buffer, startIndex, endIndex)) {
+ return Dates.fromISO8601(buffer, startIndex, endIndex);
+ } else {
+ throw new JsonException("Unable to convert " + stringValue() + " to date ");
+ }
+ } else {
+ throw new JsonException("Unable to convert " + stringValue() + " to date ");
+ }
+ } else {
+ return new Date(Dates.utc(longValue()));
+ }
+ }
+
+ public int intValue() {
+ int sign = 1;
+ if (buffer[startIndex] == '-') {
+ startIndex++;
+ sign = -1;
+ }
+ return parseIntFromTo(buffer, startIndex, endIndex) * sign;
+ }
+
+ public long longValue() {
+ if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+ return parseIntFromTo(buffer, startIndex, endIndex);
+ } else {
+ return parseLongFromTo(buffer, startIndex, endIndex);
+ }
+ }
+
+ public byte byteValue() {
+ return (byte) intValue();
+ }
+
+ public short shortValue() {
+ return (short) intValue();
+ }
+
+ public double doubleValue() {
+ return CharScanner.parseDouble(this.buffer, startIndex, endIndex);
+ }
+
+ public boolean booleanValue() {
+ return Boolean.parseBoolean(toString());
+ }
+
+ public float floatValue() {
+ return CharScanner.parseFloat(this.buffer, startIndex, endIndex);
+ }
+
+ public final void chop() {
+ if (!chopped) {
+ this.chopped = true;
+ this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+ this.startIndex = 0;
+ this.endIndex = this.buffer.length;
+ }
+ }
+
+ public char charValue() {
+ return buffer[startIndex];
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java
new file mode 100644
index 0000000..6fdecd4
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/CharacterSource.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public interface CharacterSource {
+
+ /**
+ * Skip white space.
+ */
+ void skipWhiteSpace();
+
+ /**
+ * returns the next character moving the file pointer or index to the next location.
+ */
+ int nextChar();
+
+ /**
+ * returns the current character without changing the IO pointer or index.
+ */
+ int currentChar();
+
+ /**
+ * Checks to see if there is a next character.
+ */
+ boolean hasChar();
+
+ /**
+ * Useful for finding constants in a string like true, false, etc.
+ */
+ boolean consumeIfMatch(char[] match);
+
+ /**
+ * This is mostly for debugging and testing.
+ */
+ int location();
+
+ /**
+ * Combines the operations of nextChar and hasChar.
+ * Characters is -1 if not found which signifies end of file.
+ * This might be preferable to avoid two method calls.
+ */
+ int safeNextChar();
+
+ /**
+ * Used to find strings and their ilk
+ * Finds the next non-escaped char
+ *
+ * @param ch character to find
+ * @param esc escape character to avoid next char if escaped
+ * @return list of chars until this is found.
+ */
+ char[] findNextChar(int ch, int esc);
+
+ boolean hadEscape();
+
+ /**
+ * Reads a number from the character source.
+ */
+ char[] readNumber();
+
+ String errorDetails(String message);
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java
new file mode 100644
index 0000000..6996a8e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Chr.java
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Rick Hightower
+ */
+public class Chr {
+
+ public static char[] array(final char... array) {
+ return array;
+ }
+
+ public static char[] chars(final String array) {
+ return array.toCharArray();
+ }
+
+ public static boolean in(char value, char[] array) {
+ for (char currentValue : array) {
+ if (currentValue == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean in(int value, char[] array) {
+ for (int currentValue : array) {
+ if (currentValue == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean in(char value, int offset, char[] array) {
+ for (int index = offset; index < array.length; index++) {
+ char currentValue = array[index];
+ if (currentValue == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean in(char value, int offset, int end, char[] array) {
+ for (int index = offset; index < end; index++) {
+ char currentValue = array[index];
+ if (currentValue == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static char[] grow(char[] array, final int size) {
+ char[] newArray = new char[array.length + size];
+ arraycopy(array, 0, newArray, 0, array.length);
+ return newArray;
+ }
+
+ public static char[] grow(char[] array) {
+ char[] newArray = new char[array.length * 2];
+ arraycopy(array, 0, newArray, 0, array.length);
+ return newArray;
+ }
+
+ public static char[] copy(char[] array) {
+ char[] newArray = new char[array.length];
+ arraycopy(array, 0, newArray, 0, array.length);
+ return newArray;
+ }
+
+ public static char[] copy(char[] array, int offset, int length) {
+ char[] newArray = new char[length];
+ arraycopy(array, offset, newArray, 0, length);
+ return newArray;
+ }
+
+ public static char[] add(char[] array, char v) {
+ char[] newArray = new char[array.length + 1];
+ arraycopy(array, 0, newArray, 0, array.length);
+ newArray[array.length] = v;
+ return newArray;
+ }
+
+ public static char[] add(char[] array, String str) {
+ return add(array, str.toCharArray());
+ }
+
+ public static char[] add(char[] array, StringBuilder stringBuilder) {
+ return add(array, getCharsFromStringBuilder(stringBuilder));
+ }
+
+ public static char[] add(char[] array, char[] array2) {
+ char[] newArray = new char[array.length + array2.length];
+ arraycopy(array, 0, newArray, 0, array.length);
+ arraycopy(array2, 0, newArray, array.length, array2.length);
+ return newArray;
+ }
+
+ /* End universal methods. */
+
+ private static char[] getCharsFromStringBuilder(StringBuilder sbuf) {
+ final int length = sbuf.length();
+ char[] array2 = new char[length];
+ sbuf.getChars(0, length, array2, 0);
+ return array2;
+ }
+
+ public static char[] lpad(final char[] in, final int size, char pad) {
+ if (in.length >= size) {
+ return in;
+ }
+
+ int delta = size - in.length;
+ int index = 0;
+ char[] newArray = new char[size];
+
+ for (; index < delta; index++) {
+ newArray[index] = pad;
+ }
+
+ for (int index2 = 0; index2 < in.length; index++, index2++) {
+ newArray[index] = in[index2];
+ }
+
+ return newArray;
+ }
+
+ public static boolean contains(char[] chars, char c, int start, final int length) {
+ final int to = length + start;
+ for (int index = start; index < to; index++) {
+ char ch = chars[index];
+ if (ch == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void _idx(char[] buffer, int location, byte[] chars) {
+ int index2 = 0;
+ int endLocation = (location + chars.length);
+ for (int index = location; index < endLocation; index++, index2++) {
+ buffer[index] = (char) chars[index2];
+ }
+ }
+
+ public static void _idx(final char[] array, int startIndex, char[] input) {
+ try {
+ arraycopy(input, 0, array, startIndex, input.length);
+ } catch (Exception ex) {
+ Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
+ array.length, startIndex, input.length), ex);
+ }
+ }
+
+ private static void arraycopy(final char[] src, final int srcPos, final char[] dest, final int destPos, final int length) {
+ System.arraycopy(src, srcPos, dest, destPos, length);
+ }
+
+ public static void _idx(final char[] array, int startIndex, char[] input, final int inputLength) {
+ try {
+ arraycopy(input, 0, array, startIndex, inputLength);
+ } catch (Exception ex) {
+ Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
+ array.length, startIndex, input.length), ex);
+ }
+ }
+
+ public static void _idx(char[] buffer, int location, byte[] chars, int start, int end) {
+ int index2 = start;
+ int endLocation = (location + (end - start));
+ for (int index = location; index < endLocation; index++, index2++) {
+ buffer[index] = (char) chars[index2];
+ }
+ }
+
+ public static char[] add(char[]... strings) {
+ int length = 0;
+ for (char[] str : strings) {
+ if (str == null) {
+ continue;
+ }
+ length += str.length;
+ }
+ CharBuf builder = CharBuf.createExact(length);
+ for (char[] str : strings) {
+ if (str == null) {
+ continue;
+ }
+ builder.add(str);
+ }
+ return builder.toCharArray();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java
new file mode 100644
index 0000000..0cd95f8
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Dates.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * @author Rick Hightower
+ */
+public class Dates {
+
+ private static TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
+
+ public static long utc(long time) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(time);
+ calendar.setTimeZone(UTC_TIME_ZONE);
+ return calendar.getTime().getTime();
+ }
+
+ private static Date internalDate(TimeZone tz, int year, int month, int day, int hour,
+ int minute, int second, int miliseconds) {
+
+ Calendar calendar = Calendar.getInstance();
+
+ calendar.set(Calendar.YEAR, year);
+ calendar.set(Calendar.MONTH, month - 1);
+ calendar.set(Calendar.DAY_OF_MONTH, day);
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+ calendar.set(Calendar.MILLISECOND, miliseconds);
+
+ calendar.setTimeZone(tz);
+
+ return calendar.getTime();
+ }
+
+ public static Date toDate(TimeZone tz, int year, int month, int day,
+ int hour, int minute, int second) {
+ return internalDate(tz, year, month, day, hour, minute, second, 0);
+ }
+
+ public static Date toDate(TimeZone tz, int year, int month, int day,
+ int hour, int minute, int second, int miliseconds) {
+ return internalDate(tz, year, month, day, hour, minute, second, miliseconds);
+ }
+
+ static final int SHORT_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30Z".length();
+ static final int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length();
+ public static final int JSON_TIME_LENGTH = "2013-12-14T01:55:33.412Z".length();
+
+ public static Date fromISO8601(char[] charArray, int from, int to) {
+ try {
+ if (isISO8601(charArray, from, to)) {
+ int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
+ int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
+ int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
+ int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
+
+ int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
+
+ int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
+ TimeZone tz = null;
+
+ if (charArray[from + 19] == 'Z') {
+ tz = TimeZone.getTimeZone("GMT");
+ } else {
+ String tzStr = "GMT" + String.valueOf(charArray, from + 19, 6);
+ tz = TimeZone.getTimeZone(tzStr);
+ }
+ return toDate(tz, year, month, day, hour, minute, second);
+ } else {
+ return null;
+ }
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
+ public static Date fromJsonDate(char[] charArray, int from, int to) {
+ try {
+ if (isJsonDate(charArray, from, to)) {
+ int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
+ int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
+ int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
+ int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
+
+ int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
+
+ int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
+
+ int miliseconds = CharScanner.parseIntFromTo(charArray, from + 20, from + 23);
+
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+
+ return toDate(tz, year, month, day, hour, minute, second, miliseconds);
+ } else {
+ return null;
+ }
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
+ public static boolean isISO8601(char[] charArray, int start, int to) {
+ boolean valid = true;
+ final int length = to - start;
+
+ if (length == SHORT_ISO_8601_TIME_LENGTH) {
+ valid &= (charArray[start + 19] == 'Z');
+ } else if (length == LONG_ISO_8601_TIME_LENGTH) {
+ valid &= (charArray[start + 19] == '-' || charArray[start + 19] == '+');
+ valid &= (charArray[start + 22] == ':');
+ } else {
+ return false;
+ }
+
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
+ // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0
+
+ valid &= (charArray[start + 4] == '-') &&
+ (charArray[start + 7] == '-') &&
+ (charArray[start + 10] == 'T') &&
+ (charArray[start + 13] == ':') &&
+ (charArray[start + 16] == ':');
+
+ return valid;
+ }
+
+ public static boolean isISO8601QuickCheck(char[] charArray, int start, int to) {
+ final int length = to - start;
+
+ try {
+ return length == JSON_TIME_LENGTH || length == LONG_ISO_8601_TIME_LENGTH
+ || length == SHORT_ISO_8601_TIME_LENGTH || (length >= 17 && (charArray[start + 16] == ':'));
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ }
+ }
+
+ public static boolean isJsonDate(char[] charArray, int start, int to) {
+ boolean valid = true;
+ final int length = to - start;
+
+ if (length != JSON_TIME_LENGTH) {
+ return false;
+ }
+
+ valid &= (charArray[start + 19] == '.' || charArray[start + 19] == '+');
+
+ if (!valid) {
+ return false;
+ }
+
+ valid &= (charArray[start + 4] == '-') &&
+ (charArray[start + 7] == '-') &&
+ (charArray[start + 10] == 'T') &&
+ (charArray[start + 13] == ':') &&
+ (charArray[start + 16] == ':');
+
+ return valid;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
new file mode 100644
index 0000000..e122778
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Collections;
+
+/**
+ * @author Rick Hightower
+ */
+public class Exceptions {
+
+ public static boolean die() {
+ throw new JsonInternalException("died");
+ }
+
+ public static boolean die(String message) {
+ throw new JsonInternalException(message);
+ }
+
+ public static <T> T die(Class<T> clazz, String message) {
+ throw new JsonInternalException(message);
+ }
+
+ public static void handle(java.lang.Exception e) {
+ throw new JsonInternalException(e);
+ }
+
+ public static <T> T handle(Class<T> clazz, java.lang.Exception e) {
+ if (e instanceof JsonInternalException) {
+ throw (JsonInternalException) e;
+ }
+ throw new JsonInternalException(e);
+ }
+
+ public static <T> T handle(Class<T> clazz, String message, Throwable e) {
+ throw new JsonInternalException(message, e);
+ }
+
+ public static void handle(String message, Throwable e) {
+ throw new JsonInternalException(message, e);
+ }
+
+ public static class JsonInternalException extends JsonException {
+
+ public JsonInternalException(String message) {
+ super(message);
+ }
+
+ public JsonInternalException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public JsonInternalException(Throwable cause) {
+ super("Wrapped Exception", cause);
+ }
+
+ public void printStackTrace(PrintStream s) {
+ s.println(this.getMessage());
+ if (getCause() != null) {
+ s.println("This Exception was wrapped, the original exception\n" +
+ "stack trace is:\n");
+ getCause().printStackTrace(s);
+ } else {
+ super.printStackTrace(s);
+ }
+ }
+
+ public String getMessage() {
+ return super.getMessage() + (getCause() == null ? "" :
+ getCauseMessage());
+ }
+
+ private String getCauseMessage() {
+ return "\n CAUSE " + getCause().getClass().getName() + " :: " +
+ getCause().getMessage();
+ }
+
+ public String getLocalizedMessage() {
+ return this.getMessage();
+ }
+
+ public StackTraceElement[] getStackTrace() {
+ if (getCause() != null) {
+ return getCause().getStackTrace();
+ } else {
+ return super.getStackTrace();
+ }
+ }
+
+ public Throwable getCause() {
+ return super.getCause();
+ }
+
+ public void printStackTrace(PrintWriter s) {
+ s.println(this.getMessage());
+
+ if (getCause() != null) {
+ s.println("This Exception was wrapped, the original exception\n" +
+ "stack trace is:\n");
+ getCause().printStackTrace(s);
+ } else {
+ super.printStackTrace(s);
+ }
+ }
+
+ public void printStackTrace() {
+ System.err.println(this.getMessage());
+
+ if (getCause() != null) {
+ System.err.println("This Exception was wrapped, the original exception\n" +
+ "stack trace is:\n");
+ getCause().printStackTrace();
+ } else {
+ super.printStackTrace();
+ }
+ }
+ }
+
+ public static String toString(Exception ex) {
+ CharBuf buffer = CharBuf.create(255);
+ buffer.addLine(ex.getLocalizedMessage());
+
+ final StackTraceElement[] stackTrace = ex.getStackTrace();
+ for (StackTraceElement element : stackTrace) {
+ buffer.add(element.getClassName());
+ sputs(buffer, "class", element.getClassName(),
+ "method", element.getMethodName(), "line", element.getLineNumber());
+ }
+
+ return buffer.toString();
+ }
+
+ public static String sputs(CharBuf buf, Object... messages) {
+ int index = 0;
+ for (Object message : messages) {
+ if (index != 0) {
+ buf.add(' ');
+ }
+ index++;
+
+ if (message == null) {
+ buf.add("<NULL>");
+ } else if (message.getClass().isArray()) {
+ buf.add(Collections.singletonList(message).toString());
+ } else {
+ buf.add(message.toString());
+ }
+ }
+ buf.add('\n');
+
+ return buf.toString();
+ }
+
+ public static String sputs(Object... messages) {
+ CharBuf buf = CharBuf.create(100);
+ return sputs(buf, messages);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java
new file mode 100644
index 0000000..a8c5dc6
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/FastStringUtils.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import org.apache.groovy.json.DefaultFastStringService;
+import org.apache.groovy.json.FastStringService;
+import org.apache.groovy.json.FastStringServiceFactory;
+
+import java.util.ServiceLoader;
+
+/**
+ * Internal class for fast processing of Strings during JSON parsing
+ */
+public class FastStringUtils {
+
+ private static class ServiceHolder {
+ static final FastStringService INSTANCE = loadService();
+
+ private static FastStringService loadService() {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+// left classloading very simple in light of potential changes needed for jdk9
+// that means you might need @GrabConfig(systemClassLoader=true) if getting json via grab
+// ClassLoader rootLoader = DefaultGroovyMethods.getRootLoader(loader);
+ ServiceLoader<FastStringServiceFactory> serviceLoader = ServiceLoader.load(FastStringServiceFactory.class, loader);
+ FastStringService found = null;
+ for (FastStringServiceFactory factory : serviceLoader) {
+ FastStringService service = factory.getService();
+ if (service != null) {
+ found = service;
+ if (!(service instanceof DefaultFastStringService)) {
+ break;
+ }
+ }
+ }
+ return found;
+ }
+ }
+
+ private static FastStringService getService() {
+ if (ServiceHolder.INSTANCE == null) {
+ throw new RuntimeException("Unable to load FastStringService");
+ }
+ return ServiceHolder.INSTANCE;
+ }
+
+ /**
+ * @param string string to grab array from.
+ * @return char array from string
+ */
+ public static char[] toCharArray(final String string) {
+ return getService().toCharArray(string);
+ }
+
+ /**
+ * @param charSequence to grab array from.
+ * @return char array from char sequence
+ */
+ public static char[] toCharArray(final CharSequence charSequence) {
+ return toCharArray(charSequence.toString());
+ }
+
+ /**
+ * @param chars to shove array into.
+ * @return new string with chars copied into it
+ */
+ public static String noCopyStringFromChars(final char[] chars) {
+ return getService().noCopyStringFromChars(chars);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java
new file mode 100644
index 0000000..fdfec3e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/IO.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * @author Rick Hightower
+ */
+public class IO {
+
+ private static final int EOF = -1;
+
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+ public static CharBuf read(Reader input, CharBuf charBuf, final int bufSize) {
+ if (charBuf == null) {
+ charBuf = CharBuf.create(bufSize);
+ } else {
+ charBuf.readForRecycle();
+ }
+
+ try {
+ char[] buffer = charBuf.toCharArray();
+ int size = input.read(buffer);
+ if (size != -1) {
+ charBuf._len(size);
+ }
+ if (size < 0) {
+ return charBuf;
+ }
+
+ copy(input, charBuf);
+ } catch (IOException e) {
+ Exceptions.handle(e);
+ } finally {
+ try {
+ input.close();
+ } catch (IOException e) {
+ Exceptions.handle(e);
+ }
+ }
+
+ return charBuf;
+ }
+
+ public static int copy(Reader input, Writer output) {
+ long count = copyLarge(input, output);
+ if (count > Integer.MAX_VALUE) {
+ return -1;
+ }
+ return (int) count;
+ }
+
+ public static long copyLarge(Reader reader, Writer writer) {
+ return copyLarge(reader, writer, new char[DEFAULT_BUFFER_SIZE]);
+ }
+
+ public static long copyLarge(Reader reader, Writer writer, char[] buffer) {
+ long count = 0;
+ int n;
+
+ try {
+ while (EOF != (n = reader.read(buffer))) {
+ writer.write(buffer, 0, n);
+ count += n;
+ }
+ } catch (IOException e) {
+ Exceptions.handle(e);
+ }
+ return count;
+ }
+}
[2/7] groovy git commit: GROOVY-8379: Rework groovy-json
FastStringUtils (closes #667)
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java
new file mode 100644
index 0000000..4517f7f
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ReaderCharacterSource.java
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+/**
+ * @author Richard Hightower
+ */
+public class ReaderCharacterSource implements CharacterSource {
+
+ private static final int MAX_TOKEN_SIZE = 5;
+
+ private final Reader reader;
+ private final int readAheadSize;
+ private int ch = -2;
+
+ private boolean foundEscape;
+
+ private final char[] readBuf;
+
+ private int index;
+
+ private int length;
+
+ boolean more = true;
+ private boolean done = false;
+
+ public ReaderCharacterSource(final Reader reader, final int readAheadSize) {
+ this.reader = reader;
+ this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
+ this.readAheadSize = readAheadSize;
+ }
+
+ public ReaderCharacterSource(final Reader reader) {
+ this.reader = reader;
+ this.readAheadSize = 10000;
+ this.readBuf = new char[readAheadSize + MAX_TOKEN_SIZE];
+ }
+
+ public ReaderCharacterSource(final String string) {
+ this(new StringReader(string));
+ }
+
+ private void readForToken() {
+ try {
+ length += reader.read(readBuf, readBuf.length - MAX_TOKEN_SIZE, MAX_TOKEN_SIZE);
+ } catch (IOException e) {
+ Exceptions.handle(e);
+ }
+ }
+
+ private void ensureBuffer() {
+ try {
+ if (index >= length && !done) {
+ readNextBuffer();
+ } else {
+ more = !(done && index >= length);
+ }
+ } catch (Exception ex) {
+ String str = CharScanner.errorDetails("ensureBuffer issue", readBuf, index, ch);
+ Exceptions.handle(str, ex);
+ }
+ }
+
+ private void readNextBuffer() throws IOException {
+ length = reader.read(readBuf, 0, readAheadSize);
+
+ index = 0;
+ if (length == -1) {
+ ch = -1;
+ length = 0;
+ more = false;
+ done = true;
+ } else {
+ more = true;
+ }
+ }
+
+ public final int nextChar() {
+ ensureBuffer();
+ return ch = readBuf[index++];
+ }
+
+ public final int currentChar() {
+ ensureBuffer();
+ return readBuf[index];
+ }
+
+ public final boolean hasChar() {
+ ensureBuffer();
+ return more;
+ }
+
+ public final boolean consumeIfMatch(char[] match) {
+ try {
+ char[] _chars = readBuf;
+ int i = 0;
+ int idx = index;
+ boolean ok = true;
+
+ if (idx + match.length > length) {
+ readForToken();
+ }
+
+ for (; i < match.length; i++, idx++) {
+ ok &= (match[i] == _chars[idx]);
+ if (!ok) break;
+ }
+
+ if (ok) {
+ index = idx;
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception ex) {
+ String str = CharScanner.errorDetails("consumeIfMatch issue", readBuf, index, ch);
+ return Exceptions.handle(boolean.class, str, ex);
+ }
+ }
+
+ public final int location() {
+ return index;
+ }
+
+ public final int safeNextChar() {
+ try {
+ ensureBuffer();
+ return index + 1 < readBuf.length ? readBuf[index++] : -1;
+ } catch (Exception ex) {
+ String str = CharScanner.errorDetails("safeNextChar issue", readBuf, index, ch);
+ return Exceptions.handle(int.class, str, ex);
+ }
+ }
+
+ private static final char[] EMPTY_CHARS = new char[0];
+
+ public char[] findNextChar(int match, int esc) {
+ try {
+ ensureBuffer();
+
+ foundEscape = false;
+ if (readBuf[index] == '"') {
+ index++;
+ return EMPTY_CHARS;
+ }
+
+ int start = index;
+
+ char[] results = null;
+ boolean foundEnd = false;
+ boolean wasEscaped = false;
+ while (!foundEnd) {
+ for (; index < length; index++) {
+ ch = readBuf[index];
+ if (wasEscaped) {
+ wasEscaped = false;
+ } else if (ch == match) {
+ foundEnd = true;
+ break;
+ } else if (ch == esc) {
+ foundEscape = true;
+ wasEscaped = true;
+ }
+ }
+
+ if (results != null) {
+ results = Chr.add(results, ArrayUtils.copyRange(readBuf, start, index));
+ }
+ else {
+ results = ArrayUtils.copyRange(readBuf, start, index);
+ }
+
+ ensureBuffer();
+
+ // Reset start if new buffer
+ if (index == 0) {
+ start = 0;
+ }
+
+ // Exit early if we run out of data
+ if (done) {
+ break;
+ }
+ }
+
+ // done will only be true if we ran out of data without seeing the match character
+ if (done) {
+ return Exceptions.die(char[].class, "Unable to find close char " + (char)match + ": " + new String(results));
+ } else {
+ index++;
+ return results;
+ }
+ } catch (Exception ex) {
+ String str = CharScanner.errorDetails("findNextChar issue", readBuf, index, ch);
+ return Exceptions.handle(char[].class, str, ex);
+ }
+ }
+
+ public boolean hadEscape() {
+ return foundEscape;
+ }
+
+ public void skipWhiteSpace() {
+ try {
+ index = CharScanner.skipWhiteSpace(readBuf, index, length);
+ if (index >= length && more) {
+ ensureBuffer();
+
+ skipWhiteSpace();
+ }
+ } catch (Exception ex) {
+ String str = CharScanner.errorDetails("skipWhiteSpace issue", readBuf, index, ch);
+ Exceptions.handle(str, ex);
+ }
+ }
+
+ public char[] readNumber() {
+ try {
+ ensureBuffer();
+
+ char[] results = CharScanner.readNumber(readBuf, index, length);
+ index += results.length;
+
+ if (index >= length && more) {
+ ensureBuffer();
+ if (length != 0) {
+ char results2[] = readNumber();
+ return Chr.add(results, results2);
+ } else {
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } catch (Exception ex) {
+ String str = CharScanner.errorDetails("readNumber issue", readBuf, index, ch);
+ return Exceptions.handle(char[].class, str, ex);
+ }
+ }
+
+ public String errorDetails(String message) {
+ return CharScanner.errorDetails(message, readBuf, index, ch);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java
new file mode 100644
index 0000000..afa54e8
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/SimpleCache.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import org.codehaus.groovy.runtime.memoize.CommonCache;
+import org.codehaus.groovy.runtime.memoize.EvictableCache;
+
+/**
+ * @author Richard Hightower
+ */
+public class SimpleCache<K, V> implements Cache<K, V> {
+ private EvictableCache<K, V> cache;
+
+ public SimpleCache(final int limit, CacheType type) {
+ if (type.equals(CacheType.LRU)) {
+ cache = new CommonCache<K, V>(limit);
+ } else {
+ cache = new CommonCache<K, V>(CommonCache.DEFAULT_INITIAL_CAPACITY, limit, EvictableCache.EvictionStrategy.FIFO);
+ }
+ }
+
+ public SimpleCache(final int limit) {
+ this(limit, CacheType.LRU);
+ }
+
+ public void put(K key, V value) {
+ cache.put(key, value);
+ }
+
+ public V get(K key) {
+ return cache.get(key);
+ }
+
+ //For testing only
+
+ public V getSilent(K key) {
+ V value = cache.get(key);
+ if (value != null) {
+ cache.remove(key);
+ cache.put(key, value);
+ }
+ return value;
+ }
+
+ public void remove(K key) {
+ cache.remove(key);
+ }
+
+ public int size() {
+ return cache.size();
+ }
+
+ public String toString() {
+ return cache.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
new file mode 100644
index 0000000..6c7dac5
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class Sys {
+
+ private static final boolean is1_8OrLater;
+ private static final boolean is1_7;
+ private static final boolean is1_8;
+
+ static {
+ BigDecimal v = new BigDecimal("-1");
+ String sversion = System.getProperty("java.version");
+ if (sversion.indexOf("_") != -1) {
+ final String[] split = sversion.split("_");
+ try {
+ String ver = split[0];
+
+ if (ver.startsWith("1.7")) {
+ v = new BigDecimal("1.7");
+ }
+
+ if (ver.startsWith("1.8")) {
+ v = new BigDecimal("1.8");
+ }
+
+ if (ver.startsWith("1.9")) {
+ v = new BigDecimal("1.9");
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.err.println("Unable to determine build number or version");
+ }
+ } else if ("1.8.0".equals(sversion)) {
+ v = new BigDecimal("1.8");
+ } else {
+ Pattern p = Pattern.compile("^([1-9]\\.[0-9]+)");
+ Matcher matcher = p.matcher(sversion);
+ if (matcher.find()) {
+ v = new BigDecimal(matcher.group(0));
+ }
+ }
+
+ is1_8OrLater = v.compareTo(new BigDecimal("1.8")) >= 0;
+ is1_7 = v.compareTo(new BigDecimal("1.7")) == 0;
+ is1_8 = v.compareTo(new BigDecimal("1.8")) == 0;
+ }
+
+ public static boolean is1_7OrLater() {
+ return true;
+ }
+
+ public static boolean is1_8OrLater() {
+ return is1_8OrLater;
+ }
+
+ public static boolean is1_7() {
+ return is1_7;
+ }
+
+ public static boolean is1_8() {
+ return is1_8;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java
new file mode 100644
index 0000000..5ce3d27
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Type.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public enum Type {
+
+ INTEGER, STRING, DOUBLE, TRUE, FALSE, NULL, MAP, LIST
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java
new file mode 100644
index 0000000..f3024fb
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Value.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * @author Rick Hightower
+ */
+public interface Value {
+
+ byte byteValue();
+
+ short shortValue();
+
+ int intValue();
+
+ long longValue();
+
+ BigDecimal bigDecimalValue();
+
+ BigInteger bigIntegerValue();
+
+ float floatValue();
+
+ double doubleValue();
+
+ boolean booleanValue();
+
+ Date dateValue();
+
+ String stringValue();
+
+ String stringValueEncoded();
+
+ Object toValue();
+
+ <T extends Enum> T toEnum(Class<T> cls);
+
+ boolean isContainer(); //either a map or a collection
+
+ void chop();
+
+ char charValue();
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java
new file mode 100644
index 0000000..aa21168
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueContainer.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+import static org.apache.groovy.json.internal.Exceptions.sputs;
+
+/**
+ * @author Rick Hightower
+ */
+public class ValueContainer implements CharSequence, Value {
+
+ public static final Value TRUE = new ValueContainer(Type.TRUE);
+ public static final Value FALSE = new ValueContainer(Type.FALSE);
+ public static final Value NULL = new ValueContainer(Type.NULL);
+
+ public Object value;
+
+ public Type type;
+ private boolean container;
+
+ public boolean decodeStrings;
+
+ public ValueContainer(Object value, Type type, boolean decodeStrings) {
+ this.value = value;
+ this.type = type;
+ this.decodeStrings = decodeStrings;
+ }
+
+ public ValueContainer(Type type) {
+ this.type = type;
+ }
+
+ public ValueContainer(Map<String, Object> map) {
+ this.value = map;
+ this.type = Type.MAP;
+ this.container = true;
+ }
+
+ public ValueContainer(List<Object> list) {
+ this.value = list;
+ this.type = Type.LIST;
+ this.container = true;
+ }
+
+ public int intValue() {
+ return die(int.class, sputs("intValue not supported for type ", type));
+ }
+
+ public long longValue() {
+ return die(int.class, sputs("intValue not supported for type ", type));
+ }
+
+ public boolean booleanValue() {
+ switch (type) {
+ case FALSE:
+ return false;
+ case TRUE:
+ return true;
+ }
+ die();
+ return false;
+ }
+
+ public String stringValue() {
+ if (type == Type.NULL) {
+ return null;
+ } else {
+ return type.toString();
+ }
+ }
+
+ public String stringValueEncoded() {
+ return toString();
+ }
+
+ public String toString() {
+ return type.toString();
+ }
+
+ public Object toValue() {
+ if (value != null) {
+ return value;
+ }
+ switch (type) {
+ case FALSE:
+ return (value = false);
+
+ case TRUE:
+ return (value = true);
+ case NULL:
+ return null;
+ }
+ die();
+ return null;
+ }
+
+ public <T extends Enum> T toEnum(Class<T> cls) {
+ return (T) value;
+ }
+
+ public boolean isContainer() {
+ return container;
+ }
+
+ public void chop() {
+ }
+
+ public char charValue() {
+ return 0;
+ }
+
+ public int length() {
+ return 0;
+ }
+
+ public char charAt(int index) {
+ return '0';
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ return "";
+ }
+
+ public Date dateValue() {
+ return null;
+ }
+
+ public byte byteValue() {
+ return 0;
+ }
+
+ public short shortValue() {
+ return 0;
+ }
+
+ public BigDecimal bigDecimalValue() {
+ return null;
+ }
+
+ public BigInteger bigIntegerValue() {
+ return null;
+ }
+
+ public double doubleValue() {
+ return 0;
+ }
+
+ public float floatValue() {
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java
new file mode 100644
index 0000000..7027200
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueList.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Rick Hightower
+ */
+public class ValueList extends AbstractList<Object> {
+
+ List<Object> list = new ArrayList<Object>(5);
+
+ private final boolean lazyChop;
+ boolean converted = false;
+
+ public ValueList(boolean lazyChop) {
+ this.lazyChop = lazyChop;
+ }
+
+ public Object get(int index) {
+ Object obj = list.get(index);
+
+ if (obj instanceof Value) {
+ obj = convert((Value) obj);
+ list.set(index, obj);
+ }
+
+ chopIfNeeded(obj);
+ return obj;
+ }
+
+ private static Object convert(Value value) {
+ return value.toValue();
+ }
+
+ public int size() {
+ return list.size();
+ }
+
+ public Iterator<Object> iterator() {
+ convertAllIfNeeded();
+ return list.iterator();
+ }
+
+ private void convertAllIfNeeded() {
+ if (!converted) {
+ converted = true;
+ for (int index = 0; index < list.size(); index++) {
+ this.get(index);
+ }
+ }
+ }
+
+ public void clear() {
+ list.clear();
+ }
+
+ public boolean add(Object obj) {
+ return list.add(obj);
+ }
+
+ public void chopList() {
+ for (Object obj : list) {
+ if (obj == null) continue;
+
+ if (obj instanceof Value) {
+ Value value = (Value) obj;
+ if (value.isContainer()) {
+ chopContainer(value);
+ } else {
+ value.chop();
+ }
+ }
+ }
+ }
+
+ private void chopIfNeeded(Object object) {
+ if (lazyChop) {
+ if (object instanceof LazyValueMap) {
+ LazyValueMap m = (LazyValueMap) object;
+ m.chopMap();
+ } else if (object instanceof ValueList) {
+ ValueList list = (ValueList) object;
+ list.chopList();
+ }
+ }
+ }
+
+ static void chopContainer(Value value) {
+ Object obj = value.toValue();
+ if (obj instanceof LazyValueMap) {
+ LazyValueMap map = (LazyValueMap) obj;
+ map.chopMap();
+ } else if (obj instanceof ValueList) {
+ ValueList list = (ValueList) obj;
+ list.chopList();
+ }
+ }
+
+ public List<Object> list() {
+ return this.list;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java
new file mode 100644
index 0000000..c238cbf
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMap.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.Map;
+
+/**
+ * @author Richard Hightower
+ */
+public interface ValueMap<K, V> extends Map<K, V> {
+
+ /* add a map item value. */
+ void add(MapItemValue miv);
+
+ /**
+ * Return size w/o hydrating the map.
+ */
+ int len();
+
+ /**
+ * Has the map been hydrated.
+ */
+ boolean hydrated();
+
+ /**
+ * Give me the items in the map without hydrating the map.
+ * Realize that the array is likely larger than the length so array items can be null.
+ */
+ Entry<String, Value>[] items();
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java
new file mode 100644
index 0000000..0b3103e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/ValueMapImpl.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * This map is for object serialization mainly.
+ * The idea is the final conversion of
+ * the Value objects are delayed until the last possible moment, i.e., just before injected into a bean.
+ *
+ * @author Rick Hightower
+ */
+public class ValueMapImpl extends AbstractMap<String, Value> implements ValueMap<String, Value> {
+
+ /**
+ * The internal map to hold the Value map.
+ */
+ private Map<String, Value> map = null;
+
+ /**
+ * The items held in the map.
+ */
+ private Entry<String, Value>[] items = new Entry[20];
+
+ /* The current length of the map. */
+ private int len = 0;
+
+ /**
+ * Add a MapItemValue to the map.
+ *
+ * @param miv map value item.
+ */
+
+ public void add(MapItemValue miv) {
+ if (len >= items.length) {
+ items = LazyMap.grow(items);
+ }
+ items[len] = miv;
+ len++;
+ }
+
+ public int len() {
+ return len;
+ }
+
+ public boolean hydrated() {
+ return map != null;
+ }
+
+ public Entry<String, Value>[] items() {
+ return items;
+ }
+
+ /**
+ * Get the items for the key.
+ *
+ * @param key
+ * @return the items for the given key
+ */
+
+ public Value get(Object key) {
+ /* If the length is under and we are asking for the key, then just look for the key. Don't build the map. */
+ if (map == null && items.length < 20) {
+ for (Object item : items) {
+ MapItemValue miv = (MapItemValue) item;
+ if (key.equals(miv.name.toValue())) {
+ return miv.value;
+ }
+ }
+ return null;
+ } else {
+ if (map == null) buildIfNeededMap();
+ return map.get(key);
+ }
+ }
+
+ public Value put(String key, Value value) {
+ die("Not that kind of map");
+ return null;
+ }
+
+ /**
+ * If the map has not been built yet, then we just return a fake entry set.
+ */
+
+ public Set<Entry<String, Value>> entrySet() {
+ buildIfNeededMap();
+ return map.entrySet();
+ }
+
+ /**
+ * Build the map if requested to, it does this lazily.
+ */
+ private void buildIfNeededMap() {
+ if (map == null) {
+ map = new HashMap<String, Value>(items.length);
+
+ for (Entry<String, Value> miv : items) {
+ if (miv == null) {
+ break;
+ }
+ map.put(miv.getKey(), miv.getValue());
+ }
+ }
+ }
+
+ /**
+ * Return a collection of values.
+ */
+ public Collection<Value> values() {
+ this.buildIfNeededMap();
+ return map.values();
+ }
+
+ /**
+ * Return the size of the map. Use the map if it has already been created.
+ *
+ * @return size
+ */
+ public int size() {
+ this.buildIfNeededMap();
+ return map.size();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory b/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
new file mode 100644
index 0000000..eff53ea
--- /dev/null
+++ b/subprojects/groovy-json/src/main/resources/META-INF/services/org.apache.groovy.json.FastStringServiceFactory
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.groovy.json.DefaultFastStringServiceFactory
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
index 8915f55..a09721c 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
@@ -18,7 +18,7 @@
*/
package groovy.json
-import groovy.json.internal.CharBuf
+import org.apache.groovy.json.internal.CharBuf
/**
* Test the internal CharBuf class
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
index ad21ee9..09bb35f 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy
@@ -20,7 +20,7 @@ package groovy.json
import groovy.json.JsonGenerator.Converter
import groovy.json.JsonGenerator.Options
-import groovy.json.internal.CharBuf
+import org.apache.groovy.json.internal.CharBuf
/**
* Tests extensibility of JsonGenerator and associated classes
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
index 3ec2266..17819f5 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
@@ -18,8 +18,8 @@
*/
package groovy.json
-import groovy.json.internal.CharBuf
-import groovy.json.internal.IO
+import org.apache.groovy.json.internal.CharBuf
+import org.apache.groovy.json.internal.IO
/**
* Test the internal IO class
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
index 9356825..db039d3 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
@@ -18,7 +18,7 @@
*/
package groovy.json
-import groovy.json.internal.Value
+import org.apache.groovy.json.internal.Value
/**
* @author Guillaume Laforge
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy
deleted file mode 100644
index 890350e..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ArrayUtilsTest.groovy
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-class ArrayUtilsTest extends GroovyTestCase {
-
- void testCopyRange() {
- char[] chars = "t"
- assert ArrayUtils.copyRange(chars, 0, 1) == ((char[]) "t")
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
deleted file mode 100644
index a420eef..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-class CharScannerTest extends GroovyTestCase {
-
- void testParseInt() {
- int i = CharScanner.parseInt("-22".toCharArray())
- assert i == -22
-
- i = CharScanner.parseInt("22".toCharArray())
- assert i == 22
- }
-
- void testParseLongTest() {
- long value = CharScanner.parseLong("-22".toCharArray())
- assert value == -22L
-
- value = CharScanner.parseInt("22".toCharArray())
- assert value == 22
- }
-
- void testParseLongTest2() {
- String test = "" + ((long) (Long.MAX_VALUE / 2L))
- long value = CharScanner.parseLong(test.toCharArray())
- assert value == Long.parseLong(test)
- }
-
- void testParseLongTest3() {
- String test = "" + (Long.MIN_VALUE / 2L)
- long value = CharScanner.parseLong(test.toCharArray())
- assert value == Long.parseLong(test)
- }
-
- void testParseLongTest4() {
- String test = "" + (Long.MAX_VALUE)
- long value = CharScanner.parseLong(test.toCharArray())
- assert value == Long.parseLong(test)
- }
-
- void testParseLongTest5() {
- String test = "" + (Long.MIN_VALUE)
- long value = CharScanner.parseLong(test.toCharArray())
- assert value == Long.parseLong(test)
- }
-
- void testParseIntMax() {
- int i = 0
- i = CharScanner.parseInt(("" + Integer.MAX_VALUE).toCharArray())
- assert i == Integer.MAX_VALUE
- }
-
- void testParseIntMin() {
- int i = 0
- i = CharScanner.parseInt(("" + Integer.MIN_VALUE).toCharArray())
- assert i == Integer.MIN_VALUE
- }
-
- void testParseLongMax() {
- long l = 0
- l = CharScanner.parseLong(("" + Long.MAX_VALUE).toCharArray())
- assert l == Long.MAX_VALUE
- }
-
- void testParseLongMin() {
- long l = 0
- l = CharScanner.parseLong(("" + Long.MIN_VALUE).toCharArray())
- assert l == Long.MIN_VALUE || die("l", l, "MIN", Long.MIN_VALUE)
- }
-
- void testParseDouble() {
- String str = "123456789"
- double num =
- CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
- assert num == 123456789d
- }
-
- void testParseDoubleNegative() {
- String str = "-1.23456789E8"
- double num =
- (Double) CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length())
- assert num == -1.23456789E8
- }
-
- void testParseDoubleNegativeNoE() {
- String str = "-123456789"
- testDouble(str)
- }
-
- void testParseDoubleNegativeNoE2() {
- String str = "-1234567890"
- testDouble(str)
- }
-
- void testParseDoubleMax() {
- String str = "" + Double.MAX_VALUE
- testDouble(str)
- }
-
- void testParseDoubleMin() {
- String str = "" + Double.MIN_VALUE
- testDouble(str)
- }
-
- void testManyDoubles() {
- List<String> doubles = ["" + 1.01d, "" + 123456789.234D, "" + 55D,
- "" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE,
- "66666666.666", "-6666666666.6666", "1E10"]
-
- for (String str : doubles) {
- testDouble(str)
- }
- }
-
- private void testDouble(String str) {
- double num = CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
- assert num == Double.parseDouble(str)
- }
-
- private void testDoubleInStringThreeOver(String str) {
- double numTest = Double.parseDouble(str)
- double num = CharScanner.parseJsonNumber((" " + str).toCharArray(), 3, str.length() + 3).doubleValue()
- assert num == numTest
- }
-
- void testParseIntIgnore0() {
- int i = CharScanner.parseIntFromToIgnoreDot("1.1".toCharArray(), 0, "1.1".length())
- assert i == 11
- }
-
- void testSimpleDoubleInString() {
- testDoubleInStringThreeOver("1.1")
- }
-
- void testLongMaxWithOffset() {
- testDoubleInStringThreeOver("" + Long.MAX_VALUE)
- }
-
- void testLargeDecimal() {
- testDoubleInStringThreeOver("" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE)
- }
-
- void testLargeDecimal2() {
- testDoubleInStringThreeOver("1000" + "." + "10001")
- }
-
- void testLargeDecimal3() {
- testDoubleInStringThreeOver("10000" + "." + "100001")
- }
-
- void testLargeDecimal4() {
- testDoubleInStringThreeOver("" + 10_000_000 + "." + 10_000_001)
- }
-
- void testLargeDecimal5() {
- testDoubleInStringThreeOver("" + 100_000_000 + "." + 100_000_001)
- }
-
- void testLargeDecimal6() {
- testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001)
- }
-
- void testLargeDecimal7() {
- testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001L)
- }
-
- void testLargeDecimal8() {
- testDoubleInStringThreeOver("" + 1_000_000_000_000L + "." + 1_000_000_001L)
- }
-
- void testLargeDecimal9() {
- testDoubleInStringThreeOver("" + 10_000_000_000_000L + "." + 1_000_000_001L)
- }
-
- void testLargeDecimal10() {
- testDoubleInStringThreeOver("" + 100_000_000_000_000_000L + "." + 1_000_000_001L)
- }
-
- void testLargeDecimal11() {
- testDoubleInStringThreeOver("" + 1_000_000_000_000_000_000L + "." + 1_000_000_001L)
- }
-
- void testLongMinWithOffset() {
- testDoubleInStringThreeOver("" + Long.MIN_VALUE)
- }
-
- void testDoubleMaxWithOffset() {
- testDoubleInStringThreeOver("" + Double.MAX_VALUE)
- }
-
- void testDoubleMinWithOffset() {
- testDoubleInStringThreeOver("" + Double.MIN_VALUE)
- }
-
- void testDoubleMaxWithOffset2() {
- testDoubleInStringThreeOver("" + Double.MAX_VALUE / 2)
- }
-
- void testDoubleMinWithOffset2() {
- testDoubleInStringThreeOver("" + Double.MIN_VALUE / 2)
- }
-
- void testDoubleMaxWithOffset3() {
- testDoubleInStringThreeOver("" + (Double.MAX_VALUE / 9) * 8)
- }
-
- void testDoubleMinWithOffset3() {
- testDoubleInStringThreeOver("" + (Double.MIN_VALUE / 9) * 8)
- }
-
- void testParseLong() {
- String str = "12345678910"
- long l1 = CharScanner.parseLongFromTo(str.toCharArray(), 0, str.length())
- assert l1 == 12345678910L
-
- str = "abc12345678910"
- l1 = CharScanner.parseLongFromTo(str.toCharArray(), 3, str.length())
- assert l1 == 12345678910L
-
- str = "abcdefghijklmnopqrstuvwxyz12345678910"
- l1 = CharScanner.parseLongFromTo(str.toCharArray(), 26, str.length())
- assert l1 == 12345678910L
-
- String str2 = "abcdefghijklmnopqrstuvwxyz12345678910mymilkshakemakestheboysintheyard"
- l1 = CharScanner.parseLongFromTo(str2.toCharArray(), 26, str.length())
- assert l1 == 12345678910L
- }
-
- void testParseIntFromTo() {
- String str = "123456789"
- int i = CharScanner.parseIntFromTo(str.toCharArray(), 0, str.length())
- assert i == 123456789
-
- str = "abc-123456789"
- i = CharScanner.parseIntFromTo(str.toCharArray(), 3, str.length())
- assert i == -123456789
-
- str = "abcdefghijklmnopqrstuvwxyz56789"
- i = CharScanner.parseIntFromTo(str.toCharArray(), 26, str.length())
- assert i == 56789
-
- str = "abcdefghijklmnopqrstuvwxyz-6789mymilkshakemakestheboysintheyard"
- i = CharScanner.parseIntFromTo(str.toCharArray(), 26, 31)
- assert i == -6789
- }
-
- void testParseJsonNumberToDecimal() {
- def num = CharScanner.parseJsonNumber('123.40'.toCharArray())
- assert num instanceof BigDecimal
- assert num == 123.40G
- assert num.scale() == 2
-
- num = CharScanner.parseJsonNumber('-123.400'.toCharArray())
- assert num instanceof BigDecimal
- assert num == -123.400G
- assert num.scale() == 3
-
- num = CharScanner.parseJsonNumber('3.7e-5'.toCharArray())
- assert num instanceof BigDecimal
- assert num == 0.000037G
- assert num.scale() == 6
-
- num = CharScanner.parseJsonNumber('-1.25E+7'.toCharArray())
- assert num instanceof BigDecimal
- assert num == -12500000.0G
- assert num.scale() == -5
- }
-
- protected assertArrayEquals(char[] expected, char[] actual) {
- assertArrayEquals((Object[]) expected, (Object[]) actual)
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
deleted file mode 100644
index b790760..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-import static groovy.json.internal.Chr.*
-
-class ChrTest extends GroovyTestCase {
-
- void testLpad() {
- def results = lpad('abc'.toCharArray(), 5, '#' as char)
-
- assertArrayEquals(
- '##abc'.toCharArray(),
- results
- )
- }
-
- void testIsIn() {
- def letters = 'abcd'.toCharArray()
-
- assertTrue Chr.in('a' as char, letters)
- assertFalse Chr.in('z' as char, letters)
- }
-
- void testIsInAtOffset() {
- def letters = 'abcd'.toCharArray()
-
- assertFalse Chr.in('a' as char, 1, letters)
- assertTrue Chr.in('c' as char, 1, letters)
- }
-
- void testIsInAtRange() {
- def letters = 'abcd'.toCharArray()
-
- assertFalse Chr.in('a' as char, 1, 2, letters)
- assertTrue Chr.in('c' as char, 1, 3, letters)
- }
-
- void testGrow() {
- def letters = 'abcde'.toCharArray()
- letters = grow(letters, 21)
-
- assertEquals(
- 'e',
- letters[4]
- )
-
- assertEquals(
- 'a',
- letters[0]
- )
-
- assertEquals(
- 26,
- letters.length
- )
-
- assertEquals(
- '\0',
- letters[20]
- )
- }
-
- void testGrowFast() {
- def letters = 'abcdef'.toCharArray()
- letters = grow(letters)
-
- assertEquals(
- 'e',
- letters[4]
- )
-
- assertEquals(
- 'a',
- letters[0]
- )
-
- assertEquals(
- 12,
- letters.length
- )
-
- assertEquals(
- letters[9],
- '\0'
- )
- }
-
- void testCopy() {
- def chars = 'abcde'.toCharArray()
-
- assertArrayEquals(
- chars,
- copy(chars)
- )
- }
-
- void testByteCopyIntoCharArray() {
- def charArray = new char[1000]
- def bytes = "0123456789000".bytes
-
- Chr._idx(charArray, 0, bytes)
-
- char ch = charArray[0]
- assert ch == '0'
-
- ch = charArray[9]
- assert ch == '9'
-
- Chr._idx(charArray, 100, bytes, 0, 3)
-
- ch = charArray[100]
- assert ch == '0'
-
- ch = charArray[101]
- assert ch == '1'
-
- ch = charArray[102]
- assert ch == '2'
-
- Chr._idx(charArray, 200, bytes, 3, 6)
-
- ch = charArray[200]
- assert ch == '3' || die(" not '3' " + ch)
-
- ch = charArray[201]
- assert ch == '4' || die(" not '4' " + ch)
-
- ch = charArray[202]
- assert ch == '5' || die(" not '5' " + ch)
- }
-
- protected assertArrayEquals(char[] expected, char[] actual) {
- assertArrayEquals((Object[]) expected, (Object[]) actual)
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy
deleted file mode 100644
index abc31c0..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/DatesTest.groovy
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-
-class DatesTest extends GroovyTestCase{
-
- // GROOVY-7462
- void testDatesFactory() {
- Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
- Thread.sleep(1) // lets get some time between calling constructors
-
- Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
- assert d1 == d2
- }
-
- void testDatesFactoryWithDefaultMs() {
- Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,0)
- Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
- assert d1 == d2
- }
-
- void testDatesFactoryEnforceDefaultMs() {
- Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,1)
- Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
-
- assert d1 != d2
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy
deleted file mode 100644
index 1c31673..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsTest.groovy
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-class FastStringUtilsTest extends GroovyTestCase {
-
- void testToCharArray() {
- synchronized (FastStringUtils) {
- def str = "some test"
- // FastStringUtils accesses the underlying char array directly
- if (str.value instanceof char[]) {
- assert FastStringUtils.toCharArray(str).is(str.value) : FastStringUtils.STRING_IMPLEMENTATION.toString()
- } else if (str.value instanceof byte[]) {
- // jdk9
- assert FastStringUtils.toCharArray(str) == str.toCharArray()
- } else {
- fail('unexpected type encountered for String value field')
- }
- }
- }
-
- void testToCharArrayWithStringBuilder() {
- synchronized (FastStringUtils) {
- def str = new StringBuilder().append("some test")
- // StringBuilder#toString() returns a new String object
- assert FastStringUtils.toCharArray(str) == "some test".toCharArray()
- }
- }
-
- void testNoCopyStringFromChars() {
- synchronized (FastStringUtils) {
- def source = "äöüliu"
- def chars = source.toCharArray()
-
- assert FastStringUtils.noCopyStringFromChars(chars) == source
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
deleted file mode 100644
index 6e3e5f4..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-class FastStringUtilsUnsafeDisabledTest extends GroovyTestCase {
-
- FastStringUtils.StringImplementation oldStringImplementation
-
- void setUp() {
- // to disable Unsafe usage, we set the StringImplementation to the very safe UNKNOWN
-
- oldStringImplementation = FastStringUtils.STRING_IMPLEMENTATION
- FastStringUtils.STRING_IMPLEMENTATION = FastStringUtils.StringImplementation.UNKNOWN
- }
-
- @Override
- void tearDown() {
- FastStringUtils.STRING_IMPLEMENTATION = oldStringImplementation
- }
-
- void testToCharArray() {
- synchronized (FastStringUtils) {
- def str = "some test"
- assert !FastStringUtils.toCharArray(str).is(str.value)
- }
- }
-
- void testToCharArrayWithStringBuilder() {
- synchronized (FastStringUtils) {
- def str = new StringBuilder().append("some test")
- // StringBuilder#toString() returns a new String object
- assert FastStringUtils.toCharArray(str) == "some test".toCharArray()
- }
- }
-
- void testNoCopyStringFromChars() {
- synchronized (FastStringUtils) {
- def source = "äöüliu"
- def chars = source.toCharArray()
-
- assert FastStringUtils.noCopyStringFromChars(chars) == source
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
deleted file mode 100644
index 99c0751..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-class LazyMapTest extends GroovyTestCase {
-
- // GROOVY-7302
- void testSizeWhenNoBackingMapCreated() {
- def map = new LazyMap()
- map.someProperty = "1"
- map.someProperty = "2"
- map.someProperty = "3"
- assert map.size() == 1
- map.someProperty2 = "4"
- assert map.size() == 2
- }
-
- void testSizeWhenLazyCreated() {
- def map = new LazyMap()
- map.someProperty1 = '1'
- assert map.@map == null
- map.someProperty2 = '2'
- assert map.@map == null
- map.someProperty3 = '3'
- assert map.@map == null
- map.someProperty4 = '4'
- assert map.@map == null
- map.someProperty5 = '5'
- assert map.@map == null
- map.someProperty6 = '6'
- assert map.@map == null
- map.someProperty7 = '7'
- assert map.someProperty6 == '6'
- assert map.@map?.size() == 7
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
deleted file mode 100644
index 6f79081..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal
-
-import groovy.json.internal.Exceptions.JsonInternalException;
-
-class ReaderCharacterSourceTest extends GroovyTestCase {
-
- public static final int QUOTE_CHAR = (int)'"'.charAt(0)
- public static final int BACKSLASH_CHAR = (int)'\\'.charAt(0)
-
- void testFindNextChar() {
- def testCases = [
- [ input: '""', expected: '' ],
- [ input: '"word"', expected: 'word' ],
- [ input: '"\\u0026value"', expected: '\\u0026value' ],
- [ input: '"value\\u0026"', expected: 'value\\u0026' ],
- [ input: '"double\\"quote"', expected: 'double\\"quote' ],
- [ input: '"\\"\\"\\"\\""', expected: '\\"\\"\\"\\"' ],
- [ input: '"\\\\\\\\\\\\"', expected: '\\\\\\\\\\\\' ]
- ]
-
- testCases.each {
- boolean containsEscape = it.input.contains('\\')
- // Test all possible buffer sizes
- for (int i = 1; i < it.input.length() + 1; i++) {
- ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader(it.input), i)
- rcs.nextChar() // Read the first double quote as if JSON parsing
-
- String result = new String(rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR))
-
- assertEquals("Buffer size ${i}", it.expected, result)
- assertEquals("Expected escape character in ${it.input}, buffer size ${i}", containsEscape, rcs.hadEscape())
- }
- }
- }
-
- void testFindNextCharException() {
- shouldFail(JsonInternalException) {
- ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote'))
- rcs.nextChar() // Read the first double quote as if JSON parsing
- rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
- }
- }
-
- void testFindNextCharExceptionWithEscapedEnding() {
- shouldFail(JsonInternalException) {
- ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote ending with escape \\'))
- rcs.nextChar() // Read the first double quote as if JSON parsing
- rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
- }
- }
-
- void testFindNextCharExceptionWithEscapedQuote() {
- shouldFail(JsonInternalException) {
- ReaderCharacterSource rcs = new ReaderCharacterSource(new StringReader('"missing end quote with escaped quote \\"'))
- rcs.nextChar() // Read the first double quote as if JSON parsing
- rcs.findNextChar(QUOTE_CHAR, BACKSLASH_CHAR)
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy
new file mode 100644
index 0000000..c79ac34
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/DefaultFastStringServiceTest.groovy
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json
+
+class DefaultFastStringServiceTest extends GroovyTestCase {
+
+ FastStringService service = new DefaultFastStringServiceFactory().service
+
+ void testToCharArray() {
+ def str = "some test"
+ assert service.toCharArray(str) == str.toCharArray()
+ }
+
+ void testNoCopyStringFromChars() {
+ def source = "äöüliu"
+ def chars = source.toCharArray()
+ assert service.noCopyStringFromChars(chars) == source
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy
new file mode 100644
index 0000000..d6bea5c
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ArrayUtilsTest.groovy
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal
+
+class ArrayUtilsTest extends GroovyTestCase {
+
+ void testCopyRange() {
+ char[] chars = "t"
+ assert ArrayUtils.copyRange(chars, 0, 1) == ((char[]) "t")
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy
new file mode 100644
index 0000000..5e3f49a
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/CharScannerTest.groovy
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal
+
+class CharScannerTest extends GroovyTestCase {
+
+ void testParseInt() {
+ int i = CharScanner.parseInt("-22".toCharArray())
+ assert i == -22
+
+ i = CharScanner.parseInt("22".toCharArray())
+ assert i == 22
+ }
+
+ void testParseLongTest() {
+ long value = CharScanner.parseLong("-22".toCharArray())
+ assert value == -22L
+
+ value = CharScanner.parseInt("22".toCharArray())
+ assert value == 22
+ }
+
+ void testParseLongTest2() {
+ String test = "" + ((long) (Long.MAX_VALUE / 2L))
+ long value = CharScanner.parseLong(test.toCharArray())
+ assert value == Long.parseLong(test)
+ }
+
+ void testParseLongTest3() {
+ String test = "" + (Long.MIN_VALUE / 2L)
+ long value = CharScanner.parseLong(test.toCharArray())
+ assert value == Long.parseLong(test)
+ }
+
+ void testParseLongTest4() {
+ String test = "" + (Long.MAX_VALUE)
+ long value = CharScanner.parseLong(test.toCharArray())
+ assert value == Long.parseLong(test)
+ }
+
+ void testParseLongTest5() {
+ String test = "" + (Long.MIN_VALUE)
+ long value = CharScanner.parseLong(test.toCharArray())
+ assert value == Long.parseLong(test)
+ }
+
+ void testParseIntMax() {
+ int i = 0
+ i = CharScanner.parseInt(("" + Integer.MAX_VALUE).toCharArray())
+ assert i == Integer.MAX_VALUE
+ }
+
+ void testParseIntMin() {
+ int i = 0
+ i = CharScanner.parseInt(("" + Integer.MIN_VALUE).toCharArray())
+ assert i == Integer.MIN_VALUE
+ }
+
+ void testParseLongMax() {
+ long l = 0
+ l = CharScanner.parseLong(("" + Long.MAX_VALUE).toCharArray())
+ assert l == Long.MAX_VALUE
+ }
+
+ void testParseLongMin() {
+ long l = 0
+ l = CharScanner.parseLong(("" + Long.MIN_VALUE).toCharArray())
+ assert l == Long.MIN_VALUE || die("l", l, "MIN", Long.MIN_VALUE)
+ }
+
+ void testParseDouble() {
+ String str = "123456789"
+ double num =
+ CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
+ assert num == 123456789d
+ }
+
+ void testParseDoubleNegative() {
+ String str = "-1.23456789E8"
+ double num =
+ (Double) CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length())
+ assert num == -1.23456789E8
+ }
+
+ void testParseDoubleNegativeNoE() {
+ String str = "-123456789"
+ testDouble(str)
+ }
+
+ void testParseDoubleNegativeNoE2() {
+ String str = "-1234567890"
+ testDouble(str)
+ }
+
+ void testParseDoubleMax() {
+ String str = "" + Double.MAX_VALUE
+ testDouble(str)
+ }
+
+ void testParseDoubleMin() {
+ String str = "" + Double.MIN_VALUE
+ testDouble(str)
+ }
+
+ void testManyDoubles() {
+ List<String> doubles = ["" + 1.01d, "" + 123456789.234D, "" + 55D,
+ "" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE,
+ "66666666.666", "-6666666666.6666", "1E10"]
+
+ for (String str : doubles) {
+ testDouble(str)
+ }
+ }
+
+ private void testDouble(String str) {
+ double num = CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
+ assert num == Double.parseDouble(str)
+ }
+
+ private void testDoubleInStringThreeOver(String str) {
+ double numTest = Double.parseDouble(str)
+ double num = CharScanner.parseJsonNumber((" " + str).toCharArray(), 3, str.length() + 3).doubleValue()
+ assert num == numTest
+ }
+
+ void testParseIntIgnore0() {
+ int i = CharScanner.parseIntFromToIgnoreDot("1.1".toCharArray(), 0, "1.1".length())
+ assert i == 11
+ }
+
+ void testSimpleDoubleInString() {
+ testDoubleInStringThreeOver("1.1")
+ }
+
+ void testLongMaxWithOffset() {
+ testDoubleInStringThreeOver("" + Long.MAX_VALUE)
+ }
+
+ void testLargeDecimal() {
+ testDoubleInStringThreeOver("" + Integer.MAX_VALUE + "." + Integer.MAX_VALUE)
+ }
+
+ void testLargeDecimal2() {
+ testDoubleInStringThreeOver("1000" + "." + "10001")
+ }
+
+ void testLargeDecimal3() {
+ testDoubleInStringThreeOver("10000" + "." + "100001")
+ }
+
+ void testLargeDecimal4() {
+ testDoubleInStringThreeOver("" + 10_000_000 + "." + 10_000_001)
+ }
+
+ void testLargeDecimal5() {
+ testDoubleInStringThreeOver("" + 100_000_000 + "." + 100_000_001)
+ }
+
+ void testLargeDecimal6() {
+ testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001)
+ }
+
+ void testLargeDecimal7() {
+ testDoubleInStringThreeOver("" + 100_000_000 + "." + 1_000_000_001L)
+ }
+
+ void testLargeDecimal8() {
+ testDoubleInStringThreeOver("" + 1_000_000_000_000L + "." + 1_000_000_001L)
+ }
+
+ void testLargeDecimal9() {
+ testDoubleInStringThreeOver("" + 10_000_000_000_000L + "." + 1_000_000_001L)
+ }
+
+ void testLargeDecimal10() {
+ testDoubleInStringThreeOver("" + 100_000_000_000_000_000L + "." + 1_000_000_001L)
+ }
+
+ void testLargeDecimal11() {
+ testDoubleInStringThreeOver("" + 1_000_000_000_000_000_000L + "." + 1_000_000_001L)
+ }
+
+ void testLongMinWithOffset() {
+ testDoubleInStringThreeOver("" + Long.MIN_VALUE)
+ }
+
+ void testDoubleMaxWithOffset() {
+ testDoubleInStringThreeOver("" + Double.MAX_VALUE)
+ }
+
+ void testDoubleMinWithOffset() {
+ testDoubleInStringThreeOver("" + Double.MIN_VALUE)
+ }
+
+ void testDoubleMaxWithOffset2() {
+ testDoubleInStringThreeOver("" + Double.MAX_VALUE / 2)
+ }
+
+ void testDoubleMinWithOffset2() {
+ testDoubleInStringThreeOver("" + Double.MIN_VALUE / 2)
+ }
+
+ void testDoubleMaxWithOffset3() {
+ testDoubleInStringThreeOver("" + (Double.MAX_VALUE / 9) * 8)
+ }
+
+ void testDoubleMinWithOffset3() {
+ testDoubleInStringThreeOver("" + (Double.MIN_VALUE / 9) * 8)
+ }
+
+ void testParseLong() {
+ String str = "12345678910"
+ long l1 = CharScanner.parseLongFromTo(str.toCharArray(), 0, str.length())
+ assert l1 == 12345678910L
+
+ str = "abc12345678910"
+ l1 = CharScanner.parseLongFromTo(str.toCharArray(), 3, str.length())
+ assert l1 == 12345678910L
+
+ str = "abcdefghijklmnopqrstuvwxyz12345678910"
+ l1 = CharScanner.parseLongFromTo(str.toCharArray(), 26, str.length())
+ assert l1 == 12345678910L
+
+ String str2 = "abcdefghijklmnopqrstuvwxyz12345678910mymilkshakemakestheboysintheyard"
+ l1 = CharScanner.parseLongFromTo(str2.toCharArray(), 26, str.length())
+ assert l1 == 12345678910L
+ }
+
+ void testParseIntFromTo() {
+ String str = "123456789"
+ int i = CharScanner.parseIntFromTo(str.toCharArray(), 0, str.length())
+ assert i == 123456789
+
+ str = "abc-123456789"
+ i = CharScanner.parseIntFromTo(str.toCharArray(), 3, str.length())
+ assert i == -123456789
+
+ str = "abcdefghijklmnopqrstuvwxyz56789"
+ i = CharScanner.parseIntFromTo(str.toCharArray(), 26, str.length())
+ assert i == 56789
+
+ str = "abcdefghijklmnopqrstuvwxyz-6789mymilkshakemakestheboysintheyard"
+ i = CharScanner.parseIntFromTo(str.toCharArray(), 26, 31)
+ assert i == -6789
+ }
+
+ void testParseJsonNumberToDecimal() {
+ def num = CharScanner.parseJsonNumber('123.40'.toCharArray())
+ assert num instanceof BigDecimal
+ assert num == 123.40G
+ assert num.scale() == 2
+
+ num = CharScanner.parseJsonNumber('-123.400'.toCharArray())
+ assert num instanceof BigDecimal
+ assert num == -123.400G
+ assert num.scale() == 3
+
+ num = CharScanner.parseJsonNumber('3.7e-5'.toCharArray())
+ assert num instanceof BigDecimal
+ assert num == 0.000037G
+ assert num.scale() == 6
+
+ num = CharScanner.parseJsonNumber('-1.25E+7'.toCharArray())
+ assert num instanceof BigDecimal
+ assert num == -12500000.0G
+ assert num.scale() == -5
+ }
+
+ protected assertArrayEquals(char[] expected, char[] actual) {
+ assertArrayEquals((Object[]) expected, (Object[]) actual)
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy
new file mode 100644
index 0000000..bcdac93
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/ChrTest.groovy
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal
+
+import static org.apache.groovy.json.internal.Chr.*
+
+class ChrTest extends GroovyTestCase {
+
+ void testLpad() {
+ def results = lpad('abc'.toCharArray(), 5, '#' as char)
+
+ assertArrayEquals(
+ '##abc'.toCharArray(),
+ results
+ )
+ }
+
+ void testIsIn() {
+ def letters = 'abcd'.toCharArray()
+
+ assertTrue Chr.in('a' as char, letters)
+ assertFalse Chr.in('z' as char, letters)
+ }
+
+ void testIsInAtOffset() {
+ def letters = 'abcd'.toCharArray()
+
+ assertFalse Chr.in('a' as char, 1, letters)
+ assertTrue Chr.in('c' as char, 1, letters)
+ }
+
+ void testIsInAtRange() {
+ def letters = 'abcd'.toCharArray()
+
+ assertFalse Chr.in('a' as char, 1, 2, letters)
+ assertTrue Chr.in('c' as char, 1, 3, letters)
+ }
+
+ void testGrow() {
+ def letters = 'abcde'.toCharArray()
+ letters = grow(letters, 21)
+
+ assertEquals(
+ 'e',
+ letters[4]
+ )
+
+ assertEquals(
+ 'a',
+ letters[0]
+ )
+
+ assertEquals(
+ 26,
+ letters.length
+ )
+
+ assertEquals(
+ '\0',
+ letters[20]
+ )
+ }
+
+ void testGrowFast() {
+ def letters = 'abcdef'.toCharArray()
+ letters = grow(letters)
+
+ assertEquals(
+ 'e',
+ letters[4]
+ )
+
+ assertEquals(
+ 'a',
+ letters[0]
+ )
+
+ assertEquals(
+ 12,
+ letters.length
+ )
+
+ assertEquals(
+ letters[9],
+ '\0'
+ )
+ }
+
+ void testCopy() {
+ def chars = 'abcde'.toCharArray()
+
+ assertArrayEquals(
+ chars,
+ copy(chars)
+ )
+ }
+
+ void testByteCopyIntoCharArray() {
+ def charArray = new char[1000]
+ def bytes = "0123456789000".bytes
+
+ Chr._idx(charArray, 0, bytes)
+
+ char ch = charArray[0]
+ assert ch == '0'
+
+ ch = charArray[9]
+ assert ch == '9'
+
+ Chr._idx(charArray, 100, bytes, 0, 3)
+
+ ch = charArray[100]
+ assert ch == '0'
+
+ ch = charArray[101]
+ assert ch == '1'
+
+ ch = charArray[102]
+ assert ch == '2'
+
+ Chr._idx(charArray, 200, bytes, 3, 6)
+
+ ch = charArray[200]
+ assert ch == '3' || die(" not '3' " + ch)
+
+ ch = charArray[201]
+ assert ch == '4' || die(" not '4' " + ch)
+
+ ch = charArray[202]
+ assert ch == '5' || die(" not '5' " + ch)
+ }
+
+ protected assertArrayEquals(char[] expected, char[] actual) {
+ assertArrayEquals((Object[]) expected, (Object[]) actual)
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy
new file mode 100644
index 0000000..f130362
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/org/apache/groovy/json/internal/DatesTest.groovy
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal
+
+class DatesTest extends GroovyTestCase{
+
+ // GROOVY-7462
+ void testDatesFactory() {
+ Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+ Thread.sleep(1) // lets get some time between calling constructors
+
+ Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+ assert d1 == d2
+ }
+
+ void testDatesFactoryWithDefaultMs() {
+ Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,0)
+ Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+ assert d1 == d2
+ }
+
+ void testDatesFactoryEnforceDefaultMs() {
+ Date d1 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59,1)
+ Date d2 = Dates.toDate(TimeZone.getTimeZone("GMT"),2015,06,07,23,55,59)
+
+ assert d1 != d2
+ }
+}
[6/7] groovy git commit: GROOVY-8379: Rework groovy-json
FastStringUtils (closes #667)
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java
deleted file mode 100644
index 871cf13..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharacterSource.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Richard Hightower
- */
-public interface CharacterSource {
-
- /**
- * Skip white space.
- */
- void skipWhiteSpace();
-
- /**
- * returns the next character moving the file pointer or index to the next location.
- */
- int nextChar();
-
- /**
- * returns the current character without changing the IO pointer or index.
- */
- int currentChar();
-
- /**
- * Checks to see if there is a next character.
- */
- boolean hasChar();
-
- /**
- * Useful for finding constants in a string like true, false, etc.
- */
- boolean consumeIfMatch(char[] match);
-
- /**
- * This is mostly for debugging and testing.
- */
- int location();
-
- /**
- * Combines the operations of nextChar and hasChar.
- * Characters is -1 if not found which signifies end of file.
- * This might be preferable to avoid two method calls.
- */
- int safeNextChar();
-
- /**
- * Used to find strings and their ilk
- * Finds the next non-escaped char
- *
- * @param ch character to find
- * @param esc escape character to avoid next char if escaped
- * @return list of chars until this is found.
- */
- char[] findNextChar(int ch, int esc);
-
- boolean hadEscape();
-
- /**
- * Reads a number from the character source.
- */
- char[] readNumber();
-
- String errorDetails(String message);
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
deleted file mode 100644
index a5146b0..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-/**
- * @author Rick Hightower
- */
-public class Chr {
-
- public static char[] array(final char... array) {
- return array;
- }
-
- public static char[] chars(final String array) {
- return array.toCharArray();
- }
-
- public static boolean in(char value, char[] array) {
- for (char currentValue : array) {
- if (currentValue == value) {
- return true;
- }
- }
- return false;
- }
-
- public static boolean in(int value, char[] array) {
- for (int currentValue : array) {
- if (currentValue == value) {
- return true;
- }
- }
- return false;
- }
-
- public static boolean in(char value, int offset, char[] array) {
- for (int index = offset; index < array.length; index++) {
- char currentValue = array[index];
- if (currentValue == value) {
- return true;
- }
- }
- return false;
- }
-
- public static boolean in(char value, int offset, int end, char[] array) {
- for (int index = offset; index < end; index++) {
- char currentValue = array[index];
- if (currentValue == value) {
- return true;
- }
- }
- return false;
- }
-
- public static char[] grow(char[] array, final int size) {
- char[] newArray = new char[array.length + size];
- arraycopy(array, 0, newArray, 0, array.length);
- return newArray;
- }
-
- public static char[] grow(char[] array) {
- char[] newArray = new char[array.length * 2];
- arraycopy(array, 0, newArray, 0, array.length);
- return newArray;
- }
-
- public static char[] copy(char[] array) {
- char[] newArray = new char[array.length];
- arraycopy(array, 0, newArray, 0, array.length);
- return newArray;
- }
-
- public static char[] copy(char[] array, int offset, int length) {
- char[] newArray = new char[length];
- arraycopy(array, offset, newArray, 0, length);
- return newArray;
- }
-
- public static char[] add(char[] array, char v) {
- char[] newArray = new char[array.length + 1];
- arraycopy(array, 0, newArray, 0, array.length);
- newArray[array.length] = v;
- return newArray;
- }
-
- public static char[] add(char[] array, String str) {
- return add(array, str.toCharArray());
- }
-
- public static char[] add(char[] array, StringBuilder stringBuilder) {
- return add(array, getCharsFromStringBuilder(stringBuilder));
- }
-
- public static char[] add(char[] array, char[] array2) {
- char[] newArray = new char[array.length + array2.length];
- arraycopy(array, 0, newArray, 0, array.length);
- arraycopy(array2, 0, newArray, array.length, array2.length);
- return newArray;
- }
-
- /* End universal methods. */
-
- private static char[] getCharsFromStringBuilder(StringBuilder sbuf) {
- final int length = sbuf.length();
- char[] array2 = new char[length];
- sbuf.getChars(0, length, array2, 0);
- return array2;
- }
-
- public static char[] lpad(final char[] in, final int size, char pad) {
- if (in.length >= size) {
- return in;
- }
-
- int delta = size - in.length;
- int index = 0;
- char[] newArray = new char[size];
-
- for (; index < delta; index++) {
- newArray[index] = pad;
- }
-
- for (int index2 = 0; index2 < in.length; index++, index2++) {
- newArray[index] = in[index2];
- }
-
- return newArray;
- }
-
- public static boolean contains(char[] chars, char c, int start, final int length) {
- final int to = length + start;
- for (int index = start; index < to; index++) {
- char ch = chars[index];
- if (ch == c) {
- return true;
- }
- }
- return false;
- }
-
- public static void _idx(char[] buffer, int location, byte[] chars) {
- int index2 = 0;
- int endLocation = (location + chars.length);
- for (int index = location; index < endLocation; index++, index2++) {
- buffer[index] = (char) chars[index2];
- }
- }
-
- public static void _idx(final char[] array, int startIndex, char[] input) {
- try {
- arraycopy(input, 0, array, startIndex, input.length);
- } catch (Exception ex) {
- Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
- array.length, startIndex, input.length), ex);
- }
- }
-
- private static void arraycopy(final char[] src, final int srcPos, final char[] dest, final int destPos, final int length) {
- System.arraycopy(src, srcPos, dest, destPos, length);
- }
-
- public static void _idx(final char[] array, int startIndex, char[] input, final int inputLength) {
- try {
- arraycopy(input, 0, array, startIndex, inputLength);
- } catch (Exception ex) {
- Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
- array.length, startIndex, input.length), ex);
- }
- }
-
- public static void _idx(char[] buffer, int location, byte[] chars, int start, int end) {
- int index2 = start;
- int endLocation = (location + (end - start));
- for (int index = location; index < endLocation; index++, index2++) {
- buffer[index] = (char) chars[index2];
- }
- }
-
- public static char[] add(char[]... strings) {
- int length = 0;
- for (char[] str : strings) {
- if (str == null) {
- continue;
- }
- length += str.length;
- }
- CharBuf builder = CharBuf.createExact(length);
- for (char[] str : strings) {
- if (str == null) {
- continue;
- }
- builder.add(str);
- }
- return builder.toCharArray();
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
deleted file mode 100644
index 5a07c6b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.TimeZone;
-
-/**
- * @author Rick Hightower
- */
-public class Dates {
-
- private static TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("UTC");
-
- public static long utc(long time) {
- Calendar calendar = Calendar.getInstance();
- calendar.setTimeInMillis(time);
- calendar.setTimeZone(UTC_TIME_ZONE);
- return calendar.getTime().getTime();
- }
-
- private static Date internalDate(TimeZone tz, int year, int month, int day, int hour,
- int minute, int second, int miliseconds) {
-
- Calendar calendar = Calendar.getInstance();
-
- calendar.set(Calendar.YEAR, year);
- calendar.set(Calendar.MONTH, month - 1);
- calendar.set(Calendar.DAY_OF_MONTH, day);
- calendar.set(Calendar.HOUR_OF_DAY, hour);
- calendar.set(Calendar.MINUTE, minute);
- calendar.set(Calendar.SECOND, second);
- calendar.set(Calendar.MILLISECOND, miliseconds);
-
- calendar.setTimeZone(tz);
-
- return calendar.getTime();
- }
-
- public static Date toDate(TimeZone tz, int year, int month, int day,
- int hour, int minute, int second) {
- return internalDate(tz, year, month, day, hour, minute, second, 0);
- }
-
- public static Date toDate(TimeZone tz, int year, int month, int day,
- int hour, int minute, int second, int miliseconds) {
- return internalDate(tz, year, month, day, hour, minute, second, miliseconds);
- }
-
- static final int SHORT_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30Z".length();
- static final int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length();
- public static final int JSON_TIME_LENGTH = "2013-12-14T01:55:33.412Z".length();
-
- public static Date fromISO8601(char[] charArray, int from, int to) {
- try {
- if (isISO8601(charArray, from, to)) {
- int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
- int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
- int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
- int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
-
- int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
-
- int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
- TimeZone tz = null;
-
- if (charArray[from + 19] == 'Z') {
- tz = TimeZone.getTimeZone("GMT");
- } else {
- String tzStr = "GMT" + String.valueOf(charArray, from + 19, 6);
- tz = TimeZone.getTimeZone(tzStr);
- }
- return toDate(tz, year, month, day, hour, minute, second);
- } else {
- return null;
- }
- } catch (Exception ex) {
- return null;
- }
- }
-
- public static Date fromJsonDate(char[] charArray, int from, int to) {
- try {
- if (isJsonDate(charArray, from, to)) {
- int year = CharScanner.parseIntFromTo(charArray, from, from + 4);
- int month = CharScanner.parseIntFromTo(charArray, from + 5, from + 7);
- int day = CharScanner.parseIntFromTo(charArray, from + 8, from + 10);
- int hour = CharScanner.parseIntFromTo(charArray, from + 11, from + 13);
-
- int minute = CharScanner.parseIntFromTo(charArray, from + 14, from + 16);
-
- int second = CharScanner.parseIntFromTo(charArray, from + 17, from + 19);
-
- int miliseconds = CharScanner.parseIntFromTo(charArray, from + 20, from + 23);
-
- TimeZone tz = TimeZone.getTimeZone("GMT");
-
- return toDate(tz, year, month, day, hour, minute, second, miliseconds);
- } else {
- return null;
- }
- } catch (Exception ex) {
- return null;
- }
- }
-
- public static boolean isISO8601(char[] charArray, int start, int to) {
- boolean valid = true;
- final int length = to - start;
-
- if (length == SHORT_ISO_8601_TIME_LENGTH) {
- valid &= (charArray[start + 19] == 'Z');
- } else if (length == LONG_ISO_8601_TIME_LENGTH) {
- valid &= (charArray[start + 19] == '-' || charArray[start + 19] == '+');
- valid &= (charArray[start + 22] == ':');
- } else {
- return false;
- }
-
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
- // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0
-
- valid &= (charArray[start + 4] == '-') &&
- (charArray[start + 7] == '-') &&
- (charArray[start + 10] == 'T') &&
- (charArray[start + 13] == ':') &&
- (charArray[start + 16] == ':');
-
- return valid;
- }
-
- public static boolean isISO8601QuickCheck(char[] charArray, int start, int to) {
- final int length = to - start;
-
- try {
- return length == JSON_TIME_LENGTH || length == LONG_ISO_8601_TIME_LENGTH
- || length == SHORT_ISO_8601_TIME_LENGTH || (length >= 17 && (charArray[start + 16] == ':'));
-
- } catch (Exception ex) {
- ex.printStackTrace();
- return false;
- }
- }
-
- public static boolean isJsonDate(char[] charArray, int start, int to) {
- boolean valid = true;
- final int length = to - start;
-
- if (length != JSON_TIME_LENGTH) {
- return false;
- }
-
- valid &= (charArray[start + 19] == '.' || charArray[start + 19] == '+');
-
- if (!valid) {
- return false;
- }
-
- valid &= (charArray[start + 4] == '-') &&
- (charArray[start + 7] == '-') &&
- (charArray[start + 10] == 'T') &&
- (charArray[start + 13] == ':') &&
- (charArray[start + 16] == ':');
-
- return valid;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
deleted file mode 100644
index 6617031..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.util.Collections;
-
-/**
- * @author Rick Hightower
- */
-public class Exceptions {
-
- public static boolean die() {
- throw new JsonInternalException("died");
- }
-
- public static boolean die(String message) {
- throw new JsonInternalException(message);
- }
-
- public static <T> T die(Class<T> clazz, String message) {
- throw new JsonInternalException(message);
- }
-
- public static void handle(java.lang.Exception e) {
- throw new JsonInternalException(e);
- }
-
- public static <T> T handle(Class<T> clazz, java.lang.Exception e) {
- if (e instanceof JsonInternalException) {
- throw (JsonInternalException) e;
- }
- throw new JsonInternalException(e);
- }
-
- public static <T> T handle(Class<T> clazz, String message, Throwable e) {
- throw new JsonInternalException(message, e);
- }
-
- public static void handle(String message, Throwable e) {
- throw new JsonInternalException(message, e);
- }
-
- public static class JsonInternalException extends JsonException {
-
- public JsonInternalException(String message) {
- super(message);
- }
-
- public JsonInternalException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public JsonInternalException(Throwable cause) {
- super("Wrapped Exception", cause);
- }
-
- public void printStackTrace(PrintStream s) {
- s.println(this.getMessage());
- if (getCause() != null) {
- s.println("This Exception was wrapped, the original exception\n" +
- "stack trace is:\n");
- getCause().printStackTrace(s);
- } else {
- super.printStackTrace(s);
- }
- }
-
- public String getMessage() {
- return super.getMessage() + (getCause() == null ? "" :
- getCauseMessage());
- }
-
- private String getCauseMessage() {
- return "\n CAUSE " + getCause().getClass().getName() + " :: " +
- getCause().getMessage();
- }
-
- public String getLocalizedMessage() {
- return this.getMessage();
- }
-
- public StackTraceElement[] getStackTrace() {
- if (getCause() != null) {
- return getCause().getStackTrace();
- } else {
- return super.getStackTrace();
- }
- }
-
- public Throwable getCause() {
- return super.getCause();
- }
-
- public void printStackTrace(PrintWriter s) {
- s.println(this.getMessage());
-
- if (getCause() != null) {
- s.println("This Exception was wrapped, the original exception\n" +
- "stack trace is:\n");
- getCause().printStackTrace(s);
- } else {
- super.printStackTrace(s);
- }
- }
-
- public void printStackTrace() {
- System.err.println(this.getMessage());
-
- if (getCause() != null) {
- System.err.println("This Exception was wrapped, the original exception\n" +
- "stack trace is:\n");
- getCause().printStackTrace();
- } else {
- super.printStackTrace();
- }
- }
- }
-
- public static String toString(Exception ex) {
- CharBuf buffer = CharBuf.create(255);
- buffer.addLine(ex.getLocalizedMessage());
-
- final StackTraceElement[] stackTrace = ex.getStackTrace();
- for (StackTraceElement element : stackTrace) {
- buffer.add(element.getClassName());
- sputs(buffer, "class", element.getClassName(),
- "method", element.getMethodName(), "line", element.getLineNumber());
- }
-
- return buffer.toString();
- }
-
- public static String sputs(CharBuf buf, Object... messages) {
- int index = 0;
- for (Object message : messages) {
- if (index != 0) {
- buf.add(' ');
- }
- index++;
-
- if (message == null) {
- buf.add("<NULL>");
- } else if (message.getClass().isArray()) {
- buf.add(Collections.singletonList(message).toString());
- } else {
- buf.add(message.toString());
- }
- }
- buf.add('\n');
-
- return buf.toString();
- }
-
- public static String sputs(Object... messages) {
- CharBuf buf = CharBuf.create(100);
- return sputs(buf, messages);
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
deleted file mode 100644
index 9986a1b..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import sun.misc.Unsafe;
-
-import java.lang.reflect.Field;
-
-/**
- * Internal class for fast processing of Strings during JSON parsing
- */
-public class FastStringUtils {
-
- public static final Unsafe UNSAFE;
- public static final long STRING_VALUE_FIELD_OFFSET;
- public static final long STRING_OFFSET_FIELD_OFFSET;
- public static final long STRING_COUNT_FIELD_OFFSET;
- public static final boolean ENABLED;
-
- private static final boolean WRITE_TO_FINAL_FIELDS = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.write.to.final.fields", "false"));
- private static final boolean DISABLE = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.disable", "false"));
-
- private static Unsafe loadUnsafe() {
- try {
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- return (Unsafe) unsafeField.get(null);
-
- } catch (Exception e) {
- return null;
- }
- }
-
- static {
- UNSAFE = DISABLE ? null : loadUnsafe();
- ENABLED = UNSAFE != null;
- }
-
- private static long getFieldOffset(String fieldName) {
- if (ENABLED) {
- try {
- return UNSAFE.objectFieldOffset(String.class.getDeclaredField(fieldName));
- } catch (NoSuchFieldException e) {
- // field undefined
- }
- }
- return -1L;
- }
-
- static {
- STRING_VALUE_FIELD_OFFSET = getFieldOffset("value");
- STRING_OFFSET_FIELD_OFFSET = getFieldOffset("offset");
- STRING_COUNT_FIELD_OFFSET = getFieldOffset("count");
- }
-
- protected enum StringImplementation {
- /**
- * JDK 7 drops offset and count so there is special handling for later version of JDK 7.
- */
- DIRECT_CHARS {
- @Override
- public char[] toCharArray(String string) {
- return (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
- }
-
- @Override
- public String noCopyStringFromChars(char[] chars) {
- if (WRITE_TO_FINAL_FIELDS) {
- String string = new String();
- UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
- return string;
- } else {
- return new String(chars);
- }
- }
- },
- /**
- * JDK 4 and JDK 5 have offset and count fields.
- */
- OFFSET {
- @Override
- public char[] toCharArray(String string) {
- char[] value = (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
- int offset = UNSAFE.getInt(string, STRING_OFFSET_FIELD_OFFSET);
- int count = UNSAFE.getInt(string, STRING_COUNT_FIELD_OFFSET);
- if (offset == 0 && count == value.length) {
- // no need to copy
- return value;
- } else {
- return string.toCharArray();
- }
- }
-
- @Override
- public String noCopyStringFromChars(char[] chars) {
- if (WRITE_TO_FINAL_FIELDS) {
- String string = new String();
- UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
- UNSAFE.putInt(string, STRING_COUNT_FIELD_OFFSET, chars.length);
- return string;
- } else {
- return new String(chars);
- }
- }
- },
- UNKNOWN {
- @Override
- public char[] toCharArray(String string) {
- return string.toCharArray();
- }
-
- @Override
- public String noCopyStringFromChars(char[] chars) {
- return new String(chars);
- }
- };
-
- public abstract char[] toCharArray(String string);
-
- public abstract String noCopyStringFromChars(char[] chars);
- }
-
- public static StringImplementation STRING_IMPLEMENTATION = computeStringImplementation();
-
- private static StringImplementation computeStringImplementation() {
- if (STRING_VALUE_FIELD_OFFSET != -1L) {
- if (STRING_OFFSET_FIELD_OFFSET != -1L && STRING_COUNT_FIELD_OFFSET != -1L) {
- return StringImplementation.OFFSET;
- } else if (STRING_OFFSET_FIELD_OFFSET == -1L && STRING_COUNT_FIELD_OFFSET == -1L && valueFieldIsCharArray()) {
- return StringImplementation.DIRECT_CHARS;
- } else {
- // JDK 9
- // TODO: GROOVY-7716 workaround - find way to optimize JDK9 String (or rethink need for Unsafe usage)
- return StringImplementation.UNKNOWN;
- }
- } else {
- return StringImplementation.UNKNOWN;
- }
- }
-
- /**
- * JDK9 Compat Strings enhancement changed the internal representation of the value field from a char[]
- * to a byte[] (see http://openjdk.java.net/jeps/254).
- *
- * @return true if internal String value field is a char[], otherwise false
- */
- private static boolean valueFieldIsCharArray() {
- Object o = UNSAFE.getObject("", STRING_VALUE_FIELD_OFFSET);
- return (o instanceof char[]);
- }
-
- /**
- * @param string string to grab array from.
- * @return char array from string
- */
- public static char[] toCharArray(final String string) {
- return STRING_IMPLEMENTATION.toCharArray(string);
- }
-
- /**
- * @param charSequence to grab array from.
- * @return char array from char sequence
- */
- public static char[] toCharArray(final CharSequence charSequence) {
- return toCharArray(charSequence.toString());
- }
-
- /**
- * @param chars to shove array into.
- * @return new string with chars copied into it
- */
- public static String noCopyStringFromChars(final char[] chars) {
- return STRING_IMPLEMENTATION.noCopyStringFromChars(chars);
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
deleted file mode 100644
index 4c2847f..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-
-/**
- * @author Rick Hightower
- */
-public class IO {
-
- private static final int EOF = -1;
-
- private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
-
- public static CharBuf read(Reader input, CharBuf charBuf, final int bufSize) {
- if (charBuf == null) {
- charBuf = CharBuf.create(bufSize);
- } else {
- charBuf.readForRecycle();
- }
-
- try {
- char[] buffer = charBuf.toCharArray();
- int size = input.read(buffer);
- if (size != -1) {
- charBuf._len(size);
- }
- if (size < 0) {
- return charBuf;
- }
-
- copy(input, charBuf);
- } catch (IOException e) {
- Exceptions.handle(e);
- } finally {
- try {
- input.close();
- } catch (IOException e) {
- Exceptions.handle(e);
- }
- }
-
- return charBuf;
- }
-
- public static int copy(Reader input, Writer output) {
- long count = copyLarge(input, output);
- if (count > Integer.MAX_VALUE) {
- return -1;
- }
- return (int) count;
- }
-
- public static long copyLarge(Reader reader, Writer writer) {
- return copyLarge(reader, writer, new char[DEFAULT_BUFFER_SIZE]);
- }
-
- public static long copyLarge(Reader reader, Writer writer, char[] buffer) {
- long count = 0;
- int n;
-
- try {
- while (EOF != (n = reader.read(buffer))) {
- writer.write(buffer, 0, n);
- count += n;
- }
- } catch (IOException e) {
- Exceptions.handle(e);
- }
- return count;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
deleted file mode 100644
index a2dfb1e..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This works in index overlay mode or chop mode.
- * Chop mode reduces possibility of memory leak but causes a few more buffer copies as it chops up the buffer.
- *
- * @author Rick Hightower
- */
-public class JsonFastParser extends JsonParserCharArray {
-
- private final boolean useValues;
- private final boolean chop;
- private final boolean lazyChop;
- private final boolean checkDates;
-
- public JsonFastParser() {
- this(true);
- }
-
- public JsonFastParser(boolean useValues) {
- this(useValues, false);
- }
-
- public JsonFastParser(boolean useValues, boolean chop) {
- this(useValues, chop, !chop);
- }
-
- public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop) {
- this(useValues, chop, lazyChop, true);
- }
-
- public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop, boolean checkDates) {
- this.useValues = useValues;
- this.chop = chop;
- this.lazyChop = lazyChop;
- this.checkDates = checkDates;
- }
-
- protected final Value decodeJsonObjectLazyFinalParse() {
- char[] array = charArray;
-
- if (__currentChar == '{')
- __index++;
-
- ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
- Value value = new ValueContainer(map);
-
- objectLoop:
- for (; __index < array.length; __index++) {
- skipWhiteSpace();
- switch (__currentChar) {
-
- case '"':
- Value key = decodeStringOverlay();
- skipWhiteSpace();
-
- if (__currentChar != ':') {
-
- complain("expecting current character to be " + charDescription(__currentChar) + "\n");
- }
- __index++;
-
- Value item = decodeValueOverlay();
-
- skipWhiteSpace();
-
- MapItemValue miv = new MapItemValue(key, item);
-
- map.add(miv);
- }
-
- switch (__currentChar) {
- case '}':
- __index++;
- break objectLoop;
-
- case ',':
- continue;
-
- default:
-
- complain(
- "expecting '}' or ',' but got current char " + charDescription(__currentChar));
- }
- }
- return value;
- }
-
- protected Value decodeValue() {
- return decodeValueOverlay();
- }
-
- private Value decodeValueOverlay() {
- skipWhiteSpace();
-
- switch (__currentChar) {
- case '"':
- return decodeStringOverlay();
-
- case '{':
- return decodeJsonObjectLazyFinalParse();
-
- case 't':
- return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
-
- case 'f':
- return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
-
- case 'n':
- return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
-
- case '[':
- return decodeJsonArrayOverlay();
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- return decodeNumberOverlay(false);
-
- case '-':
- return decodeNumberOverlay(true);
-
- default:
- complain("Unable to determine the " +
- "current character, it is not a string, number, array, or object");
- return null;
- }
- }
-
- private Value decodeNumberOverlay(final boolean minus) {
- char[] array = charArray;
-
- final int startIndex = __index;
- int index = __index;
- char currentChar;
- boolean doubleFloat = false;
- boolean foundDot = false;
- boolean foundSign = false;
- boolean foundExp = false;
-
- if (minus && index + 1 < array.length) {
- index++;
- }
-
- while (true) {
- currentChar = array[index];
- if (isNumberDigit(currentChar)) {
- //noop
- } else if (currentChar <= 32) { //white
- break;
- } else if (isDelimiter(currentChar)) {
- break;
- } else if (isDecimalChar(currentChar)) {
- switch (currentChar) {
- case DECIMAL_POINT:
- if (foundDot || foundExp) { complain("unexpected character " + currentChar); }
- foundDot = true;
- break;
- case LETTER_E:
- case LETTER_BIG_E:
- if (foundExp) { complain("unexpected character " + currentChar); }
- foundExp = true;
- break;
- case MINUS:
- case PLUS:
- if (foundSign || !foundExp) { complain("unexpected character " + currentChar); }
- if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
- complain("unexpected character " + currentChar);
- }
- foundSign = true;
- break;
- }
- doubleFloat = true;
- } else {
- complain("unexpected character " + currentChar);
- }
- index++;
- if (index >= array.length) break;
- }
-
- // Handle the case where the exponential number ends without the actual exponent
- if (foundExp) {
- char prevChar = array[index - 1];
- if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
- complain("unexpected character " + currentChar);
- }
- }
-
- __index = index;
- __currentChar = currentChar;
-
- Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
-
- return new NumberValue(chop, type, startIndex, __index, this.charArray);
- }
-
- private Value decodeStringOverlay() {
- char[] array = charArray;
- int index = __index;
- char currentChar = charArray[index];
-
- if (index < array.length && currentChar == '"') {
- index++;
- }
-
- final int startIndex = index;
-
- boolean encoded = hasEscapeChar(array, index, indexHolder);
- index = indexHolder[0];
-
- if (encoded) {
- index = findEndQuote(array, index);
- }
-
- Value value = new CharSequenceValue(chop, Type.STRING, startIndex, index, array, encoded, checkDates);
-
- if (index < array.length) {
- index++;
- }
-
- __index = index;
- return value;
- }
-
- private Value decodeJsonArrayOverlay() {
- char[] array = charArray;
- if (__currentChar == '[') {
- __index++;
- }
-
- skipWhiteSpace();
-
- /* the list might be empty */
- if (__currentChar == ']') {
- __index++;
- return new ValueContainer(new ArrayList());
- }
-
- List<Object> list;
-
- if (useValues) {
- list = new ArrayList<Object>();
- } else {
- list = new ValueList(lazyChop);
- }
-
- Value value = new ValueContainer(list);
-
- Value item;
- char c;
- int lastIndex;
- boolean foundEnd = false;
-
- arrayLoop:
- for (; __index < array.length; __index++) {
- item = decodeValueOverlay();
-
- list.add(item);
- c = currentChar();
- switch (c) {
- case ',':
- continue;
- case ']':
- __index++;
- foundEnd = true;
- break arrayLoop;
- }
-
- lastIndex = __index;
- skipWhiteSpace();
- c = currentChar();
-
- switch (c) {
- case ',':
- continue;
- case ']':
- if (__index == lastIndex) {
- complain("missing ]");
- }
- foundEnd = true;
- __index++;
- break arrayLoop;
- default:
- complain(
- String.format("expecting a ',' or a ']', " +
- " but got \nthe current character of %s " +
- " on array size of %s \n", charDescription(__currentChar), list.size())
- );
- }
- }
-
- if (!foundEnd) {
- complain("Did not find end of Json Array");
- }
- return value;
- }
-
- protected final Object decodeFromChars(char[] cs) {
- Value value = ((Value) super.decodeFromChars(cs));
- if (value.isContainer()) {
- return value.toValue();
- } else {
- return value;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
deleted file mode 100644
index 85120d1..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Converts an input JSON String into Java objects works with String or char array
- * as input. Produces an Object which can be any of the basic JSON types mapped
- * to Java.
- * <p/>
- *
- * @author Rick Hightower
- */
-public class JsonParserCharArray extends BaseJsonParser {
-
- protected char[] charArray;
- protected int __index;
- protected char __currentChar;
-
- private int lastIndex;
-
- protected Object decodeFromChars(char[] cs) {
- __index = 0;
- charArray = cs;
- lastIndex = cs.length - 1;
- return decodeValue();
- }
-
- protected final boolean hasMore() {
- return __index < lastIndex;
- }
-
- protected final boolean hasCurrent() {
- return __index <= lastIndex;
- }
-
- protected final void skipWhiteSpace() {
- int ix = __index;
-
- if (hasCurrent()) {
- this.__currentChar = this.charArray[ix];
- }
-
- if (__currentChar <= 32) {
- ix = skipWhiteSpaceFast(this.charArray, ix);
- this.__currentChar = this.charArray[ix];
- __index = ix;
- }
- }
-
- protected final char nextChar() {
- try {
- if (hasMore()) {
- __index++;
- return __currentChar = charArray[__index];
- } else {
- // TODO move unicode 0 to separate file to avoid doc parsing issues
- return '\u0000';
- }
- } catch (Exception ex) {
- throw new JsonException(exceptionDetails("unable to advance character"), ex);
- }
- }
-
- protected String exceptionDetails(String message) {
- return CharScanner.errorDetails(message, charArray, __index, __currentChar);
- }
-
- private static int skipWhiteSpaceFast(char[] array, int index) {
- char c;
- for (; index < array.length; index++) {
- c = array[index];
- if (c > 32) {
- return index;
- }
- }
- return index - 1;
- }
-
- protected final Object decodeJsonObject() {
- if (__currentChar == '{') {
- __index++;
- }
-
- LazyMap map = new LazyMap();
-
- for (; __index < this.charArray.length; __index++) {
- skipWhiteSpace();
-
- if (__currentChar == '"') {
- String key = decodeString();
-
- if (internKeys) {
- String keyPrime = internedKeysCache.get(key);
- if (keyPrime == null) {
- key = key.intern();
- internedKeysCache.put(key, key);
- } else {
- key = keyPrime;
- }
- }
-
- skipWhiteSpace();
-
- if (__currentChar != ':') {
- complain("expecting current character to be " + charDescription(__currentChar) + "\n");
- }
- __index++;
-
- skipWhiteSpace();
-
- Object value = decodeValueInternal();
-
- skipWhiteSpace();
- map.put(key, value);
- }
-
- if (__currentChar == '}') {
- __index++;
- break;
- } else if (__currentChar == ',') {
- continue;
- } else {
- complain(
- "expecting '}' or ',' but got current char " + charDescription(__currentChar));
- }
- }
-
- return map;
- }
-
- protected final void complain(String complaint) {
- throw new JsonException(exceptionDetails(complaint));
- }
-
- protected Object decodeValue() {
- return decodeValueInternal();
- }
-
- private Object decodeValueInternal() {
- Object value = null;
- skipWhiteSpace();
-
- switch (__currentChar) {
- case '"':
- value = decodeString();
- break;
-
- case 't':
- value = decodeTrue();
- break;
-
- case 'f':
- value = decodeFalse();
- break;
-
- case 'n':
- value = decodeNull();
- break;
-
- case '[':
- value = decodeJsonArray();
- break;
-
- case '{':
- value = decodeJsonObject();
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- value = decodeNumber();
- break;
- case '-':
- value = decodeNumber();
- break;
-
- default:
- throw new JsonException(exceptionDetails("Unable to determine the " +
- "current character, it is not a string, number, array, or object"));
- }
-
- return value;
- }
-
- int[] endIndex = new int[1];
-
- private Object decodeNumber() {
- Number num = CharScanner.parseJsonNumber(charArray, __index, charArray.length, endIndex);
- __index = endIndex[0];
-
- return num;
- }
-
- protected static final char[] NULL = Chr.chars("null");
-
- protected final Object decodeNull() {
- if (__index + NULL.length <= charArray.length) {
- if (charArray[__index] == 'n' &&
- charArray[++__index] == 'u' &&
- charArray[++__index] == 'l' &&
- charArray[++__index] == 'l') {
- __index++;
- return null;
- }
- }
- throw new JsonException(exceptionDetails("null not parse properly"));
- }
-
- protected static final char[] TRUE = Chr.chars("true");
-
- protected final boolean decodeTrue() {
- if (__index + TRUE.length <= charArray.length) {
- if (charArray[__index] == 't' &&
- charArray[++__index] == 'r' &&
- charArray[++__index] == 'u' &&
- charArray[++__index] == 'e') {
-
- __index++;
- return true;
- }
- }
-
- throw new JsonException(exceptionDetails("true not parsed properly"));
- }
-
- protected static char[] FALSE = Chr.chars("false");
-
- protected final boolean decodeFalse() {
- if (__index + FALSE.length <= charArray.length) {
- if (charArray[__index] == 'f' &&
- charArray[++__index] == 'a' &&
- charArray[++__index] == 'l' &&
- charArray[++__index] == 's' &&
- charArray[++__index] == 'e') {
- __index++;
- return false;
- }
- }
- throw new JsonException(exceptionDetails("false not parsed properly"));
- }
-
- private CharBuf builder = CharBuf.create(20);
-
- private String decodeString() {
- char[] array = charArray;
- int index = __index;
- char currentChar = array[index];
-
- if (index < array.length && currentChar == '"') {
- index++;
- }
-
- final int startIndex = index;
-
- boolean encoded = hasEscapeChar(array, index, indexHolder);
- index = indexHolder[0];
-
- String value = null;
- if (encoded) {
- index = findEndQuote(array, index);
- value = builder.decodeJsonString(array, startIndex, index).toString();
- builder.recycle();
- } else {
- value = new String(array, startIndex, (index - startIndex));
- }
-
- if (index < charArray.length) {
- index++;
- }
- __index = index;
- return value;
- }
-
- protected final List decodeJsonArray() {
- ArrayList<Object> list = null;
-
- boolean foundEnd = false;
- char[] charArray = this.charArray;
-
- try {
- if (__currentChar == '[') {
- __index++;
- }
-
- int lastIndex;
-
- skipWhiteSpace();
-
- /* the list might be empty */
- if (__currentChar == ']') {
- __index++;
- return new ArrayList();
- }
-
- list = new ArrayList();
-
- while (this.hasMore()) {
- Object arrayItem = decodeValueInternal();
-
- list.add(arrayItem);
-
- char c = charArray[__index];
-
- if (c == ',') {
- __index++;
- continue;
- } else if (c == ']') {
- __index++;
- foundEnd = true;
- break;
- }
-
- lastIndex = __index;
- skipWhiteSpace();
-
- c = charArray[__index];
-
- if (c == ',') {
- __index++;
- continue;
- } else if (c == ']' && lastIndex != __index) {
- __index++;
- foundEnd = true;
- break;
- } else {
- String charString = charDescription(c);
-
- complain(
- String.format("expecting a ',' or a ']', " +
- " but got \nthe current character of %s " +
- " on array index of %s \n", charString, list.size())
- );
- }
- }
- } catch (Exception ex) {
- if (ex instanceof JsonException) {
- throw (JsonException) ex;
- }
- throw new JsonException(exceptionDetails("issue parsing JSON array"), ex);
- }
- if (!foundEnd) {
- complain("Did not find end of Json Array");
- }
- return list;
- }
-
- protected final char currentChar() {
- if (__index > lastIndex) {
- return 0;
- } else {
- return charArray[__index];
- }
- }
-
- public Object parse(char[] chars) {
- return this.decodeFromChars(chars);
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
deleted file mode 100644
index cde56b9..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Richard Hightower
- */
-public class JsonParserLax extends JsonParserCharArray {
-
- private final boolean useValues;
- private final boolean chop;
- private final boolean lazyChop;
- private final boolean defaultCheckDates;
-
- public JsonParserLax() {
- this(true);
- }
-
- public JsonParserLax(boolean useValues) {
- this(useValues, false);
- }
-
- public JsonParserLax(boolean useValues, boolean chop) {
- this(useValues, chop, !chop);
- }
-
- public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop) {
- this(useValues, chop, lazyChop, true);
- }
-
- public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop, boolean defaultCheckDates) {
- this.useValues = useValues;
- this.chop = chop;
- this.lazyChop = lazyChop;
- this.defaultCheckDates = defaultCheckDates;
- }
-
- private Value decodeJsonObjectLax() {
- if (__currentChar == '{')
- this.nextChar();
-
- ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
- Value value = new ValueContainer(map);
-
- skipWhiteSpace();
- int startIndexOfKey = __index;
- Value key;
- MapItemValue miv;
- Value item;
-
- done:
- for (; __index < this.charArray.length; __index++) {
- skipWhiteSpace();
-
- switch (__currentChar) {
- case ':':
- char startChar = charArray[startIndexOfKey];
- if (startChar == ',') {
- startIndexOfKey++;
- }
-
- key = extractLaxString(startIndexOfKey, __index - 1, false, false);
- __index++; //skip :
-
- item = decodeValueInternal();
- skipWhiteSpace();
-
- miv = new MapItemValue(key, item);
-
- map.add(miv);
-
- startIndexOfKey = __index;
- if (__currentChar == '}') {
- __index++;
- break done;
- }
-
- break;
-
- case '\'':
- key = decodeStringSingle();
-
- //puts ("key with quote", key);
-
- skipWhiteSpace();
-
- if (__currentChar != ':') {
- complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
- }
- __index++;
- item = decodeValueInternal();
-
- //puts ("key", "#" + key + "#", value);
-
- skipWhiteSpace();
-
- miv = new MapItemValue(key, item);
-
- map.add(miv);
- startIndexOfKey = __index;
- if (__currentChar == '}') {
- __index++;
- break done;
- }
-
- break;
-
- case '"':
- key = decodeStringDouble();
-
- //puts ("key with quote", key);
-
- skipWhiteSpace();
-
- if (__currentChar != ':') {
- complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
- }
- __index++;
- item = decodeValueInternal();
-
- //puts ("key", "#" + key + "#", value);
-
- skipWhiteSpace();
-
- miv = new MapItemValue(key, item);
-
- map.add(miv);
- startIndexOfKey = __index;
- if (__currentChar == '}') {
- __index++;
- break done;
- }
-
- break;
- }
-
- switch (__currentChar) {
- case '}':
- __index++;
- break done;
-
- case '/': /* */ //
- handleComment();
- startIndexOfKey = __index;
- break;
-
- case '#':
- handleBashComment();
- startIndexOfKey = __index;
- break;
- }
- }
-
- return value;
- }
-
- private Value extractLaxString(int startIndexOfKey, int end, boolean encoded, boolean checkDate) {
- char startChar;
- startIndexLookup:
- for (; startIndexOfKey < __index && startIndexOfKey < charArray.length; startIndexOfKey++) {
- startChar = charArray[startIndexOfKey];
- switch (startChar) {
- case ' ':
- case '\n':
- case '\t':
- continue;
-
- default:
- break startIndexLookup;
- }
- }
-
- char endChar;
- int endIndex = end >= charArray.length ? charArray.length - 1 : end;
- endIndexLookup:
- for (; endIndex >= startIndexOfKey + 1 && endIndex >= 0; endIndex--) {
- endChar = charArray[endIndex];
- switch (endChar) {
- case ' ':
- case '\n':
- case '\t':
- case '}':
- continue;
- case ',':
- case ';':
- continue;
-
- case ']':
- continue;
- default:
- break endIndexLookup;
- }
- }
- return new CharSequenceValue(chop, Type.STRING, startIndexOfKey, endIndex + 1, this.charArray, encoded, checkDate);
- }
-
- protected final Object decodeValue() {
- return this.decodeValueInternal();
- }
-
- private Value decodeValueInternal() {
- Value value = null;
-
- for (; __index < charArray.length; __index++) {
- skipWhiteSpace();
-
- switch (__currentChar) {
- case '\n':
- break;
-
- case '\r':
- break;
-
- case ' ':
- break;
-
- case '\t':
- break;
-
- case '\b':
- break;
-
- case '\f':
- break;
-
- case '/': /* */ //
- handleComment();
- break;
-
- case '#':
- handleBashComment();
- break;
-
- case '"':
- value = decodeStringDouble();
- break;
-
- case '\'':
- value = decodeStringSingle();
- break;
-
- case 't':
- if (isTrue()) {
- return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
- } else {
- value = decodeStringLax();
- }
- break;
-
- case 'f':
- if (isFalse()) {
- return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
- } else {
- value = decodeStringLax();
- }
- break;
-
- case 'n':
- if (isNull()) {
- return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
- } else {
- value = decodeStringLax();
- }
-
- break;
-
- case '[':
- value = decodeJsonArrayLax();
- break;
-
- case '{':
- value = decodeJsonObjectLax();
- break;
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- return decodeNumberLax(false);
-
- case '-':
- return decodeNumberLax(true);
-
- default:
- value = decodeStringLax();
- }
-
- if (value != null) {
- return value;
- }
- }
-
- return null;
- }
-
- private void handleBashComment() {
- for (; __index < charArray.length; __index++) {
- __currentChar = charArray[__index];
-
- if (__currentChar == '\n') {
- __index++;
- return;
- }
- }
- }
-
- private void handleComment() {
- if (hasMore()) {
- __index++;
- __currentChar = charArray[__index];
-
- switch (__currentChar) {
- case '*':
- for (; __index < charArray.length; __index++) {
- __currentChar = charArray[__index];
-
- if (__currentChar == '*') {
- if (hasMore()) {
- __index++;
- __currentChar = charArray[__index];
- if (__currentChar == '/') {
- if (hasMore()) {
- __index++;
- return;
- }
- }
- } else {
- complain("missing close of comment");
- }
- }
- }
-
- case '/':
- for (; __index < charArray.length; __index++) {
- __currentChar = charArray[__index];
-
- if (__currentChar == '\n') {
- if (hasMore()) {
- __index++;
- return;
- } else {
- return;
- }
- }
- }
- }
- }
- }
-
- /**
- * Decodes a number from a JSON value. If at any point it is determined that
- * the value is not a valid number the value is treated as a {@code String}.
- *
- * @param minus indicate whether the number is negative
- * @return a number, or {@code String} if not a valid number
- */
- protected final Value decodeNumberLax(boolean minus) {
- char[] array = charArray;
-
- final int startIndex = __index;
- int index = __index;
- char currentChar;
- boolean doubleFloat = false;
- boolean foundDot = false;
- boolean foundSign = false;
- boolean foundExp = false;
-
- if (minus && index + 1 < array.length) {
- index++;
- }
-
- while (true) {
- currentChar = array[index];
- if (isNumberDigit(currentChar)) {
- //noop
- } else if (currentChar <= 32) { //white
- break;
- } else if (isDelimiter(currentChar)) {
- break;
- } else if (isDecimalChar(currentChar)) {
- switch (currentChar) {
- case DECIMAL_POINT:
- if (foundDot || foundExp) { return decodeStringLax(); }
- foundDot = true;
- break;
- case LETTER_E:
- case LETTER_BIG_E:
- if (foundExp) { return decodeStringLax(); }
- foundExp = true;
- break;
- case MINUS:
- case PLUS:
- if (foundSign || !foundExp) { return decodeStringLax(); }
- if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
- return decodeStringLax();
- }
- foundSign = true;
- break;
- }
- doubleFloat = true;
- } else {
- return decodeStringLax();
- }
- index++;
- if (index >= array.length) break;
- }
-
- // Handle the case where the exponential number ends without the actual exponent
- if (foundExp) {
- char prevChar = array[index - 1];
- if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
- return decodeStringLax();
- }
- }
-
- __index = index;
- __currentChar = currentChar;
-
- Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
-
- return new NumberValue(chop, type, startIndex, __index, this.charArray);
- }
-
- private boolean isNull() {
- if (__index + NULL.length <= charArray.length) {
- if (charArray[__index] == 'n' &&
- charArray[__index + 1] == 'u' &&
- charArray[__index + 2] == 'l' &&
- charArray[__index + 3] == 'l') {
- return true;
- }
- }
- return false;
- }
-
- private boolean isTrue() {
- if (__index + TRUE.length <= charArray.length) {
- if (charArray[__index] == 't' &&
- charArray[__index + 1] == 'r' &&
- charArray[__index + 2] == 'u' &&
- charArray[__index + 3] == 'e') {
- return true;
-
- }
- }
- return false;
- }
-
- private boolean isFalse() {
- if (__index + FALSE.length <= charArray.length) {
- if (charArray[__index] == 'f' &&
- charArray[__index + 1] == 'a' &&
- charArray[__index + 2] == 'l' &&
- charArray[__index + 3] == 's' &&
- charArray[__index + 4] == 'e') {
- return true;
- }
- }
- return false;
- }
-
- private Value decodeStringLax() {
- int index = __index;
- char currentChar = charArray[__index];
- final int startIndex = __index;
- boolean encoded = false;
- char[] charArray = this.charArray;
-
- for (; index < charArray.length; index++) {
- currentChar = charArray[index];
-
- if (isDelimiter(currentChar)) break;
- else if (currentChar == '\\') break;
- }
-
- Value value = this.extractLaxString(startIndex, index, encoded, defaultCheckDates);
-
- __index = index;
- return value;
- }
-
- private Value decodeStringDouble() {
- __currentChar = charArray[__index];
-
- if (__index < charArray.length && __currentChar == '"') {
- __index++;
- }
-
- final int startIndex = __index;
-
- boolean escape = false;
- boolean encoded = false;
-
- done:
- for (; __index < this.charArray.length; __index++) {
- __currentChar = charArray[__index];
- switch (__currentChar) {
-
- case '"':
- if (!escape) {
- break done;
- } else {
- escape = false;
- continue;
- }
-
- case '\\':
- escape = !escape;
- encoded = true;
- continue;
- }
- escape = false;
- }
-
- Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, defaultCheckDates);
-
- if (__index < charArray.length) {
- __index++;
- }
-
- return value;
- }
-
- private Value decodeStringSingle() {
- __currentChar = charArray[__index];
-
- if (__index < charArray.length && __currentChar == '\'') {
- __index++;
- }
-
- final int startIndex = __index;
-
- boolean escape = false;
- boolean encoded = false;
- int minusCount = 0;
- int colonCount = 0;
-
- done:
- for (; __index < this.charArray.length; __index++) {
- __currentChar = charArray[__index];
- switch (__currentChar) {
- case '\'':
- if (!escape) {
- break done;
- } else {
- escape = false;
- continue;
- }
-
- case '\\':
- encoded = true;
- escape = true;
- continue;
-
- case '-':
- minusCount++;
- break;
-
- case ':':
- colonCount++;
- break;
- }
- escape = false;
- }
-
- boolean checkDates = defaultCheckDates && !encoded && minusCount >= 2 && colonCount >= 2;
-
- Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, checkDates);
-
- if (__index < charArray.length) {
- __index++;
- }
-
- return value;
- }
-
- private Value decodeJsonArrayLax() {
- if (__currentChar == '[') {
- __index++;
- }
-
- skipWhiteSpace();
-
- if (__currentChar == ']') {
- __index++;
- return new ValueContainer(new ArrayList());
- }
-
- List<Object> list;
-
- if (useValues) {
- list = new ArrayList<Object>();
- } else {
- list = new ValueList(lazyChop);
- }
-
- Value value = new ValueContainer(list);
-
- do {
- skipWhiteSpace();
-
- Object arrayItem = decodeValueInternal();
-
- list.add(arrayItem);
-
- boolean doStop = false;
-
- done:
- do { // Find either next array element or end of array while ignoring comments
- skipWhiteSpace();
-
- switch (__currentChar) {
- case '/':
- handleComment();
- continue;
- case '#':
- handleBashComment();
- continue;
- case ',':
- __index++;
- break done;
- case ']':
- __index++;
- doStop = true;
- break done;
- default:
- String charString = charDescription(__currentChar);
-
- complain(
- String.format("expecting a ',' or a ']', " +
- " but got \nthe current character of %s " +
- " on array index of %s \n", charString, list.size())
- );
- }
- } while (this.hasMore());
-
- if (doStop) break;
-
- } while (this.hasMore());
-
- return value;
- }
-
- protected final Object decodeFromChars(char[] cs) {
- Value value = ((Value) super.decodeFromChars(cs));
- if (value.isContainer()) {
- return value.toValue();
- } else {
- return value;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
deleted file mode 100644
index 47a470f..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy.json.internal;
-
-import groovy.json.JsonException;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Converts an input JSON String into Java objects works with String or char array
- * as input. Produces an Object which can be any of the basic JSON types mapped
- * to Java.
- * <p/>
- *
- * @author Rick Hightower
- */
-public class JsonParserUsingCharacterSource extends BaseJsonParser {
-
- private CharacterSource characterSource;
-
- protected String exceptionDetails(String message) {
- return characterSource.errorDetails(message);
- }
-
- protected final Object decodeJsonObject() {
- LazyMap map = new LazyMap();
-
- try {
- CharacterSource characterSource = this.characterSource;
-
- if (characterSource.currentChar() == '{') {
- characterSource.nextChar();
- }
-
- while (characterSource.hasChar()) {
- characterSource.skipWhiteSpace();
-
- if (characterSource.currentChar() == DOUBLE_QUOTE) {
- String key = decodeString();
- //puts ("key", key);
-
- if (internKeys) {
- String keyPrime = internedKeysCache.get(key);
- if (keyPrime == null) {
- key = key.intern();
- internedKeysCache.put(key, key);
- } else {
- key = keyPrime;
- }
- }
-
- characterSource.skipWhiteSpace();
- if (characterSource.currentChar() != COLON) {
- complain("expecting current character to be : but was " + charDescription(characterSource.currentChar()) + "\n");
- }
-
- characterSource.nextChar();
- characterSource.skipWhiteSpace();
-
- Object value = decodeValue();
-
- //puts ("key", key, "value", value);
-
- characterSource.skipWhiteSpace();
-
- map.put(key, value);
- }
-
- int ch = characterSource.currentChar();
- if (ch == '}') {
- characterSource.nextChar();
- break;
- } else if (ch == ',') {
- characterSource.nextChar();
- continue;
- } else {
- complain(
- "expecting '}' or ',' but got current char " + charDescription(ch));
- }
- }
- } catch (Exception ex) {
- throw new JsonException(exceptionDetails("Unable to parse JSON object"), ex);
- }
-
- return map;
- }
-
- protected final void complain(String complaint) {
- throw new JsonException(exceptionDetails(complaint));
- }
-
- private Object decodeValue() {
- CharacterSource characterSource = this.characterSource;
- Object value = null;
- characterSource.skipWhiteSpace();
-
- switch (characterSource.currentChar()) {
- case '"':
- value = decodeString();
- break;
-
- case 't':
- value = decodeTrue();
- break;
-
- case 'f':
- value = decodeFalse();
- break;
-
- case 'n':
- value = decodeNull();
- break;
-
- case '[':
- value = decodeJsonArray();
- break;
-
- case '{':
- value = decodeJsonObject();
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- value = decodeNumber(false);
- break;
-
- case '-':
- value = decodeNumber(true);
- break;
-
- default:
- throw new JsonException(exceptionDetails("Unable to determine the " +
- "current character, it is not a string, number, array, or object"));
- }
-
- return value;
- }
-
- private Object decodeNumber(boolean negative) {
- char[] chars = characterSource.readNumber();
- Object value = null;
-
- if (CharScanner.hasDecimalChar(chars, negative)) {
- value = CharScanner.parseBigDecimal(chars);
- } else if (CharScanner.isInteger(chars)) {
- value = CharScanner.parseInt(chars);
- } else if (CharScanner.isLong(chars)) {
- value = CharScanner.parseLong(chars);
- }
-
- return value;
- }
-
- protected static final char[] NULL = Chr.chars("null");
-
- protected final Object decodeNull() {
- if (!characterSource.consumeIfMatch(NULL)) {
- throw new JsonException(exceptionDetails("null not parse properly"));
- }
- return null;
- }
-
- protected static final char[] TRUE = Chr.chars("true");
-
- protected final boolean decodeTrue() {
- if (characterSource.consumeIfMatch(TRUE)) {
- return true;
- } else {
- throw new JsonException(exceptionDetails("true not parsed properly"));
- }
- }
-
- protected static char[] FALSE = Chr.chars("false");
-
- protected final boolean decodeFalse() {
- if (characterSource.consumeIfMatch(FALSE)) {
- return false;
- } else {
- throw new JsonException(exceptionDetails("false not parsed properly"));
- }
- }
-
- private CharBuf builder = CharBuf.create(20);
-
- private String decodeString() {
- CharacterSource characterSource = this.characterSource;
-
- characterSource.nextChar();
-
- char[] chars = characterSource.findNextChar('"', '\\');
-
- String value = null;
- if (characterSource.hadEscape()) {
- value = builder.decodeJsonString(chars).toString();
- builder.recycle();
- } else {
- value = new String(chars);
- }
-
- return value;
- }
-
- protected final List decodeJsonArray() {
- ArrayList<Object> list = null;
-
- boolean foundEnd = false;
- try {
- CharacterSource characterSource = this.characterSource;
-
- if (this.characterSource.currentChar() == '[') {
- characterSource.nextChar();
- }
-
- characterSource.skipWhiteSpace();
-
- /* the list might be empty */
- if (this.characterSource.currentChar() == ']') {
- characterSource.nextChar();
- return new ArrayList();
- }
-
- list = new ArrayList();
-
- do {
- characterSource.skipWhiteSpace();
-
- Object arrayItem = decodeValue();
-
- list.add(arrayItem);
-
- characterSource.skipWhiteSpace();
-
- int c = characterSource.currentChar();
-
- if (c == COMMA) {
- characterSource.nextChar();
- continue;
- } else if (c == CLOSED_BRACKET) {
- foundEnd = true;
- characterSource.nextChar();
- break;
- } else {
- String charString = charDescription(c);
-
- complain(
- String.format("expecting a ',' or a ']', " +
- " but got \nthe current character of %s " +
- " on array index of %s \n", charString, list.size())
- );
-
- }
- } while (characterSource.hasChar());
- } catch (Exception ex) {
- throw new JsonException(exceptionDetails("Unexpected issue"), ex);
- }
-
- if (!foundEnd) {
- throw new JsonException(exceptionDetails("Could not find end of JSON array"));
- }
- return list;
- }
-
- public Object parse(Reader reader) {
- characterSource = new ReaderCharacterSource(reader);
- return this.decodeValue();
- }
-
- public Object parse(char[] chars) {
- return parse(new StringReader(new String(chars)));
- }
-}
[3/7] groovy git commit: GROOVY-8379: Rework groovy-json
FastStringUtils (closes #667)
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java
new file mode 100644
index 0000000..4cc219c
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonFastParser.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This works in index overlay mode or chop mode.
+ * Chop mode reduces possibility of memory leak but causes a few more buffer copies as it chops up the buffer.
+ *
+ * @author Rick Hightower
+ */
+public class JsonFastParser extends JsonParserCharArray {
+
+ private final boolean useValues;
+ private final boolean chop;
+ private final boolean lazyChop;
+ private final boolean checkDates;
+
+ public JsonFastParser() {
+ this(true);
+ }
+
+ public JsonFastParser(boolean useValues) {
+ this(useValues, false);
+ }
+
+ public JsonFastParser(boolean useValues, boolean chop) {
+ this(useValues, chop, !chop);
+ }
+
+ public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop) {
+ this(useValues, chop, lazyChop, true);
+ }
+
+ public JsonFastParser(boolean useValues, boolean chop, boolean lazyChop, boolean checkDates) {
+ this.useValues = useValues;
+ this.chop = chop;
+ this.lazyChop = lazyChop;
+ this.checkDates = checkDates;
+ }
+
+ protected final Value decodeJsonObjectLazyFinalParse() {
+ char[] array = charArray;
+
+ if (__currentChar == '{')
+ __index++;
+
+ ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
+ Value value = new ValueContainer(map);
+
+ objectLoop:
+ for (; __index < array.length; __index++) {
+ skipWhiteSpace();
+ switch (__currentChar) {
+
+ case '"':
+ Value key = decodeStringOverlay();
+ skipWhiteSpace();
+
+ if (__currentChar != ':') {
+
+ complain("expecting current character to be " + charDescription(__currentChar) + "\n");
+ }
+ __index++;
+
+ Value item = decodeValueOverlay();
+
+ skipWhiteSpace();
+
+ MapItemValue miv = new MapItemValue(key, item);
+
+ map.add(miv);
+ }
+
+ switch (__currentChar) {
+ case '}':
+ __index++;
+ break objectLoop;
+
+ case ',':
+ continue;
+
+ default:
+
+ complain(
+ "expecting '}' or ',' but got current char " + charDescription(__currentChar));
+ }
+ }
+ return value;
+ }
+
+ protected Value decodeValue() {
+ return decodeValueOverlay();
+ }
+
+ private Value decodeValueOverlay() {
+ skipWhiteSpace();
+
+ switch (__currentChar) {
+ case '"':
+ return decodeStringOverlay();
+
+ case '{':
+ return decodeJsonObjectLazyFinalParse();
+
+ case 't':
+ return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
+
+ case 'f':
+ return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
+
+ case 'n':
+ return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
+
+ case '[':
+ return decodeJsonArrayOverlay();
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ return decodeNumberOverlay(false);
+
+ case '-':
+ return decodeNumberOverlay(true);
+
+ default:
+ complain("Unable to determine the " +
+ "current character, it is not a string, number, array, or object");
+ return null;
+ }
+ }
+
+ private Value decodeNumberOverlay(final boolean minus) {
+ char[] array = charArray;
+
+ final int startIndex = __index;
+ int index = __index;
+ char currentChar;
+ boolean doubleFloat = false;
+ boolean foundDot = false;
+ boolean foundSign = false;
+ boolean foundExp = false;
+
+ if (minus && index + 1 < array.length) {
+ index++;
+ }
+
+ while (true) {
+ currentChar = array[index];
+ if (isNumberDigit(currentChar)) {
+ //noop
+ } else if (currentChar <= 32) { //white
+ break;
+ } else if (isDelimiter(currentChar)) {
+ break;
+ } else if (isDecimalChar(currentChar)) {
+ switch (currentChar) {
+ case DECIMAL_POINT:
+ if (foundDot || foundExp) { complain("unexpected character " + currentChar); }
+ foundDot = true;
+ break;
+ case LETTER_E:
+ case LETTER_BIG_E:
+ if (foundExp) { complain("unexpected character " + currentChar); }
+ foundExp = true;
+ break;
+ case MINUS:
+ case PLUS:
+ if (foundSign || !foundExp) { complain("unexpected character " + currentChar); }
+ if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
+ complain("unexpected character " + currentChar);
+ }
+ foundSign = true;
+ break;
+ }
+ doubleFloat = true;
+ } else {
+ complain("unexpected character " + currentChar);
+ }
+ index++;
+ if (index >= array.length) break;
+ }
+
+ // Handle the case where the exponential number ends without the actual exponent
+ if (foundExp) {
+ char prevChar = array[index - 1];
+ if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
+ complain("unexpected character " + currentChar);
+ }
+ }
+
+ __index = index;
+ __currentChar = currentChar;
+
+ Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
+
+ return new NumberValue(chop, type, startIndex, __index, this.charArray);
+ }
+
+ private Value decodeStringOverlay() {
+ char[] array = charArray;
+ int index = __index;
+ char currentChar = charArray[index];
+
+ if (index < array.length && currentChar == '"') {
+ index++;
+ }
+
+ final int startIndex = index;
+
+ boolean encoded = hasEscapeChar(array, index, indexHolder);
+ index = indexHolder[0];
+
+ if (encoded) {
+ index = findEndQuote(array, index);
+ }
+
+ Value value = new CharSequenceValue(chop, Type.STRING, startIndex, index, array, encoded, checkDates);
+
+ if (index < array.length) {
+ index++;
+ }
+
+ __index = index;
+ return value;
+ }
+
+ private Value decodeJsonArrayOverlay() {
+ char[] array = charArray;
+ if (__currentChar == '[') {
+ __index++;
+ }
+
+ skipWhiteSpace();
+
+ /* the list might be empty */
+ if (__currentChar == ']') {
+ __index++;
+ return new ValueContainer(new ArrayList());
+ }
+
+ List<Object> list;
+
+ if (useValues) {
+ list = new ArrayList<Object>();
+ } else {
+ list = new ValueList(lazyChop);
+ }
+
+ Value value = new ValueContainer(list);
+
+ Value item;
+ char c;
+ int lastIndex;
+ boolean foundEnd = false;
+
+ arrayLoop:
+ for (; __index < array.length; __index++) {
+ item = decodeValueOverlay();
+
+ list.add(item);
+ c = currentChar();
+ switch (c) {
+ case ',':
+ continue;
+ case ']':
+ __index++;
+ foundEnd = true;
+ break arrayLoop;
+ }
+
+ lastIndex = __index;
+ skipWhiteSpace();
+ c = currentChar();
+
+ switch (c) {
+ case ',':
+ continue;
+ case ']':
+ if (__index == lastIndex) {
+ complain("missing ]");
+ }
+ foundEnd = true;
+ __index++;
+ break arrayLoop;
+ default:
+ complain(
+ String.format("expecting a ',' or a ']', " +
+ " but got \nthe current character of %s " +
+ " on array size of %s \n", charDescription(__currentChar), list.size())
+ );
+ }
+ }
+
+ if (!foundEnd) {
+ complain("Did not find end of Json Array");
+ }
+ return value;
+ }
+
+ protected final Object decodeFromChars(char[] cs) {
+ Value value = ((Value) super.decodeFromChars(cs));
+ if (value.isContainer()) {
+ return value.toValue();
+ } else {
+ return value;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java
new file mode 100644
index 0000000..6fb6f4c
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserCharArray.java
@@ -0,0 +1,386 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Converts an input JSON String into Java objects works with String or char array
+ * as input. Produces an Object which can be any of the basic JSON types mapped
+ * to Java.
+ * <p/>
+ *
+ * @author Rick Hightower
+ */
+public class JsonParserCharArray extends BaseJsonParser {
+
+ protected char[] charArray;
+ protected int __index;
+ protected char __currentChar;
+
+ private int lastIndex;
+
+ protected Object decodeFromChars(char[] cs) {
+ __index = 0;
+ charArray = cs;
+ lastIndex = cs.length - 1;
+ return decodeValue();
+ }
+
+ protected final boolean hasMore() {
+ return __index < lastIndex;
+ }
+
+ protected final boolean hasCurrent() {
+ return __index <= lastIndex;
+ }
+
+ protected final void skipWhiteSpace() {
+ int ix = __index;
+
+ if (hasCurrent()) {
+ this.__currentChar = this.charArray[ix];
+ }
+
+ if (__currentChar <= 32) {
+ ix = skipWhiteSpaceFast(this.charArray, ix);
+ this.__currentChar = this.charArray[ix];
+ __index = ix;
+ }
+ }
+
+ protected final char nextChar() {
+ try {
+ if (hasMore()) {
+ __index++;
+ return __currentChar = charArray[__index];
+ } else {
+ // TODO move unicode 0 to separate file to avoid doc parsing issues
+ return '\u0000';
+ }
+ } catch (Exception ex) {
+ throw new JsonException(exceptionDetails("unable to advance character"), ex);
+ }
+ }
+
+ protected String exceptionDetails(String message) {
+ return CharScanner.errorDetails(message, charArray, __index, __currentChar);
+ }
+
+ private static int skipWhiteSpaceFast(char[] array, int index) {
+ char c;
+ for (; index < array.length; index++) {
+ c = array[index];
+ if (c > 32) {
+ return index;
+ }
+ }
+ return index - 1;
+ }
+
+ protected final Object decodeJsonObject() {
+ if (__currentChar == '{') {
+ __index++;
+ }
+
+ LazyMap map = new LazyMap();
+
+ for (; __index < this.charArray.length; __index++) {
+ skipWhiteSpace();
+
+ if (__currentChar == '"') {
+ String key = decodeString();
+
+ if (internKeys) {
+ String keyPrime = internedKeysCache.get(key);
+ if (keyPrime == null) {
+ key = key.intern();
+ internedKeysCache.put(key, key);
+ } else {
+ key = keyPrime;
+ }
+ }
+
+ skipWhiteSpace();
+
+ if (__currentChar != ':') {
+ complain("expecting current character to be " + charDescription(__currentChar) + "\n");
+ }
+ __index++;
+
+ skipWhiteSpace();
+
+ Object value = decodeValueInternal();
+
+ skipWhiteSpace();
+ map.put(key, value);
+ }
+
+ if (__currentChar == '}') {
+ __index++;
+ break;
+ } else if (__currentChar == ',') {
+ continue;
+ } else {
+ complain(
+ "expecting '}' or ',' but got current char " + charDescription(__currentChar));
+ }
+ }
+
+ return map;
+ }
+
+ protected final void complain(String complaint) {
+ throw new JsonException(exceptionDetails(complaint));
+ }
+
+ protected Object decodeValue() {
+ return decodeValueInternal();
+ }
+
+ private Object decodeValueInternal() {
+ Object value = null;
+ skipWhiteSpace();
+
+ switch (__currentChar) {
+ case '"':
+ value = decodeString();
+ break;
+
+ case 't':
+ value = decodeTrue();
+ break;
+
+ case 'f':
+ value = decodeFalse();
+ break;
+
+ case 'n':
+ value = decodeNull();
+ break;
+
+ case '[':
+ value = decodeJsonArray();
+ break;
+
+ case '{':
+ value = decodeJsonObject();
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ value = decodeNumber();
+ break;
+ case '-':
+ value = decodeNumber();
+ break;
+
+ default:
+ throw new JsonException(exceptionDetails("Unable to determine the " +
+ "current character, it is not a string, number, array, or object"));
+ }
+
+ return value;
+ }
+
+ int[] endIndex = new int[1];
+
+ private Object decodeNumber() {
+ Number num = CharScanner.parseJsonNumber(charArray, __index, charArray.length, endIndex);
+ __index = endIndex[0];
+
+ return num;
+ }
+
+ protected static final char[] NULL = Chr.chars("null");
+
+ protected final Object decodeNull() {
+ if (__index + NULL.length <= charArray.length) {
+ if (charArray[__index] == 'n' &&
+ charArray[++__index] == 'u' &&
+ charArray[++__index] == 'l' &&
+ charArray[++__index] == 'l') {
+ __index++;
+ return null;
+ }
+ }
+ throw new JsonException(exceptionDetails("null not parse properly"));
+ }
+
+ protected static final char[] TRUE = Chr.chars("true");
+
+ protected final boolean decodeTrue() {
+ if (__index + TRUE.length <= charArray.length) {
+ if (charArray[__index] == 't' &&
+ charArray[++__index] == 'r' &&
+ charArray[++__index] == 'u' &&
+ charArray[++__index] == 'e') {
+
+ __index++;
+ return true;
+ }
+ }
+
+ throw new JsonException(exceptionDetails("true not parsed properly"));
+ }
+
+ protected static char[] FALSE = Chr.chars("false");
+
+ protected final boolean decodeFalse() {
+ if (__index + FALSE.length <= charArray.length) {
+ if (charArray[__index] == 'f' &&
+ charArray[++__index] == 'a' &&
+ charArray[++__index] == 'l' &&
+ charArray[++__index] == 's' &&
+ charArray[++__index] == 'e') {
+ __index++;
+ return false;
+ }
+ }
+ throw new JsonException(exceptionDetails("false not parsed properly"));
+ }
+
+ private CharBuf builder = CharBuf.create(20);
+
+ private String decodeString() {
+ char[] array = charArray;
+ int index = __index;
+ char currentChar = array[index];
+
+ if (index < array.length && currentChar == '"') {
+ index++;
+ }
+
+ final int startIndex = index;
+
+ boolean encoded = hasEscapeChar(array, index, indexHolder);
+ index = indexHolder[0];
+
+ String value = null;
+ if (encoded) {
+ index = findEndQuote(array, index);
+ value = builder.decodeJsonString(array, startIndex, index).toString();
+ builder.recycle();
+ } else {
+ value = new String(array, startIndex, (index - startIndex));
+ }
+
+ if (index < charArray.length) {
+ index++;
+ }
+ __index = index;
+ return value;
+ }
+
+ protected final List decodeJsonArray() {
+ ArrayList<Object> list = null;
+
+ boolean foundEnd = false;
+ char[] charArray = this.charArray;
+
+ try {
+ if (__currentChar == '[') {
+ __index++;
+ }
+
+ int lastIndex;
+
+ skipWhiteSpace();
+
+ /* the list might be empty */
+ if (__currentChar == ']') {
+ __index++;
+ return new ArrayList();
+ }
+
+ list = new ArrayList();
+
+ while (this.hasMore()) {
+ Object arrayItem = decodeValueInternal();
+
+ list.add(arrayItem);
+
+ char c = charArray[__index];
+
+ if (c == ',') {
+ __index++;
+ continue;
+ } else if (c == ']') {
+ __index++;
+ foundEnd = true;
+ break;
+ }
+
+ lastIndex = __index;
+ skipWhiteSpace();
+
+ c = charArray[__index];
+
+ if (c == ',') {
+ __index++;
+ continue;
+ } else if (c == ']' && lastIndex != __index) {
+ __index++;
+ foundEnd = true;
+ break;
+ } else {
+ String charString = charDescription(c);
+
+ complain(
+ String.format("expecting a ',' or a ']', " +
+ " but got \nthe current character of %s " +
+ " on array index of %s \n", charString, list.size())
+ );
+ }
+ }
+ } catch (Exception ex) {
+ if (ex instanceof JsonException) {
+ throw (JsonException) ex;
+ }
+ throw new JsonException(exceptionDetails("issue parsing JSON array"), ex);
+ }
+ if (!foundEnd) {
+ complain("Did not find end of Json Array");
+ }
+ return list;
+ }
+
+ protected final char currentChar() {
+ if (__index > lastIndex) {
+ return 0;
+ } else {
+ return charArray[__index];
+ }
+ }
+
+ public Object parse(char[] chars) {
+ return this.decodeFromChars(chars);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java
new file mode 100644
index 0000000..89e1fa4
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserLax.java
@@ -0,0 +1,677 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Richard Hightower
+ */
+public class JsonParserLax extends JsonParserCharArray {
+
+ private final boolean useValues;
+ private final boolean chop;
+ private final boolean lazyChop;
+ private final boolean defaultCheckDates;
+
+ public JsonParserLax() {
+ this(true);
+ }
+
+ public JsonParserLax(boolean useValues) {
+ this(useValues, false);
+ }
+
+ public JsonParserLax(boolean useValues, boolean chop) {
+ this(useValues, chop, !chop);
+ }
+
+ public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop) {
+ this(useValues, chop, lazyChop, true);
+ }
+
+ public JsonParserLax(boolean useValues, boolean chop, boolean lazyChop, boolean defaultCheckDates) {
+ this.useValues = useValues;
+ this.chop = chop;
+ this.lazyChop = lazyChop;
+ this.defaultCheckDates = defaultCheckDates;
+ }
+
+ private Value decodeJsonObjectLax() {
+ if (__currentChar == '{')
+ this.nextChar();
+
+ ValueMap map = useValues ? new ValueMapImpl() : new LazyValueMap(lazyChop);
+ Value value = new ValueContainer(map);
+
+ skipWhiteSpace();
+ int startIndexOfKey = __index;
+ Value key;
+ MapItemValue miv;
+ Value item;
+
+ done:
+ for (; __index < this.charArray.length; __index++) {
+ skipWhiteSpace();
+
+ switch (__currentChar) {
+ case ':':
+ char startChar = charArray[startIndexOfKey];
+ if (startChar == ',') {
+ startIndexOfKey++;
+ }
+
+ key = extractLaxString(startIndexOfKey, __index - 1, false, false);
+ __index++; //skip :
+
+ item = decodeValueInternal();
+ skipWhiteSpace();
+
+ miv = new MapItemValue(key, item);
+
+ map.add(miv);
+
+ startIndexOfKey = __index;
+ if (__currentChar == '}') {
+ __index++;
+ break done;
+ }
+
+ break;
+
+ case '\'':
+ key = decodeStringSingle();
+
+ //puts ("key with quote", key);
+
+ skipWhiteSpace();
+
+ if (__currentChar != ':') {
+ complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
+ }
+ __index++;
+ item = decodeValueInternal();
+
+ //puts ("key", "#" + key + "#", value);
+
+ skipWhiteSpace();
+
+ miv = new MapItemValue(key, item);
+
+ map.add(miv);
+ startIndexOfKey = __index;
+ if (__currentChar == '}') {
+ __index++;
+ break done;
+ }
+
+ break;
+
+ case '"':
+ key = decodeStringDouble();
+
+ //puts ("key with quote", key);
+
+ skipWhiteSpace();
+
+ if (__currentChar != ':') {
+ complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
+ }
+ __index++;
+ item = decodeValueInternal();
+
+ //puts ("key", "#" + key + "#", value);
+
+ skipWhiteSpace();
+
+ miv = new MapItemValue(key, item);
+
+ map.add(miv);
+ startIndexOfKey = __index;
+ if (__currentChar == '}') {
+ __index++;
+ break done;
+ }
+
+ break;
+ }
+
+ switch (__currentChar) {
+ case '}':
+ __index++;
+ break done;
+
+ case '/': /* */ //
+ handleComment();
+ startIndexOfKey = __index;
+ break;
+
+ case '#':
+ handleBashComment();
+ startIndexOfKey = __index;
+ break;
+ }
+ }
+
+ return value;
+ }
+
+ private Value extractLaxString(int startIndexOfKey, int end, boolean encoded, boolean checkDate) {
+ char startChar;
+ startIndexLookup:
+ for (; startIndexOfKey < __index && startIndexOfKey < charArray.length; startIndexOfKey++) {
+ startChar = charArray[startIndexOfKey];
+ switch (startChar) {
+ case ' ':
+ case '\n':
+ case '\t':
+ continue;
+
+ default:
+ break startIndexLookup;
+ }
+ }
+
+ char endChar;
+ int endIndex = end >= charArray.length ? charArray.length - 1 : end;
+ endIndexLookup:
+ for (; endIndex >= startIndexOfKey + 1 && endIndex >= 0; endIndex--) {
+ endChar = charArray[endIndex];
+ switch (endChar) {
+ case ' ':
+ case '\n':
+ case '\t':
+ case '}':
+ continue;
+ case ',':
+ case ';':
+ continue;
+
+ case ']':
+ continue;
+ default:
+ break endIndexLookup;
+ }
+ }
+ return new CharSequenceValue(chop, Type.STRING, startIndexOfKey, endIndex + 1, this.charArray, encoded, checkDate);
+ }
+
+ protected final Object decodeValue() {
+ return this.decodeValueInternal();
+ }
+
+ private Value decodeValueInternal() {
+ Value value = null;
+
+ for (; __index < charArray.length; __index++) {
+ skipWhiteSpace();
+
+ switch (__currentChar) {
+ case '\n':
+ break;
+
+ case '\r':
+ break;
+
+ case ' ':
+ break;
+
+ case '\t':
+ break;
+
+ case '\b':
+ break;
+
+ case '\f':
+ break;
+
+ case '/': /* */ //
+ handleComment();
+ break;
+
+ case '#':
+ handleBashComment();
+ break;
+
+ case '"':
+ value = decodeStringDouble();
+ break;
+
+ case '\'':
+ value = decodeStringSingle();
+ break;
+
+ case 't':
+ if (isTrue()) {
+ return decodeTrue() ? ValueContainer.TRUE : ValueContainer.FALSE;
+ } else {
+ value = decodeStringLax();
+ }
+ break;
+
+ case 'f':
+ if (isFalse()) {
+ return !decodeFalse() ? ValueContainer.FALSE : ValueContainer.TRUE;
+ } else {
+ value = decodeStringLax();
+ }
+ break;
+
+ case 'n':
+ if (isNull()) {
+ return decodeNull() == null ? ValueContainer.NULL : ValueContainer.NULL;
+ } else {
+ value = decodeStringLax();
+ }
+
+ break;
+
+ case '[':
+ value = decodeJsonArrayLax();
+ break;
+
+ case '{':
+ value = decodeJsonObjectLax();
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '0':
+ return decodeNumberLax(false);
+
+ case '-':
+ return decodeNumberLax(true);
+
+ default:
+ value = decodeStringLax();
+ }
+
+ if (value != null) {
+ return value;
+ }
+ }
+
+ return null;
+ }
+
+ private void handleBashComment() {
+ for (; __index < charArray.length; __index++) {
+ __currentChar = charArray[__index];
+
+ if (__currentChar == '\n') {
+ __index++;
+ return;
+ }
+ }
+ }
+
+ private void handleComment() {
+ if (hasMore()) {
+ __index++;
+ __currentChar = charArray[__index];
+
+ switch (__currentChar) {
+ case '*':
+ for (; __index < charArray.length; __index++) {
+ __currentChar = charArray[__index];
+
+ if (__currentChar == '*') {
+ if (hasMore()) {
+ __index++;
+ __currentChar = charArray[__index];
+ if (__currentChar == '/') {
+ if (hasMore()) {
+ __index++;
+ return;
+ }
+ }
+ } else {
+ complain("missing close of comment");
+ }
+ }
+ }
+
+ case '/':
+ for (; __index < charArray.length; __index++) {
+ __currentChar = charArray[__index];
+
+ if (__currentChar == '\n') {
+ if (hasMore()) {
+ __index++;
+ return;
+ } else {
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Decodes a number from a JSON value. If at any point it is determined that
+ * the value is not a valid number the value is treated as a {@code String}.
+ *
+ * @param minus indicate whether the number is negative
+ * @return a number, or {@code String} if not a valid number
+ */
+ protected final Value decodeNumberLax(boolean minus) {
+ char[] array = charArray;
+
+ final int startIndex = __index;
+ int index = __index;
+ char currentChar;
+ boolean doubleFloat = false;
+ boolean foundDot = false;
+ boolean foundSign = false;
+ boolean foundExp = false;
+
+ if (minus && index + 1 < array.length) {
+ index++;
+ }
+
+ while (true) {
+ currentChar = array[index];
+ if (isNumberDigit(currentChar)) {
+ //noop
+ } else if (currentChar <= 32) { //white
+ break;
+ } else if (isDelimiter(currentChar)) {
+ break;
+ } else if (isDecimalChar(currentChar)) {
+ switch (currentChar) {
+ case DECIMAL_POINT:
+ if (foundDot || foundExp) { return decodeStringLax(); }
+ foundDot = true;
+ break;
+ case LETTER_E:
+ case LETTER_BIG_E:
+ if (foundExp) { return decodeStringLax(); }
+ foundExp = true;
+ break;
+ case MINUS:
+ case PLUS:
+ if (foundSign || !foundExp) { return decodeStringLax(); }
+ if (foundExp && array[index - 1] != LETTER_E && array[index - 1] != LETTER_BIG_E) {
+ return decodeStringLax();
+ }
+ foundSign = true;
+ break;
+ }
+ doubleFloat = true;
+ } else {
+ return decodeStringLax();
+ }
+ index++;
+ if (index >= array.length) break;
+ }
+
+ // Handle the case where the exponential number ends without the actual exponent
+ if (foundExp) {
+ char prevChar = array[index - 1];
+ if (prevChar == LETTER_E || prevChar == LETTER_BIG_E || prevChar == MINUS || prevChar == PLUS) {
+ return decodeStringLax();
+ }
+ }
+
+ __index = index;
+ __currentChar = currentChar;
+
+ Type type = doubleFloat ? Type.DOUBLE : Type.INTEGER;
+
+ return new NumberValue(chop, type, startIndex, __index, this.charArray);
+ }
+
+ private boolean isNull() {
+ if (__index + NULL.length <= charArray.length) {
+ if (charArray[__index] == 'n' &&
+ charArray[__index + 1] == 'u' &&
+ charArray[__index + 2] == 'l' &&
+ charArray[__index + 3] == 'l') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isTrue() {
+ if (__index + TRUE.length <= charArray.length) {
+ if (charArray[__index] == 't' &&
+ charArray[__index + 1] == 'r' &&
+ charArray[__index + 2] == 'u' &&
+ charArray[__index + 3] == 'e') {
+ return true;
+
+ }
+ }
+ return false;
+ }
+
+ private boolean isFalse() {
+ if (__index + FALSE.length <= charArray.length) {
+ if (charArray[__index] == 'f' &&
+ charArray[__index + 1] == 'a' &&
+ charArray[__index + 2] == 'l' &&
+ charArray[__index + 3] == 's' &&
+ charArray[__index + 4] == 'e') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private Value decodeStringLax() {
+ int index = __index;
+ char currentChar = charArray[__index];
+ final int startIndex = __index;
+ boolean encoded = false;
+ char[] charArray = this.charArray;
+
+ for (; index < charArray.length; index++) {
+ currentChar = charArray[index];
+
+ if (isDelimiter(currentChar)) break;
+ else if (currentChar == '\\') break;
+ }
+
+ Value value = this.extractLaxString(startIndex, index, encoded, defaultCheckDates);
+
+ __index = index;
+ return value;
+ }
+
+ private Value decodeStringDouble() {
+ __currentChar = charArray[__index];
+
+ if (__index < charArray.length && __currentChar == '"') {
+ __index++;
+ }
+
+ final int startIndex = __index;
+
+ boolean escape = false;
+ boolean encoded = false;
+
+ done:
+ for (; __index < this.charArray.length; __index++) {
+ __currentChar = charArray[__index];
+ switch (__currentChar) {
+
+ case '"':
+ if (!escape) {
+ break done;
+ } else {
+ escape = false;
+ continue;
+ }
+
+ case '\\':
+ escape = !escape;
+ encoded = true;
+ continue;
+ }
+ escape = false;
+ }
+
+ Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, defaultCheckDates);
+
+ if (__index < charArray.length) {
+ __index++;
+ }
+
+ return value;
+ }
+
+ private Value decodeStringSingle() {
+ __currentChar = charArray[__index];
+
+ if (__index < charArray.length && __currentChar == '\'') {
+ __index++;
+ }
+
+ final int startIndex = __index;
+
+ boolean escape = false;
+ boolean encoded = false;
+ int minusCount = 0;
+ int colonCount = 0;
+
+ done:
+ for (; __index < this.charArray.length; __index++) {
+ __currentChar = charArray[__index];
+ switch (__currentChar) {
+ case '\'':
+ if (!escape) {
+ break done;
+ } else {
+ escape = false;
+ continue;
+ }
+
+ case '\\':
+ encoded = true;
+ escape = true;
+ continue;
+
+ case '-':
+ minusCount++;
+ break;
+
+ case ':':
+ colonCount++;
+ break;
+ }
+ escape = false;
+ }
+
+ boolean checkDates = defaultCheckDates && !encoded && minusCount >= 2 && colonCount >= 2;
+
+ Value value = new CharSequenceValue(chop, Type.STRING, startIndex, __index, this.charArray, encoded, checkDates);
+
+ if (__index < charArray.length) {
+ __index++;
+ }
+
+ return value;
+ }
+
+ private Value decodeJsonArrayLax() {
+ if (__currentChar == '[') {
+ __index++;
+ }
+
+ skipWhiteSpace();
+
+ if (__currentChar == ']') {
+ __index++;
+ return new ValueContainer(new ArrayList());
+ }
+
+ List<Object> list;
+
+ if (useValues) {
+ list = new ArrayList<Object>();
+ } else {
+ list = new ValueList(lazyChop);
+ }
+
+ Value value = new ValueContainer(list);
+
+ do {
+ skipWhiteSpace();
+
+ Object arrayItem = decodeValueInternal();
+
+ list.add(arrayItem);
+
+ boolean doStop = false;
+
+ done:
+ do { // Find either next array element or end of array while ignoring comments
+ skipWhiteSpace();
+
+ switch (__currentChar) {
+ case '/':
+ handleComment();
+ continue;
+ case '#':
+ handleBashComment();
+ continue;
+ case ',':
+ __index++;
+ break done;
+ case ']':
+ __index++;
+ doStop = true;
+ break done;
+ default:
+ String charString = charDescription(__currentChar);
+
+ complain(
+ String.format("expecting a ',' or a ']', " +
+ " but got \nthe current character of %s " +
+ " on array index of %s \n", charString, list.size())
+ );
+ }
+ } while (this.hasMore());
+
+ if (doStop) break;
+
+ } while (this.hasMore());
+
+ return value;
+ }
+
+ protected final Object decodeFromChars(char[] cs) {
+ Value value = ((Value) super.decodeFromChars(cs));
+ if (value.isContainer()) {
+ return value.toValue();
+ } else {
+ return value;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java
new file mode 100644
index 0000000..8b7d969
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonParserUsingCharacterSource.java
@@ -0,0 +1,298 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Converts an input JSON String into Java objects works with String or char array
+ * as input. Produces an Object which can be any of the basic JSON types mapped
+ * to Java.
+ * <p/>
+ *
+ * @author Rick Hightower
+ */
+public class JsonParserUsingCharacterSource extends BaseJsonParser {
+
+ private CharacterSource characterSource;
+
+ protected String exceptionDetails(String message) {
+ return characterSource.errorDetails(message);
+ }
+
+ protected final Object decodeJsonObject() {
+ LazyMap map = new LazyMap();
+
+ try {
+ CharacterSource characterSource = this.characterSource;
+
+ if (characterSource.currentChar() == '{') {
+ characterSource.nextChar();
+ }
+
+ while (characterSource.hasChar()) {
+ characterSource.skipWhiteSpace();
+
+ if (characterSource.currentChar() == DOUBLE_QUOTE) {
+ String key = decodeString();
+ //puts ("key", key);
+
+ if (internKeys) {
+ String keyPrime = internedKeysCache.get(key);
+ if (keyPrime == null) {
+ key = key.intern();
+ internedKeysCache.put(key, key);
+ } else {
+ key = keyPrime;
+ }
+ }
+
+ characterSource.skipWhiteSpace();
+ if (characterSource.currentChar() != COLON) {
+ complain("expecting current character to be : but was " + charDescription(characterSource.currentChar()) + "\n");
+ }
+
+ characterSource.nextChar();
+ characterSource.skipWhiteSpace();
+
+ Object value = decodeValue();
+
+ //puts ("key", key, "value", value);
+
+ characterSource.skipWhiteSpace();
+
+ map.put(key, value);
+ }
+
+ int ch = characterSource.currentChar();
+ if (ch == '}') {
+ characterSource.nextChar();
+ break;
+ } else if (ch == ',') {
+ characterSource.nextChar();
+ continue;
+ } else {
+ complain(
+ "expecting '}' or ',' but got current char " + charDescription(ch));
+ }
+ }
+ } catch (Exception ex) {
+ throw new JsonException(exceptionDetails("Unable to parse JSON object"), ex);
+ }
+
+ return map;
+ }
+
+ protected final void complain(String complaint) {
+ throw new JsonException(exceptionDetails(complaint));
+ }
+
+ private Object decodeValue() {
+ CharacterSource characterSource = this.characterSource;
+ Object value = null;
+ characterSource.skipWhiteSpace();
+
+ switch (characterSource.currentChar()) {
+ case '"':
+ value = decodeString();
+ break;
+
+ case 't':
+ value = decodeTrue();
+ break;
+
+ case 'f':
+ value = decodeFalse();
+ break;
+
+ case 'n':
+ value = decodeNull();
+ break;
+
+ case '[':
+ value = decodeJsonArray();
+ break;
+
+ case '{':
+ value = decodeJsonObject();
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ value = decodeNumber(false);
+ break;
+
+ case '-':
+ value = decodeNumber(true);
+ break;
+
+ default:
+ throw new JsonException(exceptionDetails("Unable to determine the " +
+ "current character, it is not a string, number, array, or object"));
+ }
+
+ return value;
+ }
+
+ private Object decodeNumber(boolean negative) {
+ char[] chars = characterSource.readNumber();
+ Object value = null;
+
+ if (CharScanner.hasDecimalChar(chars, negative)) {
+ value = CharScanner.parseBigDecimal(chars);
+ } else if (CharScanner.isInteger(chars)) {
+ value = CharScanner.parseInt(chars);
+ } else if (CharScanner.isLong(chars)) {
+ value = CharScanner.parseLong(chars);
+ }
+
+ return value;
+ }
+
+ protected static final char[] NULL = Chr.chars("null");
+
+ protected final Object decodeNull() {
+ if (!characterSource.consumeIfMatch(NULL)) {
+ throw new JsonException(exceptionDetails("null not parse properly"));
+ }
+ return null;
+ }
+
+ protected static final char[] TRUE = Chr.chars("true");
+
+ protected final boolean decodeTrue() {
+ if (characterSource.consumeIfMatch(TRUE)) {
+ return true;
+ } else {
+ throw new JsonException(exceptionDetails("true not parsed properly"));
+ }
+ }
+
+ protected static char[] FALSE = Chr.chars("false");
+
+ protected final boolean decodeFalse() {
+ if (characterSource.consumeIfMatch(FALSE)) {
+ return false;
+ } else {
+ throw new JsonException(exceptionDetails("false not parsed properly"));
+ }
+ }
+
+ private CharBuf builder = CharBuf.create(20);
+
+ private String decodeString() {
+ CharacterSource characterSource = this.characterSource;
+
+ characterSource.nextChar();
+
+ char[] chars = characterSource.findNextChar('"', '\\');
+
+ String value = null;
+ if (characterSource.hadEscape()) {
+ value = builder.decodeJsonString(chars).toString();
+ builder.recycle();
+ } else {
+ value = new String(chars);
+ }
+
+ return value;
+ }
+
+ protected final List decodeJsonArray() {
+ ArrayList<Object> list = null;
+
+ boolean foundEnd = false;
+ try {
+ CharacterSource characterSource = this.characterSource;
+
+ if (this.characterSource.currentChar() == '[') {
+ characterSource.nextChar();
+ }
+
+ characterSource.skipWhiteSpace();
+
+ /* the list might be empty */
+ if (this.characterSource.currentChar() == ']') {
+ characterSource.nextChar();
+ return new ArrayList();
+ }
+
+ list = new ArrayList();
+
+ do {
+ characterSource.skipWhiteSpace();
+
+ Object arrayItem = decodeValue();
+
+ list.add(arrayItem);
+
+ characterSource.skipWhiteSpace();
+
+ int c = characterSource.currentChar();
+
+ if (c == COMMA) {
+ characterSource.nextChar();
+ continue;
+ } else if (c == CLOSED_BRACKET) {
+ foundEnd = true;
+ characterSource.nextChar();
+ break;
+ } else {
+ String charString = charDescription(c);
+
+ complain(
+ String.format("expecting a ',' or a ']', " +
+ " but got \nthe current character of %s " +
+ " on array index of %s \n", charString, list.size())
+ );
+
+ }
+ } while (characterSource.hasChar());
+ } catch (Exception ex) {
+ throw new JsonException(exceptionDetails("Unexpected issue"), ex);
+ }
+
+ if (!foundEnd) {
+ throw new JsonException(exceptionDetails("Could not find end of JSON array"));
+ }
+ return list;
+ }
+
+ public Object parse(Reader reader) {
+ characterSource = new ReaderCharacterSource(reader);
+ return this.decodeValue();
+ }
+
+ public Object parse(char[] chars) {
+ return parse(new StringReader(new String(chars)));
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java
new file mode 100644
index 0000000..a53c9fa
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/JsonStringDecoder.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+/**
+ * @author Richard Hightower
+ */
+public class JsonStringDecoder {
+
+ public static String decode(char[] chars, int start, int to) {
+ if (!Chr.contains(chars, '\\', start, to - start)) {
+ return new String(chars, start, to - start);
+ }
+ return decodeForSure(chars, start, to);
+ }
+
+ public static String decodeForSure(char[] chars, int start, int to) {
+ CharBuf builder = CharBuf.create(to - start);
+ builder.decodeJsonString(chars, start, to);
+ return builder.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java
new file mode 100644
index 0000000..81da4d3
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyMap.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.lang.reflect.Array;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * This maps only builds once you ask for a key for the first time.
+ * It is designed to not incur the overhead of creating a map unless needed.
+ *
+ * @author Rick Hightower
+ */
+public class LazyMap extends AbstractMap<String, Object> {
+
+ static final String JDK_MAP_ALTHASHING_SYSPROP = System.getProperty("jdk.map.althashing.threshold");
+
+ /* Holds the actual map that will be lazily created. */
+ private Map<String, Object> map;
+ /* The size of the map. */
+ private int size;
+ /* The keys stored in the map. */
+ private String[] keys;
+ /* The values stored in the map. */
+ private Object[] values;
+
+ public LazyMap() {
+ keys = new String[5];
+ values = new Object[5];
+ }
+
+ public LazyMap(int initialSize) {
+ keys = new String[initialSize];
+ values = new Object[initialSize];
+ }
+
+ public Object put(String key, Object value) {
+ if (map == null) {
+ for (int i = 0; i < size; i++) {
+ String curKey = keys[i];
+ if ((key == null && curKey == null)
+ || (key != null && key.equals(curKey))) {
+ Object val = values[i];
+ keys[i] = key;
+ values[i] = value;
+ return val;
+ }
+ }
+ keys[size] = key;
+ values[size] = value;
+ size++;
+ if (size == keys.length) {
+ keys = grow(keys);
+ values = grow(values);
+ }
+ return null;
+ } else {
+ return map.put(key, value);
+ }
+ }
+
+ public Set<Entry<String, Object>> entrySet() {
+ buildIfNeeded();
+ return map.entrySet();
+ }
+
+ public int size() {
+ if (map == null) {
+ return size;
+ } else {
+ return map.size();
+ }
+ }
+
+ public boolean isEmpty() {
+ if (map == null) {
+ return size == 0;
+ } else {
+ return map.isEmpty();
+ }
+ }
+
+ public boolean containsValue(Object value) {
+ buildIfNeeded();
+ return map.containsValue(value);
+ }
+
+ public boolean containsKey(Object key) {
+ buildIfNeeded();
+ return map.containsKey(key);
+ }
+
+ public Object get(Object key) {
+ buildIfNeeded();
+ return map.get(key);
+ }
+
+ private void buildIfNeeded() {
+ if (map == null) {
+ // added to avoid hash collision attack
+ if (Sys.is1_8OrLater() || (Sys.is1_7() && JDK_MAP_ALTHASHING_SYSPROP != null)) {
+ map = new LinkedHashMap<String, Object>(size, 0.01f);
+ } else {
+ map = new TreeMap<String, Object>();
+ }
+
+ for (int index = 0; index < size; index++) {
+ map.put(keys[index], values[index]);
+ }
+ this.keys = null;
+ this.values = null;
+ }
+ }
+
+ public Object remove(Object key) {
+ buildIfNeeded();
+ return map.remove(key);
+ }
+
+ public void putAll(Map m) {
+ buildIfNeeded();
+ map.putAll(m);
+ }
+
+ public void clear() {
+ if (map == null) {
+ size = 0;
+ } else {
+ map.clear();
+ }
+ }
+
+ public Set<String> keySet() {
+ buildIfNeeded();
+ return map.keySet();
+ }
+
+ public Collection<Object> values() {
+ buildIfNeeded();
+ return map.values();
+ }
+
+ public boolean equals(Object o) {
+ buildIfNeeded();
+ return map.equals(o);
+ }
+
+ public int hashCode() {
+ buildIfNeeded();
+ return map.hashCode();
+ }
+
+ public String toString() {
+ buildIfNeeded();
+ return map.toString();
+ }
+
+ protected Object clone() throws CloneNotSupportedException {
+ if (map == null) {
+ return null;
+ } else {
+ if (map instanceof LinkedHashMap) {
+ return ((LinkedHashMap) map).clone();
+ } else {
+ return new LinkedHashMap(this);
+ }
+ }
+ }
+
+ public LazyMap clearAndCopy() {
+ LazyMap map = new LazyMap();
+ for (int index = 0; index < size; index++) {
+ map.put(keys[index], values[index]);
+ }
+ size = 0;
+ return map;
+ }
+
+ public static <V> V[] grow(V[] array) {
+ Object newArray = Array.newInstance(array.getClass().getComponentType(), array.length * 2);
+ System.arraycopy(array, 0, newArray, 0, array.length);
+ return (V[]) newArray;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java
new file mode 100644
index 0000000..7692388
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/LazyValueMap.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * This class is important to the performance of the parser.
+ * It stores Value objects in a map where they are evaluated lazily.
+ * This is great for JSONPath types of application, and Object Serialization but not for maps that are going to be stored in a cache.
+ * <p/>
+ * This is because the Value construct is a type of index overlay that merely tracks where the token is located in the buffer,
+ * and what if any thing we noted about it (like can be converted to a decimal number, etc.).
+ * <p/>
+ * To mitigate memory leaks this class along with CharSequenceValue implement two constructs, namely,
+ * chop, and lazyChop.
+ * <p/>
+ * A chop is when we convert backing buffer of a Value object into a smaller buffer.
+ * A lazyChop is when we do a chop but only when a get operation is called.
+ * <p/>
+ * The lazyChop is performed on the tree that is touched by the JSONPath expression or its ilk.
+ * <p/>
+ * The chop operation can be done during parsing or lazily by storing the values in this construct.
+ *
+ * @author Rick Hightower (insane chipmonk)
+ */
+public class LazyValueMap extends AbstractMap<String, Object> implements ValueMap<String, Object> {
+
+ /**
+ * holds the map that gets lazily created on first access.
+ */
+ private Map<String, Object> map = null;
+ /**
+ * holds the list of items that we are managing.
+ */
+ private Entry<String, Value>[] items;
+ /**
+ * Holds the current number mapping managed by this map.
+ */
+ private int len = 0;
+ /**
+ * Holds whether or not we ae in lazy chop mode or not.
+ */
+ private final boolean lazyChop;
+
+ /**
+ * Keep track if this map has already been chopped so we don't waste time trying to chop it again.
+ */
+ boolean mapChopped = false;
+
+ public LazyValueMap(boolean lazyChop) {
+ this.items = new Entry[5];
+ this.lazyChop = lazyChop;
+ }
+
+ public LazyValueMap(boolean lazyChop, int initialSize) {
+ this.items = new Entry[initialSize];
+ this.lazyChop = lazyChop;
+ }
+
+ /**
+ * Adds a new MapItemValue to the mapping.
+ *
+ * @param miv miv we are adding.
+ */
+ public final void add(MapItemValue miv) {
+ if (len >= items.length) {
+ items = LazyMap.grow(items);
+ }
+ items[len] = miv;
+ len++;
+ }
+
+ /**
+ * Gets the item by key from the mapping.
+ *
+ * @param key to lookup
+ * @return the item for the given key
+ */
+ public final Object get(Object key) {
+ Object object = null;
+
+ /* if the map is null, then we create it. */
+ if (map == null) {
+ buildMap();
+ }
+ object = map.get(key);
+
+ lazyChopIfNeeded(object);
+ return object;
+ }
+
+ /**
+ * If in lazy chop mode, and the object is a Lazy Value Map or a ValueList
+ * then we force a chop operation for each of its items.
+ */
+ private void lazyChopIfNeeded(Object object) {
+ if (lazyChop) {
+ if (object instanceof LazyValueMap) {
+ LazyValueMap m = (LazyValueMap) object;
+ m.chopMap();
+ } else if (object instanceof ValueList) {
+ ValueList list = (ValueList) object;
+ list.chopList();
+ }
+ }
+ }
+
+ /**
+ * Chop this map.
+ */
+ public final void chopMap() {
+ /* if it has been chopped then you have to return. */
+ if (mapChopped) {
+ return;
+ }
+ mapChopped = true;
+
+ /* If the internal map was not create yet, don't. We can chop the value w/o creating the internal map.*/
+ if (this.map == null) {
+ for (int index = 0; index < len; index++) {
+ MapItemValue entry = (MapItemValue) items[index];
+
+ Value value = entry.getValue();
+ if (value == null) continue;
+ if (value.isContainer()) {
+ chopContainer(value);
+ } else {
+ value.chop();
+ }
+ }
+ } else {
+ /* Iterate through the map and do the same thing. Make sure children and children of children are chopped. */
+ for (Map.Entry<String, Object> entry : map.entrySet()) {
+
+ Object object = entry.getValue();
+ if (object instanceof Value) {
+ Value value = (Value) object;
+ if (value.isContainer()) {
+ chopContainer(value);
+ } else {
+ value.chop();
+ }
+ } else if (object instanceof LazyValueMap) {
+ LazyValueMap m = (LazyValueMap) object;
+ m.chopMap();
+ } else if (object instanceof ValueList) {
+ ValueList list = (ValueList) object;
+ list.chopList();
+ }
+ }
+ }
+ }
+
+ /* We need to chop up this child container. */
+ private static void chopContainer(Value value) {
+ Object obj = value.toValue();
+ if (obj instanceof LazyValueMap) {
+ LazyValueMap map = (LazyValueMap) obj;
+ map.chopMap();
+ } else if (obj instanceof ValueList) {
+ ValueList list = (ValueList) obj;
+ list.chopList();
+ }
+ }
+
+ public Value put(String key, Object value) {
+ die("Not that kind of map");
+ return null;
+ }
+
+ public Set<Entry<String, Object>> entrySet() {
+ if (map == null) {
+ buildMap();
+ }
+ return map.entrySet();
+ }
+
+ private void buildMap() {
+ // added to avoid hash collision attack
+ if (Sys.is1_8OrLater() || (Sys.is1_7() && LazyMap.JDK_MAP_ALTHASHING_SYSPROP != null)) {
+ map = new HashMap<String, Object>(items.length);
+ } else {
+ map = new TreeMap<String, Object>();
+ }
+
+ for (Entry<String, Value> miv : items) {
+ if (miv == null) {
+ break;
+ }
+ map.put(miv.getKey(), miv.getValue().toValue());
+ }
+
+ len = 0;
+ items = null;
+ }
+
+ public Collection<Object> values() {
+ if (map == null) buildMap();
+ return map.values();
+ }
+
+ public int size() {
+ if (map == null) buildMap();
+ return map.size();
+ }
+
+ public String toString() {
+ if (map == null) buildMap();
+ return map.toString();
+ }
+
+ public int len() {
+ return len;
+ }
+
+ public boolean hydrated() {
+ return map != null;
+ }
+
+ public Entry<String, Value>[] items() {
+ return items;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java
new file mode 100644
index 0000000..8a10c59
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/MapItemValue.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.groovy.json.internal.Exceptions.die;
+
+/**
+ * This holds a mapping from value key to value value to maximize laziness.
+ *
+ * @author Rick Hightower
+ */
+public class MapItemValue implements Map.Entry<String, Value> {
+
+ final Value name;
+ final Value value;
+
+ private String key = null;
+
+ private static final boolean internKeys = Boolean.parseBoolean(System.getProperty("groovy.json.implementation.internKeys", "false"));
+
+ protected static ConcurrentHashMap<String, String> internedKeysCache;
+
+ static {
+ if (internKeys) {
+ internedKeysCache = new ConcurrentHashMap<String, String>();
+ }
+ }
+
+ public MapItemValue(Value name, Value value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getKey() {
+ if (key == null) {
+ if (internKeys) {
+ key = name.toString();
+
+ String keyPrime = internedKeysCache.get(key);
+ if (keyPrime == null) {
+ key = key.intern();
+ internedKeysCache.put(key, key);
+ } else {
+ key = keyPrime;
+ }
+ } else {
+ key = name.toString();
+ }
+ }
+ return key;
+ }
+
+ public Value getValue() {
+ return value;
+ }
+
+ public Value setValue(Value value) {
+ Exceptions.die("not that kind of Entry");
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/25e2a386/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java
new file mode 100644
index 0000000..525010e
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/NumberValue.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.json.internal;
+
+import groovy.json.JsonException;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Date;
+
+import static java.lang.Boolean.parseBoolean;
+import static org.apache.groovy.json.internal.CharScanner.isInteger;
+import static org.apache.groovy.json.internal.CharScanner.parseDouble;
+import static org.apache.groovy.json.internal.CharScanner.parseFloat;
+import static org.apache.groovy.json.internal.CharScanner.parseIntFromTo;
+import static org.apache.groovy.json.internal.CharScanner.parseLongFromTo;
+import static org.apache.groovy.json.internal.Exceptions.die;
+import static org.apache.groovy.json.internal.Exceptions.sputs;
+
+/**
+ * @author Rick Hightower
+ */
+public class NumberValue extends java.lang.Number implements Value {
+
+ private char[] buffer;
+ private boolean chopped;
+ private int startIndex;
+ private int endIndex;
+ private final Type type;
+ private Object value;
+
+ public NumberValue(Type type) {
+ this.type = type;
+ }
+
+ public NumberValue() {
+ this.type = null;
+ }
+
+ public NumberValue(boolean chop, Type type, int startIndex, int endIndex, char[] buffer) {
+ this.type = type;
+
+ try {
+ if (chop) {
+ this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+ this.startIndex = 0;
+ this.endIndex = this.buffer.length;
+ chopped = true;
+ } else {
+ this.startIndex = startIndex;
+ this.endIndex = endIndex;
+ this.buffer = buffer;
+ }
+ } catch (Exception ex) {
+ Exceptions.handle(sputs("exception", ex, "start", startIndex, "end", endIndex), ex);
+ }
+
+ // Check for a single minus now, rather than finding out later during lazy parsing.
+ if (this.endIndex - this.startIndex == 1 && this.buffer[this.startIndex] == '-') {
+ die("A single minus is not a valid number");
+ }
+
+ }
+
+ public String toString() {
+ if (startIndex == 0 && endIndex == buffer.length) {
+ return FastStringUtils.noCopyStringFromChars(buffer);
+ } else {
+ return new String(buffer, startIndex, (endIndex - startIndex));
+ }
+ }
+
+ public final Object toValue() {
+ return value != null ? value : (value = doToValue());
+ }
+
+ public <T extends Enum> T toEnum(Class<T> cls) {
+ return toEnum(cls, intValue());
+ }
+
+ public static <T extends Enum> T toEnum(Class<T> cls, int value) {
+ T[] enumConstants = cls.getEnumConstants();
+ for (T e : enumConstants) {
+ if (e.ordinal() == value) {
+ return e;
+ }
+ }
+ die("Can't convert ordinal value " + value + " into enum of type " + cls);
+ return null;
+ }
+
+ public boolean isContainer() {
+ return false;
+ }
+
+ private Object doToValue() {
+ switch (type) {
+ case DOUBLE:
+ return bigDecimalValue();
+ case INTEGER:
+ if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+ return intValue();
+ } else {
+ return longValue();
+ }
+ }
+ die();
+ return null;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Value)) return false;
+
+ NumberValue value1 = (NumberValue) o;
+
+ if (endIndex != value1.endIndex) return false;
+ if (startIndex != value1.startIndex) return false;
+ if (!Arrays.equals(buffer, value1.buffer)) return false;
+ if (type != value1.type) return false;
+ return value != null ? value.equals(value1.value) : value1.value == null;
+
+ }
+
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (buffer != null ? Arrays.hashCode(buffer) : 0);
+ result = 31 * result + startIndex;
+ result = 31 * result + endIndex;
+ result = 31 * result + (value != null ? value.hashCode() : 0);
+ return result;
+ }
+
+ public BigDecimal bigDecimalValue() {
+ try {
+ return new BigDecimal(buffer, startIndex, endIndex - startIndex);
+ } catch (NumberFormatException e) {
+ throw new JsonException("unable to parse " + new String(buffer, startIndex, endIndex - startIndex), e);
+ }
+ }
+
+ public BigInteger bigIntegerValue() {
+ return new BigInteger(toString());
+ }
+
+ public String stringValue() {
+ return toString();
+ }
+
+ public String stringValueEncoded() {
+ return toString();
+ }
+
+ public Date dateValue() {
+ return new Date(Dates.utc(longValue()));
+ }
+
+ public int intValue() {
+ return parseIntFromTo(buffer, startIndex, endIndex);
+ }
+
+ public long longValue() {
+ if (isInteger(buffer, startIndex, endIndex - startIndex)) {
+ return parseIntFromTo(buffer, startIndex, endIndex);
+ } else {
+ return parseLongFromTo(buffer, startIndex, endIndex);
+ }
+ }
+
+ public byte byteValue() {
+ return (byte) intValue();
+ }
+
+ public short shortValue() {
+ return (short) intValue();
+ }
+
+ public double doubleValue() {
+ return parseDouble(this.buffer, startIndex, endIndex);
+ }
+
+ public boolean booleanValue() {
+ return parseBoolean(toString());
+ }
+
+ public float floatValue() {
+ return parseFloat(this.buffer, startIndex, endIndex);
+ }
+
+ public final void chop() {
+ if (!chopped) {
+ this.chopped = true;
+ this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
+ this.startIndex = 0;
+ this.endIndex = this.buffer.length;
+ }
+ }
+
+ public char charValue() {
+ return buffer[startIndex];
+ }
+}