Skip to content

Commit

Permalink
fix(plc4j/codgen): implement array type reading with new readern
Browse files Browse the repository at this point in the history
  • Loading branch information
sruehl authored and chrisdutz committed Nov 17, 2021
1 parent 47764fe commit 1e819e6
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
<#-- TODO: Port this -->
<#case "array">
<#assign arrayField = field.asArrayField().orElseThrow()>

<#if arrayField.type.isByteBased()>
// Byte Array field (${arrayField.name})
<#assign numberOfBytesExpression>
Expand All @@ -169,138 +170,29 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<
byte[] ${arrayField.name} = readBuffer.readByteArray("${arrayField.name}", numberOfBytes);
<#else>
// Array field (${arrayField.name})
readBuffer.pullContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
<#-- Only update curPos if the length expression uses it -->
<#if arrayField.loopExpression.contains("curPos")>
curPos = readBuffer.getPos() - startPos;
</#if>
<#-- If this is a count array, we can directly initialize an array with the given size -->
<#if field.isCountArrayField()>
// Count array
if(${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)} > Integer.MAX_VALUE) {
throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
}
${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name};
{
int itemCount = Math.max(0, (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount];
for(int curItem = 0; curItem < itemCount; curItem++) {
<#-- When parsing simple types, there is nothing that could require the "lastItem" -->
<#if !helper.isSimpleTypeReference(arrayField.type)>boolean lastItem = curItem == (itemCount - 1);</#if>
<@compress single_line=true>
${arrayField.name}[curItem] =
<#if helper.isSimpleTypeReference(arrayField.type)>
${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
<#else>
${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
<#--if field.params.isPresent()>
,
<#list field.params.orElseThrow() as parserArgument>
<#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true) = 'String'>
${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}.valueOf(${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
<#else>
(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
</#if>
</#list>
</#if-->
<#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
<#-- We expose the parentParserArguments to the child here too-->
<#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
<#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
<#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
)
<#if helper.getTypeDefinitionForTypeReference(arrayField.type).isDiscriminatedChildTypeDefinition()>
.build()
</#if>
</#if>;
</@compress>
}
}
Object ${arrayField.name}Object = readCountArrayField(${helper.getLanguageTypeNameForField(field)}.class, "${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = (${helper.getLanguageTypeNameForField(field)}[]) ${arrayField.name}Object;
<#-- In all other cases do we have to work with a list, that is later converted to an array -->
<#else>
<#-- For a length array, we read data till the read position of the buffer reaches a given position -->
<#if field.isLengthArrayField()>
// Length array
long _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)};
List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
long ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length;
while(readBuffer.getPos() < ${arrayField.name}EndPos) {
<@compress single_line=true>
_${arrayField.name}List.add(
<#if helper.isSimpleTypeReference(arrayField.type)>
${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
<#else>
${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
<#--if field.params.isPresent()>
,
<#list field.params.orElseThrow() as parserArgument>
(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
(${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
</#list>
</#if-->
<#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
<#-- We expose the parentParserArguments to the child here too-->
<#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
<#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
<#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
)
</#if>
);
</@compress>
<#-- After parsing, update the current position, but only if it's needed -->
<#if arrayField.loopExpression.contains("curPos")>
curPos = readBuffer.getPos() - startPos;
</#if>
}
Object ${arrayField.name}Object = readLengthArrayField(${helper.getLanguageTypeNameForField(field)}.class, "${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)});
${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = (${helper.getLanguageTypeNameForField(field)}[]) ${arrayField.name}Object;
<#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
<#elseif field.isTerminatedArrayField()>
// Terminated array
List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>();
while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)}))) {
<@compress single_line=true>
_${arrayField.name}List.add(
<#if helper.isSimpleTypeReference(arrayField.type)>
${helper.getReadBufferReadMethodCall("", arrayField.type.asSimpleTypeReference().orElseThrow(), "", arrayField)}
<#else>
${arrayField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer
<#--if field.params.isPresent()>
,
<#list field.params.orElseThrow() as parserArgument>
(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)})
(${helper.toParseExpression(arrayField, parserArgument, parserArguments)})<#sep>, </#sep>
</#list>
</#if-->
<#assign typeDefinition=helper.getTypeDefinitionForTypeReference(arrayField.type)>
<#-- We expose the parentParserArguments to the child here too-->
<#assign hasParentParseArguments=typeDefinition.parentType?? && typeDefinition.parentType.parserArguments.isPresent()>
<#assign parentParseArguments><#if hasParentParseArguments><#list typeDefinition.parentType.parserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
<#if hasParentParseArguments>, ${tracer.dive("count array parent parse arguments")} ${parentParseArguments}</#if>
)
</#if>
);
</@compress>

<#-- After parsing, update the current position, but only if it's needed -->
<#if arrayField.loopExpression.contains("curPos")>
curPos = readBuffer.getPos() - startPos;
</#if>
}
</#if>
<#--
Convert the list into an array. However if the array is of a primitive
type we have to iterate over it's elements and explicitly cast them.
Otherwise a simple toArray call is fine.
-->
<#if helper.isSimpleTypeReference(arrayField.type)>
${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${arrayField.name}List.size()];
for(int i = 0; i < _${arrayField.name}List.size(); i++) {
${arrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${arrayField.name}List.get(i);
}
<#else>
${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]);
Object ${arrayField.name}Object = readTerminatedArrayField(${helper.getLanguageTypeNameForField(field)}.class, "${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, parserArguments)})));
${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = (${helper.getLanguageTypeNameForField(field)}[]) ${arrayField.name}Object;
</#if>
</#if>
readBuffer.closeContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true));
</#if>
<#break>
<#case "assert">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

public interface FieldReader<T> extends FieldCommons {

// TODO: this is useless here as you always operate on the concrete instance
T readField(String logicalName, DataReader<T> dataIO, WithReaderArgs... readerArgs) throws ParseException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,65 @@
*/
package org.apache.plc4x.java.spi.codegen.fields;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.plc4x.java.spi.codegen.io.DataReader;
import org.apache.plc4x.java.spi.generation.ParseException;
import org.apache.plc4x.java.spi.generation.WithReaderArgs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.plc4x.java.spi.generation.WithReaderWriterArgs;

public class FieldReaderArray<T> implements FieldReader<T> {
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Supplier;

private static final Logger LOGGER = LoggerFactory.getLogger(FieldReaderArray.class);
public class FieldReaderArray<T> implements FieldReader<T> {

@Override
public T readField(String logicalName, DataReader<T> dataReader, WithReaderArgs... readerArgs) throws ParseException {
return switchByteOrderIfNecessary(() -> dataReader.read(logicalName, readerArgs), dataReader, extractByteOder(readerArgs).orElse(null));
throw new NotImplementedException("use dedicated methods instead");
}

public T[] readFieldCount(String logicalName, DataReader<T> dataReader, int count, WithReaderArgs... readerArgs) throws ParseException {
return null;
public List<T> readFieldCount(String logicalName, DataReader<T> dataReader, long count, WithReaderArgs... readerArgs) throws ParseException {
if (count > Integer.MAX_VALUE) {
throw new ParseException("Array count of " + count + " exceeds the maximum allowed count of " + Integer.MAX_VALUE);
}
// Ensure we have the render as list argument present
readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
dataReader.pullContext(logicalName, readerArgs);
int itemCount = Math.max(0, (int) count);
List<T> result = new ArrayList<>(itemCount);
for (int curItem = 0; curItem < itemCount; curItem++) {
result.set(curItem, dataReader.read("", readerArgs));
}
dataReader.closeContext(logicalName, readerArgs);
return result;
}

public T[] readFieldLength(String logicalName, DataReader<T> dataReader, int length, WithReaderArgs... readerArgs) throws ParseException {
return null;
public List<T> readFieldLength(String logicalName, DataReader<T> dataReader, int length, WithReaderArgs... readerArgs) throws ParseException {
// Ensure we have the render as list argument present
readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
dataReader.pullContext(logicalName, readerArgs);
List<T> result = new LinkedList<>();
while (dataReader.getPos() < length) {
result.add(dataReader.read("", readerArgs));
}
dataReader.closeContext(logicalName, readerArgs);
return result;
}

public T[] readFieldTerminated(String logicalName, DataReader<T> dataReader, T termination, WithReaderArgs... readerArgs) throws ParseException {
return null;
public List<T> readFieldTerminated(String logicalName, DataReader<T> dataReader, Supplier<Boolean> termination, WithReaderArgs... readerArgs) throws ParseException {
// Ensure we have the render as list argument present
readerArgs = ArrayUtils.add(readerArgs, WithReaderWriterArgs.WithRenderAsList(true));
dataReader.pullContext(logicalName, readerArgs);
List<T> result = new LinkedList<>();
while (!termination.get()) {
result.add(dataReader.read("", readerArgs));
}
dataReader.closeContext(logicalName, readerArgs);
return result;
}

}
Loading

0 comments on commit 1e819e6

Please sign in to comment.