in serialization/src/main/java/com/twitter/serial/stream/bytebuffer/ByteBufferSerializerOutput.java [256:305]
private void encodeString(@NotNull String string) {
final int length = string.length();
final int headerPosition = mByteBuffer.position();
writeIntHeader(SerializerDefs.TYPE_STRING_ASCII, length);
boolean isAscii = true;
for (int i = 0; i < length; ++i) {
final int ch = (int) string.charAt(i);
if (ch < 0x80) {
ensureCapacity(ByteBufferSerializerDefs.SIZE_BYTE);
mByteBuffer.put((byte) ch);
} else {
isAscii = false;
if (ch < 0x800) {
ensureCapacity(2 * ByteBufferSerializerDefs.SIZE_BYTE);
mByteBuffer.put((byte) ((ch >> 6) | 0xc0));
mByteBuffer.put((byte) ((ch & 0x3f) | 0x80));
} else if (isSurrogate(ch)) {
// A supplementary character.
final int low = i + 1 != length ? string.charAt(i + 1) : 0;
if (!isSurrogateLead(ch) || !isSurrogate(low) || !isSurrogateTrail(low)) {
ensureCapacity(ByteBufferSerializerDefs.SIZE_BYTE);
mByteBuffer.put((byte) '?');
} else {
// Now we know we have a *valid* surrogate pair, we can consume the low surrogate.
//noinspection AssignmentToForLoopParameter
++i;
ensureCapacity(4 * ByteBufferSerializerDefs.SIZE_BYTE);
final int supplementary = getSupplementary(ch, low);
mByteBuffer.put((byte) ((supplementary >> 18) | 0xf0));
mByteBuffer.put((byte) (((supplementary >> 12) & 0x3f) | 0x80));
mByteBuffer.put((byte) (((supplementary >> 6) & 0x3f) | 0x80));
mByteBuffer.put((byte) ((supplementary & 0x3f) | 0x80));
}
} else {
ensureCapacity(3 * ByteBufferSerializerDefs.SIZE_BYTE);
mByteBuffer.put((byte) ((ch >> 12) | 0xe0));
mByteBuffer.put((byte) (((ch >> 6) & 0x3f) | 0x80));
mByteBuffer.put((byte) ((ch & 0x3f) | 0x80));
}
}
}
// If the string is not ASCII, update the header.
if (!isAscii) {
final int currentPosition = mByteBuffer.position();
mByteBuffer.position(headerPosition);
writeIntHeader(SerializerDefs.TYPE_STRING_UTF8, length);
mByteBuffer.position(currentPosition);
}
}