private Entry writeJavaChunkGeneric()

in java/fury-core/src/main/java/org/apache/fury/serializer/collection/AbstractMapSerializer.java [344:448]


  private Entry writeJavaChunkGeneric(
      TypeResolver classResolver,
      Generics generics,
      GenericType genericType,
      MemoryBuffer buffer,
      Entry<Object, Object> entry,
      Iterator<Entry<Object, Object>> iterator) {
    // type parameters count for `Map field` will be 0;
    // type parameters count for `SubMap<V> field` which SubMap is
    // `SubMap<V> implements Map<String, V>` will be 1;
    if (genericType.getTypeParametersCount() < 2) {
      genericType = getKVGenericType(genericType);
    }
    GenericType keyGenericType = genericType.getTypeParameter0();
    GenericType valueGenericType = genericType.getTypeParameter1();
    if (keyGenericType == objType && valueGenericType == objType) {
      return writeJavaChunk(classResolver, buffer, entry, iterator, null, null);
    }
    // Can't avoid push generics repeatedly in loop by stack depth, because push two
    // generic type changed generics stack top, which is depth index, update stack top
    // and depth will have some cost too.
    // Stack depth to avoid push generics repeatedly in loop.
    // Note push two generic type changed generics stack top, which is depth index,
    // stack top should be updated when using for serialization k/v.
    // int depth = fury.getDepth();
    // // depth + 1 to leave a slot for value generics, otherwise value generics will
    // // be overwritten by nested key generics.
    // fury.setDepth(depth + 1);
    // generics.pushGenericType(keyGenericType);
    // fury.setDepth(depth);
    // generics.pushGenericType(valueGenericType);
    boolean keyGenericTypeFinal = keyGenericType.isMonomorphic();
    boolean valueGenericTypeFinal = valueGenericType.isMonomorphic();
    Object key = entry.getKey();
    Object value = entry.getValue();
    Class keyType = key.getClass();
    Class valueType = value.getClass();
    Serializer keySerializer, valueSerializer;
    // place holder for chunk header and size.
    buffer.writeInt16((short) -1);
    int chunkSizeOffset = buffer.writerIndex() - 1;
    int chunkHeader = 0;
    // noinspection Duplicates
    if (keyGenericTypeFinal) {
      chunkHeader |= KEY_DECL_TYPE;
      keySerializer = keyGenericType.getSerializer(classResolver);
    } else {
      keySerializer = writeKeyClassInfo(classResolver, keyType, buffer);
    }
    if (valueGenericTypeFinal) {
      chunkHeader |= VALUE_DECL_TYPE;
      valueSerializer = valueGenericType.getSerializer(classResolver);
    } else {
      valueSerializer = writeValueClassInfo(classResolver, valueType, buffer);
    }
    boolean keyWriteRef = keySerializer.needToWriteRef();
    if (keyWriteRef) {
      chunkHeader |= TRACKING_KEY_REF;
    }
    boolean valueWriteRef = valueSerializer.needToWriteRef();
    if (valueWriteRef) {
      chunkHeader |= TRACKING_VALUE_REF;
    }
    buffer.putByte(chunkSizeOffset - 1, (byte) chunkHeader);
    RefResolver refResolver = fury.getRefResolver();
    // Use int to make chunk size representable for 0~255 instead of 0~127.
    int chunkSize = 0;
    while (true) {
      if (key == null
          || value == null
          || (key.getClass() != keyType)
          || (value.getClass() != valueType)) {
        break;
      }
      generics.pushGenericType(keyGenericType);
      if (!keyWriteRef || !refResolver.writeRefOrNull(buffer, key)) {
        fury.incDepth(1);
        binding.write(buffer, keySerializer, key);
        fury.incDepth(-1);
      }
      generics.popGenericType();
      generics.pushGenericType(valueGenericType);
      if (!valueWriteRef || !refResolver.writeRefOrNull(buffer, value)) {
        fury.incDepth(1);
        binding.write(buffer, valueSerializer, value);
        fury.incDepth(-1);
      }
      generics.popGenericType();
      ++chunkSize;
      // noinspection Duplicates
      if (iterator.hasNext()) {
        entry = iterator.next();
        key = entry.getKey();
        value = entry.getValue();
      } else {
        entry = null;
        break;
      }
      if (chunkSize == MAX_CHUNK_SIZE) {
        break;
      }
    }
    buffer.putByte(chunkSizeOffset, (byte) chunkSize);
    return entry;
  }