Merge pull request #6266 from thundernest/convert_to_kotlin3

Convert `IdGrouper` to Kotlin
This commit is contained in:
cketti 2022-09-02 19:26:39 +02:00 committed by GitHub
commit d6ba51b899
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 118 additions and 174 deletions

View file

@ -1,94 +0,0 @@
package com.fsck.k9.mail.store.imap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
class IdGrouper {
static GroupedIds groupIds(Set<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new IllegalArgumentException("groupId() must be called with non-empty set of ids");
}
if (ids.size() < 2) {
return new GroupedIds(ids, Collections.<ContiguousIdGroup>emptyList());
}
TreeSet<Long> orderedIds = new TreeSet<>(ids);
Iterator<Long> orderedIdIterator = orderedIds.iterator();
Long previousId = orderedIdIterator.next();
TreeSet<Long> remainingIds = new TreeSet<>();
remainingIds.add(previousId);
List<ContiguousIdGroup> idGroups = new ArrayList<>();
long currentIdGroupStart = -1L;
long currentIdGroupEnd = -1L;
while (orderedIdIterator.hasNext()) {
Long currentId = orderedIdIterator.next();
if (previousId + 1L == currentId) {
if (currentIdGroupStart == -1L) {
remainingIds.remove(previousId);
currentIdGroupStart = previousId;
currentIdGroupEnd = currentId;
} else {
currentIdGroupEnd = currentId;
}
} else {
if (currentIdGroupStart != -1L) {
idGroups.add(new ContiguousIdGroup(currentIdGroupStart, currentIdGroupEnd));
currentIdGroupStart = -1L;
}
remainingIds.add(currentId);
}
previousId = currentId;
}
if (currentIdGroupStart != -1L) {
idGroups.add(new ContiguousIdGroup(currentIdGroupStart, currentIdGroupEnd));
}
return new GroupedIds(remainingIds, idGroups);
}
static class GroupedIds {
public final Set<Long> ids;
public final List<ContiguousIdGroup> idGroups;
GroupedIds(Set<Long> ids, List<ContiguousIdGroup> idGroups) {
if (ids.isEmpty() && idGroups.isEmpty()) {
throw new IllegalArgumentException("Must have at least one id");
}
this.ids = ids;
this.idGroups = idGroups;
}
}
static class ContiguousIdGroup {
public final long start;
public final long end;
ContiguousIdGroup(long start, long end) {
if (start >= end) {
throw new IllegalArgumentException("start >= end");
}
this.start = start;
this.end = end;
}
@Override
public String toString() {
return start + ":" + end;
}
}
}

View file

@ -0,0 +1,62 @@
package com.fsck.k9.mail.store.imap
private const val NO_VALID_ID = -1L
internal object IdGrouper {
fun groupIds(ids: Set<Long>): GroupedIds {
require(ids.isNotEmpty()) { "groupIds() must be called with non-empty set of IDs" }
if (ids.size < 2) return GroupedIds(ids, emptyList())
val orderedIds = ids.toSortedSet()
val firstId = orderedIds.first()
val remainingIds = mutableSetOf(firstId)
val idGroups = mutableListOf<ContiguousIdGroup>()
var previousId = firstId
var currentIdGroupStart = NO_VALID_ID
var currentIdGroupEnd = NO_VALID_ID
for (currentId in orderedIds.asSequence().drop(1)) {
if (previousId + 1L == currentId) {
if (currentIdGroupStart == NO_VALID_ID) {
remainingIds.remove(previousId)
currentIdGroupStart = previousId
currentIdGroupEnd = currentId
} else {
currentIdGroupEnd = currentId
}
} else {
if (currentIdGroupStart != NO_VALID_ID) {
idGroups.add(ContiguousIdGroup(currentIdGroupStart, currentIdGroupEnd))
currentIdGroupStart = NO_VALID_ID
}
remainingIds.add(currentId)
}
previousId = currentId
}
if (currentIdGroupStart != NO_VALID_ID) {
idGroups.add(ContiguousIdGroup(currentIdGroupStart, currentIdGroupEnd))
}
return GroupedIds(remainingIds, idGroups)
}
}
internal class GroupedIds(@JvmField val ids: Set<Long>, @JvmField val idGroups: List<ContiguousIdGroup>) {
init {
require(ids.isNotEmpty() || idGroups.isNotEmpty()) { "Must have at least one ID" }
}
}
internal class ContiguousIdGroup(val start: Long, val end: Long) {
init {
require(start < end) { "start >= end" }
}
override fun toString(): String {
return "$start:$end"
}
}

View file

@ -6,9 +6,6 @@ import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import com.fsck.k9.mail.store.imap.IdGrouper.ContiguousIdGroup;
import com.fsck.k9.mail.store.imap.IdGrouper.GroupedIds;
class ImapCommandSplitter {
static List<String> splitCommand(String prefix, String suffix, GroupedIds groupedIds, int lengthLimit) {

View file

@ -1,73 +0,0 @@
package com.fsck.k9.mail.store.imap;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class IdGrouperTest {
@Test
public void groupIds_withSingleContiguousGroup() throws Exception {
Set<Long> ids = newSet(1L, 2L, 3L);
IdGrouper.GroupedIds groupedIds = IdGrouper.groupIds(ids);
assertEquals(0, groupedIds.ids.size());
assertEquals(1, groupedIds.idGroups.size());
assertEquals("1:3", groupedIds.idGroups.get(0).toString());
}
@Test
public void groupIds_withoutContiguousGroup() throws Exception {
Set<Long> ids = newSet(23L, 42L, 2L, 5L);
IdGrouper.GroupedIds groupedIds = IdGrouper.groupIds(ids);
assertEquals(ids, groupedIds.ids);
assertEquals(0, groupedIds.idGroups.size());
}
@Test
public void groupIds_withMultipleContiguousGroups() throws Exception {
Set<Long> ids = newSet(1L, 3L, 4L, 5L, 6L, 10L, 12L, 13L, 14L, 23L);
IdGrouper.GroupedIds groupedIds = IdGrouper.groupIds(ids);
assertEquals(newSet(1L, 10L, 23L), groupedIds.ids);
assertEquals(2, groupedIds.idGroups.size());
assertEquals("3:6", groupedIds.idGroups.get(0).toString());
assertEquals("12:14", groupedIds.idGroups.get(1).toString());
}
@Test
public void groupIds_withSingleId() throws Exception {
Set<Long> ids = newSet(23L);
IdGrouper.GroupedIds groupedIds = IdGrouper.groupIds(ids);
assertEquals(newSet(23L), groupedIds.ids);
assertEquals(0, groupedIds.idGroups.size());
}
@Test(expected = IllegalArgumentException.class)
public void groupIds_withEmptySet_shouldThrow() throws Exception {
IdGrouper.groupIds(newSet());
}
@Test(expected = IllegalArgumentException.class)
public void groupIds_withNullArgument_shouldThrow() throws Exception {
IdGrouper.groupIds(null);
}
private static Set<Long> newSet(Long... values) {
HashSet<Long> set = new HashSet<>(values.length);
set.addAll(Arrays.asList(values));
return set;
}
}

View file

@ -0,0 +1,53 @@
package com.fsck.k9.mail.store.imap
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class IdGrouperTest {
@Test
fun `groupIds() with single contiguous group`() {
val ids = setOf(1L, 2L, 3L)
val groupedIds = IdGrouper.groupIds(ids)
assertThat(groupedIds.ids).isEmpty()
assertThat(groupedIds.idGroups.mapToString()).containsExactly("1:3")
}
@Test
fun `groupIds() without contiguous group`() {
val ids = setOf(23L, 42L, 2L, 5L)
val groupedIds = IdGrouper.groupIds(ids)
assertThat(groupedIds.ids).isEqualTo(ids)
assertThat(groupedIds.idGroups).isEmpty()
}
@Test
fun `groupIds() with multiple contiguous groups`() {
val ids = setOf(1L, 3L, 4L, 5L, 6L, 10L, 12L, 13L, 14L, 23L)
val groupedIds = IdGrouper.groupIds(ids)
assertThat(groupedIds.ids).containsExactly(1L, 10L, 23L)
assertThat(groupedIds.idGroups.mapToString()).containsExactly("3:6", "12:14")
}
@Test
fun `groupIds() with single ID`() {
val ids = setOf(23L)
val groupedIds = IdGrouper.groupIds(ids)
assertThat(groupedIds.ids).containsExactly(23L)
assertThat(groupedIds.idGroups).isEmpty()
}
@Test(expected = IllegalArgumentException::class)
fun `groupIds() with empty set should throw`() {
IdGrouper.groupIds(emptySet())
}
}
private fun <T> List<T>.mapToString() = map { it.toString() }

View file

@ -6,7 +6,6 @@ import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import com.fsck.k9.mail.store.imap.IdGrouper.GroupedIds;
import com.google.common.collect.Sets;
import org.junit.Test;
@ -24,7 +23,7 @@ public class ImapCommandSplitterTest {
@Test
public void splitCommand_withManyNonContiguousIds_shouldSplitCommand() throws Exception {
Set<Long> ids = createNonContiguousIdSet(10000, 10500, 2);
GroupedIds groupedIds = new GroupedIds(ids, Collections.<IdGrouper.ContiguousIdGroup>emptyList());
GroupedIds groupedIds = new GroupedIds(ids, Collections.emptyList());
List<String> commands = ImapCommandSplitter.splitCommand(COMMAND_PREFIX, COMMAND_SUFFIX, groupedIds, 980);
@ -39,7 +38,7 @@ public class ImapCommandSplitterTest {
Set<Long> idSet = Sets.union(
createNonContiguousIdSet(10000, 10298, 2),
createNonContiguousIdSet(10402, 10500, 2));
List<IdGrouper.ContiguousIdGroup> idGroups = singletonList(new IdGrouper.ContiguousIdGroup(10300L, 10400L));
List<ContiguousIdGroup> idGroups = singletonList(new ContiguousIdGroup(10300L, 10400L));
GroupedIds groupedIds = new GroupedIds(idSet, idGroups);
List<String> commands = ImapCommandSplitter.splitCommand(COMMAND_PREFIX, COMMAND_SUFFIX, groupedIds, 980);
@ -55,7 +54,7 @@ public class ImapCommandSplitterTest {
@Test
public void splitCommand_withEmptySuffix_shouldCreateCommandWithoutTrailingSpace() throws Exception {
Set<Long> ids = createNonContiguousIdSet(1, 2, 1);
GroupedIds groupedIds = new GroupedIds(ids, Collections.<IdGrouper.ContiguousIdGroup>emptyList());
GroupedIds groupedIds = new GroupedIds(ids, Collections.<ContiguousIdGroup>emptyList());
List<String> commands = ImapCommandSplitter.splitCommand("UID SEARCH UID", "", groupedIds, 980);