Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert Value to interface, extract functionality to CoreValue and create a NotAValue class #282

Merged
merged 18 commits into from
Feb 16, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f3db1f8
#280: Changed Value into an interface, extracted functionality into C…
jvdb Feb 7, 2019
9732725
#280: Moved NOT_A_VALUE from CoreValue back to Value.
jvdb Feb 7, 2019
34ccd75
#280: Created NotAValue class.
jvdb Feb 7, 2019
33d8584
#280: Replaced reference checks on NOT_A_VALUE with calls to equals().
jvdb Feb 8, 2019
5b066d4
#280: Added and adapted unit tests for NotAValue.
jvdb Feb 10, 2019
0755624
#280: Added missing license header.
jvdb Feb 10, 2019
87e0260
#280: Made the NotAValue class final to ensure uniqueness of NOT_A_VA…
jvdb Feb 11, 2019
a0699f6
#70: Added SingleValueExpression interface. Converted size argument o…
jvdb Feb 11, 2019
51c1986
#70: Converted n argument of RepN to SingleValueExpression, along wit…
jvdb Feb 11, 2019
b74a111
#70: Converted Expand, Count, CurrentIteration, CurrentOffset, First …
jvdb Feb 11, 2019
d7543b4
#70: Converted the initial argument to the various Fold ValueExpressi…
jvdb Feb 11, 2019
b731301
#70: Converted type of SELF in Shorthand.
jvdb Feb 11, 2019
a690989
#70: Resolved variable name shadowing.
jvdb Feb 12, 2019
3deb451
#70: Converted all Fold operations to SingleValueExpression.
jvdb Feb 12, 2019
60fedd2
#70: Handled review comments from @rdvdijk and @ccreeten.
jvdb Feb 16, 2019
1744fda
Merge pull request #283 from parsingdata/single-value-expression
jvdb Feb 16, 2019
b712149
#280: Fixed stack trace issue with exceptions thrown from NotAValue b…
jvdb Feb 16, 2019
6480c62
#280: Renamed and fixed spacing between interface/abstract methods. B…
jvdb Feb 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core/src/main/java/io/parsingdata/metal/Shorthand.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import io.parsingdata.metal.expression.value.Cat;
import io.parsingdata.metal.expression.value.Const;
import io.parsingdata.metal.expression.value.ConstantFactory;
import io.parsingdata.metal.expression.value.CoreValue;
import io.parsingdata.metal.expression.value.Elvis;
import io.parsingdata.metal.expression.value.Expand;
import io.parsingdata.metal.expression.value.FoldCat;
Expand Down Expand Up @@ -176,7 +177,7 @@ private Shorthand() {}
public static ValueExpression con(final String value) { return con(value, DEFAULT_ENCODING); }
public static ValueExpression con(final String value, final Encoding encoding) { return con(ConstantFactory.createFromString(value, encoding)); }
public static ValueExpression con(final Value value) { return new Const(value); }
public static ValueExpression con(final Encoding encoding, final int... values) { return new Const(new Value(createFromBytes(toByteArray(values)), encoding)); }
public static ValueExpression con(final Encoding encoding, final int... values) { return new Const(new CoreValue(createFromBytes(toByteArray(values)), encoding)); }
public static ValueExpression con(final int... values) { return con(DEFAULT_ENCODING, values); }
public static ValueExpression con(final byte[] value) { return con(value, DEFAULT_ENCODING); }
public static ValueExpression con(final byte[] value, final Encoding encoding) { return con(ConstantFactory.createFromBytes(value, encoding)); }
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/io/parsingdata/metal/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.parsingdata.metal.data.ParseState;
import io.parsingdata.metal.data.Slice;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.value.CoreValue;
import io.parsingdata.metal.expression.value.UnaryValueExpression;
import io.parsingdata.metal.expression.value.Value;
import io.parsingdata.metal.expression.value.ValueExpression;
Expand Down Expand Up @@ -105,7 +106,7 @@ public Optional<Value> eval(final Value value, final ParseState parseState, fina
return Optional.empty();
}
}
return Optional.of(new Value(Slice.createFromBytes(out.toByteArray()), encoding));
return Optional.of(new CoreValue(Slice.createFromBytes(out.toByteArray()), encoding));
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.Util.format;
import static io.parsingdata.metal.data.Selection.reverse;
import static io.parsingdata.metal.expression.value.Value.NOT_A_VALUE;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.math.BigInteger;
import java.util.Objects;
Expand Down Expand Up @@ -61,10 +61,10 @@ private static Trampoline<BigInteger> calculateTotalSize(final ImmutableList<Val
if (values.isEmpty()) {
return complete(() -> size);
}
if (values.head == NOT_A_VALUE) {
if (values.head.equals(NOT_A_VALUE)) {
return complete(() -> ZERO);
}
return intermediate(() -> calculateTotalSize(values.tail, size.add(values.head.slice.length)));
return intermediate(() -> calculateTotalSize(values.tail, size.add(values.head.getSlice().length)));
}

@Override
Expand All @@ -79,13 +79,13 @@ private Trampoline<byte[]> getData(final ImmutableList<Value> values, final BigI
if (length.compareTo(ZERO) <= 0) {
return complete(() -> output);
}
if (currentOffset.add(values.head.slice.length).compareTo(offset) <= 0) {
return intermediate(() -> getData(values.tail, currentOffset.add(values.head.slice.length), currentDest, offset, length, output));
if (currentOffset.add(values.head.getSlice().length).compareTo(offset) <= 0) {
return intermediate(() -> getData(values.tail, currentOffset.add(values.head.getSlice().length), currentDest, offset, length, output));
}
final BigInteger localOffset = offset.subtract(currentOffset).compareTo(ZERO) < 0 ? ZERO : offset.subtract(currentOffset);
final BigInteger toCopy = length.compareTo(values.head.slice.length.subtract(localOffset)) > 0 ? values.head.slice.length.subtract(localOffset) : length;
System.arraycopy(values.head.slice.getData(), localOffset.intValueExact(), output, currentDest.intValueExact(), toCopy.intValueExact());
return intermediate(() -> getData(values.tail, currentOffset.add(values.head.slice.length), currentDest.add(toCopy), offset, length.subtract(toCopy), output));
final BigInteger toCopy = length.compareTo(values.head.getSlice().length.subtract(localOffset)) > 0 ? values.head.getSlice().length.subtract(localOffset) : length;
System.arraycopy(values.head.getSlice().getData(), localOffset.intValueExact(), output, currentDest.intValueExact(), toCopy.intValueExact());
return intermediate(() -> getData(values.tail, currentOffset.add(values.head.getSlice().length), currentDest.add(toCopy), offset, length.subtract(toCopy), output));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static io.parsingdata.metal.Util.checkNotNegative;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.Util.format;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.math.BigInteger;
import java.util.Objects;
Expand Down Expand Up @@ -71,7 +72,7 @@ private synchronized byte[] getValue() {
throw new IllegalStateException(format("ValueExpression dataExpression must yield at least %d results.", index+1));
}
final Value cacheValue = getValueAtIndex(results, index, 0).computeResult();
if (cacheValue == Value.NOT_A_VALUE) {
if (cacheValue.equals(NOT_A_VALUE)) {
throw new IllegalStateException(format("ValueExpression dataExpression yields empty Value at index %d.", index));
}
cache = cacheValue.getValue();
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/io/parsingdata/metal/data/ParseValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
import java.util.Objects;

import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.value.Value;
import io.parsingdata.metal.expression.value.CoreValue;
import io.parsingdata.metal.token.Token;

public class ParseValue extends Value implements ParseItem {
public class ParseValue extends CoreValue implements ParseItem {

public final String name;
public final Token definition;
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/io/parsingdata/metal/data/Selection.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static Trampoline<Optional<ParseItem>> findItemAtOffset(final ImmutableLi
}

private static boolean matchesLocation(final ParseValue value, final BigInteger offset, final Source source) {
return value.slice.offset.compareTo(offset) == 0 && value.slice.source.equals(source);
return value.getSlice().offset.compareTo(offset) == 0 && value.getSlice().source.equals(source);
}

private static Trampoline<ParseValue> getLowestOffsetValue(final ImmutableList<ParseGraph> graphList, final ParseValue lowest) {
Expand All @@ -77,7 +77,7 @@ private static ParseValue compareIfValue(final ParseValue lowest, final ParseIte
}

private static ParseValue getLowest(final ParseValue lowest, final ParseValue value) {
return lowest == null || lowest.slice.offset.compareTo(value.slice.offset) > 0 ? value : lowest;
return lowest == null || lowest.getSlice().offset.compareTo(value.getSlice().offset) > 0 ? value : lowest;
}

private static ImmutableList<ParseGraph> addIfGraph(final ImmutableList<ParseGraph> graphList, final ParseItem head) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import static io.parsingdata.metal.Trampoline.complete;
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.expression.value.Value.NOT_A_VALUE;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.util.Objects;

Expand Down Expand Up @@ -68,7 +68,7 @@ public boolean eval(final ParseState parseState, final Encoding encoding) {
}

private Trampoline<Boolean> compare(final ImmutableList<Value> currents, final ImmutableList<Value> predicates) {
if (currents.head == NOT_A_VALUE || predicates.head == NOT_A_VALUE) {
if (currents.head.equals(NOT_A_VALUE) || predicates.head.equals(NOT_A_VALUE)) {
return complete(() -> false);
}
final boolean headResult = compare(currents.head, predicates.head);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public Eq(final ValueExpression value, final ValueExpression predicate) {

@Override
public boolean compare(final Value left, final Value right) {
return left.slice.length.compareTo(right.slice.length) == 0
return left.getSlice().length.compareTo(right.getSlice().length) == 0
&& Arrays.equals(left.getValue(), right.getValue());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.data.Selection.reverse;
import static io.parsingdata.metal.expression.value.Value.NOT_A_VALUE;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -88,7 +88,7 @@ private Trampoline<ImmutableList<Value>> padList(final ImmutableList<Value> list
}

private Value checkEval(final Value leftValue, final Value rightValue, final ParseState parseState, final Encoding encoding) {
if (leftValue == NOT_A_VALUE || rightValue == NOT_A_VALUE) {
if (leftValue.equals(NOT_A_VALUE) || rightValue.equals(NOT_A_VALUE)) {
return NOT_A_VALUE;
}
return eval(leftValue, rightValue, parseState, encoding).orElse(NOT_A_VALUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.data.Slice.createFromSource;
import static io.parsingdata.metal.expression.value.Value.NOT_A_VALUE;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.math.BigInteger;
import java.util.Objects;
Expand Down Expand Up @@ -71,10 +71,10 @@ private Trampoline<ImmutableList<Value>> toByteValues(final ImmutableList<Value>
}

private Trampoline<ImmutableList<Value>> extractByteValues(final ImmutableList<Value> output, final Value value, final int i, final Encoding encoding) {
if (value == NOT_A_VALUE || BigInteger.valueOf(i).compareTo(value.getLength()) >= 0) {
if (value.equals(NOT_A_VALUE) || BigInteger.valueOf(i).compareTo(value.getLength()) >= 0) {
return complete(() -> output);
}
return intermediate(() -> extractByteValues(output.add(new Value(createFromSource(value.slice.source, value.slice.offset.add(BigInteger.valueOf(i)), ONE).get(), encoding)), value, i + 1, encoding));
return intermediate(() -> extractByteValues(output.add(new CoreValue(createFromSource(value.getSlice().source, value.getSlice().offset.add(BigInteger.valueOf(i)), ONE).get(), encoding)), value, i + 1, encoding));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public Cat(final ValueExpression left, final ValueExpression right) {
public Optional<Value> eval(final Value leftValue, final Value rightValue, final ParseState parseState, final Encoding encoding) {
return ConcatenatedValueSource.create(ImmutableList.create(leftValue).add(rightValue))
.flatMap(source -> createFromSource(source, ZERO, leftValue.getLength().add(rightValue.getLength())))
.map(source -> new Value(source, encoding));
.map(source -> new CoreValue(source, encoding));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public final class ConstantFactory {
private ConstantFactory() {}

public static Value createFromBytes(final byte[] value, final Encoding encoding) {
return new Value(Slice.createFromBytes(value), encoding);
return new CoreValue(Slice.createFromBytes(value), encoding);
}

public static Value createFromNumeric(final BigInteger value, final Encoding encoding) {
Expand All @@ -41,14 +41,14 @@ public static Value createFromNumeric(final long value, final Encoding encoding)
}

public static Value createFromString(final String value, final Encoding encoding) {
return new Value(Slice.createFromBytes(value.getBytes(encoding.charset)), encoding);
return new CoreValue(Slice.createFromBytes(value.getBytes(encoding.charset)), encoding);
}

public static Value createFromBitSet(final BitSet value, final int minSize, final Encoding encoding) {
final byte[] bytes = ByteOrder.LITTLE_ENDIAN.apply(value.toByteArray());
final byte[] outBytes = new byte[Math.max(minSize, bytes.length)];
System.arraycopy(bytes, 0, outBytes, outBytes.length - bytes.length, bytes.length);
return new Value(Slice.createFromBytes(outBytes), setToBigEndian(encoding));
return new CoreValue(Slice.createFromBytes(outBytes), setToBigEndian(encoding));
}

private static Encoding setToBigEndian(final Encoding encoding) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2013-2016 Netherlands Forensic Institute
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.parsingdata.metal.expression.value;

import static io.parsingdata.metal.Util.bytesToHexString;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.encoding.Encoding.DEFAULT_ENCODING;

import java.math.BigInteger;
import java.util.BitSet;
import java.util.Objects;

import io.parsingdata.metal.Util;
import io.parsingdata.metal.data.Slice;
import io.parsingdata.metal.encoding.ByteOrder;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.encoding.Sign;

public class CoreValue implements Value {
jvdb marked this conversation as resolved.
Show resolved Hide resolved

public static final BigInteger TO_STRING_BYTE_COUNT = BigInteger.valueOf(4);

private final Slice slice;
private final Encoding encoding;

public CoreValue(final Slice slice, final Encoding encoding) {
this.slice = checkNotNull(slice, "slice");
this.encoding = checkNotNull(encoding, "encoding");
}

@Override
public Slice getSlice() {
return slice;
}

@Override
public Encoding getEncoding() {
return encoding;
}

@Override
public byte[] getValue() {
return slice.getData();
}

@Override
public BigInteger getLength() {
return slice.length;
}

@Override
public BigInteger asNumeric() {
return encoding.sign == Sign.SIGNED ? new BigInteger(encoding.byteOrder.apply(getValue()))
: new BigInteger(1, encoding.byteOrder.apply(getValue()));
}

@Override
public String asString() {
return new String(getValue(), encoding.charset);
}

@Override
public BitSet asBitSet() {
return BitSet.valueOf(encoding.byteOrder == ByteOrder.BIG_ENDIAN ? ByteOrder.LITTLE_ENDIAN.apply(getValue()) : getValue());
}

@Override
public String toString() {
return "0x" + bytesToHexString(slice.getData(TO_STRING_BYTE_COUNT)) + (getLength().compareTo(TO_STRING_BYTE_COUNT) > 0 ? "..." : "");
}

@Override
public boolean equals(final Object obj) {
return Util.notNullAndSameClass(this, obj)
&& Objects.equals(slice, ((CoreValue)obj).slice)
&& Objects.equals(encoding, ((CoreValue)obj).encoding);
}

@Override
public int hashCode() {
return Objects.hash(getClass(), slice, encoding);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.data.Selection.reverse;
import static io.parsingdata.metal.expression.value.Value.NOT_A_VALUE;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -65,7 +65,7 @@ private Trampoline<ImmutableList<Value>> eval(final ImmutableList<Value> result,
if (rightValues.isEmpty()) {
return complete(() -> result.add(reverse(leftValues)));
}
return intermediate(() -> eval(result.add(leftValues.head != NOT_A_VALUE ? leftValues.head : rightValues.head), leftValues.tail, rightValues.tail));
return intermediate(() -> eval(result.add(leftValues.head.equals(NOT_A_VALUE) ? rightValues.head : leftValues.head), leftValues.tail, rightValues.tail));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import static io.parsingdata.metal.Trampoline.complete;
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.expression.value.Value.NOT_A_VALUE;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.util.Objects;

Expand Down Expand Up @@ -57,7 +57,7 @@ public ImmutableList<Value> eval(final ParseState parseState, final Encoding enc
return baseList;
}
final ImmutableList<Value> countList = count.eval(parseState, encoding);
if (countList.size != 1 || countList.head == NOT_A_VALUE) {
if (countList.size != 1 || countList.head.equals(NOT_A_VALUE)) {
throw new IllegalArgumentException("Count must evaluate to a single non-empty value.");
}
return expand(baseList, countList.head.asNumeric().intValueExact(), new ImmutableList<>()).computeResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import static io.parsingdata.metal.Trampoline.complete;
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.expression.value.Value.NOT_A_VALUE;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.util.Objects;
import java.util.function.BinaryOperator;
Expand Down Expand Up @@ -59,7 +59,7 @@ public Fold(final ValueExpression values, final BinaryOperator<ValueExpression>
@Override
public ImmutableList<Value> eval(final ParseState parseState, final Encoding encoding) {
final ImmutableList<Value> initialList = initial != null ? initial.eval(parseState, encoding) : new ImmutableList<>();
if (initialList.size > 1 || initialList.head == NOT_A_VALUE) {
if (initialList.size > 1 || (!initialList.isEmpty() && initialList.head.equals(NOT_A_VALUE))) {
return ImmutableList.create(NOT_A_VALUE);
}
final ImmutableList<Value> unpreparedValues = this.values.eval(parseState, encoding);
Expand All @@ -74,7 +74,7 @@ public ImmutableList<Value> eval(final ParseState parseState, final Encoding enc
}

private Trampoline<Value> fold(final ParseState parseState, final Encoding encoding, final BinaryOperator<ValueExpression> reducer, final Value head, final ImmutableList<Value> tail) {
if (head == NOT_A_VALUE) {
if (head.equals(NOT_A_VALUE)) {
return complete(() -> NOT_A_VALUE);
}
if (tail.isEmpty()) {
Expand All @@ -91,7 +91,7 @@ private Trampoline<Boolean> containsNotAValue(final ImmutableList<Value> list) {
if (list.isEmpty()) {
return complete(() -> false);
}
if (list.head != NOT_A_VALUE) {
if (!list.head.equals(NOT_A_VALUE)) {
return intermediate(() -> containsNotAValue(list.tail));
}
return complete(() -> true);
Expand Down
Loading