aboutsummaryrefslogtreecommitdiff
path: root/caliper/src/main/java/com/google/caliper/util/InterleavedReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'caliper/src/main/java/com/google/caliper/util/InterleavedReader.java')
-rw-r--r--caliper/src/main/java/com/google/caliper/util/InterleavedReader.java128
1 files changed, 128 insertions, 0 deletions
diff --git a/caliper/src/main/java/com/google/caliper/util/InterleavedReader.java b/caliper/src/main/java/com/google/caliper/util/InterleavedReader.java
new file mode 100644
index 0000000..40293bf
--- /dev/null
+++ b/caliper/src/main/java/com/google/caliper/util/InterleavedReader.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed 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 com.google.caliper.util;
+
+import com.google.gson.JsonParser;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Reads a stream containing inline JSON objects. Each JSON object is prefixed
+ * by a marker string and suffixed by a newline character.
+ */
+public final class InterleavedReader implements Closeable {
+
+ /**
+ * The length of the scratch buffer to search for markers in. Also acts as an
+ * upper bound on the length of returned strings. Not used as an I/O buffer.
+ */
+ private static final int BUFFER_LENGTH = 80;
+
+ private final String marker;
+ private final BufferedReader reader;
+ private final JsonParser jsonParser = new JsonParser();
+
+ public static final String DEFAULT_MARKER = "//ZxJ/";
+
+ public InterleavedReader(Reader reader) {
+ this(DEFAULT_MARKER, reader);
+ }
+
+ public InterleavedReader(String marker, Reader reader) {
+ if (marker.length() > BUFFER_LENGTH) {
+ throw new IllegalArgumentException("marker.length() > BUFFER_LENGTH");
+ }
+ this.marker = marker;
+ this.reader = reader instanceof BufferedReader
+ ? (BufferedReader) reader
+ : new BufferedReader(reader);
+ }
+
+ /**
+ * Returns the next value in the stream: either a String, a JsonElement, or
+ * null to indicate the end of the stream. Callers should use instanceof to
+ * inspect the return type.
+ */
+ public Object read() throws IOException {
+ char[] buffer = new char[BUFFER_LENGTH];
+ reader.mark(BUFFER_LENGTH);
+ int count = 0;
+ int textEnd;
+
+ while (true) {
+ int r = reader.read(buffer, count, buffer.length - count);
+
+ if (r == -1) {
+ // the input is exhausted; return the remaining characters
+ textEnd = count;
+ break;
+ }
+
+ count += r;
+ int possibleMarker = findPossibleMarker(buffer, count);
+
+ if (possibleMarker != 0) {
+ // return the characters that precede the marker
+ textEnd = possibleMarker;
+ break;
+ }
+
+ if (count < marker.length()) {
+ // the buffer contains only the prefix of a marker so we must read more
+ continue;
+ }
+
+ // we've read a marker so return the value that follows
+ reader.reset();
+ String json = reader.readLine().substring(marker.length());
+ return jsonParser.parse(json);
+ }
+
+ if (count == 0) {
+ return null;
+ }
+
+ // return characters
+ reader.reset();
+ count = reader.read(buffer, 0, textEnd);
+ return new String(buffer, 0, count);
+ }
+
+ @Override public void close() throws IOException {
+ reader.close();
+ }
+
+ /**
+ * Returns the index of marker in {@code chars}, stopping at {@code limit}.
+ * Should the chars end with a prefix of marker, the offset of that prefix
+ * is returned.
+ */
+ int findPossibleMarker(char[] chars, int limit) {
+ search:
+ for (int i = 0; true; i++) {
+ for (int m = 0; m < marker.length() && i + m < limit; m++) {
+ if (chars[i + m] != marker.charAt(m)) {
+ continue search;
+ }
+ }
+ return i;
+ }
+ }
+}