Skip to content
Merged
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
1 change: 1 addition & 0 deletions exonum-java-binding/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
`ProofMapIndexProxy#getIndexHash` accordingly.

### Added
- `stream` for sets: `KeySetIndex` and `ValueSetIndex`. (#1088)
- Proofs of absence of an element with the specified index for `ProofListIndexProxy`. (#1081)

## [0.7.0] - 2019-07-17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
import com.exonum.binding.core.util.LibraryLoader;
import com.google.protobuf.MessageLite;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.LongSupplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
* A key set is an index that contains no duplicate elements (keys).
Expand Down Expand Up @@ -61,6 +65,11 @@ public final class KeySetIndexProxy<E> extends AbstractIndexProxy implements Ite
LibraryLoader.load();
}

// Note that we do *not* specify Spliterator.DISTINCT because it is documented in terms
// of Object#equals which this set does not use.
private static final int BASE_SPLITERATOR_CHARACTERISTICS =
Spliterator.NONNULL | Spliterator.ORDERED;

private final CheckingSerializerDecorator<E> serializer;

/**
Expand Down Expand Up @@ -220,6 +229,25 @@ public Iterator<E> iterator() {
serializer::fromBytes);
}

/**
* Returns a stream of the set elements. The elements are ordered lexicographically.
*
* @throws IllegalStateException if this set is not valid
*/
public Stream<E> stream() {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator(), streamCharacteristics()),
false);
}

private int streamCharacteristics() {
if (dbView.canModify()) {
return BASE_SPLITERATOR_CHARACTERISTICS;
} else {
return BASE_SPLITERATOR_CHARACTERISTICS | Spliterator.IMMUTABLE;
}
}

/**
* Removes the element from this set. If it's not in the set, does nothing.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.MessageLite;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.LongSupplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.Nullable;

/**
Expand Down Expand Up @@ -68,6 +72,11 @@ public final class ValueSetIndexProxy<E> extends AbstractIndexProxy
LibraryLoader.load();
}

// Note that we do *not* specify Spliterator.DISTINCT because it is documented in terms
// of Object#equals which this set does not use.
private static final int BASE_SPLITERATOR_CHARACTERISTICS =
Spliterator.NONNULL | Spliterator.ORDERED;

private final CheckingSerializerDecorator<E> serializer;

/**
Expand Down Expand Up @@ -241,7 +250,7 @@ public Iterator<HashCode> hashes() {

/**
* Returns an iterator over the entries of this set. An entry is a hash-value pair.
* The entries are ordered by keys lexicographically.
* The entries are ordered by hashes lexicographically.
*
* @return an iterator over the entries of this set
* @throws IllegalStateException if this set is not valid
Expand All @@ -263,6 +272,27 @@ public Iterator<Entry<E>> iterator() {

private native void nativeIteratorFree(long iterNativeHandle);

/**
* Returns a stream of the entries in this set. An entry is a hash-value pair.
* The entries are ordered by hashes lexicographically.
*
* @throws IllegalStateException if this set is not valid
*/
public Stream<Entry<E>> stream() {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator(), streamCharacteristics()),
false
);
}

private int streamCharacteristics() {
if (dbView.canModify()) {
return BASE_SPLITERATOR_CHARACTERISTICS;
} else {
return BASE_SPLITERATOR_CHARACTERISTICS | Spliterator.IMMUTABLE;
}
}

/**
* An entry of a value set index: a hash-value pair.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.exonum.binding.core.storage.indices.TestStorageItems.K1;
import static com.exonum.binding.core.storage.indices.TestStorageItems.K9;
import static com.exonum.binding.core.storage.indices.TestStorageItems.V1;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
Expand Down Expand Up @@ -112,6 +113,22 @@ void testIterator() {
});
}

@Test
void testStream() {
runTestWithView(database::createFork, (set) -> {
List<String> elements = TestStorageItems.keys;

elements.forEach(set::add);

List<String> streamElements = set.stream()
.collect(toList());

// Check that the stream includes all the elements added
// and that they appear in lexicographical order (the order of TestStorageItems.keys).
assertThat(streamElements, equalTo(elements));
});
}

@Test
void removesAddedElement() {
runTestWithView(database::createFork, (set) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.exonum.binding.core.storage.indices.TestStorageItems.V1;
import static com.exonum.binding.core.storage.indices.TestStorageItems.V2;
import static com.exonum.binding.core.storage.indices.TestStorageItems.V9;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
Expand All @@ -37,7 +38,6 @@
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;

class ValueSetIndexProxyIntegrationTest
Expand Down Expand Up @@ -159,18 +159,33 @@ void testIterator() {
});
}

@Test
void testStream() {
runTestWithView(database::createFork, (set) -> {
List<String> elements = TestStorageItems.values;

elements.forEach(set::add);

List<ValueSetIndexProxy.Entry<String>> entriesFromStream = set.stream()
.collect(toList());
List<ValueSetIndexProxy.Entry<String>> entriesExpected = getOrderedEntries(elements);

assertThat(entriesFromStream, equalTo(entriesExpected));
});
}

private static List<HashCode> getOrderedHashes(List<String> elements) {
return getOrderedEntries(elements).stream()
.map(ValueSetIndexProxy.Entry::getHash)
.collect(Collectors.toList());
.collect(toList());
}

private static List<ValueSetIndexProxy.Entry<String>> getOrderedEntries(List<String> elements) {
return elements.stream()
.map(value -> ValueSetIndexProxy.Entry.from(getHashOf(value), value))
.sorted((e1, e2) -> UnsignedBytes.lexicographicalComparator()
.compare(e1.getHash().asBytes(), e2.getHash().asBytes()))
.collect(Collectors.toList());
.collect(toList());
}

@Test
Expand Down