in java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java [778:871]
protected Expression writeCollectionData(
Expression buffer, Expression collection, Expression serializer, TypeRef<?> elementType) {
Invoke onCollectionWrite =
new Invoke(
serializer,
"onCollectionWrite",
TypeUtils.collectionOf(elementType),
buffer,
collection);
boolean isList = List.class.isAssignableFrom(getRawType(collection.type()));
collection =
isList ? new Cast(onCollectionWrite.inline(), LIST_TYPE, "list") : onCollectionWrite;
Expression size = new Invoke(collection, "size", PRIMITIVE_INT_TYPE);
walkPath.add(elementType.toString());
ListExpression builder = new ListExpression();
Class<?> elemClass = TypeUtils.getRawType(elementType);
boolean trackingRef = needWriteRef(elementType);
Tuple2<Expression, Invoke> writeElementsHeader =
writeElementsHeader(elemClass, trackingRef, serializer, buffer, collection);
Expression flags = writeElementsHeader.f0;
builder.add(flags);
boolean finalType = isMonomorphic(elemClass);
if (finalType) {
if (trackingRef) {
builder.add(
writeContainerElements(elementType, true, null, null, buffer, collection, size));
} else {
Literal hasNullFlag = ofInt(CollectionFlags.HAS_NULL);
Expression hasNull = eq(new BitAnd(flags, hasNullFlag), hasNullFlag, "hasNull");
builder.add(
hasNull,
writeContainerElements(elementType, false, null, hasNull, buffer, collection, size));
}
} else {
Literal flag = ofInt(CollectionFlags.NOT_SAME_TYPE);
Expression sameElementClass = neq(new BitAnd(flags, flag), flag, "sameElementClass");
builder.add(sameElementClass);
// if ((flags & Flags.NOT_DECL_ELEMENT_TYPE) == Flags.NOT_DECL_ELEMENT_TYPE)
Literal notDeclTypeFlag = ofInt(CollectionFlags.NOT_DECL_ELEMENT_TYPE);
Expression isDeclType = neq(new BitAnd(flags, notDeclTypeFlag), notDeclTypeFlag);
Expression elemSerializer; // make it in scope of `if(sameElementClass)`
boolean maybeDecl = visitFury(f -> f.getClassResolver().isSerializable(elemClass));
TypeRef<?> serializerType = getSerializerType(elementType);
if (maybeDecl) {
elemSerializer =
new If(
isDeclType,
cast(getOrCreateSerializer(elemClass), serializerType),
cast(writeElementsHeader.f1.inline(), serializerType),
false,
serializerType);
} else {
elemSerializer = cast(writeElementsHeader.f1.inline(), serializerType);
}
elemSerializer = uninline(elemSerializer);
Expression action;
if (trackingRef) {
ListExpression writeBuilder = new ListExpression(elemSerializer);
writeBuilder.add(
writeContainerElements(
elementType, true, elemSerializer, null, buffer, collection, size));
Set<Expression> cutPoint = ofHashSet(buffer, collection, size);
if (maybeDecl) {
cutPoint.add(flags);
}
action =
new If(
sameElementClass,
invokeGenerated(ctx, cutPoint, writeBuilder, "sameElementClassWrite", false),
writeContainerElements(elementType, true, null, null, buffer, collection, size));
} else {
Literal hasNullFlag = ofInt(CollectionFlags.HAS_NULL);
Expression hasNull = eq(new BitAnd(flags, hasNullFlag), hasNullFlag, "hasNull");
builder.add(hasNull);
ListExpression writeBuilder = new ListExpression(elemSerializer);
writeBuilder.add(
writeContainerElements(
elementType, false, elemSerializer, hasNull, buffer, collection, size));
Set<Expression> cutPoint = ofHashSet(buffer, collection, size, hasNull);
if (maybeDecl) {
cutPoint.add(flags);
}
action =
new If(
sameElementClass,
invokeGenerated(ctx, cutPoint, writeBuilder, "sameElementClassWrite", false),
writeContainerElements(
elementType, false, null, hasNull, buffer, collection, size));
}
builder.add(action);
}
walkPath.removeLast();
return new ListExpression(onCollectionWrite, new If(gt(size, ofInt(0)), builder));
}