Skip to content

Commit 8913ca5

Browse files
committed
Combine XBytesRef and EncodedString into XContentString
1 parent fd4ec6c commit 8913ca5

File tree

12 files changed

+130
-135
lines changed

12 files changed

+130
-135
lines changed

libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/ESUTF8StreamJsonParser.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import com.fasterxml.jackson.core.json.UTF8StreamJsonParser;
1717
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
1818

19-
import org.elasticsearch.xcontent.XBytesRef;
19+
import org.elasticsearch.xcontent.XContentString;
2020

2121
import java.io.IOException;
2222
import java.io.InputStream;
@@ -44,17 +44,20 @@ public ESUTF8StreamJsonParser(
4444
* This is only a best-effort attempt; if there is some reason the bytes cannot be retrieved, this method will return null.
4545
* Currently, this is only implemented for ascii-only strings that do not contain escaped characters.
4646
*/
47-
public XBytesRef getValueAsByteRef() throws IOException {
47+
public XContentString getValueAsByteRef() throws IOException {
4848
if (_currToken == JsonToken.VALUE_STRING && _tokenIncomplete) {
4949
if (stringEnd > 0) {
50-
return new XBytesRef(_inputBuffer, _inputPtr, stringEnd - 1);
50+
final int len = stringEnd - 1 - _inputPtr;
51+
// For now, we can use `len` for `charCount` because we only support ascii-encoded unescaped strings,
52+
// which means each character uses exactly 1 byte.
53+
return new XContentString(new XContentString.ByteRef(_inputBuffer, _inputPtr, len), len);
5154
}
5255
return _finishAndReturnByteRef();
5356
}
5457
return null;
5558
}
5659

57-
protected XBytesRef _finishAndReturnByteRef() throws IOException {
60+
protected XContentString _finishAndReturnByteRef() throws IOException {
5861
int ptr = _inputPtr;
5962
if (ptr >= _inputEnd) {
6063
_loadMoreGuaranteed();
@@ -70,7 +73,10 @@ protected XBytesRef _finishAndReturnByteRef() throws IOException {
7073
if (codes[c] != 0) {
7174
if (c == INT_QUOTE) {
7275
stringEnd = ptr + 1;
73-
return new XBytesRef(inputBuffer, startPtr, ptr);
76+
final int len = ptr - startPtr;
77+
// For now, we can use `len` for `charCount` because we only support ascii-encoded unescaped strings,
78+
// which means each character uses exactly 1 byte.
79+
return new XContentString(new XContentString.ByteRef(inputBuffer, startPtr, len), len);
7480
}
7581
return null;
7682
}

libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentParser.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
import com.fasterxml.jackson.core.io.JsonEOFException;
1919

2020
import org.elasticsearch.core.IOUtils;
21-
import org.elasticsearch.xcontent.XBytesRef;
2221
import org.elasticsearch.xcontent.XContentEOFException;
2322
import org.elasticsearch.xcontent.XContentLocation;
2423
import org.elasticsearch.xcontent.XContentParseException;
2524
import org.elasticsearch.xcontent.XContentParserConfiguration;
25+
import org.elasticsearch.xcontent.XContentString;
2626
import org.elasticsearch.xcontent.XContentType;
2727
import org.elasticsearch.xcontent.provider.XContentParserConfigurationImpl;
2828
import org.elasticsearch.xcontent.support.AbstractXContentParser;
@@ -117,14 +117,17 @@ public String text() throws IOException {
117117
}
118118

119119
@Override
120-
public XBytesRef textRefOrNull() throws IOException {
120+
public XContentString xContentText() throws IOException {
121121
if (currentToken().isValue() == false) {
122-
return null;
122+
throwOnNoText();
123123
}
124124
if (parser instanceof ESUTF8StreamJsonParser esParser) {
125-
return esParser.getValueAsByteRef();
125+
var bytesRef = esParser.getValueAsByteRef();
126+
if (bytesRef != null) {
127+
return bytesRef;
128+
}
126129
}
127-
return null;
130+
return new XContentString(text());
128131
}
129132

130133
private void throwOnNoText() {

libs/x-content/impl/src/test/java/org/elasticsearch/xcontent/provider/json/ESUTF8StreamJsonParserTests.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import org.elasticsearch.core.CheckedConsumer;
1717
import org.elasticsearch.test.ESTestCase;
18-
import org.elasticsearch.xcontent.XBytesRef;
18+
import org.elasticsearch.xcontent.XContentString;
1919
import org.hamcrest.Matchers;
2020

2121
import java.io.IOException;
@@ -33,8 +33,8 @@ private void testParseJson(String input, CheckedConsumer<ESUTF8StreamJsonParser,
3333
test.accept((ESUTF8StreamJsonParser) parser);
3434
}
3535

36-
private void assertTextRef(XBytesRef textRef, String expectedValue) {
37-
var data = Arrays.copyOfRange(textRef.bytes(), textRef.start(), textRef.end());
36+
private void assertTextRef(XContentString.ByteRef textRef, String expectedValue) {
37+
var data = Arrays.copyOfRange(textRef.bytes(), textRef.offset(), textRef.offset() + textRef.length());
3838
assertThat(data, Matchers.equalTo(StandardCharsets.UTF_8.encode(expectedValue).array()));
3939
}
4040

@@ -44,10 +44,10 @@ public void testGetValueAsByteRef() throws IOException {
4444
assertThat(parser.nextFieldName(), Matchers.equalTo("foo"));
4545
assertThat(parser.nextValue(), Matchers.equalTo(JsonToken.VALUE_STRING));
4646

47-
XBytesRef textRef = parser.getValueAsByteRef();
47+
XContentString.ByteRef textRef = parser.getValueAsByteRef().getBytes();
4848
assertThat(textRef, Matchers.notNullValue());
49-
assertThat(textRef.start(), Matchers.equalTo(9));
50-
assertThat(textRef.end(), Matchers.equalTo(12));
49+
assertThat(textRef.offset(), Matchers.equalTo(9));
50+
assertThat(textRef.length(), Matchers.equalTo(3));
5151
assertTextRef(textRef, "bar");
5252

5353
assertThat(parser.getValueAsString(), Matchers.equalTo("bar"));
@@ -81,28 +81,28 @@ public void testGetValueAsByteRef() throws IOException {
8181

8282
assertThat(parser.nextValue(), Matchers.equalTo(JsonToken.VALUE_STRING));
8383
{
84-
XBytesRef textRef = parser.getValueAsByteRef();
84+
XContentString.ByteRef textRef = parser.getValueAsByteRef().getBytes();
8585
assertThat(textRef, Matchers.notNullValue());
86-
assertThat(textRef.start(), Matchers.equalTo(10));
87-
assertThat(textRef.end(), Matchers.equalTo(15));
86+
assertThat(textRef.offset(), Matchers.equalTo(10));
87+
assertThat(textRef.length(), Matchers.equalTo(5));
8888
assertTextRef(textRef, "lorem");
8989
}
9090

9191
assertThat(parser.nextValue(), Matchers.equalTo(JsonToken.VALUE_STRING));
9292
{
93-
XBytesRef textRef = parser.getValueAsByteRef();
93+
XContentString.ByteRef textRef = parser.getValueAsByteRef().getBytes();
9494
assertThat(textRef, Matchers.notNullValue());
95-
assertThat(textRef.start(), Matchers.equalTo(19));
96-
assertThat(textRef.end(), Matchers.equalTo(24));
95+
assertThat(textRef.offset(), Matchers.equalTo(19));
96+
assertThat(textRef.length(), Matchers.equalTo(5));
9797
assertTextRef(textRef, "ipsum");
9898
}
9999

100100
assertThat(parser.nextValue(), Matchers.equalTo(JsonToken.VALUE_STRING));
101101
{
102-
XBytesRef textRef = parser.getValueAsByteRef();
102+
XContentString.ByteRef textRef = parser.getValueAsByteRef().getBytes();
103103
assertThat(textRef, Matchers.notNullValue());
104-
assertThat(textRef.start(), Matchers.equalTo(28));
105-
assertThat(textRef.end(), Matchers.equalTo(33));
104+
assertThat(textRef.offset(), Matchers.equalTo(28));
105+
assertThat(textRef.length(), Matchers.equalTo(5));
106106
assertTextRef(textRef, "dolor");
107107
}
108108

libs/x-content/src/main/java/org/elasticsearch/xcontent/FilterXContentParser.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,12 @@ public String textOrNull() throws IOException {
100100
return delegate().textOrNull();
101101
}
102102

103-
@Override
104-
public XBytesRef textRefOrNull() throws IOException {
105-
return delegate().textRefOrNull();
103+
public XContentString xContentText() throws IOException {
104+
return delegate().xContentText();
105+
}
106+
107+
public XContentString xContentTextOrNull() throws IOException {
108+
return delegate().xContentTextOrNull();
106109
}
107110

108111
@Override

libs/x-content/src/main/java/org/elasticsearch/xcontent/XBytesRef.java

Lines changed: 0 additions & 12 deletions
This file was deleted.

libs/x-content/src/main/java/org/elasticsearch/xcontent/XContentParser.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,9 @@ <T> Map<String, T> map(Supplier<Map<String, T>> mapFactory, CheckedFunction<XCon
109109

110110
String textOrNull() throws IOException;
111111

112-
/**
113-
* Returns a {@link XBytesRef} containing UTF-8 bytes, if possible.
114-
* This is only a best-effort attempt; if there is some reason the bytes cannot be retrieved, this method will return null.
115-
* In this case, use {@link #textOrNull()} to get the string-encoded value.
116-
*/
117-
default XBytesRef textRefOrNull() throws IOException {
118-
return null;
119-
}
112+
XContentString xContentText() throws IOException;
113+
114+
XContentString xContentTextOrNull() throws IOException;
120115

121116
CharBuffer charBufferOrNull() throws IOException;
122117

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.xcontent;
11+
12+
import java.nio.ByteBuffer;
13+
import java.nio.charset.StandardCharsets;
14+
import java.util.Objects;
15+
16+
public class XContentString {
17+
private String stringValue;
18+
private ByteRef bytesValue;
19+
private final int charCount;
20+
21+
public record ByteRef(byte[] bytes, int offset, int length) {}
22+
23+
public XContentString(String string) {
24+
this.stringValue = Objects.requireNonNull(string);
25+
this.charCount = string.length();
26+
}
27+
28+
public XContentString(ByteRef bytes, int charCount) {
29+
this.bytesValue = Objects.requireNonNull(bytes);
30+
this.charCount = charCount;
31+
}
32+
33+
public ByteRef getBytes() {
34+
if (bytesValue == null) {
35+
var byteBuffer = StandardCharsets.UTF_8.encode(stringValue);
36+
bytesValue = new ByteRef(byteBuffer.array(), 0, byteBuffer.limit());
37+
}
38+
return bytesValue;
39+
}
40+
41+
public String getString() {
42+
if (stringValue == null) {
43+
stringValue = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytesValue.bytes(), bytesValue.offset(), bytesValue.length()))
44+
.toString();
45+
assert stringValue.length() == charCount;
46+
}
47+
return stringValue;
48+
}
49+
50+
public int length() {
51+
return charCount;
52+
}
53+
54+
}

libs/x-content/src/main/java/org/elasticsearch/xcontent/support/AbstractXContentParser.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.elasticsearch.xcontent.NamedXContentRegistry;
1818
import org.elasticsearch.xcontent.XContentParseException;
1919
import org.elasticsearch.xcontent.XContentParser;
20+
import org.elasticsearch.xcontent.XContentString;
2021

2122
import java.io.IOException;
2223
import java.math.BigDecimal;
@@ -258,6 +259,19 @@ public final String textOrNull() throws IOException {
258259
return text();
259260
}
260261

262+
@Override
263+
public XContentString xContentText() throws IOException {
264+
return new XContentString(text());
265+
}
266+
267+
@Override
268+
public final XContentString xContentTextOrNull() throws IOException {
269+
if (currentToken() == Token.VALUE_NULL) {
270+
return null;
271+
}
272+
return xContentText();
273+
}
274+
261275
@Override
262276
public CharBuffer charBufferOrNull() throws IOException {
263277
if (currentToken() == Token.VALUE_NULL) {

server/src/main/java/org/elasticsearch/common/bytes/EncodedString.java

Lines changed: 0 additions & 56 deletions
This file was deleted.

server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@
3333
import org.elasticsearch.xcontent.FilterXContentParser;
3434
import org.elasticsearch.xcontent.NamedXContentRegistry;
3535
import org.elasticsearch.xcontent.ToXContent;
36-
import org.elasticsearch.xcontent.XBytesRef;
3736
import org.elasticsearch.xcontent.XContentLocation;
3837
import org.elasticsearch.xcontent.XContentParser;
3938
import org.elasticsearch.xcontent.XContentParser.NumberType;
4039
import org.elasticsearch.xcontent.XContentParser.Token;
40+
import org.elasticsearch.xcontent.XContentString;
4141
import org.elasticsearch.xcontent.XContentType;
4242
import org.elasticsearch.xcontent.support.MapXContentParser;
4343

@@ -709,11 +709,11 @@ public Token currentToken() {
709709
}
710710

711711
@Override
712-
public XBytesRef textRefOrNull() throws IOException {
712+
public XContentString xContentTextOrNull() throws IOException {
713713
if (parsingObject == false) {
714-
return null;
714+
return new XContentString(textValue);
715715
}
716-
return super.textRefOrNull();
716+
return super.xContentTextOrNull();
717717
}
718718

719719
@Override

0 commit comments

Comments
 (0)