Skip to content

Commit

Permalink
Merge pull request #370 from gdgib/G2-1609-MoveReduceStrategy
Browse files Browse the repository at this point in the history
G2-1609 Move reduce strategy to alexandria
  • Loading branch information
gdgib authored Jul 12, 2024
2 parents 4de13fc + a9542e1 commit f3aa7d5
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.g2forge.alexandria.adt;

import java.util.Objects;

import com.g2forge.alexandria.java.core.error.UnreachableCodeError;
import com.g2forge.alexandria.java.function.IConsumer1;
import com.g2forge.alexandria.java.function.IFunction1;
import com.g2forge.alexandria.java.function.IFunction2;

/**
* Strategies for reducing fields of POJOs.
*/
public enum ReduceStrategy {
NullIsNone {
@Override
public <T, V> void reduce(T t0, T t1, IFunction1<? super T, ? extends V> getter, IConsumer1<? super V> setter, IFunction2<? super V, ? super V, ? extends V> merge) {
final V v0 = getter.apply(t0);
final V v1 = getter.apply(t1);
switch (computeIndex(v0, v1)) {
case 0:
break;
case 1:
setter.accept(v0);
break;
case 2:
setter.accept(v1);
break;
case 3:
if (merge != null) {
final V merged = merge.apply(v0, v1);
setter.accept(merged);
break;
} else if (Objects.equals(v0, v1)) {
setter.accept(v0);
break;
} else throw new IllegalArgumentException(String.format("Cannot merge non-null values (%1$s and %2$s), as no merging function as supplied", v0, v1));
default:
throw new UnreachableCodeError();
}
}
},
NullIsNoneSkip0 {
@Override
public <T, V> void reduce(T t0, T t1, IFunction1<? super T, ? extends V> getter, IConsumer1<? super V> setter, IFunction2<? super V, ? super V, ? extends V> merge) {
final V v0 = getter.apply(t0);
final V v1 = getter.apply(t1);
switch (computeIndex(v0, v1)) {
case 0:
case 1:
break;
case 2:
case 3:
setter.accept(v1);
break;
default:
throw new UnreachableCodeError();
}
}
};

protected <V> int computeIndex(final V v0, final V v1) {
return ((v1 != null) ? 2 : 0) | ((v0 != null) ? 1 : 0);
}

public abstract <T, V> void reduce(T t0, T t1, IFunction1<? super T, ? extends V> getter, IConsumer1<? super V> setter, IFunction2<? super V, ? super V, ? extends V> merge);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.g2forge.alexandria.adt;

import org.junit.Test;

import com.g2forge.alexandria.test.HAssert;

import lombok.Builder;
import lombok.Data;
import lombok.RequiredArgsConstructor;

public class TestReduceStrategy {
@Data
@Builder(toBuilder = true)
@RequiredArgsConstructor
public static class Record {
protected final String field;
}

@Test
public void none() {
final Record.RecordBuilder builder = Record.builder();
ReduceStrategy.NullIsNone.reduce(new Record(null), new Record(null), Record::getField, builder::field, null);
HAssert.assertNull(builder.build().getField());
}

@Test
public void a() {
final Record.RecordBuilder builder = Record.builder();
ReduceStrategy.NullIsNone.reduce(new Record("A"), new Record(null), Record::getField, builder::field, null);
HAssert.assertEquals("A", builder.build().getField());
}

@Test
public void b() {
final Record.RecordBuilder builder = Record.builder();
ReduceStrategy.NullIsNone.reduce(new Record(null), new Record("B"), Record::getField, builder::field, null);
HAssert.assertEquals("B", builder.build().getField());
}

@Test
public void merge() {
final Record.RecordBuilder builder = Record.builder();
final Record a = new Record("A");
final Record b = new Record("B");
HAssert.assertThrows(IllegalArgumentException.class, () -> ReduceStrategy.NullIsNone.reduce(a, b, Record::getField, builder::field, null));
}
}

0 comments on commit f3aa7d5

Please sign in to comment.