dev.cel.common.internal.CelCodePointArray Maven / Gradle / Ivy
Show all versions of runtime Show documentation
// Copyright 2022 Google LLC
//
// 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
//
// https://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 dev.cel.common.internal;
import static com.google.common.base.Strings.isNullOrEmpty;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;
import java.util.PrimitiveIterator;
/**
* Represents an in-memory read-only contiguous source of Unicode code points.
*
* CEL Library Internals. Do Not Use.
*/
@Immutable
@Internal
public abstract class CelCodePointArray {
// Package-private default constructor to prevent extensions outside of the codebase.
CelCodePointArray() {}
/** Returns a new {@link CelCodePointArray} that is a subview of this between [i, j). */
public abstract CelCodePointArray slice(int i, int j);
/** Get the code point at the given index. */
public abstract int get(int index);
/** Returns the number of code points. */
public abstract int size();
/** Returns the line offsets. */
public abstract ImmutableList lineOffsets();
public final int length() {
return size();
}
/** Returns true if empty, false otherwise. */
public boolean isEmpty() {
return length() == 0;
}
@Override
public abstract String toString();
public static CelCodePointArray fromString(String text) {
if (isNullOrEmpty(text)) {
return EmptyCodePointArray.INSTANCE;
}
PrimitiveIterator.OfInt codePoints = text.codePoints().iterator();
byte[] byteArray = new byte[text.length()];
int byteIndex = 0;
LineOffsetContext lineOffsetContext = new LineOffsetContext();
while (codePoints.hasNext()) {
int codePoint = codePoints.nextInt();
lineOffsetContext.process(codePoint);
if (codePoint <= 0xff) {
byteArray[byteIndex++] = (byte) codePoint;
continue;
}
if (codePoint <= 0xffff) {
char[] charArray = new char[text.length()];
int charIndex = 0;
for (; charIndex < byteIndex; charIndex++) {
charArray[charIndex] = (char) (byteArray[charIndex] & 0xff);
}
byteArray = null;
charArray[charIndex++] = (char) codePoint;
while (codePoints.hasNext()) {
codePoint = codePoints.nextInt();
lineOffsetContext.process(codePoint);
if (codePoint <= 0xffff) {
charArray[charIndex++] = (char) codePoint;
continue;
}
int[] intArray = new int[text.length()];
int intIndex = 0;
for (; intIndex < charIndex; intIndex++) {
intArray[intIndex] = charArray[intIndex] & 0xffff;
}
charArray = null;
intArray[intIndex++] = codePoint;
while (codePoints.hasNext()) {
codePoint = codePoints.nextInt();
lineOffsetContext.process(codePoint);
intArray[intIndex++] = codePoint;
}
return SupplementalCodePointArray.create(
intArray, intIndex, lineOffsetContext.buildLineOffsets());
}
return BasicCodePointArray.create(
charArray, charIndex, lineOffsetContext.buildLineOffsets());
}
int[] intArray = new int[text.length()];
int intIndex = 0;
for (; intIndex < byteIndex; intIndex++) {
intArray[intIndex] = byteArray[intIndex] & 0xff;
}
byteArray = null;
intArray[intIndex++] = codePoint;
while (codePoints.hasNext()) {
codePoint = codePoints.nextInt();
lineOffsetContext.process(codePoint);
intArray[intIndex++] = codePoint;
}
return SupplementalCodePointArray.create(
intArray, intIndex, lineOffsetContext.buildLineOffsets());
}
return Latin1CodePointArray.create(byteArray, byteIndex, lineOffsetContext.buildLineOffsets());
}
private static class LineOffsetContext {
private static final int NEWLINE_CODE_POINT = 10;
private final ImmutableList.Builder lineOffsetBuilder;
private int lineOffsetCodePoints;
private void process(int codePoint) {
lineOffsetCodePoints++;
if (codePoint == NEWLINE_CODE_POINT) {
lineOffsetBuilder.add(lineOffsetCodePoints);
}
}
private ImmutableList buildLineOffsets() {
return lineOffsetBuilder.add(lineOffsetCodePoints + 1).build();
}
private LineOffsetContext() {
this.lineOffsetBuilder = ImmutableList.builder();
}
}
}