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

Add collectors for Maps #256

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 55 additions & 0 deletions drv/Maps.drv
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ import java.util.Map;
import java.util.function.Consumer;
import PACKAGE.MAP.FastEntrySet;

import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collector;

/** A class providing static methods and objects that do useful things with type-specific maps.
*
* @see java.util.Collections
Expand Down Expand Up @@ -680,4 +685,54 @@ public final class MAPS {
*/
public static KEY_VALUE_GENERIC MAP KEY_VALUE_GENERIC unmodifiable(final MAP KEY_VALUE_EXTENDS_GENERIC m) { return new UnmodifiableMap KEY_VALUE_GENERIC_DIAMOND(m); }

#if KEYS_PRIMITIVE && VALUES_PRIMITIVE
static <M extends MAP>
#elif KEYS_PRIMITIVE && VALUES_REFERENCE
static <VALUE_GENERIC_CLASS, M extends MAP<VALUE_GENERIC_CLASS>>
#elif KEYS_REFERENCE && VALUES_PRIMITIVE
static <KEY_GENERIC_CLASS, M extends MAP<KEY_GENERIC_CLASS>>
#else
static <KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS, M extends MAP<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>>
#endif
BinaryOperator<M> merger(BIFUNCTION mergeFunction) {
return (m1, m2) -> {
fastForEach(
m2,
entry -> m1.MERGE_VALUE(entry.ENTRY_GET_KEY(), entry.ENTRY_GET_VALUE(), mergeFunction)
);
return m1;
};
}

#if KEYS_PRIMITIVE && VALUES_PRIMITIVE
public static <T, M extends MAP> Collector<T, ?, M> collector(
#elif KEYS_PRIMITIVE && VALUES_REFERENCE
public static <T, VALUE_GENERIC_CLASS, M extends MAP<VALUE_GENERIC_CLASS>> Collector<T, ?, M> collector(
#elif KEYS_REFERENCE && VALUES_PRIMITIVE
public static <T, KEY_GENERIC_CLASS, M extends MAP<KEY_GENERIC_CLASS>> Collector<T, ?, M> collector(
#else
public static <T, KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS, M extends MAP<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>> Collector<T, ?, M> toMap(
#endif
METHOD_GENERIC_TO_KEY keyMapper,
METHOD_GENERIC_TO_VALUE valueMapper,
BIFUNCTION mergeFunction,
Supplier<M> creator
) {
BiConsumer<M, T> accumulator =
(map, element) ->
map.MERGE_VALUE(
METHOD_GENERIC_TO_KEY_APPLY(element),
METHOD_GENERIC_TO_VALUE_APPLY(element),
#if VALUE_CLASS_Boolean
mergeFunction::apply
#else
mergeFunction
#endif
);
return Collector.of(
creator,
accumulator,
merger(mergeFunction)
);
}
}
38 changes: 38 additions & 0 deletions gencsource.sh
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,33 @@ $(if [[ "${CLASS[$k]}" != "" && "${CLASS[$v]}" != "" ]]; then\
"#define VALUE_OPERATOR_APPLY apply\n"\
"#endif\n"\
\
"#if KEYS_INT_LONG_DOUBLE\n"\
"#define METHOD_GENERIC_TO_KEY java.util.function.To${TYPE_CAP[$k]}Function<T>\n"\
"#define METHOD_GENERIC_TO_KEY_APPLY keyMapper.applyAs${TYPE_CAP[$wk]}\n"\
"#elif KEY_CLASS_Boolean\n"\
"#define METHOD_GENERIC_TO_KEY java.util.function.Predicate<T>\n"\
"#define METHOD_GENERIC_TO_KEY_APPLY keyMapper.test\n"\
"#elif KEY_CLASS_Object || KEY_CLASS_Reference\n"\
"#define METHOD_GENERIC_TO_KEY java.util.function.Function<? super T, ? extends K>\n"\
"#define METHOD_GENERIC_TO_KEY_APPLY keyMapper.apply\n"\
"#else\n"\
"#define METHOD_GENERIC_TO_KEY it.unimi.dsi.fastutil.objects.Object2${TYPE_CAP[$k]}Function<? super T>\n"\
"#define METHOD_GENERIC_TO_KEY_APPLY keyMapper.get${TYPE_CAP[$k]}\n"\
"#endif\n"\
"#if VALUES_INT_LONG_DOUBLE\n"\
"#define METHOD_GENERIC_TO_VALUE java.util.function.To${TYPE_CAP[$v]}Function<? super T>\n"\
"#define METHOD_GENERIC_TO_VALUE_APPLY valueMapper.applyAs${TYPE_CAP[$wv]}\n"\
"#elif VALUE_CLASS_Boolean\n"\
"#define METHOD_GENERIC_TO_VALUE java.util.function.Predicate<? super T>\n"\
"#define METHOD_GENERIC_TO_VALUE_APPLY valueMapper.test\n"\
"#elif VALUE_CLASS_Object || VALUE_CLASS_Reference\n"\
"#define METHOD_GENERIC_TO_VALUE java.util.function.Function<? super T, ? extends V>\n"\
"#define METHOD_GENERIC_TO_VALUE_APPLY valueMapper.apply\n"\
"#else\n"\
"#define METHOD_GENERIC_TO_VALUE it.unimi.dsi.fastutil.objects.Object2${TYPE_CAP[$v]}Function<? super T>\n"\
"#define METHOD_GENERIC_TO_VALUE_APPLY valueMapper.get${TYPE_CAP[$v]}\n"\
"#endif\n"\
\
\
"/* Abstract implementations (keys) */\n"\
\
Expand Down Expand Up @@ -522,6 +549,13 @@ $(if [[ "${CLASS[$k]}" != "" && "${CLASS[$v]}" != "" ]]; then\
"#define BIG_LISTS ${TYPE_CAP[$k]}BigLists\n"\
"#define MAPS ${TYPE_CAP[$k]}2${TYPE_CAP[$v]}Maps\n"\
"#define FUNCTIONS ${TYPE_CAP[$k]}2${TYPE_CAP[$v]}Functions\n"\
"#if VALUES_REFERENCE\n"\
"#define BIFUNCTION java.util.function.BiFunction<? super VALUE_GENERIC_TYPE , ? super VALUE_GENERIC_TYPE, ? extends VALUE_GENERIC_TYPE>\n"\
"#elif VALUES_INT_LONG_DOUBLE\n"\
"#define BIFUNCTION java.util.function.${TYPE_CAP[$v]}BinaryOperator\n"\
"#else\n"\
"#define BIFUNCTION VALUE_PACKAGE.VALUE_BINARY_OPERATOR\n"\
"#endif\n"\
"#define SORTED_MAPS ${TYPE_CAP[$k]}2${TYPE_CAP[$v]}SortedMaps\n"\
"#define PRIORITY_QUEUES ${TYPE_CAP2[$k]}PriorityQueues\n"\
"#define HEAPS ${TYPE_CAP2[$k]}Heaps\n"\
Expand Down Expand Up @@ -670,7 +704,11 @@ $(if [[ "${CLASS[$k]}" != "" && "${CLASS[$v]}" != "" ]]; then\
"/* Methods (values) */\n"\
\
\
"#if VALUE_CLASS_Boolean\n"\
"#define MERGE_VALUE merge\n"\
"#else\n"\
"#define MERGE_VALUE merge${TYPE_STD[$v]}\n"\
"#endif\n"\
"#define NEXT_VALUE next${TYPE_STD[$v]}\n"\
"#define PREV_VALUE previous${TYPE_STD[$v]}\n"\
"#define READ_VALUE read${TYPE_CAP2[$v]}\n"\
Expand Down
59 changes: 59 additions & 0 deletions test/it/unimi/dsi/fastutil/ints/Int2BooleanMapsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package it.unimi.dsi.fastutil.ints;

import org.junit.Test;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Stream;

import static org.junit.Assert.assertEquals;

public class Int2BooleanMapsTest {

static Predicate<Integer> getPredicate() {
AtomicInteger calls = new AtomicInteger();
return i -> {
int c = calls.getAndIncrement();
return c % 2 == 0;
};
}

@Test
public void testInt2BooleanMap() {
final Int2BooleanMap result =
Stream.of(1, 2, 3, 3)
.collect(
Int2BooleanMaps.collector(
i -> i,
getPredicate(),
Boolean::logicalAnd,
Int2BooleanArrayMap::new
)
);
Int2BooleanMap expected =
new Int2BooleanArrayMap(
new int[] {1, 2, 3},
new boolean[] {true, false, false}
);

assertEquals(result, expected);
}

@Test
public void testInt2BooleanMapEmpty() {
final Int2BooleanMap result =
Stream.<Integer>empty()
.collect(
Int2BooleanMaps.collector(
i -> i,
getPredicate(),
Boolean::logicalAnd,
Int2BooleanArrayMap::new
)
);
Int2BooleanMap expected = Int2BooleanMaps.EMPTY_MAP;

assertEquals(result, expected);
}

}
49 changes: 49 additions & 0 deletions test/it/unimi/dsi/fastutil/ints/Int2CharMapsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package it.unimi.dsi.fastutil.ints;

import org.junit.Test;

import java.util.stream.Stream;

import static org.junit.Assert.assertEquals;

public class Int2CharMapsTest {

@Test
public void testInt2CharMap() {
final Int2CharMap result =
Stream.of(1, 2, 3, 3)
.collect(
Int2CharMaps.collector(
i -> (char) i.intValue(),
i -> (Character) i,
(char c0, char c1) -> (char) ((int) c0 + (int) c1),
Int2CharArrayMap::new
)
);
Int2CharMap expected =
new Int2CharArrayMap(
new int[] {1, 2, 3},
new char[] {'\u0001', '\u0002', '\u0006'}
);

assertEquals(result, expected);
}

@Test
public void testInt2CharMapEmpty() {
final Int2CharMap result =
Stream.<Integer>empty()
.collect(
Int2CharMaps.collector(
i -> (char) i.intValue(),
i -> (Character) i,
(char c0, char c1) -> (char) ((int) c0 + (int) c1),
Int2CharArrayMap::new
)
);
Int2CharMap expected = Int2CharMaps.EMPTY_MAP;

assertEquals(result, expected);
}

}
39 changes: 39 additions & 0 deletions test/it/unimi/dsi/fastutil/ints/Int2IntMapsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

import org.junit.Test;

Expand Down Expand Up @@ -75,4 +76,42 @@ public void testFastIteratorHelpers() {
Int2IntMaps.fastIterable(m).forEach(s::add);
assertEquals(1, s.size()); // Should be always the same entry, mutated
}

@Test
public void testInt2IntMap() {
final Int2IntMap result =
Stream.of(1, 2, 3, 3)
.collect(
Int2IntMaps.collector(
i -> i,
i -> i,
Integer::sum,
Int2IntArrayMap::new
)
);
Int2IntMap expected =
new Int2IntArrayMap(
new int[] {1, 2, 3},
new int[] {1, 2, 6}
);

assertEquals(result, expected);
}

@Test
public void testInt2IntMapEmpty() {
final Int2IntMap result =
Stream.<Integer>empty()
.collect(
Int2IntMaps.collector(
i -> i,
i -> i,
Integer::sum,
Int2IntArrayMap::new
)
);
Int2IntMap expected = Int2IntMaps.EMPTY_MAP;

assertEquals(result, expected);
}
}