All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.parboiled1.grappa.backport.buffers.CharSequenceInputBuffer Maven / Gradle / Ivy

There is a newer version: 2.0.0.1-sonar
Show newest version
/*
 * Copyright (C) 2014 Francis Galiegue 
 *
 * 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.github.parboiled1.grappa.backport.buffers;

import com.google.common.base.Preconditions;
import com.google.common.collect.Range;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.parboiled.support.Chars;
import org.parboiled.support.IndexRange;
import org.parboiled.support.Position;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.nio.CharBuffer;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * An {@link InputBuffer} over a {@link CharSequence}
 *
 * 

A {@link CharSequence} is the most basic character interface in the JDK. * It is implemented by a lot of character related classes, including {@link * String}, and is also the argument type used by a {@link Pattern}'s {@link * Matcher}.

* *

Among other things, this means you can use this package on very large * files using largetext, which * implements {@link CharSequence} over multi-gigabyte files.

* *

This is a backport from grappa 2.0.x.

*/ @Immutable public final class CharSequenceInputBuffer implements InputBuffer { private static final ExecutorService EXECUTOR_SERVICE; static { final ThreadFactory factory = new ThreadFactoryBuilder() .setDaemon(true).setNameFormat("linecounter-thread-%d").build(); EXECUTOR_SERVICE = Executors.newCachedThreadPool(factory); } private final CharSequence charSequence; private final Future lineCounter; public static InputBuffer fromLegacy( final org.parboiled.buffers.InputBuffer legacyBuffer ) { return new CharSequenceInputBuffer(loadLegacyBuffer(legacyBuffer)); } public CharSequenceInputBuffer(@Nonnull final CharSequence charSequence) { this.charSequence = Objects.requireNonNull(charSequence); lineCounter = EXECUTOR_SERVICE.submit(new Callable() { @Override public LineCounter call() throws Exception { return new LineCounter(charSequence); } }); } public CharSequenceInputBuffer(@Nonnull final char[] chars) { this(CharBuffer.wrap(Objects.requireNonNull(chars))); } @Override public char charAt(final int index) { if (index < 0) throw new IllegalArgumentException("index is negative"); return index < charSequence.length() ? charSequence.charAt(index) : Chars.EOI; } @SuppressWarnings("ImplicitNumericConversion") @Override public int codePointAt(final int index) { final int length = charSequence.length(); if (index >= length) return -1; if (index < 0) throw new IllegalArgumentException("index is negative"); final char c = charSequence.charAt(index); if (!Character.isHighSurrogate(c)) return c; if (index == length - 1) return c; final char c2 = charSequence.charAt(index + 1); return Character.isLowSurrogate(c2) ? Character.toCodePoint(c, c2) : c; } @Override public boolean test(final int index, final char[] characters) { final int length = characters.length; if (index + length > charSequence.length()) return false; for (int i = 0; i < length; i++) if (charSequence.charAt(index + i) != characters[i]) return false; return true; } @Override public String extract(final int start, final int end) { final int realStart = Math.max(start, 0); final int realEnd = Math.min(end, charSequence.length()); return charSequence.subSequence(realStart, realEnd).toString(); } @Override public String extract(final IndexRange range) { return extract(range.start, range.end); } @Override public Position getPosition(final int index) { return Futures.getUnchecked(lineCounter).toPosition(index); } @Override public String extractLine(final int lineNumber) { Preconditions.checkArgument(lineNumber > 0, "line number is negative"); final LineCounter counter = Futures.getUnchecked(lineCounter); final Range range = counter.getLineRange(lineNumber); final int start = range.lowerEndpoint(); int end = range.upperEndpoint(); if (charAt(end - 1) == '\n') end--; if (charAt(end - 1) == '\r') end--; return extract(start, end); } @SuppressWarnings("AutoUnboxing") @Override public IndexRange getLineRange(final int lineNumber) { final Range range = Futures.getUnchecked(lineCounter).getLineRange(lineNumber); return new IndexRange(range.lowerEndpoint(), range.upperEndpoint()); } @Override public int getLineCount() { return Futures.getUnchecked(lineCounter).getNrLines(); } @Override public int length() { return charSequence.length(); } private static CharSequence loadLegacyBuffer( final org.parboiled.buffers.InputBuffer buffer) { final int bufsize = 4096; String s; final StringBuilder sb = new StringBuilder(); int len; int index = 0; do { s = buffer.extract(index, index + bufsize); len = s.length(); sb.append(s); index += bufsize; } while (len == bufsize); return sb; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy