Skip to content

Commit

Permalink
refactor record wrapper instantiation
Browse files Browse the repository at this point in the history
  • Loading branch information
osiegmar committed Jan 9, 2024
1 parent b97099d commit b803f23
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import ch.randelshofer.fastdoubleparser.JavaDoubleParser;
import de.siegmar.fastcsv.reader.AbstractBaseCsvCallbackHandler;
import de.siegmar.fastcsv.reader.CsvReader;
import de.siegmar.fastcsv.reader.RecordWrapper;
import de.siegmar.fastcsv.writer.CsvWriter;

/**
Expand Down Expand Up @@ -170,7 +171,7 @@ private static double parseDouble(final char[] buf, final int offset, final int
}

@Override
public Measurement build() {
protected RecordWrapper<Measurement> buildRecord() {
if (recordCount++ == 0) {
// Skip header
return null;
Expand All @@ -181,7 +182,7 @@ public Measurement build() {
.formatted(getFieldCount(), getStartingLineNumber()));
}

return new Measurement(id, timestamp, latitude, longitude, temperature);
return wrapRecord(new Measurement(id, timestamp, latitude, longitude, temperature));
}

}
Expand All @@ -204,6 +205,7 @@ public String toString() {
return "Measured %.1f°C (%.1f°F) on station %d at %s - see: %s".formatted(
temperature, fahrenheit(), id, Instant.ofEpochMilli(timestamp), mapLocation());
}

}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package de.siegmar.fastcsv.reader;

import java.util.Objects;

/**
* Base class for {@link CsvCallbackHandler} implementations that handles their own field storage and record building.
* <p>
* This implementation is stateful and must not be reused.
*
* @param <T> the type of the record
*/
public abstract class AbstractBaseCsvCallbackHandler<T> implements CsvCallbackHandler<T> {
public abstract class AbstractBaseCsvCallbackHandler<T> extends CsvCallbackHandler<T> {

private long startingLineNumber;
private boolean comment;
Expand All @@ -27,7 +29,7 @@ protected AbstractBaseCsvCallbackHandler() {
*
* @return the starting line number of the current record
*/
public long getStartingLineNumber() {
protected long getStartingLineNumber() {
return startingLineNumber;
}

Expand All @@ -36,7 +38,7 @@ public long getStartingLineNumber() {
*
* @return {@code true} if the current record is a comment
*/
public boolean isComment() {
protected boolean isComment() {
return comment;
}

Expand All @@ -45,7 +47,7 @@ public boolean isComment() {
*
* @return {@code true} if the current record is an empty line
*/
public boolean isEmptyLine() {
protected boolean isEmptyLine() {
return emptyLine;
}

Expand All @@ -54,7 +56,7 @@ public boolean isEmptyLine() {
*
* @return the number of fields in the current record
*/
public int getFieldCount() {
protected int getFieldCount() {
return fieldCount;
}

Expand All @@ -64,7 +66,7 @@ public int getFieldCount() {
*/
@SuppressWarnings("checkstyle:HiddenField")
@Override
public final void beginRecord(final long startingLineNumber) {
protected final void beginRecord(final long startingLineNumber) {
this.startingLineNumber = startingLineNumber;
fieldCount = 0;
comment = false;
Expand All @@ -90,7 +92,7 @@ protected void handleBegin(final long startingLineNumber) {
* {@link #emptyLine} flag and before incrementing the {@link #fieldCount}.
*/
@Override
public final void addField(final char[] buf, final int offset, final int len, final boolean quoted) {
protected final void addField(final char[] buf, final int offset, final int len, final boolean quoted) {
emptyLine = emptyLine && len == 0;
handleField(fieldCount++, buf, offset, len, quoted);
}
Expand All @@ -99,6 +101,8 @@ public final void addField(final char[] buf, final int offset, final int len, fi
* Handles a field.
* <p>
* This method is called for each field in the record.
* <p>
* See {@link CsvCallbackHandler#addField(char[], int, int, boolean)} for more details on the parameters.
*
* @param fieldIdx the index of the field in the record (starting with 0)
* @param buf the internal buffer that contains the field value (among other data)
Expand All @@ -117,7 +121,7 @@ protected void handleField(final int fieldIdx, final char[] buf, final int offse
* and {@link #emptyLine} flag and before incrementing the {@link #fieldCount}.
*/
@Override
public final void setComment(final char[] buf, final int offset, final int len) {
protected final void setComment(final char[] buf, final int offset, final int len) {
comment = true;
emptyLine = false;
handleComment(buf, offset, len);
Expand All @@ -128,6 +132,8 @@ public final void setComment(final char[] buf, final int offset, final int len)
* Handles a comment.
* <p>
* This method is called for each comment line.
* <p>
* See {@link CsvCallbackHandler#setComment(char[], int, int)} for more details on the parameters.
*
* @param buf the internal buffer that contains the field value (among other data)
* @param offset the offset of the field value in the buffer
Expand All @@ -137,21 +143,16 @@ protected void handleComment(final char[] buf, final int offset, final int len)
}

/**
* {@inheritDoc}
* <p>
* This implementation creates a {@link RecordWrapper} with the current {@link #comment}, {@link #emptyLine} and
* {@link #fieldCount} and delegates the creation of the actual record to {@link #build()}.
*/
@Override
public final RecordWrapper<T> buildRecord() {
return new RecordWrapper<>(comment, emptyLine, fieldCount, build());
}

/**
* Builds the record.
* Builds a wrapper for the record that contains information necessary for the {@link CsvReader} in order to
* determine how to process the record.
*
* @return the record, or {@code null} if the record is to be skipped
* @param record the actual record to be returned by the {@link CsvReader}, must not be {@code null}
* @return the wrapper for the actual record
* @throws NullPointerException if {@code null} is passed for {@code record}
*/
protected abstract T build();
protected RecordWrapper<T> wrapRecord(final T record) {
return new RecordWrapper<>(comment, emptyLine, fieldCount,
Objects.requireNonNull(record, "record must not be null"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @param <T> the type of the resulting records
*/
abstract class AbstractCsvCallbackHandler<T> implements CsvCallbackHandler<T> {
abstract class AbstractCsvCallbackHandler<T> extends CsvCallbackHandler<T> {

private static final int INITIAL_FIELDS_SIZE = 32;

Expand Down Expand Up @@ -40,7 +40,7 @@ abstract class AbstractCsvCallbackHandler<T> implements CsvCallbackHandler<T> {
/**
* The current index in the internal fields array.
*/
protected int idx;
protected int fieldIdx;

/**
* Whether the current record is a comment.
Expand Down Expand Up @@ -76,9 +76,9 @@ protected AbstractCsvCallbackHandler(final FieldModifier fieldModifier) {
*/
@SuppressWarnings("checkstyle:HiddenField")
@Override
public void beginRecord(final long startingLineNumber) {
protected void beginRecord(final long startingLineNumber) {
this.startingLineNumber = startingLineNumber;
idx = 0;
fieldIdx = 0;
recordSize = 0;
comment = false;
}
Expand All @@ -91,7 +91,7 @@ public void beginRecord(final long startingLineNumber) {
* @throws CsvParseException if the addition exceeds the limit of record size or maximum fields count.
*/
@Override
public void addField(final char[] buf, final int offset, final int len, final boolean quoted) {
protected void addField(final char[] buf, final int offset, final int len, final boolean quoted) {
if (recordSize + len > Limits.MAX_RECORD_SIZE) {
throw new CsvParseException(maxRecordSizeExceededMessage(startingLineNumber));
}
Expand All @@ -108,11 +108,11 @@ public void addField(final char[] buf, final int offset, final int len, final bo
* @throws CsvParseException if the addition exceeds the maximum fields count.
*/
protected void addField(final String value, final boolean quoted) {
if (idx == fields.length) {
if (fieldIdx == fields.length) {
extendCapacity();
}

fields[idx++] = value;
fields[fieldIdx++] = value;
recordSize += value.length();
}

Expand All @@ -124,7 +124,7 @@ protected void addField(final String value, final boolean quoted) {
* @return the modified field value
*/
protected String modifyField(final String value, final boolean quoted) {
return fieldModifier.modify(startingLineNumber, idx, quoted, value);
return fieldModifier.modify(startingLineNumber, fieldIdx, quoted, value);
}

/**
Expand Down Expand Up @@ -152,8 +152,8 @@ private static String maxRecordSizeExceededMessage(final long line) {
* @throws CsvParseException if the addition exceeds the limit of record size.
*/
@Override
public void setComment(final char[] buf, final int offset, final int len) {
if (idx != 0) {
protected void setComment(final char[] buf, final int offset, final int len) {
if (fieldIdx != 0) {
// Can't happen with the current implementation of CsvParser
throw new IllegalStateException("Comment must be the first and only field in a record");
}
Expand All @@ -177,7 +177,7 @@ public void setComment(final char[] buf, final int offset, final int len) {
protected void setComment(final String value) {
recordSize += value.length();
comment = true;
fields[idx++] = value;
fields[fieldIdx++] = value;
}

/**
Expand Down Expand Up @@ -208,33 +208,33 @@ private void extendCapacity() {
throw new CsvParseException("Maximum number of fields exceeded: " + Limits.MAX_FIELD_COUNT);
}
final String[] newFields = new String[newLen];
System.arraycopy(fields, 0, newFields, 0, idx);
System.arraycopy(fields, 0, newFields, 0, fieldIdx);
fields = newFields;
}

/**
* {@inheritDoc}
* Builds a compact fields array (a copy of the internal fields array with the length of the current record).
* <p>
* This method creates a compact copy of the internal fields array and passes it to
* {@link #buildRecord(String[])}.
* In contrast to the class property {@link #fields}, the returned array does only contain the fields of the
* current record.
*
* @return the compact fields array
*/
@Override
public RecordWrapper<T> buildRecord() {
final String[] ret = new String[idx];
System.arraycopy(fields, 0, ret, 0, idx);
return new RecordWrapper<>(comment, recordSize == 0, idx, buildRecord(ret));
protected String[] compactFields() {
final String[] ret = new String[fieldIdx];
System.arraycopy(fields, 0, ret, 0, fieldIdx);
return ret;
}

/**
* Builds a record from the given compact fields array.
* <p>
* In contrast to the class property {@link #fields}, the given {@code compactFields} argument does only contain
* the fields of the current record (copied by {@link #buildRecord()}).
* Builds a record wrapper for the given record.
*
* @param compactFields the compact fields array
* @return the record
* @param rec the record, must not be {@code null}
* @return the record wrapper
* @throws NullPointerException if {@code rec} is {@code null}
*/
@SuppressWarnings({"PMD.UseVarargs", "checkstyle:HiddenField"})
protected abstract T buildRecord(String[] compactFields);
protected RecordWrapper<T> buildWrapper(final T rec) {
return new RecordWrapper<>(comment, recordSize == 0, fieldIdx, rec);
}

}
Loading

0 comments on commit b803f23

Please sign in to comment.