diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd0a3c0a0..9d5d321bb 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -42,7 +42,7 @@ Make sure to compare your version against the latest available version at https: **Java version:** -Please tell us which Java version you are using. +Please tell us which Java version you are using. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9d8aa8f83..18c2b823c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,4 +6,3 @@ ### Automated Checks - [ ] I have run `./gradlew test` and made sure that my PR does not break any unit test. -- [ ] I have run `./gradlew checkstyleMain` or the equivalent and corrected the formatting warnings reported. diff --git a/.github/workflows/checkascii.yml b/.github/workflows/checkascii.yml index 720bedd4b..29317dcac 100644 --- a/.github/workflows/checkascii.yml +++ b/.github/workflows/checkascii.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check ASCII run: | find . -type f -name '*.java' | xargs file | grep -qv ASCII || exit 0 && exit 1 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a6923df69..14d4bc438 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 497d1f389..375241d72 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,5 +6,5 @@ jobs: name: "validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/java-all-versions.yml b/.github/workflows/java-all-versions.yml index 35474f684..ecfa7471d 100644 --- a/.github/workflows/java-all-versions.yml +++ b/.github/workflows/java-all-versions.yml @@ -1,4 +1,4 @@ -name: Java 8, 11, 17 CI +name: Java 8, 11, 17, 21 CI on: [push,pull_request] @@ -7,22 +7,23 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up JDKs 8, 11, 17 - uses: actions/setup-java@v3 + - uses: actions/checkout@v4 + - name: Set up JDKs 8, 11, 17, 21 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: | 8 11 17 + 21 - name: Build with Gradle run: ./gradlew assemble - - name: Style check - run: ./gradlew checkstyleMain - name: Test with Java 8 run: ./gradlew test -PtestOnJava=8 --stacktrace - name: Test with Java 11 run: ./gradlew test -PtestOnJava=11 --stacktrace - name: Test with Java 17 run: ./gradlew test -PtestOnJava=17 --stacktrace + - name: Test with Java 21 + run: ./gradlew test -PtestOnJava=21 --stacktrace diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ff4acb6b0..dcfa5e89a 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -7,9 +7,9 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 11 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: 11 diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 65939873e..d2c44f100 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -1,22 +1,30 @@ -name: "tagged-release" - +name: Publish package to GitHub Packages on: - push: - tags: - - "(\\d)+\\.(\\d)+\\.(\\d)+" - + release: + types: [created] jobs: - tagged-release: - name: "Tagged Release" - runs-on: "ubuntu-latest" - + publish: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - - name: "Creating a release" - run: | - echo "done!" - - - uses: "marvinpinto/action-automatic-releases@latest" + - uses: actions/checkout@v4 with: - repo_token: "${{ secrets.GITHUB_TOKEN }}" - prerelease: false - + path: roaring + - uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + - name: Setup Gradle + uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 + - name: Build with Gradle + run: ./gradlew build -x test -i + working-directory: ./roaring + - name: Publish package + run: ./gradlew publishSonatypePublicationToGitHubPackagesRepository -i + working-directory: ./roaring + env: + GITHUB_USER: ${{ github.actor }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.gitignore b/.gitignore index 5ec4ec483..0d544b3ae 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ build/ # OS X .DS_Store +.java-version # intellij .idea @@ -30,5 +31,4 @@ pom.xml.tag # We ignore .bin files as they may be generated by fuzz-tests # Beware there is real .bin files in /testdata -# git add --force ./RoaringBitmap/src/test/resources/testdata/*.bin *.bin diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2492d43e9..000000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -language: java -sudo: false - -jdk: - - openjdk8 - - openjdk11 - - openjdk14 - - oraclejdk11 - - -############ -# We still support and test jdk8 for clients, but on travis we no longer build with jkd8, see -# https://github.com/RoaringBitmap/RoaringBitmap/pull/290 for rationale. -########## -# we removed oraclejdk7 as per https://github.com/RoaringBitmap/RoaringBitmap/pull/176#issuecomment-322257170 -######### - -# from https://docs.travis-ci.com/user/languages/java/#caching -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - -# Install silently to ensure all pom are installed and compilation is OK: actual checks will be processed by script: -# Including testClasses so tests will compile too. -install: "./gradlew assemble testClasses" - -branches: - only: - - master - -script: - # run checkstyle, etc, without the tests to fail fast - - ./gradlew check -x test - - ./gradlew test jacocoTestReport -DBITMAP_TYPES=ROARING_ONLY - -after_success: - - ./gradlew coveralls diff --git a/LICENSE-2.0.txt b/LICENSE-2.0.txt index efa0e258b..3bdd00362 100644 --- a/LICENSE-2.0.txt +++ b/LICENSE-2.0.txt @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2013-2016 the RoaringBitmap authors + Copyright 2013-2016 the RoaringBitmap authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index e86816eee..c583fa4c7 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,34 @@ RoaringBitmap [![docs-badge][]][docs] ![Java 11 CI](https://github.com/RoaringBitmap/RoaringBitmap/workflows/Java%2011%20CI/badge.svg) +- [Introduction](#introduction) +- [When should you use a bitmap?](#when-should-you-use-a-bitmap) +- [When should you use compressed bitmaps?](#when-should-you-use-compressed-bitmaps) +- [How does Roaring compare with the alternatives?](#how-does-roaring-compare-with-the-alternatives) +- [Code sample](#code-sample) +- [API docs](#api-docs) +- [Download](#download) +- [Usage within a Maven project](#usage-within-a-maven-project) +- [Usage within a gradle project](#usage-within-a-gradle-project) +- [Scientific Documentation](#scientific-documentation) +- [Unsigned integers](#unsigned-integers) +- [Working with memory-mapped bitmaps](#working-with-memory-mapped-bitmaps) +- [Thread safety](#thread-safety) +- [Kryo](#kryo) +- [64-bit integers (long)](#64-bit-integers-long) +- [Range Bitmaps](#range-bitmaps) +- [Prerequisites](#prerequisites) +- [Usage for RoaringBitmap Developers](#usage-for-roaringbitmap-developers) +- [IntelliJ and Eclipse](#intellij-and-eclipse) +- [Contributing](#contributing) +- [FAQ](#faq) +- [Benchmark](#benchmark) +- [Mailing list/discussion group](#mailing-listdiscussion-group) +- [Funding](#funding) + +Introduction +------------- + Bitsets, also called bitmaps, are commonly used as fast data structures. Unfortunately, they can use too much memory. To compensate, we often use compressed bitmaps. @@ -37,10 +65,12 @@ This library is used by * [SirixDB](https://sirix.io) * [EvitaDB](https://evitadb.io/) * [Apache Iceberg](https://iceberg.apache.org/) +* [Apache Pulsar](https://pulsar.apache.org/) +The library is mature and has been used in production for many years. The YouTube SQL Engine, [Google Procella](https://research.google/pubs/pub48388/), uses Roaring bitmaps for indexing. [Apache Lucene](http://lucene.apache.org/) uses Roaring bitmaps, though they have their own [independent implementation](https://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/lucene/core/src/java/org/apache/lucene/util/RoaringDocIdSet.java?view=markup&pathrev=1629606). Derivatives of Lucene such as Solr and Elastic also use Roaring bitmaps. -Other platforms such as [Whoosh](https://pypi.python.org/pypi/Whoosh/), [Microsoft Visual Studio Team Services (VSTS)](https://www.visualstudio.com/team-services/) and [Pilosa](https://github.com/pilosa/pilosa) also use Roaring bitmaps with their own implementations. You find Roaring bitmaps in [InfluxDB](https://www.influxdata.com), [Bleve](http://www.blevesearch.com), [Cloud Torrent](https://github.com/jpillora/cloud-torrent), and so forth. +Other platforms such as [Whoosh](https://pypi.python.org/pypi/Whoosh/), [Microsoft Visual Studio Team Services (VSTS)](https://www.visualstudio.com/team-services/) and [Pilosa](https://github.com/pilosa/pilosa) also use Roaring bitmaps with their own implementations. You find Roaring bitmaps in [InfluxDB](https://www.influxdata.com), [Bleve](http://www.blevesearch.com), [Cloud Torrent](https://github.com/jpillora/cloud-torrent), [Redpanda](https://github.com/redpanda-data/redpanda), and so forth. [There is a serialized format specification for interoperability between implementations](https://github.com/RoaringBitmap/RoaringFormatSpec/). @@ -54,7 +84,7 @@ This code is licensed under Apache License, Version 2.0 (AL2.0). When should you use a bitmap? -=================================== +------------------------------- Sets are a fundamental abstraction in @@ -82,12 +112,12 @@ When the bitset approach is applicable, it can be orders of magnitude faster than other possible implementation of a set (e.g., as a hash set) while using several times less memory. -However, a bitset, even a compressed one is not always applicable. For example, if +However, a bitset, even a compressed one is not always applicable. For example, if you have 1000 random-looking integers, then a simple array might be the best representation. We refer to this case as the "sparse" scenario. When should you use compressed bitmaps? -=================================== +-------------------------- An uncompressed BitSet can use a lot of memory. For example, if you take a BitSet and set the bit at position 1,000,000 to true and you have just over 100kB. That is over 100kB @@ -108,8 +138,7 @@ Keep in mind that random-looking data is usually not compressible. E.g., if you and attempts at compression can be counterproductive. How does Roaring compare with the alternatives? -================================================== - +------------------------------------------------ Most alternatives to Roaring are part of a larger family of compressed bitmaps that are run-length-encoded bitmaps. They identify long runs of 1s or 0s and they represent them with a marker word. @@ -139,25 +168,10 @@ formats like WAH, EWAH, Concise... Maybe surprisingly, Roaring also generally of -API docs ---------- - -http://www.javadoc.io/doc/org.roaringbitmap/RoaringBitmap/ - -Scientific Documentation --------------------------- - -- Daniel Lemire, Owen Kaser, Nathan Kurz, Luca Deri, Chris O'Hara, François Saint-Jacques, Gregory Ssi-Yan-Kai, Roaring Bitmaps: Implementation of an Optimized Software Library, Software: Practice and Experience 48 (4), 2018 [arXiv:1709.07821](https://arxiv.org/abs/1709.07821) -- Samy Chambi, Daniel Lemire, Owen Kaser, Robert Godin, -Better bitmap performance with Roaring bitmaps, -Software: Practice and Experience 46 (5), 2016. [arXiv:1402.6407](http://arxiv.org/abs/1402.6407) This paper used data from http://lemire.me/data/realroaring2014.html -- Daniel Lemire, Gregory Ssi-Yan-Kai, Owen Kaser, Consistently faster and smaller compressed bitmaps with Roaring, Software: Practice and Experience 46 (11), 2016. [arXiv:1603.06549](http://arxiv.org/abs/1603.06549) -- Samy Chambi, Daniel Lemire, Robert Godin, Kamel Boukhalfa, Charles Allen, Fangjin Yang, Optimizing Druid with Roaring bitmaps, IDEAS 2016, 2016. http://r-libre.teluq.ca/950/ - Code sample ------------- -```java +```java import org.roaringbitmap.RoaringBitmap; public class Basic { @@ -188,6 +202,203 @@ public class Basic { Please see the examples folder for more examples, which you can run with `./gradlew :examples:runAll`, or run a specific one with `./gradlew :examples:runExampleBitmap64`, etc. +API docs +--------- + +http://www.javadoc.io/doc/org.roaringbitmap/RoaringBitmap/ + + +Download +--------- + +You can download releases from github: +https://github.com/RoaringBitmap/RoaringBitmap/releases + +Usage within a Maven project +--------- + +### 1. Using JitPack + + +Add the following dependency to your pom.xml file... + +```xml + + com.github.RoaringBitmap.RoaringBitmap + roaringbitmap + 1.3.16 + +``` + +You may adjust the version number. + +Then add the repository to your pom.xml file: + +```xml + + + jitpack.io + https://jitpack.io + + +``` +See https://github.com/RoaringBitmap/JitPackRoaringBitmapProject for a complete example. + + +### 2. Using GitHub Packages + +Add the following dependency to your `pom.xml` file inside the `` element... + +```xml + + org.roaringbitmap + roaringbitmap + 1.3.16 + +``` + +Add the GitHub repository inside the `` element (`pom.xml` file)... + +```xml + + + github + Roaring Maven Packages + https://maven.pkg.github.com/RoaringBitmap/RoaringBitmap + true + true + + +``` + +See https://github.com/RoaringBitmap/MavenRoaringBitmapProject for a complete example. + +The registry access is is protected by an authorisation. So you have to add your GitHub credentials to your global settings.xml: `$HOME\.m2\settings.xml`. + +You will need a token which you can generate on GitHub. + +``` +GitHub > Settings > Developer Settings > Personal access tokens > Generate new token +``` + +The token needs the read:packages permission. The token identifier is a long string such as `ghp_ieOkN`. + +Put the following in your `settings.xml` file, within the `` element. + +```xml + + github + lemire + ghp_ieOkN + +``` + +Replace `lemire` by your GitHub username and `ghp_ieOkN` by the token identifier +you just generated. + +Usage within a gradle project +------------------ + +### 1. Using JitPack + +Then all you need is to edit your `build.gradle` file like so: + + +```groovy +plugins { + id 'java' +} + +group 'org.roaringbitmap' // name of your project +version '1.0-SNAPSHOT' // version of your project + +repositories { + mavenCentral() + maven { + url 'https://jitpack.io' + } +} + +dependencies { + implementation 'com.github.RoaringBitmap.RoaringBitmap:roaringbitmap:1.3.16' + testImplementation 'junit:junit:3.8.1' +} +``` + + +See https://github.com/RoaringBitmap/JitPackRoaringBitmapProject for a complete example. + + +### 2. Using GitHub Packages + + +You first need your GitHub credentials. Go +to + +``` +GitHub > Settings > Developer Settings > Personal access tokens > Generate new token +``` + +And create a token with read:packages permission. + +If your GitHub user name is `lemire` and your GitHub personal token `ghp_ieOkN`, +then you can set them using system variables. Under bash, you can do it like so: +``` +export GITHUB_USER=lemire +export GITHUB_PASSWORD=ghp_ieOkN +``` + + +If you prefer you can write your GitHub credentials in your gradle.properties +file + +``` +# gradle.properties +githubUser=lemire +githubPassword=ghp_ieOkN +``` + +Then all you need is to edit your `build.gradle` file like so: + +```groovy +plugins { + id 'java' +} + +group 'org.roaringbitmap' // name of your project +version '1.0-SNAPSHOT' // version of your project + +repositories { + mavenCentral() + maven { + url 'https://maven.pkg.github.com/RoaringBitmap/RoaringBitmap' + credentials { + username = System.properties['githubUser'] ?: System.env.GITHUB_USER + password = System.properties['githubPassword'] ?: System.env.GITHUB_PASSWORD + } + } +} + +dependencies { + implementation 'org.roaringbitmap:roaringbitmap:1.3.16' + testImplementation 'junit:junit:3.8.1' +} +``` + +See https://github.com/RoaringBitmap/MavenRoaringBitmapProject for a complete example. + + + +Scientific Documentation +-------------------------- + +- Daniel Lemire, Owen Kaser, Nathan Kurz, Luca Deri, Chris O'Hara, François Saint-Jacques, Gregory Ssi-Yan-Kai, Roaring Bitmaps: Implementation of an Optimized Software Library, Software: Practice and Experience 48 (4), 2018 [arXiv:1709.07821](https://arxiv.org/abs/1709.07821) +- Samy Chambi, Daniel Lemire, Owen Kaser, Robert Godin, +Better bitmap performance with Roaring bitmaps, +Software: Practice and Experience 46 (5), 2016. [arXiv:1402.6407](http://arxiv.org/abs/1402.6407) This paper used data from http://lemire.me/data/realroaring2014.html +- Daniel Lemire, Gregory Ssi-Yan-Kai, Owen Kaser, Consistently faster and smaller compressed bitmaps with Roaring, Software: Practice and Experience 46 (11), 2016. [arXiv:1603.06549](http://arxiv.org/abs/1603.06549) +- Samy Chambi, Daniel Lemire, Robert Godin, Kamel Boukhalfa, Charles Allen, Fangjin Yang, Optimizing Druid with Roaring bitmaps, IDEAS 2016, 2016. http://r-libre.teluq.ca/950/ + Unsigned integers ------------------ @@ -264,7 +475,7 @@ generate a RoaringBitmap which lies in RAM. As the name suggest, the ImmutableRoaringBitmap itself cannot be modified. -This design was inspired by Druid. +This design was inspired by Apache Druid. One can find a complete working example in the test file TestMemoryMapping.java. @@ -273,6 +484,10 @@ from the org.roaringbitmap.buffer package. They are incompatible. They serialize to the same output however. The performance of the code in org.roaringbitmap package is generally superior because there is no overhead due to the use of ByteBuffer instances. +Thread safety +----- + +In general, it is unsafe to access the same bitmaps using different threads--the bitmaps are unsynchronized for performance. Should you want to access a Bitmap from more than one thread, you should provide synchronization. However, you can access an immutable bitmap from multiple threads, as long as you abide by the `ImmutableBitmapDataProvider` interface. Kryo ----- @@ -317,14 +532,14 @@ the most significant 32~bits of elements whereas the values of the tree are 32-bit Roaring bitmaps. The 32-bit Roaring bitmaps represent the least significant bits of a set of elements. -The newer `Roaring64Bitmap` approach relies on the ART data structure to hold the key/value pair. The key +The newer `Roaring64Bitmap` approach relies on the ART data structure to hold the key/value pair. The key is made of the most significant 48~bits of elements whereas the values are 16-bit Roaring containers. It is inspired by [The Adaptive Radix Tree: ARTful Indexing for Main-Memory Databases](https://db.in.tum.de/~leis/papers/ART.pdf) by Leis et al. (ICDE '13). ```java import org.roaringbitmap.longlong.*; - + // first Roaring64NavigableMap LongBitmapDataProvider r = Roaring64NavigableMap.bitmapOf(1,2,100,1000); r.addLong(1234); @@ -360,12 +575,12 @@ Range Bitmaps `RangeBitmap` is a succinct data structure supporting range queries. Each value added to the bitmap is associated with an incremental identifier, and queries produce a `RoaringBitmap` of the identifiers associated with values -that satisfy the query. Every value added to the bitmap is stored separately, -so that if a value is added twice, it will be stored twice, and if that value +that satisfy the query. Every value added to the bitmap is stored separately, +so that if a value is added twice, it will be stored twice, and if that value is less than some threshold, there will be at least two integers in the resultant `RoaringBitmap`. -It is more efficient - in terms of both time and space - to +It is more efficient - in terms of both time and space - to provide a maximum value. If you don't know the maximum value, provide a `Long.MAX_VALUE`. Unsigned order is used like elsewhere in the library. @@ -405,34 +620,10 @@ Prerequisites - Version 0.6.x requires JDK 7 or better - Version 0.5.x requires JDK 6 or better -To build the project you need maven (version 3). -Download ---------- - -You can download releases from github: -https://github.com/RoaringBitmap/RoaringBitmap/releases - -Maven repository ----------------- -If your project depends on roaring, you can specify the dependency in the Maven "pom.xml" file: -```xml - - - org.roaringbitmap - RoaringBitmap - 0.9.9 - - -``` - -where you should replace the version number by the version you require. - -[For up-to-date releases, we recommend configuring maven and gradle to depend on the Jitpack repository](https://jitpack.io/#RoaringBitmap/RoaringBitmap). - -Usage +Usage for RoaringBitmap Developers ------ * Get java @@ -442,23 +633,23 @@ Usage * ``./gradlew test `` will run the tests * ``./gradlew :roaringbitmap:test --tests TestIterators.testIndexIterator4`` runs just the test `TestIterators.testIndexIterator4`; `./gradlew -i :roaringbitmap:test --tests TestRoaringBitmap.issue623` runs just the test `issue623` in the class ` TestRoaringBitmap` while printing out to the console. * ``./gradlew bsi:test --tests BufferBSITest.testEQ`` run just the test `BufferBSITest.testEQ` in the `bsi` submodule -* ``./gradlew checkstyleMain`` will check that you abide by the code style and that the code compiles. We enforce a strict style so that there is no debate as to the proper way to format the code. IntelliJ and Eclipse -------- -If you plan to contribute to RoaringBitmap, you can have load +If you plan to contribute to RoaringBitmap, you can load it up in your favorite IDE. - For IntelliJ, in the IDE create a new project, possibly from existing sources, choose import, gradle. -- For Eclipse: File, Import, Existing Gradle Projects, Select RoaringBitmap on my disk +- For Eclipse: File, Import, Existing Gradle Projects, Select RoaringBitmap from your disk. Contributing ------------ -Contributions are invited. We enforce the Google Java style. -Please run ``./gradlew checkstyleMain`` on your code before submitting -a patch. +Contributions are invited. We use the Google Java style (see `roaring_google_checks.xml`). It can be applied +automatically to your code with `./gradlew spotlessApply` + +Please do not reformat the code needlessly (especially on comments/javadoc). FAQ ---- @@ -512,11 +703,16 @@ application, you might be better served with a conventional bitset (e.g., Java's Benchmark ----------- -To run JMH benchmarks, use the following command: +To run JMH benchmarks, use the following commands: + + $ ./gradlew jmh::shadowJar + $ java -jar jmh/build/libs/benchmarks.jar + +You can also run a specific benchmark: - $ ./gradlew jmhJar + $ java -jar jmh/build/libs/benchmarks.jar 'org.roaringbitmap.aggregation.and.identical.*' -You can also run specific benchmarks... +If you have a bash shell, you can also run our script which automatically builds and run specific tests... $ ./jmh/run.sh 'org.roaringbitmap.aggregation.and.identical.*' @@ -524,7 +720,7 @@ You can also run specific benchmarks... Mailing list/discussion group ----------------------------- -https://groups.google.com/forum/#!forum/roaring-bitmaps +https://groups.google.com/forum/#!forum/roaringbitmaps Funding ---------- diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/NodeType.java b/RoaringBitmap/src/main/java/org/roaringbitmap/art/NodeType.java deleted file mode 100644 index ab7bacbc6..000000000 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/NodeType.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.roaringbitmap.art; - -public enum NodeType { - NODE4, NODE16, NODE48, NODE256, LEAF_NODE, DUMMY_ROOT; -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/ContainerBatchIteratorTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/ContainerBatchIteratorTest.java deleted file mode 100644 index f7a577976..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/ContainerBatchIteratorTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static java.util.Arrays.copyOfRange; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -@Execution(ExecutionMode.CONCURRENT) -public class ContainerBatchIteratorTest { - - private static int[][] DATA; - - @BeforeAll - public static void setup() { - DATA = Stream.of(IntStream.range(0, 20000).toArray(), - IntStream.range(0, 1 << 16).toArray(), - IntStream.range(0, 1 << 16).filter(i -> i < 500 || i > 2000).filter(i -> i < (1 << 15) || i > ((1 << 15) | (1 << 8))).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 12) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 11) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 10) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 9) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 8) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 7) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 6) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 5) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 4) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 3) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 2) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 1) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 3) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 5) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 7) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 9) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 271) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 1000) == 0).toArray(), - IntStream.empty().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray()).toArray(int[][]::new); - } - - @AfterAll - public static void clear() { - DATA = null; - } - - - public static Stream params() { - return Stream.of(DATA) - .flatMap(array -> IntStream.concat(IntStream.of( - 512, 1024, 2048, 4096, 8192, 65536 - ), IntStream.range(0, 100).map(i -> ThreadLocalRandom.current().nextInt(1, 65536))) - .mapToObj(i -> Arguments.of(array, i))); - } - - @ParameterizedTest(name = "{1}") - @MethodSource("params") - public void test(int[] expectedValues, int batchSize) { - int[] buffer = new int[batchSize]; - Container container = createContainer(expectedValues); - ContainerBatchIterator it = container.getBatchIterator(); - int cardinality = 0; - while (it.hasNext()) { - int from = cardinality; - cardinality += it.next(0, buffer); - assertArrayEquals( - copyOfRange(expectedValues, from, cardinality), copyOfRange(buffer, 0, cardinality - from), - "Failure with batch size " + batchSize); - } - assertEquals(expectedValues.length, cardinality); - } - - @ParameterizedTest(name = "{1}") - @MethodSource("params") - public void testAdvanceIfNeeded(int[] expectedValues, int batchSize) { - if (expectedValues.length < 2) { - return; - } - int[] buffer = new int[batchSize]; - Container container = createContainer(expectedValues); - ContainerBatchIterator it = container.getBatchIterator(); - int cardinality = expectedValues.length / 2; - int advanceUntil = expectedValues[cardinality]; - it.advanceIfNeeded((char) advanceUntil); - while (it.hasNext()) { - int from = cardinality; - cardinality += it.next(0, buffer); - assertArrayEquals( - copyOfRange(expectedValues, from, cardinality), copyOfRange(buffer, 0, cardinality - from), - "Failure with batch size " + batchSize + " and container type " + container.getContainerName()); - } - assertEquals(expectedValues.length, cardinality); - } - - private Container createContainer(int[] expectedValues) { - Container container = new ArrayContainer(); - for (int value : expectedValues) { - container = container.add((char) value); - } - return container.runOptimize(); - } -} \ No newline at end of file diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/KryoTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/KryoTest.java deleted file mode 100644 index 258ba7271..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/KryoTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.roaringbitmap; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.Serializer; -import com.esotericsoftware.kryo.io.Input; -import com.esotericsoftware.kryo.io.KryoDataInput; -import com.esotericsoftware.kryo.io.KryoDataOutput; -import com.esotericsoftware.kryo.io.Output; -import org.junit.jupiter.api.Test; - -import java.io.*; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class KryoTest { - public static Kryo createKryo() { - Kryo kryo = new Kryo(); - kryo.setRegistrationRequired(false); - kryo.register(RoaringBitmap.class, new RoaringSerializer()); - return kryo; - } - - public static void writeRoaringToFile(File f, - RoaringBitmap roaring, - Serializer serializer) throws FileNotFoundException { - Kryo kryo = createKryo(); - Output kryoOutputMap = new Output(new FileOutputStream(f)); - kryo.writeObjectOrNull(kryoOutputMap, roaring, serializer); - kryoOutputMap.flush(); - kryoOutputMap.close(); - } - - public static RoaringBitmap readRoaringFromFile(File f, - Serializer serializer) throws FileNotFoundException { - Kryo kryo = createKryo(); - Input inputMap = new Input(new FileInputStream(f)); - RoaringBitmap roaring = kryo.readObjectOrNull(inputMap, RoaringBitmap.class, serializer); - inputMap.close(); - return roaring; - } - - @Test - public void roaringTest() throws IOException { - RoaringSerializer serializer = new RoaringSerializer(); - RoaringBitmap roaringDense = new RoaringBitmap(); - for (int i = 0; i < 100_000; i++) { - roaringDense.add(i); - } - File tmpfiledense = File.createTempFile("roaring_dense", "bin"); - tmpfiledense.deleteOnExit(); - writeRoaringToFile(tmpfiledense, roaringDense, serializer); - RoaringBitmap denseRoaringFromFile = readRoaringFromFile(tmpfiledense, serializer); - assertEquals(denseRoaringFromFile, roaringDense); - - RoaringBitmap roaringSparse = new RoaringBitmap(); - for (int i = 0; i < 100_000; i++) { - if (i % 11 == 0) { - roaringSparse.add(i); - } - } - File tmpfilesparse = File.createTempFile("roaring_sparse", "bin"); - writeRoaringToFile(tmpfilesparse, roaringSparse, serializer); - RoaringBitmap sparseRoaringFromFile = readRoaringFromFile(tmpfilesparse, serializer); - assertEquals(sparseRoaringFromFile, roaringSparse); - } - -} - -class RoaringSerializer extends Serializer { - @Override - public void write(Kryo kryo, Output output, RoaringBitmap bitmap) { - try { - bitmap.serialize(new KryoDataOutput(output)); - } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException(); - } - } - - @Override - public RoaringBitmap read(Kryo kryo, Input input, Class type) { - RoaringBitmap bitmap = new RoaringBitmap(); - try { - bitmap.deserialize(new KryoDataInput(input)); - } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException(); - } - return bitmap; - } - -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/OrNotTruncationTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/OrNotTruncationTest.java deleted file mode 100644 index 77314b3f9..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/OrNotTruncationTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.function.Consumer; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.roaringbitmap.SeededTestData.TestDataSet.testCase; - -@Execution(ExecutionMode.CONCURRENT) -public class OrNotTruncationTest { - - private static final Consumer NO_OP = x -> { - }; - - - public static Stream params() { - return Stream.of( - Arguments.of(new RoaringBitmap(), NO_OP), - Arguments.of(new RoaringBitmap(), (Consumer) x -> x.add(2)), - Arguments.of(new RoaringBitmap(), (Consumer) x -> x.add(2L, 5L)), - Arguments.of(new RoaringBitmap(), (Consumer) x -> x.add(3L, 5L)), - Arguments.of(new RoaringBitmap(), (Consumer) x -> { - x.add(1L, 10L); - x.remove(2L, 10L); - }), - Arguments.of(new RoaringBitmap(), (Consumer) x -> { - for (int i : new int[]{0, 1, 2, 3, 4, 5, 6}) - x.add(i); - }), - Arguments.of(RoaringBitmap.bitmapOf(2), NO_OP), - Arguments.of(RoaringBitmap.bitmapOf(2, 3, 4), NO_OP), - Arguments.of(testCase().withArrayAt(0).build(), NO_OP), - Arguments.of(testCase().withRunAt(0).build(), NO_OP), - Arguments.of(testCase().withBitmapAt(0).build(), NO_OP), - Arguments.of(testCase().withArrayAt(0).withRunAt(1).build(), NO_OP), - Arguments.of(testCase().withRunAt(0).withRunAt(1).build(), NO_OP), - Arguments.of(testCase().withBitmapAt(0).withRunAt(1).build(), NO_OP), - Arguments.of(testCase().withArrayAt(1).build(), NO_OP), - Arguments.of(testCase().withRunAt(1).build(), NO_OP), - Arguments.of(testCase().withBitmapAt(1).build(), NO_OP), - Arguments.of(testCase().withArrayAt(1).withRunAt(2).build(), NO_OP), - Arguments.of(testCase().withRunAt(1).withRunAt(2).build(), NO_OP), - Arguments.of(testCase().withBitmapAt(1).withRunAt(2).build(), NO_OP) - ); - } - - @ParameterizedTest - @MethodSource("params") - public void testTruncation(RoaringBitmap other, Consumer init) { - RoaringBitmap one = new RoaringBitmap(); - one.add(0); - one.add(10); - init.accept(other); - one.orNot(other, 7); - assertTrue(one.contains(10)); - } - -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapBatchIteratorTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapBatchIteratorTest.java deleted file mode 100644 index 3ad09607f..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapBatchIteratorTest.java +++ /dev/null @@ -1,211 +0,0 @@ -package org.roaringbitmap; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.concurrent.TimeUnit; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.RoaringBitmapWriter.writer; -import static org.roaringbitmap.SeededTestData.TestDataSet.testCase; - -@Execution(ExecutionMode.CONCURRENT) -public class RoaringBitmapBatchIteratorTest { - - private static RoaringBitmap[] BITMAPS; - private static final int[] SIZES = { - 128, 256, 1024, 8192, 5, 127, 1023 - }; - - private static void initBitmaps() { - BITMAPS = new RoaringBitmap[] { - testCase().withArrayAt(0).withArrayAt(2).withArrayAt(4).withArrayAt((1 << 15) | (1 << 14)).build(), - testCase().withRunAt(0).withRunAt(2).withRunAt(4).withRunAt((1 << 15) | (1 << 14)).build(), - testCase().withBitmapAt(0).withRunAt(2).withBitmapAt(4).withBitmapAt((1 << 15) | (1 << 14)).build(), - testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).withBitmapAt((1 << 15) | (1 << 14)).build(), - testCase().withRunAt(0).withArrayAt(2).withBitmapAt(4).withRunAt((1 << 15) | (1 << 14)).build(), - testCase().withBitmapAt(0).withRunAt(2).withArrayAt(4).withBitmapAt((1 << 15) | (1 << 14)).build(), - testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).withArrayAt((1 << 15) | (1 << 14)).build(), - testCase().withBitmapAt(0).withArrayAt(2).withBitmapAt(4).withRunAt((1 << 15) | (1 << 14)).build(), - testCase().withRunAt((1 << 15) | (1 << 11)).withBitmapAt((1 << 15) | (1 << 12)).withArrayAt((1 << 15) | (1 << 13)).withBitmapAt((1 << 15) | (1 << 14)).build(), - RoaringBitmap.bitmapOf(IntStream.range(1 << 10, 1 << 26).filter(i -> (i & 1) == 0).toArray()), - RoaringBitmap.bitmapOf(IntStream.range(1 << 10, 1 << 25).filter(i -> ((i >>> 8) & 1) == 0).toArray()), - RoaringBitmap.bitmapOf(IntStream.range(0,127).toArray()), - RoaringBitmap.bitmapOf(IntStream.range(0,1024).toArray()), - RoaringBitmap.bitmapOf(IntStream.concat(IntStream.range(0,256), IntStream.range(1 << 16, (1 << 16) | 256)).toArray()), - RoaringBitmap.bitmapOf(8511), - new RoaringBitmap() - }; - } - - @BeforeAll - public static void beforeAll() throws InterruptedException { - int tryIndex = 0; - int maxTryIndex = 3; - while (++tryIndex < maxTryIndex) { - try { - initBitmaps(); - } catch (OutOfMemoryError e) { - if (tryIndex == maxTryIndex) { - throw e; - } - e.printStackTrace(); - System.out.println("RoaringBitmapBatchIteratorTest.beforeAll Issue on try #" + tryIndex + ". Sleeping 5s for other tests to complete"); - TimeUnit.SECONDS.sleep(5); - } - } - } - - @AfterAll - public static void clear() { - BITMAPS = null; - } - - - public static Stream params() { - return Stream.of(BITMAPS) - .flatMap(bitmap -> IntStream.of(SIZES).mapToObj(i -> Arguments.of(bitmap, i))); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAsIntIterator(RoaringBitmap bitmap, int size) { - IntIterator it = bitmap.getBatchIterator().asIntIterator(new int[size]); - RoaringBitmapWriter w = writer().constantMemory() - .initialCapacity(bitmap.highLowContainer.size).get(); - while (it.hasNext()) { - w.add(it.next()); - } - RoaringBitmap copy = w.get(); - assertEquals(bitmap, copy); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void test(RoaringBitmap bitmap, int batchSize) { - int[] buffer = new int[batchSize]; - RoaringBitmap result = new RoaringBitmap(); - RoaringBatchIterator it = bitmap.getBatchIterator(); - int cardinality = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - cardinality += batch; - } - assertEquals(bitmap, result); - assertEquals(bitmap.getCardinality(), cardinality); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAdvancedIfNeeded(RoaringBitmap bitmap, int batchSize) { - final int cardinality = bitmap.getCardinality(); - if (cardinality < 2) { - return; - } - int midpoint = bitmap.select(cardinality / 2); - int[] buffer = new int[batchSize]; - RoaringBitmap result = new RoaringBitmap(); - RoaringBatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded(midpoint); - int consumed = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - consumed += batch; - } - RoaringBitmap expected = bitmap.clone(); - expected.remove(0, midpoint & 0xFFFFFFFFL); - assertEquals(expected, result); - assertEquals(expected.getCardinality(), consumed); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAdvancedIfNeededToAbsentValue(RoaringBitmap bitmap, int batchSize) { - long firstAbsent = bitmap.nextAbsentValue(0); - int[] buffer = new int[batchSize]; - RoaringBitmap result = new RoaringBitmap(); - BatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded((int) firstAbsent); - int consumed = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - consumed += batch; - } - RoaringBitmap expected = bitmap.clone(); - expected.remove(0, firstAbsent & 0xFFFFFFFFL); - assertEquals(expected, result); - assertEquals(expected.getCardinality(), consumed); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAdvancedIfNeededBeyondLastValue(RoaringBitmap bitmap, int batchSize) { - long advanceTo = bitmap.isEmpty() ? 0 : bitmap.last() + 1; - int[] buffer = new int[batchSize]; - RoaringBitmap result = new RoaringBitmap(); - BatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded((int) advanceTo); - int consumed = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - consumed += batch; - } - assertEquals(0, consumed); - assertTrue(result.isEmpty()); - } - - @Test - public void testTimelyTermination() { - RoaringBitmap bm = RoaringBitmap.bitmapOf(8511); - BatchIterator bi = bm.getBatchIterator(); - int[] batch = new int[10]; - assertTrue(bi.hasNext()); - int n = bi.nextBatch(batch); - assertEquals(n, 1); - assertEquals(batch[0], 8511); - assertFalse(bi.hasNext()); - } - - @Test - public void testTimelyTerminationAfterAdvanceIfNeeded() { - RoaringBitmap bm = RoaringBitmap.bitmapOf(8511); - BatchIterator bi = bm.getBatchIterator(); - assertTrue(bi.hasNext()); - bi.advanceIfNeeded(8512); - assertFalse(bi.hasNext()); - } - - @Test - public void testBatchIteratorWithAdvanceIfNeeded() { - RoaringBitmap bitmap = RoaringBitmap.bitmapOf(3 << 16, (3 << 16) + 5, (3 << 16) + 10); - BatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded(6); - assertTrue(it.hasNext()); - int[] batch = new int[10]; - int n = it.nextBatch(batch); - assertEquals(n, 3); - assertEquals(batch[0], 3 << 16); - assertEquals(batch[1], (3 << 16) + 5); - assertEquals(batch[2], (3 << 16) + 10); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapSubsetTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapSubsetTest.java deleted file mode 100644 index b1d4477ac..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapSubsetTest.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.roaringbitmap; - -import com.google.common.collect.*; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class RoaringBitmapSubsetTest { - - - private static final Predicate DIVISIBLE_BY_4 = i -> i % 4 == 0; - - private static final Predicate DIVISIBLE_BY_3 = i -> i % 3 == 0; - - public static Stream params() { - return Stream.of( - Arguments.of( // array vs array - ImmutableSet.of(1, 2, 3, 4), - ImmutableSet.of(2, 3) - ), - Arguments.of( // array vs empty - ImmutableSet.of(1, 2, 3, 4), - ImmutableSet.of() - ), - Arguments.of( // identical arrays - ImmutableSet.of(1, 2, 3, 4), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // disjoint arrays - ImmutableSet.of(10, 12, 14, 15), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of(// disjoint arrays, cardinality mismatch - ImmutableSet.of(10, 12, 14), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // run vs array, subset - ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // run vs array, subset - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // run vs empty - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of() - ), - Arguments.of( // identical runs, 1 container - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()) - ), - Arguments.of( // identical runs, 2 containers - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()), - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()) - ), - Arguments.of( // disjoint array vs run, either side of container boundary - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of((1 << 16) + 1, (1 << 16) + 2, (1 << 16) + 3, (1 << 16) + 4) - ), - Arguments.of( // disjoint array vs run - ContiguousSet.create(Range.closed(3, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of(1, 2) - ), - Arguments.of( // run vs run, overlap with shift - ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()), - ContiguousSet.create(Range.closed(1 << 4, 1 << 12), DiscreteDomain.integers()) - ), - Arguments.of( // run vs run, subset - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()), - ImmutableSet.of(1, 1 << 8) - ), - Arguments.of( // run vs run, overlap with shift, 2 containers - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()), - ImmutableSet.of(1 << 6, 1 << 26) - ), - Arguments.of( // run vs 2 container run, overlap - ImmutableSet.of(1, 1 << 16), - ContiguousSet.create(Range.closed(0, 1 << 20), DiscreteDomain.integers()) - ), - Arguments.of( // bitmap vs intersecting array - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.of(4, 8) - ), - Arguments.of( // bitmap vs bitmap, cardinality mismatch - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 16), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // bitmap vs empty - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.of() - ), - Arguments.of( // identical bitmaps - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // bitmap vs overlapping but disjoint array - ImmutableSet.of(3, 7), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // bitmap vs overlapping but disjoint bitmap - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_3::test)), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // disjoint, large (signed-negative) keys - ImmutableSet.of(0xbf09001d, 0xbf090169), - ImmutableSet.of(0x8088000e, 0x80880029) - )); - } - - - @ParameterizedTest(name = "assert that {1} is subset of {0}") - @MethodSource("params") - public void testProperSubset(Set superSet, Set subSet) { - RoaringBitmap superSetRB = create(superSet); - RoaringBitmap subSetRB = create(subSet); - assertEquals(superSet.containsAll(subSet), superSetRB.contains(subSetRB)); - // reverse the test - assertEquals(subSet.containsAll(superSet), subSetRB.contains(superSetRB)); - } - - private RoaringBitmap create(Set set) { - RoaringBitmap rb = new RoaringBitmap(); - if (set instanceof ContiguousSet) { - ContiguousSet contiguousSet = (ContiguousSet) set; - rb.add(contiguousSet.first().longValue(), contiguousSet.last().longValue()); - } else { - for (Integer i : set) { - rb.add(i); - } - } - return rb; - } - - -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapWriterRandomisedTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapWriterRandomisedTest.java deleted file mode 100644 index 78ca1c4cb..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapWriterRandomisedTest.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.Arrays; -import java.util.Random; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.roaringbitmap.RoaringBitmapWriter.writer; -import static org.roaringbitmap.Util.toUnsignedLong; - -@Execution(ExecutionMode.CONCURRENT) -public class RoaringBitmapWriterRandomisedTest { - - private static int[][] ARRAYS; - - @BeforeAll - public static void init() { - ARRAYS = new int[][] { - new int[]{0, 1, 2, 3}, - randomArray(0), - randomArray(10), - randomArray(100), - randomArray(1000), - randomArray(10_000), - randomArray(100_000), - randomArray(1000_000), - randomArray(10_000_000) - }; - } - - @AfterAll - public static void clear() { - ARRAYS = null; - } - - public static Stream tests() { - return Stream.of(ARRAYS).map(Arguments::of); - } - - @ParameterizedTest(name = "-") - @MethodSource("tests") - public void shouldBuildSameBitmapAsBitmapOf(int[] values) { - RoaringBitmapWriter writer = writer() - .expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))) - .get(); - for (int i : values) { - writer.add(i); - } - writer.flush(); - verify(writer.getUnderlying(), values); - } - - @ParameterizedTest(name = "-") - @MethodSource("tests") - public void shouldBuildSameBitmapAsBitmapOfWithAddMany(int[] values) { - RoaringBitmapWriter writer = writer() - .expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))) - .get(); - writer.addMany(values); - writer.flush(); - verify(writer.getUnderlying(), values); - } - - @ParameterizedTest(name = "-") - @MethodSource("tests") - public void getShouldFlushToTheUnderlyingBitmap(int[] values) { - RoaringBitmapWriter writer = writer() - .expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))) - .get(); - writer.addMany(values); - verify(writer.get(), values); - } - - @ParameterizedTest(name = "-") - @MethodSource("tests") - public void getShouldFlushToTheUnderlyingBitmap_ConstantMemory(int[] values) { - RoaringBitmapWriter writer = writer() - .constantMemory() - .get(); - writer.addMany(values); - verify(writer.get(), values); - } - - @ParameterizedTest(name = "-") - @MethodSource("tests") - public void shouldBuildSameBitmapAsBitmapOf_ConstantMemory(int[] values) { - RoaringBitmapWriter writer = writer() - .constantMemory() - .expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))) - .get(); - for (int i : values) { - writer.add(i); - } - writer.flush(); - verify(writer.getUnderlying(), values); - } - - @ParameterizedTest(name = "-") - @MethodSource("tests") - public void shouldBuildSameBitmapAsBitmapOfWithAddMany_ConstantMemory(int[] values) { - RoaringBitmapWriter writer = writer() - .constantMemory() - .expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))) - .get(); - writer.addMany(values); - writer.flush(); - verify(writer.getUnderlying(), values); - } - - private void verify(RoaringBitmap rb, int[] values) { - RoaringBitmap baseline = RoaringBitmap.bitmapOf(values); - RoaringArray baselineHLC = baseline.highLowContainer; - RoaringArray rbHLC = rb.highLowContainer; - assertEquals(baselineHLC.size, rbHLC.size); - for (int i = 0; i < baselineHLC.size; ++i) { - Container baselineContainer = baselineHLC.getContainerAtIndex(i); - Container rbContainer = rbHLC.getContainerAtIndex(i); - assertEquals(baselineContainer, rbContainer); - } - assertEquals(baseline, rb); - } - - private static int[] randomArray(int size) { - Random random = new Random(1234); - int[] data = new int[size]; - int last = 0; - int i = 0; - while (i < size) { - if (random.nextGaussian() > 0.1) { - int runLength = random.nextInt(Math.min(size - i, 1 << 16)); - for (int j = 1; j < runLength; ++j) { - data[i + j] = last + 1; - last = data[i + j]; - } - i += runLength; - } else { - data[i] = last + 1 + random.nextInt(999); - last = data[i]; - ++i; - } - } - Arrays.sort(data); - return data; - } - - private int max(int[] values) { - return values.length == 0 ? 0 : values[values.length - 1]; - } - - private int min() { - return 0; - } -} \ No newline at end of file diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestAdversarialInputs.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestAdversarialInputs.java deleted file mode 100644 index 91ce47b7d..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestAdversarialInputs.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.roaringbitmap; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.*; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - - -public class TestAdversarialInputs { - - public static Stream badFiles() { - return IntStream.rangeClosed(1, 7) - .mapToObj(i -> Arguments.of("/testdata/crashproneinput" + i + ".bin")); - } - - // open a stream without copying files - public static InputStream openInputstream(String resourceName) throws IOException { - InputStream resourceAsStream = TestAdversarialInputs.class.getResourceAsStream(resourceName); - if(resourceAsStream == null) { - throw new IOException("Cannot get resource \"" + resourceName + "\"."); - } - return resourceAsStream; - } - - @Test - public void testInputGoodFile1() throws IOException { - InputStream inputStream = openInputstream("/testdata/bitmapwithruns.bin"); - RoaringBitmap rb = new RoaringBitmap(); - // should not throw an exception - rb.deserialize(new DataInputStream(inputStream)); - assertEquals(rb.getCardinality(), 200100); - } - - @Test - public void testInputGoodFile2() throws IOException { - InputStream inputStream = openInputstream("/testdata/bitmapwithoutruns.bin"); - RoaringBitmap rb = new RoaringBitmap(); - // should not throw an exception - rb.deserialize(new DataInputStream(inputStream)); - assertEquals(rb.getCardinality(), 200100); - } - - @ParameterizedTest - @MethodSource("badFiles") - public void testInputBadFile8(String fileName) { - assertThrows(IOException.class, () -> deserialize(fileName)); - } - - - private void deserialize(String fileName) throws IOException { - InputStream inputStream = openInputstream(fileName); - RoaringBitmap rb = new RoaringBitmap(); - // should not work - rb.deserialize(new DataInputStream(inputStream)); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java deleted file mode 100644 index f7602e731..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java +++ /dev/null @@ -1,953 +0,0 @@ -package org.roaringbitmap; - -import com.google.common.primitives.Ints; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Arrays; -import java.util.List; -import java.util.NoSuchElementException; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.ValidationRangeConsumer.Value.*; - -@Execution(ExecutionMode.CONCURRENT) -public class TestArrayContainer { - - @Test - public void testConst() { - ArrayContainer ac1 = new ArrayContainer(5, 15); - char[] data = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; - ArrayContainer ac2 = new ArrayContainer(data); - assertEquals(ac1, ac2); - } - - @Test - public void testRemove() { - ArrayContainer ac1 = new ArrayContainer(5, 15); - ac1.remove((char)14); - ArrayContainer ac2 = new ArrayContainer(5, 14); - assertEquals(ac1, ac2); - } - - @Test - public void arrayContainersNeverFull() { - assertFalse(new ArrayContainer(5, 15).isFull()); - } - - @Test - public void testToString() { - ArrayContainer ac1 = new ArrayContainer(5, 15); - ac1.add((char) -3); - ac1.add((char) -17); - assertEquals("{5,6,7,8,9,10,11,12,13,14,65519,65533}", ac1.toString()); - } - - @Test - public void testIandNot() { - ArrayContainer ac1 = new ArrayContainer(5, 15); - ArrayContainer ac2 = new ArrayContainer(10, 15); - BitmapContainer bc = new BitmapContainer(5, 10); - ArrayContainer ac3 = ac1.iandNot(bc); - assertEquals(ac2, ac3); - } - - @Test - public void testReverseArrayContainerShortIterator() { - //Test Clone - ArrayContainer ac1 = new ArrayContainer(5, 15); - ReverseArrayContainerCharIterator rac1 = new ReverseArrayContainerCharIterator(ac1); - CharIterator rac2 = rac1.clone(); - assertNotNull(rac2); - assertEquals(asList(rac1), asList(rac2)); - } - - private static List asList(CharIterator ints) { - int[] values = new int[10]; - int size = 0; - while (ints.hasNext()) { - if (!(size < values.length)) { - values = Arrays.copyOf(values, values.length * 2); - } - values[size++] = ints.next(); - } - return Ints.asList(Arrays.copyOf(values, size)); - } - - @Test - public void roundtrip() throws Exception { - Container ac = new ArrayContainer(); - ac = ac.add(1, 5); - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try (ObjectOutputStream oo = new ObjectOutputStream(bos)) { - ac.writeExternal(oo); - } - Container ac2 = new ArrayContainer(); - final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); - ac2.readExternal(new ObjectInputStream(bis)); - - assertEquals(4, ac2.getCardinality()); - for (int i = 1; i < 5; i++) { - assertTrue(ac2.contains((char) i)); - } - } - - @Test - public void intersectsArray() { - Container ac = new ArrayContainer(); - ac = ac.add(1, 10); - Container ac2 = new ArrayContainer(); - ac2 = ac2.add(5, 25); - assertTrue(ac.intersects(ac2)); - } - - @Test - public void orFullToRunContainer() { - ArrayContainer ac = new ArrayContainer(0, 1 << 12); - BitmapContainer half = new BitmapContainer(1 << 12, 1 << 16); - Container result = ac.or(half); - assertEquals(1 << 16, result.getCardinality()); - assertTrue(result instanceof RunContainer); - } - - @Test - public void orFullToRunContainer2() { - ArrayContainer ac = new ArrayContainer(0, 1 << 15); - ArrayContainer half = new ArrayContainer(1 << 15, 1 << 16); - Container result = ac.or(half); - assertEquals(1 << 16, result.getCardinality()); - assertTrue(result instanceof RunContainer); - } - - @Test - public void iandBitmap() { - Container ac = new ArrayContainer(); - ac = ac.add(1, 10); - Container bc = new BitmapContainer(); - bc = bc.add(5, 25); - ac.iand(bc); - assertEquals(5, ac.getCardinality()); - for (int i = 5; i < 10; i++) { - assertTrue(ac.contains((char) i)); - } - } - - @Test - public void iandRun() { - Container ac = new ArrayContainer(); - ac = ac.add(1, 10); - Container rc = new RunContainer(); - rc = rc.add(5, 25); - ac = ac.iand(rc); - assertEquals(5, ac.getCardinality()); - for (int i = 5; i < 10; i++) { - assertTrue(ac.contains((char) i)); - } - } - - @Test - public void addEmptyRange() { - Container ac = new ArrayContainer(); - ac = ac.add(1,1); - assertEquals(0, ac.getCardinality()); - } - - @Test - public void addInvalidRange() { - assertThrows(IllegalArgumentException.class, () -> { - Container ac = new ArrayContainer(); - ac.add(13, 1); - }); - } - - @Test - public void iaddEmptyRange() { - Container ac = new ArrayContainer(); - ac = ac.iadd(1,1); - assertEquals(0, ac.getCardinality()); - } - - @Test - public void iaddInvalidRange() { - assertThrows(IllegalArgumentException.class, () -> { - Container ac = new ArrayContainer(); - ac.iadd(13, 1); - }); - } - - @Test - public void iaddSanityTest() { - Container ac = new ArrayContainer(); - ac = ac.iadd(10,20); - //insert disjoint at end - ac = ac.iadd(30,70); - //insert disjoint between - ac = ac.iadd(25,26); - //insert disjoint at start - ac = ac.iadd(1,2); - //insert overlap at end - ac = ac.iadd(60,80); - //insert overlap between - ac = ac.iadd(10,30); - //insert overlap at start - ac = ac.iadd(1,20); - assertEquals(79, ac.getCardinality()); - } - - @Test - public void clear() { - Container ac = new ArrayContainer(); - ac = ac.add(1, 10); - ac.clear(); - assertEquals(0, ac.getCardinality()); - } - - @Test - public void testLazyORFull() { - ArrayContainer ac = new ArrayContainer(0, 1 << 15); - ArrayContainer ac2 = new ArrayContainer(1 << 15, 1 << 16); - Container rbc = ac.lazyor(ac2); - assertEquals(-1, rbc.getCardinality()); - Container repaired = rbc.repairAfterLazy(); - assertEquals(1 << 16, repaired.getCardinality()); - assertTrue(repaired instanceof RunContainer); - } - - @Test - public void testFirst_Empty() { - assertThrows(NoSuchElementException.class, () -> new ArrayContainer().first()); - } - - @Test - public void testLast_Empty() { - assertThrows(NoSuchElementException.class, () -> new ArrayContainer().last()); - } - - @Test - public void testFirstLast() { - Container rc = new ArrayContainer(); - final int firstInclusive = 1; - int lastExclusive = firstInclusive; - for (int i = 0; i < 1 << 16 - 10; ++i) { - int newLastExclusive = lastExclusive + 10; - rc = rc.add(lastExclusive, newLastExclusive); - assertEquals(firstInclusive, rc.first()); - assertEquals(newLastExclusive - 1, rc.last()); - lastExclusive = newLastExclusive; - } - } - - @Test - public void testContainsBitmapContainer_ExcludeShiftedSet() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new BitmapContainer().add(2,12); - assertFalse(ac.contains(subset)); - } - - @Test - public void testContainsBitmapContainer_AlwaysFalse() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new BitmapContainer().add(0,10); - assertFalse(ac.contains(subset)); - } - - @Test - public void testContainsBitmapContainer_ExcludeSuperSet() { - Container ac = new ArrayContainer().add(0,10); - Container superset = new BitmapContainer().add(0,20); - assertFalse(ac.contains(superset)); - } - - @Test - public void testContainsBitmapContainer_ExcludeDisJointSet() { - Container ac = new ArrayContainer().add(0,10); - Container disjoint = new BitmapContainer().add(20, 40); - assertFalse(ac.contains(disjoint)); - assertFalse(disjoint.contains(ac)); - } - - @Test - public void testContainsRunContainer_EmptyContainsEmpty() { - Container ac = new ArrayContainer(); - Container subset = new RunContainer(); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsRunContainer_IncludeProperSubset() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new RunContainer().add(0,9); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsRunContainer_IncludeSelf() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new RunContainer().add(0,10); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsRunContainer_ExcludeSuperSet() { - Container ac = new ArrayContainer().add(0,10); - Container superset = new RunContainer().add(0,20); - assertFalse(ac.contains(superset)); - } - - @Test - public void testContainsRunContainer_IncludeProperSubsetDifferentStart() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new RunContainer().add(1,9); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsRunContainer_ExcludeShiftedSet() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new RunContainer().add(2,12); - assertFalse(ac.contains(subset)); - } - - @Test - public void testContainsRunContainer_ExcludeDisJointSet() { - Container ac = new ArrayContainer().add(0,10); - Container disjoint = new RunContainer().add(20, 40); - assertFalse(ac.contains(disjoint)); - assertFalse(disjoint.contains(ac)); - } - - @Test - public void testContainsArrayContainer_EmptyContainsEmpty() { - Container ac = new ArrayContainer(); - Container subset = new ArrayContainer(); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsArrayContainer_IncludeProperSubset() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new ArrayContainer().add(0,9); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsArrayContainer_IncludeProperSubsetDifferentStart() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new ArrayContainer().add(2,9); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsArrayContainer_ExcludeShiftedSet() { - Container ac = new ArrayContainer().add(0,10); - Container shifted = new ArrayContainer().add(2,12); - assertFalse(ac.contains(shifted)); - } - - @Test - public void testContainsArrayContainer_IncludeSelf() { - Container ac = new ArrayContainer().add(0,10); - Container subset = new ArrayContainer().add(0,10); - assertTrue(ac.contains(subset)); - } - - @Test - public void testContainsArrayContainer_ExcludeSuperSet() { - Container ac = new ArrayContainer().add(0,10); - Container superset = new ArrayContainer().add(0,20); - assertFalse(ac.contains(superset)); - } - - @Test - public void testContainsArrayContainer_ExcludeDisJointSet() { - Container ac = new ArrayContainer().add(0, 10); - Container disjoint = new ArrayContainer().add(20, 40); - assertFalse(ac.contains(disjoint)); - assertFalse(disjoint.contains(ac)); - } - - @Test - public void iorNotIncreaseCapacity() { - Container ac1 = new ArrayContainer(); - Container ac2 = new ArrayContainer(); - ac1.add((char) 128); - ac1.add((char) 256); - ac2.add((char) 1024); - - ac1.ior(ac2); - assertTrue(ac1.contains((char) 128)); - assertTrue(ac1.contains((char) 256)); - assertTrue(ac1.contains((char) 1024)); - } - - @Test - public void iorIncreaseCapacity() { - Container ac1 = new ArrayContainer(); - Container ac2 = new ArrayContainer(); - ac1.add((char) 128); - ac1.add((char) 256); - ac1.add((char) 512); - ac1.add((char) 513); - ac2.add((char) 1024); - - ac1.ior(ac2); - assertTrue(ac1.contains((char) 128)); - assertTrue(ac1.contains((char) 256)); - assertTrue(ac1.contains((char) 512)); - assertTrue(ac1.contains((char) 513)); - assertTrue(ac1.contains((char) 1024)); - } - - @Test - public void iorSanityCheck() { - Container ac = new ArrayContainer().add(0, 10); - Container disjoint = new ArrayContainer().add(20, 40); - ac.ior(disjoint); - assertTrue(ac.contains(disjoint)); - } - - @Test - public void iorNot() { - Container rc1 = new ArrayContainer(); - Container rc2 = new ArrayContainer(); - - rc1.iadd(257, 258); - rc2.iadd(128, 256); - rc1 = rc1.iorNot(rc2, 258); - assertEquals(130, rc1.getCardinality()); - - PeekableCharIterator iterator = rc1.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(257, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - @Test - public void iorNot2() { - Container rc1 = new ArrayContainer(); - Container rc2 = new ArrayContainer(); - rc2.iadd(128, 256).iadd(257, 260); - rc1 = rc1.iorNot(rc2, 261); - assertEquals(130, rc1.getCardinality()); - - PeekableCharIterator iterator = rc1.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(260, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - @Test - public void iorNot3() { - Container rc1 = new ArrayContainer(); - Container rc2 = new BitmapContainer(); - - rc1.iadd(257, 258); - rc2.iadd(128, 256); - rc1 = rc1.iorNot(rc2, 258); - assertEquals(130, rc1.getCardinality()); - - PeekableCharIterator iterator = rc1.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(257, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - @Test - public void iorNot4() { - Container rc1 = new ArrayContainer(); - Container rc2 = new RunContainer(); - - rc1.iadd(257, 258); - rc2.iadd(128, 256); - rc1 = rc1.iorNot(rc2, 258); - assertEquals(130, rc1.getCardinality()); - - PeekableCharIterator iterator = rc1.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(257, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - @Test - public void orNot() { - final Container rc1 = new ArrayContainer(); - - { - Container rc2 = new ArrayContainer(); - rc2.iadd(128, 256); - Container res = rc1.orNot(rc2, 257); - assertEquals(129, res.getCardinality()); - - PeekableCharIterator iterator = res.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - { - Container rc2 = new BitmapContainer(); - rc2.iadd(128, 256); - Container res = rc1.orNot(rc2, 257); - assertEquals(129, res.getCardinality()); - - PeekableCharIterator iterator = res.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - { - Container rc2 = new RunContainer(); - rc2.iadd(128, 256); - Container res = rc1.orNot(rc2, 257); - assertEquals(129, res.getCardinality()); - - PeekableCharIterator iterator = res.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - } - - @Test - public void orNot2() { - Container rc1 = new ArrayContainer(); - Container rc2 = new ArrayContainer(); - rc2.iadd(128, 256).iadd(257, 260); - rc1 = rc1.orNot(rc2, 261); - assertEquals(130, rc1.getCardinality()); - - PeekableCharIterator iterator = rc1.getCharIterator(); - for (int i = 0; i < 128; i++) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertTrue(iterator.hasNext()); - assertEquals(256, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(260, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - @Test - public void testIntersectsWithRange() { - Container container = new ArrayContainer().add(0, 10); - assertTrue(container.intersects(0, 1)); - assertTrue(container.intersects(0, 101)); - assertTrue(container.intersects(0, lower16Bits(-1))); - assertFalse(container.intersects(11, lower16Bits(-1))); - } - - - @Test - public void testIntersectsWithRange2() { - Container container = new ArrayContainer().add(lower16Bits(-50), lower16Bits(-10)); - assertFalse(container.intersects(0, 1)); - assertTrue(container.intersects(0, lower16Bits(-40))); - assertFalse(container.intersects(lower16Bits(-100), lower16Bits(-55))); - assertFalse(container.intersects(lower16Bits(-9), lower16Bits(-1))); - assertTrue(container.intersects(11, 1 << 16)); - } - - - @Test - public void testIntersectsWithRange3() { - Container container = new ArrayContainer() - .add((char) 1) - .add((char) 300) - .add((char) 1024); - assertTrue(container.intersects(0, 300)); - assertTrue(container.intersects(1, 300)); - assertFalse(container.intersects(2, 300)); - assertFalse(container.intersects(2, 299)); - assertTrue(container.intersects(0, lower16Bits(-1))); - assertFalse(container.intersects(1025, 1 << 16)); - } - - - @Test - public void testContainsRange() { - Container ac = new ArrayContainer().add(20, 100); - assertFalse(ac.contains(1, 21)); - assertFalse(ac.contains(1, 19)); - assertTrue(ac.contains(20, 100)); - assertTrue(ac.contains(20, 99)); - assertTrue(ac.contains(21, 100)); - assertFalse(ac.contains(21, 101)); - assertFalse(ac.contains(19, 99)); - assertFalse(ac.contains(190, 9999)); - } - - @Test - public void testContainsRange2() { - Container ac = new ArrayContainer() - .add((char)1).add((char)10) - .add(20, 100); - assertFalse(ac.contains(1, 21)); - assertFalse(ac.contains(1, 20)); - assertTrue(ac.contains(1, 2)); - } - - @Test - public void testContainsRangeUnsigned() { - Container ac = new ArrayContainer().add(1 << 15, 1 << 8 | 1 << 15); - assertTrue(ac.contains(1 << 15, 1 << 8 | 1 << 15)); - assertTrue(ac.contains(1 + (1 << 15), (1 << 8 | 1 << 15) - 1)); - assertFalse(ac.contains(1 + (1 << 15), (1 << 8 | 1 << 15) + 1)); - assertFalse(ac.contains((1 << 15) - 1, (1 << 8 | 1 << 15) - 1)); - assertFalse(ac.contains(0, 1 << 15)); - assertFalse(ac.contains(1 << 8 | 1 << 15 | 1, 1 << 16)); - } - - @Test - public void testNextValueBeforeStart() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(10, container.nextValue((char)5)); - } - - @Test - public void testNextValue() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(10, container.nextValue((char)10)); - assertEquals(20, container.nextValue((char)11)); - assertEquals(30, container.nextValue((char)30)); - } - - @Test - public void testNextValueAfterEnd() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(-1, container.nextValue((char)31)); - } - - @Test - public void testNextValue2() { - Container container = new ArrayContainer().iadd(64, 129); - assertTrue(container instanceof ArrayContainer); - assertEquals(64, container.nextValue((char)0)); - assertEquals(64, container.nextValue((char)64)); - assertEquals(65, container.nextValue((char)65)); - assertEquals(128, container.nextValue((char)128)); - assertEquals(-1, container.nextValue((char)129)); - assertEquals(-1, container.nextValue((char)5000)); - } - - @Test - public void testNextValueBetweenRuns() { - Container container = new ArrayContainer().iadd(64, 129).iadd(256, 321); - assertTrue(container instanceof ArrayContainer); - assertEquals(64, container.nextValue((char)0)); - assertEquals(64, container.nextValue((char)64)); - assertEquals(65, container.nextValue((char)65)); - assertEquals(128, container.nextValue((char)128)); - assertEquals(256, container.nextValue((char)129)); - assertEquals(-1, container.nextValue((char)512)); - } - - @Test - public void testNextValue3() { - Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201); - assertTrue(container instanceof ArrayContainer); - assertEquals(64, container.nextValue((char)0)); - assertEquals(64, container.nextValue((char)63)); - assertEquals(64, container.nextValue((char)64)); - assertEquals(65, container.nextValue((char)65)); - assertEquals(128, container.nextValue((char)128)); - assertEquals(200, container.nextValue((char)129)); - assertEquals(200, container.nextValue((char)199)); - assertEquals(200, container.nextValue((char)200)); - assertEquals(250, container.nextValue((char)250)); - assertEquals(5000, container.nextValue((char)2500)); - assertEquals(5000, container.nextValue((char)5000)); - assertEquals(5200, container.nextValue((char)5200)); - assertEquals(-1, container.nextValue((char)5201)); - } - - @Test - public void testPreviousValue1() { - Container container = new ArrayContainer().iadd(64, 129); - assertTrue(container instanceof ArrayContainer); - assertEquals(-1, container.previousValue((char)0)); - assertEquals(-1, container.previousValue((char)63)); - assertEquals(64, container.previousValue((char)64)); - assertEquals(65, container.previousValue((char)65)); - assertEquals(128, container.previousValue((char)128)); - assertEquals(128, container.previousValue((char)129)); - } - - @Test - public void testPreviousValue2() { - Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201); - assertTrue(container instanceof ArrayContainer); - assertEquals(-1, container.previousValue((char)0)); - assertEquals(-1, container.previousValue((char)63)); - assertEquals(64, container.previousValue((char)64)); - assertEquals(65, container.previousValue((char)65)); - assertEquals(128, container.previousValue((char)128)); - assertEquals(128, container.previousValue((char)129)); - assertEquals(128, container.previousValue((char)199)); - assertEquals(200, container.previousValue((char)200)); - assertEquals(250, container.previousValue((char)250)); - assertEquals(500, container.previousValue((char)2500)); - assertEquals(5000, container.previousValue((char)5000)); - assertEquals(5200, container.previousValue((char)5200)); - } - - @Test - public void testPreviousValueBeforeStart() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(-1, container.previousValue((char)5)); - } - - @Test - public void testPreviousValueSparse() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(-1, container.previousValue((char)9)); - assertEquals(10, container.previousValue((char)10)); - assertEquals(10, container.previousValue((char)11)); - assertEquals(20, container.previousValue((char)21)); - assertEquals(30, container.previousValue((char)30)); - } - - @Test - public void testPreviousValueUnsigned() { - ArrayContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}); - assertEquals(-1, container.previousValue((char)((1 << 15) | 4))); - assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 5))); - assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 6))); - assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 7))); - assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 8))); - } - - @Test - public void testNextValueUnsigned() { - ArrayContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}); - assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 4))); - assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 5))); - assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 6))); - assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 7))); - assertEquals(-1, container.nextValue((char)((1 << 15) | 8))); - } - - @Test - public void testPreviousValueAfterEnd() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(30, container.previousValue((char)31)); - } - - @Test - public void testPreviousAbsentValue1() { - Container container = new ArrayContainer().iadd(64, 129); - assertEquals(0, container.previousAbsentValue((char)0)); - assertEquals(63, container.previousAbsentValue((char)63)); - assertEquals(63, container.previousAbsentValue((char)64)); - assertEquals(63, container.previousAbsentValue((char)65)); - assertEquals(63, container.previousAbsentValue((char)128)); - assertEquals(129, container.previousAbsentValue((char)129)); - } - - @Test - public void testPreviousAbsentValue2() { - Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201); - assertEquals(0, container.previousAbsentValue((char)0)); - assertEquals(63, container.previousAbsentValue((char)63)); - assertEquals(63, container.previousAbsentValue((char)64)); - assertEquals(63, container.previousAbsentValue((char)65)); - assertEquals(63, container.previousAbsentValue((char)128)); - assertEquals(129, container.previousAbsentValue((char)129)); - assertEquals(199, container.previousAbsentValue((char)199)); - assertEquals(199, container.previousAbsentValue((char)200)); - assertEquals(199, container.previousAbsentValue((char)250)); - assertEquals(2500, container.previousAbsentValue((char)2500)); - assertEquals(4999, container.previousAbsentValue((char)5000)); - assertEquals(4999, container.previousAbsentValue((char)5200)); - } - - @Test - public void testPreviousAbsentValueEmpty() { - ArrayContainer container = new ArrayContainer(); - for (int i = 0; i < 1000; i++) { - assertEquals(i, container.previousAbsentValue((char)i)); - } - } - - @Test - public void testPreviousAbsentValueSparse() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(9, container.previousAbsentValue((char)9)); - assertEquals(9, container.previousAbsentValue((char)10)); - assertEquals(11, container.previousAbsentValue((char)11)); - assertEquals(21, container.previousAbsentValue((char)21)); - assertEquals(29, container.previousAbsentValue((char)30)); - } - - @Test - public void testPreviousAbsentValueUnsigned() { - ArrayContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}); - assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 4))); - assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 5))); - assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 6))); - assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 7))); - assertEquals(((1 << 15) | 8), container.previousAbsentValue((char)((1 << 15) | 8))); - } - - - @Test - public void testNextAbsentValue1() { - Container container = new ArrayContainer().iadd(64, 129); - assertEquals(0, container.nextAbsentValue((char)0)); - assertEquals(63, container.nextAbsentValue((char)63)); - assertEquals(129, container.nextAbsentValue((char)64)); - assertEquals(129, container.nextAbsentValue((char)65)); - assertEquals(129, container.nextAbsentValue((char)128)); - assertEquals(129, container.nextAbsentValue((char)129)); - } - - @Test - public void testNextAbsentValue2() { - Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201); - assertEquals(0, container.nextAbsentValue((char)0)); - assertEquals(63, container.nextAbsentValue((char)63)); - assertEquals(129, container.nextAbsentValue((char)64)); - assertEquals(129, container.nextAbsentValue((char)65)); - assertEquals(129, container.nextAbsentValue((char)128)); - assertEquals(129, container.nextAbsentValue((char)129)); - assertEquals(199, container.nextAbsentValue((char)199)); - assertEquals(501, container.nextAbsentValue((char)200)); - assertEquals(501, container.nextAbsentValue((char)250)); - assertEquals(2500, container.nextAbsentValue((char)2500)); - assertEquals(5201, container.nextAbsentValue((char)5000)); - assertEquals(5201, container.nextAbsentValue((char)5200)); - } - - @Test - public void testNextAbsentValueEmpty() { - ArrayContainer container = new ArrayContainer(); - for (int i = 0; i < 1000; i++) { - assertEquals(i, container.nextAbsentValue((char)i)); - } - } - - @Test - public void testNextAbsentValueSparse() { - ArrayContainer container = new ArrayContainer(new char[] { 10, 20, 30}); - assertEquals(9, container.nextAbsentValue((char)9)); - assertEquals(11, container.nextAbsentValue((char)10)); - assertEquals(11, container.nextAbsentValue((char)11)); - assertEquals(21, container.nextAbsentValue((char)21)); - assertEquals(31, container.nextAbsentValue((char)30)); - } - - @Test - public void testNextAbsentValueUnsigned() { - ArrayContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}); - assertEquals(((1 << 15) | 4), container.nextAbsentValue((char)((1 << 15) | 4))); - assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 5))); - assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 6))); - assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 7))); - assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 8))); - } - - @Test - public void testRangeConsumer() { - char[] entries = new char[] {3, 4, 7, 8, 10, 65530, 65534, 65535}; - ArrayContainer container = new ArrayContainer(entries); - - ValidationRangeConsumer consumer = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] { - ABSENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, PRESENT - }); - container.forAllUntil(0, (char) 11, consumer); - assertEquals(11, consumer.getNumberOfValuesConsumed()); - - ValidationRangeConsumer consumer2 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] { - PRESENT, ABSENT, ABSENT, PRESENT, PRESENT - }); - container.forAllInRange((char) 4, (char) 9, consumer2); - assertEquals(5, consumer2.getNumberOfValuesConsumed()); - - ValidationRangeConsumer consumer3 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] { - PRESENT, ABSENT, ABSENT, ABSENT, PRESENT, PRESENT - }); - container.forAllFrom((char) 65530, consumer3); - assertEquals(6, consumer3.getNumberOfValuesConsumed()); - - ValidationRangeConsumer consumer4 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY); - container.forAll(0, consumer4); - consumer4.assertAllAbsentExcept(entries, 0); - - ValidationRangeConsumer consumer5 = ValidationRangeConsumer.ofSize(2 * BitmapContainer.MAX_CAPACITY); - consumer5.acceptAllAbsent(0, BitmapContainer.MAX_CAPACITY); - container.forAll(BitmapContainer.MAX_CAPACITY, consumer5); - consumer5.assertAllAbsentExcept(entries, BitmapContainer.MAX_CAPACITY); - - container = new ArrayContainer(); - ValidationRangeConsumer consumer6 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY); - container.forAll(0, consumer6); - consumer6.assertAllAbsent(); - - container = new ArrayContainer(); - Container c = container.iadd(0, ArrayContainer.DEFAULT_MAX_SIZE); - assertTrue(container == c, "Container type changed!"); - ValidationRangeConsumer consumer7 = ValidationRangeConsumer.ofSize(ArrayContainer.DEFAULT_MAX_SIZE); - container.forAllUntil(0, (char) ArrayContainer.DEFAULT_MAX_SIZE, consumer7); - consumer7.assertAllPresent(); - } - - private static int lower16Bits(int x) { - return ((char)x) & 0xFFFF; - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestEmptyRoaringBatchIterator.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestEmptyRoaringBatchIterator.java deleted file mode 100644 index 466adcc4f..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestEmptyRoaringBatchIterator.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.roaringbitmap; - -import org.junit.jupiter.api.Test; -import org.roaringbitmap.buffer.ImmutableRoaringBitmap; -import org.roaringbitmap.buffer.MutableRoaringBitmap; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestEmptyRoaringBatchIterator { - - @Test - public void testEmptyMutableRoaringBitmap(){ - MutableRoaringBitmap mutableRoaringBitmap = new MutableRoaringBitmap(); - BatchIterator iterator = mutableRoaringBitmap.getBatchIterator(); - int[] ints = new int[1024]; - int cnt = iterator.nextBatch(ints); - assertEquals(0, cnt); - - mutableRoaringBitmap.add(1); - iterator = mutableRoaringBitmap.getBatchIterator(); - cnt = iterator.nextBatch(ints); - assertEquals(1, cnt); - } - - @Test - public void testEmptyImmutableRoaringBitmap(){ - MutableRoaringBitmap mutableRoaringBitmap = new MutableRoaringBitmap(); - ImmutableRoaringBitmap immutableRoaringBitmap = mutableRoaringBitmap.toImmutableRoaringBitmap(); - BatchIterator iterator = immutableRoaringBitmap.getBatchIterator(); - int[] ints = new int[1024]; - int cnt = iterator.nextBatch(ints); - assertEquals(0, cnt); - - mutableRoaringBitmap.add(1); - iterator = mutableRoaringBitmap.toImmutableRoaringBitmap().getBatchIterator(); - cnt = iterator.nextBatch(ints); - assertEquals(1, cnt); - } - - @Test - public void testEmptyRoaringBitmap(){ - RoaringBitmap roaringBitmap = new RoaringBitmap(); - BatchIterator iterator = roaringBitmap.getBatchIterator(); - int[] ints = new int[1024]; - int cnt = iterator.nextBatch(ints); - assertEquals(0, cnt); - - roaringBitmap.add(1); - iterator = roaringBitmap.getBatchIterator(); - cnt = iterator.nextBatch(ints); - assertEquals(1, cnt); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestFastAggregation.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestFastAggregation.java deleted file mode 100644 index 07d9b0671..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestFastAggregation.java +++ /dev/null @@ -1,283 +0,0 @@ -package org.roaringbitmap; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.SeededTestData.TestDataSet.testCase; - - -@Execution(ExecutionMode.CONCURRENT) -public class TestFastAggregation { - - @Test - public void horizontal_or() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6); - RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1<<16, 2<<16); - RoaringBitmap result = FastAggregation.horizontal_or(Arrays.asList(rb1, rb2, rb3)); - RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1<<16, 2<<16); - assertEquals(expected, result); - } - - @Test - public void or() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6); - RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1<<16, 2<<16); - RoaringBitmap result = FastAggregation.or(rb1, rb2, rb3); - RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1<<16, 2<<16); - assertEquals(expected, result); - } - - @Test - public void horizontal_or2() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6); - RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1<<16, 2<<16); - RoaringBitmap result = FastAggregation.horizontal_or(rb1, rb2, rb3); - RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1<<16, 2<<16); - assertEquals(expected, result); - } - - @Test - public void priorityqueue_or() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6); - RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1<<16, 2<<16); - RoaringBitmap result = FastAggregation.priorityqueue_or(Arrays.asList(rb1, rb2, rb3).iterator()); - RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1<<16, 2<<16); - assertEquals(expected, result); - } - - @Test - public void priorityqueue_or2() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6); - RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1<<16, 2<<16); - RoaringBitmap result = FastAggregation.priorityqueue_or(rb1, rb2, rb3); - RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1<<16, 2<<16); - assertEquals(expected, result); - } - - private static class ExtendedRoaringBitmap extends RoaringBitmap {} - - - @Test - public void testWorkShyAnd() { - final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2, 0x10001, 0x20001, 0x30001); - final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3, 0x20002, 0x30001); - final RoaringBitmap bResult = FastAggregation.workShyAnd(new long[1024], b1, b2); - assertFalse(bResult.contains(1)); - assertTrue(bResult.contains(2)); - assertFalse(bResult.contains(3)); - } - - @Test - public void testAndWithIterator() { - final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2); - final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3); - final RoaringBitmap bResult = FastAggregation.and(Arrays.asList(b1, b2).iterator()); - assertFalse(bResult.contains(1)); - assertTrue(bResult.contains(2)); - assertFalse(bResult.contains(3)); - - final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap(); - eb1.add(1); - eb1.add(2); - final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap(); - eb2.add(2); - eb2.add(3); - final RoaringBitmap ebResult = FastAggregation.and(Arrays.asList(b1, b2).iterator()); - assertFalse(ebResult.contains(1)); - assertTrue(ebResult.contains(2)); - assertFalse(ebResult.contains(3)); - } - - @Test - public void testNaiveAndWithIterator() { - final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2); - final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3); - final RoaringBitmap bResult = FastAggregation.naive_and(Arrays.asList(b1, b2).iterator()); - assertFalse(bResult.contains(1)); - assertTrue(bResult.contains(2)); - assertFalse(bResult.contains(3)); - - final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap(); - eb1.add(1); - eb1.add(2); - final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap(); - eb2.add(2); - eb2.add(3); - final RoaringBitmap ebResult = FastAggregation.naive_and(Arrays.asList(b1, b2).iterator()); - assertFalse(ebResult.contains(1)); - assertTrue(ebResult.contains(2)); - assertFalse(ebResult.contains(3)); - } - - @Test - public void testOrWithIterator() { - final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2); - final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3); - final RoaringBitmap bItResult = FastAggregation.or(Arrays.asList(b1, b2).iterator()); - assertTrue(bItResult.contains(1)); - assertTrue(bItResult.contains(2)); - assertTrue(bItResult.contains(3)); - - final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap(); - eb1.add(1); - eb1.add(2); - final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap(); - eb2.add(2); - eb2.add(3); - final RoaringBitmap ebItResult = FastAggregation.or(Arrays.asList(b1, b2).iterator()); - assertTrue(ebItResult.contains(1)); - assertTrue(ebItResult.contains(2)); - assertTrue(ebItResult.contains(3)); - } - - @Test - public void testNaiveOrWithIterator() { - final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2); - final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3); - final RoaringBitmap bResult = FastAggregation.naive_or(Arrays.asList(b1, b2).iterator()); - assertTrue(bResult.contains(1)); - assertTrue(bResult.contains(2)); - assertTrue(bResult.contains(3)); - - final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap(); - eb1.add(1); - eb1.add(2); - final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap(); - eb2.add(2); - eb2.add(3); - final RoaringBitmap ebResult = FastAggregation.naive_or(Arrays.asList(b1, b2).iterator()); - assertTrue(ebResult.contains(1)); - assertTrue(ebResult.contains(2)); - assertTrue(ebResult.contains(3)); - } - - @Test - public void testNaiveXorWithIterator() { - final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2); - final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3); - final RoaringBitmap bResult = FastAggregation.naive_xor(Arrays.asList(b1, b2).iterator()); - assertTrue(bResult.contains(1)); - assertFalse(bResult.contains(2)); - assertTrue(bResult.contains(3)); - - final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap(); - eb1.add(1); - eb1.add(2); - final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap(); - eb2.add(2); - eb2.add(3); - final RoaringBitmap ebResult = FastAggregation.naive_xor(Arrays.asList(b1, b2).iterator()); - assertTrue(ebResult.contains(1)); - assertFalse(ebResult.contains(2)); - assertTrue(ebResult.contains(3)); - } - - public static Stream bitmaps() { - return Stream.of( - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(), - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(), - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build(), - testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build(), - testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(), - testCase().withBitmapAt(0).withArrayAt(3).withRunAt(4).build(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withBitmapAt(1).withRunAt(2).build(), - testCase().withRunAt(0).withArrayAt(1).withBitmapAt(2).build(), - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(), - testCase().withBitmapAt(0).withArrayAt(2).withRunAt(4).build(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withArrayAt(1).withArrayAt(2).build(), - testCase().withBitmapAt(0).withBitmapAt(2).withBitmapAt(4).build(), - testCase().withRunAt(0).withRunAt(1).withRunAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withArrayAt(1).withArrayAt(2).build(), - testCase().withBitmapAt(0).withBitmapAt(2).withArrayAt(4).build(), - testCase().withRunAt(0).withRunAt(1).withArrayAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withArrayAt(1).withBitmapAt(2).build(), - testCase().withBitmapAt(0).withBitmapAt(2).withBitmapAt(4).build(), - testCase().withRunAt(0).withRunAt(1).withBitmapAt(2).build() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(20).build(), - testCase().withBitmapAt(0).withBitmapAt(1).withBitmapAt(4).build(), - testCase().withRunAt(0).withRunAt(1).withBitmapAt(3).build() - )) - ); - } - - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testWorkShyAnd") - public void testWorkShyAnd(List list) { - RoaringBitmap[] bitmaps = list.toArray(new RoaringBitmap[0]); - long[] buffer = new long[1024]; - RoaringBitmap result = FastAggregation.and(buffer, bitmaps); - RoaringBitmap expected = FastAggregation.naive_and(bitmaps); - assertEquals(expected, result); - result = FastAggregation.and(bitmaps); - assertEquals(expected, result); - result = FastAggregation.workAndMemoryShyAnd(buffer, bitmaps); - assertEquals(expected, result); - } - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testAndCardinality") - public void testAndCardinality(List list) { - RoaringBitmap[] bitmaps = list.toArray(new RoaringBitmap[0]); - for (int length = 0; length <= bitmaps.length; length++) { - RoaringBitmap[] subset = Arrays.copyOf(bitmaps, length); - RoaringBitmap and = FastAggregation.and(subset); - int andCardinality = FastAggregation.andCardinality(subset); - assertEquals(and.getCardinality(), andCardinality); - } - } - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testOrCardinality") - public void testOrCardinality(List list) { - RoaringBitmap[] bitmaps = list.toArray(new RoaringBitmap[0]); - for (int length = 0; length <= bitmaps.length; length++) { - RoaringBitmap[] subset = Arrays.copyOf(bitmaps, length); - RoaringBitmap or = FastAggregation.or(subset); - int orCardinality = FastAggregation.orCardinality(subset); - assertEquals(or.getCardinality(), orCardinality); - } - } - -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestForEach.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestForEach.java deleted file mode 100644 index 3279d4fa1..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestForEach.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestForEach { - - @Test - public void testContinuous() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(100L, 10000L); - - final MutableInteger cardinality = new MutableInteger(); - bitmap.forEach(new IntConsumer() { - int expected = 100; - - @Override - public void accept(int value) { - cardinality.value++; - assertEquals(value, expected++); - } - }); - assertEquals(cardinality.value, bitmap.getCardinality()); - } - - @Test - public void testDense() { - RoaringBitmap bitmap = new RoaringBitmap(); - for (int k = 0; k < 100000; k += 3) - bitmap.add(k); - - final MutableInteger cardinality = new MutableInteger(); - bitmap.forEach(new IntConsumer() { - int expected = 0; - - @Override - public void accept(int value) { - cardinality.value++; - assertEquals(value, expected); - expected += 3; - } - }); - assertEquals(cardinality.value, bitmap.getCardinality()); - } - - - @Test - public void testSparse() { - RoaringBitmap bitmap = new RoaringBitmap(); - for (int k = 0; k < 100000; k += 3000) - bitmap.add(k); - - final MutableInteger cardinality = new MutableInteger(); - bitmap.forEach(new IntConsumer() { - int expected = 0; - - @Override - public void accept(int value) { - cardinality.value++; - assertEquals(value, expected); - expected += 3000; - } - }); - assertEquals(cardinality.value, bitmap.getCardinality()); - } -} - - -class MutableInteger { - public int value = 0; -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestImmutableRoaringBitmap.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestImmutableRoaringBitmap.java deleted file mode 100644 index 323ce4764..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestImmutableRoaringBitmap.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.roaringbitmap; - -import org.junit.jupiter.api.Test; -import org.roaringbitmap.buffer.ImmutableRoaringBitmap; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - - -public class TestImmutableRoaringBitmap { - - @Test - public void xor() { - ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 73647, 83469); - ImmutableRoaringBitmap b = ImmutableRoaringBitmap.bitmapOf(1, 5, 10<<16); - ImmutableRoaringBitmap xor = ImmutableRoaringBitmap.xor(a, b); - ImmutableRoaringBitmap expected = ImmutableRoaringBitmap.bitmapOf(5, 73647, 83469, 10<<16); - assertEquals(expected, xor); - } - - @Test - public void or() { - ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 73647, 83469); - ImmutableRoaringBitmap b = ImmutableRoaringBitmap.bitmapOf(1, 5, 10<<16); - ImmutableRoaringBitmap expected = ImmutableRoaringBitmap.bitmapOf(1, 5, 73647, 83469, 10<<16); - assertEquals(expected, ImmutableRoaringBitmap.or(a, b)); - assertEquals(expected, ImmutableRoaringBitmap.or(b, a)); - } - - @Test - public void andNot() { - ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1<<16, 2<<16); - ImmutableRoaringBitmap b = ImmutableRoaringBitmap.bitmapOf(11, 12, 13, 2<<16); - ImmutableRoaringBitmap andNot = ImmutableRoaringBitmap.andNot(a, b); - ImmutableRoaringBitmap expected = ImmutableRoaringBitmap.bitmapOf(1<<16); - assertEquals(expected, andNot); - } - - @Test - public void flipInvalidRange() { - assertThrows(RuntimeException.class, () -> { - ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 5, 7, 13); - ImmutableRoaringBitmap.flip(a, 7L, 5L); - }); - } - - @Test - public void flipInvalidRange2() { - assertThrows(IllegalArgumentException.class, () -> { - ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 5, 7, 13); - ImmutableRoaringBitmap.flip(a, 1L << 32, 1L << 33); - }); - } - - @Test - public void flipInvalidRange3() { - assertThrows(IllegalArgumentException.class, () -> { - ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 5, 7, 13); - ImmutableRoaringBitmap.flip(a, 1L, 1L << 33); - }); - } - - - -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRangeCardinality.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestRangeCardinality.java deleted file mode 100644 index a09463834..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRangeCardinality.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class TestRangeCardinality { - - public static Stream data() { - return Stream.of( - Arguments.of(new int[]{1, 3, 5, 7, 9}, 3, 8, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 2, 8, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 3, 7, 2), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 0, 7, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 0, 6, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9, Short.MAX_VALUE}, 0, Short.MAX_VALUE + 1, 6), - Arguments.of(new int[]{1, 10000, 25000, Short.MAX_VALUE - 1}, 0, Short.MAX_VALUE, 4), - Arguments.of(new int[]{1 << 3, 1 << 8, 511,512,513, 1 << 12, 1 << 14}, 0, Short.MAX_VALUE, 7) - ); - } - - @ParameterizedTest - @MethodSource("data") - public void testCardinalityInBitmapWordRange(int[] elements, int begin, int end, int expected) { - BitmapContainer bc = new BitmapContainer(); - for (int e : elements) { - bc.add((char) e); - } - assertEquals(expected, Util.cardinalityInBitmapRange(bc.bitmap, begin, end)); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap.java deleted file mode 100644 index 47c52db0f..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap.java +++ /dev/null @@ -1,5478 +0,0 @@ -/* - * (c) the authors Licensed under the Apache License, Version 2.0. - */ -package org.roaringbitmap; - -import com.google.common.base.Predicate; -import com.google.common.collect.ContiguousSet; -import com.google.common.collect.DiscreteDomain; -import com.google.common.collect.Iterables; -import com.google.common.collect.Range; -import org.apache.commons.lang3.ArrayUtils; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; - -import java.io.*; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.stream.IntStream; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.RoaringBitmapWriter.writer; - -/** - * Generic testing of the roaring bitmaps - */ -@SuppressWarnings({"static-method"}) -@Execution(ExecutionMode.CONCURRENT) -public class TestRoaringBitmap { - @Test - public void intersectBitmapWithRangeHighBits() { - Container[] values = new Container[1]; - RoaringArray ra = new RoaringArray(new char[1], values, 1); - long[] bitmap = new long[1024]; - Arrays.fill(bitmap, 0, 512, 0xAAAAAAAAAAAAAAAAL); - values[0] = new BitmapContainer(bitmap, 512 * Long.bitCount(0xAAAAAAAAAAAAAAAAL)); - RoaringBitmap rr1 = new RoaringBitmap(ra); - assertFalse(rr1.intersects((1 << 15), 0xFFFF)); - } - - @Test - public void testRangeCardinality() { - RoaringBitmap r = new RoaringBitmap(); - long Min = 0L; - long Max = 1000000L; - r.add(Min, Max); - for (long s = Min; s <= Max; s += 100) { - for (long e = s; e <= Max; e += 100) { - assertEquals(e - s, r.rangeCardinality(s, e)); - } - } - } - - @Test - public void testRangeCardinality2() { - RoaringBitmap r = new RoaringBitmap(); - long Min = 1L << 16; - long Max = 1L << 18; - r.add(Min, Max); - for (long s = Min; s <= Max; s += 1024) { - for (long e = s; e <= Max; e += 1024) { - assertEquals(e - s, r.rangeCardinality(s, e)); - } - } - } - - @Test - public void testMultipleAdd() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(1); - bitmap.add(1, 2, 3); - bitmap.add(0xFFFFFFFF); - bitmap.add(0xFFFFFFFEL, 0xFFFFFFFFL); - assertEquals("{1,2,3,4294967294,4294967295}", bitmap.toString()); - } - - @Test - public void testAddN() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.addN(new int[]{1, 2, 3, 4, 5}, 1, 3); - assertEquals("{2,3,4}", bitmap.toString()); - } - - @Test - public void testStringer() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(1); - bitmap.add(2); - bitmap.add(3); - bitmap.add(0xFFFFFFFF); - assertEquals("{1,2,3,4294967295}", bitmap.toString()); - } - - @Test - public void report128() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(59798854); - bitmap.add(91274955); - bitmap.add(97569495); - bitmap.add(101993170); - PeekableIntIterator it = bitmap.getIntIterator(); - it.advanceIfNeeded(100620278); - assertTrue(it.hasNext()); - assertEquals(101993170, it.next()); - assertFalse(it.hasNext()); - } - - @Test - public void report128_fly() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(59798854); - bitmap.add(91274955); - bitmap.add(97569495); - bitmap.add(101993170); - IntIteratorFlyweight it = new IntIteratorFlyweight(); - it.wrap(bitmap); - it.advanceIfNeeded(100620278); - assertTrue(it.hasNext()); - assertEquals(101993170, it.next()); - assertFalse(it.hasNext()); - } - - @Test - public void limitBug2() { - class MyConsumer implements IntConsumer { - public int count = 0; - - @Override - public void accept(int value) { - count++; - } - } - - RoaringBitmap r = new RoaringBitmap(); - int count = 0; - for (int i = 0; i < 500; i++) { - for (int j = 0; j < 9943; j++) { - if (i % 2 == 0) r.add(count); - count++; - } - } - RoaringBitmap limited = r.limit(1000000); - assertEquals(1000000, limited.getCardinality()); - MyConsumer c = new MyConsumer(); - limited.forEach(c); - assertEquals(1000000, c.count); - assertEquals(1000000, limited.toArray().length); - - } - - @Test - public void limitTest() { - RoaringBitmap r = new RoaringBitmap(); - r.add(0l, 10000000l); - assertEquals(1, r.limit(1).getCardinality()); - assertEquals(10, r.limit(10).getCardinality()); - assertEquals(100, r.limit(100).getCardinality()); - assertEquals(1000, r.limit(1000).getCardinality()); - assertEquals(10000, r.limit(10000).getCardinality()); - assertEquals(100000, r.limit(100000).getCardinality()); - assertEquals(1000000, r.limit(1000000).getCardinality()); - } - - @Test - public void pointerContainerTest() { - RoaringBitmap rb = new RoaringBitmap(); - for (int i = 0; i < (1 << 16); i += 2) { - rb.add(i); - } - for (int i = (1 << 16); i < 2 * ((1 << 16)); i += 512) { - rb.add(i); - } - for (int i = 2 * (1 << 16); i < 3 * ((1 << 16)); i++) { - rb.add(i); - } - rb.runOptimize(); - ContainerPointer cp = rb.getContainerPointer(); - ContainerPointer cpo = (ContainerPointer) cp.clone(); - assertNotEquals(cp.getContainer(), null); - assertNotEquals(cpo.getContainer(), null); - - assertEquals(cp.compareTo(cpo), 0); - - assertEquals(cp.getCardinality(), (1 << 16) / 2); - assertTrue(cp.isBitmapContainer()); - assertFalse(cp.isRunContainer()); - - cp.advance(); - assertTrue(cp.compareTo(cpo) > 0); - assertNotEquals(cp.getContainer(), null); - assertEquals(cp.getCardinality(), (1 << 16) / 512); - assertFalse(cp.isBitmapContainer()); - assertFalse(cp.isRunContainer()); - - cp.advance(); - assertTrue(cp.compareTo(cpo) > 0); - assertNotEquals(cp.getContainer(), null); - assertEquals(cp.getCardinality(), (1 << 16)); - assertFalse(cp.isBitmapContainer()); - assertTrue(cp.isRunContainer()); - - cpo.advance(); - assertTrue(cp.compareTo(cpo) > 0); - cpo.advance(); - assertEquals(0, cp.compareTo(cpo)); - - cp.advance(); - - assertNull(cp.getContainer()); - } - - - public static int[][] randomlists = {{127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, - 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, - 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, - 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, - 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, - 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, - 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, - 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, - 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, - 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, - 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, - 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, - 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, - 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, - 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, - 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, - 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, - 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, - 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, - 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, - 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, - 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, - 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, - 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, - 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, - 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, - 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, - 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, - 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, - 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, - 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, - 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, - 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, - 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, - 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, - 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, - 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, - 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, - 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, - 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, - 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, - 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, - 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, - 1205, 1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, - 1220, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, - 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, - 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, - 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, - 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, - 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, - 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, - 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, - 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, - 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, - 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, - 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, - 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, - 1415, 1416, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, - 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, - 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, - 1460, 1461, 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, - 1475, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, - 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, - 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, - 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, 1534, - 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549, - 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, - 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, - 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, - 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, - 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, - 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, - 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, - 1655, 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, - 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, - 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, - 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, - 1715, 1716, 1717, 1718, 1719, 1720, 1721, 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, - 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1744, - 1745, 1746, 1747, 1748, 1749, 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, - 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, - 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, - 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804, - 1805, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, - 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1834, - 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, - 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, - 1865, 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, - 1880, 1881, 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, - 1895, 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, - 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, - 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, - 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, - 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, - 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, - 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, - 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, - 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, - 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, - 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, - 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, - 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, - 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, - 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, - 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, - 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, - 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, - 2180, 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, - 2195, 2196, 2197, 2198, 2199, 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, - 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, - 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, - 2240, 2241, 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, - 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, - 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, - 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, - 2300, 2301, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, - 2315, 2316, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, - 2330, 2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, - 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, 2359, - 2360, 2361, 2362, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, - 2375, 2376, 2377, 2378, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2387, 2388, 2389, - 2390, 2391, 2392, 2393, 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2402, 2403, 2404, - 2405, 2406, 2407, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2416, 2417, 2418, 2419, - 2420, 2421, 2422, 2423, 2424, 2425, 2426, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, - 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, - 2450, 2451, 2452, 2453, 2454, 2455, 2456, 2457, 2458, 2459, 2460, 2461, 2462, 2463, 2464, - 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, - 2480, 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, 2491, 2492, 2493, 2494, - 2495, 2496, 2497, 2498, 2499, 2500, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, - 2510, 2511, 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, - 2525, 2526, 2527, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, - 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, - 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, - 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 2583, 2584, - 2585, 2586, 2587, 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, - 2600, 2601, 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, - 2615, 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, - 2630, 2631, 2632, 2633, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, - 2645, 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, - 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, - 2675, 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, - 2690, 2691, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 2701, 2702, 2703, 2704, - 2705, 2706, 2707, 2708, 2709, 2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, 2718, 2719, - 2720, 2721, 2722, 2723, 2724, 2725, 2726, 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2734, - 2735, 2736, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749, - 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, 2761, 2762, 2763, 2764, - 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2774, 2775, 2776, 2777, 2778, 2779, - 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, - 2795, 2796, 2797, 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, - 2810, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, - 2825, 2826, 2827, 2828, 2829, 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, - 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, 2851, 2852, 2853, 2854, - 2855, 2856, 2857, 2858, 2859, 2860, 2861, 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, - 2870, 2871, 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, - 2885, 2886, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, - 2900, 2901, 2902, 2903, 2904, 2905, 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, - 2915, 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, - 2930, 2931, 2932, 2933, 2934, 2935, 2936, 2937, 2938, 2939, 2940, 2941, 2942, 2943, 2944, - 2945, 2946, 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959, - 2960, 2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, 2973, 2974, - 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, - 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 2999, 3000, 3001, 3002, 3003, 3004, - 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, - 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, 3034, - 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, - 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, - 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, - 3080, 3081, 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, - 3095, 3096, 3097, 3098, 3099, 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, - 3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, - 3125, 3126, 3127, 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, - 3140, 3141, 3142, 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, 3154, - 3155, 3156, 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, - 3170, 3171, 3172, 3173, 3174, 3175, 3176, 3177, 3178, 3179, 3180, 3181, 3182, 3183, 3184, - 3185, 3186, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3199, - 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213, 3214, - 3215, 3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, - 3230, 3231, 3232, 3233, 3234, 3235, 3236, 3237, 3238, 3239, 3240, 3241, 3242, 3243, 3244, - 3245, 3246, 3247, 3248, 3249, 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, - 3260, 3261, 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, 3270, 3271, 3272, 3273, 3274, - 3275, 3276, 3277, 3278, 3279, 3280, 3281, 3282, 3283, 3284, 3285, 3286, 3287, 3288, 3289, - 3290, 3291, 3292, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, - 3305, 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, - 3320, 3321, 3322, 3323, 3324, 3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, - 3335, 3336, 3337, 3338, 3339, 3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, - 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, - 3365, 3366, 3367, 3368, 3369, 3370, 3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, - 3380, 3381, 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, - 3395, 3396, 3397, 3398, 3399, 3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, - 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, - 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, - 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448, 3449, 3450, 3451, 3452, 3453, 3454, - 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469, - 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, - 3485, 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3493, 3494, 3495, 3496, 3497, 3498, 3499, - 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, - 3515, 3516, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 3524, 3525, 3526, 3527, 3528, 3529, - 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3544, - 3545, 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, 3558, 3559, - 3560, 3561, 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574, - 3575, 3576, 3577, 3578, 3579, 3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, - 3590, 3591, 3592, 3593, 3594, 3595, 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3604, - 3605, 3606, 3607, 3608, 3609, 3610, 3611, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, - 3620, 3621, 3622, 3623, 3624, 3625, 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, 3634, - 3635, 3636, 3637, 3638, 3639, 3640, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, - 3650, 3651, 3652, 3653, 3654, 3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662, 3663, 3664, - 3665, 3666, 3667, 3668, 3669, 3670, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3678, 3679, - 3680, 3681, 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, - 3695, 3696, 3697, 3698, 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, - 3710, 3711, 3712, 3713, 3714, 3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, - 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, - 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, - 3755, 3756, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, - 3770, 3771, 3772, 3773, 3774, 3775, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, - 3785, 3786, 3787, 3788, 3789, 3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, - 3800, 3801, 3802, 3803, 3804, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 3814, - 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, 3828, 3829, - 3830, 3831, 3832, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, 3844, - 3845, 3846, 3847, 3848, 3849, 3850, 3851, 3852, 3853, 3854, 3855, 3856, 3857, 3858, 3859, - 3860, 3861, 3862, 3863, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 3872, 3873, 3874, - 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3888, 3889, - 3890, 3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, - 3905, 3906, 3907, 3908, 3909, 3910, 3911, 3912, 3913, 3914, 3915, 3916, 3917, 3918, 3919, - 3920, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3934, - 3935, 3936, 3937, 3938, 3939, 3940, 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, 3949, - 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3964, - 3965, 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, - 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, 3988, 3989, 3990, 3991, 3992, 3993, 3994, - 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, - 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, - 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, - 4040, 4041, 4042, 4043, 4044, 4045, 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, - 4055, 4056, 4057, 4058, 4059, 4060, 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, - 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, 4084, - 4085, 4086, 4087, 4088, 4089, 4090, 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, - 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, - 4115, 4116, 4117, 4118, 4119, 4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, - 4130, 4131, 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, 4144, - 4145, 4146, 4147, 4148, 4149, 4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, - 4160, 4161, 4162, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, - 4175, 4176, 4177, 4178, 4179, 4180, 4181, 4182, 4183, 4184, 4185, 4186, 4187, 4188, 4189, - 4190, 4191, 4192, 4193, 4194, 4195, 4196, 4197, 4198, 4199, 4200, 4201, 4202, 4203, 4204, - 4205, 4206, 4207, 4208, 4209, 4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4218, 4219, - 4220, 4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234, - 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249, - 4250, 4251, 4252, 4253, 4254, 4255, 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, - 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, - 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, - 4295, 4296, 4297, 4298, 4299, 4300, 4301, 4302, 4303, 4304, 4305, 4306, 4307, 4308, 4309, - 4310, 4311, 4312, 4313, 4314, 4315, 4316, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, - 4325, 4326, 4327, 4328, 4329, 4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, - 4340, 4341, 4342, 4343, 4344, 4345, 4346, 4347, 4348, 4349, 4350, 4351, 4352, 4353, 4354, - 4355, 4356, 4357, 4358, 4359, 4360, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, - 4370, 4371, 4372, 4373, 4374, 4375, 4376, 4377, 4378, 4379, 4380, 4381, 4382, 4383, 4384, - 4385, 4386, 4387, 4388, 4389, 4390, 4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399, - 4400, 4401, 4402, 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, 4411, 4412, 4413, 4414, - 4415, 4416, 4417, 4418, 4419, 4420, 4421, 4422, 4423, 4424, 4425, 4426, 4427, 4428, 4429, - 4430, 4431, 4432, 4433, 4434, 4435, 4436, 4437, 4438, 4439, 4440, 4441, 4442, 4443, 4444, - 4445, 4446, 4447, 4448, 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, - 4460, 4461, 4462, 4463, 4464, 4465, 4466, 4467, 4468, 4469, 4470, 4471, 4472, 4473, 4474, - 4475, 4476, 4477, 4478, 4479, 4480, 4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, 4489, - 4490, 4491, 4492, 4493, 4494, 4495, 4496, 4497, 4498, 4499, 4500, 4501, 4502, 4503, 4504, - 4505, 4506, 4507, 4508, 4509, 4510, 4511, 4512, 4513, 4514, 4515, 4516, 4517, 4518, 4519, - 4520, 4521, 4522, 4523, 4524, 4525, 4526, 4527, 4528, 4529, 4530, 4531, 4532, 4533, 4534, - 4535, 4536, 4537, 4538, 4539, 4540, 4541, 4542, 4543, 4544, 4545, 4546, 4547, 4548, 4549, - 4550, 4551, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4559, 4560, 4561, 4562, 4563, 4564, - 4565, 4566, 4567, 4568, 4569, 4570, 4571, 4572, 4573, 4574, 4575, 4576, 4577, 4578, 4579, - 4580, 4581, 4582, 4583, 4584, 4585, 4586, 4587, 4588, 4589, 4590, 4591, 4592, 4593, 4594, - 4595, 4596, 4597, 4598, 4599, 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4609, - 4610, 4611, 4612, 4613, 4614, 4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, - 4625, 4626, 4627, 4628, 4629, 4630, 4631, 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, - 4640, 4641, 4642, 4643, 4644, 4645, 4646, 4647, 4648, 4649, 4650, 4651, 4652, 4653, 4654, - 4655, 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, 4664, 4665, 4666, 4667, 4668, 4669, - 4670, 4671, 4672, 4673, 4674, 4675, 4676, 4677, 4678, 4679, 4680, 4681, 4682, 4683, 4684, - 4685, 4686, 4687, 4688, 4689, 4690, 4691, 4692, 4693, 4694, 4695, 4696, 4697, 4698, 4699, - 4700, 4701, 4702, 4703, 4704, 4705, 4706, 4707, 4708, 4709, 4710, 4711, 4712, 4713, 4714, - 4715, 4716, 4717, 4718, 4719, 4720, 4721, 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4729, - 4730, 4731, 4732, 4733, 4734, 4735, 4736, 4737, 4738, 4739, 4740, 4741, 4742, 4743, 4744, - 4745, 4746, 4747, 4748, 4749, 4750, 4751, 4752, 4753, 4754, 4755, 4756, 4757, 4758, 4759, - 4760, 4761, 4762, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773, 4774, - 4775, 4776, 4777, 4778, 4779, 4780, 4781, 4782, 4783, 4784, 4785, 4786, 4787, 4788, 4789, - 4790, 4791, 4792, 4793, 4794, 4795, 4796, 4797, 4798, 4799, 4800, 4801, 4802, 4803, 4804, - 4805, 4806, 4807, 4808, 4809, 4810, 4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, - 4820, 4821, 4822, 4823, 4824, 4825, 4826, 4827, 4828, 4829, 4830, 4831, 4832, 4833, 4834, - 4835, 4836, 4837, 4838, 4839, 4840, 4841, 4842, 4843, 4844, 4845, 4846, 4847, 4848, 4849, - 4850, 4851, 4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, 4860, 4861, 4862, 4863, 4864, - 4865, 4866, 4867, 4868, 4869, 4870, 4871, 4872, 4873, 4874, 4875, 4876, 4877, 4878, 4879, - 4880, 4881, 4882, 4883, 4884, 4885, 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, 4894, - 4895, 4896, 4897, 4898, 4899, 4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, - 4910, 4911, 4912, 4913, 4914, 4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924, - 4925, 4926, 4927, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, - 4940, 4941, 4942, 4943, 4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, - 4955, 4956, 4957, 4958, 4959, 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, - 4970, 4971, 4972, 4973, 4974, 4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, - 4985, 4986, 4987, 4988, 4989, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, - 5000, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, - 5015, 5016, 5017, 5018, 5019, 5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, - 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, - 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, - 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074, - 5075, 5076, 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, - 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 5104, - 5105, 5106, 5107, 5108, 5109, 5110, 5111, 5112, 5113, 5114, 5115, 5116, 5117, 5118, 5119, - 5120, 5121, 5122, 5123, 5124, 5125, 5126, 5127, 5128, 5129, 5130, 5131, 5132, 5133, 5134, - 5135, 5136, 5137, 5138, 5139, 5140, 5141, 5142, 5143, 5144, 5145, 5146, 5147, 5148, 5149, - 5150, 5151, 5152, 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5163, 5164, - 5165, 5166, 5167, 5168, 5169, 5170, 5171, 5172, 5173, 5174, 5175, 5176, 5177, 5178, 5179, - 5180, 5181, 5182, 5183, 5184, 5185, 5186, 5187, 5188, 5189, 5190, 5191, 5192, 5193, 5194, - 5195, 5196, 5197, 5198, 5199, 5200, 5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209, - 5210, 5211, 5212, 5213, 5214, 5215, 5216, 5217, 5218, 5219, 5220, 5221, 5222, 5223, 5224, - 5225, 5226, 5227, 5228, 5229, 5230, 5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, - 5240, 5241, 5242, 5243, 5244, 5245, 5246, 5247, 5248, 5249, 5250, 5251, 5252, 5253, 5254, - 5255, 5256, 5257, 5258, 5259, 5260, 5261, 5262, 5263, 5264, 5265, 5266, 5267, 5268, 5269, - 5270, 5271, 5272, 5273, 5274, 5275, 5276, 5277, 5278, 5279, 5280, 5281, 5282, 5283, 5284, - 5285, 5286, 5287, 5288, 5289, 5290, 5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, 5299, - 5300, 5301, 5302, 5303, 5304, 5305, 5306, 5307, 5308, 5309, 5310, 5311, 5312, 5313, 5314, - 5315, 5316, 5317, 5318, 5319, 5320, 5321, 5322, 5323, 5324, 5325, 5326, 5327, 5328, 5329, - 5330, 5331, 5332, 5333, 5334, 5335, 5336, 5337, 5338, 5339, 5340, 5341, 5342, 5343, 5344, - 5345, 5346, 5347, 5348, 5349, 5350, 5351, 5352, 5353, 5354, 5355, 5356, 5357, 5358, 5359, - 5360, 5361, 5362, 5363, 5364, 5365, 5366, 5367, 5368, 5369, 5370, 5371, 5372, 5373, 5374, - 5375, 5376, 5377, 5378, 5379, 5380, 5381, 5382, 5383, 5384, 5385, 5386, 5387, 5388, 5389, - 5390, 5391, 5392, 5393, 5394, 5395, 5396, 5397, 5398, 5399, 5400, 5401, 5402, 5403, 5404, - 5405, 5406, 5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, - 5420, 5421, 5422, 5423, 5424, 5425, 5426, 5427, 5428, 5429, 5430, 5431, 5432, 5433, 5434, - 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5442, 5443, 5444, 5445, 5446, 5447, 5448, 5449, - 5450, 5451, 5452, 5453, 5454, 5455, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, - 5465, 5466, 5467, 5468, 5469, 5470, 5471, 5472, 5473, 5474, 5475, 5476, 5477, 5478, 5479, - 5480, 5481, 5482, 5483, 5484, 5485, 5486, 5487, 5488, 5489, 5490, 5491, 5492, 5493, 5494, - 5495, 5496, 5497, 5498, 5499, 5500, 5501, 5502, 5503, 5504, 5505, 5506, 5507, 5508, 5509, - 5510, 5511, 5512, 5513, 5514, 5515, 5516, 5517, 5518, 5519, 5520, 5521, 5522, 5523, 5524, - 5525, 5526, 5527, 5528, 5529, 5530, 5531, 5532, 5533, 5534, 5535, 5536, 5537, 5538, 5539, - 5540, 5541, 5542, 5543, 5544, 5545, 5546, 5547, 5548, 5549, 5550, 5551, 5552, 5553, 5554, - 5555, 5556, 5557, 5558, 5559, 5560, 5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, - 5570, 5571, 5572, 5573, 5574, 5575, 5576, 5577, 5578, 5579, 5580, 5581, 5582, 5583, 5584, - 5585, 5586, 5587, 5588, 5589, 5590, 5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, 5599, - 5600, 5601, 5602, 5603, 5604, 5605, 5606, 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, - 5615, 5616, 5617, 5618, 5619, 5620, 5621, 5622, 5623, 5624, 5625, 5626, 5627, 5628, 5629, - 5630, 5631, 5632, 5633, 5634, 5635, 5636, 5637, 5638, 5639, 5640, 5641, 5642, 5643, 5644, - 5645, 5646, 5647, 5648, 5649, 5650, 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, - 5660, 5661, 5662, 5663, 5664, 5665, 5666, 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674, - 5675, 5676, 5677, 5678, 5679, 5680, 5681, 5682, 5683, 5684, 5685, 5686, 5687, 5688, 5689, - 5690, 5691, 5692, 5693, 5694, 5695, 5696, 5697, 5698, 5699, 5700, 5701, 5702, 5703, 5704, - 5705, 5706, 5707, 5708, 5709, 5710, 5711, 5712, 5713, 5714, 5715, 5716, 5717, 5718, 5719, - 5720, 5721, 5722, 5723, 5724, 5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, - 5735, 5736, 5737, 5738, 5739, 5740, 5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, - 5750, 5751, 5752, 5753, 5754, 5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, 5763, 5764, - 5765, 5766, 5767, 5768, 5769, 5770, 5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, 5779, - 5780, 5781, 5782, 5783, 5784, 5785, 5786, 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, - 5795, 5796, 5797, 5798, 5799, 5800, 5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, - 5810, 5811, 5812, 5813, 5814, 5815, 5816, 5817, 5818, 5819, 5820, 5821, 5822, 5823, 5824, - 5825, 5826, 5827, 5828, 5829, 5830, 5831, 5832, 5833, 5834, 5835, 5836, 5837, 5838, 5839, - 5840, 5841, 5842, 5843, 5844, 5845, 5846, 5847, 5848, 5849, 5850, 5851, 5852, 5853, 5854, - 5855, 5856, 5857, 5858, 5859, 5860, 5861, 5862, 5863, 5864, 5865, 5866, 5867, 5868, 5869, - 5870, 5871, 5872, 5873, 5874, 5875, 5876, 5877, 5878, 5879, 5880, 5881, 5882, 5883, 5884, - 5885, 5886, 5887, 5888, 5889, 5890, 5891, 5892, 5893, 5894, 5895, 5896, 5897, 5898, 5899, - 5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909, 5910, 5911, 5912, 5913, 5914, - 5915, 5916, 5917, 5918, 5919, 5920, 5921, 5922, 5923, 5924, 5925, 5926, 5927, 5928, 5929, - 5930, 5931, 5932, 5933, 5934, 5935, 5936, 5937, 5938, 5939, 5940, 5941, 5942, 5943, 5944, - 5945, 5946, 5947, 5948, 5949, 5950, 5951, 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, - 5960, 5961, 5962, 5963, 5964, 5965, 5966, 5967, 5968, 5969, 5970, 5971, 5972, 5973, 5974, - 5975, 5976, 5977, 5978, 5979, 5980, 5981, 5982, 5983, 5984, 5985, 5986, 5987, 5988, 5989, - 5990, 5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999, 6000, 6001, 6002, 6003, 6004, - 6005, 6006, 6007, 6008, 6009, 6010, 6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6019, - 6020, 6021, 6022, 6023, 6024, 6025, 6026, 6027, 6028, 6029, 6030, 6031, 6032, 6033, 6034, - 6035, 6036, 6037, 6038, 6039, 6040, 6041, 6042, 6043, 6044, 6045, 6046, 6047, 6048, 6049, - 6050, 6051, 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, 6060, 6061, 6062, 6063, 6064, - 6065, 6066, 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6074, 6075, 6076, 6077, 6078, 6079, - 6080, 6081, 6082, 6083, 6084, 6085, 6086, 6087, 6088, 6089, 6090, 6091, 6092, 6093, 6094, - 6095, 6096, 6097, 6098, 6099, 6100, 6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109, - 6110, 6111, 6112, 6113, 6114, 6115, 6116, 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124, - 6125, 6126, 6127, 6128, 6129, 6130, 6131, 6132, 6133, 6134, 6135, 6136, 6137, 6138, 6139, - 6140, 6141, 6142, 6143, 6144, 6145, 6146, 6147, 6148, 6149, 6150, 6151, 6152, 6153, 6154, - 6155, 6156, 6157, 6158, 6159, 6160, 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, - 6170, 6171, 6172, 6173, 6174, 6175, 6176, 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, - 6185, 6186, 6187, 6188, 6189, 6190, 6191, 6192, 6193, 6194, 6195, 6196, 6197, 6198, 6199, - 6200, 6201, 6202, 6203, 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 6212, 6213, 6214, - 6215, 6216, 6217, 6218, 6219, 6220, 6221, 6222, 6223, 6224, 6225, 6226, 6227, 6228, 6229, - 6230, 6231, 6232, 6233, 6234, 6235, 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, 6244, - 6245, 6246, 6247, 6248, 6249, 6250, 6251, 6252, 6253, 6254, 6255, 6256, 6257, 6258, 6259, - 6260, 6261, 6262, 6263, 6264, 6265, 6266, 6267, 6268, 6269, 6270, 6271, 6272, 6273, 6274, - 6275, 6276, 6277, 6278, 6279, 6280, 6281, 6282, 6283, 6284, 6285, 6286, 6287, 6288, 6289, - 6290, 6291, 6292, 6293, 6294, 6295, 6296, 6297, 6298, 6299, 6300, 6301, 6302, 6303, 6304, - 6305, 6306, 6307, 6308, 6309, 6310, 6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, 6319, - 6320, 6321, 6322, 6323, 6324, 6325, 6326, 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, - 6335, 6336, 6337, 6338, 6339, 6340, 6341, 6342, 6343, 6344, 6345, 6346, 6347, 6348, 6349, - 6350, 6351, 6352, 6353, 6354, 6355, 6356, 6357, 6358, 6359, 6360, 6361, 6362, 6363, 6364, - 6365, 6366, 6367, 6368, 6369, 6370, 6371, 6372, 6373, 6374, 6375, 6376, 6377, 6378, 6379, - 6380, 6381, 6382, 6383, 6384, 6385, 6386, 6387, 6388, 6389, 6390, 6391, 6392, 6393, 6394, - 6395, 6396, 6397, 6398, 6399, 6400, 6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409, - 6410, 6411, 6412, 6413, 6414, 6415, 6416, 6417, 6418, 6419, 6420, 6421, 6422, 6423, 6424, - 6425, 6426, 6427, 6428, 6429, 6430, 6431, 6432, 6433, 6434, 6435, 6436, 6437, 6438, 6439, - 6440, 6441, 6442, 6443, 6444, 6445, 6446, 6447, 6448, 6449, 6450, 6451, 6452, 6453, 6454, - 6455, 6456, 6457, 6458, 6459, 6460, 6461, 6462, 6463, 6464, 6465, 6466, 6467, 6468, 6469, - 6470, 6471, 6472, 6473, 6474, 6475, 6476, 6477, 6478, 6479, 6480, 6481, 6482, 6483, 6484, - 6485, 6486, 6487, 6488, 6489, 6490, 6491, 6492, 6493, 6494, 6495, 6496, 6497, 6498, 6499, - 6500, 6501, 6502, 6503, 6504, 6505, 6506, 6507, 6508, 6509, 6510, 6511, 6512, 6513, 6514, - 6515, 6516, 6517, 6518, 6519, 6520, 6521, 6522, 6523, 6524, 6525, 6526, 6527, 6528, 6529, - 6530, 6531, 6532, 6533, 6534, 6535, 6536, 6537, 6538, 6539, 6540, 6541, 6542, 6543, 6544, - 6545, 6546, 6547, 6548, 6549, 6550, 6551, 6552, 6553, 6554, 6555, 6556, 6557, 6558, 6559, - 6560, 6561, 6562, 6563, 6564, 6565, 6566, 6567, 6568, 6569, 6570, 6571, 6572, 6573, 6574, - 6575, 6576, 6577, 6578, 6579, 6580, 6581, 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, - 6590, 6591, 6592, 6593, 6594, 6595, 6596, 6597, 6598, 6599, 6600, 6601, 6602, 6603, 6604, - 6605, 6606, 6607, 6608, 6609, 6610, 6611, 6612, 6613, 6614, 6615, 6616, 6617, 6618, 6619, - 6620, 6621, 6622, 6623, 6624, 6625, 6626, 6627, 6628, 6629, 6630, 6631, 6632, 6633, 6634, - 6635, 6636, 6637, 6638, 6639, 6640, 6641, 6642, 6643, 6644, 6645, 6646, 6647, 6648, 6649, - 6650, 6651, 6652, 6653, 6654, 6655, 6656, 6657, 6658, 6659, 6660, 6661, 6662, 6663, 6664, - 6665, 6666, 6667, 6668, 6669, 6670, 6671, 6672, 6673, 6674, 6675, 6676, 6677, 6678, 6679, - 6680, 6681, 6682, 6683, 6684, 6685, 6686, 6687, 6688, 6689, 6690, 6691, 6692, 6693, 6694, - 6695, 6696, 6697, 6698, 6699, 6700, 6701, 6702, 6703, 6704, 6705, 6706, 6707, 6708, 6709, - 6710, 6711, 6712, 6713, 6714, 6715, 6716, 6717, 6718, 6719, 6720, 6721, 6722, 6723, 6724, - 6725, 6726, 6727, 6728, 6729, 6730, 6731, 6732, 6733, 6734, 6735, 6736, 6737, 6738, 6739, - 6740, 6741, 6742, 6743, 6744, 6745, 6746, 6747, 6748, 6749, 6750, 6751, 6752, 6753, 6754, - 6755, 6756, 6757, 6758, 6759, 6760, 6761, 6762, 6763, 6764, 6765, 6766, 6767, 6768, 6769, - 6770, 6771, 6772, 6773, 6774, 6775, 6776, 6777, 6778, 6779, 6780, 6781, 6782, 6783, 6784, - 6785, 6786, 6787, 6788, 6789, 6790, 6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799, - 6800, 6801, 6802, 6803, 6804, 6805, 6806, 6807, 6808, 6809, 6810, 6811, 6812, 6813, 6814, - 6815, 6816, 6817, 6818, 6819, 6820, 6821, 6822, 6823, 6824, 6825, 6826, 6827, 6828, 6829, - 6830, 6831, 6832, 6833, 6834, 6835, 6836, 6837, 6838, 6839, 6840, 6841, 6842, 6843, 6844, - 6845, 6846, 6847, 6848, 6849, 6850, 6851, 6852, 6853, 6854, 6855, 6856, 6857, 6858, 6859, - 6860, 6861, 6862, 6863, 6864, 6865, 6866, 6867, 6868, 6869, 6870, 6871, 6872, 6873, 6874, - 6875, 6876, 6877, 6878, 6879, 6880, 6881, 6882, 6883, 6884, 6885, 6886, 6887, 6888, 6889, - 6890, 6891, 6892, 6893, 6894, 6895, 6896, 6897, 6898, 6899, 6900, 6901, 6902, 6903, 6904, - 6905, 6906, 6907, 6908, 6909, 6910, 6911, 6912, 6913, 6914, 6915, 6916, 6917, 6918, 6919, - 6920, 6921, 6922, 6923, 6924, 6925, 6926, 6927, 6928, 6929, 6930, 6931, 6932, 6933, 6934, - 6935, 6936, 6937, 6938, 6939, 6940, 6941, 6942, 6943, 6944, 6945, 6946, 6947, 6948, 6949, - 6950, 6951, 6952, 6953, 6954, 6955, 6956, 6957, 6958, 6959, 6960, 6961, 6962, 6963, 6964, - 6965, 6966, 6967, 6968, 6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, - 6980, 6981, 6982, 6983, 6984, 6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, - 6995, 6996, 6997, 6998, 6999, 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, - 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, - 7025, 7026, 7027, 7028, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, - 7040, 7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, - 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063, 7064, 7065, 7066, 7067, 7068, 7069, - 7070, 7071, 7072, 7073, 7074, 7075, 7076, 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, - 7085, 7086, 7087, 7088, 7089, 7090, 7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, - 7100, 7101, 7102, 7103, 7104, 7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, - 7115, 7116, 7117, 7118, 7119, 7120, 7121, 7122, 7123, 7124, 7125, 7126, 7127, 7128, 7129, - 7130, 7131, 7132, 7133, 7134, 7135, 7136, 7137, 7138, 7139, 7140, 7141, 7142, 7143, 7144, - 7145, 7146, 7147, 7148, 7149, 7150, 7151, 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, - 7160, 7161, 7162, 7163, 7164, 7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7174, - 7175, 7176, 7177, 7178, 7179, 7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, - 7190, 7191, 7192, 7193, 7194, 7195, 7196, 7197, 7198, 7199, 7200, 7201, 7202, 7203, 7204, - 7205, 7206, 7207, 7208, 7209, 7210, 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, - 7220, 7221, 7222, 7223, 7224, 7225, 7226, 7227, 7228, 7229, 7230, 7231, 7232, 7233, 7234, - 7235, 7236, 7237, 7238, 7239, 7240, 7241, 7242, 7243, 7244, 7245, 7246, 7247, 7248, 7249, - 7250, 7251, 7252, 7253, 7254, 7255, 7256, 7257, 7258, 7259, 7260, 7261, 7262, 7263, 7264, - 7265, 7266, 7267, 7268, 7269, 7270, 7271, 7272, 7273, 7274, 7275, 7276, 7277, 7278, 7279, - 7280, 7281, 7282, 7283, 7284, 7285, 7286, 7287, 7288, 7289, 7290, 7291, 7292, 7293, 7294, - 7295, 7296, 7297, 7298, 7299, 7300, 7301, 7302, 7303, 7304, 7305, 7306, 7307, 7308, 7309, - 7310, 7311, 7312, 7313, 7314, 7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, - 7325, 7326, 7327, 7328, 7329, 7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, - 7340, 7341, 7342, 7343, 7344, 7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, - 7355, 7356, 7357, 7358, 7359, 7360, 7361, 7362, 7363, 7364, 7365, 7366, 7367, 7368, 7369, - 7370, 7371, 7372, 7373, 7374, 7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, - 7385, 7386, 7387, 7388, 7389, 7390, 7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, 7399, - 7400, 7401, 7402, 7403, 7404, 7405, 7406, 7407, 7408, 7409, 7410, 7411, 7412, 7413, 7414, - 7415, 7416, 7417, 7418, 7419, 7420, 7421, 7422, 7423, 7424, 7425, 7426, 7427, 7428, 7429, - 7430, 7431, 7432, 7433, 7434, 7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, - 7445, 7446, 7447, 7448, 7449, 7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, - 7460, 7461, 7462, 7463, 7464, 7465, 7466, 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474, - 7475, 7476, 7477, 7478, 7479, 7480, 7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, - 7490, 7491, 7492, 7493, 7494, 7495, 7496, 7497, 7498, 7499, 7500, 7501, 7502, 7503, 7504, - 7505, 7506, 7507, 7508, 7509, 7510, 7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, - 7520, 7521, 7522, 7523, 7524, 7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, 7533, 7534, - 7535, 7536, 7537, 7538, 7539, 7540, 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549, - 7550, 7551, 7552, 7553, 7554, 7555, 7556, 7557, 7558, 7559, 7560, 7561, 7562, 7563, 7564, - 7565, 7566, 7567, 7568, 7569, 7570, 7571, 7572, 7573, 7574, 7575, 7576, 7577, 7578, 7579, - 7580, 7581, 7582, 7583, 7584, 7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 7594, - 7595, 7596, 7597, 7598, 7599, 7600, 7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, - 7610, 7611, 7612, 7613, 7614, 7615, 7616, 7617, 7618, 7619, 7620, 7621, 7622, 7623, 7624, - 7625, 7626, 7627, 7628, 7629, 7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, - 7640, 7641, 7642, 7643, 7644, 7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, 7653, 7654, - 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7665, 7666, 7667, 7668, 7669, - 7670, 7671, 7672, 7673, 7674, 7675, 7676, 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, - 7685, 7686, 7687, 7688, 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, - 7700, 7701, 7702, 7703, 7704, 7705, 7706, 7707, 7708, 7709, 7710, 7711, 7712, 7713, 7714, - 7715, 7716, 7717, 7718, 7719, 7720, 7721, 7722, 7723, 7724, 7725, 7726, 7727, 7728, 7729, - 7730, 7731, 7732, 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, - 7745, 7746, 7747, 7748, 7749, 7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, - 7760, 7761, 7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, 7771, 7772, 7773, 7774, - 7775, 7776, 7777, 7778, 7779, 7780, 7781, 7782, 7783, 7784, 7785, 7786, 7787, 7788, 7789, - 7790, 7791, 7792, 7793, 7794, 7795, 7796, 7797, 7798, 7799, 7800, 7801, 7802, 7803, 7804, - 7805, 7806, 7807, 7808, 7809, 7810, 7811, 7812, 7813, 7814, 7815, 7816, 7817, 7818, 7819, - 7820, 7821, 7822, 7823, 7824, 7825, 7826, 7827, 7828, 7829, 7830, 7831, 7832, 7833, 7834, - 7835, 7836, 7837, 7838, 7839, 7840, 7841, 7842, 7843, 7844, 7845, 7846, 7847, 7848, 7849, - 7850, 7851, 7852, 7853, 7854, 7855, 7856, 7857, 7858, 7859, 7860, 7861, 7862, 7863, 7864, - 7865, 7866, 7867, 7868, 7869, 7870, 7871, 7872, 7873, 7874, 7875, 7876, 7877, 7878, 7879, - 7880, 7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, 7893, 7894, - 7895, 7896, 7897, 7898, 7899, 7900, 7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, - 7910, 7911, 7912, 7913, 7914, 7915, 7916, 7917, 7918, 7919, 7920, 7921, 7922, 7923, 7924, - 7925, 7926, 7927, 7928, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, - 7940, 7941, 7942, 7943, 7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951, 7952, 7953, 7954, - 7955, 7956, 7957, 7958, 7959, 7960, 7961, 7962, 7963, 7964, 7965, 7966, 7967, 7968, 7969, - 7970, 7971, 7972, 7973, 7974, 7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7984, - 7985, 7986, 7987, 7988, 7989, 7990, 7991, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999}, - {95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126}}; - - public static boolean equals(BitSet bs, RoaringBitmap rr) { - final int[] a = new int[bs.cardinality()]; - int pos = 0; - for (int x = bs.nextSetBit(0); x >= 0; x = bs.nextSetBit(x + 1)) { - a[pos++] = x; - } - return Arrays.equals(rr.toArray(), a); - } - - private static Iterator toIterator(final T[] x) { - return new Iterator() { - int pos = 0; - - @Override - public boolean hasNext() { - return pos < x.length; - } - - @Override - public T next() { - return x[pos++]; - } - - @Override - public void remove() { - } - }; - - } - - - @Test - public void andBigIntsTest() { - RoaringBitmap rb = new RoaringBitmap(); - RoaringBitmap rb2 = new RoaringBitmap(); - HashSet hs = new HashSet(); - - for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) { - rb.add(i); - } - for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) { - rb.add(i); - } - for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 3) { - rb.add(i); - } - for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 4) { - rb.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) { - rb.add(i); - } - - for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) { - hs.add(i); - rb2.add(i); - } - for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 4) { - hs.add(i); - rb2.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) { - hs.add(i); - rb2.add(i); - } - for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 7) { - rb2.add(i); - } - - RoaringBitmap rband = RoaringBitmap.and(rb, rb2); - - Object[] correct = hs.toArray(); - Arrays.sort(correct); - Integer[] resand = ArrayUtils.toObject(rband.toArray()); - assertArrayEquals(correct, resand); - } - - @Test - public void andcounttest() { - // This is based on andtest - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr.add(k); - } - rr.add(100000); - rr.add(110000); - final RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(13); - final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2); - assertEquals(rrand.getCardinality(), RoaringBitmap.andCardinality(rr, rr2)); - assertEquals(rrand.getCardinality(), RoaringBitmap.andCardinality(rr2, rr)); - rr.and(rr2); - assertEquals(rrand.getCardinality(), RoaringBitmap.andCardinality(rr2, rr)); - } - - @Test - public void andCounttest3() { - // This is based on andtest3 - final int[] arrayand = new int[11256]; - int pos = 0; - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536; k < 3 * 65536 + 1000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536 + 7000; k < 3 * 65536 + 9000; ++k) { - rr.add(k); - } - for (int k = 4 * 65536; k < 4 * 65536 + 7000; ++k) { - rr.add(k); - } - for (int k = 6 * 65536; k < 6 * 65536 + 10000; ++k) { - rr.add(k); - } - for (int k = 8 * 65536; k < 8 * 65536 + 1000; ++k) { - rr.add(k); - } - for (int k = 9 * 65536; k < 9 * 65536 + 30000; ++k) { - rr.add(k); - } - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 6 * 65536; k < 6 * 65536 + 1000; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 7 * 65536; k < 7 * 65536 + 1000; ++k) { - rr2.add(k); - } - for (int k = 10 * 65536; k < 10 * 65536 + 5000; ++k) { - rr2.add(k); - } - - final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2); - final int rrandCount = RoaringBitmap.andCardinality(rr, rr2); - - assertEquals(rrand.getCardinality(), rrandCount); - } - - @Test - public void andNot() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - - rb.add(1); - rb.add(1 << 16); - rb2.add(1 << 16); - rb.add(2 << 16); - rb.add(3 << 16); - rb2.add(3 << 16); - rb.andNot(rb2); - - final IntIterator i = rb.getIntIterator(); - assertTrue(i.hasNext()); - assertEquals(1, i.next()); - assertTrue(i.hasNext()); - assertEquals(2 << 16, i.next()); - assertFalse(i.hasNext()); - } - - @Test - public void andNotBigIntsTest() { - RoaringBitmap rb = new RoaringBitmap(); - RoaringBitmap rb2 = new RoaringBitmap(); - HashSet hs = new HashSet(); - - for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) { - rb.add(i); - hs.add(i); - } - for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) { - rb.add(i); - } - for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 6 * 65536; i += 3) { - hs.add(i); - rb.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) { - rb.add(i); - } - - for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) { - rb2.add(i); - } - for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 4) { - rb2.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) { - rb2.add(i); - } - for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 7) { - rb2.add(i); - } - - RoaringBitmap rbandnot = RoaringBitmap.andNot(rb, rb2); - - Object[] correct = hs.toArray(); - Arrays.sort(correct); - Integer[] resandNot = ArrayUtils.toObject(rbandnot.toArray()); - assertArrayEquals(correct, resandNot); - } - - @Test - public void ANDNOTtest() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) { - rr.add(k); - } - for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) { - rr.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) { - rr.add(k); - } - for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) { - rr.add(k); - } - for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) { - rr.add(k); - } - - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr2.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr2.add(k); - } - for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) { - rr2.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) { - rr2.add(k); - } - final RoaringBitmap correct = RoaringBitmap.andNot(rr, rr2); - rr.andNot(rr2); - assertEquals(correct, rr); - } - - @Test - public void andnottest4() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - - for (int i = 0; i < 200000; i += 4) { - rb2.add(i); - } - for (int i = 200000; i < 400000; i += 14) { - rb2.add(i); - } - rb2.getCardinality(); - - // check or against an empty bitmap - final RoaringBitmap andNotresult = RoaringBitmap.andNot(rb, rb2); - final RoaringBitmap off = RoaringBitmap.andNot(rb2, rb); - - assertEquals(rb, andNotresult); - assertEquals(rb2, off); - rb2.andNot(rb); - assertEquals(rb2, off); - } - - @Test - public void andtest() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr.add(k); - } - rr.add(100000); - rr.add(110000); - final RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(13); - final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2); - int[] array = rrand.toArray(); - - assertEquals(array.length, 1); - assertEquals(array[0], 13); - rr.and(rr2); - array = rr.toArray(); - assertEquals(array.length, 1); - assertEquals(array[0], 13); - - } - - @Test - public void ANDtest() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) { - rr.add(k); - } - for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) { - rr.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) { - rr.add(k); - } - for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) { - rr.add(k); - } - for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) { - rr.add(k); - } - - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr2.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr2.add(k); - } - for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) { - rr2.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) { - rr2.add(k); - } - final RoaringBitmap correct = RoaringBitmap.and(rr, rr2); - rr.and(rr2); - assertEquals(correct, rr); - } - - @Test - public void andtest2() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr.add(k); - } - rr.add(100000); - rr.add(110000); - final RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(13); - final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2); - - final int[] array = rrand.toArray(); - assertEquals(array.length, 1); - assertEquals(array[0], 13); - } - - @Test - public void andtest3() { - final int[] arrayand = new int[11256]; - int pos = 0; - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536; k < 3 * 65536 + 1000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536 + 7000; k < 3 * 65536 + 9000; ++k) { - rr.add(k); - } - for (int k = 4 * 65536; k < 4 * 65536 + 7000; ++k) { - rr.add(k); - } - for (int k = 6 * 65536; k < 6 * 65536 + 10000; ++k) { - rr.add(k); - } - for (int k = 8 * 65536; k < 8 * 65536 + 1000; ++k) { - rr.add(k); - } - for (int k = 9 * 65536; k < 9 * 65536 + 30000; ++k) { - rr.add(k); - } - - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 6 * 65536; k < 6 * 65536 + 1000; ++k) { - rr2.add(k); - arrayand[pos++] = k; - } - for (int k = 7 * 65536; k < 7 * 65536 + 1000; ++k) { - rr2.add(k); - } - for (int k = 10 * 65536; k < 10 * 65536 + 5000; ++k) { - rr2.add(k); - } - - final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2); - - final int[] arrayres = rrand.toArray(); - - assertArrayEquals(arrayand, arrayres); - - } - - @Test - public void andtest4() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - - for (int i = 0; i < 200000; i += 4) { - rb2.add(i); - } - for (int i = 200000; i < 400000; i += 14) { - rb2.add(i); - } - - // check or against an empty bitmap - final RoaringBitmap andresult = RoaringBitmap.and(rb, rb2); - final RoaringBitmap off = RoaringBitmap.and(rb2, rb); - assertEquals(andresult, off); - - assertEquals(0, andresult.getCardinality()); - - for (int i = 500000; i < 600000; i += 14) { - rb.add(i); - } - for (int i = 200000; i < 400000; i += 3) { - rb2.add(i); - } - // check or against an empty bitmap - final RoaringBitmap andresult2 = RoaringBitmap.and(rb, rb2); - assertEquals(0, andresult.getCardinality()); - - assertEquals(0, andresult2.getCardinality()); - for (int i = 0; i < 200000; i += 4) { - rb.add(i); - } - for (int i = 200000; i < 400000; i += 14) { - rb.add(i); - } - assertEquals(0, andresult.getCardinality()); - final RoaringBitmap rc = RoaringBitmap.and(rb, rb2); - rb.and(rb2); - assertEquals(rc.getCardinality(), rb.getCardinality()); - - } - - @Test - public void ArrayContainerCardinalityTest() { - final ArrayContainer ac = new ArrayContainer(); - for (char k = 0; k < 100; ++k) { - ac.add(k); - assertEquals(ac.getCardinality(), k + 1); - } - for (char k = 0; k < 100; ++k) { - ac.add(k); - assertEquals(ac.getCardinality(), 100); - } - } - - @Test - public void arraytest() { - final ArrayContainer rr = new ArrayContainer(); - rr.add((char) 110); - rr.add((char) 114); - rr.add((char) 115); - final char[] array = new char[3]; - int pos = 0; - for (final char i : rr) { - array[pos++] = i; - } - assertEquals(array[0], (char) 110); - assertEquals(array[1], (char) 114); - assertEquals(array[2], (char) 115); - } - - @Test - public void basictest() { - final RoaringBitmap rr = new RoaringBitmap(); - final int[] a = new int[4002]; - int pos = 0; - for (int k = 0; k < 4000; ++k) { - rr.add(k); - a[pos++] = k; - } - rr.add(100000); - a[pos++] = 100000; - rr.add(110000); - a[pos++] = 110000; - final int[] array = rr.toArray(); - - - assertArrayEquals(array, a); - } - - @Test - public void BitmapContainerCardinalityTest() { - final BitmapContainer ac = new BitmapContainer(); - for (char k = 0; k < 100; ++k) { - ac.add(k); - assertEquals(ac.getCardinality(), k + 1); - } - for (char k = 0; k < 100; ++k) { - ac.add(k); - assertEquals(ac.getCardinality(), 100); - } - } - - @Test - public void bitmapOfTest() { - int[] cuiRelsArray = new int[1024]; - for (int k = 0; k < cuiRelsArray.length; ++k) { - cuiRelsArray[k] = k; - } - RoaringBitmap rr1 = RoaringBitmap.bitmapOf(cuiRelsArray); - int[] back = rr1.toArray(); - assertArrayEquals(cuiRelsArray, back); - } - - @Test - public void bitmaptest() { - final BitmapContainer rr = new BitmapContainer(); - rr.add((char) 110); - rr.add((char) 114); - rr.add((char) 115); - final char[] array = new char[3]; - int pos = 0; - for (final char i : rr) { - array[pos++] = i; - } - assertEquals(array[0], (char) 110); - assertEquals(array[1], (char) 114); - assertEquals(array[2], (char) 115); - } - - @Test - public void cardinalityTest() { - final int N = 1024; - for (int gap = 7; gap < 100000; gap *= 10) { - for (int offset = 2; offset <= 1024; offset *= 2) { - final RoaringBitmap rb = new RoaringBitmap(); - // check the add of new values - for (int k = 0; k < N; k++) { - rb.add(k * gap); - assertEquals(rb.getCardinality(), k + 1); - } - assertEquals(rb.getCardinality(), N); - // check the add of existing values - for (int k = 0; k < N; k++) { - rb.add(k * gap); - assertEquals(rb.getCardinality(), N); - } - - final RoaringBitmap rb2 = new RoaringBitmap(); - - for (int k = 0; k < N; k++) { - rb2.add(k * gap * offset); - assertEquals(rb2.getCardinality(), k + 1); - } - - assertEquals(rb2.getCardinality(), N); - - for (int k = 0; k < N; k++) { - rb2.add(k * gap * offset); - assertEquals(rb2.getCardinality(), N); - } - assertEquals(RoaringBitmap.and(rb, rb2).getCardinality(), N / offset); - assertEquals(RoaringBitmap.or(rb, rb2).getCardinality(), 2 * N - N / offset); - assertEquals(RoaringBitmap.xor(rb, rb2).getCardinality(), 2 * N - 2 * N / offset); - } - } - } - - @Test - public void clearTest() { - final RoaringBitmap rb = new RoaringBitmap(); - for (int i = 0; i < 200000; i += 7) { - // dense - rb.add(i); - } - for (int i = 200000; i < 400000; i += 177) { - // sparse - rb.add(i); - } - - final RoaringBitmap rb2 = new RoaringBitmap(); - final RoaringBitmap rb3 = new RoaringBitmap(); - for (int i = 0; i < 200000; i += 4) { - rb2.add(i); - } - for (int i = 200000; i < 400000; i += 14) { - rb2.add(i); - } - - rb.clear(); - assertEquals(0, rb.getCardinality()); - assertTrue(0 != rb2.getCardinality()); - - rb.add(4); - rb3.add(4); - final RoaringBitmap andresult = RoaringBitmap.and(rb, rb2); - final RoaringBitmap orresult = RoaringBitmap.or(rb, rb2); - - assertEquals(1, andresult.getCardinality()); - assertEquals(rb2.getCardinality(), orresult.getCardinality()); - - for (int i = 0; i < 200000; i += 4) { - rb.add(i); - rb3.add(i); - } - for (int i = 200000; i < 400000; i += 114) { - rb.add(i); - rb3.add(i); - } - - final int[] arrayrr = rb.toArray(); - final int[] arrayrr3 = rb3.toArray(); - - assertArrayEquals(arrayrr, arrayrr3); - } - - @Test - public void ContainerFactory() { - BitmapContainer bc1, bc2, bc3; - ArrayContainer ac1, ac2, ac3; - - bc1 = new BitmapContainer(); - bc2 = new BitmapContainer(); - bc3 = new BitmapContainer(); - ac1 = new ArrayContainer(); - ac2 = new ArrayContainer(); - ac3 = new ArrayContainer(); - - for (char i = 0; i < 5000; i++) { - bc1.add((char) (i * 70)); - } - for (char i = 0; i < 5000; i++) { - bc2.add((char) (i * 70)); - } - for (char i = 0; i < 5000; i++) { - bc3.add((char) (i * 70)); - } - - for (char i = 0; i < 4000; i++) { - ac1.add((char) (i * 50)); - } - for (char i = 0; i < 4000; i++) { - ac2.add((char) (i * 50)); - } - for (char i = 0; i < 4000; i++) { - ac3.add((char) (i * 50)); - } - - BitmapContainer rbc; - - rbc = ac1.clone().toBitmapContainer(); - assertTrue(validate(rbc, ac1)); - rbc = ac2.clone().toBitmapContainer(); - assertTrue(validate(rbc, ac2)); - rbc = ac3.clone().toBitmapContainer(); - assertTrue(validate(rbc, ac3)); - } - - @Test - public void containerSharingWithXor() { - RoaringBitmap r1 = new RoaringBitmap(); - r1.flip(131000L, 131001L); - RoaringBitmap r2 = new RoaringBitmap(); - r2.add(220000); - RoaringBitmap r3 = new RoaringBitmap(); - int killingPosition = 66000; - r3.add(killingPosition); - assertFalse(r1.contains(killingPosition)); - r2.xor(r1); - assertTrue(r2.contains(131000)); - assertFalse(r1.contains(killingPosition)); - r2.or(r3); - assertTrue(r2.contains(131000)); - assertTrue(r2.contains(killingPosition)); - assertFalse(r1.contains(killingPosition)); - } - - // From a bug report contributed by Kevin Karpenske - // this had created an array out of bounds error - @Test - public void fliptest_Karpenske() { - long[] array = new long[]{343798, 343799, 343800, 343801, 343803, 343804, 343805, 343807, 343809, - 343811, 343812, 343815, 343816, 343817, 343818, 343819, 343821, 343825, 343827, 343828, - 343830, 343831, 343832, 343833, 343835, 343836, 343837, 343838, 343839, 343840, 343841, - 343842, 343843, 343844, 343845, 343847, 343848, 343849, 343850, 343851, 343853, 343854, - 343855, 343856, 343858, 343859, 343860, 343861, 343862, 343863, 343864, 343865, 343866, - 343868, 343869, 343874, 343875, 343877, 343879, 343880, 343881, 343882, 343883, 343887, - 343889, 343890, 343891, 343894, 343895, 343898, 343899, 343900, 343901, 343902, 343904, - 343906, 343907, 343908, 343909, 343910, 343911, 343912, 343913, 343914, 343915, 343916, - 343917, 343918, 343919, 343921, 343922, 343923, 343924, 343927, 343928, 343929, 343930, - 343931, 343932, 343933, 343934, 343935, 343938, 343939, 343941, 343942, 343943, 343944, - 343945, 343946, 343949, 343951, 343953, 343954, 343955, 343956, 343958, 343959, 343961, - 343962, 343964, 343965, 343966, 343967, 343968, 343969, 343971, 343972, 343973, 343974, - 343976, 343978, 343979, 343981, 343982, 343983, 343985, 343987, 343988, 343989, 343992, - 343993, 343994, 343995, 343996, 343997, 343998, 344000, 344001, 344002, 344003, 344004, - 344006, 344008, 344009, 344011, 344012, 344013, 344015, 344017, 344019, 344020, 344021, - 344023, 344025, 344026, 344027, 344028, 344029, 344030, 344031, 344034, 344035, 344036, - 344037, 344038, 344039, 344040, 344042, 344043, 344046, 344047}; - RoaringBitmap bitmap = new RoaringBitmap(); - long[] indexes = array; - int rangeStart = 0; - for (int rangeEnd = 1; rangeEnd < indexes.length; rangeEnd++) { - if (indexes[rangeEnd - 1] + 1 != indexes[rangeEnd]) { - if (rangeStart == rangeEnd - 1) { - bitmap.add((int) indexes[rangeStart]); - } else { - bitmap.flip(indexes[rangeStart], indexes[rangeEnd - 1] + 1); - } - rangeStart = rangeEnd; - } - } - if (rangeStart == indexes.length - 1) { - bitmap.add((int) indexes[rangeStart]); - } else { - bitmap.flip(indexes[rangeStart], indexes[indexes.length - 1] + 1); - } - assertEquals(182, bitmap.getCardinality()); - } - - @Test - public void flipTest1() { - final RoaringBitmap rb = new RoaringBitmap(); - - rb.flip(100000L, 200000L); // in-place on empty bitmap - final int rbcard = rb.getCardinality(); - assertEquals(100000, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 100000; i < 200000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest1A() { - final RoaringBitmap rb = new RoaringBitmap(); - - final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 200000L); - final int rbcard = rb1.getCardinality(); - assertEquals(100000, rbcard); - assertEquals(0, rb.getCardinality()); - - final BitSet bs = new BitSet(); - assertTrue(equals(bs, rb)); // still empty? - for (int i = 100000; i < 200000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb1)); - } - - @Test - public void flipTest2() { - final RoaringBitmap rb = new RoaringBitmap(); - - rb.flip(100000L, 100000L); - final int rbcard = rb.getCardinality(); - assertEquals(0, rbcard); - - final BitSet bs = new BitSet(); - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest2A() { - final RoaringBitmap rb = new RoaringBitmap(); - - final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 100000L); - rb.add(1); // will not affect rb1 (no shared container) - final int rbcard = rb1.getCardinality(); - assertEquals(0, rbcard); - assertEquals(1, rb.getCardinality()); - - final BitSet bs = new BitSet(); - assertTrue(equals(bs, rb1)); - bs.set(1); - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest3() { - final RoaringBitmap rb = new RoaringBitmap(); - - rb.flip(100000L, 200000L); // got 100k-199999 - rb.flip(100000L, 199991L); // give back 100k-199990 - final int rbcard = rb.getCardinality(); - - assertEquals(9, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 199991; i < 200000; ++i) { - bs.set(i); - } - - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest3A() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 200000L); - final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 100000L, 199991L); - final int rbcard = rb2.getCardinality(); - - assertEquals(9, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 199991; i < 200000; ++i) { - bs.set(i); - } - - assertTrue(equals(bs, rb2)); - } - - @Test - public void flipTest4() { // fits evenly on both ends - final RoaringBitmap rb = new RoaringBitmap(); - rb.flip(100000L, 200000L); // got 100k-199999 - rb.flip(65536L, 4 * 65536L); - final int rbcard = rb.getCardinality(); - - // 65536 to 99999 are 1s - // 200000 to 262143 are 1s: total card - - assertEquals(96608, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 65536; i < 100000; ++i) { - bs.set(i); - } - for (int i = 200000; i < 262144; ++i) { - bs.set(i); - } - - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest4A() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 200000L); - final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 65536L, 4 * 65536L); - final int rbcard = rb2.getCardinality(); - - assertEquals(96608, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 65536; i < 100000; ++i) { - bs.set(i); - } - for (int i = 200000; i < 262144; ++i) { - bs.set(i); - } - - assertTrue(equals(bs, rb2)); - } - - @Test - public void flipTest5() { // fits evenly on small end, multiple - // containers - final RoaringBitmap rb = new RoaringBitmap(); - rb.flip(100000L, 132000L); - rb.flip(65536L, 120000L); - final int rbcard = rb.getCardinality(); - - // 65536 to 99999 are 1s - // 120000 to 131999 - - assertEquals(46464, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 65536; i < 100000; ++i) { - bs.set(i); - } - for (int i = 120000; i < 132000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest5A() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 132000L); - final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 65536L, 120000L); - final int rbcard = rb2.getCardinality(); - - assertEquals(46464, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 65536; i < 100000; ++i) { - bs.set(i); - } - for (int i = 120000; i < 132000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb2)); - } - - @Test - public void flipTest6() { // fits evenly on big end, multiple containers - final RoaringBitmap rb = new RoaringBitmap(); - rb.flip(100000L, 132000L); - rb.flip(99000L, 2 * 65536L); - final int rbcard = rb.getCardinality(); - - // 99000 to 99999 are 1000 1s - // 131072 to 131999 are 928 1s - - assertEquals(1928, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 99000; i < 100000; ++i) { - bs.set(i); - } - for (int i = 2 * 65536; i < 132000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest6A() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 132000L); - final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 99000L, 2 * 65536L); - final int rbcard = rb2.getCardinality(); - - assertEquals(1928, rbcard); - - final BitSet bs = new BitSet(); - for (int i = 99000; i < 100000; ++i) { - bs.set(i); - } - for (int i = 2 * 65536; i < 132000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb2)); - } - - @Test - public void flipTest7() { // within 1 word, first container - final RoaringBitmap rb = new RoaringBitmap(); - rb.flip(650L, 132000L); - rb.flip(648L, 651L); - final int rbcard = rb.getCardinality(); - - // 648, 649, 651-131999 - - assertEquals(132000 - 651 + 2, rbcard); - - final BitSet bs = new BitSet(); - bs.set(648); - bs.set(649); - for (int i = 651; i < 132000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb)); - } - - @Test - public void flipTest7A() { // within 1 word, first container - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 650L, 132000L); - final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 648L, 651L); - final int rbcard = rb2.getCardinality(); - - // 648, 649, 651-131999 - - assertEquals(132000 - 651 + 2, rbcard); - - final BitSet bs = new BitSet(); - bs.set(648); - bs.set(649); - for (int i = 651; i < 132000; ++i) { - bs.set(i); - } - assertTrue(equals(bs, rb2)); - } - - @Test - public void flipTest8() { - final RoaringBitmap rb = new RoaringBitmap(); - rb.add(0); - rb.add(2); - final RoaringBitmap rb2 = RoaringBitmap.flip(rb, 0L, 3L); - - final BitSet bs = new BitSet(); - bs.set(1); - assertTrue(equals(bs, rb2)); - } - - - @Test - public void flipTestBigInt() { - final RoaringBitmap rb = new RoaringBitmap(); - rb.add(Integer.MAX_VALUE + 100000); - rb.add(Integer.MAX_VALUE + 100002); - final RoaringBitmap rb2 = RoaringBitmap.flip(rb, Integer.MAX_VALUE + 100001L, - Integer.MAX_VALUE + 200000L); - assertEquals(99999, rb2.getCardinality()); - assertTrue(rb2.contains(Integer.MAX_VALUE + 100000)); - assertFalse(rb2.contains(Integer.MAX_VALUE + 100002)); - assertTrue(rb2.contains(Integer.MAX_VALUE + 199999)); - } - - - @Test - public void flipTestBig() { - final int numCases = 1000; - final RoaringBitmap rb = new RoaringBitmap(); - final BitSet bs = new BitSet(); - final Random r = new Random(3333); - int checkTime = 2; - - for (int i = 0; i < numCases; ++i) { - final long start = r.nextInt(65536 * 20); - long end = r.nextInt(65536 * 20); - if (r.nextDouble() < 0.1) { - end = start + r.nextInt(100); - } - rb.flip(start, end); - if (start < end) { - bs.flip((int) start, (int) end); // throws exception - } - // otherwise - // insert some more ANDs to keep things sparser - if (r.nextDouble() < 0.2) { - final RoaringBitmap mask = new RoaringBitmap(); - final BitSet mask1 = new BitSet(); - final long startM = r.nextInt(65536 * 20); - final long endM = startM + 100000; - mask.flip(startM, endM); - mask1.flip((int) startM, (int) endM); - mask.flip(0L, 65536L * 20 + 100000); - mask1.flip(0, 65536 * 20 + 100000); - rb.and(mask); - bs.and(mask1); - } - // see if we can detect incorrectly shared containers - if (r.nextDouble() < 0.1) { - final RoaringBitmap irrelevant = RoaringBitmap.flip(rb, 10L, 100000L); - irrelevant.flip(5L, 200000L); - irrelevant.flip(190000L, 260000L); - } - if (i > checkTime) { - assertTrue(equals(bs, rb)); - checkTime *= 1.5; - } - } - } - - @Test - public void flipTestBigA() { - final int numCases = 1000; - final BitSet bs = new BitSet(); - final Random r = new Random(3333); - int checkTime = 2; - RoaringBitmap rb1 = new RoaringBitmap(), rb2 = null; // alternate - // between - // them - for (int i = 0; i < numCases; ++i) { - final int start = r.nextInt(65536 * 20); - int end = r.nextInt(65536 * 20); - if (r.nextDouble() < 0.1) { - end = start + r.nextInt(100); - } - - if ((i & 1) == 0) { - rb2 = RoaringBitmap.flip(rb1, (long) start, (long) end); - // tweak the other, catch bad sharing - long r1 = r.nextInt(65536 * 20); - long r2 = r.nextInt(65536 * 20); - rb1.flip(r1, r2); - } else { - rb1 = RoaringBitmap.flip(rb2, (long) start, (long) end); - long r1 = r.nextInt(65536 * 20); - long r2 = r.nextInt(65536 * 20); - rb2.flip(r1, r2); - } - - if (start < end) { - bs.flip(start, end); // throws exception - // otherwise - } - // insert some more ANDs to keep things sparser - if (r.nextDouble() < 0.2 && (i & 1) == 0) { - final RoaringBitmap mask = new RoaringBitmap(); - final BitSet mask1 = new BitSet(); - final int startM = r.nextInt(65536 * 20); - final int endM = startM + 100000; - mask.flip((long) startM, (long) endM); - mask1.flip(startM, endM); - mask.flip(0L, 65536L * 20 + 100000); - mask1.flip(0, 65536 * 20 + 100000); - rb2.and(mask); - bs.and(mask1); - } - if (i > checkTime) { - final RoaringBitmap rb = (i & 1) == 0 ? rb2 : rb1; - final boolean status = equals(bs, rb); - assertTrue(status); - checkTime *= 1.5; - } - } - } - - @Test - public void intersecttest() { - final RoaringBitmap rr1 = new RoaringBitmap(); - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 0; k < 40000; ++k) { - rr1.add(2 * k); - rr2.add(2 * k + 1); - } - assertFalse(RoaringBitmap.intersects(rr1, rr2)); - rr1.add(2 * 500 + 1); - assertTrue(RoaringBitmap.intersects(rr1, rr2)); - final RoaringBitmap rr3 = new RoaringBitmap(); - rr3.add(2 * 501 + 1); - assertTrue(RoaringBitmap.intersects(rr3, rr2)); - assertFalse(RoaringBitmap.intersects(rr3, rr1)); - for (int k = 0; k < 40000; ++k) { - rr1.add(2 * k + 1); - } - rr1.runOptimize(); - assertTrue(RoaringBitmap.intersects(rr1, rr2)); - } - - @Test - public void intersecttestWithRange() { - RoaringBitmap rr1 = new RoaringBitmap(); - RoaringBitmap rr2 = new RoaringBitmap(); - RoaringBitmap rr3 = new RoaringBitmap(); - - // This bitmap containers will be Run Containers - rr1.add(1L, 4L); - rr1.add(6L, 10L); - - - // This one will be Array Containers - rr2.add(0); - rr2.add(2); - - rr2.add(6); - rr2.add(7); - rr2.add(9); - - assertFalse(rr1.intersects(0, 1)); - assertTrue(rr1.intersects(0, 3)); - assertTrue(rr1.intersects(0, 11)); - assertFalse(rr1.intersects(12, 14)); - assertFalse(rr1.intersects(4, 5)); - assertTrue(rr1.intersects(2, 3)); - assertTrue(rr1.intersects(4, 8)); - assertTrue(rr1.intersects(8, 12)); - - assertTrue(rr2.intersects(0, 11)); - assertFalse(rr2.intersects(12, 14)); - assertFalse(rr2.intersects(4, 5)); - assertTrue(rr2.intersects(2, 3)); - assertTrue(rr2.intersects(4, 8)); - assertTrue(rr2.intersects(8, 12)); - - rr3.add(5L, 10L); - assertTrue(rr3.intersects(5, 10)); - } - - - @Test - public void shouldNotIntersectWithDisjointRangeBelowBitmapFirst() { - char[] keys = new char[1]; - Container[] values = new Container[1]; - RoaringBitmap bitmap = new RoaringBitmap(new RoaringArray(keys, values, 1)); - keys[0] = (char) (1 << 15); - long[] bits = new long[1024]; - long word = 1789303257167203747L; - Arrays.fill(bits, word); - values[0] = new BitmapContainer(bits, 1024 * Long.bitCount(word)); - assertFalse(bitmap.intersects(0, bitmap.first() & 0xFFFFFFFFL)); - } - - @Test - public void shouldIntersectWithFirstWhenBitmapAtStart() { - char[] keys = new char[1]; - Container[] values = new Container[1]; - RoaringBitmap bitmap = new RoaringBitmap(new RoaringArray(keys, values, 1)); - keys[0] = (char) (1 << 15); - long[] bits = new long[1024]; - long word = 2697219678014362575L; - Arrays.fill(bits, word); - values[0] = new BitmapContainer(bits, 1024 * Long.bitCount(word)); - long first = (bitmap.first() & 0xFFFFFFFFL); - assertTrue(bitmap.intersects(first - 1, first + 1)); - assertTrue(bitmap.intersects(first, first + 1)); - assertFalse(bitmap.intersects(first - 1, first)); - } - - @Test - public void orBigIntsTest() { - RoaringBitmap rb = new RoaringBitmap(); - RoaringBitmap rb2 = new RoaringBitmap(); - HashSet hs = new HashSet(); - - for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) { - rb.add(i); - hs.add(i); - } - for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) { - hs.add(i); - rb.add(i); - } - for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 5) { - hs.add(i); - rb.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 3) { - hs.add(i); - rb.add(i); - } - - for (int i = 1 << 31 + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 5) { - hs.add(i); - rb2.add(i); - } - for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 3) { - hs.add(i); - rb2.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 11 * 65536; i += 5) { - hs.add(i); - rb2.add(i); - } - for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 7) { - hs.add(i); - rb2.add(i); - } - - RoaringBitmap rbor = RoaringBitmap.or(rb, rb2); - - Object[] correct = hs.toArray(); - Arrays.sort(correct); - Integer[] resor = ArrayUtils.toObject(rbor.toArray()); - assertArrayEquals(correct, resor); - } - - @Test - public void orcount() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr.add(k); - } - rr.add(100000); - rr.add(110000); - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr2.add(k); - } - - final RoaringBitmap rror = RoaringBitmap.or(rr, rr2); - assertEquals(rror.getCardinality(), RoaringBitmap.orCardinality(rr, rr2)); - - } - - @Test - public void testXorCardinality() { - final RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rb.add(k); - } - rb.add(100000); - rb.add(110000); - rb.add(1L << 20, 1L << 21); - rb.flip((1 << 20) | (1 << 19)); - final RoaringBitmap rb2 = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rb2.add(k); - } - RoaringBitmap xor = RoaringBitmap.xor(rb, rb2); - assertEquals(xor.getCardinality(), RoaringBitmap.xorCardinality(rb, rb2)); - } - - @Test - public void testAndNotCardinality() { - final RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rb.add(k); - } - rb.add(100000); - rb.add(110000); - rb.add(1L << 20, 1L << 21); - rb.flip((1 << 20) | (1 << 19)); - final RoaringBitmap rb2 = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rb2.add(k); - } - RoaringBitmap andNot = RoaringBitmap.andNot(rb, rb2); - assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(rb, rb2)); - } - - @Test - public void testAndNotCardinalityBigVsSmall() { - RoaringBitmap small = RoaringBitmap.bitmapOf(1, 2, 3); - RoaringBitmap big = new RoaringBitmap(); - for (int i = 0; i < 4000; ++i) { - big.add(1 + i * 0x1000); - } - RoaringBitmap andNot = RoaringBitmap.andNot(big, small); - assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(big, small)); - } - - @Test - public void testAndNotCardinalitySmallVsBig() { - RoaringBitmap small = RoaringBitmap.bitmapOf(1, 2, 3); - RoaringBitmap big = new RoaringBitmap(); - for (int i = 0; i < 4000; ++i) { - big.add(1 + i * 0x1000); - } - RoaringBitmap andNot = RoaringBitmap.andNot(small, big); - assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(small, big)); - } - - @Test - public void testAndNotCardinality_646() { - RoaringBitmap rb = RoaringBitmap.bitmapOf(-587409880, 605467000); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(-587409880, 347844183); - - RoaringBitmap andNot = RoaringBitmap.andNot(rb, rb2); - assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(rb, rb2)); - } - - @Test - public void testAndNotCardinality_648() { - RoaringBitmap s1 = RoaringBitmap.bitmapOf(-1388308580, 236217409, -805382570, 612285977, 1389629939, 851442526, 375756307, 61533603, 1908301308, 2097309572, 204769050, 703198559, -545810986, 2090296816, -87319453, 158018332, -685188145, -566739002, -1446363859, -372441875, -957637004, -1144076256, -1248859542, -160225853, 14707613, 866274329, 1550526350, 877999004, -1784269953, 1274953255, 1490490469, -1340013077, 2067958239, 51232349, 2060711699, -1802459974, 2039829040, -2079650027, -278950425, 1145674649, 298101576, 1687655442, 1209489632, -762136131, 399832491, 1077638711, -635674559, -1643781464, -1067907341, 144525399, 651571848, 1893053071, -2058528151, 1592871441, 84583235, 374119809, -867104416, -1941224259, 787356209, 1972857336, -720703901, -1310021857, -1831922816, 181898740, 600942551, -1745822849, -856908487, 2060184086, -1217485514, -1680395029, 1539735915, 2042390564, -1539856946, 1824974207, 1695025297, 1908431629, -395090370, -1688185468, 570601902, -701368853, -1211735380, -825285093, 788089714, -857723909, 1400502194, 285106906, -1450842998, -2125215206, 1451519492, -1559357910, 1157633452, -387704829, 2036134025, 1051239778, -1542956455, 357879569, 1962230155, -1994777800, 672516512, 174507423, -299175291, 821891018, 1062886766, -1313955904, 1732661804, -767116537, 1352149580, 2001322279, 1698147357, 40451458, 996819026, 1904959950, 2058544757, 1514282221, 234242255, -1364505429, 1498471146, 1134429786, -918860049, 1430732385, 644983298, 793600316, -1726956640, -538511147, -1945670935, 291567421, 1033590420, -1831809482, 985031287, -773476240, 1724734191, -1364525376, 1208307142, -2126741265, -1851759120, 1083333467, 185208087, -375950074, 48210573, -843304856, -295266615, -843941360, -524390895, -102924717, 836117637, 683196001, -1824825594, -1470017798, -1554712054, 291236023, -907874606, 2068945326, -899352179, -1488751007, -449279886, -1085935420, -2094131785, -474243782, 1306756671, 1353254318, 86944198, 1148225154, 487252515, -229770314, -1484325603, 109043190, -252122045, 1431750974, 1667547537, -1775516477, -512978266, -216545450, -486550865, -1193721685, -1108677522, -628326149, -1568065979, -675571394); - RoaringBitmap s2 = RoaringBitmap.bitmapOf(2060184086, 704452713, 1236293943, -178539376, 2037977331, -78910667, -587409880, 204769050, -854426111, 90628341, -1411939301, -927754519, -211274987, 998450197, -1515133464, -1652963250, 499001553, 383696025, -2019580769, 1583380373, -79264832, 1065614902, 1243463658, 424214238, 1124141647, 271662535, 1415634429, 1893053071, -1624960757, -1933550809, -1170233109, -542340662, -1681838238, 292656484, 1587781520, -1463647396, -124042559, -162307067, 1411905814, -1524651941, 1935844108, 1992426746, 422443777, 679395872, -764857187, -401706366, -2007177999, 1044794027, -1561188953, 1627034126, -401273669, -123973748, -694963705, 838892817, -1640102435, 852253834, -23120023, -2072644924, 1140820264, -550227319, -1692730465, 1491150291, 1607642920, -1015774573, -1801713682, -752796152, -439281693, -792361100, -188208805, 808883165, -1364525376, 896915854, -1672522244, -1718572341); - RoaringBitmap s3 = RoaringBitmap.bitmapOf(-30718004, -1652963250, -762136131, -1552606582, -1933550809, -1230616126, 736584428, -2136360654, 1097548480, 192408815, -295266615); - RoaringBitmap s1AndS2 = RoaringBitmap.and(s1, s2); - assertEquals(RoaringBitmap.andNot(s1AndS2, s3).getCardinality(), RoaringBitmap.andNotCardinality(s1AndS2, s3)); - } - - @Test - public void ortest() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr.add(k); - } - rr.add(100000); - rr.add(110000); - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr2.add(k); - } - - final RoaringBitmap rror = RoaringBitmap.or(rr, rr2); - - final int[] array = rror.toArray(); - final int[] arrayrr = rr.toArray(); - - assertArrayEquals(array, arrayrr); - - rr.or(rr2); - final int[] arrayirr = rr.toArray(); - assertArrayEquals(array, arrayirr); - - } - - @Test - public void ORtest() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) { - rr.add(k); - } - for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) { - rr.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) { - rr.add(k); - } - for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) { - rr.add(k); - } - for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) { - rr.add(k); - } - - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr2.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr2.add(k); - } - for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) { - rr2.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) { - rr2.add(k); - } - final RoaringBitmap correct = RoaringBitmap.or(rr, rr2); - rr.or(rr2); - assertEquals(correct, rr); - } - - @Test - public void ortest2() { - final int[] arrayrr = new int[4000 + 4000 + 2]; - int pos = 0; - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rr.add(k); - arrayrr[pos++] = k; - } - rr.add(100000); - rr.add(110000); - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 4000; k < 8000; ++k) { - rr2.add(k); - arrayrr[pos++] = k; - } - - arrayrr[pos++] = 100000; - arrayrr[pos++] = 110000; - - final RoaringBitmap rror = RoaringBitmap.or(rr, rr2); - - final int[] arrayor = rror.toArray(); - - assertArrayEquals(arrayor, arrayrr); - } - - @Test - public void ortest3() { - final HashSet V1 = new HashSet(); - final HashSet V2 = new HashSet(); - - final RoaringBitmap rr = new RoaringBitmap(); - final RoaringBitmap rr2 = new RoaringBitmap(); - // For the first 65536: rr2 has a bitmap container, and rr has - // an array container. - // We will check the union between a BitmapCintainer and an - // arrayContainer - for (int k = 0; k < 4000; ++k) { - rr2.add(k); - V1.add(k); - } - for (int k = 3500; k < 4500; ++k) { - rr.add(k); - V1.add(k); - } - for (int k = 4000; k < 65000; ++k) { - rr2.add(k); - V1.add(k); - } - - // In the second node of each roaring bitmap, we have two bitmap - // containers. - // So, we will check the union between two BitmapContainers - for (int k = 65536; k < 65536 + 10000; ++k) { - rr.add(k); - V1.add(k); - } - - for (int k = 65536; k < 65536 + 14000; ++k) { - rr2.add(k); - V1.add(k); - } - - // In the 3rd node of each Roaring Bitmap, we have an - // ArrayContainer, so, we will try the union between two - // ArrayContainers. - for (int k = 4 * 65535; k < 4 * 65535 + 1000; ++k) { - rr.add(k); - V1.add(k); - } - - for (int k = 4 * 65535; k < 4 * 65535 + 800; ++k) { - rr2.add(k); - V1.add(k); - } - - // For the rest, we will check if the union will take them in - // the result - for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) { - rr.add(k); - V1.add(k); - } - - for (int k = 7 * 65535; k < 7 * 65535 + 2000; ++k) { - rr2.add(k); - V1.add(k); - } - - final RoaringBitmap rror = RoaringBitmap.or(rr, rr2); - boolean valide = true; - - // Si tous les elements de rror sont dans V1 et que tous les - // elements de - // V1 sont dans rror(V2) - // alors V1 == rror - - final Object[] tab = V1.toArray(); - final Vector vector = new Vector(); - for (Object aTab : tab) { - vector.add((Integer) aTab); - } - - for (final int i : rror.toArray()) { - if (!vector.contains(i)) { - valide = false; - } - V2.add(i); - } - for (int i = 0; i < V1.size(); i++) { - if (!V2.contains(vector.elementAt(i))) { - valide = false; - } - } - - assertTrue(valide); - } - - @Test - public void ortest4() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - - for (int i = 0; i < 200000; i += 4) { - rb2.add(i); - } - for (int i = 200000; i < 400000; i += 14) { - rb2.add(i); - } - final int rb2card = rb2.getCardinality(); - - // check or against an empty bitmap - final RoaringBitmap orresult = RoaringBitmap.or(rb, rb2); - final RoaringBitmap off = RoaringBitmap.or(rb2, rb); - assertEquals(orresult, off); - - assertEquals(rb2card, orresult.getCardinality()); - - for (int i = 500000; i < 600000; i += 14) { - rb.add(i); - } - for (int i = 200000; i < 400000; i += 3) { - rb2.add(i); - } - // check or against an empty bitmap - final RoaringBitmap orresult2 = RoaringBitmap.or(rb, rb2); - assertEquals(rb2card, orresult.getCardinality()); - - assertEquals(rb2.getCardinality() + rb.getCardinality(), orresult2.getCardinality()); - rb.or(rb2); - assertEquals(rb, orresult2); - - } - - @Test - public void orNot() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - - rb.add(2); - rb.add(1); - rb.add(1 << 16); // 65536 - rb.add(2 << 16); //131072 - rb.add(3 << 16); //196608 - - rb2.add(1 << 16);// 65536 - rb2.add(3 << 16);//196608 - - rb.orNot(rb2, (4 << 16) - 1); - - assertEquals((4 << 16) - 1, rb.getCardinality()); - - final IntIterator iterator = rb.getIntIterator(); - - for (int i = 0; i < (4 << 16) - 1; ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next()); - } - assertFalse(iterator.hasNext()); - } - - - @Test - public void orNotRegressionTest() { - long len = 3L; - long orLen = 3L; - - RoaringBitmap one = new RoaringBitmap(); - RoaringBitmap other = new RoaringBitmap(); - other.add(0L, len); - - one.orNot(other, orLen); - } - - @Test - public void orNotZeroRangeEndPreservesBitmap() { - RoaringBitmap one = new RoaringBitmap(); - one.add(32); - - RoaringBitmap other = new RoaringBitmap(); - other.add(0L, 100); - - one.orNot(other, 0); - assertEquals(one, RoaringBitmap.bitmapOf(32)); - } - - @Test - public void orNotLimitLowerThanFirstPreservesBitmap() { - RoaringBitmap one = new RoaringBitmap(); - one.add(32); - - RoaringBitmap other = new RoaringBitmap(); - other.add(0L, 100); - - one.orNot(other, 10); - assertEquals(one, RoaringBitmap.bitmapOf(32)); - } - - - @Test - public void orNotLimitHigherThanFirstBitPreservesBitmap() { - RoaringBitmap one = new RoaringBitmap(); - one.add(32); - - RoaringBitmap other = new RoaringBitmap(); - other.add(0L, 100); - - one.orNot(other, 35); - assertEquals(one, RoaringBitmap.bitmapOf(32)); - } - - @Test - public void orNotWithSparseBitmaps() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - - rb.add(0); - rb.add(1 << 16); // 65536 - rb.add(3 << 16); //196608 - - rb2.add((4 << 16) - 1); //262143 - - rb.orNot(rb2, 4 << 16); - - assertEquals((4 << 16) - 1, rb.getCardinality()); - - final IntIterator iterator = rb.getIntIterator(); - - for (int i = 0; i < (4 << 16) - 1; ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next()); - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNotWithOtherBiggerThanOriginal() { - final RoaringBitmap rb = new RoaringBitmap(); - rb.add(1); - - final RoaringBitmap rb2 = new RoaringBitmap(); - rb2.add(1 << 14); //16384 - rb2.add(3 << 16); //196608 - - rb.orNot(rb2, (5 << 16)); - assertEquals((5 << 16) - 2, rb.getCardinality()); - - final IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (5 << 16); ++i) { - if ((i != (1 << 14)) && (i != (3 << 16))) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNotWithOtherBiggerThanOriginalAndEndRange() { - final RoaringBitmap rb = new RoaringBitmap(); - rb.add(1); - - final RoaringBitmap rb2 = new RoaringBitmap(); - rb2.add(3 << 16); //196608 - - rb.orNot(rb2, (2 << 16) + (2 << 14)); //131072 + 32768 = 163840 - assertEquals((2 << 16) + (2 << 14), rb.getCardinality()); - - final IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (2 << 16) + (2 << 14); ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNotWithOriginalBiggerThanOther() { - final RoaringBitmap rb = new RoaringBitmap(); - - rb.add(1); - rb.add(1 << 16); // 65536 - rb.add(2 << 16); //131072 - rb.add(3 << 16); //196608 - - final RoaringBitmap rb2 = new RoaringBitmap(); - - rb.orNot(rb2, (5 << 16)); - assertEquals((5 << 16), rb.getCardinality()); - - final IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (5 << 16); ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNotWithOriginalBiggerThanOther2() { - final RoaringBitmap rb = new RoaringBitmap(); - - rb.add(1); - rb.add((1 << 16) - 1); // 65535 - rb.add(1 << 16); // 65536 - rb.add(2 << 16); //131072 - rb.add(3 << 16); //196608 - - final RoaringBitmap rb2 = new RoaringBitmap(); - - rb.orNot(rb2, (1 << 14)); - - // {[0, 2^14], 65535, 65536, 131072, 196608} - assertEquals((1 << 14) + 4, rb.getCardinality()); - - final IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (1 << 14); ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - - assertTrue(iterator.hasNext()); - assertEquals((1 << 16) - 1, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(1 << 16, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(2 << 16, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(3 << 16, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - @Test - public void randomTest() { - rTest(15); - rTest(1024); - rTest(4096); - rTest(65536); - rTest(65536 * 16); - } - - public void rTest(final int N) { - for (int gap = 1; gap <= 65536; gap *= 2) { - final BitSet bs1 = new BitSet(); - final RoaringBitmap rb1 = new RoaringBitmap(); - for (int x = 0; x <= N; x += gap) { - bs1.set(x); - rb1.add(x); - } - if (bs1.cardinality() != rb1.getCardinality()) { - throw new RuntimeException("different card"); - } - if (!equals(bs1, rb1)) { - throw new RuntimeException("basic bug"); - } - for (int offset = 1; offset <= gap; offset *= 2) { - final BitSet bs2 = new BitSet(); - final RoaringBitmap rb2 = new RoaringBitmap(); - for (int x = 0; x <= N; x += gap) { - bs2.set(x + offset); - rb2.add(x + offset); - } - if (bs2.cardinality() != rb2.getCardinality()) { - throw new RuntimeException("different card"); - } - if (!equals(bs2, rb2)) { - throw new RuntimeException("basic bug"); - } - - BitSet clonebs1; - // testing AND - clonebs1 = (BitSet) bs1.clone(); - clonebs1.and(bs2); - if (!equals(clonebs1, RoaringBitmap.and(rb1, rb2))) { - throw new RuntimeException("bug and"); - } - { - final RoaringBitmap t = rb1.clone(); - t.and(rb2); - if (!equals(clonebs1, t)) { - throw new RuntimeException("bug inplace and"); - } - if (!t.equals(RoaringBitmap.and(rb1, rb2))) { - System.out - .println(t.highLowContainer.getContainerAtIndex(0).getClass().getCanonicalName()); - System.out.println(RoaringBitmap.and(rb1, rb2).highLowContainer.getContainerAtIndex(0) - .getClass().getCanonicalName()); - - throw new RuntimeException("bug inplace and"); - } - } - - // testing OR - clonebs1 = (BitSet) bs1.clone(); - clonebs1.or(bs2); - - if (!equals(clonebs1, RoaringBitmap.or(rb1, rb2))) { - throw new RuntimeException("bug or"); - } - { - final RoaringBitmap t = rb1.clone(); - t.or(rb2); - if (!equals(clonebs1, t)) { - throw new RuntimeException("bug or"); - } - if (!t.equals(RoaringBitmap.or(rb1, rb2))) { - throw new RuntimeException("bug or"); - } - if (!t.toString().equals(RoaringBitmap.or(rb1, rb2).toString())) { - throw new RuntimeException("bug or"); - } - - } - // testing XOR - clonebs1 = (BitSet) bs1.clone(); - clonebs1.xor(bs2); - if (!equals(clonebs1, RoaringBitmap.xor(rb1, rb2))) { - throw new RuntimeException("bug xor"); - } - { - final RoaringBitmap t = rb1.clone(); - t.xor(rb2); - if (!equals(clonebs1, t)) { - throw new RuntimeException("bug xor"); - } - if (!t.equals(RoaringBitmap.xor(rb1, rb2))) { - throw new RuntimeException("bug xor"); - } - } - // testing NOTAND - clonebs1 = (BitSet) bs1.clone(); - clonebs1.andNot(bs2); - if (!equals(clonebs1, RoaringBitmap.andNot(rb1, rb2))) { - throw new RuntimeException("bug andnot"); - } - clonebs1 = (BitSet) bs2.clone(); - clonebs1.andNot(bs1); - if (!equals(clonebs1, RoaringBitmap.andNot(rb2, rb1))) { - throw new RuntimeException("bug andnot"); - } - { - final RoaringBitmap t = rb2.clone(); - t.andNot(rb1); - if (!equals(clonebs1, t)) { - throw new RuntimeException("bug inplace andnot"); - } - final RoaringBitmap g = RoaringBitmap.andNot(rb2, rb1); - if (!equals(clonebs1, g)) { - throw new RuntimeException("bug andnot"); - } - if (!t.equals(g)) { - throw new RuntimeException("bug"); - } - } - clonebs1 = (BitSet) bs1.clone(); - clonebs1.andNot(bs2); - if (!equals(clonebs1, RoaringBitmap.andNot(rb1, rb2))) { - throw new RuntimeException("bug andnot"); - } - { - final RoaringBitmap t = rb1.clone(); - t.andNot(rb2); - if (!equals(clonebs1, t)) { - throw new RuntimeException("bug andnot"); - } - final RoaringBitmap g = RoaringBitmap.andNot(rb1, rb2); - if (!equals(clonebs1, g)) { - throw new RuntimeException("bug andnot"); - } - if (!t.equals(g)) { - throw new RuntimeException("bug"); - } - } - } - } - } - - @Test - public void sillytestHighBits() { - RoaringBitmap rb = RoaringBitmap.bitmapOf(-1, 0); - int[] array = rb.toArray(); - assertEquals(0, array[0]); - assertEquals(array[1], -1); - } - - @Test - public void simplecardinalityTest() { - final int N = 512; - final int gap = 70; - - final RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < N; k++) { - rb.add(k * gap); - assertEquals(rb.getCardinality(), k + 1); - } - assertEquals(rb.getCardinality(), N); - for (int k = 0; k < N; k++) { - rb.add(k * gap); - assertEquals(rb.getCardinality(), N); - } - - } - - @Test - public void sparseAnd() { - final RoaringBitmap rr1 = new RoaringBitmap(); - rr1.add(1); - rr1.add(1 << 31); - final RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(1 << 31); - RoaringBitmap and = RoaringBitmap.and(rr1, rr2); - assertEquals(1, and.getCardinality()); - assertTrue(and.contains(1 << 31)); - rr1.and(rr2); - assertEquals(1, rr1.getCardinality()); - assertTrue(and.contains(1 << 31)); - } - - @Test - public void sparseAndNot() { - final RoaringBitmap rr1 = new RoaringBitmap(); - rr1.add(1); - rr1.add(1 << 31); - final RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(1 << 31); - RoaringBitmap andNot = RoaringBitmap.andNot(rr1, rr2); - assertEquals(1, andNot.getCardinality()); - assertTrue(andNot.contains(1)); - rr1.andNot(rr2); - assertEquals(1, rr1.getCardinality()); - assertTrue(andNot.contains(1)); - } - - @Test - public void sparseOr() { - final RoaringBitmap rr1 = new RoaringBitmap(); - rr1.add(1); - rr1.add(1 << 31); - final RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(1 << 31); - RoaringBitmap or = RoaringBitmap.or(rr1, rr2); - assertEquals(2, or.getCardinality()); - assertTrue(or.contains(1)); - assertTrue(or.contains(1 << 31)); - rr1.or(rr2); - assertEquals(2, rr1.getCardinality()); - assertTrue(or.contains(1)); - assertTrue(or.contains(1 << 31)); - } - - - @Test - public void sparseXor() { - final RoaringBitmap rr1 = new RoaringBitmap(); - rr1.add(1); - rr1.add(1 << 31); - final RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(1 << 31); - RoaringBitmap xor = RoaringBitmap.xor(rr1, rr2); - assertEquals(1, xor.getCardinality()); - assertTrue(xor.contains(1)); - rr1.xor(rr2); - assertEquals(1, rr1.getCardinality()); - assertTrue(xor.contains(1)); - } - - @Test - public void testAndNot() { - int[] array1 = {39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183, - 39184, 39185, 39186, 39187, 39188}; - int[] array2 = {14205}; - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(array1); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(array2); - RoaringBitmap answer = RoaringBitmap.andNot(rb1, rb2); - assertEquals(answer.getCardinality(), array1.length); - } - - @Test - public void testAstesana() { - RoaringBitmap r1 = new RoaringBitmap(); - // Strange thing: Replace this line by r1.add(131000) and the bug vanishes! - r1.flip(131000L, 131001L); - RoaringBitmap r2 = new RoaringBitmap(); - r2.add(220000); - RoaringBitmap r3 = new RoaringBitmap(); - int killingPosition = 66000; - r3.add(killingPosition); - assertFalse(r1.contains(killingPosition)); // ok - r2.or(r1); - assertFalse(r1.contains(killingPosition)); // ok - r2.or(r3); - assertFalse(r1.contains(killingPosition)); // ko - } - - @Test - public void testCheckedAdd() { - RoaringBitmap rb = new RoaringBitmap(); - // checking if the true value is well returned - // when adding new ints - for (int i = 0; i < 2 * (1 << 16); i += 2) { - assertTrue(rb.checkedAdd(i)); - } - for (int i = 1; i < 2 * (1 << 16); i += 2) { - assertTrue(rb.checkedAdd(i)); - } - // Checking if the false value is well returned - // when adding already existing ints - for (int i = 0; i < 2 * (1 << 16); i += 2) { - assertFalse(rb.checkedAdd(i)); - } - for (int i = 1; i < 2 * (1 << 16) + 1; i += 2) { - assertFalse(rb.checkedAdd(i)); - } - } - - @Test - public void testCheckedRemove() { - RoaringBitmap rb = new RoaringBitmap(); - // checking if the true value is well returned - // when adding new ints - for (int i = 0; i < 2 * (1 << 16); i++) { - rb.add(i); - } - for (int i = 0; i < 2 * (1 << 16); i += 2) { - assertTrue(rb.checkedRemove(i)); - } - for (int i = 0; i < 2 * (1 << 16); i += 2) { - assertFalse(rb.checkedRemove(i)); - } - for (int i = 1; i < 2 * (1 << 16); i += 2) { - assertTrue(rb.checkedRemove(i)); - } - for (int i = 1; i < 2 * (1 << 16) + 1; i += 2) { - assertFalse(rb.checkedRemove(i)); - } - } - - @Test - public void testContains() throws IOException { - RoaringBitmap rbm1 = new RoaringBitmap(); - for (int k = 0; k < 1000; ++k) { - rbm1.add(17 * k); - } - for (int k = 0; k < 17 * 1000; ++k) { - assertEquals(rbm1.contains(k), (k / 17 * 17 == k)); - } - } - - @Test - public void testEqual() { - RoaringBitmap rr1 = RoaringBitmap.bitmapOf(1, 2, 100000); - RoaringBitmap rr2 = RoaringBitmap.bitmapOf(3, 4, 100001); - RoaringBitmap rr3 = RoaringBitmap.bitmapOf(1, 2, 100000); - assertEquals(rr1, rr3); - assertNotEquals(rr1, rr2); - assertNotEquals(rr3, rr2); - } - - // tests for how range falls on container boundaries - - @Test - public void testFlip() { - RoaringBitmap rb = new RoaringBitmap(); - for (int i = 0; i < 1 << 20; ++i) { - rb.flip(i); - assertEquals(rb.getCardinality(), i + 1); - } - for (int i = (1 << 20) - 1; i >= 0; --i) { - rb.flip(i); - assertEquals(rb.getCardinality(), i); - } - } - - @Test - public void testFlipBigInts() { - RoaringBitmap rb = new RoaringBitmap(); - for (int i = 0; i < 1 << 20; ++i) { - rb.flip((1 << 31) + i); - assertEquals(rb.getCardinality(), i + 1); - } - for (int i = (1 << 20) - 1; i >= 0; --i) { - rb.flip((1 << 31) + i); - assertEquals(rb.getCardinality(), i); - } - } - - - @Test - public void testFlipOnEmpty() { - RoaringBitmap r1 = new RoaringBitmap(); - r1.flip(0L, 10L); - assertEquals(10, r1.getCardinality()); - } - - @Test - public void testHash() { - RoaringBitmap rbm1 = new RoaringBitmap(); - rbm1.add(17); - RoaringBitmap rbm2 = new RoaringBitmap(); - rbm2.add(17); - assertEquals(rbm1.hashCode(), rbm2.hashCode()); - rbm2 = rbm1.clone(); - assertEquals(rbm1.hashCode(), rbm2.hashCode()); - } - - @Test - public void testHighBits() { - for (int offset = 1 << 14; offset < 1 << 18; offset *= 2) { - RoaringBitmap rb = new RoaringBitmap(); - for (long k = Integer.MIN_VALUE; k < Integer.MAX_VALUE; k += offset) { - rb.add((int) k); - } - int cardinality = 0; - for (long k = Integer.MIN_VALUE; k < Integer.MAX_VALUE; k += offset) { - assertTrue(rb.contains((int) k)); - ++cardinality; - } - int[] array = rb.toArray(); - assertEquals(array.length, cardinality); - for (int k = 0; k < array.length - 1; ++k) { - assertTrue((0xFFFFFFFFL & array[k]) <= (0xFFFFFFFFL & array[k + 1])); - } - } - } - - @Test - public void testHorizontalOrCardinality() { - int[] vals = {65535, 131071, 196607, 262143, 327679, 393215, 458751, 524287}; - final RoaringBitmap[] b = new RoaringBitmap[2]; - b[0] = RoaringBitmap.bitmapOf(vals); - b[1] = RoaringBitmap.bitmapOf(vals); - RoaringBitmap a = FastAggregation.or(new Iterator() { - int k = 0; - - @Override - public boolean hasNext() { - return k < b.length; - } - - @Override - public RoaringBitmap next() { - return b[k++]; - } - - @Override - public void remove() { - } - }); - assertEquals(8, a.getCardinality()); - } - - - @Test - public void testHorizontalOrCardinalityBigInts() { - int[] vals = {(1 << 31) + 65535, (1 << 31) + 131071, (1 << 31) + 196607, (1 << 31) + 262143, (1 << 31) + 327679, (1 << 31) + 393215, (1 << 31) + 458751, (1 << 31) + 524287}; - final RoaringBitmap[] b = new RoaringBitmap[2]; - b[0] = RoaringBitmap.bitmapOf(vals); - b[1] = RoaringBitmap.bitmapOf(vals); - RoaringBitmap a = FastAggregation.or(new Iterator() { - int k = 0; - - @Override - public boolean hasNext() { - return k < b.length; - } - - @Override - public RoaringBitmap next() { - return b[k++]; - } - - @Override - public void remove() { - } - }); - assertEquals(8, a.getCardinality()); - } - - - @Test - public void testIterator() { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rb.add(k); - } - for (int k = 0; k < 1000; ++k) { - rb.add(k * 100); - } - RoaringBitmap copy1 = new RoaringBitmap(); - for (int x : rb) { - copy1.add(x); - } - assertEquals(copy1, rb); - RoaringBitmap copy2 = new RoaringBitmap(); - IntIterator i = rb.getIntIterator(); - while (i.hasNext()) { - copy2.add(i.next()); - } - assertEquals(copy2, rb); - } - - - @Test - public void testIteratorBigInts() { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 4000; ++k) { - rb.add((1 << 31) + k); - } - for (int k = 0; k < 1000; ++k) { - rb.add((1 << 31) + k * 100); - } - RoaringBitmap copy1 = new RoaringBitmap(); - for (int x : rb) { - copy1.add(x); - } - assertEquals(copy1, rb); - RoaringBitmap copy2 = new RoaringBitmap(); - IntIterator i = rb.getIntIterator(); - while (i.hasNext()) { - copy2.add(i.next()); - } - assertEquals(copy2, rb); - } - - - @Test - public void testLimit() { - for (int gap = 1; gap <= 1024; gap *= 2) { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k += gap) { - rb.add(k); - } - int thiscard = rb.getCardinality(); - for (int k = 0; k < thiscard; k += 100) { - RoaringBitmap limited = rb.limit(k); - assertEquals(limited.getCardinality(), k); - } - assertEquals(rb.limit(thiscard).getCardinality(), thiscard); - assertEquals(rb.limit(thiscard + 1).getCardinality(), thiscard); - } - } - - - @Test - public void testLimitBigInts() { - for (int gap = 1; gap <= 1024; gap *= 2) { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k += gap) { - rb.add((1 << 31) + k); - } - int thiscard = rb.getCardinality(); - for (int k = 0; k < thiscard; k += 100) { - RoaringBitmap limited = rb.limit(k); - assertEquals(limited.getCardinality(), k); - } - assertEquals(rb.limit(thiscard).getCardinality(), thiscard); - assertEquals(rb.limit(thiscard + 1).getCardinality(), thiscard); - } - } - - - /** - * Test massive and. - */ - @Test - public void testMassiveAnd() { - RoaringBitmap[] ewah = new RoaringBitmap[1024]; - for (int k = 0; k < ewah.length; ++k) { - ewah[k] = new RoaringBitmap(); - } - int howmany = 1000000; - for (int k = 0; k < howmany; ++k) { - ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k); - } - for (int k = 3; k < ewah.length; k += 3) { - ewah[k].flip(13L, (long) howmany / 2); - } - for (int N = 2; N < ewah.length; ++N) { - RoaringBitmap answer = ewah[0]; - for (int k = 1; k < N; ++k) { - RoaringBitmap oldAnswer = answer; - answer = RoaringBitmap.and(oldAnswer, ewah[k]); - assertEquals(answer.getCardinality(), - RoaringBitmap.andCardinality(oldAnswer, ewah[k])); - } - RoaringBitmap answer2 = FastAggregation.and(Arrays.copyOf(ewah, N)); - assertEquals(answer, answer2); - RoaringBitmap answer2b = FastAggregation.and(toIterator(Arrays.copyOf(ewah, N))); - assertEquals(answer, answer2b); - } - } - - @Test - public void testMassiveAndBigInts() { - RoaringBitmap[] ewah = new RoaringBitmap[1024]; - for (int k = 0; k < ewah.length; ++k) { - ewah[k] = new RoaringBitmap(); - } - int howmany = 1000000; - for (int k = 0; k < howmany; ++k) { - ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k); - } - for (int k = 3; k < ewah.length; k += 3) { - ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2); - } - for (int N = 2; N < ewah.length; ++N) { - RoaringBitmap answer = ewah[0]; - for (int k = 1; k < N; ++k) { - RoaringBitmap oldAnswer = answer; - answer = RoaringBitmap.and(oldAnswer, ewah[k]); - assertEquals(answer.getCardinality(), - RoaringBitmap.andCardinality(oldAnswer, ewah[k])); - } - RoaringBitmap answer2 = FastAggregation.and(Arrays.copyOf(ewah, N)); - assertEquals(answer, answer2); - RoaringBitmap answer2b = FastAggregation.and(toIterator(Arrays.copyOf(ewah, N))); - assertEquals(answer, answer2b); - } - } - - private static class ExtendedRoaringBitmap extends RoaringBitmap { - } - - /** - * Tests that the static #or operation works correctly with an iterator of - * RoaringBitmap extended classes. - */ - @Test - public void testOrWithIterator() { - final RoaringBitmap b1 = new RoaringBitmap(); - b1.add(13); - final RoaringBitmap b2 = new RoaringBitmap(); - b2.add(42); - - final RoaringBitmap result = RoaringBitmap.or(Arrays.asList(b1, b2).iterator()); - assertTrue(result.contains(13)); - assertTrue(result.contains(42)); - } - - /** - * Tests that the static #or operation works correctly with an iterator of - * RoaringBitmap extended classes. - */ - @Test - public void testOrWithIteratorOfExtendedRoaringBitmaps() { - final ExtendedRoaringBitmap b1 = new ExtendedRoaringBitmap(); - b1.add(1); - final ExtendedRoaringBitmap b2 = new ExtendedRoaringBitmap(); - b2.add(2); - - final RoaringBitmap result = RoaringBitmap.or(Arrays.asList(b1, b2).iterator()); - assertTrue(result.contains(1)); - assertTrue(result.contains(2)); - } - - /** - * Test massive or. - */ - @Test - public void testMassiveOr() { - final int N = 128; - for (int howmany = 512; howmany <= 1000000; howmany *= 2) { - RoaringBitmap[] ewah = new RoaringBitmap[N]; - for (int k = 0; k < ewah.length; ++k) { - ewah[k] = new RoaringBitmap(); - } - for (int k = 0; k < howmany; ++k) { - ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k); - } - for (int k = 3; k < ewah.length; k += 3) { - ewah[k].flip(13L, (long) howmany / 2); - } - RoaringBitmap answer = ewah[0]; - for (int k = 1; k < ewah.length; ++k) { - answer = RoaringBitmap.or(answer, ewah[k]); - } - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]); - List rbl = new ArrayList<>(); - rbl.add(rb1); - rbl.add(rb2); - - ArrayList arrayList = new ArrayList<>(); - arrayList.add(rb1); - arrayList.add(rb2); - Iterator rbi = arrayList.iterator(); - - RoaringBitmap rbor = RoaringBitmap.or(rb1, rb2); - RoaringBitmap answer2 = FastAggregation.or(ewah); - RoaringBitmap answer3 = FastAggregation.horizontal_or(ewah); - RoaringBitmap answer3b = FastAggregation.or(toIterator(ewah)); - assertEquals(answer, answer2); - assertEquals(answer, answer3); - assertEquals(answer, answer3b); - assertEquals(rbor, FastAggregation.horizontal_or(rbl)); - assertEquals(rbor, FastAggregation.priorityqueue_or(rb1, rb2)); - assertEquals(rbor, FastAggregation.priorityqueue_or(rbi)); - } - } - - @Test - public void testMassiveOrBigInts() { - final int N = 128; - for (int howmany = 512; howmany <= 1000000; howmany *= 2) { - RoaringBitmap[] ewah = new RoaringBitmap[N]; - for (int k = 0; k < ewah.length; ++k) { - ewah[k] = new RoaringBitmap(); - } - for (int k = 0; k < howmany; ++k) { - ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k); - } - for (int k = 3; k < ewah.length; k += 3) { - ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2); - } - RoaringBitmap answer = ewah[0]; - for (int k = 1; k < ewah.length; ++k) { - answer = RoaringBitmap.or(answer, ewah[k]); - } - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]); - List rbl = new ArrayList<>(); - rbl.add(rb1); - rbl.add(rb2); - - ArrayList arrayList = new ArrayList<>(); - arrayList.add(rb1); - arrayList.add(rb2); - Iterator rbi = arrayList.iterator(); - - RoaringBitmap rbor = RoaringBitmap.or(rb1, rb2); - RoaringBitmap answer2 = FastAggregation.or(ewah); - RoaringBitmap answer3 = FastAggregation.horizontal_or(ewah); - RoaringBitmap answer3b = FastAggregation.or(toIterator(ewah)); - assertEquals(answer, answer2); - assertEquals(answer, answer3); - assertEquals(answer, answer3b); - assertEquals(rbor, FastAggregation.horizontal_or(rbl)); - assertEquals(rbor, FastAggregation.priorityqueue_or(rb1, rb2)); - assertEquals(rbor, FastAggregation.priorityqueue_or(rbi)); - } - } - - - /** - * Test massive xor. - */ - @Test - public void testMassiveXOr() { - final int N = 128; - for (int howmany = 512; howmany <= 1000000; howmany *= 2) { - RoaringBitmap[] ewah = new RoaringBitmap[N]; - for (int k = 0; k < ewah.length; ++k) { - ewah[k] = new RoaringBitmap(); - } - for (int k = 0; k < howmany; ++k) { - ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k); - } - for (int k = 3; k < ewah.length; k += 3) { - ewah[k].flip(13L, (long) howmany / 2); - } - - RoaringBitmap answer = ewah[0]; - for (int k = 1; k < ewah.length; ++k) { - answer = RoaringBitmap.xor(answer, ewah[k]); - } - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]); - RoaringBitmap rxor = FastAggregation.xor(rb1, rb2); - RoaringBitmap answer2 = FastAggregation.xor(ewah); - RoaringBitmap answer3 = FastAggregation.horizontal_xor(ewah); - assertEquals(answer, answer2); - assertEquals(answer, answer3); - assertEquals(rxor, FastAggregation.priorityqueue_xor(rb1, rb2)); - } - } - - - @Test - public void testMassiveXOrBigInts() { - final int N = 128; - for (int howmany = 512; howmany <= 1000000; howmany *= 2) { - RoaringBitmap[] ewah = new RoaringBitmap[N]; - for (int k = 0; k < ewah.length; ++k) { - ewah[k] = new RoaringBitmap(); - } - for (int k = 0; k < howmany; ++k) { - ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k); - } - for (int k = 3; k < ewah.length; k += 3) { - ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2); - } - - RoaringBitmap answer = ewah[0]; - for (int k = 1; k < ewah.length; ++k) { - answer = RoaringBitmap.xor(answer, ewah[k]); - } - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]); - RoaringBitmap rxor = FastAggregation.xor(rb1, rb2); - RoaringBitmap answer2 = FastAggregation.xor(ewah); - RoaringBitmap answer3 = FastAggregation.horizontal_xor(ewah); - assertEquals(answer, answer2); - assertEquals(answer, answer3); - assertEquals(rxor, FastAggregation.priorityqueue_xor(rb1, rb2)); - } - } - - @Test - public void testOr001() { - int[] array1 = {22871, 22873, 22876, 22880, 22886, 22889, 22893, 22897, 22901, 22905, 22910, - 22915, 22919, 22927, 22934, 22940, 24750, 38579, 48470, 50533, 53256, 53717, 53752, 53802, - 53938, 54727, 54865, 55202, 55815, 55822, 55940, 56711, 56977, 57122, 59933, 60037, 60402, - 60520, 60853, 61163, 61340, 61549, 61632, 62097, 62373, 62961, 62993, 63031, 63075, 64209, - 64644, 64762, 64893, 64927, 64997, 65117, 65128, 65173, 65201, 65472, 65536, 65622, 66092, - 66162, 66302, 66381, 66551, 103979, 104644, 106866, 117285, 123372, 127548, 132167, 132168, - 136283, 136433, 137661, 138019, 138239, 138380, 138816, 138916, 138933, 139414, 140342, - 140914, 142751, 142994, 143895, 145081, 147331, 147686, 148021, 148375, 148587, 149114, - 149734, 152696, 153608, 154741, 154932, 155263, 157121, 158947, 159444, 161102, 161383, - 162735, 164298, 168043, 169398, 169536, 170419, 170846, 171153, 177016, 177471, 178305, - 178673, 183731, 183936, 184083, 184106, 185663, 188371, 189495, 189531, 196189, 198419, - 198758, 198796, 200645, 201137, 216865, 216936, 217770, 217810, 217836, 217909, 218569, - 218700, 218931, 219363, 220009, 225925, 234706, 241183, 241561, 242140, 242281, 245018, - 245056, 249935, 250442, 250615, 251696, 252825, 254178, 256788, 256906, 257289, 258833, - 260432, 260563, 260930, 262684, 262834, 263128, 265919, 268662, 269542, 270217, 271673, - 273776, 274560, 275649, 305458, 306241, 306550, 307580, 310891, 312701, 313514, 318134, - 319185, 320757, 321280, 322046, 322743, 323211, 324667, 325382, 326450, 327159, 328836, - 329075, 331179, 332836, 332997, 333071, 333205, 333488, 333595, 335045, 335803, 336417, - 336610, 338487, 339827, 339992, 346123, 348858, 351257, 351957, 353896, 354559, 357142, - 358253, 366662, 378768, 391984, 392282, 415077, 429446, 429449, 429452, 429453, 429476, - 429480, 429486, 429492, 429497, 429501, 429504, 429505, 429510, 429515, 429519, 429524, - 429530, 429533, 429541, 429546, 429553, 429554, 429564, 429572, 429577, 429579, 429586, - 429589, 429596, 429604, 429606, 429612, 429615, 429616, 429624, 429632, 429639, 429642, - 429646, 429651, 429656, 429664, 429670, 429674, 429678, 429681, 429686, 429695, 429701, - 429706, 429717, 429721, 429725, 429733, 429736, 429739, 429743, 429748, 429754, 429761, - 429767, 429772, 429780, 429791, 429792, 429793, 429794, 429795, 429817, 429822, 429823, - 429831, 429836, 429842, 429849, 429855, 429859, 429863, 429866, 429873, 429876, 429882, - 429885, 429900, 429903, 429913, 429921, 429923, 429927, 429932, 429939, 429947, 429950, - 429955, 429964, 429968, 429974, 429982, 429987, 429993, 429999, 430003, 430011, 430015, - 430023, 430028, 430033, 430039, 430044, 430048, 430053, 430057, 430059, 430063, 430068, - 430073, 430077, 430082, 430086, 430093, 430098, 430101, 430114, 430120, 430126, 430131, - 430135, 430139, 430144, 430149, 430155, 430157, 430167, 430175, 430181, 430186, 430194, - 430195, 430196, 430214, 430223, 430228, 430236, 430253, 430258, 430263, 430269, 430277, - 430284, 430288, 430293, 430297, 430303, 430309, 430316, 430321, 430332, 430338, 430343, - 430346, 430348, 430355, 430358, 430369, 430375, 430384, 430391, 430397, 430410, 430415, - 430420, 430424, 430430, 430435, 430437, 430445, 430449, 430461, 430467, 430473, 430482, - 430486, 430490, 430496, 430500, 430506, 430511, 430515, 430535, 430539, 430550, 430568, - 430575, 430581, 430588, 430591, 430596, 430605, 430612, 430617, 430625, 430629, 430633, - 430638, 430643, 430649, 430656, 430663, 430666, 430672, 430679, 430684, 430692, 430696, - 430700, 430707, 430716, 430723, 430728, 430733, 430745, 430751, 430755, 430759, 430767, - 430770, 430782, 430787, 430791, 430804, 430810, 430814, 430821, 430825, 430829, 430833, - 430838, 430844, 430849, 430852, 430859, 430864, 430867, 430870, 430877, 430881, 430887, - 430891, 430896, 430901, 430907, 430912, 430917, 430923, 430927, 430932, 430936, 430944, - 430947, 430953, 430959, 430967, 430971, 430979, 430985, 430989, 430993, 430997, 431003, - 431006, 431015, 431021, 431022, 431033, 431039, 431046, 431050, 431054, 431059, 431065, - 431069, 431074, 431081, 431085, 431092, 431097, 431104, 431110, 431120, 431125, 431133, - 431138, 431142, 431147, 431157, 431164, 431171, 431175, 431180, 431186, 431190, 431195, - 431207, 431213, 431218, 431220, 431224, 431228, 431233, 431235, 431240, 431245, 431251, - 431259, 431264, 431271, 431272, 431280, 431287, 431294, 431299, 431307, 431315, 431319, - 431324, 431330, 431334, 431339, 431345, 431352, 431356, 431363, 431375, 431379, 431383, - 431388, 431393, 431398, 431405, 431409, 431416, 431422, 431426, 431433, 431438, 431444, - 431451, 431455, 431464, 431469, 431472, 431477, 431483, 431490, 431496, 431506, 431513, - 431516, 431521, 431526, 431534, 431536, 431545, 431550, 431559, 431564, 431571, 431573, - 431579, 431584, 431587, 431592, 431604, 431614, 431624, 431629, 431634, 431638, 431645, - 431651, 431659, 431663, 431674, 431678, 431684, 431692, 431696, 431700, 431706, 431712, - 431719, 431723, 431729, 431736, 431741, 431747, 431755, 431758, 431762, 431767, 431777, - 431782, 431787, 431791, 431796, 431799, 431805, 431809, 431814, 431819, 431823, 431828, - 431832, 431838, 431842, 431849, 431853, 431858, 431862, 431866, 431869, 431874, 431881, - 431887, 431894, 431900, 431906, 431912, 431917, 431925, 431931, 431936, 431943, 431948, - 431956, 431958, 431964, 431971, 431976, 431981, 431988, 431994, 431998, 432008, 432012, - 432024, 432029, 432033, 432038, 432045, 432048, 432058, 432062, 432066, 432070, 432076, - 432077, 432087, 432093, 432098, 432104, 432114, 432123, 432128, 432133, 432139, 432145, - 432151, 432161, 432168, 432177, 432181, 432188, 432189, 432203, 432209, 432216, 432222, - 432227, 432232, 432242, 432247, 432256, 432259, 432264, 432269, 432271, 432277, 432286, - 432294, 432297, 432302, 432308, 432313, 432319, 432326, 432331, 432337, 432345, 432349, - 432353, 432356, 432361, 432366, 432370, 432378, 432384, 432390, 432391, 432397, 432400, - 432403, 432408, 432413, 432419, 432422, 432427, 432433, 432440, 432443, 432450, 432455, - 432460, 432466, 432467, 432481, 432489, 432493, 432498, 432504, 432511, 432513, 432517, - 432525, 432531, 432537, 432544, 432546, 432555, 432561, 432565, 432569, 432574, 432579, - 432586, 432590, 432597, 432605, 432611, 432619, 432626, 432630, 432637, 432644, 432646, - 432653, 432654, 432664, 432670, 432674, 432679, 432682, 432687, 432694, 432706, 432711, - 432714, 432721, 432726, 432732, 432741, 432747, 432753, 432755, 432761, 432764, 432768, - 432774, 432779, 432784, 432792, 432798, 432801, 432808, 432815, 432823, 432825, 432833, - 432838, 432842, 432847, 432853, 432861, 432866, 432873, 432879, 432889, 432895, 432901, - 432906, 432913, 432917, 432920, 432926, 432935, 432940, 432949, 432953, 432958, 432960, - 432966, 432967, 432968, 432969, 432970, 432971, 432972, 432996, 432999, 433004, 433010, - 433020, 433026, 433029, 433033, 433042, 433045, 433050, 433054, 433058, 433062, 433065, - 433070, 433076, 433086, 433095, 433101, 433102, 433116, 433122, 433129, 433132, 433140, - 433146, 433151, 433157, 433163, 433169, 433176, 433181, 433188, 433198, 433204, 433219, - 433229, 433236, 433240, 433246, 433250, 433259, 433263, 433274, 433277, 433282, 433286, - 433291, 433295, 433299, 433306, 433316, 433318, 433322, 433327, 433335, 433342, 433348, - 433351, 433359, 433362, 433367, 433371, 433377, 433384, 433393, 433398, 433403, 433407, - 433411, 433425, 433430, 433437, 433441, 433445, 433452, 433453, 433458, 433462, 433469, - 433473, 433478, 433484, 433490, 433495, 433501, 433506, 433514, 433517, 433521, 433527, - 433534, 433544, 433549, 433552, 433561, 433565, 433569, 433576, 433585, 433589, 433594, - 433597, 433600, 433603, 433606, 433613, 433619, 433623, 433627, 433639, 433643, 433648, - 433654, 433658, 433665, 433673, 433678, 433681, 433689, 433696, 433704, 433709, 433716, - 433721, 433725, 433729, 433734, 433738, 433744, 433749, 433755, 433760, 433766, 433771, - 433776, 433781, 433785, 433790, 433798, 433803, 433810, 433814, 433817, 433822, 433828, - 433833, 433837, 433843, 433849, 433852, 433858, 433863, 433871, 433875, 433881, 433883, - 433884, 433897, 433903, 433909, 433913, 433921, 433926, 433932, 433936, 433942, 433946, - 433951, 433959, 433965, 433976, 433981, 433989, 433996, 434004, 434011, 434013, 434019, - 434023, 434029, 434036, 434041, 434048, 434050, 434056, 434060, 434068, 434074, 434079, - 434085, 434091, 434096, 434100, 434105, 434110, 434119, 434123, 434129, 434133, 434139, - 434146, 434150, 434156, 434161, 434168, 434173, 434183, 434188, 434193, 434200, 434208, - 434213, 434219, 434223, 434229, 434235, 434241, 434247, 434258, 434262, 434269, 434275, - 434282, 434287, 434291, 434296, 434303, 434308, 434313, 434316, 434323, 434327, 434335, - 434342, 434349, 434353, 434360, 434366, 434372, 434373, 434381, 434387, 434392, 434397, - 434401, 434403, 434409, 434414, 434420, 434427, 434433, 434440, 434445, 434449, 434454, - 434460, 434467, 434473, 434479, 434481, 434490, 434494, 434501, 434505, 434510, 434517, - 434526, 434537, 434542, 434548, 434553, 434558, 434563, 434569, 434574, 434580, 434586, - 434588, 434595, 434603, 434606, 434617, 434620, 434626, 434630, 434638, 434644, 434647, - 434651, 434658, 434666, 434671, 434679, 434681, 434685, 434692, 434699, 434703, 434708, - 434713, 434720, 434723, 434729, 434734, 434738, 434742, 434746, 434753, 434762, 434766, - 434773, 434781, 434790, 434799, 434805, 434810, 434814, 434823, 434831, 434839, 434845, - 434850, 434856, 434859, 434863, 434869, 434870, 434882, 434890, 434896, 434899, 434906, - 434912, 434917, 434921, 434930, 434935, 434940, 434945, 434949, 434956, 434961, 434967, - 434977, 434982, 434987, 434992, 434995, 435002, 435005, 435009, 435016, 435021, 435025, - 435028, 435034, 435041, 435050, 435055, 435065, 435069, 435075, 435078, 435083, 435091, - 435097, 435102, 435105, 435107, 435113, 435118, 435124, 435131, 435141, 435144, 435150, - 435154, 435159, 435167, 435171, 435177, 435181, 435187, 435192, 435198, 435204, 435211, - 435212, 435221, 435228, 435231, 435237, 435244, 435246, 435254, 435258, 435264, 435275, - 435283, 435289, 435301, 435304, 435312, 435318, 435323, 435329, 435334, 435340, 435343, - 435347, 435351, 435358, 435363, 435368, 435375, 435382, 435388, 435391, 435396, 435399, - 435405, 435412, 435416, 435422, 435425, 435429, 435437, 435444, 435447, 435453, 435458, - 435470, 435477, 435486, 435491, 435497, 435500, 435511, 435516, 435520, 435526, 435533, - 435539, 435545, 435551, 435559, 435564, 435569, 435575, 435579, 435585, 435590, 435597, - 435599, 435600, 435610, 435616, 435618, 435623, 435628, 435636, 435643, 435649, 435654, - 435659, 435663, 435671, 435675, 435678, 435683, 435689, 435702, 435705, 435712, 435718, - 435749, 435755, 435759, 435764, 435771, 435775, 435780, 435785, 435791, 435794, 435802, - 435811, 435816, 435822, 435828, 435833, 435838, 435844, 435851, 435859, 435861, 435866, - 435869, 435876, 435882, 435890, 435897, 435900, 435908, 435913, 435923, 435929, 435934, - 435937, 435942, 435945, 435951, 435953, 435959, 435965, 435969, 435975, 435982, 435987, - 435992, 436000, 436008, 436013, 436017, 436022, 436027, 436033, 436038, 436043, 436048, - 436052, 436062, 436065, 436069, 436073, 436079, 436088, 436092, 436100, 436106, 436116, - 436123, 436127, 436133, 436139, 436147, 436153, 436159, 436165, 436172, 436179, 436184, - 436190, 436194, 436199, 436206, 436210, 436211, 436217, 436223, 436229, 436234, 436240, - 436245, 436253, 436258, 436262, 436268, 436273, 436282, 436287, 436294, 436303, 436306, - 436313, 436316, 436321, 436329, 436337, 436341, 436349, 436353, 436358, 436365, 436368, - 436373, 436378, 436387, 436391, 436396, 436401, 436408, 436412, 436420, 436423, 436428, - 436435, 436441, 436447, 436451, 436461, 436463, 436467, 436471, 436477, 436479, 436485, - 436489, 436494, 436502, 436509, 436512, 436518, 436529, 436538, 436543, 436552, 436553, - 436560, 436564, 436569, 436575, 436580, 436585, 436591, 436597, 436603, 436605, 436610, - 436616, 436619, 436628, 436633, 436637, 436640, 436644, 436649, 436653, 436659, 436666, - 436674, 436681, 436687, 436694, 436700, 436703, 436710, 436720, 436723, 436730, 436735, - 436742, 436748, 436756, 436761, 436766, 436772, 436778, 436783, 436787, 436792, 436799, - 436808, 436810, 436812, 436817, 436823, 436832, 436838, 436845, 436849, 436853, 436859, - 436865, 436872, 436878, 436882, 436885, 436891, 436898, 436903, 436910, 436911, 436922, - 436928, 436932, 436939, 436942, 436948, 436950, 436956, 436963, 436968, 436975, 436984, - 436988, 436994, 437003, 437009, 437013, 437020, 437023, 437028, 437033, 437043, 437053, - 437058, 437063, 437073, 437076, 437079, 437089, 437093, 437095, 437101, 437111, 437119, - 437121, 437127, 437135, 437140, 437147, 437151, 437155, 437160, 437165, 437171, 437173, - 437180, 437186, 437194, 437199, 437205, 437213, 437217, 437223, 437227, 437231, 437243, - 437250, 437256, 437261, 437267, 437271, 437277, 437284, 437289, 437295, 437300, 437304, - 437312, 437322, 437326, 437333, 437338, 437354, 437357, 437362, 437366, 437370, 437374, - 437380, 437386, 437391, 437395, 437399, 437404, 437412, 437416, 437419, 437427, 437432, - 437433, 437451, 437456, 437461, 437467, 437468, 437477, 437485, 437492, 437495, 437501, - 437502, 437506, 437513, 437524, 437526, 437539, 437544, 437552, 437558, 437562, 437568, - 437573, 437578, 437587, 437592, 437596, 437600, 437605, 437610, 437619, 437625, 437630, - 437631, 437639, 437647, 437648, 437655, 437661, 437667, 437672, 437676, 437680, 437687, - 437689, 437693, 437697, 437704, 437707, 437716, 437723, 437730, 437737, 437740, 437741, - 437757, 437763, 437771, 437778, 437784, 437789, 437793, 437800, 437804, 437811, 437812, - 437819, 437823, 437827, 437833, 437841, 437844, 437853, 437857, 437861, 437866, 437874, - 437881, 437886, 437892, 437901, 437902, 437909, 437914, 437922, 437928, 437934, 437939, - 437948, 437951, 437957, 437963, 437965, 437971, 437980, 437985, 437990, 437996, 438002, - 438008, 438013, 438017, 438025, 438030, 438036, 438041, 438052, 438060, 438065, 438072, - 438073, 438079, 438084, 438091, 438097, 438099, 438107, 438111, 438119, 438125, 438136, - 438144, 438148, 438153, 438158, 438164, 438166, 438173, 438176, 438183, 438184, 438192, - 438198, 438204, 438209, 438216, 438228, 438231, 438237, 438243, 438248, 438257, 438267, - 438269, 438274, 438282, 438287, 438295, 438301, 438306, 438313, 438318, 438323, 438328, - 438335, 438339, 438346, 438352, 438357, 438363, 438370, 438374, 438380, 438384, 438388, - 438394, 438399, 438404, 438409, 438413, 438422, 438428, 438436, 438439, 438444, 438453, - 438461, 438471, 438477, 438483, 438491, 438503, 438505, 438511, 438518, 438527, 438531, - 438541, 438546, 438552, 438556, 438562, 438566, 438570, 438580, 438585, 438593, 438595, - 438603, 438605, 438607, 438614, 438619, 438626, 438631, 438634, 438641, 438646, 438652, - 438657, 438663, 438664, 438665, 438673, 438677, 438682, 438692, 438700, 438706, 438708, - 438715, 438723, 438727, 438737, 438742, 438753, 438760, 438764, 438771, 438775, 438780, - 438783, 438789, 438797, 438806, 438810, 438815, 438832, 438837, 438841, 438845, 438852, - 438860, 438865, 438873, 438883, 438884, 438896, 438908, 438912, 438920, 438924, 438927, - 438934, 438936, 438940, 438946, 438953, 438961, 438968, 438976, 438980, 438985, 438994, - 439006, 439011, 439017, 439021, 439027, 439032, 439036, 439043, 439047, 439055, 439059, - 439065, 439070, 439075, 439083, 439087, 439093, 439099, 439104, 439109, 439114, 439120, - 439123, 439128, 439130, 439134, 439139, 439147, 439157, 439162, 439167, 439172, 439178, - 439183, 439187, 439194, 439201, 439205, 439210, 439216, 439222, 439225, 439231, 439235, - 439245, 439251, 439255, 439261, 439277, 439282, 439288, 439295, 439302, 439308, 439309, - 439314, 439320, 439328, 439332, 439339, 439345, 439350, 439354, 439359, 439365, 439372, - 439377, 439379, 439386, 439391, 439404, 439410, 439416, 439419, 439425, 439430, 439434, - 439438, 439455, 439461, 439465, 439472, 439476, 439482, 439488, 439493, 439496, 439506, - 439510, 439516, 439521, 439527, 439536, 439543, 439551, 439554, 439557, 439564, 439569, - 439574, 439577, 439584, 439588, 439593, 439597, 439602, 439607, 439613, 439618, 439624, - 439625, 439633, 439638, 439641, 439645, 439650, 439655, 439659, 439669, 439670, 439671, - 439682, 439692, 439696, 439701, 439709, 439718, 439725, 439730, 439733, 439739, 439745, - 439757, 439764, 439768, 439771, 439778, 439783, 439788, 439796, 439805, 439811, 439815, - 439820, 439827, 439830, 439840, 439846, 439850, 439854, 439865, 439873, 439879, 439886, - 439891, 439898, 439903, 439909, 439917, 439925, 439928, 439933, 439938, 439944, 439948, - 439955, 439959, 439965, 439969, 439974, 439988, 439989, 440005, 440008, 440011, 440015, - 440020, 440026, 440030, 440035, 440043, 440044, 440055, 440060, 440078, 440091, 440096, - 440101, 440106, 440111, 440116, 440120, 440134, 440139, 440143, 440149, 440157, 440163, - 440167, 440171, 440179, 440187, 440191, 440196, 440201, 440207, 440213, 440218, 440223, - 440228, 440233, 440239, 440244, 440249, 440256, 440262, 440268, 440274, 440277, 440282, - 440289, 440295, 440307, 440311, 440315, 440321, 440327, 440331, 440336, 440341, 440346, - 440355, 440361, 440368, 440375, 440379, 440388, 440394, 440399, 440402, 440410, 440413, - 440421, 440427, 440431, 440435, 440440, 440446, 440454, 440461, 440467, 440476, 440481, - 440486, 440490, 440495, 440500, 440506, 440512, 440523, 440529, 440533, 440539, 440546, - 440552, 440560, 440568, 440578, 440584, 440590, 440594, 440598, 440606, 440612, 440620, - 440623, 440629, 440634, 440641, 440647, 440651, 440655, 440663, 440669, 440674, 440682, - 440689, 440694, 440698, 440702, 440706, 440713, 440719, 440727, 440733, 440737, 440743, - 440747, 440753, 440760, 440767, 440772, 440779, 440783, 440789, 440792, 440798, 440806, - 440808, 440812, 440819, 440823, 440826, 440830, 440835, 440840, 440845, 440853, 440856, - 440861, 440867, 440872, 440876, 440882, 440888, 440893, 440903, 440910, 440915, 440921, - 440927, 440933, 440938, 440945, 440950, 440958, 440966, 440969, 440973, 440977, 440983, - 440987, 440992, 440996, 441005, 441008, 441013, 441028, 441035, 441042, 441047, 441052, - 441056, 441061, 441068, 441075, 441080, 441087, 441094, 441097, 441106, 441111, 441115, - 441121, 441125, 441132, 441136, 441143, 441150, 441157, 441161, 441167, 441171, 441175, - 441179, 441185, 441193, 441196, 441200, 441204, 441210, 441216, 441223, 441226, 441234, - 441238, 441243, 441253, 441260, 441268, 441276, 441287, 441294, 441297, 441306, 441313, - 441315, 441323, 441332, 441339, 441346, 441353, 441358, 441362, 441368, 441373, 441378, - 441382, 441390, 441394, 441399, 441404, 441411, 441416, 441420, 441427, 441432, 441440, - 441445, 441448, 441453, 441456, 441461, 441467, 441473, 441479, 441484, 441491, 441497, - 441506, 441509, 441515, 441521, 441526, 441531, 441535, 441542, 441547, 441551, 441555, - 441559, 441565, 441569, 441574, 441579, 441596, 441599, 441605, 441610, 441617, 441619, - 441623, 441628, 441630, 441636, 441637, 441651, 441652, 441662, 441664, 441667, 441671, - 441681, 441684, 441689, 441693, 441701, 441705, 441710, 441718, 441720, 441726, 441740, - 441746, 441757, 441759, 441766, 441773, 441775, 441780, 441793, 441794, 441799, 441807, - 441817, 441822, 441828, 441831, 441834, 441838, 441845, 441853, 441857, 441863, 441866, - 441872, 441880, 441883, 441886, 441891, 441895, 441900, 441910, 441915, 441921, 441928, - 441934, 441939, 441945, 441947, 441952, 441957, 441964, 441971, 441974, 441980, 441985, - 441990, 441994, 441998, 442002, 442007, 442010, 442017, 442019, 442027, 442043, 442046, - 442054, 442060, 442067, 442074, 442076, 442081, 442086, 442093, 442099, 442103, 442108, - 442112, 442120, 442131, 442135, 442139, 442144, 442148, 442156, 442161, 442165, 442170, - 442181, 442186, 442192, 442197, 442203, 442220, 442226, 442233, 442239, 442245, 442249, - 442254, 442259, 442267, 442275, 442281, 442284, 442287, 442292, 442299, 442308, 442314, - 442318, 442325, 442332, 442333, 442334, 442346, 442351, 442354, 442358, 442364, 442370, - 442372, 442377, 442381, 442389, 442397, 442402, 442409, 442415, 442419, 442424, 442430, - 442438, 442443, 442451, 442459, 442470, 442473, 442482, 442490, 442496, 442501, 442506, - 442514, 442520, 442524, 442530, 442534, 442541, 442546, 442549, 442554, 442558, 442563, - 442573, 442586, 442591, 442595, 442600, 442607, 442613, 442618, 442624, 442628, 442632, - 442640, 442647, 442651, 442657, 442666, 442674, 442679, 442682, 442686, 442692, 442699, - 442705, 442714, 442718, 442722, 442729, 442734, 442739, 442748, 442751, 442754, 442757, - 442765, 442770, 442778, 442783, 442792, 442798, 442802, 442813, 442820, 442829, 442833, - 442841, 442845, 442851, 442857, 442860, 442865, 442871, 442877, 442882, 442886, 442892, - 442898, 442904, 442906, 442911, 442915, 442922, 442929, 442934, 442940, 442944, 442946, - 442952, 442956, 442963, 442971, 442973, 442979, 442985, 442997, 443001, 443006, 443017, - 443019, 443024, 443027, 443036, 443046, 443050, 443057, 443066, 443069, 443078, 443083, - 443089, 443093, 443100, 443104, 443109, 443118, 443126, 443134, 443141, 443146, 443151, - 443158, 443164, 443169, 443174, 443179, 443182, 443189, 443195, 443198, 443206, 443211, - 443213, 443214, 443222, 443224, 443228, 443235, 443240, 443246, 443255, 443259, 443269, - 443270, 443277, 443285, 443291, 443299, 443303, 443311, 443313, 443319, 443322, 443328, - 443338, 443342, 443350, 443351, 443356, 443362, 443365, 443368, 443371, 443375, 443378, - 443384, 443388, 443391, 443397, 443404, 443412, 443416, 443421, 443424, 443428, 443433, - 443438, 443442, 443449, 443462, 443463, 443470, 443474, 443482, 443490, 443495, 443499, - 443506, 443519, 443523, 443527, 443533, 443540, 443548, 443550, 443556, 443559, 443564, - 443568, 443574, 443582, 443589, 443594, 443596, 443602, 443610, 443612, 443616, 443620, - 443625, 443631, 443638, 443643, 443649, 443656, 443660, 443669, 443672, 443680, 443691, - 443695, 443699, 443706, 443710, 443714, 443718, 443721, 443726, 443734, 443739, 443745, - 443752, 443758, 443765, 443771, 443774, 443781, 443786, 443789, 443793, 443797, 443802, - 443811, 443812, 443820, 443829, 443832, 443838, 443847, 443851, 443856, 443857, 443864, - 443871, 443877, 443886, 443892, 443896, 443903, 443909, 443913, 443920, 443925, 443930, - 443935, 443942, 443946, 443954, 443963, 443966, 443969, 443975, 443979, 443982, 443988, - 443996, 443999, 444003, 444007, 444012, 444019, 444026, 444030, 444040, 444049, 444056, - 444060, 444064, 444069, 444073, 444075, 444078, 444083, 444091, 444098, 444103, 444111, - 444121, 444124, 444130, 444136, 444140, 444145, 444150, 444156, 444162, 444168, 444172, - 444179, 444182, 444186, 444189, 444193, 444198, 444203, 444208, 444212, 444218, 444225, - 444231, 444234, 444240, 444246, 444258, 444265, 444273, 444277, 444281, 444288, 444292, - 444298, 444301, 444309, 444314, 444319, 444327, 444332, 444338, 444349, 444354, 444359, - 444364, 444374, 444377, 444381, 444386, 444388, 444394, 444401, 444406, 444417, 444422, - 444429, 444438, 444439, 444448, 444449, 444456, 444461, 444467, 444473, 444480, 444486, - 444490, 444495, 444500, 444503, 444508, 444514, 444518, 444525, 444528, 444535, 444540, - 444544, 444550, 444556, 444563, 444570, 444576, 444580, 444583, 444587, 444591, 444599, - 444605, 444608, 444612, 444619, 444629, 444635, 444643, 444646, 444652, 444660, 444671, - 444676, 444681, 444686, 444690, 444696, 444703, 444710, 444711, 444720, 444723, 444734, - 444742, 444752, 444758, 444763, 444767, 444770, 444774, 444786, 444789, 444794, 444800, - 444809, 444818, 444822, 444830, 444836, 444841, 444846, 444853, 444859, 444866, 444873, - 444878, 444885, 444890, 444896, 444904, 444907, 444914, 444922, 444924, 444931, 446357, - 488475, 495304, 496119, 497438, 498593, 498603, 498917, 499048, 499713, 500776, 501348, - 503424, 508844, 518359, 519305, 519446, 523627, 523776, 523878, 523902, 524135, 524329, - 524515, 524611, 524686, 524798, 524852, 525209, 525700, 525913, 525954, 526158, 526332, - 526356, 536810, 537279, 563933, 578719, 579248, 579791, 584191, 591485, 592871, 613176, - 615012, 616428, 619153, 636103, 640708, 643141, 645080, 646349, 647043, 649345, 651085, - 652849, 653092, 653169, 653227, 653586, 655241, 656093, 658355, 658564, 659381, 659518, - 690513, 693218, 693746, 694340, 694842, 695155, 695563, 695776, 696380, 697608, 697797, - 698222, 698835, 699307, 700154, 700203, 700235, 700404, 700806, 700900, 701796, 702155, - 702956, 702998, 705105, 705377, 705631, 708650, 709265, 709787, 725122, 735376, 737115, - 737174, 738005, 741377, 741986, 746045, 746404, 746590, 748212, 753574, 754379, 764728, - 765776, 766863, 769126, 782626, 782723, 783529, 786875, 787544, 807281, 811132, 821933, - 822194, 829768, 830997, 831095, 832481, 834082, 844664, 845574, 845764, 846820, 849481, - 855607, 857775, 872350, 876126, 902029, 903509, 904449, 904469, 905915, 910463, 911856, - 924365, 928664, 929314, 929606, 929983, 930478, 933195, 933819, 935628, 935911, 935922, - 936002, 937668, 941895, 942677, 943721, 944661, 944980, 945121, 945268, 945360, 950756, - 951007, 959993, 960787, 961048, 961084, 961238, 961589, 962000, 962797, 962827, 962910, - 963788, 964272, 964343, 964431, 964573, 964949, 965017, 965036, 965041, 965598, 965674, - 965957, 966014, 966032, 966092, 966144, 966226, 966234, 966265, 966291, 978103, 980858, - 987212, 987458, 987498, 988368, 988513, 988939, 990571, 993183, 1005493, 1007972, 1008230, - 1009675, 1010075, 1010685, 1011441, 1011828, 1012269, 1012310, 1013612, 1013907, 1014379, - 1018659, 1018923, 1022035, 1024567, 1024568, 1025024, 1026699, 1027212, 1027840, 1029108, - 1031846, 1032670, 1032970, 1034016, 1039255, 1040626, 1040796, 1043457, 1043632, 1051053, - 1052581, 1091611, 1092316, 1092564, 1092634, 1096386, 1096820, 1098606, 1104201, 1107101, - 1110019, 1111384, 1111707, 1128990, 1129111, 1129147, 1129160, 1129367, 1129408, 1129508, - 1129577, 1129699, 1129750, 1129840, 1129951, 1129988, 1130041, 1130139, 1130177, 1130241, - 1130248, 1130268, 1130276, 1130367, 1130540, 1130562, 1130636, 1130637, 1130662, 1130716, - 1131139, 1131218, 1131250, 1131454, 1131541, 1131775, 1132208, 1132280, 1132901, 1133264, - 1133474, 1133475, 1133764, 1133841, 1133988, 1134290, 1134533, 1134553, 1134614, 1134667, - 1134710, 1134861, 1134896, 1135008, 1135178, 1135544, 1135551, 1135573, 1136260, 1136385, - 1136458, 1136782, 1136960, 1137342, 1137713, 1137824, 1138160, 1138291, 1138340, 1138457, - 1138468, 1138516, 1138526, 1138610, 1138648, 1138700, 1138801, 1138869, 1138999, 1139010, - 1139102, 1139114, 1139145, 1139302, 1139322, 1139417, 1139496, 1139581, 1139668, 1139852, - 1139930, 1139958, 1140325, 1140616, 1140811, 1140861, 1141056, 1141197, 1141311, 1141346, - 1141551, 1141666, 1141735, 1141786, 1141895, 1142017, 1142228, 1142242, 1142415, 1142484, - 1142579, 1142599, 1142867, 1142929, 1143057, 1143132, 1143191, 1143203, 1143293, 1143476, - 1143860, 1143997, 1144044, 1144321, 1144338, 1144459, 1144548, 1144564, 1144588, 1144592, - 1144606, 1144623, 1144718, 1144792, 1144906, 1144997, 1145007, 1145082, 1145274, 1145380, - 1145430, 1145584, 1145731, 1145778, 1145869, 1145914, 1145925, 1146025, 1146158, 1146212, - 1146223, 1146448, 1146594, 1146663, 1146761, 1146803, 1146826, 1146833, 1146898, 1147078, - 1147099, 1147330, 1147382, 1147424, 1147431, 1147472, 1147545, 1147592, 1147627, 1147657, - 1147742, 1148005, 1148699, 1155013, 1155166, 1155915, 1178902, 1179255, 1180871, 1184802, - 1187587, 1190670, 1198632, 1198646, 1198832, 1199211, 1199259, 1199330, 1200318, 1200824, - 1200959, 1201200, 1202513, 1210077, 1210208, 1210296, 1211774, 1211775, 1211776, 1211777, - 1212528, 1212529, 1212843, 1216377, 1219904, 1220650, 1232492, 1235492, 1243381, 1243807, - 1267467, 1267561, 1267615, 1267691, 1267708, 1267731, 1267797, 1273165, 1278015, 1278076, - 1278615, 1279032, 1279185, 1279756, 1281009, 1281074, 1282368, 1284002, 1284572, 1285041, - 1285278, 1285788, 1285969, 1286573, 1286679, 1287001, 1287466, 1287714, 1287819, 1288542, - 1288897, 1289486, 1290086, 1290286, 1291047, 1291363, 1291498, 1291749, 1291853, 1292129, - 1292571, 1292828, 1292855, 1292859, 1292892, 1292893, 1292909, 1292910, 1292956, 1292957, - 1292985, 1293133, 1293185, 1293926, 1294446, 1294490, 1294571, 1294966, 1295003, 1295395, - 1295491, 1296604, 1298327, 1298527, 1298685, 1300235, 1300501, 1301193, 1301345, 1301536, - 1301908, 1301969, 1301988, 1302146, 1302158, 1302810, 1303060, 1303244, 1303275, 1303487, - 1303721, 1303831, 1303943, 1304875, 1305210, 1305677, 1305687, 1306397, 1306865, 1307044, - 1307745, 1307926, 1308080, 1308680, 1309204, 1309475, 1310596, 1312574, 1313313, 1313764, - 1313792, 1313963, 1314093, 1314284, 1314743, 1315154, 1315292, 1315503, 1315994, 1316517, - 1316872, 1316909, 1317089, 1317327, 1318223, 1319657, 1321070, 1321083, 1321495, 1321517, - 1322195, 1322221, 1322293, 1322330, 1322471, 1322496, 1322569, 1322634, 1322716, 1322859, - 1323066, 1323356, 1323530, 1323539, 1323614, 1323868, 1323925, 1328650, 1329210, 1332937, - 1333431, 1335482, 1338092, 1342268, 1345890, 1346245, 1346532, 1346613, 1346783, 1347371, - 1347858, 1348077, 1348468, 1349166, 1349298, 1349335, 1350775, 1350809, 1351329, 1352877}; - int[] array2 = {14402, 14403, 14404, 14405, 14406, 14407, 23246, 23247, 23248, 23249, 23250, - 23936, 23937, 23938, 23939, 23940, 23941, 23942, 29721, 29722, 29723, 29724, 29725, 30226, - 30227, 30228, 30229, 30230, 32141, 32142, 32143, 47737, 47738, 47739, 47740, 47741, 47742, - 47743, 47744, 47745, 47746, 47747, 47748, 47749, 47750, 47751, 47752, 68770, 68771, 68772, - 68773, 68774, 68775, 68776, 68777, 68778, 68779, 68780, 72301, 72302, 83071, 83072, 83073, - 83074, 85302, 85303, 85304, 85305, 85306, 85307, 85308, 85309, 85310, 85311, 85312, 85313, - 85314, 85315, 85316, 97108, 97109, 97110, 97111, 103442, 103443, 103444, 103445, 103446, - 103447, 103448, 103449, 103450, 103451, 103452, 103453, 103454, 103455, 103456, 103457, - 103458, 103459, 103460, 103461, 103462, 103463, 103464, 103465, 103466, 103467, 103468, - 103469, 128488, 128489, 128490, 128491, 128492, 128493, 135003, 135004, 135005, 135006, - 135007, 135008, 135009, 135010, 135011, 135012, 135013, 135014, 140363, 140364, 140365, - 140366, 140367, 140368, 140369, 140370, 140371, 140372, 149844, 149845, 149846, 149847, - 149848, 149849, 149850, 149851, 149852, 149853, 149854, 149855, 149856, 149857, 149858, - 149859, 149860, 149861, 149862, 149863, 149864, 172805, 172806, 172807, 172808, 172809, - 172810, 172811, 172812, 172813, 172814, 172815, 172816, 172817, 172818, 172819, 172820, - 172821, 172822, 172823, 172824, 172825, 172826, 172827, 172828, 172829, 172830, 172831, - 172832, 172833, 172834, 172835, 172836, 172837, 172838, 172839, 172840, 172841, 172842, - 172843, 172844, 172845, 172846, 172847, 172848, 172849, 172850, 172851, 172852, 172853, - 172854, 172855, 172856, 172857, 172858, 172859, 172860, 172861, 172862, 172863, 172864, - 172865, 172866, 172867, 172868, 172869, 172870, 172871, 202530, 202531, 202532, 209488, - 209489, 209490, 209491, 209492, 209493, 209494, 209495, 209496, 209497, 209498, 209499, - 209500, 209501, 209502, 209503, 209504, 209505, 209506, 225554, 225555, 225556, 225557, - 225558, 225559, 225560, 225561, 225562, 225563, 225564, 225565, 225566, 225567, 225568, - 225569, 225570, 225571, 225572, 225573, 225574, 225575, 225576, 225577, 225578, 225579, - 225580, 225581, 227917, 227918, 227919, 227920, 227921, 227922, 227923, 227924, 227925, - 227926, 227927, 227928, 227929, 227930, 227931, 227932, 227933, 227934, 227935, 227936, - 227937, 227938, 227939, 252773, 252774, 252775, 252776, 252777, 252778, 252779, 252780, - 252781, 252782, 252783, 252784, 252785, 252786, 252787, 252788, 252789, 252790, 252791, - 252792, 252793, 252794, 278695, 278696, 278697, 278698, 278699, 301237, 301238, 301239, - 301240, 301241, 301242, 301243, 301244, 301245, 301246, 301247, 301248, 301249, 301250, - 301251, 301252, 301253, 301254, 301255, 301256, 301257, 301258, 301259, 301260, 301261, - 301262, 301263, 301264, 301265, 320515, 320516, 320517, 320518, 320519, 320520, 320521, - 320522, 320523, 320524, 320525, 320526, 320527, 320528, 320529, 320530, 320531, 320532, - 320533, 320534, 320535, 320536, 320537, 320538, 320539, 320540, 320541, 320542, 320543, - 320544, 320545, 320546, 320547, 320548, 329641, 329642, 329643, 329644, 329645, 329646, - 329647, 329648, 329649, 329650, 329651, 329652, 329653, 329654, 329655, 329656, 329657, - 329658, 329659, 342703, 342704, 342705, 342706, 349520, 349521, 349522, 349523, 349524, - 349525, 349526, 349527, 349528, 349529, 349530, 362716, 362717, 362718, 362719, 362720, - 362721, 362722, 362723, 362724, 362725, 362726, 362727, 378643, 378644, 378645, 378646, - 390154, 390155, 390156, 390157, 390158, 390159, 390160, 390161, 390162, 390163, 390164, - 390165, 390166, 390167, 390168, 390169, 395108, 395109, 395110, 395111, 395112, 395113, - 395114, 395115, 403260, 403261, 403262, 403263, 403264, 403265, 403266, 403267, 403268, - 403269, 403270, 403271, 417315, 417316, 417317, 417318, 417319, 417320, 432653, 432654, - 432655, 432656, 432657, 432658, 432659, 432660, 432661, 432662, 432663, 432664, 432665, - 432666, 432667, 432668, 432669, 432670, 432671, 432672, 432673, 432674, 432675, 432676, - 432677, 432678, 449394, 449395, 449396, 449397, 449398, 459961, 459962, 459963, 459964, - 474537, 474538, 474539, 474540, 474541, 474542, 474543, 474544, 474545, 474546, 474547, - 474548, 474549, 474550, 474551, 474552, 474553, 474554, 474555, 474556, 474557, 474558, - 474559, 474560, 474561, 474562, 474563, 474564, 474565, 474566, 474567, 474568, 474569, - 474570, 474571, 474572, 474573, 474574, 474575, 474576, 474577, 474578, 474579, 474580, - 474581, 474582, 474583, 474584, 474585, 474586, 474587, 474588, 474589, 474590, 474591, - 474592, 474593, 474594, 474595, 474596, 474597, 483571, 483572, 483573, 483574, 483575, - 483576, 489641, 489642, 489643, 489644, 489645, 489646, 489647, 489648, 489649, 489650, - 489651, 491296, 491297, 491298, 495868, 495869, 495870, 502769, 502770, 502771, 502772, - 502773, 502774, 502775, 502776, 502777, 502778, 502779, 502780, 502781, 502782, 502783, - 513810, 513811, 513812, 513813, 513814, 513815, 513816, 513817, 513818, 513819, 513820, - 513821, 513822, 513823, 513824, 513825, 513826, 513827, 513828, 513829, 513830, 513831, - 513832, 517220, 517221, 517222, 517223, 517224, 517225, 517226, 517227, 519778, 519779, - 519780, 519781, 519782, 519783, 519784, 519785, 524240, 524241, 524242, 524243, 524244, - 524245, 524246, 524247, 524248, 524249, 527255, 527256, 527257, 527258, 527259, 533697, - 533698, 533699, 533700, 533701, 533702, 533703, 533704, 533705, 533706, 533707, 533708, - 533709, 539237, 539238, 539239, 539240, 539241, 539242, 539243, 562203, 562204, 562205, - 562206, 569773, 569774, 569775, 569776, 569777, 569778, 569779, 569780, 569781, 569782, - 569783, 569784, 569785, 569786, 569787, 569788, 569789, 569790, 569791, 569792, 569793, - 569794, 569795, 569796, 569797, 569798, 569799, 569800, 569801, 569802, 569803, 569804, - 569805, 569806, 569807, 569808, 569809, 569810, 569811, 569812, 569813, 569814, 569815, - 569816, 569817, 569818, 569819, 569820, 569821, 580161, 580162, 580163, 580164, 580165, - 580166, 580167, 580168, 580169, 580170, 580171, 580172, 580173, 580174, 580175, 580176, - 588299, 588300, 588301, 588302, 588303, 588304, 588305, 588306, 588307, 588308, 588309, - 588310, 588311, 588312, 588313, 588314, 588315, 588316, 588317, 588318, 588319, 588320, - 588321, 588322, 588323, 588324, 588325, 588326, 588327, 588328, 588329, 588330, 588331, - 588332, 588333, 588334, 588335, 608580, 608581, 608582, 608583, 608584, 608585, 608586, - 608587, 608588, 608589, 608590, 608591, 608592, 608593, 608594, 608595, 608596, 608597, - 608598, 608599, 608600, 608601, 608602, 608603, 608604, 608605, 618326, 618327, 618328, - 618329, 618330, 618331, 618332, 618333, 618334, 618335, 618336, 618337, 618338, 618339, - 618340, 618341, 618342, 618343, 618344, 618345, 618346, 618347, 618348, 618349, 626895, - 626896, 626897, 626898, 626899, 626900, 635313, 635314, 635315, 635316, 635317, 635318, - 635319, 635320, 635321, 635322, 635323, 635324, 635325, 635326, 635327, 635328, 635329, - 635330, 635331, 635332, 635333, 635334, 635335, 635336, 635337, 635338, 635339, 635340, - 635341, 635342, 635343, 635344, 635345, 635346, 635347, 635348, 635349, 635350, 635351, - 635352, 635353, 635354, 635355, 648087, 648088, 648089, 648090, 648091, 648092, 648093, - 648094, 648095, 648096, 648097, 648098, 648099, 648100, 648101, 648102, 648103, 648104, - 648105, 648106, 648107, 648108, 648109, 648110, 661574, 661575, 661576, 661577, 674566, - 674567, 674568, 674569, 674570, 674571, 674572, 674573, 674574, 674575, 674576, 674577, - 674578, 674579, 674580, 674581, 674582, 674583, 674584, 674585, 689328, 689329, 689330, - 689331, 689332, 689333, 689334, 689335, 689336, 689337, 697978, 697979, 697980, 697981, - 697982, 697983, 697984, 697985, 697986, 697987, 697988, 697989, 697990, 697991, 697992, - 697993, 697994, 726676, 726677, 726678, 726679, 726680, 726681, 782220, 782221, 782222, - 782223, 782224, 782225, 782226, 782227, 782228, 782229, 782230, 782231, 782232, 782233, - 782234, 782235, 782236, 782237, 782238, 782239, 797574, 797575, 797576, 797577, 797578, - 797579, 797580, 797581, 797582, 804283, 804284, 804285, 822332, 822333, 822334, 822335, - 822336, 831020, 831021, 831022, 831023, 831024, 831025, 831026, 831027, 831028, 831029, - 831030, 831031, 831032, 831033, 831034, 831035, 831036, 831037, 831038, 831039, 831040, - 847227, 847228, 847229, 847230, 847231, 847232, 847233, 847234, 847235, 847236, 847237, - 847238, 847239, 847240, 847241, 847242, 847243, 847244, 847245, 857616, 857617, 857618, - 857619, 857620, 857621, 857622, 857623, 857624, 857625, 867324, 867325, 867326, 867327, - 867328, 867329, 867330, 867331, 867332, 867333, 867334, 867335, 867336, 867337, 867338, - 867339, 877587, 877588, 877589, 877590, 877591, 877592, 877593, 877594, 877595, 877596, - 877597, 877598, 877599, 877600, 877601, 877602, 877603, 877604, 877605, 877606, 877607, - 877608, 877609, 877610, 877611, 877612, 877613, 877614, 877615, 896235, 896236, 896237, - 896238, 896239, 896240, 916629, 916630, 916631, 916632, 929361, 929362, 929363, 929364, - 929365, 929366, 929367, 929368, 929369, 929370, 929371, 948695, 948696, 948697, 948698, - 948699, 948700, 948701, 948702, 949573, 949574, 957768, 957769, 957770, 957771, 957772, - 957773, 957774, 957775, 961032, 961033, 961034, 961035, 987440, 987441, 987442, 987443, - 1001434, 1001435, 1001436, 1001437, 1001438, 1001439, 1001440, 1001441, 1001442, 1001443, - 1001444, 1001445, 1001446, 1001447, 1001448, 1001449, 1001450, 1001451, 1001452, 1001453, - 1001454, 1001455, 1001456, 1001457, 1001458, 1001459, 1001460, 1009985, 1009986, 1009987, - 1009988, 1009989, 1037191, 1037192, 1037193, 1037194, 1037195, 1037196, 1037197, 1037198, - 1037199, 1037200, 1037201, 1037202, 1037203, 1037204, 1053198, 1053199, 1053200, 1053201, - 1053202, 1053203, 1053204, 1053205, 1053206, 1053207, 1053208, 1053209, 1053210, 1053211, - 1053212, 1053213, 1053214, 1053215, 1053216, 1053217, 1053218, 1053219, 1053220, 1053221, - 1053222, 1053223, 1053224, 1084019, 1084020, 1084021, 1084022, 1084023, 1084024, 1084025, - 1088361, 1088362, 1088363, 1088364, 1088365, 1088366, 1089312, 1089313, 1089314, 1089315, - 1089316, 1089317, 1089318, 1092235, 1092236, 1092237, 1092238, 1092239, 1092240, 1092241, - 1092242, 1092243, 1092244, 1102836, 1102837, 1102838, 1102839, 1102840, 1102841, 1102842, - 1102843, 1102844, 1102845, 1102846, 1102847, 1108575, 1108576, 1108577, 1108578, 1108579, - 1108580, 1108581, 1108582, 1108583, 1108584, 1108585, 1108586, 1108587, 1108588, 1108589, - 1108590, 1108591, 1108592, 1108593, 1108594, 1108595, 1108596, 1108597, 1108598, 1134091, - 1134092, 1134093, 1134094, 1134095, 1134096, 1134097, 1134098, 1134099, 1134100, 1134101, - 1134102, 1134103, 1134104, 1134105, 1134106, 1134107, 1134108, 1134109, 1134110, 1134111, - 1134112, 1134113, 1134114, 1134115, 1134116, 1134117, 1134118, 1134119, 1134120, 1134121, - 1134122, 1134123, 1134124, 1134125, 1134126, 1134127, 1134128, 1134129, 1151732, 1151733, - 1151734, 1151735, 1151736, 1151737, 1151738, 1151739, 1151740, 1151741, 1151742, 1151743, - 1151744, 1151745, 1151746, 1151747, 1199223, 1199224, 1199225, 1199226, 1203252, 1203253, - 1203254, 1203255, 1203256, 1203257, 1203258, 1203259, 1203260, 1217223, 1217224, 1217225, - 1217226, 1226505, 1226506, 1226507, 1226508, 1226509, 1226510, 1226511, 1226512, 1231411, - 1231412, 1231413, 1231414, 1231415, 1231416, 1231417, 1231418, 1231419, 1231420, 1231421, - 1231422, 1231423, 1243464, 1243465, 1243466, 1243467, 1243468, 1243469, 1243470, 1247919, - 1247920, 1247921, 1255972, 1255973, 1255974, 1255975, 1255976, 1255977, 1255978, 1255979, - 1255980, 1263675, 1263676, 1263677, 1263678, 1263679, 1277693, 1277694, 1277695, 1277696, - 1277697, 1277698, 1277699, 1277700, 1283492, 1283493, 1283494, 1283495, 1283496, 1283497, - 1283498, 1283499, 1283500, 1283501, 1283502, 1283503, 1283504, 1283505, 1283506, 1283507, - 1283508, 1283509, 1283510, 1283511, 1283512, 1283513, 1283514, 1325789, 1325790, 1325791, - 1325792, 1325793, 1325794, 1325795, 1325796, 1325797, 1325798, 1325799}; - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(array1); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(array2); - RoaringBitmap rrb1 = rb1.clone(); - RoaringBitmap rrb2 = rb2.clone(); - rrb1.runOptimize(); - rrb2.runOptimize(); - assertEquals(RoaringBitmap.or(rb1, rb2), RoaringBitmap.or(rrb1, rrb2)); - } - - @Test - public void testRandomLists() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]); - RoaringBitmap rbor = RoaringBitmap.or(rb1, rb2); - assertEquals(rbor, FastAggregation.horizontal_or(rb1, rb2)); - } - - @Test - public void testRank() { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k += 7) { - rb.add(k); - } - for (int k = 100000; k < 200000; k += 1000) { - rb.add(k); - } - for (int k = 0; k < 100000; ++k) { - assertEquals(1 + k / 7, rb.rank(k)); - } - for (int k = 100000; k < 200000; ++k) { - assertEquals(1 + 100000 / 7 + 1 + (k - 100000) / 1000, rb.rank(k)); - } - } - - @Test - public void testRankBigInts() { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k += 7) { - rb.add((1 << 31) + k); - } - for (int k = 100000; k < 200000; k += 1000) { - rb.add((1 << 31) + k); - } - for (int k = 0; k < 100000; ++k) { - assertEquals(1 + k / 7, rb.rank((1 << 31) + k)); - } - for (int k = 100000; k < 200000; ++k) { - assertEquals(1 + 100000 / 7 + 1 + (k - 100000) / 1000, rb.rank((1 << 31) + k)); - } - } - - - @Test - public void testSelect() { - long w = ~0l; - for (int k = 0; k < 64; ++k) { - assertEquals(k, Util.select(w, k)); - } - for (int k = 0; k < 64; ++k) { - assertEquals(k, Util.select(1l << k, 0)); - } - for (int k = 1; k < 64; ++k) { - assertEquals(k, Util.select((1l << k) + 1, 1)); - } - assertEquals(0, Util.select(1, 0)); - assertEquals(0, Util.select(5, 0)); - assertEquals(2, Util.select(5, 1)); - for (int gap = 1; gap <= 1024; gap *= 2) { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k += gap) { - rb.add(k); - } - for (int k = 0; k < 100000 / gap; ++k) { - assertEquals(k * gap, rb.select(k)); - } - } - } - - - @Test - public void testSelectBigInts() { - for (int gap = 1; gap <= 1024; gap *= 2) { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k += gap) { - rb.add((1 << 31) + k); - } - for (int k = 0; k < 100000 / gap; ++k) { - assertEquals((1 << 31) + k * gap, rb.select(k)); - } - } - } - - - @Test - public void testSerialization() throws IOException, ClassNotFoundException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - final ObjectOutputStream oo = new ObjectOutputStream(bos); - rr.writeExternal(oo); - oo.close(); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); - rrback.readExternal(new ObjectInputStream(bis)); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - - @Test - public void testSerializationBigInts() throws IOException, ClassNotFoundException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add((1 << 31) + k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - final ObjectOutputStream oo = new ObjectOutputStream(bos); - rr.writeExternal(oo); - oo.close(); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); - rrback.readExternal(new ObjectInputStream(bis)); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - - @Test - public void testSerialization2() throws IOException, ClassNotFoundException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 200; k < 400; ++k) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - final ObjectOutputStream oo = new ObjectOutputStream(bos); - rr.writeExternal(oo); - oo.close(); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); - rrback.readExternal(new ObjectInputStream(bis)); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSerialization3() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add(k); - } - rr.add(1444000); - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray()))); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - // Deserialize DataInput with a buffer - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSerialization4() throws IOException, ClassNotFoundException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 1; k <= 10000000; k += 10) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray()))); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - // Deserialize DataInput with a buffer - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - - @Test - public void testSerializationDataInputWithBuffer() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - - @Test - public void testSerializationDataInputWithBufferBigInts() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add((1 << 31) + k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - - @Test - public void testSerializationDataInputWithBuffer2() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 200; k < 400; ++k) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSerializationDataInputWithBuffer3() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add(k); - } - rr.add(1444000); - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSerializationDataInputWithBuffer4() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 1; k <= 10000000; k += 10) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSerializationByteBuffer() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray()); - rrback.deserialize(buf); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - - @Test - public void testSerializationByteBufferBigInts() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add((1 << 31) + k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray()); - rrback.deserialize(buf); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - - @Test - public void testSerializationByteBuffer2() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 200; k < 400; ++k) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray()); - rrback.deserialize(buf); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSerializationByteBuffer3() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 65000; k < 2 * 65000; ++k) { - rr.add(k); - } - rr.add(1444000); - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray()); - rrback.deserialize(buf); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSerializationByteBuffer4() throws IOException { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 1; k <= 10000000; k += 10) { - rr.add(k); - } - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // Note: you could use a file output steam instead of - // ByteArrayOutputStream - int howmuch = rr.serializedSizeInBytes(); - final DataOutputStream oo = new DataOutputStream(bos); - rr.serialize(oo); - oo.close(); - assertEquals(howmuch, bos.toByteArray().length); - final RoaringBitmap rrback = new RoaringBitmap(); - final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray()); - rrback.deserialize(buf); - assertEquals(rr.getCardinality(), rrback.getCardinality()); - assertEquals(rr, rrback); - } - - @Test - public void testSetUtilIntersection() { - char[] data1 = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18}; - char[] data2 = {0, 3, 6, 9, 12, 15, 18}; - char[] result = new char[data1.length + data2.length]; - char[] expectedresult = {0, 6, 12, 18}; - int nl = Util.unsignedLocalIntersect2by2(data1, data1.length, data2, data2.length, result); - result = Arrays.copyOf(result, nl); - assertArrayEquals(expectedresult, result); - } - - @Test - public void testXORSimple() { - RoaringBitmap a = RoaringBitmap.bitmapOf(73647, 83469); - RoaringBitmap b = RoaringBitmap.bitmapOf(1, 2, 3, 5, 6, 8, 9, 10, 11, 13, 14, 16, 17, 18, 19, - 20, 21, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 39, 40, 41, 50, 51, 69, 79, 80, 81, - 88, 89, 172); - RoaringBitmap rxor = RoaringBitmap.xor(a, b); - RoaringBitmap ror = RoaringBitmap.or(a, b); - assertEquals(rxor, ror); - } - - @Test - public void trimArrayContainerCardinalityTest() { - final ArrayContainer ac = new ArrayContainer(); - ac.trim(); - for (char k = 0; k < 100; ++k) { - ac.add(k); - ac.trim(); - assertEquals(ac.getCardinality(), k + 1); - } - for (char k = 0; k < 100; ++k) { - ac.add(k); - ac.trim(); - assertEquals(ac.getCardinality(), 100); - } - } - - boolean validate(BitmapContainer bc, ArrayContainer ac) { - // Checking the cardinalities of each container - - if (bc.getCardinality() != ac.getCardinality()) { - System.out.println("cardinality differs"); - return false; - } - // Checking that the two containers contain the same values - int counter = 0; - - int i = bc.nextSetBit(0); - while (i >= 0) { - ++counter; - if (!ac.contains((char) i)) { - System.out.println("content differs"); - System.out.println(bc); - System.out.println(ac); - return false; - } - i = bc.nextSetBit(i + 1); - } - - // checking the cardinality of the BitmapContainer - return counter == bc.getCardinality(); - } - - @Test - public void trimTest() { - // with bitmap containing 4k containers - RoaringBitmap rb = new RoaringBitmap(); - for (int i = 0; i < 4000; i++) { - rb.add((1 << 16) * i); - } - - rb.trim(); - - int wastedBytes = 0; - final int javaReferenceSize = 4; // or 8 depending on factors - RoaringArray ra = rb.highLowContainer; - wastedBytes += Short.BYTES * (ra.keys.length - ra.size); - wastedBytes += javaReferenceSize * (ra.values.length - ra.size); - ContainerPointer cp = ra.getContainerPointer(); - while (cp.getContainer() != null) { - if (cp.isBitmapContainer()) { - ; //nothing wasted - } else if (cp.isRunContainer()) { - ; //not able to access information about wasted bytes - } else { - ArrayContainer ac = (ArrayContainer) cp.getContainer(); - wastedBytes += Short.BYTES * (ac.content.length - ac.cardinality); - } - cp.advance(); - } - assertEquals(0, wastedBytes); - } - - @Test - public void xorBigIntsTest() { - RoaringBitmap rb = new RoaringBitmap(); - RoaringBitmap rb2 = new RoaringBitmap(); - HashSet hs = new HashSet(); - - for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) { - hs.add(i); - rb.add(i); - } - for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) { - rb.add(i); - } - for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 5) { - rb.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 7) { - rb.add(i); - } - for (int i = (1 << 31) + 11 * 65536; i < (1 << 31) + 12 * 65536; i += 6) { - hs.add(i); - rb.add(i); - } - - for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) { - rb2.add(i); - } - for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 5) { - rb2.add(i); - } - for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 7) { - rb2.add(i); - } - for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 2) { - hs.add(i); - rb2.add(i); - } - - RoaringBitmap rbxor = RoaringBitmap.xor(rb, rb2); - - Object[] correct = hs.toArray(); - Arrays.sort(correct); - Integer[] resxor = ArrayUtils.toObject(rbxor.toArray()); - assertArrayEquals(correct, resxor); - } - - - @Test - public void XORtest() { - final RoaringBitmap rr = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr.add(k); - } - for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) { - rr.add(k); - } - for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) { - rr.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) { - rr.add(k); - } - for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) { - rr.add(k); - } - for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) { - rr.add(k); - } - - final RoaringBitmap rr2 = new RoaringBitmap(); - for (int k = 4000; k < 4256; ++k) { - rr2.add(k); - } - for (int k = 65536; k < 65536 + 4000; ++k) { - rr2.add(k); - } - for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) { - rr2.add(k); - } - for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) { - rr2.add(k); - } - for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) { - rr2.add(k); - } - final RoaringBitmap correct = RoaringBitmap.xor(rr, rr2); - rr.xor(rr2); - assertEquals(correct, rr); - } - - @Test - public void xortest1() { - final HashSet V1 = new HashSet(); - final HashSet V2 = new HashSet(); - - final RoaringBitmap rr = new RoaringBitmap(); - final RoaringBitmap rr2 = new RoaringBitmap(); - // For the first 65536: rr2 has a bitmap container, and rr has - // an array container. - // We will check the union between a BitmapCintainer and an - // arrayContainer - for (int k = 0; k < 4000; ++k) { - rr2.add(k); - if (k < 3500) { - V1.add(k); - } - } - for (int k = 3500; k < 4500; ++k) { - rr.add(k); - } - for (int k = 4000; k < 65000; ++k) { - rr2.add(k); - if (k >= 4500) { - V1.add(k); - } - } - - // In the second node of each roaring bitmap, we have two bitmap - // containers. - // So, we will check the union between two BitmapContainers - for (int k = 65536; k < 65536 + 30000; ++k) { - rr.add(k); - } - - for (int k = 65536; k < 65536 + 50000; ++k) { - rr2.add(k); - if (k >= 65536 + 30000) { - V1.add(k); - } - } - - // In the 3rd node of each Roaring Bitmap, we have an - // ArrayContainer. So, we will try the union between two - // ArrayContainers. - for (int k = 4 * 65535; k < 4 * 65535 + 1000; ++k) { - rr.add(k); - if (k >= 4 * 65535 + 800) { - V1.add(k); - } - } - - for (int k = 4 * 65535; k < 4 * 65535 + 800; ++k) { - rr2.add(k); - } - - // For the rest, we will check if the union will take them in - // the result - for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) { - rr.add(k); - V1.add(k); - } - - for (int k = 7 * 65535; k < 7 * 65535 + 2000; ++k) { - rr2.add(k); - V1.add(k); - } - - final RoaringBitmap rrxor = RoaringBitmap.xor(rr, rr2); - boolean valide = true; - - // Si tous les elements de rror sont dans V1 et que tous les - // elements de - // V1 sont dans rror(V2) - // alors V1 == rror - final Object[] tab = V1.toArray(); - final Vector vector = new Vector(); - for (Object aTab : tab) { - vector.add((Integer) aTab); - } - - for (final int i : rrxor.toArray()) { - if (!vector.contains(i)) { - valide = false; - } - V2.add(i); - } - for (int i = 0; i < V1.size(); i++) { - if (!V2.contains(vector.elementAt(i))) { - valide = false; - } - } - - assertTrue(valide); - } - - @Test - public void xortest4() { - final RoaringBitmap rb = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - - for (int i = 0; i < 200000; i += 4) { - rb2.add(i); - } - for (int i = 200000; i < 400000; i += 14) { - rb2.add(i); - } - final int rb2card = rb2.getCardinality(); - - // check or against an empty bitmap - final RoaringBitmap xorresult = RoaringBitmap.xor(rb, rb2); - final RoaringBitmap off = RoaringBitmap.or(rb2, rb); - assertEquals(xorresult, off); - - assertEquals(rb2card, xorresult.getCardinality()); - - for (int i = 500000; i < 600000; i += 14) { - rb.add(i); - } - for (int i = 200000; i < 400000; i += 3) { - rb2.add(i); - } - // check or against an empty bitmap - final RoaringBitmap xorresult2 = RoaringBitmap.xor(rb, rb2); - assertEquals(rb2card, xorresult.getCardinality()); - - assertEquals(rb2.getCardinality() + rb.getCardinality(), xorresult2.getCardinality()); - rb.xor(rb2); - assertEquals(xorresult2, rb); - - } - - - // is this better in testRange? - @Test - public void testRangedOr() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add(val1); - set1.add(val1); - - rb2.add(val2); - set2.add(val2); - } - Set unionSet = new TreeSet<>(); - unionSet.addAll(set1); - unionSet.addAll(set2); - for (int iter = 0; iter < NUM_ITER; iter++) { - int rangeStart = random.nextInt(length - 1); - // +1 to ensure rangeEnd >rangeStart, may - int rangeLength = random.nextInt(length - rangeStart) + 1; - int rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = rangeStart; i < rangeEnd; i++) { - if (unionSet.contains(i)) { - expectedResultSet.add(i); - } - } - List list = new ArrayList<>(); - list.add(rb1); - list.add(rb2); - RoaringBitmap result = RoaringBitmap.or(list.iterator(), (long) rangeStart, (long) rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - @Test - public void testRangedOrBigInts() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add((1 << 31) + val1); - set1.add((1 << 31) + val1); - - rb2.add((1 << 31) + val2); - set2.add((1 << 31) + val2); - } - Set unionSet = new TreeSet<>(); - unionSet.addAll(set1); - unionSet.addAll(set2); - for (int iter = 0; iter < NUM_ITER; iter++) { - long rangeStart1 = random.nextInt(length - 1); - long rangeStart = (1L << 31) + rangeStart1; - long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1; - long rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = (int) rangeStart; i < (int) rangeEnd; i++) { - if (unionSet.contains(i)) { - expectedResultSet.add(i); - } - } - List list = new ArrayList<>(); - list.add(rb1); - list.add(rb2); - RoaringBitmap result = RoaringBitmap.or(list.iterator(), rangeStart, rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - - @Test - public void testRangedAnd() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add(val1); - set1.add(val1); - - rb2.add(val2); - set2.add(val2); - } - Set intersectionSet = new TreeSet<>(set1); - intersectionSet.retainAll(set2); - for (int iter = 0; iter < NUM_ITER; iter++) { - int rangeStart = random.nextInt(length - 1); - // +1 to ensure rangeEnd >rangeStart, may - int rangeLength = random.nextInt(length - rangeStart) + 1; - int rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = rangeStart; i < rangeEnd; i++) { - if (intersectionSet.contains(i)) { - expectedResultSet.add(i); - } - } - List list = new ArrayList<>(); - list.add(rb1); - list.add(rb2); - RoaringBitmap result = RoaringBitmap.and(list.iterator(), (long) rangeStart, (long) rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - @Test - public void testRangedAndBigInts() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add((1 << 31) + val1); - set1.add((1 << 31) + val1); - - rb2.add((1 << 31) + val2); - set2.add((1 << 31) + val2); - } - Set intersectionSet = new TreeSet<>(set1); - intersectionSet.retainAll(set2); - for (int iter = 0; iter < NUM_ITER; iter++) { - long rangeStart1 = random.nextInt(length - 1); - long rangeStart = (1L << 31) + rangeStart1; - long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1; - long rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = (int) rangeStart; i < (int) rangeEnd; i++) { - if (intersectionSet.contains(i)) { - expectedResultSet.add(i); - } - } - List list = new ArrayList<>(); - list.add(rb1); - list.add(rb2); - RoaringBitmap result = RoaringBitmap.and(list.iterator(), rangeStart, rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - - @Test - public void testRangedXor() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add(val1); - set1.add(val1); - - rb2.add(val2); - set2.add(val2); - } - Set xorSet = new TreeSet<>(); - xorSet.addAll(set1); - xorSet.addAll(set2); - Set andSet = new TreeSet<>(set1); - andSet.retainAll(set2); - - xorSet.removeAll(andSet); - for (int iter = 0; iter < NUM_ITER; iter++) { - int rangeStart = random.nextInt(length - 1); - // +1 to ensure rangeEnd >rangeStart, may - int rangeLength = random.nextInt(length - rangeStart) + 1; - int rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = rangeStart; i < rangeEnd; i++) { - if (xorSet.contains(i)) { - expectedResultSet.add(i); - } - } - List list = new ArrayList<>(); - list.add(rb1); - list.add(rb2); - RoaringBitmap result = RoaringBitmap.xor(list.iterator(), (long) rangeStart, (long) rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - - @Test - public void testRangedXorBigInts() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add((1 << 31) + val1); - set1.add((1 << 31) + val1); - - rb2.add((1 << 31) + val2); - set2.add((1 << 31) + val2); - } - Set xorSet = new TreeSet<>(); - xorSet.addAll(set1); - xorSet.addAll(set2); - Set andSet = new TreeSet<>(set1); - andSet.retainAll(set2); - - xorSet.removeAll(andSet); - for (int iter = 0; iter < NUM_ITER; iter++) { - long rangeStart1 = random.nextInt(length - 1); - long rangeStart = (1L << 31) + rangeStart1; - long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1; - long rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = (int) rangeStart; i < (int) rangeEnd; i++) { - if (xorSet.contains(i)) { - expectedResultSet.add(i); - } - } - List list = new ArrayList<>(); - list.add(rb1); - list.add(rb2); - RoaringBitmap result = RoaringBitmap.xor(list.iterator(), rangeStart, rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - - @Test - public void testRangedAndNot() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add(val1); - set1.add(val1); - - rb2.add(val2); - set2.add(val2); - } - Set andNotSet = new TreeSet<>(); - for (int i : set1) { - if (!set2.contains(i)) { - andNotSet.add(i); - } - } - for (int iter = 0; iter < NUM_ITER; iter++) { - int rangeStart = random.nextInt(length - 1); - // +1 to ensure rangeEnd >rangeStart, may - int rangeLength = random.nextInt(length - rangeStart) + 1; - int rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = rangeStart; i < rangeEnd; i++) { - if (andNotSet.contains(i)) { - expectedResultSet.add(i); - } - } - RoaringBitmap result = RoaringBitmap.andNot(rb1, rb2, (long) rangeStart, (long) rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - - @Test - public void testRangedAndNotBigInts() { - int length = 1000; - int NUM_ITER = 10; - Random random = new Random(1234);// please use deterministic tests - for (int test = 0; test < 50; ++test) { - final RoaringBitmap rb1 = new RoaringBitmap(); - final RoaringBitmap rb2 = new RoaringBitmap(); - Set set1 = new HashSet<>(); - Set set2 = new HashSet<>(); - int numBitsToSet = length / 2; - for (int i = 0; i < numBitsToSet; i++) { - int val1 = random.nextInt(length); - int val2 = random.nextInt(length); - - rb1.add((1 << 31) + val1); - set1.add((1 << 31) + val1); - - rb2.add((1 << 31) + val2); - set2.add((1 << 31) + val2); - } - Set andNotSet = new TreeSet<>(); - for (int i : set1) { - if (!set2.contains(i)) { - andNotSet.add(i); - } - } - for (int iter = 0; iter < NUM_ITER; iter++) { - long rangeStart1 = random.nextInt(length - 1); - long rangeStart = (1L << 31) + rangeStart1; - long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1; - long rangeEnd = rangeStart + rangeLength; - Set expectedResultSet = new TreeSet<>(); - for (int i = (int) rangeStart; i < (int) rangeEnd; i++) { - if (andNotSet.contains(i)) { - expectedResultSet.add(i); - } - } - RoaringBitmap result = RoaringBitmap.andNot(rb1, rb2, rangeStart, rangeEnd); - Set actualResultSet = new TreeSet<>(); - IntIterator intIterator = result.getIntIterator(); - while (intIterator.hasNext()) { - actualResultSet.add(intIterator.next()); - } - assertEquals(expectedResultSet, actualResultSet); - } - } - } - - - @Test - public void testOr() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(4, 7, 8, 9); - RoaringBitmap rb3 = RoaringBitmap.bitmapOf(12, 13, 15, 19, 21); - RoaringBitmap rb4 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 7, 8, 9); - RoaringBitmap rb5 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 15, 19, 21); - assertEquals(rb4, RoaringBitmap.lazyorfromlazyinputs(rb1, rb2)); - assertEquals(rb5, RoaringBitmap.or(rb1, rb2, rb3)); - } - - @Test - public void testLazyOr() { - RoaringBitmap rb1 = RoaringBitmap.bitmapOf(1 << 16, 1 << 18, 1 << 19); - rb1.lazyor(RoaringBitmap.bitmapOf(4, 7, 8, 9)); - rb1.lazyor(RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 1 << 16, 1 << 17, 1 << 20)); - RoaringBitmap rb2 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 7, 8, 9, 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20); - assertEquals(rb2, rb1); - } - - @Test - public void testFirstLast_CreateSparseContainers() { - RoaringBitmap rb = new RoaringBitmap(); - for (int i = 0; i < 20; ++i) { - int x = 1 << i; - rb.add(x); - assertEquals(1, rb.first()); - assertEquals(x, rb.last()); - } - } - - @Test - public void testFirstLast_CreateSparseContainersAfterRun() { - RoaringBitmap rb = new RoaringBitmap(); - rb.add(1L, 1 << 14); - for (int i = 18; i < 31; ++i) { - int x = 1 << i; - rb.add(x); - assertEquals(1, rb.first()); - assertEquals(x, rb.last()); - } - } - - @Test - public void testFirstLast_AfterLazyMutation1() { - RoaringBitmap rb = new RoaringBitmap(); - rb.add(1, 3, 5, 7); - assertEquals(1, rb.first()); - assertEquals(7, rb.last()); - RoaringBitmap mutator = new RoaringBitmap(); - mutator.add(0, 2, 4, 6, 8); - rb.lazyor(mutator); - assertEquals(0, rb.first()); - assertEquals(8, rb.last()); - } - - - @Test - public void testFirstLast_AfterLazyMutation2() { - RoaringBitmap rb = new RoaringBitmap(); - Iterable willForceUseOfBitmapContainer = Iterables.filter( - ContiguousSet.create(Range.openClosed(0, 1 << 16), DiscreteDomain.integers()), - new Predicate() { - @Override - public boolean apply(Integer input) { - return input % 3 == 0; - } - } - ); - int max = 0; - for (Integer i : willForceUseOfBitmapContainer) { - rb.add(i); - max = i; - } - assertEquals(3, rb.first()); - assertEquals(max, rb.last()); - RoaringBitmap mutator = new RoaringBitmap(); - mutator.add(0, 2, 4, 6, 8); - rb.lazyor(mutator); - assertEquals(0, rb.first()); - assertEquals(max, rb.last()); - } - - - @Test - public void testEmptyFirst() { - assertThrows(NoSuchElementException.class, () -> new RoaringBitmap().first()); - } - - @Test - public void testEmptyLast() { - assertThrows(NoSuchElementException.class, () -> new RoaringBitmap().last()); - } - - @Test - public void testFirstLast() { - RoaringBitmap rb = new RoaringBitmap(); - - rb.add(2); - rb.add(4); - rb.add(8); - assertEquals(2, rb.first()); - assertEquals(8, rb.last()); - - rb.add(1L << 5, 1L << 14); - assertEquals(2, rb.first()); - assertEquals((1 << 14) - 1, rb.last()); - - rb.add(1L << 15, 1L << 30); - assertEquals(2, rb.first()); - assertEquals((1L << 30) - 1, rb.last()); - } - - @Test - public void testIsHammingSimilar_AtStart() { - // similar bitmaps in the first container - RoaringBitmap baseline = RoaringBitmap.bitmapOf(2, 4, 8, 1 << 17, 1 << 22); - assertTrue(baseline.isHammingSimilar(baseline, 0)); - RoaringBitmap other = baseline.clone(); - other.flip(0L, 9); - for (int i = 0; i < 9; ++i) { - assertFalse(baseline.isHammingSimilar(other, i)); - } - assertTrue(baseline.isHammingSimilar(other, 9)); - other.add(0L, 9L); - for (int i = 0; i < 6; ++i) { - assertFalse(baseline.isHammingSimilar(other, i)); - } - assertTrue(baseline.isHammingSimilar(other, 6)); - } - - @Test - public void testHammingSimilarity_BigVsSmall() { - RoaringBitmap big = new RoaringBitmap(); - big.add(1, 2, 3, 4); - big.add(1L << 17, 1L << 30); - big.flip((1 << 17) | (1 << 16)); - for (int i = 1 << 18; i < 1 << 19; ++i) { - if (i % 3 == 0) { - big.flip(i); - } - } - RoaringBitmap small = RoaringBitmap.bitmapOf(1, 2, 3, 4); - assertFalse(small.isHammingSimilar(big, 1)); - assertFalse(big.isHammingSimilar(small, 1)); - } - - @Test - public void testHammingSimilarity_Shifted() { - RoaringBitmap baseline = RoaringBitmap.bitmapOf(1, 2, 3, 4); - RoaringBitmap shifted = RoaringBitmap.bitmapOf((1 << 17) + 1, (1 << 17) + 2, (1 << 17) + 3, - (1 << 17) + 4); - assertFalse(baseline.isHammingSimilar(shifted, 0)); - } - - @Test - public void testIsHammingSimilar_AtEnd() { - // reject bitmaps that are identical for many chunks but differ at the end - RoaringBitmap baseline = new RoaringBitmap(); - for (int i = 0; i < 1 << 15; ++i) { - if (i % 3 == 0) { - baseline.add(i); - } - } - baseline.add((1L << 16) + 1, 1L << 18); - baseline.add((1L << 19) + 1, 1L << 20); - baseline.add((1 << 21) + 1); - baseline.add((1 << 21) + 3); - baseline.add((1 << 21) + 5); - assertEquals(baseline.getCardinality(), RoaringBitmap.andCardinality(baseline, baseline)); - assertTrue(baseline.isHammingSimilar(baseline, 0)); - RoaringBitmap other = baseline.clone(); - other.flip((1 << 21) + 1); - assertTrue(baseline.isHammingSimilar(other, 1)); - assertFalse(baseline.isHammingSimilar(other, 0)); - other.add((1 << 21) + 2); - assertTrue(baseline.isHammingSimilar(other, 2)); - assertFalse(baseline.isHammingSimilar(other, 1)); - other.flip((1 << 21) + 3); - assertTrue(baseline.isHammingSimilar(other, 3)); - assertFalse(baseline.isHammingSimilar(other, 2)); - } - - @Test - public void testAndCardinality() { - RoaringBitmap baseline = new RoaringBitmap(); - baseline.add((1L << 16) + 1, 1L << 18); - baseline.add((1L << 19) + 1, 1L << 20); - baseline.add((1 << 21) + 1); - baseline.add((1 << 21) + 3); - baseline.add((1 << 21) + 5); - assertEquals(baseline, RoaringBitmap.and(baseline, baseline)); - assertEquals(baseline.getCardinality(), RoaringBitmap.andCardinality(baseline, baseline)); - } - - - @Test - public void testRankOverflow() { - assertEquals(0, RoaringBitmap.bitmapOf(65537).rank(1)); - assertEquals(1, RoaringBitmap.bitmapOf(65537).rank(65537)); - assertEquals(1, RoaringBitmap.bitmapOf(65537).rank(65538)); - } - - - @Test - public void testNegativeAdd() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(-7); - - assertEquals("{4294967289}", bitmap.toString()); - } - - @Test - public void testNegative_last() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(-7); - bitmap.add(777); - - assertEquals(-7, bitmap.last()); - } - - @Test - public void testContainsRange_ContiguousBitmap() { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(0L, 1_000_000L); - assertTrue(bitmap.contains(1L, 999_999L)); - assertFalse(bitmap.contains(1L, 1_000_001L)); - bitmap.flip(500_000); - assertFalse(bitmap.contains(1L, 999_999L)); - bitmap.flip(500_000); - bitmap.flip(500_000L, 600_000L); - assertFalse(bitmap.contains(1L, 999_999L)); - assertTrue(bitmap.contains(0L, 500_000L)); - assertFalse(bitmap.contains(2_000_001L, 10_000_000L)); - } - - @Test - public void testContainsRange_SmallBitmap() { - RoaringBitmap bitmap = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6); - assertTrue(bitmap.contains(1, 6)); - assertTrue(bitmap.contains(1, 5)); - assertTrue(bitmap.contains(2, 6)); - assertTrue(bitmap.contains(2, 7)); - assertFalse(bitmap.contains(2, 8)); - assertFalse(bitmap.contains(0, 6)); - assertFalse(bitmap.contains(0, 1)); - assertFalse(bitmap.contains(6, 10)); - assertFalse(bitmap.contains(7, 1 << 16)); - assertFalse(bitmap.contains(1 << 17, 1 << 19)); - } - - @Test - public void testContainsRange_DirtyBitmap() { - RoaringBitmapWriter writer = writer().constantMemory().get(); - IntStream.range(0, 1_000_000) - .map(i -> i * 2) - .forEach(writer::add); - writer.flush(); - RoaringBitmap bitmap = writer.getUnderlying(); - assertFalse(bitmap.contains(0L, 2_000_000L)); - assertFalse(bitmap.contains(0L, 2L)); - assertTrue(bitmap.contains(0L, 1L)); - assertTrue(bitmap.contains(1L << 10, 1 | (1L << 10))); - assertFalse(bitmap.contains(1L << 31, 1L << 32)); - } - - @Test - public void addoffset() { - final RoaringBitmap rb = new RoaringBitmap(); - rb.add(10); - rb.add(0xFFFF); - rb.add(0x010101); - for (int i = 100000; i < 200000; i += 4) { - rb.add(i); - } - rb.add(400000L, 1400000L); - for (int offset = 3; offset < 1000000; offset *= 3) { - RoaringBitmap rboff = RoaringBitmap.addOffset(rb, offset); - IntIterator i = rb.getIntIterator(); - IntIterator j = rboff.getIntIterator(); - while (i.hasNext() && j.hasNext()) { - int val1 = i.next() + offset; - int val2 = j.next(); - assertEquals(val1, val2); - } - assertEquals(i.hasNext(), j.hasNext()); - } - for (int offset = 1024; offset < 1000000; offset *= 2) { - RoaringBitmap rboff = RoaringBitmap.addOffset(rb, offset); - IntIterator i = rb.getIntIterator(); - IntIterator j = rboff.getIntIterator(); - while (i.hasNext() && j.hasNext()) { - assertEquals(i.next() + offset, j.next()); - } - assertEquals(i.hasNext(), j.hasNext()); - } - } - - @Test - public void issue418() { - final RoaringBitmap rb = new RoaringBitmap(); - rb.add(0); - assertEquals(rb.contains(0), true); - assertEquals(rb.getCardinality(), 1); - long vals[] = { 100, 0xFFFF0000L, 0xFFFF0001L }; - for(long s : vals) { - RoaringBitmap shifted = RoaringBitmap.addOffset(rb, s); - System.out.println("moved "+shifted); - assertEquals(shifted.contains((int)s), true); - assertEquals(shifted.getCardinality(), 1); - System.out.println("moving back by "+(-s)); - - shifted = RoaringBitmap.addOffset(shifted, -s); - System.out.println("back "+shifted); - - assertEquals(shifted.contains(0), true); - assertEquals(shifted.getCardinality(), 1); - } - } - - @Test - public void addNegativeOffset() { - final RoaringBitmap rb = new RoaringBitmap(); - rb.add(10); - rb.add(0xFFFF); - rb.add(0x010101); - for (int i = 100000; i < 200000; i += 4) { - rb.add(i); - } - rb.add(400000L, 1400000L); - for (int offset = 3; offset < 1000000; offset *= 3) { - RoaringBitmap rboffpos = RoaringBitmap.addOffset(rb, offset); - RoaringBitmap rboff = RoaringBitmap.addOffset(rboffpos, -offset); - - IntIterator i = rb.getIntIterator(); - IntIterator j = rboff.getIntIterator(); - while (i.hasNext() && j.hasNext()) { - int val1 = i.next(); - int val2 = j.next(); - if (val1 != val2) - assertEquals(val1, val2); - } - assertEquals(i.hasNext(), j.hasNext()); - } - for (int offset = 1024; offset < 1000000; offset *= 2) { - RoaringBitmap rboffpos = RoaringBitmap.addOffset(rb, offset); - RoaringBitmap rboff = RoaringBitmap.addOffset(rboffpos, -offset); - IntIterator i = rb.getIntIterator(); - IntIterator j = rboff.getIntIterator(); - while (i.hasNext() && j.hasNext()) { - assertEquals(i.next(), j.next()); - } - assertEquals(i.hasNext(), j.hasNext()); - } - } - - - @Test - public void testNextValue() { - RoaringBitmap bitmap = SeededTestData.TestDataSet.testCase() - .withRunAt(0) - .withBitmapAt(1) - .withArrayAt(2) - .withRunAt(3) - .withBitmapAt(4) - .withArrayAt(5) - .build(); - - BitSet bitset = new BitSet(); - bitmap.forEach((IntConsumer) bitset::set); - long b1 = 0; - int b2 = 0; - while (b1 >= 0 && b2 >= 0) { - b1 = bitmap.nextValue((int) b1 + 1); - b2 = bitset.nextSetBit(b2 + 1); - assertEquals(b1, b2); - } - } - - @Test - public void testPreviousValue() { - RoaringBitmap bitmap = SeededTestData.TestDataSet.testCase() - .withRunAt(0) - .withBitmapAt(1) - .withArrayAt(2) - .withRunAt(3) - .withBitmapAt(4) - .withArrayAt(5) - .build(); - - BitSet bitset = new BitSet(); - bitmap.forEach((IntConsumer) bitset::set); - long b1 = Util.toUnsignedLong(bitmap.last()); - int b2 = bitset.previousSetBit(Integer.MAX_VALUE); - int i = bitmap.getCardinality(); - while (b1 > 0 && b2 > 0) { - assertEquals(b1, b2); - b1 = bitmap.previousValue((int) (b1 - 1)); - b2 = bitset.previousSetBit(b2 - 1); - assertEquals(b1, b2, "mismatch at " + i + "(bitset=" + b2 + ", rb=" + b1 + ")"); - --i; - } - } - - @Test - public void testPreviousValueRegression() { - // see https://github.com/RoaringBitmap/RoaringBitmap/issues/564 - assertEquals(-1, RoaringBitmap.bitmapOf(27399807).previousValue(403042)); - assertEquals(-1, RoaringBitmap.bitmapOf().previousValue(403042)); - } - - @Test - public void testRangeCardinalityAtBoundary() { - // See https://github.com/RoaringBitmap/RoaringBitmap/issues/285 - RoaringBitmap r = new RoaringBitmap(); - r.add(66236); - assertEquals(1, r.rangeCardinality(60000, 70000)); - } - - @Test - public void testNextValueArray() { - RoaringBitmap r = new RoaringBitmap(); - r.add(0, 1, 2, 4, 6); - assertEquals(-1, r.nextValue(7)); - } - - @Test - public void regressionTestEquals370() { - // see https://github.com/RoaringBitmap/RoaringBitmap/issues/370 - int[] a = {239, 240, 241, 242, 243, 244, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 273, 274, 275, 276, 277, 278, 398, 399, 400, 401, 402, 403, 404, 405, 406, 408, 409, 410, 411, 412, 413, 420, 421, 422, 509, 510, 511, 512, 513, 514, 539, 540, 541, 542, 543, 544, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 624, 625, 634, 635, 636, 649, 650, 651, 652, 653, 654, 714, 715, 716, 718, 719, 720, 721, 722, 723, 724, 725, 726, 728, 729, 730, 731, 732, 733, 734, 735, 736, 739, 740, 741, 742, 743, 744, 771, 772, 773}; - int[] b = {239, 240, 241, 242, 243, 244, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 273, 274, 275, 276, 277, 278, 398, 399, 400, 401, 402, 403, 404, 405, 406, 408, 409, 410, 411, 412, 413, 420, 421, 422, 509, 510, 511, 512, 513, 514, 539, 540, 541, 542, 543, 544, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 578, 579, 580, 581, 582, 583, 584, 585, 586, 607, 608, 634, 635, 636, 649, 650, 651, 652, 653, 654, 714, 715, 716, 718, 719, 720, 721, 722, 723, 724, 725, 726, 728, 729, 730, 731, 732, 733, 734, 735, 736, 739, 740, 741, 742, 743, 744, 771, 772, 773}; - - RoaringBitmap rbA = RoaringBitmap.bitmapOf(a); - RoaringBitmap rbB = RoaringBitmap.bitmapOf(b); - - assertNotEquals(rbB, rbA); - rbA.runOptimize(); - assertNotEquals(rbB, rbA); - rbB.runOptimize(); - assertNotEquals(rbB, rbA); - } - - @Test - public void regressionTestRemove377() { - // https://github.com/RoaringBitmap/RoaringBitmap/issues/377 - RoaringBitmap map = new RoaringBitmap(); - map.add(0L, 64L); - for (int i = 0; i < 64; i++) { - if (i != 30 && i != 32) { - map.remove(i); - } - } - map.remove(0L, 31L); - assertFalse(map.contains(30)); - assertTrue(map.contains(32)); - } - - @Test - public void invalidCookieBuffer() { - assertThrows(IOException.class, () -> { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.deserialize(ByteBuffer.allocate(4)); - }); - } - - @Test - public void invalidCookieDataInput() { - assertThrows(IOException.class, () -> { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.deserialize(new DataInputStream(new ByteArrayInputStream(new byte[4]))); - }); - } - - @Test - public void invalidCookieDataInputWithBuffer() { - assertThrows(IOException.class, () -> { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.deserialize(new DataInputStream(new ByteArrayInputStream(new byte[4])), new byte[8]); - }); - } - - @Test - public void testCardinalityExceeds() { - RoaringBitmap bitmap = new RoaringBitmap(); - long runLength = 20_000L; - bitmap.add(0L, runLength); - for (int i = (1 << 16) + 1; i < 1 << 17; i+= 2) { - bitmap.add(i); - } - long bitmapCount = 1 << 15; - bitmap.add((1 << 17) | 1); - bitmap.add((1 << 17) | 2); - bitmap.add((1 << 17) | 3); - long arrayCount = 3; - bitmap.runOptimize(); - assertFalse(bitmap.cardinalityExceeds(Integer.MAX_VALUE)); - assertFalse(bitmap.cardinalityExceeds(runLength + bitmapCount + arrayCount)); - assertTrue(bitmap.cardinalityExceeds(runLength + bitmapCount + 1)); - assertTrue(bitmap.cardinalityExceeds(runLength + bitmapCount - 1)); - assertTrue(bitmap.cardinalityExceeds(runLength - 1)); - } - - - @Test - public void testWithYourself() { - RoaringBitmap b1 = RoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10); - b1.runOptimize(); - b1.or(b1); - assertTrue(b1.equals(RoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10))); - b1.xor(b1); - assertTrue(b1.isEmpty()); - b1 = RoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10); - b1.and(b1); - assertTrue(b1.equals(RoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10))); - b1.andNot(b1); - assertTrue(b1.isEmpty()); - } - - @Test - public void testIssue566() { - RoaringBitmap roaringBitMap = new RoaringBitmap(); - BitSet bitSet = new BitSet(5000); - double prob = 0.001; - Random random = new Random(); - for (int i = 0; i < 5000; i++) { - if (random.nextDouble() < prob) { - bitSet.set(i); - roaringBitMap.add(i); - } - } - long roaringbits = roaringBitMap.getSizeInBytes() * 8; - long bitsetbits = bitSet.size(); - System.out.println("[issue566] cardinality: "+ roaringBitMap.getCardinality()); - System.out.println("[issue566] bitset bits: "+ bitsetbits); - System.out.println("[issue566] bitset bits per entry: " + bitsetbits * 1.0 / bitSet.cardinality()); - System.out.println("[issue566] RoaringBitmap bits: " + roaringbits); - System.out.println("[issue566] RoaringBitmap bits per entry: " + roaringbits * 1.0 / roaringBitMap.getCardinality()); - assertTrue(roaringbits < bitsetbits); - } - @Test - public void issue623() { - RoaringBitmap r = new RoaringBitmap(); - r.add(65535); - r.add(65535+1); - assertTrue(r.contains(65535)); - assertTrue(r.contains(65535 + 1)); - assertTrue(r.contains(65535L, 65535L + 1)); - for (long i = 1; i <= 10_000_000; i++) { - r.add(i, i + 1); - } - for (long i = 1; i <= 10_000_000; i++) { - assertTrue(r.contains(i, i + 1)); - } - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriter.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriter.java deleted file mode 100644 index 0250bfae6..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriter.java +++ /dev/null @@ -1,207 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.function.Supplier; -import java.util.stream.Stream; - -import static java.lang.Integer.*; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.roaringbitmap.RoaringBitmapWriter.bufferWriter; -import static org.roaringbitmap.RoaringBitmapWriter.writer; - -@Execution(ExecutionMode.CONCURRENT) -public class TestRoaringBitmapWriter { - - public static Stream params() { - return Stream.of( - Arguments.of(writer().optimiseForArrays()), - Arguments.of(writer().optimiseForRuns()), - Arguments.of(writer().constantMemory()), - Arguments.of(writer().optimiseForArrays().fastRank()), - Arguments.of(writer().optimiseForRuns().fastRank()), - Arguments.of(writer().constantMemory().fastRank()), - Arguments.of(writer().expectedDensity(0.001)), - Arguments.of(writer().expectedDensity(0.01)), - Arguments.of(writer().expectedDensity(0.1)), - Arguments.of(writer().expectedDensity(0.6)), - Arguments.of(writer().expectedDensity(0.001).fastRank()), - Arguments.of(writer().expectedDensity(0.01).fastRank()), - Arguments.of(writer().expectedDensity(0.1).fastRank()), - Arguments.of(writer().expectedDensity(0.6).fastRank()), - Arguments.of(writer().initialCapacity(1)), - Arguments.of(writer().initialCapacity(8)), - Arguments.of(writer().initialCapacity(8192)), - Arguments.of(writer().initialCapacity(1).fastRank()), - Arguments.of(writer().initialCapacity(8).fastRank()), - Arguments.of(writer().initialCapacity(8192).fastRank()), - Arguments.of(writer().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE))), - Arguments.of(writer().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE))), - Arguments.of(writer().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE))), - Arguments.of(writer().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank()), - Arguments.of(writer().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank()), - Arguments.of(writer().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank()), - Arguments.of(writer().optimiseForArrays().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))), - Arguments.of(writer().optimiseForRuns().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))), - Arguments.of(writer().constantMemory().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))), - Arguments.of(writer().optimiseForArrays().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).fastRank()), - Arguments.of(writer().optimiseForRuns().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).fastRank()), - Arguments.of(writer().constantMemory().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).fastRank()), - Arguments.of(bufferWriter().optimiseForArrays()), - Arguments.of(bufferWriter().optimiseForRuns()), - Arguments.of(bufferWriter().constantMemory()), - Arguments.of(bufferWriter().expectedDensity(0.001)), - Arguments.of(bufferWriter().expectedDensity(0.01)), - Arguments.of(bufferWriter().expectedDensity(0.1)), - Arguments.of(bufferWriter().expectedDensity(0.6)), - Arguments.of(bufferWriter().initialCapacity(1)), - Arguments.of(bufferWriter().initialCapacity(8)), - Arguments.of(bufferWriter().initialCapacity(8192)), - Arguments.of(bufferWriter().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE))), - Arguments.of(bufferWriter().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE))), - Arguments.of(bufferWriter().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE))), - Arguments.of(bufferWriter().optimiseForArrays().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))), - Arguments.of(bufferWriter().optimiseForRuns().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))), - Arguments.of(bufferWriter().constantMemory().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))), - Arguments.of(writer().optimiseForArrays().runCompress(false)), - Arguments.of(writer().optimiseForRuns().runCompress(false)), - Arguments.of(writer().constantMemory().runCompress(false)), - Arguments.of(writer().optimiseForArrays().fastRank().runCompress(false)), - Arguments.of(writer().optimiseForRuns().fastRank().runCompress(false)), - Arguments.of(writer().constantMemory().fastRank().runCompress(false)), - Arguments.of(writer().expectedDensity(0.001).runCompress(false)), - Arguments.of(writer().expectedDensity(0.01).runCompress(false)), - Arguments.of(writer().expectedDensity(0.1).runCompress(false)), - Arguments.of(writer().expectedDensity(0.6).runCompress(false)), - Arguments.of(writer().expectedDensity(0.001).fastRank().runCompress(false)), - Arguments.of(writer().expectedDensity(0.01).fastRank().runCompress(false)), - Arguments.of(writer().expectedDensity(0.1).fastRank().runCompress(false)), - Arguments.of(writer().expectedDensity(0.6).fastRank().runCompress(false)), - Arguments.of(writer().initialCapacity(1).runCompress(false)), - Arguments.of(writer().initialCapacity(8).runCompress(false)), - Arguments.of(writer().initialCapacity(8192).runCompress(false)), - Arguments.of(writer().initialCapacity(1).fastRank().runCompress(false)), - Arguments.of(writer().initialCapacity(8).fastRank().runCompress(false)), - Arguments.of(writer().initialCapacity(8192).fastRank().runCompress(false)), - Arguments.of(writer().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(writer().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(writer().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(writer().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank().runCompress(false)), - Arguments.of(writer().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank().runCompress(false)), - Arguments.of(writer().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank().runCompress(false)), - Arguments.of(writer().optimiseForArrays().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(writer().optimiseForRuns().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(writer().constantMemory().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(writer().optimiseForArrays().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).fastRank().runCompress(false)), - Arguments.of(writer().optimiseForRuns().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).fastRank().runCompress(false)), - Arguments.of(writer().constantMemory().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).fastRank().runCompress(false)), - Arguments.of(bufferWriter().optimiseForArrays().runCompress(false)), - Arguments.of(bufferWriter().optimiseForRuns().runCompress(false)), - Arguments.of(bufferWriter().constantMemory().runCompress(false)), - Arguments.of(bufferWriter().expectedDensity(0.001).runCompress(false)), - Arguments.of(bufferWriter().expectedDensity(0.01).runCompress(false)), - Arguments.of(bufferWriter().expectedDensity(0.1).runCompress(false)), - Arguments.of(bufferWriter().expectedDensity(0.6).runCompress(false)), - Arguments.of(bufferWriter().initialCapacity(1).runCompress(false)), - Arguments.of(bufferWriter().initialCapacity(8).runCompress(false)), - Arguments.of(bufferWriter().initialCapacity(8192).runCompress(false)), - Arguments.of(bufferWriter().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(bufferWriter().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(bufferWriter().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(bufferWriter().optimiseForArrays().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(bufferWriter().optimiseForRuns().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).runCompress(false)), - Arguments.of(bufferWriter().constantMemory().expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE)).runCompress(false)) - ); - } - - @ParameterizedTest - @MethodSource("params") - public void addInReverseOrder(Supplier> supplier) { - RoaringBitmapWriter writer = supplier.get(); - writer.add(1 << 17); - writer.add(0); - writer.flush(); - assertArrayEquals(RoaringBitmap.bitmapOf(0, 1 << 17).toArray(), writer.getUnderlying().toArray()); - } - - @ParameterizedTest - @MethodSource("params") - public void bitmapShouldContainAllValuesAfterFlush(Supplier> supplier) { - RoaringBitmapWriter writer = supplier.get(); - writer.add(0); - writer.add(1 << 17); - writer.flush(); - assertTrue(writer.getUnderlying().contains(0)); - assertTrue(writer.getUnderlying().contains(1 << 17)); - } - - - @ParameterizedTest - @MethodSource("params") - public void newKeyShouldTriggerFlush(Supplier> supplier) { - RoaringBitmapWriter writer = supplier.get(); - writer.add(0); - writer.add(1 << 17); - assertTrue(writer.getUnderlying().contains(0)); - writer.add(1 << 18); - assertTrue(writer.getUnderlying().contains(1 << 17)); - } - - @ParameterizedTest - @MethodSource("params") - public void writeSameKeyAfterManualFlush(Supplier> supplier) { - RoaringBitmapWriter writer = supplier.get(); - writer.add(0); - writer.flush(); - writer.add(1); - writer.flush(); - assertArrayEquals(RoaringBitmap.bitmapOf(0, 1).toArray(), writer.getUnderlying().toArray()); - } - - - @ParameterizedTest - @MethodSource("params") - public void writeRange(Supplier> supplier) { - RoaringBitmapWriter writer = supplier.get(); - writer.add(0); - writer.add(65500L, 65600L); - writer.add(1); - writer.add(65610); - writer.flush(); - RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 65610); - expected.add(65500L, 65600L); - assertArrayEquals(expected.toArray(), writer.getUnderlying().toArray()); - } - - @ParameterizedTest - @MethodSource("params") - public void testWriteToMaxKeyAfterFlush(Supplier> supplier) { - RoaringBitmapWriter writer = supplier.get(); - writer.add(0); - writer.add(-2); - writer.flush(); - assertArrayEquals(RoaringBitmap.bitmapOf(0, -2).toArray(), writer.get().toArray()); - writer.add(-1); - assertArrayEquals(RoaringBitmap.bitmapOf(0, -2, -1).toArray(), writer.get().toArray()); - } - - - @ParameterizedTest - @MethodSource("params") - public void testWriteBitmapAfterReset(Supplier> supplier) { - RoaringBitmapWriter writer = supplier.get(); - writer.add(0); - writer.add(-2); - assertArrayEquals(new int[]{0, -2}, writer.get().toArray()); - writer.reset(); - writer.add(100); - writer.addMany(4, 5, 6); - assertArrayEquals(new int[]{4, 5, 6, 100}, writer.get().toArray()); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestUtil.java b/RoaringBitmap/src/test/java/org/roaringbitmap/TestUtil.java deleted file mode 100644 index 9fd5ada5e..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestUtil.java +++ /dev/null @@ -1,197 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.Arrays; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.SeededTestData.*; -import static org.roaringbitmap.SeededTestData.sparseRegion; - -@Execution(ExecutionMode.CONCURRENT) -public class TestUtil { - - @Test - public void testUtilUnsignedIntersection() { - char[] data1 = fromShorts(new short[]{-19, -17, -15, -13, -11, -9, -7, -5, -3, -1}); - char[] data2 = fromShorts(new short[]{-18, -16, -14, -12, -10, -8, -1}); - assertTrue(Util.unsignedIntersects(data1, data1.length, data2, data2.length)); - char[] data3 = fromShorts(new short[]{-19, -17, -15, -13, -11, -9, -7}); - char[] data4 = fromShorts(new short[]{-18, -16, -14, -12, -10, -8, -6, -4, -2, 0}); - assertFalse(Util.unsignedIntersects(data3, data3.length, data4, data4.length)); - char[] data5 = {}; - char[] data6 = {}; - assertFalse(Util.unsignedIntersects(data5, data5.length, data6, data6.length)); - } - - @Test - public void testBranchyUnsignedBinarySearch() { - char[] data1 = fromShorts(new short[]{-19, -17, -15, -13, -11, -9, -7, -5, -3}); - assertEquals(8, Util.branchyUnsignedBinarySearch(data1, 0, data1.length, data1[8])); - assertEquals(0, Util.branchyUnsignedBinarySearch(data1, 0, data1.length, data1[0])); - assertEquals(data1.length-1, Util.branchyUnsignedBinarySearch(data1, data1.length-1, data1.length, data1[data1.length-1])); - assertEquals(-1, Util.branchyUnsignedBinarySearch(data1, 0, 0, (char)0)); - assertEquals(-10, Util.branchyUnsignedBinarySearch(data1, 0, data1.length, (char) -1)); - } - - @Test - public void testPartialRadixSortEmpty() { - int[] data = new int[] {}; - int[] test = Arrays.copyOf(data, data.length); - Util.partialRadixSort(test); - assertArrayEquals(data, test); - } - - @Test - public void testPartialRadixSortIsStableInSameKey() { - int[] data = new int[] {25, 1, 0, 10}; - for (int key : new int[]{0, 1 << 16, 1 << 17, 1 << 24, 1 << 25}) { - // clear the old key and prepend the new key - for (int i = 0; i < data.length; ++i) { - data[i] &= 0xFFFF; - data[i] |= key; - } - int[] test = Arrays.copyOf(data, data.length); - Util.partialRadixSort(test); - assertArrayEquals(data, test); - } - } - - @Test - public void testPartialRadixSortSortsKeysCorrectly() { - int[] keys = { - // the test expects the first key to be less than the second key, - // neither should have any of the lower 16 bits set - 1 << 16, 1 << 25, - 1 << 16, 1 << 17, - 1 << 17, 1 << 18, - 1 << 25, 1 << 26, - 1 << 23, 1 << 25, - 1 << 24, 1 << 25, - 1 << 25, 1 << 27, - 1 << 29, 1 << 30, - }; - for (int i = 0; i < keys.length; i += 2) { - int key1 = keys[i]; - int key2 = keys[i+1]; - int[] data = new int[]{key2 | 25, key1 | 1, 0, key2 | 10, 25, key1 | 10, key1, 10}; - // sort by keys, leave values stable - int[] expected = new int[]{0, 25, 10, key1 | 1, key1 | 10, key1, key2 | 25, key2 | 10}; - int[] test = Arrays.copyOf(data, data.length); - Util.partialRadixSort(test); - assertArrayEquals(expected, test); - } - } - - @Test - public void testPartialRadixSortSortsKeysCorrectlyWithDuplicates() { - int[] keys = { - // the test expects the first key to be less than the second key, - // neither should have any of the lower 16 bits set - 1 << 16, 1 << 25, - 1 << 16, 1 << 17, - 1 << 17, 1 << 18, - 1 << 25, 1 << 26, - 1 << 23, 1 << 25, - 1 << 24, 1 << 25, - 1 << 25, 1 << 27, - 1 << 29, 1 << 30, - }; - for (int i = 0; i < keys.length; i += 2) { - int key1 = keys[i]; - int key2 = keys[i + 1]; - int[] data = new int[]{key2 | 25, key1 | 1, 0, key2 | 10, 25, key1 | 10, key1, 10, - key2 | 25, key1 | 1, 0, key2 | 10, 25, key1 | 10, key1, 10}; - // sort by keys, leave values stable - int[] expected = new int[]{0, 25, 10, 0, 25, 10, key1 | 1, key1 | 10, key1, key1 | 1, key1 | 10, key1, - key2 | 25, key2 | 10, key2 | 25, key2 | 10}; - int[] test = Arrays.copyOf(data, data.length); - Util.partialRadixSort(test); - assertArrayEquals(expected, test); - } - } - - @Test - public void testAdvanceUntil() { - char[] data = fromShorts(new short[]{0, 3, 16, 18, 21, 29, 30,-342}); - assertEquals(1, Util.advanceUntil(data, -1, data.length, (char) 3)); - assertEquals(5, Util.advanceUntil(data, -1, data.length, (char) 28)); - assertEquals(5, Util.advanceUntil(data, -1, data.length, (char) 29)); - assertEquals(7, Util.advanceUntil(data, -1, data.length, (char) -342)); - } - - @Test - public void testReverseUntil() { - char[] data = fromShorts(new short[]{1, 3, 16, 18, 21, 29, 30,-342}); - assertEquals(0, Util.reverseUntil(data, data.length, data.length, (char) 0)); - assertEquals(1, Util.reverseUntil(data, data.length, data.length, (char) 3)); - assertEquals(4, Util.reverseUntil(data, data.length, data.length, (char) 28)); - assertEquals(5, Util.reverseUntil(data, data.length, data.length, (char) 29)); - assertEquals(6, Util.reverseUntil(data, data.length, data.length, (char) 30)); - assertEquals(6, Util.reverseUntil(data, data.length, data.length, (char) 31)); - assertEquals(7, Util.reverseUntil(data, data.length, data.length, (char) -342)); - } - - @Test - public void testIterateUntil() { - char[] data = fromShorts(new short[]{0, 3, 16, 18, 21, 29, 30,-342}); - assertEquals(1, Util.iterateUntil(data, 0, data.length, ((char) 3))); - assertEquals(5, Util.iterateUntil(data, 0, data.length, ((char) 28))); - assertEquals(5, Util.iterateUntil(data, 0, data.length, ((char) 29))); - assertEquals(7, Util.iterateUntil(data, 0, data.length, ((char) -342))); - } - - static char[] fromShorts(short[] array) { - char[] result = new char[array.length]; - for (int i = 0 ; i < array.length; ++i) { - result[i] = (char)(array[i] & 0xFFFF); - } - return result; - } - - public static Stream sets() { - return Stream.of( - Arguments.of(rleRegion().toArray(), rleRegion().toArray()), - Arguments.of(denseRegion().toArray(), rleRegion().toArray()), - Arguments.of(sparseRegion().toArray(), rleRegion().toArray()), - Arguments.of(rleRegion().toArray(), denseRegion().toArray()), - Arguments.of(denseRegion().toArray(), denseRegion().toArray()), - Arguments.of(sparseRegion().toArray(), denseRegion().toArray()), - Arguments.of(rleRegion().toArray(), sparseRegion().toArray()), - Arguments.of(denseRegion().toArray(), sparseRegion().toArray()), - Arguments.of(sparseRegion().toArray(), sparseRegion().toArray()) - ); - } - - - @MethodSource("sets") - @ParameterizedTest - public void testIntersectBitmapWithArray(int[] set1, int[] set2) { - long[] bitmap = new long[1024]; - for (int i : set1) { - bitmap[i >>> 6] |= 1L << i; - } - long[] referenceBitmap = new long[1024]; - char[] array = new char[set2.length]; - int pos = 0; - for (int i : set2) { - referenceBitmap[i >>> 6] |= 1L << i; - array[pos++] = (char)i; - } - int expectedCardinality = 0; - for (int i = 0; i < 1024; ++i) { - referenceBitmap[i] &= bitmap[i]; - expectedCardinality += Long.bitCount(referenceBitmap[i]); - } - int cardinality = Util.intersectArrayIntoBitmap(bitmap, array, array.length); - assertEquals(expectedCardinality, cardinality); - assertArrayEquals(referenceBitmap, bitmap); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/UnorderedRoaringBitmapWriterRandomisedTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/UnorderedRoaringBitmapWriterRandomisedTest.java deleted file mode 100644 index 4fff1ae22..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/UnorderedRoaringBitmapWriterRandomisedTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.roaringbitmap; - - -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - - -@Execution(ExecutionMode.CONCURRENT) -public class UnorderedRoaringBitmapWriterRandomisedTest { - - - public static Stream tests() { - return Stream.of( - Arguments.of(generateUnorderedArray(0)), - Arguments.of(generateUnorderedArray(10)), - Arguments.of(generateUnorderedArray(100)), - Arguments.of(generateUnorderedArray(1000)), - Arguments.of(generateUnorderedArray(10000)), - Arguments.of(generateUnorderedArray(100000)), - Arguments.of(generateUnorderedArray(1000000))); - } - - @ParameterizedTest - @MethodSource("tests") - public void bitmapOfUnorderedShouldBuildSameBitmapAsBitmapOf(int[] data) { - RoaringBitmap baseline = RoaringBitmap.bitmapOf(data); - RoaringBitmap test = RoaringBitmap.bitmapOfUnordered(data); - RoaringArray baselineHLC = baseline.highLowContainer; - RoaringArray testHLC = test.highLowContainer; - assertEquals(baselineHLC.size, testHLC.size); - for (int i = 0; i < baselineHLC.size; ++i) { - Container baselineContainer = baselineHLC.getContainerAtIndex(i); - Container rbContainer = testHLC.getContainerAtIndex(i); - assertEquals(baselineContainer, rbContainer); - } - assertEquals(baseline, test); - } - - private static int[] generateUnorderedArray(int size) { - if (size == 0) { - return new int[0]; - } - Random random = new Random(); - List ints = new ArrayList<>(size); - int last = 0; - for (int i = 0; i < size; ++i) { - if (random.nextGaussian() > 0.1) { - last = last + 1; - } else { - last = last + 1 + random.nextInt(99); - } - ints.add(last); - } - Collections.shuffle(ints); - int[] data = new int[size]; - int i = 0; - for (Integer value : ints) { - data[i++] = value; - } - return data; - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/BufferContainerBatchIteratorTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/BufferContainerBatchIteratorTest.java deleted file mode 100644 index f446e9b3d..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/BufferContainerBatchIteratorTest.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.roaringbitmap.buffer; - - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.roaringbitmap.Container; -import org.roaringbitmap.ContainerBatchIterator; -import org.roaringbitmap.SeededTestData; - -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static java.util.Arrays.copyOfRange; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -@Execution(ExecutionMode.CONCURRENT) -public class BufferContainerBatchIteratorTest { - - private static int[][] DATA; - - @BeforeAll - public static void setup() { - DATA = Stream.of( - IntStream.range(0, 20000).toArray(), - IntStream.range(0, 1 << 16).toArray(), - IntStream.range(0, 1 << 16).filter(i -> i < 500 || i > 2000).filter(i -> i < (1 << 15) || i > ((1 << 15) | (1 << 8))).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 12) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 11) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 10) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 9) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 8) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 7) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 6) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 5) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 4) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 3) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 2) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> ((i >>> 1) & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 3) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 5) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 7) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 9) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 271) == 0).toArray(), - IntStream.range(0, 1 << 16).filter(i -> (i % 1000) == 0).toArray(), - IntStream.empty().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.sparseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.denseRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray(), - SeededTestData.rleRegion().toArray()).toArray(int[][]::new); - } - - @AfterAll - public static void clear() { - DATA = null; - } - - public static Stream params() { - return Stream.of(DATA) - .flatMap(array -> IntStream.concat(IntStream.of( - 512, 1024, 2048, 4096, 8192, 65536 - ), IntStream.range(0, 100).map(i -> ThreadLocalRandom.current().nextInt(1, 65536))) - .mapToObj(i -> Arguments.of(array, i))); - } - - - @ParameterizedTest(name = "{1}") - @MethodSource("params") - public void test(int[] expectedValues, int batchSize) { - int[] buffer = new int[batchSize]; - MappeableContainer container = createContainer(expectedValues); - ContainerBatchIterator it = container.getBatchIterator(); - int cardinality = 0; - while (it.hasNext()) { - int from = cardinality; - cardinality += it.next(0, buffer); - assertArrayEquals( - copyOfRange(expectedValues, from, cardinality), copyOfRange(buffer, 0, cardinality - from), - "Failure with batch size " + batchSize); - } - assertEquals(expectedValues.length, cardinality); - } - - - @ParameterizedTest(name = "{1}") - @MethodSource("params") - public void testAdvanceIfNeeded(int[] expectedValues, int batchSize) { - if (expectedValues.length < 2) { - return; - } - int[] buffer = new int[batchSize]; - MappeableContainer container = createContainer(expectedValues); - ContainerBatchIterator it = container.getBatchIterator(); - int cardinality = expectedValues.length / 2; - int advanceUntil = expectedValues[cardinality]; - it.advanceIfNeeded((char) advanceUntil); - while (it.hasNext()) { - int from = cardinality; - cardinality += it.next(0, buffer); - assertArrayEquals( - copyOfRange(expectedValues, from, cardinality), copyOfRange(buffer, 0, cardinality - from), - "Failure with batch size " + batchSize + " and container type " + container.getContainerName()); - } - assertEquals(expectedValues.length, cardinality); - } - - private MappeableContainer createContainer(int[] expectedValues) { - MappeableContainer container = new MappeableArrayContainer(); - for (int value : expectedValues) { - container = container.add((char) value); - } - return container.runOptimize(); - } -} \ No newline at end of file diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/ImmutableRoaringBitmapBatchIteratorTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/ImmutableRoaringBitmapBatchIteratorTest.java deleted file mode 100644 index 4adeb5654..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/ImmutableRoaringBitmapBatchIteratorTest.java +++ /dev/null @@ -1,195 +0,0 @@ -package org.roaringbitmap.buffer; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.roaringbitmap.BatchIterator; -import org.roaringbitmap.IntIterator; -import org.roaringbitmap.RoaringBitmapWriter; - -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.RoaringBitmapWriter.bufferWriter; -import static org.roaringbitmap.SeededTestData.TestDataSet.testCase; - -@Execution(ExecutionMode.CONCURRENT) -public class ImmutableRoaringBitmapBatchIteratorTest { - - private static ImmutableRoaringBitmap[] BITMAPS; - - private static final int[] SIZES = { - 128, 256, 1024, 8192, 5, 127, 1023 - }; - - @BeforeAll - public static void beforeAll() { - BITMAPS = new ImmutableRoaringBitmap[] { - testCase().withArrayAt(0).withArrayAt(2).withArrayAt(4).withArrayAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withRunAt(0).withRunAt(2).withRunAt(4).withRunAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withRunAt(2).withBitmapAt(4).withBitmapAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).withBitmapAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withRunAt(0).withArrayAt(2).withBitmapAt(4).withRunAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withRunAt(2).withArrayAt(4).withBitmapAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).withArrayAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withArrayAt(2).withBitmapAt(4).withRunAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - testCase().withRunAt((1 << 15) | (1 << 11)).withBitmapAt((1 << 15) | (1 << 12)).withArrayAt((1 << 15) | (1 << 13)).withBitmapAt((1 << 15) | (1 << 14)).build().toMutableRoaringBitmap(), - MutableRoaringBitmap.bitmapOf(IntStream.range(1 << 10, 1 << 26).filter(i -> (i & 1) == 0).toArray()), - MutableRoaringBitmap.bitmapOf(IntStream.range(1 << 10, 1 << 25).filter(i -> ((i >>> 8) & 1) == 0).toArray()), - MutableRoaringBitmap.bitmapOf(IntStream.range(0,127).toArray()), - MutableRoaringBitmap.bitmapOf(IntStream.range(0,1024).toArray()), - MutableRoaringBitmap.bitmapOf(IntStream.concat(IntStream.range(0,256), IntStream.range(1 << 16, (1 << 16) | 256)).toArray()), - ImmutableRoaringBitmap.bitmapOf(8511), - new MutableRoaringBitmap() - }; - } - - @AfterAll - public static void clear() { - BITMAPS = null; - } - - public static Stream params() { - return Stream.of(BITMAPS) - .flatMap(bitmap -> IntStream.of(SIZES).mapToObj(i -> Arguments.of(bitmap, i))); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAsIntIterator(MutableRoaringBitmap bitmap, int batchSize) { - IntIterator it = bitmap.getBatchIterator().asIntIterator(new int[batchSize]); - RoaringBitmapWriter w = bufferWriter().constantMemory() - .initialCapacity(bitmap.highLowContainer.size()).get(); - while (it.hasNext()) { - w.add(it.next()); - } - MutableRoaringBitmap copy = w.get(); - assertEquals(bitmap, copy); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void test(MutableRoaringBitmap bitmap, int batchSize) { - int[] buffer = new int[batchSize]; - MutableRoaringBitmap result = new MutableRoaringBitmap(); - BatchIterator it = bitmap.getBatchIterator(); - int cardinality = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - cardinality += batch; - } - assertEquals(bitmap, result); - assertEquals(bitmap.getCardinality(), cardinality); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAdvancedIfNeeded(MutableRoaringBitmap bitmap, int batchSize) { - final int cardinality = bitmap.getCardinality(); - if (cardinality < 2) { - return; - } - int midpoint = bitmap.select(cardinality / 2); - int[] buffer = new int[batchSize]; - MutableRoaringBitmap result = new MutableRoaringBitmap(); - BatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded(midpoint); - int consumed = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - consumed += batch; - } - MutableRoaringBitmap expected = bitmap.clone(); - expected.remove(0, midpoint & 0xFFFFFFFFL); - assertEquals(expected, result); - assertEquals(expected.getCardinality(), consumed); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAdvancedIfNeededToAbsentValue(MutableRoaringBitmap bitmap, int batchSize) { - long firstAbsent = bitmap.nextAbsentValue(0); - int[] buffer = new int[batchSize]; - MutableRoaringBitmap result = new MutableRoaringBitmap(); - BatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded((int) firstAbsent); - int consumed = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - consumed += batch; - } - MutableRoaringBitmap expected = bitmap.clone(); - expected.remove(0, firstAbsent & 0xFFFFFFFFL); - assertEquals(expected, result); - assertEquals(expected.getCardinality(), consumed); - } - - @ParameterizedTest(name="offset={1}") - @MethodSource("params") - public void testBatchIteratorAdvancedIfNeededBeyondLastValue(MutableRoaringBitmap bitmap, int batchSize) { - long advanceTo = bitmap.isEmpty() ? 0 : bitmap.last() + 1; - int[] buffer = new int[batchSize]; - MutableRoaringBitmap result = new MutableRoaringBitmap(); - BatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded((int) advanceTo); - int consumed = 0; - while (it.hasNext()) { - int batch = it.nextBatch(buffer); - for (int i = 0; i < batch; ++i) { - result.add(buffer[i]); - } - consumed += batch; - } - assertEquals(0, consumed); - assertTrue(result.isEmpty()); - } - - @Test - public void testTimelyTermination() { - ImmutableRoaringBitmap bm = ImmutableRoaringBitmap.bitmapOf(8511); - BatchIterator bi = bm.getBatchIterator(); - int[] batch = new int[10]; - assertTrue(bi.hasNext()); - int n = bi.nextBatch(batch); - assertEquals(n, 1); - assertEquals(batch[0], 8511); - assertFalse(bi.hasNext()); - } - @Test - public void testTimelyTerminationAfterAdvanceIfNeeded() { - ImmutableRoaringBitmap bm = ImmutableRoaringBitmap.bitmapOf(8511); - BatchIterator bi = bm.getBatchIterator(); - assertTrue(bi.hasNext()); - bi.advanceIfNeeded(8512); - assertFalse(bi.hasNext()); - } - - @Test - public void testBatchIteratorWithAdvanceIfNeeded() { - MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(3 << 16, (3 << 16) + 5, (3 << 16) + 10); - BatchIterator it = bitmap.getBatchIterator(); - it.advanceIfNeeded(6); - assertTrue(it.hasNext()); - int[] batch = new int[10]; - int n = it.nextBatch(batch); - assertEquals(n, 3); - assertEquals(batch[0], 3 << 16); - assertEquals(batch[1], (3 << 16) + 5); - assertEquals(batch[2], (3 << 16) + 10); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringBitmapSubsetTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringBitmapSubsetTest.java deleted file mode 100644 index c3c35222e..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringBitmapSubsetTest.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.roaringbitmap.buffer; - -import com.google.common.collect.*; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class MutableRoaringBitmapSubsetTest { - - - private static final Predicate DIVISIBLE_BY_4 = i -> i % 4 == 0; - - private static final Predicate DIVISIBLE_BY_3 = i -> i % 3 == 0; - - - public static Stream params() { - return Stream.of( - Arguments.of( // array vs array - ImmutableSet.of(1, 2, 3, 4), - ImmutableSet.of(2, 3) - ), - Arguments.of( // array vs empty - ImmutableSet.of(1, 2, 3, 4), - ImmutableSet.of() - ), - Arguments.of( // identical arrays - ImmutableSet.of(1, 2, 3, 4), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // disjoint arrays - ImmutableSet.of(10, 12, 14, 15), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of(// disjoint arrays, cardinality mismatch - ImmutableSet.of(10, 12, 14), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // run vs array, subset - ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // run vs array, subset - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of(1, 2, 3, 4) - ), - Arguments.of( // run vs empty - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of() - ), - Arguments.of( // identical runs, 1 container - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()) - ), - Arguments.of( // identical runs, 2 containers - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()), - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()) - ), - Arguments.of( // disjoint array vs run, either side of container boundary - ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of((1 << 16) + 1, (1 << 16) + 2, (1 << 16) + 3, (1 << 16) + 4) - ), - Arguments.of( // disjoint array vs run - ContiguousSet.create(Range.closed(3, 1 << 16), DiscreteDomain.integers()), - ImmutableSet.of(1, 2) - ), - Arguments.of( // run vs run, overlap with shift - ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()), - ContiguousSet.create(Range.closed(1 << 4, 1 << 12), DiscreteDomain.integers()) - ), - Arguments.of( // run vs run, subset - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()), - ImmutableSet.of(1, 1 << 8) - ), - Arguments.of( // run vs run, overlap with shift, 2 containers - ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()), - ImmutableSet.of(1 << 6, 1 << 26) - ), - Arguments.of( // run vs 2 container run, overlap - ImmutableSet.of(1, 1 << 16), - ContiguousSet.create(Range.closed(0, 1 << 20), DiscreteDomain.integers()) - ), - Arguments.of( // bitmap vs intersecting array - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.of(4, 8) - ), - Arguments.of( // bitmap vs bitmap, cardinality mismatch - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 16), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // bitmap vs empty - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.of() - ), - Arguments.of( // identical bitmaps - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // bitmap vs overlapping but disjoint array - ImmutableSet.of(3, 7), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // bitmap vs overlapping but disjoint bitmap - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_3::test)), - ImmutableSet.copyOf(Iterables.filter(ContiguousSet.create(Range.closed(1, 1 << 15), - DiscreteDomain.integers()), - DIVISIBLE_BY_4::test)) - ), - Arguments.of( // disjoint, large (signed-negative) keys - ImmutableSet.of(0xbf09001d, 0xbf090169), - ImmutableSet.of(0x8088000e, 0x80880029) - )); - } - - - @ParameterizedTest - @MethodSource("params") - public void testProperSubset(Set superSet, Set subSet) { - MutableRoaringBitmap superSetRB = create(superSet); - MutableRoaringBitmap subSetRB = create(subSet); - assertEquals(superSet.containsAll(subSet), superSetRB.contains(subSetRB)); - // reverse the test - assertEquals(subSet.containsAll(superSet), subSetRB.contains(superSetRB)); - } - - private MutableRoaringBitmap create(Set set) { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - if (set instanceof ContiguousSet) { - ContiguousSet contiguousSet = (ContiguousSet) set; - rb.add(contiguousSet.first().longValue(), contiguousSet.last().longValue()); - } else { - for (Integer i : set) { - rb.add(i); - } - } - return rb; - } - - -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/RoaringBitmapIntervalIntersectionTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/RoaringBitmapIntervalIntersectionTest.java deleted file mode 100644 index 9a6dcb1f3..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/RoaringBitmapIntervalIntersectionTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.roaringbitmap.buffer; - - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.roaringbitmap.RoaringBitmap; - -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.roaringbitmap.SeededTestData.TestDataSet.testCase; - -@Execution(ExecutionMode.CONCURRENT) -public class RoaringBitmapIntervalIntersectionTest { - - private static Arguments[] ARGS; - - @BeforeAll - public static void before() { - ARGS = new Arguments[] { - Arguments.of(RoaringBitmap.bitmapOf(1, 2, 3).toMutableRoaringBitmap(), 0, 1 << 16), - Arguments.of(RoaringBitmap.bitmapOf(1, 2, 3).toMutableRoaringBitmap(), 1, 1), - Arguments.of(RoaringBitmap.bitmapOf(1 << 31 | 1 << 30).toMutableRoaringBitmap(), 0, 1 << 16), - Arguments.of(RoaringBitmap.bitmapOf(1 << 31 | 1 << 30).toMutableRoaringBitmap(), 0, 256), - Arguments.of(RoaringBitmap.bitmapOf(1, 1 << 31 | 1 << 30).toMutableRoaringBitmap(), 0, 256), - Arguments.of(RoaringBitmap.bitmapOf(1, 1 << 16, 1 << 31 | 1 << 30).toMutableRoaringBitmap(), 0, 1L << 32), - Arguments.of(testCase().withArrayAt(10).withBitmapAt(20).withRunAt(30) - .withRange(70000L, 150000L).build().toMutableRoaringBitmap(), 70000L, 150000L), - Arguments.of(testCase().withArrayAt(10).withBitmapAt(20).withRunAt(30) - .withRange(70000L, 150000L).build().toMutableRoaringBitmap(), 71000L, 140000L), - Arguments.of(testCase().withArrayAt(0).withBitmapAt(1).withRunAt(20).build().toMutableRoaringBitmap(), 67000, 150000), - Arguments.of(testCase().withBitmapAt(0).withArrayAt(1).withRunAt(20).build().toMutableRoaringBitmap(), 67000, 150000), - Arguments.of(testCase().withBitmapAt(0).withRunAt(1).withArrayAt(20).build().toMutableRoaringBitmap(), 67000, 150000), - Arguments.of(testCase().withArrayAt(0) - .withArrayAt(1) - .withArrayAt(2) - .withBitmapAt(200) - .withRunAt(205).build().toMutableRoaringBitmap(), 199 * (1 << 16), 200 * (1 << 16) + (1 << 14)) - }; - } - - @AfterAll - public static void after() { - ARGS = null; - } - - - public static Stream params() { - return Stream.of(ARGS); - } - - - @ParameterizedTest - @MethodSource("params") - public void test(MutableRoaringBitmap bitmap, long minimum, long supremum) { - MutableRoaringBitmap test = new MutableRoaringBitmap(); - test.add(minimum, supremum); - assertEquals(ImmutableRoaringBitmap.intersects(bitmap, test), bitmap.intersects(minimum, supremum)); - } - - @ParameterizedTest - @MethodSource("params") - public void testIntersects(MutableRoaringBitmap bitmap, long minimum, long supremum) { - MutableRoaringBitmap test = new MutableRoaringBitmap(); - test.add(minimum, supremum); - assertEquals(MutableRoaringBitmap.intersects(bitmap, test), bitmap.intersects(minimum, supremum)); - } - - @ParameterizedTest - @MethodSource("params") - public void testContains(MutableRoaringBitmap bitmap, long minimum, long supremum) { - MutableRoaringBitmap test = new MutableRoaringBitmap(); - test.add(minimum, supremum); - assertEquals(!test.isEmpty() && bitmap.contains(test), bitmap.contains(minimum, supremum)); - assertTrue(test.isEmpty() || test.contains(minimum, supremum)); - } - - @ParameterizedTest - @MethodSource("params") - public void ifContainsThenIntersects(MutableRoaringBitmap bitmap, long minimum, long supremum) { - boolean contains = bitmap.contains(minimum, supremum); - boolean intersects = bitmap.intersects(minimum, supremum); - assertTrue(!contains || intersects); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBufferAdversarialInputs.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBufferAdversarialInputs.java deleted file mode 100644 index cd3cf3c7c..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBufferAdversarialInputs.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.roaringbitmap.buffer; - - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.roaringbitmap.TestAdversarialInputs; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.CopyOption; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - - -public class TestBufferAdversarialInputs { - - public static Stream badFiles() { - return TestAdversarialInputs.badFiles(); - } - - // copy to a temporary file - protected static File copy(String resourceName) throws IOException { - File tmpFile = File.createTempFile(TestBufferAdversarialInputs.class.getName(), "bin"); - tmpFile.deleteOnExit(); - - try (InputStream input = TestAdversarialInputs.openInputstream(resourceName)) { - Files.copy(input, tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - } - - return tmpFile; - } - - public ByteBuffer memoryMap(String resourceName) throws IOException { - File tmpfile = copy(resourceName); - long totalcount = tmpfile.length(); - RandomAccessFile memoryMappedFile = new RandomAccessFile(tmpfile, "r"); - ByteBuffer bb = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, totalcount); // even though we have two bitmaps, we have one map, maps are expensive!!! - memoryMappedFile.close(); // we can safely close - bb.position(0); - return bb; - } - - @Test - public void testInputGoodFile1() throws IOException { - File file = copy("/testdata/bitmapwithruns.bin"); - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - // should not throw an exception - rb.deserialize(new DataInputStream(new FileInputStream(file))); - assertEquals(rb.getCardinality(), 200100); - file.delete(); - } - - @Test - public void testInputGoodFile1Mapped() throws IOException { - ByteBuffer bb = memoryMap("/testdata/bitmapwithruns.bin"); - ImmutableRoaringBitmap rb = new ImmutableRoaringBitmap(bb); - assertEquals(rb.getCardinality(), 200100); - } - - @Test - public void testInputGoodFile2() throws IOException { - File file = copy("/testdata/bitmapwithoutruns.bin"); - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - // should not throw an exception - rb.deserialize(new DataInputStream(new FileInputStream(file))); - assertEquals(rb.getCardinality(), 200100); - file.delete(); - } - - @Test - public void testInputGoodFile2Mapped() throws IOException { - ByteBuffer bb = memoryMap("/testdata/bitmapwithoutruns.bin"); - ImmutableRoaringBitmap rb = new ImmutableRoaringBitmap(bb); - assertEquals(rb.getCardinality(), 200100); - } - - @ParameterizedTest - @MethodSource("badFiles") - public void testInputBadFileDeserialize(String file) { - assertThrows(IOException.class, () -> deserialize(file)); - } - - @ParameterizedTest - @MethodSource("badFiles") - public void testInputBadFileMap(String file) { - if (file.endsWith("7.bin")) { - assertThrows(IllegalArgumentException.class, () -> map(file)); - } else { - assertThrows(IndexOutOfBoundsException.class, () -> map(file)); - } - } - - private void deserialize(String fileName) throws IOException { - File file = copy(fileName); - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - // should not work - rb.deserialize(new DataInputStream(new FileInputStream(file))); - file.delete(); - } - - private void map(String fileName) throws IOException { - ByteBuffer bb = memoryMap(fileName); - ImmutableRoaringBitmap rb = new ImmutableRoaringBitmap(bb); - System.out.println(rb.getCardinality()); // won't get here - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBufferRangeCardinality.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBufferRangeCardinality.java deleted file mode 100644 index cf9efd946..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBufferRangeCardinality.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.roaringbitmap.buffer; - - -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.nio.ByteBuffer; -import java.nio.LongBuffer; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - - -public class TestBufferRangeCardinality { - - - public static Stream data() { - return Stream.of( - Arguments.of(new int[]{1, 3, 5, 7, 9}, 3, 8, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 2, 8, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 3, 7, 2), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 0, 7, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9}, 0, 6, 3), - Arguments.of(new int[]{1, 3, 5, 7, 9, Short.MAX_VALUE}, 0, Short.MAX_VALUE + 1, 6), - Arguments.of(new int[]{1, 10000, 25000, Short.MAX_VALUE - 1}, 0, Short.MAX_VALUE, 4), - Arguments.of(new int[]{1 << 3, 1 << 8, 511, 512, 513, 1 << 12, 1 << 14}, 0, Short.MAX_VALUE, 7) - ); - } - - @ParameterizedTest(name = "{index}: cardinalityInBitmapRange({0},{1},{2})={3}") - @MethodSource("data") - public void testCardinalityInBitmapWordRange(int[] elements, int begin, int end, int expected) { - LongBuffer array = ByteBuffer.allocateDirect(MappeableBitmapContainer.MAX_CAPACITY / 8).asLongBuffer(); - MappeableBitmapContainer bc = new MappeableBitmapContainer(array, 0); - for (int e : elements) { - bc.add((char) e); - } - assertFalse(bc.isArrayBacked()); - assertEquals(expected, BufferUtil.cardinalityInBitmapRange(bc.bitmap, begin, end)); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestFastAggregation.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestFastAggregation.java deleted file mode 100644 index 3674be408..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestFastAggregation.java +++ /dev/null @@ -1,301 +0,0 @@ -package org.roaringbitmap.buffer; - - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.roaringbitmap.SeededTestData.TestDataSet.testCase; - -@Execution(ExecutionMode.CONCURRENT) -public class TestFastAggregation { - - private static ImmutableRoaringBitmap toDirect(MutableRoaringBitmap r) { - ByteBuffer buffer = ByteBuffer.allocateDirect(r.serializedSizeInBytes()); - r.serialize(buffer); - buffer.flip(); - return new ImmutableRoaringBitmap(buffer); - } - - private static ImmutableRoaringBitmap toMapped(MutableRoaringBitmap r) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(bos); - try { - r.serialize(dos); - dos.close(); - } catch (IOException e) { - throw new RuntimeException(e.toString()); - } - ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray()); - return new ImmutableRoaringBitmap(bb); - } - - @Test - public void testNaiveAnd() { - int[] array1 = {39173, 39174}; - int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array3 = {39173, 39174}; - int[] array4 = {}; - MutableRoaringBitmap data1 = MutableRoaringBitmap.bitmapOf(array1); - MutableRoaringBitmap data2 = MutableRoaringBitmap.bitmapOf(array2); - MutableRoaringBitmap data3 = MutableRoaringBitmap.bitmapOf(array3); - MutableRoaringBitmap data4 = MutableRoaringBitmap.bitmapOf(array4); - assertEquals(data3, BufferFastAggregation.naive_and(data1, data2)); - assertEquals(new MutableRoaringBitmap(), BufferFastAggregation.naive_and(data4)); - } - - @Test - public void testPriorityQueueOr() { - int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767}; - int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array3 = - {1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array4 = {}; - ArrayList data5 = new ArrayList<>(); - ArrayList data6 = new ArrayList<>(); - MutableRoaringBitmap data1 = MutableRoaringBitmap.bitmapOf(array1); - MutableRoaringBitmap data2 = MutableRoaringBitmap.bitmapOf(array2); - MutableRoaringBitmap data3 = MutableRoaringBitmap.bitmapOf(array3); - MutableRoaringBitmap data4 = MutableRoaringBitmap.bitmapOf(array4); - data5.add(data1); - data5.add(data2); - assertEquals(data3, BufferFastAggregation.priorityqueue_or(data1, data2)); - assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1)); - assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1, data4)); - assertEquals(data3, BufferFastAggregation.priorityqueue_or(data5.iterator())); - assertEquals(new MutableRoaringBitmap(), - BufferFastAggregation.priorityqueue_or(data6.iterator())); - data6.add(data1); - assertEquals(data1, BufferFastAggregation.priorityqueue_or(data6.iterator())); - } - - @Test - public void testPriorityQueueXor() { - assertThrows(IllegalArgumentException.class, () -> { - int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767}; - int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array3 = - {1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178, 39179}; - ImmutableRoaringBitmap data1 = MutableRoaringBitmap.bitmapOf(array1); - ImmutableRoaringBitmap data2 = MutableRoaringBitmap.bitmapOf(array2); - ImmutableRoaringBitmap data3 = MutableRoaringBitmap.bitmapOf(array3); - assertEquals(data3, BufferFastAggregation.priorityqueue_xor(data1, data2)); - BufferFastAggregation.priorityqueue_xor(data1); - }); - } - - - @Test - public void testNaiveAndMapped() { - int[] array1 = {39173, 39174}; - int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array3 = {39173, 39174}; - int[] array4 = {}; - ImmutableRoaringBitmap data1 = toMapped(MutableRoaringBitmap.bitmapOf(array1)); - ImmutableRoaringBitmap data2 = toMapped(MutableRoaringBitmap.bitmapOf(array2)); - ImmutableRoaringBitmap data3 = toMapped(MutableRoaringBitmap.bitmapOf(array3)); - ImmutableRoaringBitmap data4 = toMapped(MutableRoaringBitmap.bitmapOf(array4)); - assertEquals(data3, BufferFastAggregation.naive_and(data1, data2)); - assertEquals(new MutableRoaringBitmap(), BufferFastAggregation.naive_and(data4)); - } - - @Test - public void testPriorityQueueOrMapped() { - int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767}; - int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array3 = - {1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array4 = {}; - ArrayList data5 = new ArrayList<>(); - ArrayList data6 = new ArrayList<>(); - ImmutableRoaringBitmap data1 = toMapped(MutableRoaringBitmap.bitmapOf(array1)); - ImmutableRoaringBitmap data2 = toMapped(MutableRoaringBitmap.bitmapOf(array2)); - ImmutableRoaringBitmap data3 = toMapped(MutableRoaringBitmap.bitmapOf(array3)); - ImmutableRoaringBitmap data4 = toMapped(MutableRoaringBitmap.bitmapOf(array4)); - data5.add(data1); - data5.add(data2); - assertEquals(data3, BufferFastAggregation.priorityqueue_or(data1, data2)); - assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1)); - assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1, data4)); - assertEquals(data3, BufferFastAggregation.priorityqueue_or(data5.iterator())); - assertEquals(new MutableRoaringBitmap(), - BufferFastAggregation.priorityqueue_or(data6.iterator())); - data6.add(data1); - assertEquals(data1, BufferFastAggregation.priorityqueue_or(data6.iterator())); - } - - public void testBigOrMapped() { - MutableRoaringBitmap rb1 = new MutableRoaringBitmap(); - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - MutableRoaringBitmap rb3 = new MutableRoaringBitmap(); - for(int k = 100; k < 10000; ++k) { - if((k % 3) == 0) { - rb1.add(k); - } - if((k % 3) == 1) { - rb2.add(k); - } - if((k % 3) == 2) { - rb3.add(k); - } - } - ImmutableRoaringBitmap data1 = toMapped(rb1); - ImmutableRoaringBitmap data2 = toMapped(rb2); - ImmutableRoaringBitmap data3 = toMapped(rb3); - MutableRoaringBitmap mrb = data1.clone().toMutableRoaringBitmap(); - mrb.add(100L,10000L); - assertEquals(mrb, BufferFastAggregation.or(data1,data2,data3)); - } - - @Test - public void testPriorityQueueXorMapped() { - assertThrows(IllegalArgumentException.class, () -> { - int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767}; - int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179}; - int[] array3 = - {1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178, 39179}; - ImmutableRoaringBitmap data1 = toMapped(MutableRoaringBitmap.bitmapOf(array1)); - ImmutableRoaringBitmap data2 = toMapped(MutableRoaringBitmap.bitmapOf(array2)); - ImmutableRoaringBitmap data3 = toMapped(MutableRoaringBitmap.bitmapOf(array3)); - assertEquals(data3, BufferFastAggregation.priorityqueue_xor(data1, data2)); - BufferFastAggregation.priorityqueue_xor(data1); - }); - } - - - public static Stream bitmaps() { - return Stream.of( - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build().toMutableRoaringBitmap(), - testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build().toMutableRoaringBitmap(), - testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withArrayAt(3).withRunAt(4).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withBitmapAt(1).withRunAt(2).build().toMutableRoaringBitmap(), - testCase().withRunAt(0).withArrayAt(1).withBitmapAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withArrayAt(2).withRunAt(4).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withArrayAt(1).withArrayAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withBitmapAt(2).withBitmapAt(4).build().toMutableRoaringBitmap(), - testCase().withRunAt(0).withRunAt(1).withRunAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withArrayAt(1).withArrayAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withBitmapAt(2).withArrayAt(4).build().toMutableRoaringBitmap(), - testCase().withRunAt(0).withRunAt(1).withArrayAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(0).withArrayAt(1).withBitmapAt(2).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withBitmapAt(2).withBitmapAt(4).build().toMutableRoaringBitmap(), - testCase().withRunAt(0).withRunAt(1).withBitmapAt(2).build().toMutableRoaringBitmap() - )), - Arguments.of(Arrays.asList( - testCase().withArrayAt(20).build().toMutableRoaringBitmap(), - testCase().withBitmapAt(0).withBitmapAt(1).withBitmapAt(4).build().toMutableRoaringBitmap(), - testCase().withRunAt(0).withRunAt(1).withBitmapAt(3).build().toMutableRoaringBitmap() - )) - ); - } - - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testWorkShyAnd") - public void testWorkShyAnd(List list) { - ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]); - long[] buffer = new long[1024]; - MutableRoaringBitmap result = BufferFastAggregation.and(buffer, bitmaps); - MutableRoaringBitmap expected = BufferFastAggregation.naive_and(bitmaps); - assertEquals(expected, result); - result = BufferFastAggregation.and(bitmaps); - assertEquals(expected, result); - result = BufferFastAggregation.workAndMemoryShyAnd(buffer, bitmaps); - assertEquals(expected, result); - } - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testWorkShyAnd") - public void testWorkShyAndIterator(List bitmaps) { - long[] buffer = new long[1024]; - MutableRoaringBitmap result = BufferFastAggregation.and(buffer, bitmaps.iterator()); - MutableRoaringBitmap expected = BufferFastAggregation.naive_and(bitmaps.iterator()); - assertEquals(expected, result); - result = BufferFastAggregation.and(bitmaps.iterator()); - assertEquals(expected, result); - } - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testWorkShyAnd") - public void testWorkShyAndDirect(List list) { - ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]); - for (int i = 0; i < bitmaps.length; ++i) { - bitmaps[i] = toDirect((MutableRoaringBitmap)bitmaps[i]); - } - long[] buffer = new long[1024]; - MutableRoaringBitmap result = BufferFastAggregation.and(buffer, bitmaps); - MutableRoaringBitmap expected = BufferFastAggregation.naive_and(bitmaps); - assertEquals(expected, result); - result = BufferFastAggregation.and(bitmaps); - assertEquals(expected, result); - result = BufferFastAggregation.workAndMemoryShyAnd(buffer, bitmaps); - assertEquals(expected, result); - } - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testAndCardinality") - public void testAndCardinality(List list) { - ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]); - for (int length = 0; length <= bitmaps.length; length++) { - ImmutableRoaringBitmap[] subset = Arrays.copyOf(bitmaps, length); - ImmutableRoaringBitmap and = BufferFastAggregation.and(subset); - int andCardinality = BufferFastAggregation.andCardinality(subset); - assertEquals(and.getCardinality(), andCardinality); - } - } - - @MethodSource("bitmaps") - @ParameterizedTest(name = "testOrCardinality") - public void testOrCardinality(List list) { - ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]); - for (int length = 0; length <= bitmaps.length; length++) { - ImmutableRoaringBitmap[] subset = Arrays.copyOf(bitmaps, length); - ImmutableRoaringBitmap or = BufferFastAggregation.or(subset); - int andCardinality = BufferFastAggregation.orCardinality(subset); - assertEquals(or.getCardinality(), andCardinality); - } - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmapOrNot.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmapOrNot.java deleted file mode 100644 index 09cd36706..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmapOrNot.java +++ /dev/null @@ -1,426 +0,0 @@ -package org.roaringbitmap.buffer; - - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.roaringbitmap.IntIterator; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Base64; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.Util.toUnsignedLong; - -@Execution(ExecutionMode.CONCURRENT) -public class TestImmutableRoaringBitmapOrNot { - - @Test - public void orNot1() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - - rb.add(2); - rb.add(1); - rb.add(1 << 16); // 65536 - rb.add(2 << 16); //131072 - rb.add(3 << 16); //196608 - - rb2.add(1 << 16);// 65536 - rb2.add(3 << 16);//196608 - - rb.orNot(rb2, (4 << 16) - 1); - - assertEquals((4 << 16) - 1, rb.getCardinality()); - - IntIterator iterator = rb.getIntIterator(); - - for (int i = 0; i < (4 << 16) - 1; ++i) { - assertTrue(iterator.hasNext()); - assertEquals(i, iterator.next()); - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNot2() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - - rb.add(0); - rb.add(1 << 16); // 65536 - rb.add(3 << 16); //196608 - - rb2.add((4 << 16) - 1); //262143 - - rb.orNot(rb2, 4 << 16); - - assertEquals((4 << 16) - 1, rb.getCardinality()); - - IntIterator iterator = rb.getIntIterator(); - - for (int i = 0; i < (4 << 16) - 1; ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next()); - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNot3() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - rb.add(2 << 16); - - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - rb2.add(1 << 14); //16384 - rb2.add(3 << 16); //196608 - - rb.orNot(rb2, (5 << 16)); - assertEquals((5 << 16) - 2, rb.getCardinality()); - - IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (5 << 16); ++i) { - if ((i != (1 << 14)) && (i != (3 << 16))) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNot4() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - rb.add(1); - - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - rb2.add(3 << 16); //196608 - - rb.orNot(rb2, (2 << 16) + (2 << 14)); //131072 + 32768 = 163840 - assertEquals((2 << 16) + (2 << 14), rb.getCardinality()); - - IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (2 << 16) + (2 << 14); ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNot5() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - - rb.add(1); - rb.add(1 << 16); // 65536 - rb.add(2 << 16); //131072 - rb.add(3 << 16); //196608 - - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - - rb.orNot(rb2, (5 << 16)); - assertEquals((5 << 16), rb.getCardinality()); - - IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (5 << 16); ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - assertFalse(iterator.hasNext()); - } - - @Test - public void orNot6() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - - rb.add(1); - rb.add((1 << 16) - 1); // 65535 - rb.add(1 << 16); // 65536 - rb.add(2 << 16); //131072 - rb.add(3 << 16); //196608 - - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - - rb.orNot(rb2, (1 << 14)); - - // {[0, 2^14], 65535, 65536, 131072, 196608} - assertEquals((1 << 14) + 4, rb.getCardinality()); - - IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (1 << 14); ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - - assertTrue(iterator.hasNext()); - assertEquals((1 << 16) - 1, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(1 << 16, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(2 << 16, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(3 << 16, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - @Test - public void orNot7() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - - rb.add(1 << 16); // 65536 - rb.add(2 << 16); //131072 - rb.add(3 << 16); //196608 - - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - - rb.orNot(rb2, (1 << 14)); - - // {[0, 2^14], 65536, 131072, 196608} - assertEquals((1 << 14) + 3, rb.getCardinality()); - - IntIterator iterator = rb.getIntIterator(); - for (int i = 0; i < (1 << 14); ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - - - assertTrue(iterator.hasNext()); - assertEquals(1 << 16, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(2 << 16, iterator.next()); - - assertTrue(iterator.hasNext()); - assertEquals(3 << 16, iterator.next()); - - assertFalse(iterator.hasNext()); - } - - - - @Test - public void orNot9() { - MutableRoaringBitmap rb1 = new MutableRoaringBitmap(); - - rb1.add(1 << 16); // 65536 - rb1.add(2 << 16); //131072 - rb1.add(3 << 16); //196608 - - - { - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - MutableRoaringBitmap answer1 = ImmutableRoaringBitmap.orNot(rb1, rb2, (1 << 14)); - - // {[0, 2^14] | {65536} {131072} {196608}} - assertEquals((1 << 14) + 3, answer1.getCardinality()); - - IntIterator iterator1 = answer1.getIntIterator(); - for (int i = 0; i < (1 << 14); ++i) { - assertTrue(iterator1.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator1.next(), "Error on iteration " + i); - } - assertEquals(1 << 16, iterator1.next()); - assertEquals(2 << 16, iterator1.next()); - assertEquals(3 << 16, iterator1.next()); - } - - { - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb1, rb2, (2 << 16)); - - // {[0, 2^16] | 131072, 196608} - assertEquals((2 << 16) + 2, answer.getCardinality()); - - IntIterator iterator = answer.getIntIterator(); - for (int i = 0; i < (2 << 16) + 1; ++i) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - assertEquals(196608, iterator.next()); - } - - - { - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - rb2.add((1 << 16) + (1 << 13)); - rb2.add((1 << 16) + (1 << 14)); - rb2.add((1 << 16) + (1 << 15)); - MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb1, rb2, (2 << 16)); - - // {[0, 2^16] | 196608} - assertEquals((2 << 16) - 1, answer.getCardinality()); - - IntIterator iterator = answer.getIntIterator(); - for (int i = 0; i < (2 << 16) + 1; ++i) { - if ((i != (1 << 16) + (1 << 13)) && (i != (1 << 16) + (1 << 14)) && (i != (1 << 16) + (1 << 15))) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - } - assertEquals(196608, iterator.next()); - } - - { - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - rb2.add(1 << 16); - rb2.add(3 << 16); - rb2.add(4 << 16); - - MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb1, rb2, (5 << 16)); - - // {[0, 2^16]} - assertEquals((5 << 16) - 1, answer.getCardinality()); - - IntIterator iterator = answer.getIntIterator(); - for (int i = 0; i < (5 << 16); ++i) { - if (i != (4 << 16)) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - } - assertFalse(iterator.hasNext(), "Number of elements " + (2 << 16)); - } - - { - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - rb2.add(1 << 16); - rb2.add(3 << 16); - rb2.add(4 << 16); - - MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb2, rb1, (5 << 16)); - - // {[0, 2^16]} - assertEquals((5 << 16) - 1, answer.getCardinality()); - - IntIterator iterator = answer.getIntIterator(); - for (int i = 0; i < (5 << 16); ++i) { - if (i != (2 << 16)) { - assertTrue(iterator.hasNext(), "Error on iteration " + i); - assertEquals(i, iterator.next(), "Error on iteration " + i); - } - } - assertFalse(iterator.hasNext(), "Number of elements " + (2 << 16)); - } - } - - @Test - public void orNot10() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - - rb.add(5); - rb2.add(10); - - rb.orNot(rb2, 6); - - assertEquals(5, rb.last()); - } - - @Test - public void orNot11() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - MutableRoaringBitmap rb2 = new MutableRoaringBitmap(); - - rb.add((int) (65535L * 65536L + 65523)); - rb2.add((int) (65493L * 65536L + 65520)); - - MutableRoaringBitmap rb3 = ImmutableRoaringBitmap.orNot(rb, rb2, 65535L * 65536L + 65524); - - assertEquals((int)(65535L * 65536L + 65523), rb3.last()); - } - - @Test - public void orNotAgainstFullBitmap() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - MutableRoaringBitmap full = new MutableRoaringBitmap(); - full.add(0, 0x40000L); - rb.orNot(full, 0x30000L); - assertTrue(rb.isEmpty()); - } - - @Test - public void orNotNonEmptyAgainstFullBitmap() { - MutableRoaringBitmap rb = MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001); - MutableRoaringBitmap full = new MutableRoaringBitmap(); - full.add((long)0, (long)0x40000); - rb.orNot(full, 0x30000); - assertEquals(MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001), rb); - } - - @Test - public void orNotAgainstFullBitmapStatic() { - MutableRoaringBitmap rb = new MutableRoaringBitmap(); - MutableRoaringBitmap full = new MutableRoaringBitmap(); - full.add(0, 0x40000L); - MutableRoaringBitmap result = ImmutableRoaringBitmap.orNot(rb, full, 0x30000L); - assertTrue(result.isEmpty()); - } - - @Test - public void orNotNonEmptyAgainstFullBitmapStatic() { - MutableRoaringBitmap rb = MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001); - MutableRoaringBitmap full = new MutableRoaringBitmap(); - full.add(0, 0x40000L); - assertEquals(MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001), ImmutableRoaringBitmap.orNot(rb, full, 0x30000L)); - } - - @Test - @SuppressWarnings("unchecked") - public void testBigOrNot() throws IOException { - byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json")); - Map info = new ObjectMapper().readerFor(Map.class).readValue(bytes); - List base64Bitmaps = (List)info.get("bitmaps"); - ByteBuffer lBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(0))); - ByteBuffer rBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(1))); - MutableRoaringBitmap l = new MutableRoaringBitmap(); - l.deserialize(lBuffer); - MutableRoaringBitmap r = new MutableRoaringBitmap(); - r.deserialize(rBuffer); - - MutableRoaringBitmap range = new MutableRoaringBitmap(); - long limit = toUnsignedLong(l.last()) + 1; - range.add(0, limit); - range.andNot(r); - MutableRoaringBitmap expected = MutableRoaringBitmap.or(l, range); - - MutableRoaringBitmap actual = l.clone(); - actual.orNot(r, limit); - assertEquals(expected, actual); - } - - - @Test - @SuppressWarnings("unchecked") - public void testBigOrNotStatic() throws IOException { - byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json")); - Map info = new ObjectMapper().readerFor(Map.class).readValue(bytes); - List base64Bitmaps = (List)info.get("bitmaps"); - ByteBuffer lBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(0))); - ByteBuffer rBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(1))); - MutableRoaringBitmap l = new MutableRoaringBitmap(); - l.deserialize(lBuffer); - MutableRoaringBitmap r = new MutableRoaringBitmap(); - r.deserialize(rBuffer); - - MutableRoaringBitmap range = new MutableRoaringBitmap(); - long limit = toUnsignedLong(l.last()) + 1; - range.add(0, limit); - range.andNot(r); - MutableRoaringBitmap expected = MutableRoaringBitmap.or(l, range); - - MutableRoaringBitmap actual = ImmutableRoaringBitmap.orNot(l, r, limit); - assertEquals(expected, actual); - } - -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainerCharIterator.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainerCharIterator.java deleted file mode 100644 index 85b3f190f..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainerCharIterator.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.roaringbitmap.buffer; - -import com.google.common.primitives.Ints; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.roaringbitmap.PeekableCharIterator; - -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.roaringbitmap.buffer.MappeableArrayContainer.DEFAULT_MAX_SIZE; - -@Execution(ExecutionMode.CONCURRENT) -public class TestMappeableBitmapContainerCharIterator { - - private static List asList(PeekableCharIterator ints) { - int[] values = new int[10]; - int size = 0; - while (ints.hasNext()) { - if (!(size < values.length)) { - values = Arrays.copyOf(values, values.length * 2); - } - values[size++] = ints.next(); - } - return Ints.asList(Arrays.copyOf(values, size)); - } - - @Test - public void testClone() { - MappeableBitmapContainer mappeableBitmapContainer = new MappeableBitmapContainer(); - for (int k = 0; k < 2 * DEFAULT_MAX_SIZE; ++k) { - mappeableBitmapContainer.add((char) (k * 10)); - } - MappeableBitmapContainerCharIterator tmbc = new MappeableBitmapContainerCharIterator(mappeableBitmapContainer); - PeekableCharIterator tmbcClone = tmbc.clone(); - assertNotNull(tmbcClone); - final List tmbcList = asList(tmbc); - final List tmbcCloneList = asList(tmbcClone); - assertEquals(tmbcList, tmbcCloneList); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestReverseMappeableRunContainer.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestReverseMappeableRunContainer.java deleted file mode 100644 index ea5949550..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestReverseMappeableRunContainer.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.roaringbitmap.buffer; - -import com.google.common.primitives.Ints; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.roaringbitmap.CharIterator; - -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -@Execution(ExecutionMode.CONCURRENT) -public class TestReverseMappeableRunContainer { - - private static List asList(CharIterator ints) { - int[] values = new int[10]; - int size = 0; - while (ints.hasNext()) { - if (!(size < values.length)) { - values = Arrays.copyOf(values, values.length * 2); - } - values[size++] = ints.next(); - } - return Ints.asList(Arrays.copyOf(values, size)); - } - - @Test - public void testClone() { - MappeableRunContainer mappeableRunContainer = new MappeableRunContainer(); - for (char i = 10; i < 20; ++i) { - mappeableRunContainer.add(i); - } - ReverseMappeableRunContainerCharIterator rmr = new ReverseMappeableRunContainerCharIterator(mappeableRunContainer); - CharIterator rmrClone = rmr.clone(); - final List rmrList = asList(rmr); - assertNotNull(rmrClone); - final List rmrCloneList = asList(rmrClone); - assertEquals(rmrList, rmrCloneList); - } - - @Test - public void testNextAsInt() { - MappeableRunContainer mappeableRunContainer = new MappeableRunContainer(); - for (char i = 10; i < 15; ++i) { - mappeableRunContainer.add(i); - } - ReverseMappeableRunContainerCharIterator rmr = new ReverseMappeableRunContainerCharIterator(mappeableRunContainer); - assertEquals(14, rmr.nextAsInt()); - rmr.next(); - rmr.next(); - rmr.next(); - rmr.next(); - rmr.next(); - rmr.nextAsInt(); - rmr.nextAsInt(); - rmr.nextAsInt(); - rmr.nextAsInt(); - rmr.nextAsInt(); - assertEquals(13, rmr.nextAsInt()); - } -} - - diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestUtil.java b/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestUtil.java deleted file mode 100644 index db70f4c07..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestUtil.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.roaringbitmap.buffer; - - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.roaringbitmap.Util; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.LongBuffer; -import java.util.Arrays; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.*; -import static org.roaringbitmap.SeededTestData.*; -import static org.roaringbitmap.SeededTestData.sparseRegion; - -@Execution(ExecutionMode.CONCURRENT) -public class TestUtil { - - @Test - public void testCopy() { - CharBuffer sb = CharBuffer.allocate(64); - sb.position(32); - CharBuffer slice = sb.slice(); - CharBuffer dest = CharBuffer.allocate(64); - for(int k = 0; k < 32; ++k) - slice.put(k, (char) k); - BufferUtil.arraycopy(slice, 16, dest, 16, 16); - for(int k = 16; k < 32; ++k) - assertEquals((char)k,dest.get(k)); - BufferUtil.arraycopy(slice, 0, dest, 16, 16); - for(int k = 16; k < 32; ++k) - assertEquals((char)(k-16),dest.get(k)); - BufferUtil.arraycopy(slice, 16, dest, 0, 16); - for(int k = 0; k < 16; ++k) - assertEquals((char)(k+16),dest.get(k)); - - } - - @Test - public void testFillArrayANDNOT() { - LongBuffer data1 = LongBuffer.wrap(new long[]{1, 2, 4, 8, 16}); - LongBuffer data2 = LongBuffer.wrap(new long[]{2, 1, 3, 7, 15}); - char[] content = new char[5]; - char[] result = {0, 65, 130, 195, 260}; - BufferUtil.fillArrayANDNOT(content, data1, data2); - assertTrue(Arrays.equals(content, result)); - } - - @Test - public void testFillArrayANDNOTException() { - assertThrows(IllegalArgumentException.class, () -> { - LongBuffer data1 = LongBuffer.wrap(new long[]{1, 2, 4, 8, 16}); - LongBuffer data2 = LongBuffer.wrap(new long[]{2, 1, 3, 7}); - char[] content = new char[5]; - BufferUtil.fillArrayANDNOT(content, data1, data2); - }); - } - - - - @Test - public void testUnsignedIntersects() { - CharBuffer data1 = CharBuffer.wrap(fromShorts(new short[]{-100, -98, -96, -94, -92, -90, -88, -86, -84, -82, -80})); - CharBuffer data2 = CharBuffer.wrap(fromShorts(new short[]{-99, -97, -95, -93, -91, -89, -87, -85, -83, -81, -79})); - CharBuffer data3 = CharBuffer.wrap(fromShorts(new short[]{-99, -97, -95, -93, -91, -89, -87, -85, -83, -81, -80})); - CharBuffer data4 = CharBuffer.wrap(new char[]{}); - CharBuffer data5 = CharBuffer.wrap(new char[]{}); - assertFalse(BufferUtil.unsignedIntersects(data1, data1.limit(), data2, data2.limit())); - assertTrue(BufferUtil.unsignedIntersects(data1, data1.limit(), data3, data3.limit())); - assertFalse(BufferUtil.unsignedIntersects(data4, data4.limit(), data5, data5.limit())); - } - - @Test - public void testAdvanceUntil() { - CharBuffer data = CharBuffer.wrap(fromShorts(new short[] {0, 3, 16, 18, 21, 29, 30, -342})); - assertEquals(1, BufferUtil.advanceUntil(data, -1, data.limit(), (char) 3)); - assertEquals(5, BufferUtil.advanceUntil(data, -1, data.limit(), (char) 28)); - assertEquals(5, BufferUtil.advanceUntil(data, -1, data.limit(), (char) 29)); - assertEquals(7, BufferUtil.advanceUntil(data, -1, data.limit(), (char) -342)); - } - - @Test - public void testIterateUntil() { - CharBuffer data = CharBuffer.wrap(fromShorts(new short[] {0, 3, 16, 18, 21, 29, 30, -342})); - assertEquals(1, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) 3))); - assertEquals(5, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) 28))); - assertEquals(5, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) 29))); - assertEquals(7, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) -342))); - } - - static char[] fromShorts(short[] array) { - char[] result = new char[array.length]; - for (int i = 0 ; i < array.length; ++i) { - result[i] = (char)(array[i] & 0xFFFF); - } - return result; - } - - public static Stream sets() { - return Stream.of(true, false) - .flatMap(direct -> Stream.of( - Arguments.of(direct, rleRegion().toArray(), rleRegion().toArray()), - Arguments.of(direct, denseRegion().toArray(), rleRegion().toArray()), - Arguments.of(direct, sparseRegion().toArray(), rleRegion().toArray()), - Arguments.of(direct, rleRegion().toArray(), denseRegion().toArray()), - Arguments.of(direct, denseRegion().toArray(), denseRegion().toArray()), - Arguments.of(direct, sparseRegion().toArray(), denseRegion().toArray()), - Arguments.of(direct, rleRegion().toArray(), sparseRegion().toArray()), - Arguments.of(direct, denseRegion().toArray(), sparseRegion().toArray()), - Arguments.of(direct, sparseRegion().toArray(), sparseRegion().toArray()))); - } - - - @MethodSource("sets") - @ParameterizedTest(name = "direct={0}") - public void testIntersectBitmapWithArray(boolean direct, int[] set1, int[] set2) { - LongBuffer bitmap = direct ? ByteBuffer.allocateDirect(8192).asLongBuffer() : LongBuffer.allocate(1024); - for (int i : set1) { - bitmap.put(i >>> 6, bitmap.get(i >>> 6) | (1L << i)); - } - LongBuffer referenceBitmap = direct ? ByteBuffer.allocateDirect(8192).asLongBuffer() : LongBuffer.allocate(1024); - CharBuffer array = direct ? ByteBuffer.allocateDirect(2 * set2.length).asCharBuffer() : CharBuffer.allocate(set2.length); - int pos = 0; - for (int i : set2) { - referenceBitmap.put(i >>> 6, referenceBitmap.get(i >>> 6) | (1L << i)); - array.put(pos++, (char)i); - } - int expectedCardinality = 0; - for (int i = 0; i < 1024; ++i) { - referenceBitmap.put(i, referenceBitmap.get(i) & bitmap.get(i)); - expectedCardinality += Long.bitCount(referenceBitmap.get(i)); - } - int cardinality = BufferUtil.intersectArrayIntoBitmap(bitmap, array, set2.length); - assertEquals(expectedCardinality, cardinality); - for (int i = 0; i < bitmap.limit(); ++i) { - assertEquals(bitmap.get(i), referenceBitmap.get(i), "mismatch at " + i); - } - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/JolBenchmarksTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/JolBenchmarksTest.java deleted file mode 100644 index 3e2c0b46b..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/JolBenchmarksTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.roaringbitmap.longlong; - -import com.google.common.primitives.Ints; -import org.openjdk.jol.info.GraphLayout; - -import java.util.Arrays; -import java.util.Random; -import java.util.stream.IntStream; -import java.util.stream.LongStream; - -/** - * This runs benchmarks over {@link Roaring64NavigableMap} memory layout, as suggested in - * https://github.com/RoaringBitmap/RoaringBitmap/issues/346 - */ -// https://github.com/openjdk/jol -// https://github.com/RoaringBitmap/RoaringBitmap/issues/346 -public class JolBenchmarksTest { - - @SuppressWarnings("restriction") - public static void main(String[] args) { - // distinctHigherRadices(); - // sameHigherRadix(); - statisticsWithGrowingSizes(); - } - - private static void distinctHigherRadices() { - int valuesPerRadix = 1 << 16; - int distance = 2000; - Roaring64NavigableMap bitmapMap = new Roaring64NavigableMap(); - long[] radices = new long[1024]; - for (int i = 0; i < radices.length; ++i) { - radices[i] = ((long) i) << 48; - } - for (int i = 0; i < radices.length; i++) { - for (int j = 0; j < valuesPerRadix; ++j) { - bitmapMap.addLong(radices[i] | (j * distance)); - } - } - - long[] bitmapArray = bitmapMap.toArray(); - - Roaring64Bitmap bitmapArt = new Roaring64Bitmap(); - bitmapArt.add(bitmapArray); - - System.out.println("---distinctHigherRadices---"); - System.out.println(GraphLayout.parseInstance(bitmapArray).toFootprint()); - - System.out.println("---"); - System.out.println(GraphLayout.parseInstance(bitmapMap).toFootprint()); - System.out.println(bitmapMap.getLongSizeInBytes()); - bitmapMap.runOptimize(); - System.out.println(GraphLayout.parseInstance(bitmapMap).toFootprint()); - System.out.println(bitmapMap.getLongSizeInBytes()); - - System.out.println("---"); - System.out.println(GraphLayout.parseInstance(bitmapArt).toFootprint()); - System.out.println(bitmapArt.getLongSizeInBytes()); - bitmapArt.runOptimize(); - System.out.println(GraphLayout.parseInstance(bitmapArt).toFootprint()); - System.out.println(bitmapArt.getLongSizeInBytes()); - } - - private static void sameHigherRadix() { - int numValues = (1 << 16) * 1024; - int distance = 2000; - Roaring64NavigableMap bitmap = new Roaring64NavigableMap(); - - long x = 0L; - for (int i = 0; i < numValues; i++) { - bitmap.addLong(x); - x += distance; - } - - long[] array = bitmap.toArray(); - - Roaring64Bitmap bitmapOpt = new Roaring64Bitmap(); - bitmapOpt.add(array); - - System.out.println("---sameHigherRadix---"); - System.out.println(GraphLayout.parseInstance(array).toFootprint()); - - System.out.println("---"); - System.out.println(GraphLayout.parseInstance(bitmap).toFootprint()); - bitmap.runOptimize(); - System.out.println(GraphLayout.parseInstance(bitmap).toFootprint()); - - System.out.println("---"); - System.out.println(GraphLayout.parseInstance(bitmapOpt).toFootprint()); - bitmapOpt.runOptimize(); - System.out.println(GraphLayout.parseInstance(bitmapOpt).toFootprint()); - } - - public static void statisticsWithGrowingSizes() { - Random r = new Random(); - - // We re-use the bitmaps so that we accumulate the longs into them - // We then expect to have denser buckets (around 0) - Roaring64Bitmap bitmap64Art = new Roaring64Bitmap(); - Roaring64NavigableMap bitmap64Map = new Roaring64NavigableMap(); - - for (long size = 0 ; size < 1024 ; size++) { - long max = (1L + size*size*size*size*size); - System.out.println(size + " in [-" + max + ", " + max + "["); - - long fSize = size; - long[] array = IntStream.range(0, Ints.checkedCast(size)) - .mapToLong(i -> i) - .flatMap(i -> LongStream.generate(() -> r.nextLong() % max).limit(fSize)) - .toArray(); - - reportBitmapsMemory(array, bitmap64Art, bitmap64Map); - } - } - - private static void reportBitmapsMemory(long[] array, LongBitmapDataProvider bitmap, LongBitmapDataProvider bitmap2) { - reportBitmapsMemory(array, bitmap); - reportBitmapsMemory(array, bitmap2); - - if (!Arrays.equals(bitmap.toArray(), bitmap.toArray())) { - throw new IllegalStateException("Issue with: " + Arrays.toString(array)); - } - } - - private static void reportBitmapsMemory(long[] array, LongBitmapDataProvider bitmap) { - LongStream.of(array).forEach(bitmap::addLong); - long jolSize = GraphLayout.parseInstance(bitmap).totalSize(); - long ownEstimation = bitmap.getLongSizeInBytes(); - System.out.println(bitmap.getClass().getSimpleName() - + ": " + String.format("%,d", jolSize) + "(real) vs " - + String.format("%,d", ownEstimation) + "(estimated) " - + (ownEstimation < jolSize ? "optimistic" : "pessimistic")); - } -} diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestLongUtils.java b/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestLongUtils.java deleted file mode 100644 index 5bff24bd4..000000000 --- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestLongUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.roaringbitmap.longlong; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class TestLongUtils { - @Test - public void testHighPart() { - Assertions.assertFalse(LongUtils.isMaxHigh(LongUtils.highPart(0))); - Assertions.assertFalse(LongUtils.isMaxHigh(LongUtils.highPart(Long.MAX_VALUE))); - Assertions.assertFalse(LongUtils.isMaxHigh(LongUtils.highPart(Long.MIN_VALUE))); - - Assertions.assertTrue(LongUtils.isMaxHigh(LongUtils.highPart(-1L))); - } -} diff --git a/bsi/build.gradle.kts b/bsi/build.gradle.kts index 4eb92a893..69171d56e 100644 --- a/bsi/build.gradle.kts +++ b/bsi/build.gradle.kts @@ -1,7 +1,7 @@ val deps: Map by extra dependencies { - implementation(project(":RoaringBitmap")) + implementation(project(":roaringbitmap")) testImplementation("org.junit.jupiter:junit-jupiter-api:${deps["jupiter"]}") testImplementation("org.junit.jupiter:junit-jupiter-params:${deps["jupiter"]}") diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/BitmapSliceIndex.java b/bsi/src/main/java/org/roaringbitmap/bsi/BitmapSliceIndex.java index 4b717b435..b087d081d 100644 --- a/bsi/src/main/java/org/roaringbitmap/bsi/BitmapSliceIndex.java +++ b/bsi/src/main/java/org/roaringbitmap/bsi/BitmapSliceIndex.java @@ -12,9 +12,9 @@ * 2. high compression ratio for number * Given that,we have a table T(c1,c2,c3....Cn). As we know,most database has rowId for each row. * then table T is actually T(rowId,c1,c2,c3,Cn). - * 1. if column c1 is string, we can encode c1 using dictionary. By bsi, + * 1. if column c1 is string, we can encode c1 using dictionary. By bsi, * we can only use 33 bit slice express 2^32 cardinality dim. - * 2. if column c2 is int32(that is 4Byte), for 1_000_000 rows, the size + * 2. if column c2 is int32(that is 4Byte), for 1_000_000 rows, the size * of c2 is more than 3.81MB. however, * by bsi, the size might be less than 1MB. * @@ -41,7 +41,6 @@ enum Operation { long getLongCardinality(); - /** * set value for bsi, setValue will set each bit slice according to the input value * given that we have bsi as follow @@ -76,7 +75,8 @@ enum Operation { * and avoiding bsi expend slice array capacity. */ @Deprecated - void setValues(List> values, Integer currentMaxValue, Integer currentMinValue); + void setValues( + List> values, Integer currentMaxValue, Integer currentMinValue); /** * Set a batch of values. @@ -89,7 +89,4 @@ enum Operation { void serialize(DataOutput output) throws IOException; int serializedSizeInBytes(); - - } - diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/Pair.java b/bsi/src/main/java/org/roaringbitmap/bsi/Pair.java index db471e453..270b5925b 100644 --- a/bsi/src/main/java/org/roaringbitmap/bsi/Pair.java +++ b/bsi/src/main/java/org/roaringbitmap/bsi/Pair.java @@ -18,8 +18,7 @@ public class Pair implements Serializable { /** * Default constructor. */ - public Pair() { - } + public Pair() {} /** * Constructor @@ -96,17 +95,16 @@ public void setSecond(T2 b) { @Override @SuppressWarnings("rawtypes") public boolean equals(Object other) { - return other instanceof Pair && equals(left, ((Pair) other).left) && equals(right, ((Pair) other).right); + return other instanceof Pair + && equals(left, ((Pair) other).left) + && equals(right, ((Pair) other).right); } @Override public int hashCode() { - if (left == null) - return (right == null) ? 0 : right.hashCode() + 1; - else if (right == null) - return left.hashCode() + 2; - else - return left.hashCode() * 17 + right.hashCode(); + if (left == null) return (right == null) ? 0 : right.hashCode() + 1; + else if (right == null) return left.hashCode() + 2; + else return left.hashCode() * 17 + right.hashCode(); } @Override @@ -114,5 +112,3 @@ public String toString() { return "{" + getLeft() + "," + getRight() + "}"; } } - - diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/RoaringBitmapSliceIndex.java b/bsi/src/main/java/org/roaringbitmap/bsi/RoaringBitmapSliceIndex.java index 35ddd417a..048e8a37d 100644 --- a/bsi/src/main/java/org/roaringbitmap/bsi/RoaringBitmapSliceIndex.java +++ b/bsi/src/main/java/org/roaringbitmap/bsi/RoaringBitmapSliceIndex.java @@ -1,6 +1,5 @@ package org.roaringbitmap.bsi; -import java.util.Objects; import org.roaringbitmap.RoaringBitmap; import java.io.DataInput; @@ -8,6 +7,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; +import java.util.Objects; import java.util.stream.IntStream; /** @@ -34,7 +34,6 @@ public class RoaringBitmapSliceIndex implements BitmapSliceIndex { */ private RoaringBitmap ebM; - private Boolean runOptimized = false; /** @@ -54,7 +53,6 @@ public RoaringBitmapSliceIndex(int minValue, int maxValue) { this.ebM = new RoaringBitmap(); } - /** * NewDefaultBSI constructs an auto-sized BSI */ @@ -62,7 +60,6 @@ public RoaringBitmapSliceIndex() { this(0, 0); } - public void add(RoaringBitmapSliceIndex otherBsi) { if (null == otherBsi || otherBsi.ebM.isEmpty()) { return; @@ -85,13 +82,12 @@ public void add(RoaringBitmapSliceIndex otherBsi) { private void addDigit(RoaringBitmap foundSet, int i) { RoaringBitmap carry = RoaringBitmap.and(this.bA[i], foundSet); this.bA[i].xor(foundSet); - if (carry.getCardinality() > 0) { + if (!carry.isEmpty()) { if (i + 1 >= this.bitCount()) { grow(this.bitCount() + 1); } this.addDigit(carry, i + 1); } - } private int minValue() { @@ -152,7 +148,6 @@ public void runOptimize() { /** * hasRunCompression returns true if the bitmap benefits from run compression */ - public boolean hasRunCompression() { return this.runOptimized; } @@ -160,12 +155,10 @@ public boolean hasRunCompression() { /** * GetExistenceBitmap returns a pointer to the underlying existence bitmap of the BSI */ - public RoaringBitmap getExistenceBitmap() { return this.ebM; } - public int bitCount() { return this.bA.length; } @@ -174,7 +167,6 @@ public long getLongCardinality() { return this.ebM.getLongCardinality(); } - /** * GetValue gets the value at the column ID. Second param will be false for non-existence values. */ @@ -187,7 +179,6 @@ public Pair getValue(int columnId) { return Pair.newPair(valueAt(columnId), true); } - private void clear() { this.maxValue = 0; this.minValue = 0; @@ -249,7 +240,6 @@ public void serialize(ByteBuffer buffer) { for (RoaringBitmap rb : this.bA) { rb.serialize(buffer); } - } public void deserialize(ByteBuffer buffer) throws IOException { @@ -285,7 +275,6 @@ public int serializedSizeInBytes() { return 4 + 4 + 1 + 4 + this.ebM.serializedSizeInBytes() + size; } - /** * valueExists tests whether the value exists. */ @@ -348,8 +337,10 @@ private void grow(int newBitDepth) { @Override public void setValues(List> values) { - int maxValue = values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).max().getAsInt(); - int minValue = values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).min().getAsInt(); + int maxValue = + values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).max().getAsInt(); + int minValue = + values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).min().getAsInt(); ensureCapacityInternal(minValue, maxValue); for (Pair pair : values) { setValueInternal(pair.getKey(), pair.getValue()); @@ -360,9 +351,16 @@ public void setValues(List> values) { * Replaced by {@code setValues(values)} */ @Deprecated - public void setValues(List> values, Integer currentMaxValue, Integer currentMinValue) { - int maxValue = currentMaxValue != null ? currentMaxValue : values.stream().mapToInt(Pair::getRight).max().getAsInt(); - int minValue = currentMinValue != null ? currentMinValue : values.stream().mapToInt(Pair::getRight).min().getAsInt(); + public void setValues( + List> values, Integer currentMaxValue, Integer currentMinValue) { + int maxValue = + currentMaxValue != null + ? currentMaxValue + : values.stream().mapToInt(Pair::getRight).max().getAsInt(); + int minValue = + currentMinValue != null + ? currentMinValue + : values.stream().mapToInt(Pair::getRight).min().getAsInt(); ensureCapacityInternal(minValue, maxValue); for (Pair pair : values) { this.setValue(pair.getKey(), pair.getValue()); @@ -404,7 +402,6 @@ public void merge(RoaringBitmapSliceIndex otherBsi) { this.minValue = Integer.min(this.minValue, otherBsi.minValue); } - public RoaringBitmapSliceIndex clone() { RoaringBitmapSliceIndex bitSliceIndex = new RoaringBitmapSliceIndex(); bitSliceIndex.minValue = this.minValue; @@ -429,14 +426,14 @@ public RoaringBitmapSliceIndex clone() { * @return columnId set we found in this bsi with giving conditions, using RoaringBitmap to express * see https://github.com/lemire/BitSliceIndex/blob/master/src/main/java/org/roaringbitmap/circuits/comparator/BasicComparator.java */ - private RoaringBitmap oNeilCompare(BitmapSliceIndex.Operation operation, int predicate, RoaringBitmap foundSet) { + private RoaringBitmap oNeilCompare( + BitmapSliceIndex.Operation operation, int predicate, RoaringBitmap foundSet) { RoaringBitmap fixedFoundSet = foundSet == null ? this.ebM : foundSet; RoaringBitmap GT = new RoaringBitmap(); RoaringBitmap LT = new RoaringBitmap(); RoaringBitmap EQ = this.ebM; - for (int i = this.bitCount() - 1; i >= 0; i--) { int bit = (predicate >> i) & 1; if (bit == 1) { @@ -446,7 +443,6 @@ private RoaringBitmap oNeilCompare(BitmapSliceIndex.Operation operation, int pre GT = RoaringBitmap.or(GT, RoaringBitmap.and(EQ, this.bA[i])); EQ = RoaringBitmap.andNot(EQ, this.bA[i]); } - } EQ = RoaringBitmap.and(fixedFoundSet, EQ); switch (operation) { @@ -459,9 +455,9 @@ private RoaringBitmap oNeilCompare(BitmapSliceIndex.Operation operation, int pre case LT: return RoaringBitmap.and(LT, fixedFoundSet); case LE: - return RoaringBitmap.or(LT, EQ); + return RoaringBitmap.and(RoaringBitmap.or(LT, EQ), fixedFoundSet); case GE: - return RoaringBitmap.or(GT, EQ); + return RoaringBitmap.and(RoaringBitmap.or(GT, EQ), fixedFoundSet); default: throw new IllegalArgumentException(""); } @@ -479,7 +475,8 @@ private RoaringBitmap oNeilCompare(BitmapSliceIndex.Operation operation, int pre * @param foundSet columnId set we want compare,using RoaringBitmap to express * @return columnId set we found in this bsi with giving conditions, using RoaringBitmap to express */ - public RoaringBitmap compare(BitmapSliceIndex.Operation operation, int startOrValue, int end, RoaringBitmap foundSet) { + public RoaringBitmap compare( + BitmapSliceIndex.Operation operation, int startOrValue, int end, RoaringBitmap foundSet) { RoaringBitmap result = compareUsingMinMax(operation, startOrValue, end, foundSet); if (result != null) { return result; @@ -492,27 +489,36 @@ public RoaringBitmap compare(BitmapSliceIndex.Operation operation, int startOrVa return oNeilCompare(Operation.NEQ, startOrValue, foundSet); case GE: return oNeilCompare(Operation.GE, startOrValue, foundSet); - case GT: { - return oNeilCompare(BitmapSliceIndex.Operation.GT, startOrValue, foundSet); - } + case GT: + { + return oNeilCompare(BitmapSliceIndex.Operation.GT, startOrValue, foundSet); + } case LT: return oNeilCompare(BitmapSliceIndex.Operation.LT, startOrValue, foundSet); case LE: return oNeilCompare(BitmapSliceIndex.Operation.LE, startOrValue, foundSet); - case RANGE: { - RoaringBitmap left = oNeilCompare(Operation.GE, startOrValue, foundSet); - RoaringBitmap right = oNeilCompare(BitmapSliceIndex.Operation.LE, end, foundSet); - - return RoaringBitmap.and(left, right); - } + case RANGE: + { + if (startOrValue < minValue) { + startOrValue = minValue; + } + if (end > maxValue) { + end = maxValue; + } + RoaringBitmap left = oNeilCompare(Operation.GE, startOrValue, foundSet); + RoaringBitmap right = oNeilCompare(BitmapSliceIndex.Operation.LE, end, foundSet); + + return RoaringBitmap.and(left, right); + } default: throw new IllegalArgumentException("not support operation!"); } } - private RoaringBitmap compareUsingMinMax(BitmapSliceIndex.Operation operation, int startOrValue, int end, RoaringBitmap foundSet) { + private RoaringBitmap compareUsingMinMax( + BitmapSliceIndex.Operation operation, int startOrValue, int end, RoaringBitmap foundSet) { RoaringBitmap all = foundSet == null ? ebM.clone() : RoaringBitmap.and(ebM, foundSet); RoaringBitmap empty = new RoaringBitmap(); @@ -584,12 +590,11 @@ public Pair sum(RoaringBitmap foundSet) { } long count = foundSet.getLongCardinality(); - Long sum = IntStream.range(0, this.bitCount()) - .mapToLong(x -> (long) (1 << x) * RoaringBitmap.andCardinality(this.bA[x], foundSet)) - .sum(); + Long sum = + IntStream.range(0, this.bitCount()) + .mapToLong(x -> (long) (1 << x) * RoaringBitmap.andCardinality(this.bA[x], foundSet)) + .sum(); return Pair.newPair(sum, count); } - } - diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/WritableUtils.java b/bsi/src/main/java/org/roaringbitmap/bsi/WritableUtils.java index a56b85b45..6a1c248c9 100644 --- a/bsi/src/main/java/org/roaringbitmap/bsi/WritableUtils.java +++ b/bsi/src/main/java/org/roaringbitmap/bsi/WritableUtils.java @@ -73,7 +73,6 @@ public static void writeVLong(DataOutput stream, long i) throws IOException { } } - /** * Reads a zero-compressed encoded long from input stream and returns it. * @@ -136,4 +135,3 @@ public static int decodeVIntSize(byte value) { return -111 - value; } } - diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/buffer/BitSliceIndexBase.java b/bsi/src/main/java/org/roaringbitmap/bsi/buffer/BitSliceIndexBase.java index c40c836b0..b835fdc74 100644 --- a/bsi/src/main/java/org/roaringbitmap/bsi/buffer/BitSliceIndexBase.java +++ b/bsi/src/main/java/org/roaringbitmap/bsi/buffer/BitSliceIndexBase.java @@ -1,11 +1,9 @@ - package org.roaringbitmap.bsi.buffer; import org.roaringbitmap.BatchIterator; import org.roaringbitmap.IntConsumer; -import org.roaringbitmap.IntIterator; -import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.bsi.BitmapSliceIndex; +import org.roaringbitmap.bsi.BitmapSliceIndex.Operation; import org.roaringbitmap.bsi.Pair; import org.roaringbitmap.buffer.BufferFastAggregation; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; @@ -48,7 +46,6 @@ public class BitSliceIndexBase { */ protected ImmutableRoaringBitmap ebM; - public int bitCount() { return this.bA.length; } @@ -74,7 +71,6 @@ public Pair getValue(int columnId) { return Pair.newPair(value, true); } - /** * valueExists tests whether the value exists. */ @@ -82,9 +78,9 @@ public boolean valueExist(Long columnId) { return this.ebM.contains(columnId.intValue()); } - //===================================================================================== + // ===================================================================================== // parallel execute frame - //====================================================================================== + // ====================================================================================== /** * use java threadPool to parallel exec @@ -95,10 +91,11 @@ public boolean valueExist(Long columnId) { * @param pool threadPool to exec * @return a list of completable futures */ - protected List> parallelExec(Function func, - int parallelism, - ImmutableRoaringBitmap foundSet, - ExecutorService pool) { + protected List> parallelExec( + Function func, + int parallelism, + ImmutableRoaringBitmap foundSet, + ExecutorService pool) { int batchSize = foundSet.getCardinality() / parallelism; // fix when batchSize < parallelism batchSize = Math.max(batchSize, parallelism); @@ -106,7 +103,6 @@ protected List> parallelExec(Function func, // todo RoaringBitmap's batchIterator return max 2^16 batchSize = Math.min(batchSize, 65536); - List batches = new ArrayList<>(); final BatchIterator batchIterator = foundSet.getBatchIterator(); @@ -126,9 +122,13 @@ protected List> parallelExec(Function func, List> futures = new ArrayList<>(); for (int[] batch : batches) { - CompletableFuture future = invokeAsync(() -> { - return func.apply(batch); - }, null, pool); + CompletableFuture future = + invokeAsync( + () -> { + return func.apply(batch); + }, + null, + pool); futures.add(future); } return futures; @@ -137,20 +137,19 @@ protected List> parallelExec(Function func, protected CompletableFuture> allOf(List> futuresList) { CompletableFuture allFuturesResult = CompletableFuture.allOf(futuresList.toArray(new CompletableFuture[0])); - return allFuturesResult.thenApply(v -> - futuresList.stream(). - map(CompletableFuture::join). - collect(Collectors.toList()) - ); + return allFuturesResult.thenApply( + v -> futuresList.stream().map(CompletableFuture::join).collect(Collectors.toList())); } - protected ImmutableRoaringBitmap parallelMR(int parallelism, - ImmutableRoaringBitmap foundSet, - Function func, - ExecutorService pool) + protected ImmutableRoaringBitmap parallelMR( + int parallelism, + ImmutableRoaringBitmap foundSet, + Function func, + ExecutorService pool) throws InterruptedException, ExecutionException { - List> futures = parallelExec(func, parallelism, foundSet, pool); + List> futures = + parallelExec(func, parallelism, foundSet, pool); allOf(futures); @@ -162,19 +161,20 @@ protected ImmutableRoaringBitmap parallelMR(int parallelism, return MutableRoaringBitmap.or(rbs); } - protected CompletableFuture invokeAsync(Supplier supplier, - Function exceptionHandler, - Executor forkJoinExecutor) { - return CompletableFuture.supplyAsync(() -> { - try { - return supplier.get(); - } catch (Exception e) { - if (exceptionHandler == null) { - throw e; - } - return exceptionHandler.apply(e); - } - }, forkJoinExecutor); + protected CompletableFuture invokeAsync( + Supplier supplier, Function exceptionHandler, Executor forkJoinExecutor) { + return CompletableFuture.supplyAsync( + () -> { + try { + return supplier.get(); + } catch (Exception e) { + if (exceptionHandler == null) { + throw e; + } + return exceptionHandler.apply(e); + } + }, + forkJoinExecutor); } /** @@ -186,28 +186,33 @@ protected CompletableFuture invokeAsync(Supplier supplier, * @return ImmutableRoaringBitmap * see https://github.com/lemire/BitSliceIndex/blob/master/src/main/java/org/roaringbitmap/circuits/comparator/BasicComparator.java */ - private ImmutableRoaringBitmap oNeilCompare(BitmapSliceIndex.Operation operation, - int predicate, - ImmutableRoaringBitmap foundSet) { + private ImmutableRoaringBitmap oNeilCompare( + BitmapSliceIndex.Operation operation, int predicate, ImmutableRoaringBitmap foundSet) { ImmutableRoaringBitmap fixedFoundSet = foundSet == null ? this.ebM : foundSet; - MutableRoaringBitmap GT = new MutableRoaringBitmap(); - MutableRoaringBitmap LT = new MutableRoaringBitmap(); + MutableRoaringBitmap GT = + operation == Operation.GT || operation == Operation.GE ? new MutableRoaringBitmap() : null; + MutableRoaringBitmap LT = + operation == Operation.LT || operation == Operation.LE ? new MutableRoaringBitmap() : null; ImmutableRoaringBitmap EQ = this.ebM; - for (int i = this.bitCount() - 1; i >= 0; i--) { int bit = (predicate >> i) & 1; if (bit == 1) { - LT = ImmutableRoaringBitmap.or(LT, ImmutableRoaringBitmap.andNot(EQ, this.bA[i])); + if (operation == Operation.LT || operation == Operation.LE) { + LT = ImmutableRoaringBitmap.or(LT, ImmutableRoaringBitmap.andNot(EQ, this.bA[i])); + } EQ = ImmutableRoaringBitmap.and(EQ, this.bA[i]); } else { - GT = ImmutableRoaringBitmap.or(GT, ImmutableRoaringBitmap.and(EQ, this.bA[i])); + if (operation == Operation.GT || operation == Operation.GE) { + GT = ImmutableRoaringBitmap.or(GT, ImmutableRoaringBitmap.and(EQ, this.bA[i])); + } EQ = ImmutableRoaringBitmap.andNot(EQ, this.bA[i]); } - } - EQ = ImmutableRoaringBitmap.and(fixedFoundSet, EQ); + if (operation != Operation.LT && operation != Operation.GT) { + EQ = ImmutableRoaringBitmap.and(fixedFoundSet, EQ); + } switch (operation) { case EQ: return EQ; @@ -231,8 +236,7 @@ private ImmutableRoaringBitmap oNeilCompare(BitmapSliceIndex.Operation operation * @return ImmutableRoaringBitmap * see https://github.com/lemire/BitSliceIndex/blob/master/src/main/java/org/roaringbitmap/circuits/comparator/OwenComparator.java */ - private ImmutableRoaringBitmap owenGreatEqual(int predicate, - ImmutableRoaringBitmap foundSet) { + private ImmutableRoaringBitmap owenGreatEqual(int predicate, ImmutableRoaringBitmap foundSet) { ImmutableRoaringBitmap lastSpineGate = null; int beGtrThan = predicate - 1; List orInputs = new ArrayList<>(); @@ -241,21 +245,20 @@ private ImmutableRoaringBitmap owenGreatEqual(int predicate, for (int workingBit = this.bitCount() - 1; workingBit >= leastSignifZero; --workingBit) { if ((beGtrThan & (1L << workingBit)) == 0L) { if (lastSpineGate == null) // don't make a singleton AND! - orInputs.add(this.bA[workingBit]); + orInputs.add(this.bA[workingBit]); else { // really make the AND orInputs.add(MutableRoaringBitmap.and(lastSpineGate, this.bA[workingBit])); } } else { - if (lastSpineGate == null) - lastSpineGate = this.bA[workingBit]; - else - lastSpineGate = ImmutableRoaringBitmap.and(lastSpineGate, this.bA[workingBit]); + if (lastSpineGate == null) lastSpineGate = this.bA[workingBit]; + else lastSpineGate = ImmutableRoaringBitmap.and(lastSpineGate, this.bA[workingBit]); } } - ImmutableRoaringBitmap result = BufferFastAggregation.horizontal_or(orInputs.toArray(new ImmutableRoaringBitmap[0])); - //horizontal_or the performance is better + ImmutableRoaringBitmap result = + BufferFastAggregation.horizontal_or(orInputs.toArray(new ImmutableRoaringBitmap[0])); + // horizontal_or the performance is better // return BufferFastAggregation.or(orInputs.toArray(new ImmutableRoaringBitmap[0])) if (null == foundSet) { @@ -265,18 +268,21 @@ private ImmutableRoaringBitmap owenGreatEqual(int predicate, } } - //------------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------------ // See Bit-Sliced Index Arithmetic - // Finding the rows with the k largest values in a BSI. Given a BSI, S = S^P,S^(P-1)...S^1,S^0 over a table T - // and a positive integer k<= |T|, we wish to find the bitmap F (for "found set") of rows r with the k largest + // Finding the rows with the k largest values in a BSI. Given a BSI, S = S^P,S^(P-1)...S^1,S^0 + // over a table T + // and a positive integer k<= |T|, we wish to find the bitmap F (for "found set") of rows r with + // the k largest // S-values, S(r), in T. // Algorithm 4.1. Find k rows with largest values in a BSI. - //------------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------------ // if (k > COUNT(EBM) or k < 0) -- test if parameter k is valid // Error ("k is invalid") -- if not, exit; otherwise, kth largest S-value exists // G = empty set; E = EBM; -- G starts with no rows; E with all rows // for (i = P; i >= 0; i--) { -- i is a descending loop index for bit-slice number - // X = G OR (E AND S^i) -- X is trial set: G OR {rows in E with 1-bit in position i} + // X = G OR (E AND S^i) -- X is trial set: G OR {rows in E with 1-bit in position + // i} // if ((n = COUNT(X) ) > k) -- if n = COUNT(X) has more than k rows // E = E AND S^i -- E in next pass contains only rows r with bit i on in S(r) // else if (n < k) { -- if n = COUNT(X) has less than k rows @@ -290,19 +296,20 @@ private ImmutableRoaringBitmap owenGreatEqual(int predicate, // } -- we know at this point that COUNT(G) <= k // F = G OR E -- might be too many rows in F; check below // if ((n = (COUNT(F) - k) > 0) -- if n too many rows in F - // {turn off n bits from E in F}; -- throw out some ties to return exactly k rows + // {turn off n bits from E in F}; -- throw out some ties to return exactly k rows public MutableRoaringBitmap topK(ImmutableRoaringBitmap foundSet, int k) { ImmutableRoaringBitmap fixedFoundSet = foundSet == null ? this.ebM : foundSet; if (k > fixedFoundSet.getLongCardinality() || k < 0) { - throw new IllegalArgumentException("TopK param error,cardinality:" - + fixedFoundSet.getLongCardinality() + " k:" + k); + throw new IllegalArgumentException( + "TopK param error,cardinality:" + fixedFoundSet.getLongCardinality() + " k:" + k); } MutableRoaringBitmap G = new MutableRoaringBitmap(); ImmutableRoaringBitmap E = fixedFoundSet; for (int i = this.bitCount() - 1; i >= 0; i--) { - MutableRoaringBitmap X = ImmutableRoaringBitmap.or(G, ImmutableRoaringBitmap.and(E, this.bA[i])); + MutableRoaringBitmap X = + ImmutableRoaringBitmap.or(G, ImmutableRoaringBitmap.and(E, this.bA[i])); long n = X.getLongCardinality(); if (n > k) { E = ImmutableRoaringBitmap.and(E, this.bA[i]); @@ -317,24 +324,11 @@ public MutableRoaringBitmap topK(ImmutableRoaringBitmap foundSet, int k) { MutableRoaringBitmap F = ImmutableRoaringBitmap.or(G, E); long n = F.getLongCardinality() - k; - if (n > 0) { - // TODO: make faster - IntIterator i = F.getIntIterator(); - MutableRoaringBitmap turnoff = new MutableRoaringBitmap(); - while (i.hasNext() && n > 0) { - turnoff.add(i.next()); - --n; - } - F.andNot(turnoff); - } - - if (F.getCardinality() != k) - throw new RuntimeException("bugs found when compute topK"); - + F.remove(0L, (long) F.select((int) n)); + assert (F.getLongCardinality() == k); return F; } - /** * EQ: = * @@ -351,7 +345,8 @@ public ImmutableRoaringBitmap rangeEQ(ImmutableRoaringBitmap foundSet, int predi } // https://github.com/RoaringBitmap/RoaringBitmap/issues/549 - ImmutableRoaringBitmap result = compareUsingMinMax(BitmapSliceIndex.Operation.EQ, predicate, 0, foundSet); + ImmutableRoaringBitmap result = + compareUsingMinMax(BitmapSliceIndex.Operation.EQ, predicate, 0, foundSet); if (result != null) { return result; } @@ -398,7 +393,6 @@ public ImmutableRoaringBitmap rangeGE(ImmutableRoaringBitmap foundSet, int predi public ImmutableRoaringBitmap range(ImmutableRoaringBitmap foundSet, int start, int end) { return compare(BitmapSliceIndex.Operation.RANGE, start, end, foundSet); - } /** @@ -413,7 +407,11 @@ public ImmutableRoaringBitmap range(ImmutableRoaringBitmap foundSet, int start, * @param foundSet columnId set we want compare,using RoaringBitmap to express * @return columnId set we found in this bsi with giving conditions, using RoaringBitmap to express */ - public ImmutableRoaringBitmap compare(BitmapSliceIndex.Operation operation, int startOrValue, int end, ImmutableRoaringBitmap foundSet) { + public ImmutableRoaringBitmap compare( + BitmapSliceIndex.Operation operation, + int startOrValue, + int end, + ImmutableRoaringBitmap foundSet) { ImmutableRoaringBitmap result = compareUsingMinMax(operation, startOrValue, end, foundSet); if (result != null) { return result; @@ -426,28 +424,41 @@ public ImmutableRoaringBitmap compare(BitmapSliceIndex.Operation operation, int return rangeNEQ(foundSet, startOrValue); case GE: return owenGreatEqual(startOrValue, foundSet); - case GT: { - return oNeilCompare(BitmapSliceIndex.Operation.GT, startOrValue, foundSet); - } + case GT: + { + return oNeilCompare(BitmapSliceIndex.Operation.GT, startOrValue, foundSet); + } case LT: return oNeilCompare(BitmapSliceIndex.Operation.LT, startOrValue, foundSet); case LE: return oNeilCompare(BitmapSliceIndex.Operation.LE, startOrValue, foundSet); - case RANGE: { - ImmutableRoaringBitmap left = owenGreatEqual(startOrValue, foundSet); - ImmutableRoaringBitmap right = oNeilCompare(BitmapSliceIndex.Operation.LE, end, foundSet); - - return ImmutableRoaringBitmap.and(left, right); - } + case RANGE: + { + if (startOrValue < minValue) { + startOrValue = minValue; + } + if (end > maxValue) { + end = maxValue; + } + ImmutableRoaringBitmap left = owenGreatEqual(startOrValue, foundSet); + ImmutableRoaringBitmap right = oNeilCompare(BitmapSliceIndex.Operation.LE, end, foundSet); + + return ImmutableRoaringBitmap.and(left, right); + } default: throw new IllegalArgumentException("not support operation!"); } } - private ImmutableRoaringBitmap compareUsingMinMax(BitmapSliceIndex.Operation operation, int startOrValue, int end, ImmutableRoaringBitmap foundSet) { - ImmutableRoaringBitmap all = foundSet == null ? this.ebM.clone() : ImmutableRoaringBitmap.and(this.ebM, foundSet); + private ImmutableRoaringBitmap compareUsingMinMax( + BitmapSliceIndex.Operation operation, + int startOrValue, + int end, + ImmutableRoaringBitmap foundSet) { + ImmutableRoaringBitmap all = + foundSet == null ? this.ebM.clone() : ImmutableRoaringBitmap.and(this.ebM, foundSet); ImmutableRoaringBitmap empty = new MutableRoaringBitmap(); switch (operation) { @@ -518,27 +529,33 @@ public Pair sum(ImmutableRoaringBitmap foundSet) { } long count = foundSet.getLongCardinality(); - Long sum = IntStream.range(0, this.bitCount()) - .mapToLong(x -> (long) (1 << x) * ImmutableRoaringBitmap.andCardinality(this.bA[x], foundSet)) - .sum(); + Long sum = + IntStream.range(0, this.bitCount()) + .mapToLong( + x -> (long) (1 << x) * ImmutableRoaringBitmap.andCardinality(this.bA[x], foundSet)) + .sum(); return Pair.newPair(sum, count); } public List> toPairList() { List> pairList = new ArrayList<>(); - this.ebM.forEach((IntConsumer) cid -> { - pairList.add(Pair.newPair(cid, this.getValue(cid).getKey())); - }); + this.ebM.forEach( + (IntConsumer) + cid -> { + pairList.add(Pair.newPair(cid, this.getValue(cid).getKey())); + }); return pairList; } public List> toPairList(ImmutableRoaringBitmap foundSet) { List> pairList = new ArrayList<>(); ImmutableRoaringBitmap bitmap = ImmutableRoaringBitmap.and(this.ebM, foundSet); - bitmap.forEach((IntConsumer) cid -> { - pairList.add(Pair.newPair(cid, this.getValue(cid).getKey())); - }); + bitmap.forEach( + (IntConsumer) + cid -> { + pairList.add(Pair.newPair(cid, this.getValue(cid).getKey())); + }); return pairList; } @@ -569,17 +586,18 @@ protected MutableBitSliceIndex transposeWithCount(int[] batch) { * @param foundSet * @return the transpose */ - public MutableBitSliceIndex parallelTransposeWithCount(ImmutableRoaringBitmap foundSet, - int parallelism, - ExecutorService pool) + public MutableBitSliceIndex parallelTransposeWithCount( + ImmutableRoaringBitmap foundSet, int parallelism, ExecutorService pool) throws ExecutionException, InterruptedException { ImmutableRoaringBitmap fixedFoundSet = foundSet == null ? this.ebM : foundSet; - Function func = (int[] batch) -> { - return transposeWithCount(batch); - }; - List> futures = parallelExec(func, parallelism, fixedFoundSet, pool); + Function func = + (int[] batch) -> { + return transposeWithCount(batch); + }; + List> futures = + parallelExec(func, parallelism, fixedFoundSet, pool); allOf(futures); @@ -591,7 +609,7 @@ public MutableBitSliceIndex parallelTransposeWithCount(ImmutableRoaringBitmap fo } /** - * parallelIn search the given Set values, + * parallelIn search the given Set values, * we scan the bsi,if the value in values, we add it to result Bitmap * * @param parallelism @@ -602,23 +620,20 @@ public MutableBitSliceIndex parallelTransposeWithCount(ImmutableRoaringBitmap fo * @throws ExecutionException * @throws InterruptedException */ - public ImmutableRoaringBitmap parallelIn(int parallelism, - ImmutableRoaringBitmap foundSet, - Set values, - ExecutorService pool - ) throws ExecutionException, InterruptedException { + public ImmutableRoaringBitmap parallelIn( + int parallelism, ImmutableRoaringBitmap foundSet, Set values, ExecutorService pool) + throws ExecutionException, InterruptedException { ImmutableRoaringBitmap fixedFoundSet = foundSet == null ? this.ebM : foundSet; - Function func = (int[] batch) -> { - return batchIn(batch, values); - }; + Function func = + (int[] batch) -> { + return batchIn(batch, values); + }; return parallelMR(parallelism, fixedFoundSet, func, pool); - } - protected ImmutableRoaringBitmap batchIn(int[] batch, Set values) { MutableRoaringBitmap result = new MutableRoaringBitmap(); @@ -632,4 +647,3 @@ protected ImmutableRoaringBitmap batchIn(int[] batch, Set values) { return result; } } - diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/buffer/ImmutableBitSliceIndex.java b/bsi/src/main/java/org/roaringbitmap/bsi/buffer/ImmutableBitSliceIndex.java index 0c2cc1e13..21849d852 100644 --- a/bsi/src/main/java/org/roaringbitmap/bsi/buffer/ImmutableBitSliceIndex.java +++ b/bsi/src/main/java/org/roaringbitmap/bsi/buffer/ImmutableBitSliceIndex.java @@ -28,16 +28,15 @@ public class ImmutableBitSliceIndex extends BitSliceIndexBase implements BitmapS * @param maxValue * @param minValue */ - - public ImmutableBitSliceIndex(int maxValue, int minValue, ImmutableRoaringBitmap[] bA, ImmutableRoaringBitmap ebM) { + public ImmutableBitSliceIndex( + int maxValue, int minValue, ImmutableRoaringBitmap[] bA, ImmutableRoaringBitmap ebM) { this.maxValue = maxValue; this.minValue = minValue; this.bA = bA; this.ebM = ebM; } - public ImmutableBitSliceIndex() { - } + public ImmutableBitSliceIndex() {} /** * constructs a BSI from byteBuffer @@ -70,12 +69,10 @@ public ImmutableBitSliceIndex(ByteBuffer buffer) throws IOException { this.bA = ba; } - public void addDigit(ImmutableRoaringBitmap foundSet, int i) { throw new UnsupportedOperationException("ImmutableBSI don't support setValue"); } - public ImmutableRoaringBitmap getExistenceBitmap() { return this.ebM; } @@ -84,10 +81,9 @@ public void setValue(int cid, int value) { throw new UnsupportedOperationException("ImmutableBSI don't support setValue"); } - @Override - public void setValues(List> values, - Integer currentMaxValue, Integer currentMinValue) { + public void setValues( + List> values, Integer currentMaxValue, Integer currentMinValue) { throw new UnsupportedOperationException("ImmutableBSI don't support setValues"); } @@ -96,7 +92,6 @@ public void setValues(List> values) { throw new UnsupportedOperationException("ImmutableBSI does not support setting values"); } - public void add(BitmapSliceIndex otherBitmapSliceIndex) { throw new UnsupportedOperationException("ImmutableBSI don't support add"); } @@ -141,7 +136,6 @@ public void serialize(DataOutput output) throws IOException { } } - public int serializedSizeInBytes() { int size = 0; for (ImmutableRoaringBitmap rb : this.bA) { @@ -150,15 +144,15 @@ public int serializedSizeInBytes() { return 4 + 4 + 1 + 4 + this.ebM.serializedSizeInBytes() + size; } - public MutableBitSliceIndex toMutableBitSliceIndex() { MutableRoaringBitmap[] ibA = new MutableRoaringBitmap[this.bA.length]; for (int i = 0; i < this.bA.length; i++) { ibA[i] = this.bA[i].toMutableRoaringBitmap(); } - MutableBitSliceIndex bsi = new MutableBitSliceIndex( - this.maxValue, this.minValue, ibA, this.ebM.toMutableRoaringBitmap()); + MutableBitSliceIndex bsi = + new MutableBitSliceIndex( + this.maxValue, this.minValue, ibA, this.ebM.toMutableRoaringBitmap()); return bsi; } @@ -175,7 +169,4 @@ public ImmutableBitSliceIndex clone() { return bsi; } - - } - diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/buffer/MutableBitSliceIndex.java b/bsi/src/main/java/org/roaringbitmap/bsi/buffer/MutableBitSliceIndex.java index 3abdb0ed3..a3940b2fc 100644 --- a/bsi/src/main/java/org/roaringbitmap/bsi/buffer/MutableBitSliceIndex.java +++ b/bsi/src/main/java/org/roaringbitmap/bsi/buffer/MutableBitSliceIndex.java @@ -1,17 +1,17 @@ package org.roaringbitmap.bsi.buffer; -import java.util.Objects; -import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.bsi.BitmapSliceIndex; import org.roaringbitmap.bsi.Pair; import org.roaringbitmap.bsi.WritableUtils; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.roaringbitmap.buffer.MutableRoaringBitmap; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; +import java.util.Objects; import java.util.OptionalInt; /** @@ -29,15 +29,14 @@ public class MutableBitSliceIndex extends BitSliceIndexBase implements BitmapSli * @param bA bit slices for this bsi.using MutableRoaringBitmap array express * @param ebM exits value bitmap,use MutableRoaringBitmap express */ - public MutableBitSliceIndex(int maxValue, int minValue, - MutableRoaringBitmap[] bA, MutableRoaringBitmap ebM) { + public MutableBitSliceIndex( + int maxValue, int minValue, MutableRoaringBitmap[] bA, MutableRoaringBitmap ebM) { this.maxValue = maxValue; this.minValue = minValue; this.bA = bA; this.ebM = ebM; } - /** * construct a new MutableBitSliceIndex. * Min/Max values are optional. If set to 0 then the underlying BSI will be automatically sized. @@ -101,7 +100,6 @@ private void grow(int newBitDepth) { this.bA = newBA; } - /** * RunOptimize attempts to further compress the runs of consecutive values found in the bitmap */ @@ -121,7 +119,7 @@ public boolean hasRunCompression() { public void addDigit(MutableRoaringBitmap foundSet, int i) { MutableRoaringBitmap carry = MutableRoaringBitmap.and(this.bA[i], foundSet); this.getMutableSlice(i).xor(foundSet); - if (carry.getCardinality() > 0) { + if (!carry.isEmpty()) { if (i + 1 >= this.bitCount()) { grow(this.bitCount() + 1); } @@ -160,13 +158,16 @@ private void setValueInternal(int columnId, int value) { this.getExistenceBitmap().add(columnId); } - - public void setValues(List> values, - Integer currentMaxValue, Integer currentMinValue) { - OptionalInt maxValue = currentMaxValue != null - ? OptionalInt.of(currentMaxValue) : values.stream().mapToInt(Pair::getRight).max(); - OptionalInt minValue = currentMinValue != null - ? OptionalInt.of(currentMinValue) : values.stream().mapToInt(Pair::getRight).min(); + public void setValues( + List> values, Integer currentMaxValue, Integer currentMinValue) { + OptionalInt maxValue = + currentMaxValue != null + ? OptionalInt.of(currentMaxValue) + : values.stream().mapToInt(Pair::getRight).max(); + OptionalInt minValue = + currentMinValue != null + ? OptionalInt.of(currentMinValue) + : values.stream().mapToInt(Pair::getRight).min(); if (!maxValue.isPresent() || !minValue.isPresent()) { throw new IllegalArgumentException("wrong input values list"); @@ -176,7 +177,6 @@ public void setValues(List> values, for (Pair pair : values) { this.setValue(pair.getKey(), pair.getValue()); } - } /** @@ -186,8 +186,10 @@ public void setValues(List> values, */ @Override public void setValues(List> values) { - int maxValue = values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).max().getAsInt(); - int minValue = values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).min().getAsInt(); + int maxValue = + values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).max().getAsInt(); + int minValue = + values.stream().mapToInt(Pair::getRight).filter(Objects::nonNull).min().getAsInt(); ensureCapacityInternal(minValue, maxValue); for (Pair pair : values) { setValueInternal(pair.getKey(), pair.getValue()); @@ -281,10 +283,10 @@ public void merge(MutableBitSliceIndex otherBsi) { int bitDepth = Integer.max(this.bitCount(), otherBsi.bitCount()); MutableRoaringBitmap[] newBA = new MutableRoaringBitmap[bitDepth]; for (int i = 0; i < bitDepth; i++) { - MutableRoaringBitmap current = i < this.bA.length - ? this.getMutableSlice(i) : new MutableRoaringBitmap(); - MutableRoaringBitmap other = i < otherBsi.bA.length - ? otherBsi.getMutableSlice(i) : new MutableRoaringBitmap(); + MutableRoaringBitmap current = + i < this.bA.length ? this.getMutableSlice(i) : new MutableRoaringBitmap(); + MutableRoaringBitmap other = + i < otherBsi.bA.length ? otherBsi.getMutableSlice(i) : new MutableRoaringBitmap(); newBA[i] = MutableRoaringBitmap.or(current, other); if (this.runOptimized || otherBsi.runOptimized) { newBA[i].runOptimize(); @@ -310,7 +312,6 @@ public MutableBitSliceIndex clone() { bitSliceIndex.runOptimized = this.runOptimized; return bitSliceIndex; - } public void serialize(ByteBuffer buffer) { @@ -351,7 +352,6 @@ private void clear() { this.bA = null; } - public void deserialize(ByteBuffer buffer) throws IOException { this.clear(); // read meta @@ -406,7 +406,7 @@ public int serializedSizeInBytes() { size += rb.serializedSizeInBytes(); } return 4 + 4 + 1 + 4 + this.ebM.serializedSizeInBytes() + size; - } + } public ImmutableBitSliceIndex toImmutableBitSliceIndex() { ImmutableRoaringBitmap[] ibA = new ImmutableRoaringBitmap[this.bA.length]; @@ -414,9 +414,8 @@ public ImmutableBitSliceIndex toImmutableBitSliceIndex() { ibA[i] = this.bA[i]; } - ImmutableBitSliceIndex bsi = new ImmutableBitSliceIndex( - this.maxValue, this.minValue, ibA, this.ebM); + ImmutableBitSliceIndex bsi = + new ImmutableBitSliceIndex(this.maxValue, this.minValue, ibA, this.ebM); return bsi; } } - diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/longlong/Roaring64BitmapSliceIndex.java b/bsi/src/main/java/org/roaringbitmap/bsi/longlong/Roaring64BitmapSliceIndex.java new file mode 100644 index 000000000..5b573e837 --- /dev/null +++ b/bsi/src/main/java/org/roaringbitmap/bsi/longlong/Roaring64BitmapSliceIndex.java @@ -0,0 +1,627 @@ +package org.roaringbitmap.bsi.longlong; + +import org.roaringbitmap.bsi.BitmapSliceIndex; +import org.roaringbitmap.bsi.Pair; +import org.roaringbitmap.bsi.WritableUtils; +import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Objects; +import java.util.stream.IntStream; + +public class Roaring64BitmapSliceIndex { + /** + * the maxValue of this bsi + */ + private long maxValue; + + /** + * the minValue of this bsi + */ + private long minValue; + + /** + * the bit component slice Array of this bsi + */ + private Roaring64Bitmap[] bA; + + /** + * the exist bitmap of this bsi which means the columnId have value in this bsi + */ + private Roaring64Bitmap ebM; + + private Boolean runOptimized = false; + + /** + * NewBSI constructs a new BSI. Min/Max values are optional. If set to 0 + * then the underlying BSI will be automatically sized. + */ + public Roaring64BitmapSliceIndex(long minValue, long maxValue) { + if (minValue < 0) { + throw new IllegalArgumentException("Values should be non-negative"); + } + + this.bA = new Roaring64Bitmap[64 - Long.numberOfLeadingZeros(maxValue)]; + for (int i = 0; i < bA.length; i++) { + this.bA[i] = new Roaring64Bitmap(); + } + + this.ebM = new Roaring64Bitmap(); + } + + /** + * NewDefaultBSI constructs an auto-sized BSI + */ + public Roaring64BitmapSliceIndex() { + this(0L, 0L); + } + + public void add(Roaring64BitmapSliceIndex otherBsi) { + if (null == otherBsi || otherBsi.ebM.isEmpty()) { + return; + } + + this.ebM.or(otherBsi.ebM); + if (otherBsi.bitCount() > this.bitCount()) { + grow(otherBsi.bitCount()); + } + + for (int i = 0; i < otherBsi.bitCount(); i++) { + this.addDigit(otherBsi.bA[i], i); + } + + // update min and max after adding + this.minValue = minValue(); + this.maxValue = maxValue(); + } + + private void addDigit(Roaring64Bitmap foundSet, int i) { + Roaring64Bitmap carry = Roaring64Bitmap.and(this.bA[i], foundSet); + this.bA[i].xor(foundSet); + if (!carry.isEmpty()) { + if (i + 1 >= this.bitCount()) { + grow(this.bitCount() + 1); + } + this.addDigit(carry, i + 1); + } + } + + private long minValue() { + if (ebM.isEmpty()) { + return 0; + } + + Roaring64Bitmap minValuesId = ebM; + for (int i = bA.length - 1; i >= 0; i -= 1) { + Roaring64Bitmap tmp = Roaring64Bitmap.andNot(minValuesId, bA[i]); + if (!tmp.isEmpty()) { + minValuesId = tmp; + } + } + + return valueAt(minValuesId.first()); + } + + private long maxValue() { + if (ebM.isEmpty()) { + return 0; + } + + Roaring64Bitmap maxValuesId = ebM; + for (int i = bA.length - 1; i >= 0; i -= 1) { + Roaring64Bitmap tmp = Roaring64Bitmap.and(maxValuesId, bA[i]); + if (!tmp.isEmpty()) { + maxValuesId = tmp; + } + } + + return valueAt(maxValuesId.first()); + } + + private long valueAt(long columnId) { + long value = 0; + for (int i = 0; i < this.bitCount(); i += 1) { + if (this.bA[i].contains(columnId)) { + value |= (1L << i); + } + } + + return value; + } + + /** + * RunOptimize attempts to further compress the runs of consecutive values found in the bitmap + */ + public void runOptimize() { + this.ebM.runOptimize(); + + for (Roaring64Bitmap integers : this.bA) { + integers.runOptimize(); + } + this.runOptimized = true; + } + + /** + * hasRunCompression returns true if the bitmap benefits from run compression + */ + public boolean hasRunCompression() { + return this.runOptimized; + } + + /** + * GetExistenceBitmap returns a pointer to the underlying existence bitmap of the BSI + */ + public Roaring64Bitmap getExistenceBitmap() { + return this.ebM; + } + + public int bitCount() { + return this.bA.length; + } + + public long getLongCardinality() { + return this.ebM.getLongCardinality(); + } + + /** + * GetValue gets the value at the column ID. Second param will be false for non-existence values. + */ + public Pair getValue(long columnId) { + boolean exists = this.ebM.contains(columnId); + if (!exists) { + return Pair.newPair(0L, false); + } + + return Pair.newPair(valueAt(columnId), true); + } + + private void clear() { + this.maxValue = 0; + this.minValue = 0; + this.ebM = null; + this.bA = null; + } + + public void serialize(DataOutput output) throws IOException { + // write meta + WritableUtils.writeVLong(output, minValue); + WritableUtils.writeVLong(output, maxValue); + output.writeBoolean(this.runOptimized); + + // write ebm + this.ebM.serialize(output); + + // write ba + WritableUtils.writeVInt(output, this.bA.length); + for (Roaring64Bitmap rb : this.bA) { + rb.serialize(output); + } + } + + public void deserialize(DataInput in) throws IOException { + this.clear(); + + // read meta + this.minValue = WritableUtils.readVInt(in); + this.maxValue = WritableUtils.readVInt(in); + this.runOptimized = in.readBoolean(); + + // read ebm + Roaring64Bitmap ebm = new Roaring64Bitmap(); + ebm.deserialize(in); + this.ebM = ebm; + + // read ba + int bitDepth = WritableUtils.readVInt(in); + Roaring64Bitmap[] ba = new Roaring64Bitmap[bitDepth]; + for (int i = 0; i < bitDepth; i++) { + Roaring64Bitmap rb = new Roaring64Bitmap(); + rb.deserialize(in); + ba[i] = rb; + } + this.bA = ba; + } + + public void serialize(ByteBuffer buffer) throws IOException { + // write meta + buffer.putLong(this.minValue); + buffer.putLong(this.maxValue); + buffer.put(this.runOptimized ? (byte) 1 : (byte) 0); + // write ebm + this.ebM.serialize(buffer); + + // write ba + buffer.putInt(this.bA.length); + for (Roaring64Bitmap rb : this.bA) { + rb.serialize(buffer); + } + } + + public void deserialize(ByteBuffer buffer) throws IOException { + this.clear(); + // read meta + this.minValue = buffer.getLong(); + this.maxValue = buffer.getLong(); + this.runOptimized = buffer.get() == (byte) 1; + + // read ebm + Roaring64Bitmap ebm = new Roaring64Bitmap(); + ebm.deserialize(buffer); + this.ebM = ebm; + // read back + buffer.position(buffer.position() + ebm.getSizeInBytes()); + int bitDepth = buffer.getInt(); + Roaring64Bitmap[] ba = new Roaring64Bitmap[bitDepth]; + for (int i = 0; i < bitDepth; i++) { + Roaring64Bitmap rb = new Roaring64Bitmap(); + rb.deserialize(buffer); + ba[i] = rb; + buffer.position(buffer.position() + rb.getSizeInBytes()); + } + this.bA = ba; + } + + public int serializedSizeInBytes() { + int size = 0; + for (Roaring64Bitmap rb : this.bA) { + size += rb.getSizeInBytes(); + } + return 8 + 8 + 1 + 4 + this.ebM.getSizeInBytes() + size; + } + + /** + * valueExists tests whether the value exists. + */ + public boolean valueExist(Long columnId) { + return this.ebM.contains(columnId); + } + + /** + * SetValue sets a value for a given columnID. + */ + public void setValue(long columnId, long value) { + ensureCapacityInternal(value, value); + setValueInternal(columnId, value); + } + + private void setValueInternal(long columnId, long value) { + for (int i = 0; i < this.bitCount(); i += 1) { + if ((value & (1L << i)) > 0) { + this.bA[i].add(columnId); + } else { + this.bA[i].remove(columnId); + } + } + this.ebM.add(columnId); + } + + private void ensureCapacityInternal(long minValue, long maxValue) { + if (ebM.isEmpty()) { + this.minValue = minValue; + this.maxValue = maxValue; + grow(Long.toBinaryString(maxValue).length()); + } else if (this.minValue > minValue) { + this.minValue = minValue; + } else if (this.maxValue < maxValue) { + this.maxValue = maxValue; + grow(Long.toBinaryString(maxValue).length()); + } + } + + private void grow(int newBitDepth) { + int oldBitDepth = this.bA.length; + + if (oldBitDepth >= newBitDepth) { + return; + } + + Roaring64Bitmap[] newBA = new Roaring64Bitmap[newBitDepth]; + if (oldBitDepth != 0) { + System.arraycopy(this.bA, 0, newBA, 0, oldBitDepth); + } + + for (int i = newBitDepth - 1; i >= oldBitDepth; i--) { + newBA[i] = new Roaring64Bitmap(); + if (this.runOptimized) { + newBA[i].runOptimize(); + } + } + this.bA = newBA; + } + + public void setValues(List> values) { + long maxValue = + values.stream().mapToLong(Pair::getRight).filter(Objects::nonNull).max().getAsLong(); + long minValue = + values.stream().mapToLong(Pair::getRight).filter(Objects::nonNull).min().getAsLong(); + ensureCapacityInternal(minValue, maxValue); + for (Pair pair : values) { + setValueInternal(pair.getKey(), pair.getValue()); + } + } + + /** + * merge will merge 2 bsi into current + * merge API was designed for distributed computing + * note: current and other bsi has no intersection + * + * @param otherBsi other bsi we need merge + */ + public void merge(Roaring64BitmapSliceIndex otherBsi) { + + if (null == otherBsi || otherBsi.ebM.isEmpty()) { + return; + } + + // todo whether we need this + if (Roaring64Bitmap.intersects(this.ebM, otherBsi.ebM)) { + throw new IllegalArgumentException("merge can be used only in bsiA bsiB is null"); + } + + int bitDepth = Integer.max(this.bitCount(), otherBsi.bitCount()); + Roaring64Bitmap[] newBA = new Roaring64Bitmap[bitDepth]; + for (int i = 0; i < bitDepth; i++) { + Roaring64Bitmap current = i < this.bA.length ? this.bA[i] : new Roaring64Bitmap(); + Roaring64Bitmap other = i < otherBsi.bA.length ? otherBsi.bA[i] : new Roaring64Bitmap(); + newBA[i] = Roaring64Bitmap.or(current, other); + if (this.runOptimized || otherBsi.runOptimized) { + newBA[i].runOptimize(); + } + } + this.bA = newBA; + this.ebM.or(otherBsi.ebM); + this.runOptimized = this.runOptimized || otherBsi.runOptimized; + this.maxValue = Long.max(this.maxValue, otherBsi.maxValue); + this.minValue = Long.min(this.minValue, otherBsi.minValue); + } + + @Override + public Roaring64BitmapSliceIndex clone() { + Roaring64BitmapSliceIndex bitSliceIndex = new Roaring64BitmapSliceIndex(); + bitSliceIndex.minValue = this.minValue; + bitSliceIndex.maxValue = this.maxValue; + bitSliceIndex.ebM = this.ebM.clone(); + Roaring64Bitmap[] cloneBA = new Roaring64Bitmap[this.bitCount()]; + for (int i = 0; i < cloneBA.length; i++) { + cloneBA[i] = this.bA[i].clone(); + } + bitSliceIndex.bA = cloneBA; + bitSliceIndex.runOptimized = this.runOptimized; + + return bitSliceIndex; + } + + /** + * O'Neil range using a bit-sliced index + * + * @param operation compare operation + * @param predicate the value we found filter + * @param foundSet columnId set we want compare,using RoaringBitmap to express + * @return columnId set we found in this bsi with giving conditions, using RoaringBitmap to express + * see https://github.com/lemire/BitSliceIndex/blob/master/src/main/java/org/roaringbitmap/circuits/comparator/BasicComparator.java + */ + private Roaring64Bitmap oNeilCompare( + BitmapSliceIndex.Operation operation, long predicate, Roaring64Bitmap foundSet) { + Roaring64Bitmap fixedFoundSet = foundSet == null ? this.ebM : foundSet; + + Roaring64Bitmap GT = new Roaring64Bitmap(); + Roaring64Bitmap LT = new Roaring64Bitmap(); + Roaring64Bitmap EQ = this.ebM; + + for (int i = this.bitCount() - 1; i >= 0; i--) { + int bit = (int) ((predicate >> i) & 1); + if (bit == 1) { + LT = Roaring64Bitmap.or(LT, Roaring64Bitmap.andNot(EQ, this.bA[i])); + EQ = Roaring64Bitmap.and(EQ, this.bA[i]); + } else { + GT = Roaring64Bitmap.or(GT, Roaring64Bitmap.and(EQ, this.bA[i])); + EQ = Roaring64Bitmap.andNot(EQ, this.bA[i]); + } + } + EQ = Roaring64Bitmap.and(fixedFoundSet, EQ); + switch (operation) { + case EQ: + return EQ; + case NEQ: + return Roaring64Bitmap.andNot(fixedFoundSet, EQ); + case GT: + return Roaring64Bitmap.and(GT, fixedFoundSet); + case LT: + return Roaring64Bitmap.and(LT, fixedFoundSet); + case LE: + return Roaring64Bitmap.and(Roaring64Bitmap.or(LT, EQ), fixedFoundSet); + case GE: + return Roaring64Bitmap.and(Roaring64Bitmap.or(GT, EQ), fixedFoundSet); + default: + throw new IllegalArgumentException(""); + } + } + + /** + * BSI Compare using single thread + * this Function compose algorithm from O'Neil and Owen Kaser + * the GE algorithm is from Owen since the performance is better. others are from O'Neil + * + * @param operation + * @param startOrValue the start or value of comparison, when the comparison operation is range, it's start, + * when others,it's value. + * @param end the end value of comparison. when the comparison operation is not range,the end = 0 + * @param foundSet columnId set we want compare,using RoaringBitmap to express + * @return columnId set we found in this bsi with giving conditions, using RoaringBitmap to express + */ + public Roaring64Bitmap compare( + BitmapSliceIndex.Operation operation, long startOrValue, long end, Roaring64Bitmap foundSet) { + Roaring64Bitmap result = compareUsingMinMax(operation, startOrValue, end, foundSet); + if (result != null) { + return result; + } + + switch (operation) { + case EQ: + return oNeilCompare(BitmapSliceIndex.Operation.EQ, startOrValue, foundSet); + case NEQ: + return oNeilCompare(BitmapSliceIndex.Operation.NEQ, startOrValue, foundSet); + case GE: + return oNeilCompare(BitmapSliceIndex.Operation.GE, startOrValue, foundSet); + case GT: + { + return oNeilCompare(BitmapSliceIndex.Operation.GT, startOrValue, foundSet); + } + case LT: + return oNeilCompare(BitmapSliceIndex.Operation.LT, startOrValue, foundSet); + + case LE: + return oNeilCompare(BitmapSliceIndex.Operation.LE, startOrValue, foundSet); + + case RANGE: + { + if (startOrValue < minValue) { + startOrValue = minValue; + } + if (end > maxValue) { + end = maxValue; + } + Roaring64Bitmap left = + oNeilCompare(BitmapSliceIndex.Operation.GE, startOrValue, foundSet); + Roaring64Bitmap right = oNeilCompare(BitmapSliceIndex.Operation.LE, end, foundSet); + + return Roaring64Bitmap.and(left, right); + } + default: + throw new IllegalArgumentException("not support operation!"); + } + } + + private Roaring64Bitmap compareUsingMinMax( + BitmapSliceIndex.Operation operation, long startOrValue, long end, Roaring64Bitmap foundSet) { + Roaring64Bitmap all = foundSet == null ? ebM.clone() : Roaring64Bitmap.and(ebM, foundSet); + Roaring64Bitmap empty = new Roaring64Bitmap(); + + switch (operation) { + case LT: + if (startOrValue > maxValue) { + return all; + } else if (startOrValue <= minValue) { + return empty; + } + + break; + case LE: + if (startOrValue >= maxValue) { + return all; + } else if (startOrValue < minValue) { + return empty; + } + + break; + case GT: + if (startOrValue < minValue) { + return all; + } else if (startOrValue >= maxValue) { + return empty; + } + + break; + case GE: + if (startOrValue <= minValue) { + return all; + } else if (startOrValue > maxValue) { + return empty; + } + + break; + case EQ: + if (minValue == maxValue && minValue == startOrValue) { + return all; + } else if (startOrValue < minValue || startOrValue > maxValue) { + return empty; + } + + break; + case NEQ: + if (minValue == maxValue) { + return minValue == startOrValue ? empty : all; + } + + break; + case RANGE: + if (startOrValue <= minValue && end >= maxValue) { + return all; + } else if (startOrValue > maxValue || end < minValue) { + return empty; + } + + break; + default: + return null; + } + + return null; + } + + public Pair sum(Roaring64Bitmap foundSet) { + if (null == foundSet || foundSet.isEmpty()) { + return Pair.newPair(0L, 0L); + } + long count = foundSet.getLongCardinality(); + + Long sum = + IntStream.range(0, this.bitCount()) + .mapToLong(x -> (1L << x) * Roaring64Bitmap.andCardinality(this.bA[x], foundSet)) + .sum(); + + return Pair.newPair(sum, count); + } + + public Roaring64Bitmap topK(Roaring64Bitmap foundSet, long k) { + if (null == foundSet || foundSet.isEmpty()) { + return new Roaring64Bitmap(); + } + if (k >= foundSet.getLongCardinality()) { + return foundSet; + } + Roaring64Bitmap re = new Roaring64Bitmap(); + Roaring64Bitmap candidates = foundSet.clone(); + + for (int x = this.bitCount() - 1; x >= 0 && !candidates.isEmpty() && k > 0; x--) { + long cardinality = Roaring64Bitmap.and(candidates, this.bA[x]).getLongCardinality(); + + if (cardinality > k) { + candidates.and(this.bA[x]); + } else { + re.or(Roaring64Bitmap.and(candidates, this.bA[x])); + candidates.andNot(this.bA[x]); + k -= cardinality; + } + } + return re; + } + + public Roaring64Bitmap transpose(Roaring64Bitmap foundSet) { + Roaring64Bitmap re = new Roaring64Bitmap(); + Roaring64Bitmap fixedFoundSet = + foundSet == null ? this.ebM : Roaring64Bitmap.and(foundSet, this.ebM); + fixedFoundSet.forEach((long x) -> re.add(this.getValue(x).getKey())); + return re; + } + + public Roaring64BitmapSliceIndex transposeWithCount(Roaring64Bitmap foundSet) { + Roaring64BitmapSliceIndex re = new Roaring64BitmapSliceIndex(); + Roaring64Bitmap fixedFoundSet = + foundSet == null ? this.ebM : Roaring64Bitmap.and(foundSet, this.ebM); + fixedFoundSet.forEach( + (long x) -> { + long nk = this.getValue(x).getKey(); + if (re.valueExist(nk)) { + re.setValue(nk, re.getValue(nk).getKey() + 1); + } else { + re.setValue(nk, 1); + } + }); + return re; + } +} diff --git a/bsi/src/main/java/org/roaringbitmap/bsi/longlong/Roaring64NavigableMapSliceIndex.java b/bsi/src/main/java/org/roaringbitmap/bsi/longlong/Roaring64NavigableMapSliceIndex.java new file mode 100644 index 000000000..ffbcf1cad --- /dev/null +++ b/bsi/src/main/java/org/roaringbitmap/bsi/longlong/Roaring64NavigableMapSliceIndex.java @@ -0,0 +1,731 @@ +package org.roaringbitmap.bsi.longlong; + +import org.roaringbitmap.bsi.BitmapSliceIndex; +import org.roaringbitmap.bsi.Pair; +import org.roaringbitmap.longlong.Roaring64NavigableMap; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.stream.IntStream; + +/** + * Roaring64NavigableMap based bsi implementation.
+ * + * See {@link #serialize} for more information for serialization format} + */ +public class Roaring64NavigableMapSliceIndex { + /** + * the maxValue of this bsi + */ + private long maxValue; + + /** + * the minValue of this bsi + */ + private long minValue; + + /** + * the bit component slice Array of this bsi + */ + private Roaring64NavigableMap[] bA; + + /** + * the exist bitmap of this bsi which means the columnId have value in this bsi + */ + private Roaring64NavigableMap ebM; + + private Boolean runOptimized = false; + + /** + * bsi serialization mode compatible with roaring(go) + */ + public static int BSI64_SERIALIZATION_MODE_COMPATIBLE_WITH_GO = 0; + + /** + * The serialization format for Roaring64NavigableMapSliceIndex.
+ * Currently, {@link #BSI64_SERIALIZATION_MODE_COMPATIBLE_WITH_GO} is supported.
+ * Other serialization formats maybe added in the future, and the serialization formats may change. + * See {@link #serialize} for more information for serialization format} + */ + public static int DEFAULT_BSI64_NAVIGABLE_SERIALIZATION_MODE = + BSI64_SERIALIZATION_MODE_COMPATIBLE_WITH_GO; + + /** + * NewDefaultBSI constructs an auto-sized BSI. + */ + public Roaring64NavigableMapSliceIndex() { + this(0L, 0L); + } + + /** + * NewBSI constructs a new BSI. Min/Max values are optional. If set to 0 + * then the underlying BSI will be automatically sized. + */ + public Roaring64NavigableMapSliceIndex(long minValue, long maxValue) { + if (minValue < 0) { + throw new IllegalArgumentException("Values should be non-negative"); + } + if (maxValue < minValue) { + throw new IllegalArgumentException("maxValue should GE minValue"); + } + + this.bA = new Roaring64NavigableMap[64 - Long.numberOfLeadingZeros(maxValue)]; + for (int i = 0; i < bA.length; i++) { + this.bA[i] = new Roaring64NavigableMap(); + } + + this.ebM = new Roaring64NavigableMap(); + } + + /** + * add all content from another BSI instance, current bsi is modified + */ + public void add(Roaring64NavigableMapSliceIndex otherBsi) { + if (null == otherBsi || otherBsi.ebM.isEmpty()) { + return; + } + + this.ebM.or(otherBsi.ebM); + if (otherBsi.bitCount() > this.bitCount()) { + grow(otherBsi.bitCount()); + } + + for (int i = 0; i < otherBsi.bitCount(); i++) { + this.addDigit(otherBsi.bA[i], i); + } + + // update min and max after adding + this.minValue = minValue(); + this.maxValue = maxValue(); + } + + /** + * add the specify slice to current 'bA[]' at index 'i', and 'carry' will be processed automatically + */ + private void addDigit(Roaring64NavigableMap foundSet, int i) { + Roaring64NavigableMap carry = Roaring64NavigableMap.and(this.bA[i], foundSet); + this.bA[i].xor(foundSet); + if (!carry.isEmpty()) { + if (i + 1 >= this.bitCount()) { + grow(this.bitCount() + 1); + } + this.addDigit(carry, i + 1); + } + } + + /** + * get the min value from the bsi + */ + public long minValue() { + if (ebM.isEmpty()) { + return 0; + } + + Roaring64NavigableMap minValuesId = ebM; + for (int i = bA.length - 1; i >= 0; i -= 1) { + Roaring64NavigableMap tmp = Roaring64NavigableMap.andNot(minValuesId, bA[i]); + if (!tmp.isEmpty()) { + minValuesId = tmp; + } + } + + return valueAt(minValuesId.first()); + } + + /** + * get the max value from the bsi + */ + public long maxValue() { + if (ebM.isEmpty()) { + return 0; + } + + Roaring64NavigableMap maxValuesId = ebM; + for (int i = bA.length - 1; i >= 0; i -= 1) { + Roaring64NavigableMap tmp = Roaring64NavigableMap.and(maxValuesId, bA[i]); + if (!tmp.isEmpty()) { + maxValuesId = tmp; + } + } + + return valueAt(maxValuesId.first()); + } + + /** + * return the value associated with the input columnId + * @param columnId the column id + * @return the value associated with the input columnId + */ + private long valueAt(long columnId) { + long value = 0; + for (int i = 0; i < this.bitCount(); i += 1) { + if (this.bA[i].contains(columnId)) { + value |= (1L << i); + } + } + + return value; + } + + /** + * RunOptimize attempts to further compress the runs of consecutive values found in the bitmap + */ + public void runOptimize() { + this.ebM.runOptimize(); + + for (Roaring64NavigableMap integers : this.bA) { + integers.runOptimize(); + } + this.runOptimized = true; + } + + /** + * hasRunCompression returns true if the bitmap benefits from run compression + */ + public boolean hasRunCompression() { + return this.runOptimized; + } + + /** + * GetExistenceBitmap returns a pointer to the underlying existence bitmap of the BSI + */ + public Roaring64NavigableMap getExistenceBitmap() { + return this.ebM; + } + + /** + * the number of slice + */ + public int bitCount() { + return this.bA.length; + } + + /** + * get the cardinality of the bsi (the number of distinct values added to the ebM) + */ + public long getLongCardinality() { + return this.ebM.getLongCardinality(); + } + + /** + * get the value at the column ID. + */ + public Pair getValue(long columnId) { + boolean exists = this.ebM.contains(columnId); + if (!exists) { + return Pair.newPair(0L, false); + } + + return Pair.newPair(valueAt(columnId), true); + } + + private void clear() { + this.maxValue = 0; + this.minValue = 0; + this.ebM = null; + this.bA = null; + } + + /** + * Serialize the BSI. + *

+ * Currently, only {@link #BSI64_SERIALIZATION_MODE_COMPATIBLE_WITH_GO} is supported.
+ * *NOTE* Other serialization formats maybe added in the future, and the serialization formats may change. + *

+ * The serialization format for underlying Roaring64NavigableMap depends on + * {@link Roaring64NavigableMap#SERIALIZATION_MODE}.
+ * NOTE: if {@link Roaring64NavigableMap#SERIALIZATION_MODE} = {@link Roaring64NavigableMap#SERIALIZATION_MODE_PORTABLE} + * and {@link #DEFAULT_BSI64_NAVIGABLE_SERIALIZATION_MODE} = {@link #BSI64_SERIALIZATION_MODE_COMPATIBLE_WITH_GO}, + * then the bsi serialization is compatible with bsi implementation of roaring(Go). + *

+ * Current serialization format:
+ * --- + *

+   * ebM as standard Roaring64NavigableMap format (with specify legacy/portable format)
+   * loop over bA[]  as standard Roaring64NavigableMap format (with specify legacy/portable format)
+   * 
+ * --- + *
+ * Consider calling {@link #runOptimize} before serialization to improve compression. + * The current bsi is not modified. + *

+ * @see bsi64.WriteTo + * @param output the DataOutput stream + * @throws IOException Signals that an I/O exception has occurred. + */ + public void serialize(DataOutput output) throws IOException { + if (DEFAULT_BSI64_NAVIGABLE_SERIALIZATION_MODE == BSI64_SERIALIZATION_MODE_COMPATIBLE_WITH_GO) { + // write ebm + this.ebM.serialize(output); + for (Roaring64NavigableMap rb : this.bA) { + rb.serialize(output); + } + } else { + throw new UnsupportedOperationException( + "unsupported serialization mode " + DEFAULT_BSI64_NAVIGABLE_SERIALIZATION_MODE); + } + } + + /** + * Deserialize (retrieve) the BSI.
+ * See {@link #serialize(DataOutput)} for the serialization format. + * The current bsi is overwritten. + *

+ * *NOTE*
+ * 1. multiple bsi objects in one {@code DataInput} not supported for current serialization format.
+ * 2. for proper deserialization, {@link Roaring64NavigableMap#SERIALIZATION_MODE} should be set + * to the value as serialization
+ * @param in the DataInput stream + * @throws IOException Signals that an I/O exception has occurred. + */ + public void deserialize(DataInput in) throws IOException { + if (DEFAULT_BSI64_NAVIGABLE_SERIALIZATION_MODE == BSI64_SERIALIZATION_MODE_COMPATIBLE_WITH_GO) { + this.clear(); + // read ebm + Roaring64NavigableMap ebm = new Roaring64NavigableMap(); + ebm.deserialize(in); + this.ebM = ebm; + + List baList = new ArrayList<>(); + try (DataInputStream is = new DataInputStream((InputStream) in); ) { + while (is.available() > 0) { + Roaring64NavigableMap rb = new Roaring64NavigableMap(); + rb.deserialize(in); + baList.add(rb); + } + } + this.bA = baList.toArray(new Roaring64NavigableMap[0]); + this.minValue = minValue(); + this.maxValue = maxValue(); + } else { + throw new UnsupportedOperationException( + "unsupported serialization mode " + DEFAULT_BSI64_NAVIGABLE_SERIALIZATION_MODE); + } + } + + /* + * get the serialized size in bytes + */ + public long serializedSizeInBytes() { + long size = 0; + for (Roaring64NavigableMap rb : this.bA) { + size += rb.serializedSizeInBytes(); + } + return this.ebM.serializedSizeInBytes() + size; + } + + /** + * valueExists tests whether the value exists. + */ + public boolean valueExist(long columnId) { + return this.ebM.contains(columnId); + } + + /** + * SetValue sets a value for a given columnID. + */ + public void setValue(long columnId, long value) { + ensureCapacityInternal(value, value); + setValueInternal(columnId, value); + } + + private void setValueInternal(long columnId, long value) { + for (int i = 0; i < this.bitCount(); i += 1) { + if ((value & (1L << i)) > 0) { + this.bA[i].add(columnId); + } else { + this.bA[i].removeLong(columnId); + } + } + this.ebM.add(columnId); + } + + private void ensureCapacityInternal(long minValue, long maxValue) { + if (ebM.isEmpty()) { + this.minValue = minValue; + this.maxValue = maxValue; + grow(Long.toBinaryString(maxValue).length()); + } else if (this.minValue > minValue) { + this.minValue = minValue; + } else if (this.maxValue < maxValue) { + this.maxValue = maxValue; + grow(Long.toBinaryString(maxValue).length()); + } + } + + private void grow(int newBitDepth) { + int oldBitDepth = this.bA.length; + + if (oldBitDepth >= newBitDepth) { + return; + } + + Roaring64NavigableMap[] newBA = new Roaring64NavigableMap[newBitDepth]; + if (oldBitDepth != 0) { + System.arraycopy(this.bA, 0, newBA, 0, oldBitDepth); + } + + for (int i = newBitDepth - 1; i >= oldBitDepth; i--) { + newBA[i] = new Roaring64NavigableMap(); + if (this.runOptimized) { + newBA[i].runOptimize(); + } + } + this.bA = newBA; + } + + /** + * set list of values + * @param values list of value pairs + */ + public void setValues(List> values) { + if (values == null || values.isEmpty()) return; + long maxValue = + values.stream().mapToLong(Pair::getRight).filter(Objects::nonNull).max().getAsLong(); + long minValue = + values.stream().mapToLong(Pair::getRight).filter(Objects::nonNull).min().getAsLong(); + ensureCapacityInternal(minValue, maxValue); + for (Pair pair : values) { + setValueInternal(pair.getKey(), pair.getValue()); + } + } + + /** + * merge will merge 2 bsi into current + * merge API was designed for distributed computing + * note: current and other bsi has no intersection + * + * @param otherBsi other bsi we need merge + */ + public void merge(Roaring64NavigableMapSliceIndex otherBsi) { + + if (null == otherBsi || otherBsi.ebM.isEmpty()) { + return; + } + + // todo whether we need this + if (Roaring64NavigableMap.intersects(this.ebM, otherBsi.ebM)) { + throw new IllegalArgumentException("merge can be used only in bsiA bsiB is null"); + } + + int bitDepth = Integer.max(this.bitCount(), otherBsi.bitCount()); + Roaring64NavigableMap[] newBA = new Roaring64NavigableMap[bitDepth]; + for (int i = 0; i < bitDepth; i++) { + Roaring64NavigableMap current = i < this.bA.length ? this.bA[i] : new Roaring64NavigableMap(); + Roaring64NavigableMap other = + i < otherBsi.bA.length ? otherBsi.bA[i] : new Roaring64NavigableMap(); + newBA[i] = Roaring64NavigableMap.or(current, other); + if (this.runOptimized || otherBsi.runOptimized) { + newBA[i].runOptimize(); + } + } + this.bA = newBA; + this.ebM.or(otherBsi.ebM); + this.runOptimized = this.runOptimized || otherBsi.runOptimized; + this.maxValue = Long.max(this.maxValue, otherBsi.maxValue); + this.minValue = Long.min(this.minValue, otherBsi.minValue); + } + + /** + * clone a bsi instance + */ + @Override + public Roaring64NavigableMapSliceIndex clone() { + Roaring64NavigableMapSliceIndex bitSliceIndex = new Roaring64NavigableMapSliceIndex(); + bitSliceIndex.minValue = this.minValue; + bitSliceIndex.maxValue = this.maxValue; + bitSliceIndex.ebM = this.ebM.clone(); + Roaring64NavigableMap[] cloneBA = new Roaring64NavigableMap[this.bitCount()]; + for (int i = 0; i < cloneBA.length; i++) { + cloneBA[i] = this.bA[i].clone(); + } + bitSliceIndex.bA = cloneBA; + bitSliceIndex.runOptimized = this.runOptimized; + return bitSliceIndex; + } + + /** + * O'Neil range using a bit-sliced index + * + * @param operation compare operation + * @param predicate the value we found filter + * @param foundSet columnId set we want compare,using RoaringBitmap to express + * @return columnId set we found in this bsi with giving conditions, using RoaringBitmap to express + * see https://github.com/lemire/BitSliceIndex/blob/master/src/main/java/org/roaringbitmap/circuits/comparator/BasicComparator.java + */ + private Roaring64NavigableMap oNeilCompare( + BitmapSliceIndex.Operation operation, long predicate, Roaring64NavigableMap foundSet) { + Roaring64NavigableMap fixedFoundSet = foundSet == null ? this.ebM : foundSet; + + Roaring64NavigableMap GT = new Roaring64NavigableMap(); + Roaring64NavigableMap LT = new Roaring64NavigableMap(); + Roaring64NavigableMap EQ = this.ebM; + + for (int i = this.bitCount() - 1; i >= 0; i--) { + int bit = (int) ((predicate >> i) & 1); + if (bit == 1) { + LT = Roaring64NavigableMap.or(LT, Roaring64NavigableMap.andNot(EQ, this.bA[i])); + EQ = Roaring64NavigableMap.and(EQ, this.bA[i]); + } else { + GT = Roaring64NavigableMap.or(GT, Roaring64NavigableMap.and(EQ, this.bA[i])); + EQ = Roaring64NavigableMap.andNot(EQ, this.bA[i]); + } + } + EQ = Roaring64NavigableMap.and(fixedFoundSet, EQ); + switch (operation) { + case EQ: + return EQ; + case NEQ: + return Roaring64NavigableMap.andNot(fixedFoundSet, EQ); + case GT: + return Roaring64NavigableMap.and(GT, fixedFoundSet); + case LT: + return Roaring64NavigableMap.and(LT, fixedFoundSet); + case LE: + return Roaring64NavigableMap.and(Roaring64NavigableMap.or(LT, EQ), fixedFoundSet); + case GE: + return Roaring64NavigableMap.and(Roaring64NavigableMap.or(GT, EQ), fixedFoundSet); + default: + throw new IllegalArgumentException(""); + } + } + + /** + * BSI Compare using single thread + * this Function compose algorithm from O'Neil and Owen Kaser + * the GE algorithm is from Owen since the performance is better. others are from O'Neil + * + * @param operation the operation of BitmapSliceIndex.Operation + * @param startOrValue the start or value of comparison, when the comparison operation is range, it's start, + * when others,it's value. + * @param end the end value of comparison. when the comparison operation is not range,the end = 0 + * @param foundSet columnId set we want compare,using RoaringBitmap to express + * @return columnId set we found in this bsi with giving conditions, using Roaring64NavigableMap to express + */ + public Roaring64NavigableMap compare( + BitmapSliceIndex.Operation operation, + long startOrValue, + long end, + Roaring64NavigableMap foundSet) { + Roaring64NavigableMap result = compareUsingMinMax(operation, startOrValue, end, foundSet); + if (result != null) { + return result; + } + + switch (operation) { + case EQ: + return oNeilCompare(BitmapSliceIndex.Operation.EQ, startOrValue, foundSet); + case NEQ: + return oNeilCompare(BitmapSliceIndex.Operation.NEQ, startOrValue, foundSet); + case GE: + return oNeilCompare(BitmapSliceIndex.Operation.GE, startOrValue, foundSet); + case GT: + { + return oNeilCompare(BitmapSliceIndex.Operation.GT, startOrValue, foundSet); + } + case LT: + return oNeilCompare(BitmapSliceIndex.Operation.LT, startOrValue, foundSet); + + case LE: + return oNeilCompare(BitmapSliceIndex.Operation.LE, startOrValue, foundSet); + + case RANGE: + { + if (startOrValue < minValue) { + startOrValue = minValue; + } + if (end > maxValue) { + end = maxValue; + } + Roaring64NavigableMap left = + oNeilCompare(BitmapSliceIndex.Operation.GE, startOrValue, foundSet); + Roaring64NavigableMap right = oNeilCompare(BitmapSliceIndex.Operation.LE, end, foundSet); + + return Roaring64NavigableMap.and(left, right); + } + default: + throw new IllegalArgumentException("not support operation!"); + } + } + + private Roaring64NavigableMap compareUsingMinMax( + BitmapSliceIndex.Operation operation, + long startOrValue, + long end, + Roaring64NavigableMap foundSet) { + Roaring64NavigableMap all = + foundSet == null ? ebM.clone() : Roaring64NavigableMap.and(ebM, foundSet); + Roaring64NavigableMap empty = new Roaring64NavigableMap(); + + switch (operation) { + case LT: + if (startOrValue > maxValue) { + return all; + } else if (startOrValue <= minValue) { + return empty; + } + + break; + case LE: + if (startOrValue >= maxValue) { + return all; + } else if (startOrValue < minValue) { + return empty; + } + + break; + case GT: + if (startOrValue < minValue) { + return all; + } else if (startOrValue >= maxValue) { + return empty; + } + + break; + case GE: + if (startOrValue <= minValue) { + return all; + } else if (startOrValue > maxValue) { + return empty; + } + + break; + case EQ: + if (minValue == maxValue && minValue == startOrValue) { + return all; + } else if (startOrValue < minValue || startOrValue > maxValue) { + return empty; + } + + break; + case NEQ: + if (minValue == maxValue) { + return minValue == startOrValue ? empty : all; + } + + break; + case RANGE: + if (startOrValue <= minValue && end >= maxValue) { + return all; + } else if (startOrValue > maxValue || end < minValue) { + return empty; + } + + break; + default: + return null; + } + + return null; + } + + /** + * given columns in foundSet, return the count and sum of values found in BSI + * @param foundSet given columnIds (represent as Roaring64NavigableMap) + * @return the <sum, count> pair + */ + public Pair sum(Roaring64NavigableMap foundSet) { + if (null == foundSet || foundSet.isEmpty()) { + return Pair.newPair(0L, 0L); + } + long count = foundSet.getLongCardinality(); + + long sum = + IntStream.range(0, this.bitCount()) + .mapToLong(x -> (1L << x) * Roaring64NavigableMap.andCardinality(this.bA[x], foundSet)) + .sum(); + + return Pair.newPair(sum, count); + } + + /** + * given columns in foundSet, return the top k columnId found in BSI + * @param foundSet the columnIds needs to be checked (represent as Roaring64NavigableMap) + * @param k top k + * @return the top k columnIds found in BSI + */ + public Roaring64NavigableMap topK(Roaring64NavigableMap foundSet, long k) { + if (null == foundSet || foundSet.isEmpty()) { + return new Roaring64NavigableMap(); + } + if (k >= foundSet.getLongCardinality()) { + return foundSet; + } + Roaring64NavigableMap re = new Roaring64NavigableMap(); + Roaring64NavigableMap candidates = foundSet.clone(); + // keep target K value + long originalTargetTopK = k; + + for (int x = this.bitCount() - 1; x >= 0 && !candidates.isEmpty() && k > 0; x--) { + Roaring64NavigableMap X = Roaring64NavigableMap.and(candidates, this.bA[x]); + long cardinality = X.getLongCardinality(); + if (cardinality > k) { + candidates.and(this.bA[x]); + } else { + re.or(X); + candidates.andNot(this.bA[x]); + k -= cardinality; + } + } + + // check whether we get enough items in 're' + long reCardinality = re.getLongCardinality(); + long candidatesCardinality = candidates.getLongCardinality(); + if (reCardinality < originalTargetTopK) { + // 're' has not enough items, pick some items from candidates, then merge re&candidates + long dismissCandidatesCnt = candidatesCardinality + reCardinality - originalTargetTopK; + Iterator iterator = candidates.iterator(); + while (iterator.hasNext() && dismissCandidatesCnt > 0) { + // remove some items from candidates + candidates.removeLong(iterator.next()); + dismissCandidatesCnt--; + } + } else { + candidates = null; + } + return Roaring64NavigableMap.or(re, candidates); + } + + /** + * given columns in foundSet, + * 1. if one columnId of foundSet is in the bsi, then get the associated value + * 2. then return all the values as a Roaring64NavigableMap. + * @param foundSet the columnIds needs to be checked, null if all columnIds needs to be checked + */ + public Roaring64NavigableMap transpose(Roaring64NavigableMap foundSet) { + Roaring64NavigableMap re = new Roaring64NavigableMap(); + Roaring64NavigableMap fixedFoundSet = + foundSet == null ? this.ebM : Roaring64NavigableMap.and(foundSet, this.ebM); + fixedFoundSet.forEach((long x) -> re.add(this.getValue(x).getKey())); + return re; + } + + /** + * given columns in foundSet, + * 1. if one columnId of foundSet is in the bsi, then get the associated value in the bsi + * 2. then return all the <value, # of columnIds> as a bsi. + * @param foundSet the columnIds needs to be checked, null if all columnIds needs to be checked + */ + public Roaring64NavigableMapSliceIndex transposeWithCount(Roaring64NavigableMap foundSet) { + Roaring64NavigableMapSliceIndex re = new Roaring64NavigableMapSliceIndex(); + Roaring64NavigableMap fixedFoundSet = + foundSet == null ? this.ebM : Roaring64NavigableMap.and(foundSet, this.ebM); + fixedFoundSet.forEach( + (long x) -> { + long nk = this.getValue(x).getKey(); + if (re.valueExist(nk)) { + re.setValue(nk, re.getValue(nk).getKey() + 1); + } else { + re.setValue(nk, 1); + } + }); + return re; + } +} diff --git a/bsi/src/test/java/org/roaringbitmap/bsi/BufferBSITest.java b/bsi/src/test/java/org/roaringbitmap/bsi/BufferBSITest.java index 9f5a68a5e..ac795f28c 100644 --- a/bsi/src/test/java/org/roaringbitmap/bsi/BufferBSITest.java +++ b/bsi/src/test/java/org/roaringbitmap/bsi/BufferBSITest.java @@ -1,18 +1,25 @@ - package org.roaringbitmap.bsi; - - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +package org.roaringbitmap.bsi; import org.roaringbitmap.bsi.buffer.ImmutableBitSliceIndex; import org.roaringbitmap.bsi.buffer.MutableBitSliceIndex; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.roaringbitmap.buffer.MutableRoaringBitmap; -import java.io.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.nio.ByteBuffer; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -25,396 +32,408 @@ */ public class BufferBSITest { - private Map testDataSet = new HashMap<>(); - - private MutableBitSliceIndex mBsi; - - private ImmutableBitSliceIndex imBsi; - - - @BeforeEach - public void setup() { - IntStream.range(1, 100).forEach(x -> testDataSet.put(x, x)); - mBsi = new MutableBitSliceIndex(1, 99); - testDataSet.forEach((k, v) -> { - mBsi.setValue(k, v); - }); - imBsi = mBsi.toImmutableBitSliceIndex(); - } - - @Test - public void testSetAndGet() { - IntStream.range(1, 100).forEach(x -> { - Pair pair = mBsi.getValue(x); - Assertions.assertTrue(pair.getRight()); - Assertions.assertTrue(pair.getKey() == x); - }); - - IntStream.range(1, 100).forEach(x -> { - Pair pair = imBsi.getValue(x); - Assertions.assertTrue(pair.getRight()); - Assertions.assertTrue(pair.getKey() == x); - }); - } - - @Test - public void testMerge() { - MutableBitSliceIndex bsiA = new MutableBitSliceIndex(); - IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); - MutableBitSliceIndex bsiB = new MutableBitSliceIndex(); - IntStream.range(100, 199).forEach(x -> bsiB.setValue(x, x)); - Assertions.assertEquals(bsiA.getExistenceBitmap().getLongCardinality(), 99); - Assertions.assertEquals(bsiB.getExistenceBitmap().getLongCardinality(), 99); - bsiA.merge(bsiB); - IntStream.range(1, 199).forEach(x -> { - Pair bsiValue = bsiA.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - + private Map testDataSet = new HashMap<>(); - @Test - public void testClone() { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); - List> collect = testDataSet.entrySet() - .stream().map(x -> Pair.newPair(x.getKey(), x.getValue())).collect(Collectors.toList()); + private MutableBitSliceIndex mBsi; - bsi.setValues(collect); + private ImmutableBitSliceIndex imBsi; - Assertions.assertEquals(bsi.getExistenceBitmap().getLongCardinality(), 99); - final MutableBitSliceIndex clone = bsi.clone(); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = clone.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); + @BeforeEach + public void setup() { + IntStream.range(1, 100).forEach(x -> testDataSet.put(x, x)); + mBsi = new MutableBitSliceIndex(1, 99); + testDataSet.forEach( + (k, v) -> { + mBsi.setValue(k, v); }); - } - - - @Test - public void testAdd() { - MutableBitSliceIndex bsiA = new MutableBitSliceIndex(); - IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); - MutableBitSliceIndex bsiB = new MutableBitSliceIndex(); - IntStream.range(1, 120).forEach(x -> bsiB.setValue(x, x)); - - bsiA.add(bsiB); - - IntStream.range(1, 120).forEach(x -> { - Pair bsiValue = bsiA.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - if (x < 100) { + imBsi = mBsi.toImmutableBitSliceIndex(); + } + + @Test + public void testSetAndGet() { + IntStream.range(1, 100) + .forEach( + x -> { + Pair pair = mBsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertTrue(pair.getKey() == x); + }); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair pair = imBsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertTrue(pair.getKey() == x); + }); + } + + @Test + public void testMerge() { + MutableBitSliceIndex bsiA = new MutableBitSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + MutableBitSliceIndex bsiB = new MutableBitSliceIndex(); + IntStream.range(100, 199).forEach(x -> bsiB.setValue(x, x)); + Assertions.assertEquals(bsiA.getExistenceBitmap().getLongCardinality(), 99); + Assertions.assertEquals(bsiB.getExistenceBitmap().getLongCardinality(), 99); + bsiA.merge(bsiB); + IntStream.range(1, 199) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testClone() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); + List> collect = + testDataSet.entrySet().stream() + .map(x -> Pair.newPair(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + + bsi.setValues(collect); + + Assertions.assertEquals(bsi.getExistenceBitmap().getLongCardinality(), 99); + final MutableBitSliceIndex clone = bsi.clone(); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = clone.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testAdd() { + MutableBitSliceIndex bsiA = new MutableBitSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + MutableBitSliceIndex bsiB = new MutableBitSliceIndex(); + IntStream.range(1, 120).forEach(x -> bsiB.setValue(x, x)); + + bsiA.add(bsiB); + + IntStream.range(1, 120) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + if (x < 100) { Assertions.assertEquals((int) bsiValue.getKey(), x * 2); - } else { + } else { Assertions.assertEquals((int) bsiValue.getKey(), x); - } - - }); - } - - @Test - public void testAddAndEvaluate() { - MutableBitSliceIndex bsiA = new MutableBitSliceIndex(); - IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); - MutableBitSliceIndex bsiB = new MutableBitSliceIndex(); - IntStream.range(1, 120).forEach(x -> bsiB.setValue(120 - x, x)); - - bsiA.add(bsiB); - - ImmutableRoaringBitmap result = bsiA.compare(BitmapSliceIndex.Operation.EQ, 120, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(result.toArray(), IntStream.range(1, 100).toArray()); - - result = bsiA.compare(BitmapSliceIndex.Operation.RANGE, 1, 20, null); - Assertions.assertTrue(result.getLongCardinality() == 20); - Assertions.assertArrayEquals(result.toArray(), IntStream.range(100, 120).toArray()); - } - - - @Test - public void TestIO4Stream() throws IOException { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream bdo = new DataOutputStream(bos); - bsi.serialize(bdo); - byte[] data = bos.toByteArray(); - - MutableBitSliceIndex newBsi = new MutableBitSliceIndex(); - - ByteArrayInputStream bis = new ByteArrayInputStream(data); - DataInputStream bdi = new DataInputStream(bis); - newBsi.deserialize(bdi); - - Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = newBsi.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - - @Test - public void testIO4Buffer() throws IOException { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - ByteBuffer buffer = ByteBuffer.allocate(bsi.serializedSizeInBytes()); - bsi.serialize(buffer); - - byte[] data = buffer.array(); - MutableBitSliceIndex newBsi = new MutableBitSliceIndex(); - newBsi.deserialize(ByteBuffer.wrap(data)); - Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = newBsi.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - - - @Test - public void testIOFromExternal() { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - - - ImmutableBitSliceIndex iBsi = bsi.toImmutableBitSliceIndex(); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = iBsi.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - - // non parallel operation test - @Test - public void testSum() { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - - - ImmutableBitSliceIndex iBsi = bsi.toImmutableBitSliceIndex(); - - MutableRoaringBitmap foundSet = MutableRoaringBitmap.bitmapOf(IntStream.range(1, 51).toArray()); - - Pair sumPair = iBsi.sum(foundSet); - - System.out.println("sum:" + sumPair.toString()); - - int sum = IntStream.range(1, 51).sum(); - long count = IntStream.range(1, 51).count(); - - Assertions.assertTrue(sumPair.getLeft().intValue() == sum && sumPair.getRight() == count); - - } - - @Test - public void testEQ() { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> { - if (x <= 50) { + } + }); + } + + @Test + public void testAddAndEvaluate() { + MutableBitSliceIndex bsiA = new MutableBitSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + MutableBitSliceIndex bsiB = new MutableBitSliceIndex(); + IntStream.range(1, 120).forEach(x -> bsiB.setValue(120 - x, x)); + + bsiA.add(bsiB); + + ImmutableRoaringBitmap result = bsiA.compare(BitmapSliceIndex.Operation.EQ, 120, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(result.toArray(), IntStream.range(1, 100).toArray()); + + result = bsiA.compare(BitmapSliceIndex.Operation.RANGE, 1, 20, null); + Assertions.assertTrue(result.getLongCardinality() == 20); + Assertions.assertArrayEquals(result.toArray(), IntStream.range(100, 120).toArray()); + } + + @Test + public void TestIO4Stream() throws IOException { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream bdo = new DataOutputStream(bos); + bsi.serialize(bdo); + byte[] data = bos.toByteArray(); + + MutableBitSliceIndex newBsi = new MutableBitSliceIndex(); + + ByteArrayInputStream bis = new ByteArrayInputStream(data); + DataInputStream bdi = new DataInputStream(bis); + newBsi.deserialize(bdi); + + Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = newBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testIO4Buffer() throws IOException { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + ByteBuffer buffer = ByteBuffer.allocate(bsi.serializedSizeInBytes()); + bsi.serialize(buffer); + + byte[] data = buffer.array(); + MutableBitSliceIndex newBsi = new MutableBitSliceIndex(); + newBsi.deserialize(ByteBuffer.wrap(data)); + Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = newBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testIOFromExternal() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + ImmutableBitSliceIndex iBsi = bsi.toImmutableBitSliceIndex(); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = iBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + // non parallel operation test + @Test + public void testSum() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + ImmutableBitSliceIndex iBsi = bsi.toImmutableBitSliceIndex(); + + MutableRoaringBitmap foundSet = MutableRoaringBitmap.bitmapOf(IntStream.range(1, 51).toArray()); + + Pair sumPair = iBsi.sum(foundSet); + + System.out.println("sum:" + sumPair.toString()); + + int sum = IntStream.range(1, 51).sum(); + long count = IntStream.range(1, 51).count(); + + Assertions.assertTrue(sumPair.getLeft().intValue() == sum && sumPair.getRight() == count); + } + + @Test + public void testEQ() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); + IntStream.range(1, 100) + .forEach( + x -> { + if (x <= 50) { bsi.setValue(x, 1); - } else { + } else { bsi.setValue(x, x); - } - - }); - - ImmutableRoaringBitmap bitmap = bsi.toImmutableBitSliceIndex().rangeEQ(null, 1); - Assertions.assertTrue(bitmap.getLongCardinality() == 50L); - ImmutableRoaringBitmap bitmap129 = bsi.toImmutableBitSliceIndex().rangeEQ(null, 129); - Assertions.assertTrue(bitmap129.getLongCardinality() == 0L); - - ImmutableRoaringBitmap bitmap99 = bsi.toImmutableBitSliceIndex().rangeEQ(null, 99); - Assertions.assertTrue(bitmap99.getLongCardinality() == 1L); - Assertions.assertTrue(bitmap99.contains(99)); - } - - @Test - public void testNotEQ() { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(); - bsi.setValue(1, 99); - bsi.setValue(2, 1); - bsi.setValue(3, 50); - - ImmutableRoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 2); - Assertions.assertArrayEquals(new int[]{2, 3}, result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 100, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 3); - Assertions.assertArrayEquals(new int[]{1, 2, 3}, result.toArray()); - - bsi = new MutableBitSliceIndex(); - bsi.setValue(1, 99); - bsi.setValue(2, 99); - bsi.setValue(3, 99); - - result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); - Assertions.assertTrue(result.isEmpty()); - - result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 1, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 3); - Assertions.assertArrayEquals(new int[]{1, 2, 3}, result.toArray()); - } - - - // parallel operation test - - @Test - public void testGT() { - ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.GT, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 49); - Assertions.assertArrayEquals(IntStream.range(51, 100).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.GT, 0, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.GT, 99, 0, null); - Assertions.assertTrue(result.isEmpty()); - } - - - @Test - public void testGE() { - ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.GE, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 50); - Assertions.assertArrayEquals(IntStream.range(50, 100).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.GE, 1, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.GE, 100, 0, null); - Assertions.assertTrue(result.isEmpty()); - } - - @Test - public void testLT() { - ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.LT, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 49); - Assertions.assertArrayEquals(IntStream.range(1, 50).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.LT, Integer.MAX_VALUE, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.LT, 1, 0, null); - Assertions.assertTrue(result.isEmpty()); + } + }); + + ImmutableRoaringBitmap bitmap = bsi.toImmutableBitSliceIndex().rangeEQ(null, 1); + Assertions.assertTrue(bitmap.getLongCardinality() == 50L); + ImmutableRoaringBitmap bitmap129 = bsi.toImmutableBitSliceIndex().rangeEQ(null, 129); + Assertions.assertTrue(bitmap129.getLongCardinality() == 0L); + + ImmutableRoaringBitmap bitmap99 = bsi.toImmutableBitSliceIndex().rangeEQ(null, 99); + Assertions.assertTrue(bitmap99.getLongCardinality() == 1L); + Assertions.assertTrue(bitmap99.contains(99)); + } + + @Test + public void testNotEQ() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 1); + bsi.setValue(3, 50); + + ImmutableRoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 2); + Assertions.assertArrayEquals(new int[] {2, 3}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 100, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(new int[] {1, 2, 3}, result.toArray()); + + bsi = new MutableBitSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 99); + bsi.setValue(3, 99); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 1, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(new int[] {1, 2, 3}, result.toArray()); + } + + // parallel operation test + + @Test + public void testGT() { + ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.GT, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 49); + Assertions.assertArrayEquals(IntStream.range(51, 100).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.GT, 0, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.GT, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testGE() { + ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.GE, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 50); + Assertions.assertArrayEquals(IntStream.range(50, 100).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.GE, 1, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.GE, 100, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLT() { + ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.LT, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 49); + Assertions.assertArrayEquals(IntStream.range(1, 50).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.LT, Integer.MAX_VALUE, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.LT, 1, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLE() { + ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.LE, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 50); + Assertions.assertArrayEquals(IntStream.range(1, 51).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.LE, Integer.MAX_VALUE, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.LE, 0, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testRANGE() { + ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.RANGE, 10, 20, null); + Assertions.assertTrue(result.getLongCardinality() == 11); + Assertions.assertArrayEquals(IntStream.range(10, 21).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.RANGE, 1, 200, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = imBsi.compare(BitmapSliceIndex.Operation.RANGE, 1000, 2000, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testValueZero() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(); + bsi.setValue(0, 0); + bsi.setValue(1, 0); + bsi.setValue(2, 1); + + ImmutableRoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.EQ, 0, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 2); + Assertions.assertArrayEquals(new int[] {0, 1}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 1); + Assertions.assertArrayEquals(new int[] {2}, result.toArray()); + } + + @Test + public void testIN() throws ExecutionException, InterruptedException { + + Set values = new HashSet<>(); + int[] valArr = new int[20]; + for (int i = 0; i < 20; i++) { + values.add(i + 1); + valArr[i] = i + 1; } - - @Test - public void testLE() { - ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.LE, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 50); - Assertions.assertArrayEquals(IntStream.range(1, 51).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.LE, Integer.MAX_VALUE, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.LE, 0, 0, null); - Assertions.assertTrue(result.isEmpty()); - } - - @Test - public void testRANGE() { - ImmutableRoaringBitmap result = imBsi.compare(BitmapSliceIndex.Operation.RANGE, 10, 20, null); - Assertions.assertTrue(result.getLongCardinality() == 11); - Assertions.assertArrayEquals(IntStream.range(10, 21).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.RANGE, 1, 200, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = imBsi.compare(BitmapSliceIndex.Operation.RANGE, 1000, 2000, null); - Assertions.assertTrue(result.isEmpty()); - } - - @Test - public void testValueZero() { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(); - bsi.setValue(0, 0); - bsi.setValue(1, 0); - bsi.setValue(2, 1); - - ImmutableRoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.EQ, 0, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 2); - Assertions.assertArrayEquals(new int[]{0, 1}, result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 1); - Assertions.assertArrayEquals(new int[]{2}, result.toArray()); - } - - @Test - public void testIN() throws ExecutionException, InterruptedException { - - Set values = new HashSet<>(); - int[] valArr = new int[20]; - for (int i = 0; i < 20; i++) { - values.add(i + 1); - valArr[i] = i + 1; - } - - - ExecutorService pool = Executors.newFixedThreadPool(2); - ImmutableRoaringBitmap result = imBsi.parallelIn(2, - null, values, pool); - Assertions.assertTrue(result.getLongCardinality() == values.size()); - Assertions.assertArrayEquals(valArr, result.toArray()); - pool.shutdownNow(); - } - - - @Test - public void testTransposeWithCount() throws ExecutionException, InterruptedException { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> { - if (x <= 30) { + ExecutorService pool = Executors.newFixedThreadPool(2); + ImmutableRoaringBitmap result = imBsi.parallelIn(2, null, values, pool); + Assertions.assertTrue(result.getLongCardinality() == values.size()); + Assertions.assertArrayEquals(valArr, result.toArray()); + pool.shutdownNow(); + } + + @Test + public void testTransposeWithCount() throws ExecutionException, InterruptedException { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 99); + IntStream.range(1, 100) + .forEach( + x -> { + if (x <= 30) { bsi.setValue(x, 1); - } else if (x <= 60) { + } else if (x <= 60) { bsi.setValue(x, 2); - } else { + } else { bsi.setValue(x, 3); - } - - }); - - ExecutorService pool = Executors.newFixedThreadPool(2); - ImmutableBitSliceIndex iBsi = bsi.toImmutableBitSliceIndex(); - - final MutableBitSliceIndex result = iBsi.parallelTransposeWithCount(null, 2, pool); - - List> pairs = result.toPairList(); - pairs.forEach(System.out::println); - - - Assertions.assertEquals(30, (int) result.getValue(1).getKey()); - Assertions.assertEquals(30, (int) result.getValue(2).getKey()); - Assertions.assertEquals(39, (int) result.getValue(3).getKey()); - - } - - - @Test - public void testTopK() { - MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 100001); - IntStream.range(1, 100001).forEach(x -> bsi.setValue(x, x)); - long start = System.currentTimeMillis(); - MutableRoaringBitmap top = bsi.topK(null, 20); - long end = System.currentTimeMillis(); - System.out.println(top.toString() + " \ntime cost:" + (end - start)); - } - - + } + }); + + ExecutorService pool = Executors.newFixedThreadPool(2); + ImmutableBitSliceIndex iBsi = bsi.toImmutableBitSliceIndex(); + + final MutableBitSliceIndex result = iBsi.parallelTransposeWithCount(null, 2, pool); + + List> pairs = result.toPairList(); + pairs.forEach(System.out::println); + + Assertions.assertEquals(30, (int) result.getValue(1).getKey()); + Assertions.assertEquals(30, (int) result.getValue(2).getKey()); + Assertions.assertEquals(39, (int) result.getValue(3).getKey()); + } + + @Test + public void testTopK() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(1, 100001); + IntStream.range(1, 100001).forEach(x -> bsi.setValue(x, x)); + long start = System.currentTimeMillis(); + MutableRoaringBitmap top = bsi.topK(null, 20); + long end = System.currentTimeMillis(); + System.out.println(top.toString() + " \ntime cost:" + (end - start)); + } + + @Test + public void testIssue745() { + MutableBitSliceIndex bsi = new MutableBitSliceIndex(); + bsi.setValue(1, 1); + bsi.setValue(2, 1); + bsi.setValue(3, 1); + bsi.setValue(4, 1); + bsi.setValue(5, 1); + MutableRoaringBitmap top = bsi.topK(null, 1); + System.out.println(top); + } } - diff --git a/bsi/src/test/java/org/roaringbitmap/bsi/R64BSITest.java b/bsi/src/test/java/org/roaringbitmap/bsi/R64BSITest.java new file mode 100644 index 000000000..b119e5a52 --- /dev/null +++ b/bsi/src/test/java/org/roaringbitmap/bsi/R64BSITest.java @@ -0,0 +1,452 @@ +package org.roaringbitmap.bsi; + +import org.roaringbitmap.bsi.longlong.Roaring64BitmapSliceIndex; +import org.roaringbitmap.longlong.Roaring64Bitmap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + +public class R64BSITest { + private Map testDataSet = new HashMap<>(); + + private Roaring64BitmapSliceIndex bsi; + + @BeforeEach + public void setup() { + LongStream.range(1, 100).forEach(x -> testDataSet.put(x, x)); + bsi = new Roaring64BitmapSliceIndex(1, 99); + testDataSet.forEach( + (k, v) -> { + bsi.setValue(k, v); + }); + } + + @Test + public void testSetAndGet() { + LongStream.range(1, 100) + .forEach( + x -> { + Pair pair = bsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertEquals((long) pair.getKey(), x); + }); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair pair = bsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertEquals((long) pair.getKey(), x); + }); + } + + @Test + public void testMerge() { + Roaring64BitmapSliceIndex bsiA = new Roaring64BitmapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + Roaring64BitmapSliceIndex bsiB = new Roaring64BitmapSliceIndex(); + IntStream.range(100, 199).forEach(x -> bsiB.setValue(x, x)); + Assertions.assertEquals(bsiA.getExistenceBitmap().getLongCardinality(), 99); + Assertions.assertEquals(bsiB.getExistenceBitmap().getLongCardinality(), 99); + bsiA.merge(bsiB); + IntStream.range(1, 199) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testClone() { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(1, 99); + List> collect = + testDataSet.entrySet().stream() + .map(x -> Pair.newPair(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + + bsi.setValues(collect); + + Assertions.assertEquals(bsi.getExistenceBitmap().getLongCardinality(), 99); + final Roaring64BitmapSliceIndex clone = bsi.clone(); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = clone.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testAdd() { + Roaring64BitmapSliceIndex bsiA = new Roaring64BitmapSliceIndex(); + LongStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + Roaring64BitmapSliceIndex bsiB = new Roaring64BitmapSliceIndex(); + LongStream.range(1, 120).forEach(x -> bsiB.setValue(x, x)); + + bsiA.add(bsiB); + + LongStream.range(1, 120) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + if (x < 100) { + Assertions.assertEquals((long) bsiValue.getKey(), x * 2); + } else { + Assertions.assertEquals((long) bsiValue.getKey(), x); + } + }); + } + + @Test + public void testAddAndEvaluate() { + Roaring64BitmapSliceIndex bsiA = new Roaring64BitmapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + Roaring64BitmapSliceIndex bsiB = new Roaring64BitmapSliceIndex(); + IntStream.range(1, 120).forEach(x -> bsiB.setValue(120 - x, x)); + + bsiA.add(bsiB); + + Roaring64Bitmap result = bsiA.compare(BitmapSliceIndex.Operation.EQ, 120, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(result.toArray(), LongStream.range(1, 100).toArray()); + + result = bsiA.compare(BitmapSliceIndex.Operation.RANGE, 1, 20, null); + Assertions.assertEquals(20, result.getLongCardinality()); + Assertions.assertArrayEquals(result.toArray(), LongStream.range(100, 120).toArray()); + } + + @Test + public void TestIO4Stream() throws IOException { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(1, 99); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream bdo = new DataOutputStream(bos); + bsi.serialize(bdo); + byte[] data = bos.toByteArray(); + + Roaring64BitmapSliceIndex newBsi = new Roaring64BitmapSliceIndex(); + + ByteArrayInputStream bis = new ByteArrayInputStream(data); + DataInputStream bdi = new DataInputStream(bis); + newBsi.deserialize(bdi); + + Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); + + LongStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = newBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testIO4Buffer() throws IOException { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(1, 99); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + ByteBuffer buffer = ByteBuffer.allocate(bsi.serializedSizeInBytes()); + bsi.serialize(buffer); + + byte[] data = buffer.array(); + Roaring64BitmapSliceIndex newBsi = new Roaring64BitmapSliceIndex(); + newBsi.deserialize(ByteBuffer.wrap(data)); + Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); + + LongStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = newBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testIOFromExternal() { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(1, 99); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + LongStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = bsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testEQ() { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(1, 99); + LongStream.range(1, 100) + .forEach( + x -> { + if (x <= 50) { + bsi.setValue(x, 1); + } else { + bsi.setValue(x, x); + } + }); + + Roaring64Bitmap bitmap = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); + Assertions.assertEquals(50L, bitmap.getLongCardinality()); + } + + @Test + public void testNotEQ() { + bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 1); + bsi.setValue(3, 50); + + Roaring64Bitmap result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertEquals(2, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {2, 3}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 100, 0, null); + Assertions.assertEquals(3, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {1, 2, 3}, result.toArray()); + + bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 99); + bsi.setValue(3, 99); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 1, 0, null); + Assertions.assertEquals(3, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {1, 2, 3}, result.toArray()); + } + + // parallel operation test + + @Test + public void testGT() { + Roaring64Bitmap result = bsi.compare(BitmapSliceIndex.Operation.GT, 50, 0, null); + Assertions.assertEquals(49, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(51, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GT, 0, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GT, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testGE() { + Roaring64Bitmap result = bsi.compare(BitmapSliceIndex.Operation.GE, 50, 0, null); + Assertions.assertEquals(50, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(50, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GE, 1, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GE, 100, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLT() { + Roaring64Bitmap result = bsi.compare(BitmapSliceIndex.Operation.LT, 50, 0, null); + Assertions.assertEquals(49, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 50).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LT, Integer.MAX_VALUE, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LT, 1, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLE() { + Roaring64Bitmap result = bsi.compare(BitmapSliceIndex.Operation.LE, 50, 0, null); + Assertions.assertEquals(50, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 51).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, Integer.MAX_VALUE, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, 0, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testRANGE() { + Roaring64Bitmap result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 10, 20, null); + Assertions.assertEquals(11, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(10, 21).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1, 200, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1000, 2000, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testSum() { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(1, 99); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + Roaring64Bitmap foundSet = Roaring64Bitmap.bitmapOf(LongStream.range(1, 51).toArray()); + + Pair sumPair = bsi.sum(foundSet); + + System.out.println("sum:" + sumPair.toString()); + + long sum = LongStream.range(1, 51).sum(); + long count = LongStream.range(1, 51).count(); + + Assertions.assertTrue(sumPair.getLeft().intValue() == sum && sumPair.getRight() == count); + } + + @Test + public void testValueZero() { + bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(0, 0); + bsi.setValue(1, 0); + bsi.setValue(2, 1); + + Roaring64Bitmap result = bsi.compare(BitmapSliceIndex.Operation.EQ, 0, 0, null); + Assertions.assertEquals(2, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {0, 1}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); + Assertions.assertEquals(1, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {2}, result.toArray()); + } + + @Test + public void testTopK() { + bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(1, 3); + bsi.setValue(2, 6); + bsi.setValue(3, 4); + bsi.setValue(4, 10); + bsi.setValue(5, 7); + Roaring64Bitmap re = bsi.topK(bsi.getExistenceBitmap(), 2); + Assertions.assertEquals(re, Roaring64Bitmap.bitmapOf(4, 5)); + } + + @Test + public void testTranspose() { + bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(1, 2); + bsi.setValue(2, 4); + bsi.setValue(3, 4); + bsi.setValue(4, 8); + bsi.setValue(5, 8); + Roaring64Bitmap re = bsi.transpose(null); + Assertions.assertEquals(re, Roaring64Bitmap.bitmapOf(2, 4, 8)); + } + + @Test + public void testTransposeWithCount() { + bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(1, 2); + bsi.setValue(2, 4); + bsi.setValue(3, 4); + bsi.setValue(4, 8); + bsi.setValue(5, 8); + Roaring64BitmapSliceIndex re = bsi.transposeWithCount(null); + Assertions.assertEquals(re.getExistenceBitmap(), Roaring64Bitmap.bitmapOf(2, 4, 8)); + Assertions.assertEquals(re.getValue(2).getKey(), 1); + Assertions.assertEquals(re.getValue(4).getKey(), 2); + Assertions.assertEquals(re.getValue(8).getKey(), 2); + } + + @Test + public void testIssue743() throws IOException { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(100L, 3L); + bsi.setValue(1L, 392L); + System.out.println(bsi.getValue(100L)); + System.out.println(bsi.getValue(1L)); + + ByteBuffer buffer = ByteBuffer.allocate(bsi.serializedSizeInBytes()); + bsi.serialize(buffer); + + Roaring64BitmapSliceIndex de_bsi = new Roaring64BitmapSliceIndex(); + de_bsi.deserialize(ByteBuffer.wrap(buffer.array())); + Assertions.assertEquals(de_bsi.getValue(100L), bsi.getValue(100L)); + Assertions.assertEquals(de_bsi.getValue(1L), bsi.getValue(1L)); + } + + @Test + public void testIssue753() throws IOException { + bsi = new Roaring64BitmapSliceIndex(); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 56, null).getLongCardinality(), 56); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 129, null).getLongCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 200, null).getLongCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 20000, null).getLongCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, -129, null).getLongCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, -2, null).getLongCardinality(), 0); + + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 56, null).getLongCardinality(), 53); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 129, null).getLongCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 200, null).getLongCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 20000, null).getLongCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, -129, null).getLongCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 2, null).getLongCardinality(), 0); + + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -129, -14, null).getLongCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 129, 2000, null).getLongCardinality(), 0); + } + + @Test + public void testIssue755() throws IOException { + Roaring64BitmapSliceIndex bsi = new Roaring64BitmapSliceIndex(); + bsi.setValue(100L, 3L); + bsi.setValue(1L, (long) Integer.MAX_VALUE * 2 + 23456); + bsi.setValue(2L, (long) Integer.MAX_VALUE + 23456); + Assertions.assertEquals(bsi.getValue(100L).getKey(), 3L); // {{3,true}} + Assertions.assertEquals( + bsi.getValue(1L).getKey(), (long) Integer.MAX_VALUE * 2 + 23456); // {23455,true} + Assertions.assertEquals( + bsi.getValue(2L).getKey(), (long) Integer.MAX_VALUE + 23456); // {-2147460193,true} + } +} diff --git a/bsi/src/test/java/org/roaringbitmap/bsi/R64NavigableBSITest.java b/bsi/src/test/java/org/roaringbitmap/bsi/R64NavigableBSITest.java new file mode 100644 index 000000000..3d1d51f25 --- /dev/null +++ b/bsi/src/test/java/org/roaringbitmap/bsi/R64NavigableBSITest.java @@ -0,0 +1,450 @@ +package org.roaringbitmap.bsi; + +import org.roaringbitmap.bsi.longlong.Roaring64NavigableMapSliceIndex; +import org.roaringbitmap.longlong.Roaring64NavigableMap; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + +public class R64NavigableBSITest { + private Map testDataSet = new HashMap<>(); + + private Roaring64NavigableMapSliceIndex bsi; + + @BeforeEach + public void setup() { + LongStream.range(1, 100).forEach(x -> testDataSet.put(x, x)); + bsi = new Roaring64NavigableMapSliceIndex(1, 99); + testDataSet.forEach( + (k, v) -> { + bsi.setValue(k, v); + }); + } + + @Test + public void testSetAndGet() { + LongStream.range(1, 100) + .forEach( + x -> { + Pair pair = bsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertEquals((long) pair.getKey(), x); + }); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair pair = bsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertEquals((long) pair.getKey(), x); + }); + } + + @Test + public void testMerge() { + Roaring64NavigableMapSliceIndex bsiA = new Roaring64NavigableMapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + Roaring64NavigableMapSliceIndex bsiB = new Roaring64NavigableMapSliceIndex(); + IntStream.range(100, 199).forEach(x -> bsiB.setValue(x, x)); + Assertions.assertEquals(bsiA.getExistenceBitmap().getLongCardinality(), 99); + Assertions.assertEquals(bsiB.getExistenceBitmap().getLongCardinality(), 99); + bsiA.merge(bsiB); + IntStream.range(1, 199) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testCloneLegacy() { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(1, 99); + List> collect = + testDataSet.entrySet().stream() + .map(x -> Pair.newPair(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + + bsi.setValues(collect); + + Assertions.assertEquals(bsi.getExistenceBitmap().getLongCardinality(), 99); + final Roaring64NavigableMapSliceIndex clone = bsi.clone(); + Assertions.assertEquals(clone.minValue(), 1); + Assertions.assertEquals(clone.maxValue(), 99); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = clone.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testClonePortable() { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(1, 99); + List> collect = + testDataSet.entrySet().stream() + .map(x -> Pair.newPair(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + + bsi.setValues(collect); + + Assertions.assertEquals(bsi.getExistenceBitmap().getLongCardinality(), 99); + final Roaring64NavigableMapSliceIndex clone = bsi.clone(); + Assertions.assertEquals(clone.minValue(), 1); + Assertions.assertEquals(clone.maxValue(), 99); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = clone.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testAdd() { + Roaring64NavigableMapSliceIndex bsiA = new Roaring64NavigableMapSliceIndex(); + LongStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + Roaring64NavigableMapSliceIndex bsiB = new Roaring64NavigableMapSliceIndex(); + LongStream.range(1, 120).forEach(x -> bsiB.setValue(x, x)); + + bsiA.add(bsiB); + + LongStream.range(1, 120) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + if (x < 100) { + Assertions.assertEquals((long) bsiValue.getKey(), x * 2); + } else { + Assertions.assertEquals((long) bsiValue.getKey(), x); + } + }); + } + + @Test + public void testAddAndEvaluate() { + Roaring64NavigableMapSliceIndex bsiA = new Roaring64NavigableMapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + Roaring64NavigableMapSliceIndex bsiB = new Roaring64NavigableMapSliceIndex(); + IntStream.range(1, 120).forEach(x -> bsiB.setValue(120 - x, x)); + + bsiA.add(bsiB); + + Roaring64NavigableMap result = bsiA.compare(BitmapSliceIndex.Operation.EQ, 120, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(result.toArray(), LongStream.range(1, 100).toArray()); + + result = bsiA.compare(BitmapSliceIndex.Operation.RANGE, 1, 20, null); + Assertions.assertEquals(20, result.getLongCardinality()); + Assertions.assertArrayEquals(result.toArray(), LongStream.range(100, 120).toArray()); + } + + @Test + public void TestIO4Stream() throws IOException { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(1, 99); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream bdo = new DataOutputStream(bos); + bsi.serialize(bdo); + byte[] data = bos.toByteArray(); + + Roaring64NavigableMapSliceIndex newBsi = new Roaring64NavigableMapSliceIndex(); + + ByteArrayInputStream bis = new ByteArrayInputStream(data); + DataInputStream bdi = new DataInputStream(bis); + newBsi.deserialize(bdi); + + Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); + Assertions.assertEquals(newBsi.minValue(), 1); + Assertions.assertEquals(newBsi.maxValue(), 99); + + LongStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = newBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testIOFromExternal() { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(1, 99); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + LongStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = bsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((long) bsiValue.getKey(), x); + }); + } + + @Test + public void testEQ() { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(1, 99); + LongStream.range(1, 100) + .forEach( + x -> { + if (x <= 50) { + bsi.setValue(x, 1); + } else { + bsi.setValue(x, x); + } + }); + + Roaring64NavigableMap bitmap = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); + Assertions.assertEquals(50L, bitmap.getLongCardinality()); + } + + @Test + public void testNotEQ() { + bsi = new Roaring64NavigableMapSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 1); + bsi.setValue(3, 50); + + Roaring64NavigableMap result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertEquals(2, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {2, 3}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 100, 0, null); + Assertions.assertEquals(3, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {1, 2, 3}, result.toArray()); + + bsi = new Roaring64NavigableMapSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 99); + bsi.setValue(3, 99); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 1, 0, null); + Assertions.assertEquals(3, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {1, 2, 3}, result.toArray()); + } + + // parallel operation test + @Test + public void testGT() { + Roaring64NavigableMap result = bsi.compare(BitmapSliceIndex.Operation.GT, 50, 0, null); + Assertions.assertEquals(49, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(51, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GT, 0, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GT, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testGE() { + Roaring64NavigableMap result = bsi.compare(BitmapSliceIndex.Operation.GE, 50, 0, null); + Assertions.assertEquals(50, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(50, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GE, 1, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GE, 100, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLT() { + Roaring64NavigableMap result = bsi.compare(BitmapSliceIndex.Operation.LT, 50, 0, null); + Assertions.assertEquals(49, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 50).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LT, Integer.MAX_VALUE, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LT, 1, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLE() { + Roaring64NavigableMap result = bsi.compare(BitmapSliceIndex.Operation.LE, 50, 0, null); + Assertions.assertEquals(50, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 51).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, Integer.MAX_VALUE, 0, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, 0, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testRANGE() { + Roaring64NavigableMap result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 10, 20, null); + Assertions.assertEquals(11, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(10, 21).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1, 200, null); + Assertions.assertEquals(99, result.getLongCardinality()); + Assertions.assertArrayEquals(LongStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1000, 2000, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testSum() { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(1, 99); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + Roaring64NavigableMap foundSet = + Roaring64NavigableMap.bitmapOf(LongStream.range(1, 51).toArray()); + + Pair sumPair = bsi.sum(foundSet); + + long sum = LongStream.range(1, 51).sum(); + long count = LongStream.range(1, 51).count(); + + Assertions.assertTrue(sumPair.getLeft().intValue() == sum && sumPair.getRight() == count); + } + + @Test + public void testValueZero() { + bsi = new Roaring64NavigableMapSliceIndex(); + bsi.setValue(0, 0); + bsi.setValue(1, 0); + bsi.setValue(2, 1); + + Roaring64NavigableMap result = bsi.compare(BitmapSliceIndex.Operation.EQ, 0, 0, null); + Assertions.assertEquals(2, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {0, 1}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); + Assertions.assertEquals(1, result.getLongCardinality()); + Assertions.assertArrayEquals(new long[] {2}, result.toArray()); + } + + @Test + public void testTopK() { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(); + bsi.setValue(0, 7); + bsi.setValue(1, 6); + bsi.setValue(2, 1); + bsi.setValue(3, 7); + bsi.setValue(4, 0); + bsi.setValue(5, 9); + bsi.setValue(6, 9); + bsi.setValue(7, 8); + bsi.setValue(8, 9); + bsi.setValue(9, 8); + + Assertions.assertEquals( + bsi.topK(bsi.getExistenceBitmap(), 4), Roaring64NavigableMap.bitmapOf(5, 6, 8, 9)); + Assertions.assertEquals( + bsi.topK(bsi.getExistenceBitmap(), 5), Roaring64NavigableMap.bitmapOf(5, 6, 7, 8, 9)); + Assertions.assertEquals( + bsi.topK(bsi.getExistenceBitmap(), 2), Roaring64NavigableMap.bitmapOf(6, 8)); + } + + @Test + public void testTranspose() { + bsi = new Roaring64NavigableMapSliceIndex(); + bsi.setValue(1, 2); + bsi.setValue(2, 4); + bsi.setValue(3, 4); + bsi.setValue(4, 8); + bsi.setValue(5, 8); + Roaring64NavigableMap re = bsi.transpose(null); + Assertions.assertEquals(re, Roaring64NavigableMap.bitmapOf(2, 4, 8)); + } + + @Test + public void testTransposeWithCount() { + bsi = new Roaring64NavigableMapSliceIndex(); + bsi.setValue(1, 2); + bsi.setValue(2, 4); + bsi.setValue(3, 4); + bsi.setValue(4, 8); + bsi.setValue(5, 8); + Roaring64NavigableMapSliceIndex re = bsi.transposeWithCount(null); + Assertions.assertEquals(re.getExistenceBitmap(), Roaring64NavigableMap.bitmapOf(2, 4, 8)); + Assertions.assertEquals(re.getValue(2).getKey(), 1); + Assertions.assertEquals(re.getValue(4).getKey(), 2); + Assertions.assertEquals(re.getValue(8).getKey(), 2); + } + + @Test + public void testIssue753() throws IOException { + bsi = new Roaring64NavigableMapSliceIndex(); + LongStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 56, null).getLongCardinality(), 56); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 129, null).getLongCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 200, null).getLongCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 20000, null).getLongCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, -129, null).getLongCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, -2, null).getLongCardinality(), 0); + + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 56, null).getLongCardinality(), 53); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 129, null).getLongCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 200, null).getLongCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 20000, null).getLongCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, -129, null).getLongCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 2, null).getLongCardinality(), 0); + + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -129, -14, null).getLongCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 129, 2000, null).getLongCardinality(), 0); + } + + @Test + public void testIssue755() throws IOException { + Roaring64NavigableMapSliceIndex bsi = new Roaring64NavigableMapSliceIndex(); + bsi.setValue(100L, 3L); + bsi.setValue(1L, (long) Integer.MAX_VALUE * 2 + 23456); + bsi.setValue(2L, (long) Integer.MAX_VALUE + 23456); + Assertions.assertEquals(bsi.getValue(100L).getKey(), 3L); // {{3,true}} + Assertions.assertEquals( + bsi.getValue(1L).getKey(), (long) Integer.MAX_VALUE * 2 + 23456); // {23455,true} + Assertions.assertEquals( + bsi.getValue(2L).getKey(), (long) Integer.MAX_VALUE + 23456); // {-2147460193,true} + } +} diff --git a/bsi/src/test/java/org/roaringbitmap/bsi/RBBsiTest.java b/bsi/src/test/java/org/roaringbitmap/bsi/RBBsiTest.java index b39a76dac..18da0ffd9 100644 --- a/bsi/src/test/java/org/roaringbitmap/bsi/RBBsiTest.java +++ b/bsi/src/test/java/org/roaringbitmap/bsi/RBBsiTest.java @@ -1,9 +1,16 @@ package org.roaringbitmap.bsi; -import org.junit.jupiter.api.*; import org.roaringbitmap.RoaringBitmap; -import java.io.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; @@ -16,318 +23,406 @@ * created by haihuang@alibaba-inc.com on 2021/6/6 */ public class RBBsiTest { - private Map testDataSet = new HashMap<>(); + private Map testDataSet = new HashMap<>(); - private RoaringBitmapSliceIndex bsi; + private RoaringBitmapSliceIndex bsi; - @BeforeEach - public void setup() { - IntStream.range(1, 100).forEach(x -> testDataSet.put(x, x)); - bsi = new RoaringBitmapSliceIndex(1, 99); - testDataSet.forEach((k, v) -> { - bsi.setValue(k, v); - }); - } - - @Test - public void testSetAndGet() { - IntStream.range(1, 100).forEach(x -> { - Pair pair = bsi.getValue(x); - Assertions.assertTrue(pair.getRight()); - Assertions.assertTrue(pair.getKey() == x); - }); - - IntStream.range(1, 100).forEach(x -> { - Pair pair = bsi.getValue(x); - Assertions.assertTrue(pair.getRight()); - Assertions.assertTrue(pair.getKey() == x); - }); - } - - @Test - public void testMerge() { - RoaringBitmapSliceIndex bsiA = new RoaringBitmapSliceIndex(); - IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); - RoaringBitmapSliceIndex bsiB = new RoaringBitmapSliceIndex(); - IntStream.range(100, 199).forEach(x -> bsiB.setValue(x, x)); - Assertions.assertEquals(bsiA.getExistenceBitmap().getLongCardinality(), 99); - Assertions.assertEquals(bsiB.getExistenceBitmap().getLongCardinality(), 99); - bsiA.merge(bsiB); - IntStream.range(1, 199).forEach(x -> { - Pair bsiValue = bsiA.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); + @BeforeEach + public void setup() { + IntStream.range(1, 100).forEach(x -> testDataSet.put(x, x)); + bsi = new RoaringBitmapSliceIndex(1, 99); + testDataSet.forEach( + (k, v) -> { + bsi.setValue(k, v); }); - } - - - @Test - public void testClone() { - RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); - List> collect = testDataSet.entrySet() - .stream().map(x -> Pair.newPair(x.getKey(), x.getValue())).collect(Collectors.toList()); - - bsi.setValues(collect); - - Assertions.assertEquals(bsi.getExistenceBitmap().getLongCardinality(), 99); - final RoaringBitmapSliceIndex clone = bsi.clone(); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = clone.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - - - @Test - public void testAdd() { - RoaringBitmapSliceIndex bsiA = new RoaringBitmapSliceIndex(); - IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); - RoaringBitmapSliceIndex bsiB = new RoaringBitmapSliceIndex(); - IntStream.range(1, 120).forEach(x -> bsiB.setValue(x, x)); - - bsiA.add(bsiB); - - IntStream.range(1, 120).forEach(x -> { - Pair bsiValue = bsiA.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - if (x < 100) { + } + + @Test + public void testSetAndGet() { + IntStream.range(1, 100) + .forEach( + x -> { + Pair pair = bsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertTrue(pair.getKey() == x); + }); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair pair = bsi.getValue(x); + Assertions.assertTrue(pair.getRight()); + Assertions.assertTrue(pair.getKey() == x); + }); + } + + @Test + public void testMerge() { + RoaringBitmapSliceIndex bsiA = new RoaringBitmapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + RoaringBitmapSliceIndex bsiB = new RoaringBitmapSliceIndex(); + IntStream.range(100, 199).forEach(x -> bsiB.setValue(x, x)); + Assertions.assertEquals(bsiA.getExistenceBitmap().getLongCardinality(), 99); + Assertions.assertEquals(bsiB.getExistenceBitmap().getLongCardinality(), 99); + bsiA.merge(bsiB); + IntStream.range(1, 199) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testClone() { + RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); + List> collect = + testDataSet.entrySet().stream() + .map(x -> Pair.newPair(x.getKey(), x.getValue())) + .collect(Collectors.toList()); + + bsi.setValues(collect); + + Assertions.assertEquals(bsi.getExistenceBitmap().getLongCardinality(), 99); + final RoaringBitmapSliceIndex clone = bsi.clone(); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = clone.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testAdd() { + RoaringBitmapSliceIndex bsiA = new RoaringBitmapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + RoaringBitmapSliceIndex bsiB = new RoaringBitmapSliceIndex(); + IntStream.range(1, 120).forEach(x -> bsiB.setValue(x, x)); + + bsiA.add(bsiB); + + IntStream.range(1, 120) + .forEach( + x -> { + Pair bsiValue = bsiA.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + if (x < 100) { Assertions.assertEquals((int) bsiValue.getKey(), x * 2); - } else { + } else { Assertions.assertEquals((int) bsiValue.getKey(), x); - } - - }); - } - - @Test - public void testAddAndEvaluate() { - RoaringBitmapSliceIndex bsiA = new RoaringBitmapSliceIndex(); - IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); - RoaringBitmapSliceIndex bsiB = new RoaringBitmapSliceIndex(); - IntStream.range(1, 120).forEach(x -> bsiB.setValue(120 - x, x)); - - bsiA.add(bsiB); - - RoaringBitmap result = bsiA.compare(BitmapSliceIndex.Operation.EQ, 120, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(result.toArray(), IntStream.range(1, 100).toArray()); - - result = bsiA.compare(BitmapSliceIndex.Operation.RANGE, 1, 20, null); - Assertions.assertTrue(result.getLongCardinality() == 20); - Assertions.assertArrayEquals(result.toArray(), IntStream.range(100, 120).toArray()); - } - - - @Test - public void TestIO4Stream() throws IOException { - RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream bdo = new DataOutputStream(bos); - bsi.serialize(bdo); - byte[] data = bos.toByteArray(); - - RoaringBitmapSliceIndex newBsi = new RoaringBitmapSliceIndex(); - - ByteArrayInputStream bis = new ByteArrayInputStream(data); - DataInputStream bdi = new DataInputStream(bis); - newBsi.deserialize(bdi); - - Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = newBsi.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - - @Test - public void testIO4Buffer() throws IOException { - RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - ByteBuffer buffer = ByteBuffer.allocate(bsi.serializedSizeInBytes()); - bsi.serialize(buffer); - - byte[] data = buffer.array(); - RoaringBitmapSliceIndex newBsi = new RoaringBitmapSliceIndex(); - newBsi.deserialize(ByteBuffer.wrap(data)); - Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = newBsi.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - - - @Test - public void testIOFromExternal() { - RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - - IntStream.range(1, 100).forEach(x -> { - Pair bsiValue = bsi.getValue(x); - Assertions.assertTrue(bsiValue.getRight()); - Assertions.assertEquals((int) bsiValue.getKey(), x); - }); - } - - - @Test - public void testEQ() { - RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> { - if (x <= 50) { + } + }); + } + + @Test + public void testAddAndEvaluate() { + RoaringBitmapSliceIndex bsiA = new RoaringBitmapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsiA.setValue(x, x)); + RoaringBitmapSliceIndex bsiB = new RoaringBitmapSliceIndex(); + IntStream.range(1, 120).forEach(x -> bsiB.setValue(120 - x, x)); + + bsiA.add(bsiB); + + RoaringBitmap result = bsiA.compare(BitmapSliceIndex.Operation.EQ, 120, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(result.toArray(), IntStream.range(1, 100).toArray()); + + result = bsiA.compare(BitmapSliceIndex.Operation.RANGE, 1, 20, null); + Assertions.assertTrue(result.getLongCardinality() == 20); + Assertions.assertArrayEquals(result.toArray(), IntStream.range(100, 120).toArray()); + } + + @Test + public void TestIO4Stream() throws IOException { + RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream bdo = new DataOutputStream(bos); + bsi.serialize(bdo); + byte[] data = bos.toByteArray(); + + RoaringBitmapSliceIndex newBsi = new RoaringBitmapSliceIndex(); + + ByteArrayInputStream bis = new ByteArrayInputStream(data); + DataInputStream bdi = new DataInputStream(bis); + newBsi.deserialize(bdi); + + Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = newBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testIO4Buffer() throws IOException { + RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + ByteBuffer buffer = ByteBuffer.allocate(bsi.serializedSizeInBytes()); + bsi.serialize(buffer); + + byte[] data = buffer.array(); + RoaringBitmapSliceIndex newBsi = new RoaringBitmapSliceIndex(); + newBsi.deserialize(ByteBuffer.wrap(data)); + Assertions.assertEquals(newBsi.getExistenceBitmap().getLongCardinality(), 99); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = newBsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testIOFromExternal() { + RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + IntStream.range(1, 100) + .forEach( + x -> { + Pair bsiValue = bsi.getValue(x); + Assertions.assertTrue(bsiValue.getRight()); + Assertions.assertEquals((int) bsiValue.getKey(), x); + }); + } + + @Test + public void testEQ() { + RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); + IntStream.range(1, 100) + .forEach( + x -> { + if (x <= 50) { bsi.setValue(x, 1); - } else { + } else { bsi.setValue(x, x); - } - - }); - - RoaringBitmap bitmap = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); - Assertions.assertTrue(bitmap.getLongCardinality() == 50L); - - } - - @Test - public void testNotEQ() { - bsi = new RoaringBitmapSliceIndex(); - bsi.setValue(1, 99); - bsi.setValue(2, 1); - bsi.setValue(3, 50); - - RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 2); - Assertions.assertArrayEquals(new int[]{2, 3}, result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 100, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 3); - Assertions.assertArrayEquals(new int[]{1, 2, 3}, result.toArray()); - - bsi = new RoaringBitmapSliceIndex(); - bsi.setValue(1, 99); - bsi.setValue(2, 99); - bsi.setValue(3, 99); - - result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); - Assertions.assertTrue(result.isEmpty()); - - result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 1, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 3); - Assertions.assertArrayEquals(new int[]{1, 2, 3}, result.toArray()); - } - - - // parallel operation test - - @Test - public void testGT() { - RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.GT, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 49); - Assertions.assertArrayEquals(IntStream.range(51, 100).toArray(), result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.GT, 0, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.GT, 99, 0, null); - Assertions.assertTrue(result.isEmpty()); - } - + } + }); + + RoaringBitmap bitmap = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); + Assertions.assertTrue(bitmap.getLongCardinality() == 50L); + } - @Test - public void testGE() { - RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.GE, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 50); - Assertions.assertArrayEquals(IntStream.range(50, 100).toArray(), result.toArray()); + @Test + public void testNotEQ() { + bsi = new RoaringBitmapSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 1); + bsi.setValue(3, 50); + + RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 2); + Assertions.assertArrayEquals(new int[] {2, 3}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 100, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(new int[] {1, 2, 3}, result.toArray()); + + bsi = new RoaringBitmapSliceIndex(); + bsi.setValue(1, 99); + bsi.setValue(2, 99); + bsi.setValue(3, 99); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + + result = bsi.compare(BitmapSliceIndex.Operation.NEQ, 1, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(new int[] {1, 2, 3}, result.toArray()); + } + + // parallel operation test + + @Test + public void testGT() { + RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.GT, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 49); + Assertions.assertArrayEquals(IntStream.range(51, 100).toArray(), result.toArray()); - result = bsi.compare(BitmapSliceIndex.Operation.GE, 1, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + result = bsi.compare(BitmapSliceIndex.Operation.GT, 0, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - result = bsi.compare(BitmapSliceIndex.Operation.GE, 100, 0, null); - Assertions.assertTrue(result.isEmpty()); - } + result = bsi.compare(BitmapSliceIndex.Operation.GT, 99, 0, null); + Assertions.assertTrue(result.isEmpty()); + } - @Test - public void testLT() { - RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.LT, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 49); - Assertions.assertArrayEquals(IntStream.range(1, 50).toArray(), result.toArray()); + @Test + public void testGE() { + RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.GE, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 50); + Assertions.assertArrayEquals(IntStream.range(50, 100).toArray(), result.toArray()); - result = bsi.compare(BitmapSliceIndex.Operation.LT, Integer.MAX_VALUE, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + result = bsi.compare(BitmapSliceIndex.Operation.GE, 1, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - result = bsi.compare(BitmapSliceIndex.Operation.LT, 1, 0, null); - Assertions.assertTrue(result.isEmpty()); - } + result = bsi.compare(BitmapSliceIndex.Operation.GE, 100, 0, null); + Assertions.assertTrue(result.isEmpty()); + + RoaringBitmap foundSet = RoaringBitmap.bitmapOf(51, 52, 53); - - @Test - public void testLE() { - RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.LE, 50, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 50); - Assertions.assertArrayEquals(IntStream.range(1, 51).toArray(), result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.LE, Integer.MAX_VALUE, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.LE, 0, 0, null); - Assertions.assertTrue(result.isEmpty()); - } - - @Test - public void testRANGE() { - RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 10, 20, null); - Assertions.assertTrue(result.getLongCardinality() == 11); - Assertions.assertArrayEquals(IntStream.range(10, 21).toArray(), result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1, 200, null); - Assertions.assertTrue(result.getLongCardinality() == 99); - Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1000, 2000, null); - Assertions.assertTrue(result.isEmpty()); - } - - @Test - public void testSum() { - RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); - IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); - - RoaringBitmap foundSet = RoaringBitmap.bitmapOf(IntStream.range(1, 51).toArray()); - - Pair sumPair = bsi.sum(foundSet); - - System.out.println("sum:" + sumPair.toString()); - - int sum = IntStream.range(1, 51).sum(); - long count = IntStream.range(1, 51).count(); - - Assertions.assertTrue(sumPair.getLeft().intValue() == sum && sumPair.getRight() == count); - } - - @Test - public void testValueZero() { - bsi = new RoaringBitmapSliceIndex(); - bsi.setValue(0, 0); - bsi.setValue(1, 0); - bsi.setValue(2, 1); - - RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.EQ, 0, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 2); - Assertions.assertArrayEquals(new int[]{0, 1}, result.toArray()); - - result = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); - Assertions.assertTrue(result.getLongCardinality() == 1); - Assertions.assertArrayEquals(new int[]{2}, result.toArray()); - } + result = bsi.compare(BitmapSliceIndex.Operation.GE, 50, 0, foundSet); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(IntStream.range(51, 54).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GE, 0, 0, foundSet); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(IntStream.range(51, 54).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.GE, Integer.MAX_VALUE, 0, foundSet); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLT() { + RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.LT, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 49); + Assertions.assertArrayEquals(IntStream.range(1, 50).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LT, Integer.MAX_VALUE, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LT, 1, 0, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testLE() { + RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.LE, 50, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 50); + Assertions.assertArrayEquals(IntStream.range(1, 51).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, Integer.MAX_VALUE, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, 0, 0, null); + Assertions.assertTrue(result.isEmpty()); + + RoaringBitmap foundSet = RoaringBitmap.bitmapOf(1, 2, 3); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, 50, 0, foundSet); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(IntStream.range(1, 4).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, Integer.MAX_VALUE, 0, foundSet); + Assertions.assertTrue(result.getLongCardinality() == 3); + Assertions.assertArrayEquals(IntStream.range(1, 4).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.LE, 0, 0, foundSet); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testRANGE() { + RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 10, 20, null); + Assertions.assertTrue(result.getLongCardinality() == 11); + Assertions.assertArrayEquals(IntStream.range(10, 21).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1, 200, null); + Assertions.assertTrue(result.getLongCardinality() == 99); + Assertions.assertArrayEquals(IntStream.range(1, 100).toArray(), result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.RANGE, 1000, 2000, null); + Assertions.assertTrue(result.isEmpty()); + } + + @Test + public void testSum() { + RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(1, 99); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + + RoaringBitmap foundSet = RoaringBitmap.bitmapOf(IntStream.range(1, 51).toArray()); + + Pair sumPair = bsi.sum(foundSet); + + System.out.println("sum:" + sumPair.toString()); + + int sum = IntStream.range(1, 51).sum(); + long count = IntStream.range(1, 51).count(); + + Assertions.assertTrue(sumPair.getLeft().intValue() == sum && sumPair.getRight() == count); + } + + @Test + public void testValueZero() { + bsi = new RoaringBitmapSliceIndex(); + bsi.setValue(0, 0); + bsi.setValue(1, 0); + bsi.setValue(2, 1); + + RoaringBitmap result = bsi.compare(BitmapSliceIndex.Operation.EQ, 0, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 2); + Assertions.assertArrayEquals(new int[] {0, 1}, result.toArray()); + + result = bsi.compare(BitmapSliceIndex.Operation.EQ, 1, 0, null); + Assertions.assertTrue(result.getLongCardinality() == 1); + Assertions.assertArrayEquals(new int[] {2}, result.toArray()); + } + + @Test + public void testIssue743() throws IOException { + RoaringBitmapSliceIndex bsi = new RoaringBitmapSliceIndex(); + bsi.setValue(100, 3); + bsi.setValue(1, 392); + System.out.println(bsi.getValue(100)); + System.out.println(bsi.getValue(1)); + + ByteBuffer buffer = ByteBuffer.allocate(bsi.serializedSizeInBytes()); + bsi.serialize(buffer); + + RoaringBitmapSliceIndex de_bsi = new RoaringBitmapSliceIndex(); + de_bsi.deserialize(ByteBuffer.wrap(buffer.array())); + Assertions.assertEquals(de_bsi.getValue(100), bsi.getValue(100)); + Assertions.assertEquals(de_bsi.getValue(1), bsi.getValue(1)); + } + + @Test + public void testIssue753() throws IOException { + bsi = new RoaringBitmapSliceIndex(); + IntStream.range(1, 100).forEach(x -> bsi.setValue(x, x)); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 56, null).getCardinality(), 56); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 129, null).getCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 200, null).getCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, 20000, null).getCardinality(), 99); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, -129, null).getCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -4, -2, null).getCardinality(), 0); + + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 56, null).getCardinality(), 53); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 129, null).getCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 200, null).getCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 20000, null).getCardinality(), 96); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, -129, null).getCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 4, 2, null).getCardinality(), 0); + + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, -129, -14, null).getCardinality(), 0); + Assertions.assertEquals( + bsi.compare(BitmapSliceIndex.Operation.RANGE, 129, 2000, null).getCardinality(), 0); + } } - diff --git a/build.gradle.kts b/build.gradle.kts index 7efd6c644..c907a1224 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,12 @@ -import java.net.URI -import java.time.Duration - plugins { id("net.researchgate.release") version "2.8.1" - id("io.github.gradle-nexus.publish-plugin") version "1.0.0" id("com.github.ben-manes.versions") version "0.38.0" + id("maven-publish") + id("com.diffplug.spotless") version "6.25.0" } + + // some parts of the Kotlin DSL don't work inside a `subprojects` block yet, so we do them the old way // (without typesafe accessors) @@ -52,35 +52,53 @@ subprojects { }) } } -} -subprojects.filter { !listOf("jmh", "fuzz-tests", "examples", "bsi", "simplebenchmark").contains(it.name) }.forEach { - it.run { - apply(plugin = "checkstyle") - - tasks { - withType { - configFile = File(rootProject.projectDir, "RoaringBitmap/style/roaring_google_checks.xml") - isIgnoreFailures = false - isShowViolations = true - - // Skip checkstyle on module-info.java since it breaks. - exclude("module-info.java") - } - - // don't checkstyle source - named("checkstyleTest") { - exclude("**/**") + apply(plugin = "com.diffplug.spotless") + + // You can format the codebase with `./gradlew spotlessApply` + // You check the codebase format with `./gradlew spotlessCheck` + spotless { + // Ratchetting from master means we check/apply only files which are changed relatively to master + // This is especially useful for performance, given the whole codebase has been formatted with Spotless. + ratchetFrom("origin/master") + + java { + // Disbale javadoc formatting as most the javacode do not follow HTML syntax. + googleJavaFormat().reflowLongStrings().formatJavadoc(false) + formatAnnotations() + + importOrder("\\#", "org.roaringbitmap", "", "java", "javax") + removeUnusedImports() + + trimTrailingWhitespace() + endWithNewline() + + // https://github.com/opensearch-project/opensearch-java/commit/2d6d5f86a8db9c7c9e7b8d0f54df97246f7b7d7e + // https://github.com/diffplug/spotless/issues/649 + val wildcardImportRegex = Regex("""^import\s+(?:static\s+)?[^*\s]+\.\*;$""", RegexOption.MULTILINE) + custom("Refuse wildcard imports") { contents -> + // Wildcard imports can't be resolved by spotless itself. + // This will require the developer themselves to adhere to best practices. + val wildcardImports = wildcardImportRegex.findAll(contents) + if (wildcardImports.any()) { + var msg = """ + Please replace the following wildcard imports with explicit imports ('spotlessApply' cannot resolve this issue): + """.trimIndent() + wildcardImports.forEach { + msg += "\n\t- ${it.value}" + } + msg += "\n" + throw AssertionError(msg) + } + contents } } } } -subprojects.filter { listOf("RoaringBitmap", "bsi").contains(it.name) }.forEach { project -> +subprojects.filter { listOf("roaringbitmap", "bsi").contains(it.name) }.forEach { project -> project.run { apply(plugin = "maven-publish") - apply(plugin = "signing") - configure { withSourcesJar() withJavadocJar() @@ -140,46 +158,28 @@ subprojects.filter { listOf("RoaringBitmap", "bsi").contains(it.name) }.forEach url = project.buildDir.toPath().resolve("repos").resolve("localDebug").toUri() } } - } - // don't barf for devs without signing set up - if (project.hasProperty("signing.keyId")) { - configure { - sign(project.extensions.getByType().publications["sonatype"]) + // ./gradlew publishSonatypePublicationToGitHubPackagesRepository + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/RoaringBitmap/RoaringBitmap") + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } } - } - // releasing should publish - rootProject.tasks.afterReleaseBuild { - dependsOn(provider { project.tasks.named("publishToSonatype") }) } - } -} -tasks { - register("build") { - // dummy build task to appease release plugin + } } release { - // for some odd reason, we used to have our tags be of the form RoaringBitmap-0.1.0 + // for some odd reason, we used to have our tags be of the form roaringbitmap-0.1.0 // instead of just 0.1.0 or v0.1.0. tagTemplate = "\$version" } - -nexusPublishing { - repositories { - sonatype { - // sonatypeUsername and sonatypePassword properties are used automatically - // id found via clicking the desired profile in the web ui and noting the url fragment - stagingProfileId.set("144dd9b55bb0c2") - nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) - snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) - } - } - // these are not strictly required. The default timeouts are set to 1 minute. But Sonatype can be really slow. - // If you get the error "java.net.SocketTimeoutException: timeout", these lines will help. - connectTimeout.set(Duration.ofMinutes(3)) - clientTimeout.set(Duration.ofMinutes(3)) -} + diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 27402af6a..d9e5f6490 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -1,5 +1,5 @@ dependencies { - implementation(project(":RoaringBitmap")) + implementation(project(":roaringbitmap")) } tasks { diff --git a/examples/src/main/java/Basic.java b/examples/src/main/java/Basic.java index a091a371a..e4d59e67b 100644 --- a/examples/src/main/java/Basic.java +++ b/examples/src/main/java/Basic.java @@ -1,23 +1,22 @@ - import org.roaringbitmap.RoaringBitmap; public class Basic { public static void main(String[] args) { - RoaringBitmap rr = RoaringBitmap.bitmapOf(1,2,3,1000); - RoaringBitmap rr2 = new RoaringBitmap(); - rr2.add(4000L,4255L); + RoaringBitmap rr = RoaringBitmap.bitmapOf(1, 2, 3, 1000); + RoaringBitmap rr2 = new RoaringBitmap(); + rr2.add(4000L, 4255L); - RoaringBitmap rror = RoaringBitmap.or(rr, rr2);// new bitmap - rr.or(rr2); //in-place computation - boolean equals = rror.equals(rr);// true - if(!equals) throw new RuntimeException("bug"); - // number of values stored? - long cardinality = rr.getLongCardinality(); - System.out.println(cardinality); - // a "forEach" is faster than this loop, but a loop is possible: - for(int i : rr) { - System.out.println(i); - } + RoaringBitmap rror = RoaringBitmap.or(rr, rr2); // new bitmap + rr.or(rr2); // in-place computation + boolean equals = rror.equals(rr); // true + if (!equals) throw new RuntimeException("bug"); + // number of values stored? + long cardinality = rr.getLongCardinality(); + System.out.println(cardinality); + // a "forEach" is faster than this loop, but a loop is possible: + for (int i : rr) { + System.out.println(i); + } } } diff --git a/examples/src/main/java/Bitmap64.java b/examples/src/main/java/Bitmap64.java index 85e38a937..ad412dfea 100644 --- a/examples/src/main/java/Bitmap64.java +++ b/examples/src/main/java/Bitmap64.java @@ -1,13 +1,15 @@ -import org.roaringbitmap.longlong.*; +import org.roaringbitmap.longlong.LongBitmapDataProvider; +import org.roaringbitmap.longlong.LongIterator; +import org.roaringbitmap.longlong.Roaring64NavigableMap; public class Bitmap64 { public static void main(String[] args) { - LongBitmapDataProvider r = Roaring64NavigableMap.bitmapOf(1,2,100,1000); - r.addLong(1234); - System.out.println(r.contains(1)); // true - System.out.println(r.contains(3)); // false - LongIterator i = r.getLongIterator(); - while(i.hasNext()) System.out.println(i.next()); + LongBitmapDataProvider r = Roaring64NavigableMap.bitmapOf(1, 2, 100, 1000); + r.addLong(1234); + System.out.println(r.contains(1)); // true + System.out.println(r.contains(3)); // false + LongIterator i = r.getLongIterator(); + while (i.hasNext()) System.out.println(i.next()); } } diff --git a/examples/src/main/java/CompressionResults.java b/examples/src/main/java/CompressionResults.java index 88fd33922..b716211e6 100644 --- a/examples/src/main/java/CompressionResults.java +++ b/examples/src/main/java/CompressionResults.java @@ -1,5 +1,5 @@ - import org.roaringbitmap.RoaringBitmap; + import java.text.DecimalFormat; public class CompressionResults { @@ -7,56 +7,72 @@ public class CompressionResults { public static DecimalFormat F = new DecimalFormat("0.000"); public static void testSuperSparse() { - System.out.println("Sparse case... universe = [0,"+universe_size+")"); + System.out.println("Sparse case... universe = [0," + universe_size + ")"); RoaringBitmap r = new RoaringBitmap(); int howmany = 100; int gap = universe_size / howmany; - System.out.println("Adding "+howmany+" values separated by gaps of "+gap+ "..."); + System.out.println("Adding " + howmany + " values separated by gaps of " + gap + "..."); System.out.println("As a bitmap it would look like 1000...001000... "); for (int i = 1; i < howmany; i++) { r.add(i * gap); } - System.out.println("Bits used per value = "+F.format(r.getSizeInBytes()*8.0/howmany)); + System.out.println("Bits used per value = " + F.format(r.getSizeInBytes() * 8.0 / howmany)); r.runOptimize(); - System.out.println("Bits used per value after run optimize = "+F.format(r.getSizeInBytes()*8.0/howmany)); - System.out.println("An uncompressed bitset might use "+F.format(universe_size*1.0/howmany)+" bits per value set"); + System.out.println( + "Bits used per value after run optimize = " + F.format(r.getSizeInBytes() * 8.0 / howmany)); + System.out.println( + "An uncompressed bitset might use " + + F.format(universe_size * 1.0 / howmany) + + " bits per value set"); System.out.println(); - } public static void testSuperDense() { - System.out.println("Sparse case... universe = [0,"+universe_size+")"); + System.out.println("Sparse case... universe = [0," + universe_size + ")"); RoaringBitmap r = new RoaringBitmap(); long howmany = 100; long gap = universe_size / howmany; for (long i = 1; i < howmany; i++) { - r.add(i * gap + 1,((i + 1) * gap)); + r.add(i * gap + 1, ((i + 1) * gap)); } - System.out.println("Adding "+r.getCardinality()+" values partionned by "+howmany+" gaps of 1 ..."); + System.out.println( + "Adding " + r.getCardinality() + " values partionned by " + howmany + " gaps of 1 ..."); System.out.println("As a bitmap it would look like 01111...11011111... "); - System.out.println("Bits used per value = "+F.format(r.getSizeInBytes()*8.0/r.getCardinality())); + System.out.println( + "Bits used per value = " + F.format(r.getSizeInBytes() * 8.0 / r.getCardinality())); r.runOptimize(); - System.out.println("Bits used per value after run optimize = "+F.format(r.getSizeInBytes()*8.0/r.getCardinality())); - System.out.println("Bits used per gap after run optimize = "+F.format(r.getSizeInBytes()*8.0/howmany)); + System.out.println( + "Bits used per value after run optimize = " + + F.format(r.getSizeInBytes() * 8.0 / r.getCardinality())); + System.out.println( + "Bits used per gap after run optimize = " + F.format(r.getSizeInBytes() * 8.0 / howmany)); - System.out.println("An uncompressed bitset might use "+F.format(universe_size*1.0/r.getCardinality())+" bits per value set"); + System.out.println( + "An uncompressed bitset might use " + + F.format(universe_size * 1.0 / r.getCardinality()) + + " bits per value set"); System.out.println(); } public static void testAlternating() { - System.out.println("Alternating case... universe = [0,"+universe_size+")"); + System.out.println("Alternating case... universe = [0," + universe_size + ")"); RoaringBitmap r = new RoaringBitmap(); for (int i = 1; i < universe_size; i++) { - if(i%2 == 0) - r.add(i); + if (i % 2 == 0) r.add(i); } System.out.println("Adding all even values in the universe"); System.out.println("As a bitmap it would look like 01010101... "); - System.out.println("Bits used per value = "+F.format(r.getSizeInBytes()*8.0/r.getCardinality())); + System.out.println( + "Bits used per value = " + F.format(r.getSizeInBytes() * 8.0 / r.getCardinality())); r.runOptimize(); - System.out.println("Bits used per value after run optimize = "+F.format(r.getSizeInBytes()*8.0/r.getCardinality())); - System.out.println("An uncompressed bitset might use "+F.format(universe_size*1.0/r.getCardinality())+" bits per value set"); + System.out.println( + "Bits used per value after run optimize = " + + F.format(r.getSizeInBytes() * 8.0 / r.getCardinality())); + System.out.println( + "An uncompressed bitset might use " + + F.format(universe_size * 1.0 / r.getCardinality()) + + " bits per value set"); System.out.println(); } diff --git a/examples/src/main/java/ForEachExample.java b/examples/src/main/java/ForEachExample.java index b9fe6e596..d3eb7d66e 100644 --- a/examples/src/main/java/ForEachExample.java +++ b/examples/src/main/java/ForEachExample.java @@ -1,37 +1,37 @@ /** -* This example shows how to serialize a Roaring bitmap to a file. -* -* -* -*/ -import org.roaringbitmap.*; -import java.io.*; -import java.nio.*; -import java.util.*; + * This example shows how to serialize a Roaring bitmap to a file. + * + * + * + */ +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.RoaringBitmap; -public class ForEachExample { +import java.io.IOException; +public class ForEachExample { - public static void main(String[] args) throws IOException { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k+= 1000) { - rb.add(k); - } - for (int k = 100000; k < 200000; ++k) { - rb.add(3*k); - } - for (int k = 700000; k < 800000; ++k) { - rb.add(k); - } - final int[] count = {0}; - rb.forEach(new IntConsumer() { - @Override - public void accept(int value) { - if((value % 1500) == 0) { - count[0] ++; - } + public static void main(String[] args) throws IOException { + RoaringBitmap rb = new RoaringBitmap(); + for (int k = 0; k < 100000; k += 1000) { + rb.add(k); + } + for (int k = 100000; k < 200000; ++k) { + rb.add(3 * k); + } + for (int k = 700000; k < 800000; ++k) { + rb.add(k); + } + final int[] count = {0}; + rb.forEach( + new IntConsumer() { + @Override + public void accept(int value) { + if ((value % 1500) == 0) { + count[0]++; } + } }); - System.out.println("There are "+count[0]+" values divisible by 1500."); - } + System.out.println("There are " + count[0] + " values divisible by 1500."); + } } diff --git a/examples/src/main/java/ImmutableRoaringBitmapExample.java b/examples/src/main/java/ImmutableRoaringBitmapExample.java index d4ebf0a23..f25511a37 100644 --- a/examples/src/main/java/ImmutableRoaringBitmapExample.java +++ b/examples/src/main/java/ImmutableRoaringBitmapExample.java @@ -1,24 +1,27 @@ -import org.roaringbitmap.buffer.*; -import java.io.*; -import java.nio.*; +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; public class ImmutableRoaringBitmapExample { - public static void main(String[] args) throws IOException { - MutableRoaringBitmap rr1 = MutableRoaringBitmap.bitmapOf(1, 2, 3, 1000); - MutableRoaringBitmap rr2 = MutableRoaringBitmap.bitmapOf( 2, 3, 1010); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(bos); - // If there were runs of consecutive values, you could - // call rr1.runOptimize(); or rr2.runOptimize(); to improve compression - rr1.serialize(dos); - rr2.serialize(dos); - dos.close(); - ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray()); - ImmutableRoaringBitmap rrback1 = new ImmutableRoaringBitmap(bb); - bb.position(bb.position() + rrback1.serializedSizeInBytes()); - ImmutableRoaringBitmap rrback2 = new ImmutableRoaringBitmap(bb); - System.out.println(rrback1); - System.out.println(rrback2); - } -} \ No newline at end of file + public static void main(String[] args) throws IOException { + MutableRoaringBitmap rr1 = MutableRoaringBitmap.bitmapOf(1, 2, 3, 1000); + MutableRoaringBitmap rr2 = MutableRoaringBitmap.bitmapOf(2, 3, 1010); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(bos); + // If there were runs of consecutive values, you could + // call rr1.runOptimize(); or rr2.runOptimize(); to improve compression + rr1.serialize(dos); + rr2.serialize(dos); + dos.close(); + ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray()); + ImmutableRoaringBitmap rrback1 = new ImmutableRoaringBitmap(bb); + bb.position(bb.position() + rrback1.serializedSizeInBytes()); + ImmutableRoaringBitmap rrback2 = new ImmutableRoaringBitmap(bb); + System.out.println(rrback1); + System.out.println(rrback2); + } +} diff --git a/examples/src/main/java/IntervalCheck.java b/examples/src/main/java/IntervalCheck.java index 87575d534..bca34ee11 100644 --- a/examples/src/main/java/IntervalCheck.java +++ b/examples/src/main/java/IntervalCheck.java @@ -1,20 +1,19 @@ - import org.roaringbitmap.RoaringBitmap; public class IntervalCheck { public static void main(String[] args) { - // some bitmap - RoaringBitmap rr = RoaringBitmap.bitmapOf(1,2,3,1000); + // some bitmap + RoaringBitmap rr = RoaringBitmap.bitmapOf(1, 2, 3, 1000); - // we want to check if it intersects a given range [10,1000] - int low = 10; - int high = 1000; - RoaringBitmap range = new RoaringBitmap(); - range.add((long)low, (long)high + 1); - // - // + // we want to check if it intersects a given range [10,1000] + int low = 10; + int high = 1000; + RoaringBitmap range = new RoaringBitmap(); + range.add((long) low, (long) high + 1); + // + // - System.out.println(RoaringBitmap.intersects(rr,range)); // prints true if they intersect + System.out.println(RoaringBitmap.intersects(rr, range)); // prints true if they intersect } } diff --git a/examples/src/main/java/MemoryMappingExample.java b/examples/src/main/java/MemoryMappingExample.java index 187c37e1a..d77809220 100644 --- a/examples/src/main/java/MemoryMappingExample.java +++ b/examples/src/main/java/MemoryMappingExample.java @@ -1,44 +1,53 @@ -import org.roaringbitmap.buffer.*; +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; -import java.io.*; -import java.nio.*; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; import java.nio.channels.FileChannel; - public class MemoryMappingExample { - - public static void main(String[] args) throws IOException { - File tmpfile = File.createTempFile("roaring", "bin"); - tmpfile.deleteOnExit(); - final FileOutputStream fos = new FileOutputStream(tmpfile); - MutableRoaringBitmap Bitmap1 = MutableRoaringBitmap.bitmapOf(0, 2, 55, - 64, 1 << 30); - System.out.println("Created the bitmap "+Bitmap1); - MutableRoaringBitmap Bitmap2 = MutableRoaringBitmap.bitmapOf(0, 2, 55, - 654, 1 << 31); - System.out.println("Created the bitmap "+Bitmap2); - int pos1 = 0; // bitmap 1 is at offset 0 - // If there were runs of consecutive values, you could - // call Bitmap1.runOptimize(); to improve compression - Bitmap1.serialize(new DataOutputStream(fos)); - int pos2 = Bitmap1.serializedSizeInBytes(); // bitmap 2 will be right after it - // If there were runs of consecutive values, you could - // call Bitmap2.runOptimize(); to improve compression - Bitmap2.serialize(new DataOutputStream(fos)); - long totalcount = fos.getChannel().position(); - if(totalcount != Bitmap1.serializedSizeInBytes() + Bitmap2.serializedSizeInBytes()) - throw new RuntimeException("This will not happen."); - System.out.println("Serialized total count = "+totalcount+" bytes"); - fos.close(); - RandomAccessFile memoryMappedFile = new RandomAccessFile(tmpfile, "r"); - ByteBuffer bb = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, totalcount); // even though we have two bitmaps, we have one map, maps are expensive!!! - memoryMappedFile.close(); // we can safely close - bb.position(pos1); - ImmutableRoaringBitmap mapped1 = new ImmutableRoaringBitmap(bb); - System.out.println("Mapped the bitmap "+mapped1); - bb.position(pos2); - ImmutableRoaringBitmap mapped2 = new ImmutableRoaringBitmap(bb); - System.out.println("Mapped the bitmap "+mapped2); - if(!mapped2.equals(Bitmap2)) throw new RuntimeException("This will not happen"); - } + + public static void main(String[] args) throws IOException { + File tmpfile = File.createTempFile("roaring", "bin"); + tmpfile.deleteOnExit(); + final FileOutputStream fos = new FileOutputStream(tmpfile); + MutableRoaringBitmap Bitmap1 = MutableRoaringBitmap.bitmapOf(0, 2, 55, 64, 1 << 30); + System.out.println("Created the bitmap " + Bitmap1); + MutableRoaringBitmap Bitmap2 = MutableRoaringBitmap.bitmapOf(0, 2, 55, 654, 1 << 31); + System.out.println("Created the bitmap " + Bitmap2); + int pos1 = 0; // bitmap 1 is at offset 0 + // If there were runs of consecutive values, you could + // call Bitmap1.runOptimize(); to improve compression + Bitmap1.serialize(new DataOutputStream(fos)); + int pos2 = Bitmap1.serializedSizeInBytes(); // bitmap 2 will be right after it + // If there were runs of consecutive values, you could + // call Bitmap2.runOptimize(); to improve compression + Bitmap2.serialize(new DataOutputStream(fos)); + long totalcount = fos.getChannel().position(); + if (totalcount != Bitmap1.serializedSizeInBytes() + Bitmap2.serializedSizeInBytes()) + throw new RuntimeException("This will not happen."); + System.out.println("Serialized total count = " + totalcount + " bytes"); + fos.close(); + RandomAccessFile memoryMappedFile = new RandomAccessFile(tmpfile, "r"); + ByteBuffer bb = + memoryMappedFile + .getChannel() + .map( + FileChannel.MapMode.READ_ONLY, + 0, + totalcount); // even though we have two bitmaps, we have one map, maps are + // expensive!!! + memoryMappedFile.close(); // we can safely close + bb.position(pos1); + ImmutableRoaringBitmap mapped1 = new ImmutableRoaringBitmap(bb); + System.out.println("Mapped the bitmap " + mapped1); + bb.position(pos2); + ImmutableRoaringBitmap mapped2 = new ImmutableRoaringBitmap(bb); + System.out.println("Mapped the bitmap " + mapped2); + if (!mapped2.equals(Bitmap2)) throw new RuntimeException("This will not happen"); + } } diff --git a/examples/src/main/java/PagedIterator.java b/examples/src/main/java/PagedIterator.java index 2cfe8d36f..a570aea7f 100644 --- a/examples/src/main/java/PagedIterator.java +++ b/examples/src/main/java/PagedIterator.java @@ -1,23 +1,23 @@ - -import org.roaringbitmap.*; +import org.roaringbitmap.IntIterator; +import org.roaringbitmap.RoaringBitmap; // demonstrates how to iterator over blocks of pageSize integers efficiently public class PagedIterator { public static void main(String[] args) { - RoaringBitmap rr = new RoaringBitmap(); - for(int k = 0; k < 100; k++) { - rr.add(k * 4 + 31); - } + RoaringBitmap rr = new RoaringBitmap(); + for (int k = 0; k < 100; k++) { + rr.add(k * 4 + 31); + } - IntIterator i = rr.getIntIterator(); - final int pageSize = 10; - while(i.hasNext()) { - // we print a page - for(int k = 0; (k < pageSize) && i.hasNext() ; k++) { - System.out.print(i.next()+" "); - } - System.out.println(); - } + IntIterator i = rr.getIntIterator(); + final int pageSize = 10; + while (i.hasNext()) { + // we print a page + for (int k = 0; (k < pageSize) && i.hasNext(); k++) { + System.out.print(i.next() + " "); + } + System.out.println(); + } } } diff --git a/examples/src/main/java/SerializeToByteArrayExample.java b/examples/src/main/java/SerializeToByteArrayExample.java index 6d4ac6830..ed60cdbde 100644 --- a/examples/src/main/java/SerializeToByteArrayExample.java +++ b/examples/src/main/java/SerializeToByteArrayExample.java @@ -4,9 +4,11 @@ /*************** * for performance considerations, see https://github.com/RoaringBitmap/RoaringBitmap/issues/319 **************/ + import org.roaringbitmap.RoaringBitmap; -import java.io.*; -import java.nio.*; + +import java.io.IOException; +import java.nio.ByteBuffer; public class SerializeToByteArrayExample { @@ -19,12 +21,10 @@ public static void main(String[] args) { RoaringBitmap ret = new RoaringBitmap(); try { ret.deserialize(ByteBuffer.wrap(array)); - } catch(IOException ioe) { + } catch (IOException ioe) { ioe.printStackTrace(); // should not happen } - if (!ret.equals(mrb)) - throw new RuntimeException("bug"); + if (!ret.equals(mrb)) throw new RuntimeException("bug"); System.out.println("decoded from byte array : " + ret); - } } diff --git a/examples/src/main/java/SerializeToByteBufferExample.java b/examples/src/main/java/SerializeToByteBufferExample.java index ab47ddf75..7ed621446 100644 --- a/examples/src/main/java/SerializeToByteBufferExample.java +++ b/examples/src/main/java/SerializeToByteBufferExample.java @@ -1,23 +1,23 @@ /** -* This example shows how to serialize a Roaring bitmap to a ByteBuffer -*/ -import org.roaringbitmap.buffer.*; -import java.io.*; -import java.nio.*; + * This example shows how to serialize a Roaring bitmap to a ByteBuffer + */ +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; -public class SerializeToByteBufferExample { +import java.io.IOException; +import java.nio.ByteBuffer; - public static void main(String[] args) throws IOException{ - MutableRoaringBitmap mrb = MutableRoaringBitmap.bitmapOf(1,2,3,1000); - System.out.println("starting with bitmap "+ mrb); - mrb.runOptimize(); //to improve compression - ByteBuffer outbb = ByteBuffer.allocate(mrb.serializedSizeInBytes()); - mrb.serialize(outbb); - outbb.flip(); - ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(outbb); - System.out.println("read bitmap "+ irb); - if( ! irb.equals(mrb) ) throw new RuntimeException("bug"); +public class SerializeToByteBufferExample { - } + public static void main(String[] args) throws IOException { + MutableRoaringBitmap mrb = MutableRoaringBitmap.bitmapOf(1, 2, 3, 1000); + System.out.println("starting with bitmap " + mrb); + mrb.runOptimize(); // to improve compression + ByteBuffer outbb = ByteBuffer.allocate(mrb.serializedSizeInBytes()); + mrb.serialize(outbb); + outbb.flip(); + ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(outbb); + System.out.println("read bitmap " + irb); + if (!irb.equals(mrb)) throw new RuntimeException("bug"); + } } - diff --git a/examples/src/main/java/SerializeToDiskExample.java b/examples/src/main/java/SerializeToDiskExample.java index 382769209..61fe47983 100644 --- a/examples/src/main/java/SerializeToDiskExample.java +++ b/examples/src/main/java/SerializeToDiskExample.java @@ -1,47 +1,49 @@ /** -* This example shows how to serialize a Roaring bitmap to a file. -* -* -* -*/ -import org.roaringbitmap.*; -import java.io.*; -import java.nio.*; -import java.util.*; + * This example shows how to serialize a Roaring bitmap to a file. + * + * + * + */ +import org.roaringbitmap.RoaringBitmap; -public class SerializeToDiskExample { +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +public class SerializeToDiskExample { - public static void main(String[] args) throws IOException { - RoaringBitmap rb = new RoaringBitmap(); - for (int k = 0; k < 100000; k+= 1000) { - rb.add(k); - } - for (int k = 100000; k < 200000; ++k) { - rb.add(3*k); - } - for (int k = 700000; k < 800000; ++k) { - rb.add(k); - } - String file1 = "bitmapwithoutruns.bin"; - try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file1))) { - rb.serialize(out); - } - rb.runOptimize(); - String file2 = "bitmapwithruns.bin"; - try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file2))) { - rb.serialize(out); - } - // verify - RoaringBitmap rbtest = new RoaringBitmap(); - try (DataInputStream in = new DataInputStream(new FileInputStream(file1))) { - rbtest.deserialize(in); - } - if(!rbtest.equals(rb)) throw new RuntimeException("bug!"); - try (DataInputStream in = new DataInputStream(new FileInputStream(file2))) { - rbtest.deserialize(in); - } - if(!rbtest.equals(rb)) throw new RuntimeException("bug!"); - System.out.println("Serialized bitmaps to "+file1+" and "+file2); + public static void main(String[] args) throws IOException { + RoaringBitmap rb = new RoaringBitmap(); + for (int k = 0; k < 100000; k += 1000) { + rb.add(k); + } + for (int k = 100000; k < 200000; ++k) { + rb.add(3 * k); + } + for (int k = 700000; k < 800000; ++k) { + rb.add(k); + } + String file1 = "bitmapwithoutruns.bin"; + try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file1))) { + rb.serialize(out); + } + rb.runOptimize(); + String file2 = "bitmapwithruns.bin"; + try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file2))) { + rb.serialize(out); + } + // verify + RoaringBitmap rbtest = new RoaringBitmap(); + try (DataInputStream in = new DataInputStream(new FileInputStream(file1))) { + rbtest.deserialize(in); + } + if (!rbtest.equals(rb)) throw new RuntimeException("bug!"); + try (DataInputStream in = new DataInputStream(new FileInputStream(file2))) { + rbtest.deserialize(in); } + if (!rbtest.equals(rb)) throw new RuntimeException("bug!"); + System.out.println("Serialized bitmaps to " + file1 + " and " + file2); + } } diff --git a/examples/src/main/java/SerializeToStringExample.java b/examples/src/main/java/SerializeToStringExample.java index 63320e8fe..ef52d2430 100644 --- a/examples/src/main/java/SerializeToStringExample.java +++ b/examples/src/main/java/SerializeToStringExample.java @@ -1,34 +1,33 @@ /** -* This example shows how to serialize a Roaring bitmap to a String (Java 8) -* -* -* It is not difficult to encode a byte array to a String so that it can be later recovered. -* A standard way is to use Base 64 : https://en.wikipedia.org/wiki/Base64 -* -*/ -import org.roaringbitmap.buffer.*; -import java.io.*; -import java.nio.*; -import java.util.*; + * This example shows how to serialize a Roaring bitmap to a String (Java 8) + * + * + * It is not difficult to encode a byte array to a String so that it can be later recovered. + * A standard way is to use Base 64 : https://en.wikipedia.org/wiki/Base64 + * + */ +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Base64; public class SerializeToStringExample { - - - - - // This example uses the Base64 class introduced in Java 8. Any byte[] to String encoder would do - public static void main(String[] args) throws IOException{ - MutableRoaringBitmap mrb = MutableRoaringBitmap.bitmapOf(1,2,3,1000); - System.out.println("starting with bitmap "+ mrb); - ByteBuffer outbb = ByteBuffer.allocate(mrb.serializedSizeInBytes()); - // If there were runs of consecutive values, you could - // call mrb.runOptimize(); to improve compression - mrb.serialize(outbb); - // - outbb.flip(); - String serializedstring = Base64.getEncoder().encodeToString(outbb.array()); - ByteBuffer newbb = ByteBuffer.wrap(Base64.getDecoder().decode(serializedstring)); - ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(newbb); - System.out.println("read bitmap "+ irb); - } + + // This example uses the Base64 class introduced in Java 8. Any byte[] to String encoder would do + public static void main(String[] args) throws IOException { + MutableRoaringBitmap mrb = MutableRoaringBitmap.bitmapOf(1, 2, 3, 1000); + System.out.println("starting with bitmap " + mrb); + ByteBuffer outbb = ByteBuffer.allocate(mrb.serializedSizeInBytes()); + // If there were runs of consecutive values, you could + // call mrb.runOptimize(); to improve compression + mrb.serialize(outbb); + // + outbb.flip(); + String serializedstring = Base64.getEncoder().encodeToString(outbb.array()); + ByteBuffer newbb = ByteBuffer.wrap(Base64.getDecoder().decode(serializedstring)); + ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(newbb); + System.out.println("read bitmap " + irb); + } } diff --git a/examples/src/main/java/VeryLargeBitmap.java b/examples/src/main/java/VeryLargeBitmap.java index 93e1486e8..f9f31e76e 100644 --- a/examples/src/main/java/VeryLargeBitmap.java +++ b/examples/src/main/java/VeryLargeBitmap.java @@ -1,15 +1,12 @@ - import org.roaringbitmap.RoaringBitmap; -import java.text.DecimalFormat; public class VeryLargeBitmap { public static void main(String[] args) { - RoaringBitmap rb = new RoaringBitmap(); - rb.add(0L, 1L << 32);// the biggest bitmap we can create - System.out.println("memory usage: "+ rb.getSizeInBytes()*1.0/(1L << 32)+" byte per value"); - if(rb.getLongCardinality() != ( 1L << 32)) - throw new RuntimeException("bug!"); - + RoaringBitmap rb = new RoaringBitmap(); + rb.add(0L, 1L << 32); // the biggest bitmap we can create + System.out.println( + "memory usage: " + rb.getSizeInBytes() * 1.0 / (1L << 32) + " byte per value"); + if (rb.getLongCardinality() != (1L << 32)) throw new RuntimeException("bug!"); } } diff --git a/fuzz-tests/build.gradle.kts b/fuzz-tests/build.gradle.kts index 1bea179be..dac73142b 100644 --- a/fuzz-tests/build.gradle.kts +++ b/fuzz-tests/build.gradle.kts @@ -1,7 +1,7 @@ val deps: Map by extra dependencies { - implementation(project(":RoaringBitmap")) + implementation(project(":roaringbitmap")) testImplementation("org.junit.jupiter:junit-jupiter-api:${deps["jupiter"]}") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${deps["jupiter"]}") testImplementation("com.google.guava:guava:${deps["guava"]}") diff --git a/fuzz-tests/src/test/java/org/roaringbitmap/BufferFuzzer.java b/fuzz-tests/src/test/java/org/roaringbitmap/BufferFuzzer.java index 417ac0e48..d76160116 100644 --- a/fuzz-tests/src/test/java/org/roaringbitmap/BufferFuzzer.java +++ b/fuzz-tests/src/test/java/org/roaringbitmap/BufferFuzzer.java @@ -1,21 +1,26 @@ package org.roaringbitmap; -import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.roaringbitmap.RandomisedTestData.ITERATIONS; +import static org.roaringbitmap.Util.toUnsignedLong; + import org.roaringbitmap.buffer.BufferFastAggregation; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.roaringbitmap.buffer.MutableRoaringBitmap; +import com.google.common.collect.ImmutableMap; +import org.junit.jupiter.api.Test; + import java.util.BitSet; import java.util.concurrent.ThreadLocalRandom; -import java.util.function.*; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.IntStream; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.roaringbitmap.RandomisedTestData.ITERATIONS; -import static org.roaringbitmap.Util.toUnsignedLong; - public class BufferFuzzer { @FunctionalInterface @@ -31,9 +36,10 @@ interface RangeBitmapPredicate { public static void verifyInvariance(String testName, int maxKeys, RangeBitmapPredicate pred) { ThreadLocalRandom random = ThreadLocalRandom.current(); IntStream.range(0, ITERATIONS) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .forEach( + bitmap -> { long min = random.nextLong(1L << 32); long max = random.nextLong(min, 1L << 32); try { @@ -45,24 +51,27 @@ public static void verifyInvariance(String testName, int maxKeys, RangeBitmapPre }); } - public static void verifyInvariance(String testName, - Predicate validity, - Function left, - Function right) { + public static void verifyInvariance( + String testName, + Predicate validity, + Function left, + Function right) { verifyInvariance(testName, ITERATIONS, 1 << 8, validity, left, right); } - public static void verifyInvariance(String testName, - int count, - int maxKeys, - Predicate validity, - Function left, - Function right) { + public static void verifyInvariance( + String testName, + int count, + int maxKeys, + Predicate validity, + Function left, + Function right) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .filter(validity) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .filter(validity) + .forEach( + bitmap -> { try { assertEquals(left.apply(bitmap), right.apply(bitmap)); } catch (Throwable t) { @@ -72,11 +81,13 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, int maxKeys, Predicate pred) { + public static void verifyInvariance( + String testName, int maxKeys, Predicate pred) { IntStream.range(0, ITERATIONS) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .forEach( + bitmap -> { try { assertTrue(pred.test(bitmap)); } catch (Throwable e) { @@ -86,37 +97,41 @@ public static void verifyInvariance(String testName, int maxKeys, Predicate void verifyInvariance(String testName, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + BiFunction left, + BiFunction right) { verifyInvariance(testName, ITERATIONS, 1 << 8, left, right); } - public static void verifyInvariance(String testName, - BiPredicate validity, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + BiFunction left, + BiFunction right) { verifyInvariance(testName, validity, ITERATIONS, 1 << 8, left, right); } - - public static void verifyInvariance(String testName, - int count, - int maxKeys, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + int count, + int maxKeys, + BiFunction left, + BiFunction right) { verifyInvariance(testName, (l, r) -> true, count, maxKeys, left, right); } - public static void verifyInvariance(String testName, - BiPredicate validity, - int count, - int maxKeys, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + int count, + int maxKeys, + BiFunction left, + BiFunction right) { IntStream.range(0, count) - .parallel() - .forEach(i -> { + .parallel() + .forEach( + i -> { MutableRoaringBitmap one = randomBitmap(maxKeys); MutableRoaringBitmap two = randomBitmap(maxKeys); if (validity.test(one, two)) { @@ -130,22 +145,23 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, - Predicate validity, - IntBitmapPredicate predicate) { + public static void verifyInvariance( + String testName, Predicate validity, IntBitmapPredicate predicate) { verifyInvariance(testName, validity, ITERATIONS, 1 << 3, predicate); } - public static void verifyInvariance(String testName, - Predicate validity, - int count, - int maxKeys, - IntBitmapPredicate predicate) { + public static void verifyInvariance( + String testName, + Predicate validity, + int count, + int maxKeys, + IntBitmapPredicate predicate) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .filter(validity) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .filter(validity) + .forEach( + bitmap -> { for (int i = 0; i < bitmap.getCardinality(); ++i) { try { assertTrue(predicate.test(i, bitmap)); @@ -157,19 +173,18 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, T value, Function func) { + public static void verifyInvariance( + String testName, T value, Function func) { verifyInvariance(testName, ITERATIONS, 1 << 9, value, func); } - public static void verifyInvariance(String testName, - int count, - int maxKeys, - T value, - Function func) { + public static void verifyInvariance( + String testName, int count, int maxKeys, T value, Function func) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .forEach( + bitmap -> { try { assertEquals(value, func.apply(bitmap)); } catch (Throwable t) { @@ -179,22 +194,24 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, - BiPredicate validity, - int maxKeys, - BiPredicate test) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + int maxKeys, + BiPredicate test) { verifyInvariance(testName, validity, ITERATIONS, maxKeys, test); } - - public static void verifyInvariance(String testName, - BiPredicate validity, - int count, - int maxKeys, - BiPredicate test) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + int count, + int maxKeys, + BiPredicate test) { IntStream.range(0, count) - .parallel() - .forEach(i -> { + .parallel() + .forEach( + i -> { MutableRoaringBitmap one = randomBitmap(maxKeys); MutableRoaringBitmap two = randomBitmap(maxKeys); if (validity.test(one, two)) { @@ -208,119 +225,148 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(Predicate validity, - Consumer action) { + public static void verifyInvariance( + Predicate validity, Consumer action) { verifyInvariance(validity, ITERATIONS, 1 << 3, action); } - public static void verifyInvariance(Predicate validity, - int count, - int maxKeys, - Consumer action) { + public static void verifyInvariance( + Predicate validity, + int count, + int maxKeys, + Consumer action) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .filter(validity) - .forEach(action); + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .filter(validity) + .forEach(action); } @Test public void rankSelectInvariance() { - verifyInvariance("rankSelectInvariance", bitmap -> !bitmap.isEmpty(), (i, rb) -> rb.rank(rb.select(i)) == i + 1); + verifyInvariance( + "rankSelectInvariance", + bitmap -> !bitmap.isEmpty(), + (i, rb) -> rb.rank(rb.select(i)) == i + 1); } @Test public void selectContainsInvariance() { - verifyInvariance("selectContainsInvariance", bitmap -> !bitmap.isEmpty(), (i, rb) -> rb.contains(rb.select(i))); + verifyInvariance( + "selectContainsInvariance", + bitmap -> !bitmap.isEmpty(), + (i, rb) -> rb.contains(rb.select(i))); } @Test public void firstSelect0Invariance() { - verifyInvariance("firstSelect0Invariance", - bitmap -> !bitmap.isEmpty(), - b -> b.first(), - bitmap -> bitmap.select(0)); + verifyInvariance( + "firstSelect0Invariance", + bitmap -> !bitmap.isEmpty(), + b -> b.first(), + bitmap -> bitmap.select(0)); } @Test public void lastSelectCardinalityInvariance() { - verifyInvariance("lastSelectCardinalityInvariance", - bitmap -> !bitmap.isEmpty(), - bitmap -> bitmap.last(), - bitmap -> bitmap.select(bitmap.getCardinality() - 1)); + verifyInvariance( + "lastSelectCardinalityInvariance", + bitmap -> !bitmap.isEmpty(), + bitmap -> bitmap.last(), + bitmap -> bitmap.select(bitmap.getCardinality() - 1)); } @Test public void intersectsRangeFirstLastInvariance() { - verifyInvariance("intersectsRangeFirstLastInvariance", true, - rb -> rb.intersects(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); + verifyInvariance( + "intersectsRangeFirstLastInvariance", + true, + rb -> rb.intersects(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); } @Test public void containsRangeFirstLastInvariance() { - verifyInvariance("containsRangeFirstLastInvariance", true, - rb -> MutableRoaringBitmap.add(rb.clone(), toUnsignedLong(rb.first()), toUnsignedLong(rb.last())) - .contains(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); + verifyInvariance( + "containsRangeFirstLastInvariance", + true, + rb -> + MutableRoaringBitmap.add( + rb.clone(), toUnsignedLong(rb.first()), toUnsignedLong(rb.last())) + .contains(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); } @Test public void andCardinalityInvariance() { - verifyInvariance("andCardinalityInvariance", ITERATIONS, 1 << 9, - (l, r) -> MutableRoaringBitmap.and(l, r).getCardinality(), - (l, r) -> MutableRoaringBitmap.andCardinality(l, r)); + verifyInvariance( + "andCardinalityInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> MutableRoaringBitmap.and(l, r).getCardinality(), + (l, r) -> MutableRoaringBitmap.andCardinality(l, r)); } @Test public void orCardinalityInvariance() { - verifyInvariance("orCardinalityInvariance", ITERATIONS, 1 << 9, - (l, r) -> MutableRoaringBitmap.or(l, r).getCardinality(), - (l, r) -> MutableRoaringBitmap.orCardinality(l, r)); + verifyInvariance( + "orCardinalityInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> MutableRoaringBitmap.or(l, r).getCardinality(), + (l, r) -> MutableRoaringBitmap.orCardinality(l, r)); } @Test public void xorCardinalityInvariance() { - verifyInvariance("xorCardinalityInvariance", ITERATIONS, 1 << 9, - (l, r) -> MutableRoaringBitmap.xor(l, r).getCardinality(), - (l, r) -> MutableRoaringBitmap.xorCardinality(l, r)); + verifyInvariance( + "xorCardinalityInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> MutableRoaringBitmap.xor(l, r).getCardinality(), + (l, r) -> MutableRoaringBitmap.xorCardinality(l, r)); } @Test public void containsContainsInvariance() { - verifyInvariance("containsContainsInvariance", - (l, r) -> l.contains(r) && !r.equals(l), - (l, r) -> false, - (l, r) -> !r.contains(l)); + verifyInvariance( + "containsContainsInvariance", + (l, r) -> l.contains(r) && !r.equals(l), + (l, r) -> false, + (l, r) -> !r.contains(l)); } @Test public void containsAndInvariance() { - verifyInvariance("containsAndInvariance", - (l, r) -> l.contains(r), - (l, r) -> MutableRoaringBitmap.and(l, r).equals(r)); + verifyInvariance( + "containsAndInvariance", + (l, r) -> l.contains(r), + (l, r) -> MutableRoaringBitmap.and(l, r).equals(r)); } @Test public void andCardinalityContainsInvariance() { - verifyInvariance("andCardinalityContainsInvariance", - (l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0, - (l, r) -> false, - (l, r) -> l.contains(r) || r.contains(l)); + verifyInvariance( + "andCardinalityContainsInvariance", + (l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0, + (l, r) -> false, + (l, r) -> l.contains(r) || r.contains(l)); } @Test public void sizeOfUnionOfDisjointSetsEqualsSumOfSizes() { - verifyInvariance("sizeOfUnionOfDisjointSetsEqualsSumOfSizes", - (l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0, - (l, r) -> l.getCardinality() + r.getCardinality(), - (l, r) -> MutableRoaringBitmap.orCardinality(l, r)); + verifyInvariance( + "sizeOfUnionOfDisjointSetsEqualsSumOfSizes", + (l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0, + (l, r) -> l.getCardinality() + r.getCardinality(), + (l, r) -> MutableRoaringBitmap.orCardinality(l, r)); } @Test public void sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes() { - verifyInvariance("sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes", - (l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0, - (l, r) -> l.getCardinality() + r.getCardinality(), - (l, r) -> MutableRoaringBitmap.xorCardinality(l, r)); + verifyInvariance( + "sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes", + (l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0, + (l, r) -> l.getCardinality() + r.getCardinality(), + (l, r) -> MutableRoaringBitmap.xorCardinality(l, r)); } @Test @@ -330,171 +376,201 @@ public void equalsSymmetryInvariance() { @Test public void orOfDisjunction() { - verifyInvariance("orOfDisjunction", ITERATIONS, 1 << 8, - (l, r) -> l, - (l, r) -> MutableRoaringBitmap.or(l, MutableRoaringBitmap.and(l, r))); + verifyInvariance( + "orOfDisjunction", + ITERATIONS, + 1 << 8, + (l, r) -> l, + (l, r) -> MutableRoaringBitmap.or(l, MutableRoaringBitmap.and(l, r))); } @Test public void orCoversXor() { - verifyInvariance("orCoversXor", ITERATIONS, 1 << 8, - (l, r) -> MutableRoaringBitmap.or(l, r), - (l, r) -> MutableRoaringBitmap.or(l, MutableRoaringBitmap.xor(l, r))); + verifyInvariance( + "orCoversXor", + ITERATIONS, + 1 << 8, + (l, r) -> MutableRoaringBitmap.or(l, r), + (l, r) -> MutableRoaringBitmap.or(l, MutableRoaringBitmap.xor(l, r))); } @Test public void xorInvariance() { - verifyInvariance("xorInvariance", ITERATIONS, 1 << 9, - (l, r) -> MutableRoaringBitmap.xor(l, r), - (l, r) -> MutableRoaringBitmap.andNot(MutableRoaringBitmap.or(l, r), MutableRoaringBitmap.and(l, r))); + verifyInvariance( + "xorInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> MutableRoaringBitmap.xor(l, r), + (l, r) -> + MutableRoaringBitmap.andNot( + MutableRoaringBitmap.or(l, r), MutableRoaringBitmap.and(l, r))); } @Test public void rangeCardinalityVsMaterialisedRange() { - verifyInvariance("rangeCardinalityVsMaterialisedRange", 1 << 9, - (min, max, bitmap) -> { - MutableRoaringBitmap range = new MutableRoaringBitmap(); - range.add(min, max); - return bitmap.rangeCardinality(min, max) == ImmutableRoaringBitmap.andCardinality(range, bitmap); - }); + verifyInvariance( + "rangeCardinalityVsMaterialisedRange", + 1 << 9, + (min, max, bitmap) -> { + MutableRoaringBitmap range = new MutableRoaringBitmap(); + range.add(min, max); + return bitmap.rangeCardinality(min, max) + == ImmutableRoaringBitmap.andCardinality(range, bitmap); + }); } @Test public void intersectsUpperBoundary() { - verifyInvariance("intersectsUpperBoundary", 1 << 9, - bitmap -> { - long max = bitmap.last() & 0xFFFFFFFFL; - return max == 0xFFFFFFFFL || bitmap.intersects(max - 1, max + 1); - }); + verifyInvariance( + "intersectsUpperBoundary", + 1 << 9, + bitmap -> { + long max = bitmap.last() & 0xFFFFFFFFL; + return max == 0xFFFFFFFFL || bitmap.intersects(max - 1, max + 1); + }); } @Test public void intersectsLowerBoundary() { - verifyInvariance("intersectsLowerBoundary", 1 << 9, - bitmap -> { - long min = bitmap.first() & 0xFFFFFFFFL; - return min == 0 || bitmap.intersects(min - 1, min + 1); - }); + verifyInvariance( + "intersectsLowerBoundary", + 1 << 9, + bitmap -> { + long min = bitmap.first() & 0xFFFFFFFFL; + return min == 0 || bitmap.intersects(min - 1, min + 1); + }); } @Test public void notIntersectsDisjointUpperBoundary() { - verifyInvariance("notIntersectsDisjointUpperBoundary", 1 << 9, - bitmap -> { - long max = (bitmap.last() & 0xFFFFFFFFL) + 1; - return !bitmap.intersects(max, 0xFFFFFFFFL); - }); + verifyInvariance( + "notIntersectsDisjointUpperBoundary", + 1 << 9, + bitmap -> { + long max = (bitmap.last() & 0xFFFFFFFFL) + 1; + return !bitmap.intersects(max, 0xFFFFFFFFL); + }); } @Test public void notIntersectsDisjointLowerBoundary() { - verifyInvariance("notIntersectsDisjointLowerBoundary", 1 << 9, - bitmap -> { - long min = bitmap.first() & 0xFFFFFFFFL; - return !bitmap.intersects(0, min); - }); + verifyInvariance( + "notIntersectsDisjointLowerBoundary", + 1 << 9, + bitmap -> { + long min = bitmap.first() & 0xFFFFFFFFL; + return !bitmap.intersects(0, min); + }); } @Test public void removeIntersection() { - verifyInvariance("removeIntersection", - (l, r) -> MutableRoaringBitmap.andCardinality(l, r) > 0, - 1 << 12, - (l, r) -> { - int intersection = MutableRoaringBitmap.andCardinality(l, r); - MutableRoaringBitmap and = MutableRoaringBitmap.and(l, r); - IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); - int removed = 0; - while (it.hasNext()) { - l.remove(it.next()); - ++removed; - } - return removed == intersection; - }); + verifyInvariance( + "removeIntersection", + (l, r) -> MutableRoaringBitmap.andCardinality(l, r) > 0, + 1 << 12, + (l, r) -> { + int intersection = MutableRoaringBitmap.andCardinality(l, r); + MutableRoaringBitmap and = MutableRoaringBitmap.and(l, r); + IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); + int removed = 0; + while (it.hasNext()) { + l.remove(it.next()); + ++removed; + } + return removed == intersection; + }); } @Test public void dontContainAfterRemoval() { - verifyInvariance("dontIntersectAfterRemoval", - (l, r) -> MutableRoaringBitmap.andCardinality(l, r) > 0, - 1 << 12, - (l, r) -> { - int intersection = MutableRoaringBitmap.andCardinality(l, r); - MutableRoaringBitmap and = MutableRoaringBitmap.and(l, r); - long first = and.first() & 0xFFFFFFFFL; - int[] values = and.toArray(); - int removed = 0; - for (int next : values) { - if (!l.intersects(toUnsignedLong(next) - 1, toUnsignedLong(next) + 1)) { - return false; - } - l.remove(next); - if (l.contains(next)) { - return false; - } - if (first != next && l.contains(first, toUnsignedLong(next))) { - return false; - } - ++removed; - } - return removed == intersection; - }); + verifyInvariance( + "dontIntersectAfterRemoval", + (l, r) -> MutableRoaringBitmap.andCardinality(l, r) > 0, + 1 << 12, + (l, r) -> { + int intersection = MutableRoaringBitmap.andCardinality(l, r); + MutableRoaringBitmap and = MutableRoaringBitmap.and(l, r); + long first = and.first() & 0xFFFFFFFFL; + int[] values = and.toArray(); + int removed = 0; + for (int next : values) { + if (!l.intersects(toUnsignedLong(next) - 1, toUnsignedLong(next) + 1)) { + return false; + } + l.remove(next); + if (l.contains(next)) { + return false; + } + if (first != next && l.contains(first, toUnsignedLong(next))) { + return false; + } + ++removed; + } + return removed == intersection; + }); } @Test public void intersectsContainsRemove() { - verifyInvariance("intersectsContainsRemove", - (l, r) -> MutableRoaringBitmap.andCardinality(l, r) > 0, - 1 << 12, - (l, r) -> { - MutableRoaringBitmap and = MutableRoaringBitmap.and(l, r); - if (!(l.contains(and) && r.contains(and))) { - return false; - } - long first = and.first() & 0xFFFFFFFFL; - long last = and.last() & 0xFFFFFFFFL; - IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); - l.remove(first, last + 1); - while (it.hasNext()) { - long next = toUnsignedLong(it.next()); - if (l.intersects(first, next) || (first != next && !r.intersects(first, next))) { - return false; - } - if (l.contains(first, next)) { - return false; - } - } - return !l.contains(and); - }); + verifyInvariance( + "intersectsContainsRemove", + (l, r) -> MutableRoaringBitmap.andCardinality(l, r) > 0, + 1 << 12, + (l, r) -> { + MutableRoaringBitmap and = MutableRoaringBitmap.and(l, r); + if (!(l.contains(and) && r.contains(and))) { + return false; + } + long first = and.first() & 0xFFFFFFFFL; + long last = and.last() & 0xFFFFFFFFL; + IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); + l.remove(first, last + 1); + while (it.hasNext()) { + long next = toUnsignedLong(it.next()); + if (l.intersects(first, next) || (first != next && !r.intersects(first, next))) { + return false; + } + if (l.contains(first, next)) { + return false; + } + } + return !l.contains(and); + }); } @Test public void absentValuesConsistentWithBitSet() { - int[] offsets = new int[]{0, 1, -1, 10, -10, 100, -100}; - - // Size limit to avoid out of memory errors; r.last() > 0 to avoid bitmaps with last > Integer.MAX_VALUE - verifyInvariance(r -> r.isEmpty() || (r.last() > 0 && r.last() < 1 << 30), bitmap -> { - BitSet reference = new BitSet(); - bitmap.forEach((IntConsumer) reference::set); - - for (int next : bitmap) { - for (int offset : offsets) { - int pos = next + offset; - if (pos >= 0) { - assertEquals(reference.nextClearBit(pos), bitmap.nextAbsentValue(pos)); - assertEquals(reference.previousClearBit(pos), bitmap.previousAbsentValue(pos)); + int[] offsets = new int[] {0, 1, -1, 10, -10, 100, -100}; + + // Size limit to avoid out of memory errors; r.last() > 0 to avoid bitmaps with last > + // Integer.MAX_VALUE + verifyInvariance( + r -> r.isEmpty() || (r.last() > 0 && r.last() < 1 << 30), + bitmap -> { + BitSet reference = new BitSet(); + bitmap.forEach((IntConsumer) reference::set); + + for (int next : bitmap) { + for (int offset : offsets) { + int pos = next + offset; + if (pos >= 0) { + assertEquals(reference.nextClearBit(pos), bitmap.nextAbsentValue(pos)); + assertEquals(reference.previousClearBit(pos), bitmap.previousAbsentValue(pos)); + } + } } - } - } - }); + }); } @Test public void testFastAggregationAnd() { IntStream.range(0, ITERATIONS) - .parallel() - .forEach(i -> { - MutableRoaringBitmap[] bitmaps = new MutableRoaringBitmap[ThreadLocalRandom.current().nextInt(2, 20)]; + .parallel() + .forEach( + i -> { + MutableRoaringBitmap[] bitmaps = + new MutableRoaringBitmap[ThreadLocalRandom.current().nextInt(2, 20)]; for (int j = 0; j < bitmaps.length; ++j) { bitmaps[j] = randomBitmap(512); } diff --git a/fuzz-tests/src/test/java/org/roaringbitmap/Fuzzer.java b/fuzz-tests/src/test/java/org/roaringbitmap/Fuzzer.java index 2e73df0d3..493d18bae 100644 --- a/fuzz-tests/src/test/java/org/roaringbitmap/Fuzzer.java +++ b/fuzz-tests/src/test/java/org/roaringbitmap/Fuzzer.java @@ -1,21 +1,23 @@ package org.roaringbitmap; -import com.google.common.collect.ImmutableMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.roaringbitmap.RandomisedTestData.ITERATIONS; +import static org.roaringbitmap.RandomisedTestData.randomBitmap; +import static org.roaringbitmap.Util.toUnsignedLong; +import com.google.common.collect.ImmutableMap; import org.junit.jupiter.api.Test; import java.util.BitSet; import java.util.concurrent.ThreadLocalRandom; -import java.util.function.*; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.IntStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.roaringbitmap.RandomisedTestData.ITERATIONS; -import static org.roaringbitmap.RandomisedTestData.randomBitmap; -import static org.roaringbitmap.Util.toUnsignedLong; - public class Fuzzer { @FunctionalInterface @@ -28,19 +30,18 @@ interface RangeBitmapPredicate { boolean test(long min, long max, RoaringBitmap bitmap); } - public static void verifyInvariance(String testName, T value, Function func) { + public static void verifyInvariance( + String testName, T value, Function func) { verifyInvariance(testName, ITERATIONS, 1 << 9, value, func); } - public static void verifyInvariance(String testName, - int count, - int maxKeys, - T value, - Function func) { + public static void verifyInvariance( + String testName, int count, int maxKeys, T value, Function func) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .forEach( + bitmap -> { try { assertEquals(value, func.apply(bitmap)); } catch (Throwable e) { @@ -50,12 +51,12 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, int maxKeys, RangeBitmapPredicate pred) { IntStream.range(0, ITERATIONS) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .forEach( + bitmap -> { long min = ThreadLocalRandom.current().nextLong(1L << 32); long max = ThreadLocalRandom.current().nextLong(min, 1L << 32); try { @@ -69,9 +70,10 @@ public static void verifyInvariance(String testName, int maxKeys, RangeBitmapPre public static void verifyInvariance(String testName, int maxKeys, Predicate pred) { IntStream.range(0, ITERATIONS) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .forEach( + bitmap -> { try { assertTrue(pred.test(bitmap)); } catch (Throwable e) { @@ -81,24 +83,27 @@ public static void verifyInvariance(String testName, int maxKeys, Predicate void verifyInvariance(String testName, - Predicate validity, - Function left, - Function right) { + public static void verifyInvariance( + String testName, + Predicate validity, + Function left, + Function right) { verifyInvariance(testName, ITERATIONS, 1 << 8, validity, left, right); } - public static void verifyInvariance(String testName, - int count, - int maxKeys, - Predicate validity, - Function left, - Function right) { + public static void verifyInvariance( + String testName, + int count, + int maxKeys, + Predicate validity, + Function left, + Function right) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .filter(validity) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .filter(validity) + .forEach( + bitmap -> { try { assertEquals(left.apply(bitmap), right.apply(bitmap)); } catch (Throwable e) { @@ -108,37 +113,41 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + BiFunction left, + BiFunction right) { verifyInvariance(testName, ITERATIONS, 1 << 8, left, right); } - public static void verifyInvariance(String testName, - BiPredicate validity, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + BiFunction left, + BiFunction right) { verifyInvariance(testName, validity, ITERATIONS, 1 << 8, left, right); } - - public static void verifyInvariance(String testName, - int count, - int maxKeys, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + int count, + int maxKeys, + BiFunction left, + BiFunction right) { verifyInvariance(testName, (l, r) -> true, count, maxKeys, left, right); } - public static void verifyInvariance(String testName, - BiPredicate validity, - int count, - int maxKeys, - BiFunction left, - BiFunction right) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + int count, + int maxKeys, + BiFunction left, + BiFunction right) { IntStream.range(0, count) - .parallel() - .forEach(i -> { + .parallel() + .forEach( + i -> { RoaringBitmap one = randomBitmap(maxKeys); RoaringBitmap two = randomBitmap(maxKeys); if (validity.test(one, two)) { @@ -152,22 +161,24 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, - BiPredicate validity, - int maxKeys, - BiPredicate test) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + int maxKeys, + BiPredicate test) { verifyInvariance(testName, validity, ITERATIONS, maxKeys, test); } - - public static void verifyInvariance(String testName, - BiPredicate validity, - int count, - int maxKeys, - BiPredicate test) { + public static void verifyInvariance( + String testName, + BiPredicate validity, + int count, + int maxKeys, + BiPredicate test) { IntStream.range(0, count) - .parallel() - .forEach(i -> { + .parallel() + .forEach( + i -> { RoaringBitmap one = randomBitmap(maxKeys); RoaringBitmap two = randomBitmap(maxKeys); if (validity.test(one, two)) { @@ -181,22 +192,23 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(String testName, - Predicate validity, - IntBitmapPredicate predicate) { + public static void verifyInvariance( + String testName, Predicate validity, IntBitmapPredicate predicate) { verifyInvariance(testName, validity, ITERATIONS, 1 << 3, predicate); } - public static void verifyInvariance(String testName, - Predicate validity, - int count, - int maxKeys, - IntBitmapPredicate predicate) { + public static void verifyInvariance( + String testName, + Predicate validity, + int count, + int maxKeys, + IntBitmapPredicate predicate) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .filter(validity) - .forEach(bitmap -> { + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .filter(validity) + .forEach( + bitmap -> { for (int i = 0; i < bitmap.getCardinality(); ++i) { try { assertTrue(predicate.test(i, bitmap)); @@ -208,103 +220,132 @@ public static void verifyInvariance(String testName, }); } - public static void verifyInvariance(Predicate validity, - Consumer action) { + public static void verifyInvariance( + Predicate validity, Consumer action) { verifyInvariance(validity, ITERATIONS, 1 << 3, action); } - public static void verifyInvariance(Predicate validity, - int count, - int maxKeys, - Consumer action) { + public static void verifyInvariance( + Predicate validity, int count, int maxKeys, Consumer action) { IntStream.range(0, count) - .parallel() - .mapToObj(i -> randomBitmap(maxKeys)) - .filter(validity) - .forEach(action); + .parallel() + .mapToObj(i -> randomBitmap(maxKeys)) + .filter(validity) + .forEach(action); } @Test public void rankSelectInvariance() { - verifyInvariance("rankSelectInvariance", bitmap -> !bitmap.isEmpty(), (i, rb) -> rb.rank(rb.select(i)) == i + 1); + verifyInvariance( + "rankSelectInvariance", + bitmap -> !bitmap.isEmpty(), + (i, rb) -> rb.rank(rb.select(i)) == i + 1); } @Test public void selectContainsInvariance() { - verifyInvariance("rankSelectInvariance", bitmap -> !bitmap.isEmpty(), (i, rb) -> rb.contains(rb.select(i))); + verifyInvariance( + "rankSelectInvariance", bitmap -> !bitmap.isEmpty(), (i, rb) -> rb.contains(rb.select(i))); } @Test public void firstSelect0Invariance() { - verifyInvariance("rankSelectInvariance", bitmap -> !bitmap.isEmpty(), - l -> l.first(), - bitmap -> bitmap.select(0)); + verifyInvariance( + "rankSelectInvariance", + bitmap -> !bitmap.isEmpty(), + l -> l.first(), + bitmap -> bitmap.select(0)); } @Test public void lastSelectCardinalityInvariance() { - verifyInvariance("rankSelectInvariance", bitmap -> !bitmap.isEmpty(), - l -> l.last(), - bitmap -> bitmap.select(bitmap.getCardinality() - 1)); + verifyInvariance( + "rankSelectInvariance", + bitmap -> !bitmap.isEmpty(), + l -> l.last(), + bitmap -> bitmap.select(bitmap.getCardinality() - 1)); } @Test public void andCardinalityInvariance() { - verifyInvariance("andCardinalityInvariance", ITERATIONS, 1 << 9, - (l, r) -> RoaringBitmap.and(l, r).getCardinality(), - (l, r) -> RoaringBitmap.andCardinality(l, r)); + verifyInvariance( + "andCardinalityInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> RoaringBitmap.and(l, r).getCardinality(), + (l, r) -> RoaringBitmap.andCardinality(l, r)); } @Test public void orCardinalityInvariance() { - verifyInvariance("orCardinalityInvariance", ITERATIONS, 1 << 9, - (l, r) -> RoaringBitmap.or(l, r).getCardinality(), - (l, r) -> RoaringBitmap.orCardinality(l, r)); + verifyInvariance( + "orCardinalityInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> RoaringBitmap.or(l, r).getCardinality(), + (l, r) -> RoaringBitmap.orCardinality(l, r)); } @Test public void xorCardinalityInvariance() { - verifyInvariance("xorCardinalityInvariance", ITERATIONS, 1 << 9, - (l, r) -> RoaringBitmap.xor(l, r).getCardinality(), - (l, r) -> RoaringBitmap.xorCardinality(l, r)); + verifyInvariance( + "xorCardinalityInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> RoaringBitmap.xor(l, r).getCardinality(), + (l, r) -> RoaringBitmap.xorCardinality(l, r)); } @Test public void containsContainsInvariance() { - verifyInvariance("containsContainsInvariance", (l, r) -> l.contains(r) && !r.equals(l), - (l, r) -> false, - (l, r) -> !r.contains(l)); + verifyInvariance( + "containsContainsInvariance", + (l, r) -> l.contains(r) && !r.equals(l), + (l, r) -> false, + (l, r) -> !r.contains(l)); } @Test public void containsAndInvariance() { - verifyInvariance("containsAndInvariance", (l, r) -> l.contains(r), (l, r) -> RoaringBitmap.and(l, r).equals(r)); + verifyInvariance( + "containsAndInvariance", + (l, r) -> l.contains(r), + (l, r) -> RoaringBitmap.and(l, r).equals(r)); } - @Test public void limitCardinalityEqualsSelf() { - verifyInvariance("limitCardinalityEqualsSelf", true, rb -> rb.equals(rb.limit(rb.getCardinality()))); + verifyInvariance( + "limitCardinalityEqualsSelf", true, rb -> rb.equals(rb.limit(rb.getCardinality()))); } @Test public void limitCardinalityXorCardinalityInvariance() { - verifyInvariance("limitCardinalityXorCardinalityInvariance", rb -> true, - l -> l.getCardinality(), - rb -> rb.getCardinality() / 2 - + RoaringBitmap.xorCardinality(rb, rb.limit(rb.getCardinality() / 2))); + verifyInvariance( + "limitCardinalityXorCardinalityInvariance", + rb -> true, + l -> l.getCardinality(), + rb -> + rb.getCardinality() / 2 + + RoaringBitmap.xorCardinality(rb, rb.limit(rb.getCardinality() / 2))); } @Test public void containsRangeFirstLastInvariance() { - verifyInvariance("containsRangeFirstLastInvariance", true, - rb -> RoaringBitmap.add(rb.clone(), toUnsignedLong(rb.first()), toUnsignedLong(rb.last())) - .contains(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); + verifyInvariance( + "containsRangeFirstLastInvariance", + true, + rb -> + RoaringBitmap.add(rb.clone(), toUnsignedLong(rb.first()), toUnsignedLong(rb.last())) + .contains(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); } @Test public void intersectsRangeFirstLastInvariance() { - verifyInvariance("intersectsRangeFirstLastInvariance", true, rb -> rb.intersects(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); + verifyInvariance( + "intersectsRangeFirstLastInvariance", + true, + rb -> rb.intersects(toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))); } @Test @@ -319,23 +360,29 @@ public void containsSubset() { @Test public void andCardinalityContainsInvariance() { - verifyInvariance("andCardinalityContainsInvariance", (l, r) -> RoaringBitmap.andCardinality(l, r) == 0, - (l, r) -> false, - (l, r) -> l.contains(r) || r.contains(l)); + verifyInvariance( + "andCardinalityContainsInvariance", + (l, r) -> RoaringBitmap.andCardinality(l, r) == 0, + (l, r) -> false, + (l, r) -> l.contains(r) || r.contains(l)); } @Test public void sizeOfUnionOfDisjointSetsEqualsSumOfSizes() { - verifyInvariance("sizeOfUnionOfDisjointSetsEqualsSumOfSizes", (l, r) -> RoaringBitmap.andCardinality(l, r) == 0, - (l, r) -> l.getCardinality() + r.getCardinality(), - (l, r) -> RoaringBitmap.orCardinality(l, r)); + verifyInvariance( + "sizeOfUnionOfDisjointSetsEqualsSumOfSizes", + (l, r) -> RoaringBitmap.andCardinality(l, r) == 0, + (l, r) -> l.getCardinality() + r.getCardinality(), + (l, r) -> RoaringBitmap.orCardinality(l, r)); } @Test public void sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes() { - verifyInvariance("sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes", (l, r) -> RoaringBitmap.andCardinality(l, r) == 0, - (l, r) -> l.getCardinality() + r.getCardinality(), - (l, r) -> RoaringBitmap.xorCardinality(l, r)); + verifyInvariance( + "sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes", + (l, r) -> RoaringBitmap.andCardinality(l, r) == 0, + (l, r) -> l.getCardinality() + r.getCardinality(), + (l, r) -> RoaringBitmap.xorCardinality(l, r)); } @Test @@ -345,220 +392,254 @@ public void equalsSymmetryInvariance() { @Test public void orOfDisjunction() { - verifyInvariance("orOfDisjunction", ITERATIONS, 1 << 8, - (l, r) -> l, - (l, r) -> RoaringBitmap.or(l, RoaringBitmap.and(l, r))); + verifyInvariance( + "orOfDisjunction", + ITERATIONS, + 1 << 8, + (l, r) -> l, + (l, r) -> RoaringBitmap.or(l, RoaringBitmap.and(l, r))); } @Test public void orCoversXor() { - verifyInvariance("orCoversXor", ITERATIONS, 1 << 8, - (l, r) -> RoaringBitmap.or(l, r), - (l, r) -> RoaringBitmap.or(l, RoaringBitmap.xor(l, r))); + verifyInvariance( + "orCoversXor", + ITERATIONS, + 1 << 8, + (l, r) -> RoaringBitmap.or(l, r), + (l, r) -> RoaringBitmap.or(l, RoaringBitmap.xor(l, r))); } @Test public void xorInvariance() { - verifyInvariance("xorInvariance", ITERATIONS, 1 << 9, - (l, r) -> RoaringBitmap.xor(l, r), - (l, r) -> RoaringBitmap.andNot(RoaringBitmap.or(l, r), RoaringBitmap.and(l, r))); + verifyInvariance( + "xorInvariance", + ITERATIONS, + 1 << 9, + (l, r) -> RoaringBitmap.xor(l, r), + (l, r) -> RoaringBitmap.andNot(RoaringBitmap.or(l, r), RoaringBitmap.and(l, r))); } @Test public void rangeCardinalityVsMaterialisedRange() { - verifyInvariance("rangeCardinalityVsMaterialisedRange", 1 << 9, - (min, max, bitmap) -> { - RoaringBitmap range = new RoaringBitmap(); - range.add(min, max); - return bitmap.rangeCardinality(min, max) == RoaringBitmap.andCardinality(range, bitmap); - }); + verifyInvariance( + "rangeCardinalityVsMaterialisedRange", + 1 << 9, + (min, max, bitmap) -> { + RoaringBitmap range = new RoaringBitmap(); + range.add(min, max); + return bitmap.rangeCardinality(min, max) == RoaringBitmap.andCardinality(range, bitmap); + }); } @Test public void intersectsUpperBoundary() { - verifyInvariance("intersectsUpperBoundary", 1 << 9, - (RoaringBitmap bitmap) -> { - long max = bitmap.last() & 0xFFFFFFFFL; - return max == 0xFFFFFFFFL || bitmap.intersects(max - 1, max + 1); - }); + verifyInvariance( + "intersectsUpperBoundary", + 1 << 9, + (RoaringBitmap bitmap) -> { + long max = bitmap.last() & 0xFFFFFFFFL; + return max == 0xFFFFFFFFL || bitmap.intersects(max - 1, max + 1); + }); } @Test public void intersectsLowerBoundary() { - verifyInvariance("intersectsLowerBoundary", 1 << 9, - (RoaringBitmap bitmap) -> { - long min = bitmap.first() & 0xFFFFFFFFL; - return min == 0 || bitmap.intersects(min - 1, min + 1); - }); + verifyInvariance( + "intersectsLowerBoundary", + 1 << 9, + (RoaringBitmap bitmap) -> { + long min = bitmap.first() & 0xFFFFFFFFL; + return min == 0 || bitmap.intersects(min - 1, min + 1); + }); } @Test public void notIntersectsDisjointUpperBoundary() { - verifyInvariance("notIntersectsDisjointUpperBoundary", 1 << 9, - (RoaringBitmap bitmap) -> { - long max = (bitmap.last() & 0xFFFFFFFFL) + 1; - return !bitmap.intersects(max, 0xFFFFFFFFL); - }); + verifyInvariance( + "notIntersectsDisjointUpperBoundary", + 1 << 9, + (RoaringBitmap bitmap) -> { + long max = (bitmap.last() & 0xFFFFFFFFL) + 1; + return !bitmap.intersects(max, 0xFFFFFFFFL); + }); } @Test public void notIntersectsDisjointLowerBoundary() { - verifyInvariance("notIntersectsDisjointLowerBoundary", 1 << 9, - (RoaringBitmap bitmap) -> { - long min = bitmap.first() & 0xFFFFFFFFL; - return !bitmap.intersects(0, min); - }); + verifyInvariance( + "notIntersectsDisjointLowerBoundary", + 1 << 9, + (RoaringBitmap bitmap) -> { + long min = bitmap.first() & 0xFFFFFFFFL; + return !bitmap.intersects(0, min); + }); } @Test public void removeIntersection() { - verifyInvariance("removeIntersection", - (l, r) -> RoaringBitmap.andCardinality(l, r) > 0, - 1 << 12, - (l, r) -> { - int intersection = RoaringBitmap.andCardinality(l, r); - RoaringBitmap and = RoaringBitmap.and(l, r); - IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); - int removed = 0; - while (it.hasNext()) { - l.remove(it.next()); - ++removed; - } - return removed == intersection; - }); + verifyInvariance( + "removeIntersection", + (l, r) -> RoaringBitmap.andCardinality(l, r) > 0, + 1 << 12, + (l, r) -> { + int intersection = RoaringBitmap.andCardinality(l, r); + RoaringBitmap and = RoaringBitmap.and(l, r); + IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); + int removed = 0; + while (it.hasNext()) { + l.remove(it.next()); + ++removed; + } + return removed == intersection; + }); } @Test public void dontContainAfterRemoval() { - verifyInvariance("dontIntersectAfterRemoval", - (l, r) -> RoaringBitmap.andCardinality(l, r) > 0, - 1 << 12, - (l, r) -> { - int intersection = RoaringBitmap.andCardinality(l, r); - RoaringBitmap and = RoaringBitmap.and(l, r); - long first = and.first() & 0xFFFFFFFFL; - int[] values = and.toArray(); - int removed = 0; - for (int next : values) { - if (!l.intersects(toUnsignedLong(next) - 1, toUnsignedLong(next) + 1)) { - return false; - } - l.remove(next); - if (l.contains(next)) { - return false; - } - if (first != next && l.contains(first, toUnsignedLong(next))) { - return false; - } - ++removed; - } - return removed == intersection; - }); + verifyInvariance( + "dontIntersectAfterRemoval", + (l, r) -> RoaringBitmap.andCardinality(l, r) > 0, + 1 << 12, + (l, r) -> { + int intersection = RoaringBitmap.andCardinality(l, r); + RoaringBitmap and = RoaringBitmap.and(l, r); + long first = and.first() & 0xFFFFFFFFL; + int[] values = and.toArray(); + int removed = 0; + for (int next : values) { + if (!l.intersects(toUnsignedLong(next) - 1, toUnsignedLong(next) + 1)) { + return false; + } + l.remove(next); + if (l.contains(next)) { + return false; + } + if (first != next && l.contains(first, toUnsignedLong(next))) { + return false; + } + ++removed; + } + return removed == intersection; + }); } @Test public void intersectsContainsRemove() { - verifyInvariance("intersectsContainsRemove", - (l, r) -> RoaringBitmap.andCardinality(l, r) > 0, - 1 << 12, - (l, r) -> { - RoaringBitmap and = RoaringBitmap.and(l, r); - if (!(l.contains(and) && r.contains(and))) { - return false; - } - long first = and.first() & 0xFFFFFFFFL; - long last = and.last() & 0xFFFFFFFFL; - IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); - l.remove(first, last + 1); - while (it.hasNext()) { - long next = toUnsignedLong(it.next()); - if (l.intersects(first, next) || (first != next && !r.intersects(first, next))) { - return false; - } - if (l.contains(first, next)) { - return false; - } - } - return !l.contains(and); - }); + verifyInvariance( + "intersectsContainsRemove", + (l, r) -> RoaringBitmap.andCardinality(l, r) > 0, + 1 << 12, + (l, r) -> { + RoaringBitmap and = RoaringBitmap.and(l, r); + if (!(l.contains(and) && r.contains(and))) { + return false; + } + long first = and.first() & 0xFFFFFFFFL; + long last = and.last() & 0xFFFFFFFFL; + IntIterator it = and.getBatchIterator().asIntIterator(new int[16]); + l.remove(first, last + 1); + while (it.hasNext()) { + long next = toUnsignedLong(it.next()); + if (l.intersects(first, next) || (first != next && !r.intersects(first, next))) { + return false; + } + if (l.contains(first, next)) { + return false; + } + } + return !l.contains(and); + }); } @Test public void orNotDoesNotTruncate() { - verifyInvariance("orNotDoesNotTruncate", - (l, r) -> !l.isEmpty() && (r.isEmpty() || l.last() > r.last()), - 1 << 12, - (l, r) -> { - int last = l.last(); - if (last > 1) { - long rangeEnd = ThreadLocalRandom.current().nextLong(0, last - 1); - l.orNot(r, rangeEnd); - return l.contains(last); - } - return true; - }); + verifyInvariance( + "orNotDoesNotTruncate", + (l, r) -> !l.isEmpty() && (r.isEmpty() || l.last() > r.last()), + 1 << 12, + (l, r) -> { + int last = l.last(); + if (last > 1) { + long rangeEnd = ThreadLocalRandom.current().nextLong(0, last - 1); + l.orNot(r, rangeEnd); + return l.contains(last); + } + return true; + }); } @Test public void orNot() { - verifyInvariance("orNot", ITERATIONS, 1 << 9, - (RoaringBitmap l, RoaringBitmap r) -> { - RoaringBitmap x = l.clone(); - long max = (x.last() & 0xFFFFFFFFL) + 1; - x.orNot(r, max); - return x; - }, - (RoaringBitmap l, RoaringBitmap r) -> { - RoaringBitmap range = new RoaringBitmap(); - long limit = toUnsignedLong(l.last()) + 1; - range.add(0, limit); - range.andNot(r); - return RoaringBitmap.or(l, range); - }); + verifyInvariance( + "orNot", + ITERATIONS, + 1 << 9, + (RoaringBitmap l, RoaringBitmap r) -> { + RoaringBitmap x = l.clone(); + long max = (x.last() & 0xFFFFFFFFL) + 1; + x.orNot(r, max); + return x; + }, + (RoaringBitmap l, RoaringBitmap r) -> { + RoaringBitmap range = new RoaringBitmap(); + long limit = toUnsignedLong(l.last()) + 1; + range.add(0, limit); + range.andNot(r); + return RoaringBitmap.or(l, range); + }); } @Test public void orNotStatic() { - verifyInvariance("orNot", ITERATIONS, 1 << 9, - (RoaringBitmap l, RoaringBitmap r) -> { - RoaringBitmap x = l.clone(); - long max = (x.last() & 0xFFFFFFFFL) + 1; - x.orNot(r, max); - return x; - }, - (RoaringBitmap l, RoaringBitmap r) -> { - RoaringBitmap x = l.clone(); - long max = (x.last() & 0xFFFFFFFFL) + 1; - return RoaringBitmap.orNot(l, r, max); - }); + verifyInvariance( + "orNot", + ITERATIONS, + 1 << 9, + (RoaringBitmap l, RoaringBitmap r) -> { + RoaringBitmap x = l.clone(); + long max = (x.last() & 0xFFFFFFFFL) + 1; + x.orNot(r, max); + return x; + }, + (RoaringBitmap l, RoaringBitmap r) -> { + RoaringBitmap x = l.clone(); + long max = (x.last() & 0xFFFFFFFFL) + 1; + return RoaringBitmap.orNot(l, r, max); + }); } @Test public void absentValuesConsistentWithBitSet() { - int[] offsets = new int[]{0, 1, -1, 10, -10, 100, -100}; - // Size limit to avoid out of memory errors; r.last() > 0 to avoid bitmaps with last > Integer.MAX_VALUE - verifyInvariance(r -> r.isEmpty() || (r.last() > 0 && r.last() < 1 << 30), bitmap -> { - BitSet reference = new BitSet(); - bitmap.forEach((IntConsumer) reference::set); - - for (int next : bitmap) { - for (int offset : offsets) { - int pos = next + offset; - if (pos >= 0) { - assertEquals(reference.nextClearBit(pos), bitmap.nextAbsentValue(pos)); - assertEquals(reference.previousClearBit(pos), bitmap.previousAbsentValue(pos)); + int[] offsets = new int[] {0, 1, -1, 10, -10, 100, -100}; + // Size limit to avoid out of memory errors; r.last() > 0 to avoid bitmaps with last > + // Integer.MAX_VALUE + verifyInvariance( + r -> r.isEmpty() || (r.last() > 0 && r.last() < 1 << 30), + bitmap -> { + BitSet reference = new BitSet(); + bitmap.forEach((IntConsumer) reference::set); + + for (int next : bitmap) { + for (int offset : offsets) { + int pos = next + offset; + if (pos >= 0) { + assertEquals(reference.nextClearBit(pos), bitmap.nextAbsentValue(pos)); + assertEquals(reference.previousClearBit(pos), bitmap.previousAbsentValue(pos)); + } + } } - } - } - }); + }); } @Test public void testFastAggregationAnd() { IntStream.range(0, ITERATIONS) - .parallel() - .forEach(i -> { - RoaringBitmap[] bitmaps = new RoaringBitmap[ThreadLocalRandom.current().nextInt(2, 20)]; + .parallel() + .forEach( + i -> { + RoaringBitmap[] bitmaps = + new RoaringBitmap[ThreadLocalRandom.current().nextInt(2, 20)]; for (int j = 0; j < bitmaps.length; ++j) { bitmaps[j] = randomBitmap(512); } diff --git a/fuzz-tests/src/test/java/org/roaringbitmap/RandomisedTestData.java b/fuzz-tests/src/test/java/org/roaringbitmap/RandomisedTestData.java index 4e25cb1ad..1b8bbb869 100644 --- a/fuzz-tests/src/test/java/org/roaringbitmap/RandomisedTestData.java +++ b/fuzz-tests/src/test/java/org/roaringbitmap/RandomisedTestData.java @@ -1,42 +1,44 @@ package org.roaringbitmap; +import static java.lang.Integer.parseInt; +import static org.roaringbitmap.RoaringBitmapWriter.writer; + import java.util.Arrays; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; -import static java.lang.Integer.parseInt; -import static org.roaringbitmap.RoaringBitmapWriter.writer; - public class RandomisedTestData { - public static final int ITERATIONS = parseInt(System.getProperty("org.roaringbitmap.fuzz.iterations", "10000")); + public static final int ITERATIONS = + parseInt(System.getProperty("org.roaringbitmap.fuzz.iterations", "10000")); private static final ThreadLocal bits = ThreadLocal.withInitial(() -> new long[1 << 10]); private static final ThreadLocal runs = ThreadLocal.withInitial(() -> new int[4096]); public static RoaringBitmap randomBitmap(int maxKeys, double rleLimit, double denseLimit) { - return randomBitmap(maxKeys, rleLimit, denseLimit, writer().initialCapacity(maxKeys).optimiseForArrays().get()); + return randomBitmap( + maxKeys, rleLimit, denseLimit, writer().initialCapacity(maxKeys).optimiseForArrays().get()); } public static RoaringBitmap randomBitmap(int maxKeys) { - double rleLimit = ThreadLocalRandom.current().nextDouble(); - double denseLimit = ThreadLocalRandom.current().nextDouble(rleLimit, 1D); - return randomBitmap(maxKeys, rleLimit, denseLimit); + double rleLimit = ThreadLocalRandom.current().nextDouble(); + double denseLimit = ThreadLocalRandom.current().nextDouble(rleLimit, 1D); + return randomBitmap(maxKeys, rleLimit, denseLimit); } - public static T randomBitmap(int maxKeys, RoaringBitmapWriter writer) { - double rleLimit = ThreadLocalRandom.current().nextDouble(); - double denseLimit = ThreadLocalRandom.current().nextDouble(rleLimit, 1D); - return randomBitmap(maxKeys, rleLimit, denseLimit, writer); + public static T randomBitmap( + int maxKeys, RoaringBitmapWriter writer) { + double rleLimit = ThreadLocalRandom.current().nextDouble(); + double denseLimit = ThreadLocalRandom.current().nextDouble(rleLimit, 1D); + return randomBitmap(maxKeys, rleLimit, denseLimit, writer); } - private static T randomBitmap(int maxKeys, - double rleLimit, - double denseLimit, - RoaringBitmapWriter writer) { + private static T randomBitmap( + int maxKeys, double rleLimit, double denseLimit, RoaringBitmapWriter writer) { int[] keys = createSorted16BitInts(ThreadLocalRandom.current().nextInt(1, maxKeys)); IntStream.of(keys) - .forEach(key -> { + .forEach( + key -> { double choice = ThreadLocalRandom.current().nextDouble(); final IntStream stream; if (choice < rleLimit) { @@ -59,17 +61,17 @@ private static IntStream rleRegion() { int start = ThreadLocalRandom.current().nextInt(64); int run = 0; while (minRequiredCardinality > 0 && start < 0xFFFF && run < 2 * maxNumRuns) { - int runLength = ThreadLocalRandom.current().nextInt(1, minRequiredCardinality + 1); - values[run++] = start; - values[run++] = Math.min(start + runLength, 0x10000 - start); - start += runLength + ThreadLocalRandom.current().nextInt(64); - minRequiredCardinality -= runLength; - ++totalRuns; + int runLength = ThreadLocalRandom.current().nextInt(1, minRequiredCardinality + 1); + values[run++] = start; + values[run++] = Math.min(start + runLength, 0x10000 - start); + start += runLength + ThreadLocalRandom.current().nextInt(64); + minRequiredCardinality -= runLength; + ++totalRuns; } return IntStream.range(0, totalRuns) - .map(i -> i * 2) - .mapToObj(i -> IntStream.range(values[i], values[i + 1])) - .flatMapToInt(i -> i); + .map(i -> i * 2) + .mapToObj(i -> IntStream.range(values[i], values[i + 1])) + .flatMapToInt(i -> i); } private static IntStream sparseRegion() { diff --git a/fuzz-tests/src/test/java/org/roaringbitmap/Reporter.java b/fuzz-tests/src/test/java/org/roaringbitmap/Reporter.java index 2613542ec..a5a5d7033 100644 --- a/fuzz-tests/src/test/java/org/roaringbitmap/Reporter.java +++ b/fuzz-tests/src/test/java/org/roaringbitmap/Reporter.java @@ -1,5 +1,7 @@ package org.roaringbitmap; +import static java.util.stream.Collectors.toList; + import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; @@ -8,16 +10,23 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; - -import static java.util.stream.Collectors.toList; +import java.util.Arrays; +import java.util.Base64; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; public class Reporter { - private static final String OUTPUT_DIR = System.getProperty("org.roaringbitmap.fuzz.output", System.getProperty("user.dir")); + private static final String OUTPUT_DIR = + System.getProperty("org.roaringbitmap.fuzz.output", System.getProperty("user.dir")); private static final ObjectMapper MAPPER = new ObjectMapper(); - public static synchronized void report(String testName, Map context, Throwable error, ImmutableBitmapDataProvider... bitmaps) { + public static synchronized void report( + String testName, + Map context, + Throwable error, + ImmutableBitmapDataProvider... bitmaps) { try { Map output = new LinkedHashMap<>(); output.put("testName", testName); @@ -25,7 +34,8 @@ public static synchronized void report(String testName, Map cont output.putAll(context); String[] base64 = new String[bitmaps.length]; for (int i = 0; i < bitmaps.length; ++i) { - ByteArrayDataOutput serialised = ByteStreams.newDataOutput(bitmaps[i].serializedSizeInBytes()); + ByteArrayDataOutput serialised = + ByteStreams.newDataOutput(bitmaps[i].serializedSizeInBytes()); bitmaps[i].serialize(serialised); base64[i] = Base64.getEncoder().encodeToString(serialised.toByteArray()); } @@ -34,13 +44,17 @@ public static synchronized void report(String testName, Map cont if (!Files.exists(dir)) { Files.createDirectory(dir); } - Files.write(dir.resolve(testName + "-" + UUID.randomUUID() + ".json"), MAPPER.writeValueAsBytes(output)); + Files.write( + dir.resolve(testName + "-" + UUID.randomUUID() + ".json"), + MAPPER.writeValueAsBytes(output)); } catch (IOException e) { e.printStackTrace(); } } private static String getStackTrace(Throwable t) { - return String.join("\n\t", Arrays.stream(t.getStackTrace()).map(StackTraceElement::toString).collect(toList())); + return String.join( + "\n\t", + Arrays.stream(t.getStackTrace()).map(StackTraceElement::toString).collect(toList())); } } diff --git a/gradle.properties b/gradle.properties index ae1152f39..4784002c0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version = 1.0.1-SNAPSHOT +version = 1.3.18-SNAPSHOT org.gradle.parallel=false org.gradle.daemon=true org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 000000000..7a64387b6 --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,5 @@ +jdk: + - openjdk11 +before_install: + - sdk install java 11.0.1-open + - sdk use java 11.0.1-open diff --git a/jmh/build.gradle.kts b/jmh/build.gradle.kts index afaaac228..7affcbc64 100644 --- a/jmh/build.gradle.kts +++ b/jmh/build.gradle.kts @@ -1,5 +1,3 @@ -import java.net.URI - plugins { id("me.champeau.gradle.jmh") version "0.5.0" id("com.github.johnrengelman.shadow") version "6.0.0" @@ -30,7 +28,7 @@ dependencies { // tests and benchmarks both need dependencies: javaEWAH, extendedset, etc. listOf( - project(":RoaringBitmap"), + project(":roaringbitmap"), project(":bsi"), "com.google.guava:guava:${deps["guava"]}", "com.googlecode.javaewah:JavaEWAH:1.0.8", @@ -67,14 +65,13 @@ tasks.test { if (!project.hasProperty("roaringbitmap.jmh")) { exclude("**") } else { - // stop these tests from running before RoaringBitmap - shouldRunAfter(project(":RoaringBitmap").tasks.test) + // stop these tests from running before roaringbitmap + shouldRunAfter(project(":roaringbitmap").tasks.test) useJUnitPlatform() failFast = true } } - // jmhJar task provided by jmh gradle plugin is currently broken // https://github.com/melix/jmh-gradle-plugin/issues/97 // so instead, we configure the shadowJar task to have JMH bits in it diff --git a/jmh/src/jmh/java/org/roaringbitmap/AbstractBenchmarkState.java b/jmh/src/jmh/java/org/roaringbitmap/AbstractBenchmarkState.java index 5f61c09f1..436246407 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/AbstractBenchmarkState.java +++ b/jmh/src/jmh/java/org/roaringbitmap/AbstractBenchmarkState.java @@ -22,18 +22,18 @@ import static org.roaringbitmap.realdata.wrapper.BitmapFactory.newRoaringWithRunBitmap; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.newWahBitmap; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.TearDown; import org.roaringbitmap.realdata.wrapper.Bitmap; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; @State(Scope.Benchmark) public abstract class AbstractBenchmarkState { @@ -48,24 +48,27 @@ public abstract class AbstractBenchmarkState { public AbstractBenchmarkState() {} public void setup(final String dataset, String type, boolean immutable) throws Exception { - if (ROARING_ONLY.equals(System.getProperty(BITMAP_TYPES)) && !ROARING.equals(type) + if (ROARING_ONLY.equals(System.getProperty(BITMAP_TYPES)) + && !ROARING.equals(type) && !ROARING_WITH_RUN.equals(type)) { throw new RuntimeException(String.format("Skipping non Roaring type %s", type)); } bitmaps = new ArrayList(); - List ints = DATASET_CACHE.get(dataset, new Callable>() { + List ints = + DATASET_CACHE.get( + dataset, + new Callable>() { - @Override - public List call() throws Exception { - System.out.println("Loading" + dataset); - ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); - - return Lists.newArrayList(dataRetriever.fetchBitPositions()); - } - }); + @Override + public List call() throws Exception { + System.out.println("Loading" + dataset); + ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); + return Lists.newArrayList(dataRetriever.fetchBitPositions()); + } + }); for (int[] data : ints) { Bitmap bitmap = null; @@ -114,7 +117,6 @@ public List call() throws Exception { } bitmaps.add(bitmap); - } } @@ -122,5 +124,4 @@ public List call() throws Exception { public void tearDown() { cleanup(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/AddOffsetBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/AddOffsetBenchmark.java new file mode 100644 index 000000000..8d68960d0 --- /dev/null +++ b/jmh/src/jmh/java/org/roaringbitmap/AddOffsetBenchmark.java @@ -0,0 +1,251 @@ +package org.roaringbitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 5000) +@Measurement(iterations = 10, timeUnit = TimeUnit.MILLISECONDS, time = 5000) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +@Fork( + value = 1, + jvmArgsPrepend = { + "-XX:-TieredCompilation", + "-XX:+UseSerialGC", // "-XX:+UseParallelGC", + "-mx2G", + "-ms2G", + "-XX:+AlwaysPreTouch" + }) +public class AddOffsetBenchmark { + @Param({ + "ARRAY_ALL_IN_LOW", + "ARRAY_HALF_TO_HALF", + "ARRAY_ALL_SHIFTED_TO_HIGH", + // all variant provided for completeness only, original and current implementation are the same + // "RUN_ALL_IN_LOW", "RUN_HALF_TO_HALF", "RUN_ALL_SHIFTED_TO_HIGH", + // "BITMAP_ALL_IN_LOW", "BITMAP_HALF_TO_HALF", "BITMAP_ALL_SHIFTED_TO_HIGH", + // "BITMAP_HALF_TO_HALF_MULTIPLE_OF_LONG", "BITMAP_ALL_SHIFTED_TO_HIGH_MULTIPLE_OF_LONG", + }) + Scenario scenario; + + @SuppressWarnings("unused") + public enum Scenario { + RUN_ALL_IN_LOW(ContainerType.RUN, 0), + RUN_HALF_TO_HALF(ContainerType.RUN, 35000), + RUN_ALL_SHIFTED_TO_HIGH(ContainerType.RUN, 60000), + + ARRAY_ALL_IN_LOW(ContainerType.ARRAY, 0), + ARRAY_HALF_TO_HALF(ContainerType.ARRAY, 35000), + ARRAY_ALL_SHIFTED_TO_HIGH(ContainerType.ARRAY, 60000), + + BITMAP_ALL_IN_LOW(ContainerType.BITMAP, 0), + BITMAP_HALF_TO_HALF(ContainerType.BITMAP, 35000), + BITMAP_ALL_SHIFTED_TO_HIGH(ContainerType.BITMAP, 60000), + + BITMAP_HALF_TO_HALF_MULTIPLE_OF_LONG(ContainerType.BITMAP, 32768 + Long.SIZE * 32), // ~ 35000 + BITMAP_ALL_SHIFTED_TO_HIGH_MULTIPLE_OF_LONG(ContainerType.BITMAP, 65536 - Long.SIZE), + ; + + private final ContainerType containerType; + private final char offsets; + + Scenario(ContainerType containerType, int offsets) { + this.containerType = containerType; + this.offsets = (char) offsets; + } + + public ContainerType getContainerType() { + return containerType; + } + + public char getOffsets() { + return offsets; + } + + public Container createContainer() { + return containerType.createContainer(); + } + } + + public enum ContainerType { + RUN { + @Override + public Container createContainer() { + RunContainer rc = new RunContainer(); + for (int i = 0; i < numberOfValues; i++) { + rc.add(minValue + i * 2, minValue + i * 2 + 1); + } + return rc; + } + }, + BITMAP { + @Override + public Container createContainer() { + BitmapContainer bc = new BitmapContainer(); + for (int i = 0; i < numberOfValues; i++) { + bc.add((char) (minValue + i * 2)); + } + return bc; + } + }, + ARRAY { + @Override + public Container createContainer() { + ArrayContainer ac = new ArrayContainer(); + for (int i = 0; i < numberOfValues; i++) { + ac.add((char) (minValue + i * 2)); + } + return ac; + } + }; + // value = minValue + i * 2 for i < numberOfValues, thus they lies in interval 20000 - 40000 + private static final int minValue = 20_000; + private static final int numberOfValues = 10000; + + public abstract Container createContainer(); + } + + public Container container; + public char offsets; + + @Setup(Level.Invocation) + public void setUp() { + container = scenario.createContainer(); + offsets = scenario.getOffsets(); + } + + @Benchmark + public Container[] optimized() { + return Util.addOffset(container, offsets); + } + + @Benchmark + public Container[] optimizedFieldIncrement() { + if (container instanceof ArrayContainer) { + // only for comparison with optimized version + return addOffsetIncrementField((ArrayContainer) container, offsets); + } else { + return new Container[0]; + } + } + + @Benchmark + public Container[] original() { + return addOffsetOriginal(container, offsets); + } + + @SuppressWarnings({"RedundantCast", "PointlessArithmeticExpression", "GrazieInspection"}) + public static Container[] addOffsetOriginal(Container source, char offsets) { + // could be a whole lot faster, this is a simple implementation + if (source instanceof ArrayContainer) { + ArrayContainer c = (ArrayContainer) source; + ArrayContainer low = new ArrayContainer(c.cardinality); + ArrayContainer high = new ArrayContainer(c.cardinality); + for (int k = 0; k < c.cardinality; k++) { + int val = c.content[k]; + val += (int) (offsets); + if (val <= 0xFFFF) { + low.content[low.cardinality++] = (char) val; + } else { + high.content[high.cardinality++] = (char) val; + } + } + return new Container[] {low, high}; + } else if (source instanceof BitmapContainer) { + BitmapContainer c = (BitmapContainer) source; + BitmapContainer low = new BitmapContainer(); + BitmapContainer high = new BitmapContainer(); + low.cardinality = -1; + high.cardinality = -1; + final int b = (int) (offsets) >>> 6; + final int i = (int) (offsets) % 64; + if (i == 0) { + System.arraycopy(c.bitmap, 0, low.bitmap, b, 1024 - b); + System.arraycopy(c.bitmap, 1024 - b, high.bitmap, 0, b); + } else { + low.bitmap[b + 0] = c.bitmap[0] << i; + for (int k = 1; k < 1024 - b; k++) { + low.bitmap[b + k] = (c.bitmap[k] << i) | (c.bitmap[k - 1] >>> (64 - i)); + } + for (int k = 1024 - b; k < 1024; k++) { + high.bitmap[k - (1024 - b)] = (c.bitmap[k] << i) | (c.bitmap[k - 1] >>> (64 - i)); + } + high.bitmap[b] = (c.bitmap[1024 - 1] >>> (64 - i)); + } + return new Container[] {low.repairAfterLazy(), high.repairAfterLazy()}; + } else if (source instanceof RunContainer) { + RunContainer input = (RunContainer) source; + RunContainer low = new RunContainer(); + RunContainer high = new RunContainer(); + for (int k = 0; k < input.nbrruns; k++) { + int val = (input.getValue(k)); + val += (int) (offsets); + int finalval = val + (input.getLength(k)); + if (val <= 0xFFFF) { + if (finalval <= 0xFFFF) { + low.smartAppend((char) val, input.getLength(k)); + } else { + low.smartAppend((char) val, (char) (0xFFFF - val)); + high.smartAppend((char) 0, (char) finalval); + } + } else { + high.smartAppend((char) val, input.getLength(k)); + } + } + return new Container[] {low, high}; + } + throw new RuntimeException("unknown container type"); // never happens + } + + private static Container[] addOffsetIncrementField(ArrayContainer source, char offsets) { + ArrayContainer low; + ArrayContainer high; + if (source.first() + offsets > 0xFFFF) { + low = new ArrayContainer(); + high = new ArrayContainer(source.cardinality); + for (int k = 0; k < source.cardinality; k++) { + int val = source.content[k] + offsets; + high.content[k] = (char) val; + } + high.cardinality = source.cardinality; + } else if (source.last() + offsets < 0xFFFF) { + low = new ArrayContainer(source.cardinality); + high = new ArrayContainer(); + for (int k = 0; k < source.cardinality; k++) { + int val = source.content[k] + offsets; + low.content[k] = (char) val; + } + low.cardinality = source.cardinality; + } else { + int splitIndex = + Util.unsignedBinarySearch(source.content, 0, source.cardinality, (char) ~offsets); + if (splitIndex < 0) { + splitIndex = -splitIndex - 1; + } + low = new ArrayContainer(splitIndex); + high = new ArrayContainer(source.cardinality - splitIndex); + for (int k = 0; k < splitIndex; k++) { + int val = source.content[k] + offsets; + low.content[low.cardinality++] = (char) val; + } + for (int k = splitIndex; k < source.cardinality; k++) { + int val = source.content[k] + offsets; + high.content[high.cardinality++] = (char) val; + } + } + return new Container[] {low, high}; + } +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/AdvanceIfNeededBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/AdvanceIfNeededBenchmark.java new file mode 100644 index 000000000..e8ea2b7e6 --- /dev/null +++ b/jmh/src/jmh/java/org/roaringbitmap/AdvanceIfNeededBenchmark.java @@ -0,0 +1,65 @@ +package org.roaringbitmap; + +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import com.google.common.primitives.Ints; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 2000) +@Measurement(iterations = 10, timeUnit = TimeUnit.MILLISECONDS, time = 2000) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +public class AdvanceIfNeededBenchmark { + public static MutableRoaringBitmap c2; + public static PeekableIntIterator it; + + private static int[] takeSortedAndDistinct(Random source, int count) { + LinkedHashSet ints = new LinkedHashSet<>(count); + for (int size = 0; size < count; size++) { + int next; + do { + next = source.nextInt(1000000); + } while (!ints.add(next)); + } + // we add a range of continuous values + for (int k = 1000; k < 10000; ++k) { + ints.add(k); + } + int[] unboxed = Ints.toArray(ints); + Arrays.sort(unboxed); + return unboxed; + } + + static { + final Random source = new Random(0xcb000a2b9b5bdfb6L); + final int[] data = takeSortedAndDistinct(source, 450000); + c2 = MutableRoaringBitmap.bitmapOf(data); + } + + @Setup(Level.Iteration) + public void setup() { + it = c2.getIntIterator(); + c2.first(); + } + + @Benchmark + public MutableRoaringBitmap advanceIfNeeded() { + it.advanceIfNeeded((char) (59 + 15 * 64)); + return c2; + } +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/BasicBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/BasicBenchmark.java index 0d7721efb..de89a85a3 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/BasicBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/BasicBenchmark.java @@ -1,5 +1,17 @@ package org.roaringbitmap; +import org.roaringbitmap.buffer.BufferFastAggregation; +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import com.zaxxer.sparsebits.SparseBitSet; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -12,18 +24,6 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.buffer.BufferFastAggregation; -import org.roaringbitmap.buffer.ImmutableRoaringBitmap; -import org.roaringbitmap.buffer.MutableRoaringBitmap; - -import com.zaxxer.sparsebits.SparseBitSet; - /** * Created by Borislav Ivanov on 4/2/15. */ @@ -232,11 +232,8 @@ public StandardState() { for (int k = 1; k < N; k += 10) { ors_standard.add(Arrays.copyOf(ewah_standard, k + 1)); - } - } - } @State(Scope.Benchmark) @@ -256,7 +253,6 @@ public MutableState() { ewah_mutable[k].add(x * (N - k + 2)); } ewah_mutable[k].trim(); - } ors_mutable = new ArrayList(); @@ -264,9 +260,7 @@ public MutableState() { for (int k = 1; k < N; k += 10) { ors_mutable.add(Arrays.copyOf(ewah_mutable, k + 1)); } - } - } @State(Scope.Benchmark) @@ -285,7 +279,6 @@ public ImmutableState() { /** * Mutable & Immutable */ - for (int k = 0; k < N; ++k) { ewah_mutable[k] = new MutableRoaringBitmap(); for (int x = 0; x < M; ++x) { @@ -302,9 +295,7 @@ public ImmutableState() { ors_immutable = new ArrayList(); for (int k = 1; k < N; k += 10) { ors_immutable.add(Arrays.copyOf(ewah_immutable, k + 1)); - } - } private ImmutableRoaringBitmap convertToMappedBitmap(MutableRoaringBitmap orig) @@ -321,6 +312,5 @@ private ImmutableRoaringBitmap convertToMappedBitmap(MutableRoaringBitmap orig) memoryMappedFile.close(); return new ImmutableRoaringBitmap(bb); } - } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/BitSetUtilBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/BitSetUtilBenchmark.java index 3c0950eeb..e6be1e255 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/BitSetUtilBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/BitSetUtilBenchmark.java @@ -1,6 +1,12 @@ package org.roaringbitmap; -import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; import java.io.DataInputStream; import java.io.IOException; @@ -22,7 +28,6 @@ public long BitSetToRoaringByAddingBitByBit(Data d) { return bogus; } - @Benchmark public long BitSetToRoaringUsingBitSetUtil(Data d) { long bogus = 0; @@ -32,16 +37,16 @@ public long BitSetToRoaringUsingBitSetUtil(Data d) { return bogus; } - private static final ThreadLocal WORD_BLOCK = ThreadLocal.withInitial(() -> - new long[BitSetUtil.BLOCK_LENGTH]); + private static final ThreadLocal WORD_BLOCK = + ThreadLocal.withInitial(() -> new long[BitSetUtil.BLOCK_LENGTH]); /* - Given an uncompressed bitset represented as a byte array (basically, as read on wire) - Below benchmarks the perf difference you will get when: - 1. ByteArrayToRoaring - Directly convert the byte array to a roaring bitmap by wrapping it in a ByteBuffer - 2. ByteArrayToBitsetToRoaring - Convert the byte array to a BitSet and then create the bitmap using it - 3. ByteArrayToRoaringWithCachedBuffer - Directly convert and use a cached reused buffer - */ + Given an uncompressed bitset represented as a byte array (basically, as read on wire) + Below benchmarks the perf difference you will get when: + 1. ByteArrayToRoaring - Directly convert the byte array to a roaring bitmap by wrapping it in a ByteBuffer + 2. ByteArrayToBitsetToRoaring - Convert the byte array to a BitSet and then create the bitmap using it + 3. ByteArrayToRoaringWithCachedBuffer - Directly convert and use a cached reused buffer + */ @Benchmark public long ByteArrayToRoaring(Data d) { @@ -63,7 +68,6 @@ public long ByteArrayToRoaringWithCachedBuffer(Data d) { return bogus; } - @Benchmark public long ByteArrayToBitsetToRoaring(Data d) { long bogus = 0; @@ -86,14 +90,12 @@ private static RoaringBitmap bitmapTheNaiveWay(final long[] words) { long word = 0; int index = 0; for (int i = 0, socket = 0; i < words.length && index < cardinality; i++, socket += Long.SIZE) { - if (words[i] == 0) - continue; + if (words[i] == 0) continue; // for each bit, unless updated word has become 0 (no more bits left) or we already have // reached cardinality word = words[i]; - for (int bitIndex = 0; word != 0 && bitIndex < Long.SIZE; word >>= - 1, bitIndex++) { + for (int bitIndex = 0; word != 0 && bitIndex < Long.SIZE; word >>= 1, bitIndex++) { if ((word & 1l) != 0) { bitmap.add(socket + bitIndex); } @@ -125,18 +127,20 @@ private byte[][] bitsetsAsBytes(long[][] bitsets) { } private long[][] deserialize(final String bitsetResource) throws IOException { - final DataInputStream dos = new DataInputStream( - new GZIPInputStream(this.getClass().getResourceAsStream(bitsetResource))); + final DataInputStream dos = + new DataInputStream( + new GZIPInputStream(this.getClass().getResourceAsStream(bitsetResource))); try { /* Change this value to see number for small vs large bitsets - wordSize = 64 represents 4096 bits (512 bytes) - wordSize = 512 represents 32768 bits (~4kb) - wordSize = 8192 represents 524288 bits (~64kb) - wordSize = 131072 represents 8388608 bits (~8.3 million, ~1mb) - */ + wordSize = 64 represents 4096 bits (512 bytes) + wordSize = 512 represents 32768 bits (~4kb) + wordSize = 8192 represents 524288 bits (~64kb) + wordSize = 131072 represents 8388608 bits (~8.3 million, ~1mb) + */ final int minTotalWordSize = 512; // Try to keep size of bitsets created below 1 gb - final int bitsetCnt = Math.min((1024 * 1024 * 1024) / (minTotalWordSize * 8), dos.readInt()); + final int bitsetCnt = + Math.min((1024 * 1024 * 1024) / (minTotalWordSize * 8), dos.readInt()); final long[][] bitset = new long[bitsetCnt][]; for (int i = 0; i < bitsetCnt; i++) { @@ -150,8 +154,8 @@ private long[][] deserialize(final String bitsetResource) throws IOException { } // duplicate long[] n times to the right - for(int j = 0; j < clone; j++) { - System.arraycopy(words, 0, words, (j+1)*wordSize, wordSize); + for (int j = 0; j < clone; j++) { + System.arraycopy(words, 0, words, (j + 1) * wordSize, wordSize); } bitset[i] = words; } @@ -161,5 +165,4 @@ private long[][] deserialize(final String bitsetResource) throws IOException { } } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/BitmapOfRangeBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/BitmapOfRangeBenchmark.java new file mode 100644 index 000000000..97fed49ea --- /dev/null +++ b/jmh/src/jmh/java/org/roaringbitmap/BitmapOfRangeBenchmark.java @@ -0,0 +1,49 @@ +package org.roaringbitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 3, timeUnit = TimeUnit.MILLISECONDS, time = 1000) +@Measurement(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 1000) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +public class BitmapOfRangeBenchmark { + @Param({ + "0", // from the beginning + "100000" // from some offset + }) + int from; + + @Param({ + "10", + "100000", // ~ 100 kBi + "10000000", // ~ 10 MBi + }) + int length; + + @Benchmark + public RoaringBitmap original() { + return bitmapOfRangeOriginal(from, from + length); + } + + @Benchmark + public RoaringBitmap optimized() { + return RoaringBitmap.bitmapOfRange(from, from + length); + } + + public static RoaringBitmap bitmapOfRangeOriginal(long min, long max) { + RoaringBitmap bitmap = new RoaringBitmap(); + bitmap.add(min, max); + return bitmap; + } +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/CheckedAddBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/CheckedAddBenchmark.java new file mode 100644 index 000000000..ddd941f06 --- /dev/null +++ b/jmh/src/jmh/java/org/roaringbitmap/CheckedAddBenchmark.java @@ -0,0 +1,140 @@ +package org.roaringbitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 3, timeUnit = TimeUnit.MILLISECONDS, time = 2000) +@Measurement(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 2000) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +public class CheckedAddBenchmark { + + private static final int valuesCount = 10_000_000; + + @Param({"HALF_DUPLICATED", "UNIQUE"}) + public InputDataType inputData; + + @Param({"RUN", "BITMAP"}) + public ContainerType containerType; + + public RoaringBitmap bitmap; + + public int[] a; + + public enum InputDataType { + @SuppressWarnings("unused") + HALF_DUPLICATED { + @Override + public int getValue(int i) { + // leads to pairs of same value, resulting bitmap has half size, it does not affect + // benchmark results + return i >> 2; + } + }, + @SuppressWarnings("unused") + UNIQUE { + @Override + public int getValue(int i) { + return i; + } + }; + + protected abstract int getValue(int i); + + public int[] getValues() { + int[] a = new int[valuesCount]; + for (int i = 0; i < valuesCount; i++) { + a[i] = getValue(i); + } + return a; + } + } + + public enum ContainerType { + @SuppressWarnings("unused") + RUN { + @Override + public RoaringBitmap createBitmap(int[] values) { + RoaringBitmap bitmap = RoaringBitmap.bitmapOf(values); + bitmap.runOptimize(); + if (!(bitmap.getContainerPointer().getContainer() instanceof RunContainer)) { + throw new IllegalStateException("Container is not run!!!"); + } + return bitmap; + } + }, + @SuppressWarnings("unused") + BITMAP { + @Override + public RoaringBitmap createBitmap(int[] values) { + RoaringBitmap bitmap = RoaringBitmap.bitmapOf(values); + if (!(bitmap.getContainerPointer().getContainer() instanceof BitmapContainer)) { + throw new IllegalStateException("Container is not bitmap!!!"); + } + return bitmap; + } + }; + + public abstract RoaringBitmap createBitmap(int[] values); + } + + @Setup(Level.Invocation) + public void setUp() { + a = inputData.getValues(); + bitmap = containerType.createBitmap(a); + } + + @Benchmark + public boolean optimized() { + boolean contains = false; + for (int i = 0; i < valuesCount; i++) { + contains ^= bitmap.checkedAdd(a[i]); + } + return contains; + } + + @Benchmark + public boolean original() { + boolean contains = false; + for (int i = 0; i < valuesCount; i++) { + contains ^= checkedAddOriginal(a[i]); + } + return contains; + } + + public boolean checkedAddOriginal(final int x) { + final char hb = Util.highbits(x); + final int i = bitmap.highLowContainer.getIndex(hb); + if (i >= 0) { + Container c = bitmap.highLowContainer.getContainerAtIndex(i); + int oldCard = c.getCardinality(); + // we need to keep the newContainer if a switch between containers type + // occur, in order to get the new cardinality + Container newCont = c.add(Util.lowbits(x)); + bitmap.highLowContainer.setContainerAtIndex(i, newCont); + + //noinspection RedundantIfStatement + if (newCont.getCardinality() > oldCard) { + return true; + } + } else { + @SuppressWarnings("SpellCheckingInspection") + final ArrayContainer newac = new ArrayContainer(); + bitmap.highLowContainer.insertNewKeyValueAt(-i - 1, hb, newac.add(Util.lowbits(x))); + return true; + } + return false; + } +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/IntermediateByteArrayBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/IntermediateByteArrayBenchmark.java index 89c871020..6e74be7e3 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/IntermediateByteArrayBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/IntermediateByteArrayBenchmark.java @@ -1,8 +1,16 @@ package org.roaringbitmap; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.longlong.LongUtils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @@ -12,27 +20,27 @@ @State(Scope.Benchmark) public class IntermediateByteArrayBenchmark { - public long firstV = 0xaa_b3_41_23_22_25_33_43L; // some random value + public long firstV = 0xaa_b3_41_23_22_25_33_43L; // some random value - @Benchmark - public int original() { - byte[] firtBytes = LongUtils.toBDBytes(firstV); - int unsignedIdx = 0; - for (int i = 0; i < 8; i++) { - byte v = firtBytes[i]; - unsignedIdx += Byte.toUnsignedInt(v); - // some other stuff... - } - return unsignedIdx; + @Benchmark + public int original() { + byte[] firtBytes = LongUtils.toBDBytes(firstV); + int unsignedIdx = 0; + for (int i = 0; i < 8; i++) { + byte v = firtBytes[i]; + unsignedIdx += Byte.toUnsignedInt(v); + // some other stuff... } + return unsignedIdx; + } - @Benchmark - public int optimized() { - int unsignedIdx = 0; - for (int i = 0; i < 8; i++) { - unsignedIdx += Byte.toUnsignedInt((byte) (firstV >>> ((7 - i) << 3))); - // some other stuff... - } - return unsignedIdx; + @Benchmark + public int optimized() { + int unsignedIdx = 0; + for (int i = 0; i < 8; i++) { + unsignedIdx += Byte.toUnsignedInt((byte) (firstV >>> ((7 - i) << 3))); + // some other stuff... } + return unsignedIdx; + } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/RadixSort.java b/jmh/src/jmh/java/org/roaringbitmap/RadixSort.java index 81a92f892..8a8ad670c 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/RadixSort.java +++ b/jmh/src/jmh/java/org/roaringbitmap/RadixSort.java @@ -1,6 +1,12 @@ package org.roaringbitmap; -import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; import java.util.SplittableRandom; @@ -34,18 +40,14 @@ public void setup() { } } - @TearDown(Level.Invocation) public void restore() { System.arraycopy(input, 0, data, 0, input.length); } - @Benchmark public int[] partialSort() { Util.partialRadixSort(data); return data; } - - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/RandomData.java b/jmh/src/jmh/java/org/roaringbitmap/RandomData.java index 779f416c4..6516d518d 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/RandomData.java +++ b/jmh/src/jmh/java/org/roaringbitmap/RandomData.java @@ -5,13 +5,14 @@ import java.util.stream.IntStream; public class RandomData { - + private static final SplittableRandom RANDOM = new SplittableRandom(0); private static final ThreadLocal bits = ThreadLocal.withInitial(() -> new long[1 << 10]); private static final ThreadLocal runs = ThreadLocal.withInitial(() -> new int[4096]); - public static RoaringBitmap randomContiguousBitmap(int startKey, int numKeys, double rleLimit, double denseLimit) { + public static RoaringBitmap randomContiguousBitmap( + int startKey, int numKeys, double rleLimit, double denseLimit) { int[] keys = new int[numKeys]; for (int i = 0; i < numKeys; ++i) { keys[i] = i + startKey; @@ -39,9 +40,9 @@ public static IntStream rleRegion() { ++totalRuns; } return IntStream.range(0, totalRuns) - .map(i -> i * 2) - .mapToObj(i -> IntStream.range(values[i], values[i + 1])) - .flatMapToInt(i -> i); + .map(i -> i * 2) + .mapToObj(i -> IntStream.range(values[i], values[i + 1])) + .flatMapToInt(i -> i); } public static IntStream sparseRegion() { @@ -77,9 +78,11 @@ private static int[] createSorted16BitInts(int howMany) { } private static RoaringBitmap forKeys(int[] keys, double rleLimit, double denseLimit) { - RoaringBitmapWriter writer = RoaringBitmapWriter.writer().optimiseForArrays().get(); + RoaringBitmapWriter writer = + RoaringBitmapWriter.writer().optimiseForArrays().get(); IntStream.of(keys) - .forEach(key -> { + .forEach( + key -> { double choice = RANDOM.nextDouble(); final IntStream stream; if (choice < rleLimit) { diff --git a/jmh/src/jmh/java/org/roaringbitmap/RangeOperationBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/RangeOperationBenchmark.java index 06c41d60c..fe8516104 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/RangeOperationBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/RangeOperationBenchmark.java @@ -75,7 +75,6 @@ public int inotBig(BenchmarkState state) { return result.getCardinality(); } - @State(Scope.Benchmark) public static class BenchmarkState { BitmapContainer emptyBC = new BitmapContainer(); @@ -84,8 +83,7 @@ public static class BenchmarkState { public BenchmarkState() { for (int i = 100; i < 15000; i++) { - if (i % 5 != 0) - bc.add((char) i); + if (i % 5 != 0) bc.add((char) i); } } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/RoaringOnlyBenchmarkState.java b/jmh/src/jmh/java/org/roaringbitmap/RoaringOnlyBenchmarkState.java index fa04ffbcd..f7fb4d29d 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/RoaringOnlyBenchmarkState.java +++ b/jmh/src/jmh/java/org/roaringbitmap/RoaringOnlyBenchmarkState.java @@ -1,19 +1,18 @@ package org.roaringbitmap; +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; + import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; -import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.*; - @State(Scope.Benchmark) public abstract class RoaringOnlyBenchmarkState { @@ -44,24 +43,26 @@ public void setup(final String dataset) throws Exception { immutableOnlyRunContainers = new ArrayList<>(); immutableOnlyBitmapContainers = new ArrayList<>(); - List ints = DATASET_CACHE.get(dataset, new Callable>() { + List ints = + DATASET_CACHE.get( + dataset, + new Callable>() { - @Override - public List call() throws Exception { - System.out.println("Loading" + dataset); - ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); - return Lists.newArrayList(dataRetriever.fetchBitPositions()); - } - }); + @Override + public List call() throws Exception { + System.out.println("Loading" + dataset); + ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); + return Lists.newArrayList(dataRetriever.fetchBitPositions()); + } + }); for (int[] data : ints) { RoaringBitmap roaring = RoaringBitmap.bitmapOf(data); roaring.runOptimize(); bitmaps.add(roaring); immutableBitmaps.add(roaring.toMutableRoaringBitmap()); - } - //Add bitmaps with only RunContainers preserved + // Add bitmaps with only RunContainers preserved for (RoaringBitmap rb : bitmaps) { RoaringBitmap runOnly = new RoaringBitmap(); ContainerPointer cp = rb.getContainerPointer(); @@ -75,11 +76,11 @@ public List call() throws Exception { immutableOnlyRunContainers.add(runOnly.toMutableRoaringBitmap()); } - //Add bitmaps with only ArrayContainers preserved + // Add bitmaps with only ArrayContainers preserved for (RoaringBitmap rb : bitmaps) { RoaringBitmap clone = rb.clone(); RoaringBitmap arrayOnly = new RoaringBitmap(); - clone.removeRunCompression(); //more containers preserved + clone.removeRunCompression(); // more containers preserved ContainerPointer cp = clone.getContainerPointer(); while (cp.getContainer() != null) { if (!cp.isBitmapContainer()) { @@ -91,11 +92,11 @@ public List call() throws Exception { immutableOnlyArrayContainers.add(arrayOnly.toMutableRoaringBitmap()); } - //Add bitmaps with only BitmapContainers preserved + // Add bitmaps with only BitmapContainers preserved for (RoaringBitmap rb : bitmaps) { RoaringBitmap clone = rb.clone(); RoaringBitmap bitmapOnly = new RoaringBitmap(); - clone.removeRunCompression(); //more containers preserved + clone.removeRunCompression(); // more containers preserved ContainerPointer cp = clone.getContainerPointer(); while (cp.getContainer() != null) { if (cp.isBitmapContainer()) { @@ -106,12 +107,8 @@ public List call() throws Exception { onlyBitmapContainers.add(bitmapOnly); immutableOnlyBitmapContainers.add(bitmapOnly.toMutableRoaringBitmap()); } - - } @TearDown - public void tearDown() { - } - + public void tearDown() {} } diff --git a/jmh/src/jmh/java/org/roaringbitmap/SelectTopValuesBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/SelectTopValuesBenchmark.java new file mode 100644 index 000000000..9525228bc --- /dev/null +++ b/jmh/src/jmh/java/org/roaringbitmap/SelectTopValuesBenchmark.java @@ -0,0 +1,135 @@ +package org.roaringbitmap; + +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 3, timeUnit = TimeUnit.MILLISECONDS, time = 1000) +@Measurement(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 1000) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +public class SelectTopValuesBenchmark { + + @Param({"200"}) + int n; + + @Param({"10000"}) + public int count; + + public MutableRoaringBitmap bitmap; + + @Setup(Level.Iteration) + public void setup() { + bitmap = new MutableRoaringBitmap(); + for (int i = 0; i < count; i++) { + bitmap.add(i * 100); + } + } + + @Benchmark + public MutableRoaringBitmap limitIncludingAndNot() { + MutableRoaringBitmap turnoff = bitmap.limit(n); + bitmap.andNot(turnoff); + return bitmap; + } + + @Benchmark + public MutableRoaringBitmap limit() { + return bitmap.limit(n); + } + + @Benchmark + public MutableRoaringBitmap add() { + IntIterator it = bitmap.getIntIterator(); + MutableRoaringBitmap turnoff = new MutableRoaringBitmap(); + int i = n; + while (it.hasNext() && i > 0) { + turnoff.add(it.next()); + i--; + } + return bitmap; + } + + @Benchmark + public MutableRoaringBitmap addIncludingAndNot() { + IntIterator it = bitmap.getIntIterator(); + MutableRoaringBitmap turnoff = new MutableRoaringBitmap(); + int i = n; + while (it.hasNext() && i > 0) { + turnoff.add(it.next()); + i--; + } + bitmap.andNot(turnoff); + return bitmap; + } + + @Benchmark + public MutableRoaringBitmap remove() { + IntIterator it = bitmap.getIntIterator(); + int i = n; + while (it.hasNext() && i > 0) { + bitmap.remove(it.next()); + i--; + } + return bitmap; + } + + @Benchmark + public MutableRoaringBitmap batchIterator() { + BatchIterator it = bitmap.getBatchIterator(); + int[] buffer = new int[n]; + MutableRoaringBitmap turnoff = new MutableRoaringBitmap(); + it.nextBatch(buffer); + for (int i = 0; i < n; i++) { + turnoff.add(buffer[i]); + } + return turnoff; + } + + @Benchmark + public MutableRoaringBitmap batchIteratorIncludingAndNot() { + BatchIterator it = bitmap.getBatchIterator(); + int[] buffer = new int[n]; + MutableRoaringBitmap turnoff = new MutableRoaringBitmap(); + it.nextBatch(buffer); + for (int i = 0; i < n; i++) { + turnoff.add(buffer[i]); + } + bitmap.andNot(turnoff); + return bitmap; + } + + @Benchmark + public MutableRoaringBitmap batchIteratorAddAtOnce() { + BatchIterator it = bitmap.getBatchIterator(); + int[] buffer = new int[n]; + MutableRoaringBitmap turnoff = new MutableRoaringBitmap(); + it.nextBatch(buffer); + turnoff.add(buffer); + return turnoff; + } + + @Benchmark + public MutableRoaringBitmap batchIteratorAddAtOnceIncludingAndNot() { + BatchIterator it = bitmap.getBatchIterator(); + int[] buffer = new int[n]; + MutableRoaringBitmap turnoff = new MutableRoaringBitmap(); + it.nextBatch(buffer); + turnoff.add(buffer); + bitmap.andNot(turnoff); + return bitmap; + } +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/UtilBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/UtilBenchmark.java index f06f18bbc..2b0885a2d 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/UtilBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/UtilBenchmark.java @@ -1,8 +1,6 @@ package org.roaringbitmap; -import java.util.Arrays; -import java.util.concurrent.TimeUnit; - +import me.lemire.integercompression.synth.ClusteredDataGenerator; import org.apache.commons.math3.distribution.IntegerDistribution; import org.apache.commons.math3.distribution.UniformIntegerDistribution; import org.apache.commons.math3.random.Well19937c; @@ -15,7 +13,8 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import me.lemire.integercompression.synth.ClusteredDataGenerator; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; /** * The experiment to test the threshold when it is worth to use galloping strategy of intersecting @@ -30,11 +29,14 @@ public class UtilBenchmark { @Param({"0"}) // use {"0", "1"} to test both uniform and clustered combinations public int smallType; // 0 - uniform, 1 - clustered + @Param({"0"}) // use {"0", "1"} to test both uniform and clustered combinations public int bigType; // 0 - uniform, 1 - clustered + @Param({"0"}) // use {"0", "1", "2"} for three experiments. Update GENERATE_EXAMPLES if changing - // this + // this public int index; + @Param({"25"}) // use {"20", "25", "30"} to check different thresholds public int param; @@ -50,20 +52,19 @@ public void setup() { public void galloping() { BenchmarkContainer small = data.small[index]; BenchmarkContainer big = data.big[index]; - Util.unsignedOneSidedGallopingIntersect2by2(small.content, small.length, big.content, - big.length, data.dest); + Util.unsignedOneSidedGallopingIntersect2by2( + small.content, small.length, big.content, big.length, data.dest); } @Benchmark public void local() { BenchmarkContainer small = data.small[index]; BenchmarkContainer big = data.big[index]; - Util.unsignedLocalIntersect2by2(small.content, small.length, big.content, big.length, - data.dest); + Util.unsignedLocalIntersect2by2( + small.content, small.length, big.content, big.length, data.dest); } } - class BenchmarkData { BenchmarkData(BenchmarkContainer[] small, BenchmarkContainer[] big) { this.small = small; @@ -76,7 +77,6 @@ class BenchmarkData { final char[] dest; } - class BenchmarkContainer { BenchmarkContainer(char[] content) { this.content = content; @@ -87,17 +87,18 @@ class BenchmarkContainer { final int length; } - /** * Deterministic generator for benchmark data. For given *param* it generates *howmany* entries */ class BenchmarkDataGenerator { static BenchmarkData generate(int param, int howMany, int smallType, int bigType) { - IntegerDistribution ud = new UniformIntegerDistribution(new Well19937c(param + 17), - Short.MIN_VALUE, Short.MAX_VALUE); + IntegerDistribution ud = + new UniformIntegerDistribution( + new Well19937c(param + 17), Short.MIN_VALUE, Short.MAX_VALUE); ClusteredDataGenerator cd = new ClusteredDataGenerator(); - IntegerDistribution p = new UniformIntegerDistribution(new Well19937c(param + 123), - SMALLEST_ARRAY, BIGGEST_ARRAY / param); + IntegerDistribution p = + new UniformIntegerDistribution( + new Well19937c(param + 123), SMALLEST_ARRAY, BIGGEST_ARRAY / param); BenchmarkContainer[] smalls = new BenchmarkContainer[howMany]; BenchmarkContainer[] bigs = new BenchmarkContainer[howMany]; for (int i = 0; i < howMany; i++) { @@ -138,8 +139,6 @@ private static char[] generateUniform(IntegerDistribution ud, int howMany) { return intArrayToShortArraySorted(ud.sample(howMany)); } - private final static int SMALLEST_ARRAY = 2; - private final static int BIGGEST_ARRAY = 4096; + private static final int SMALLEST_ARRAY = 2; + private static final int BIGGEST_ARRAY = 4096; } - - diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/FastAggregationRLEStressTest.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/FastAggregationRLEStressTest.java index 8d8de2fc5..ea5f59cd5 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/FastAggregationRLEStressTest.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/FastAggregationRLEStressTest.java @@ -1,12 +1,18 @@ package org.roaringbitmap.aggregation; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.FastAggregation; import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.RoaringBitmapWriter; import org.roaringbitmap.buffer.BufferFastAggregation; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.Arrays; import java.util.SplittableRandom; @@ -20,19 +26,16 @@ public enum ConstructionStrategy { CONSTANT_MEMORY { @Override public RoaringBitmapWriter create() { - return RoaringBitmapWriter.writer() - .constantMemory() - .get(); + return RoaringBitmapWriter.writer().constantMemory().get(); } }, CONTAINER_APPENDER { @Override public RoaringBitmapWriter create() { - return RoaringBitmapWriter.writer() - .get(); + return RoaringBitmapWriter.writer().get(); } - } - ; + }; + public abstract RoaringBitmapWriter create(); } @@ -48,8 +51,7 @@ public RoaringBitmapWriter create() { @Param({"0.01", "0.1", "0.5"}) double probability; - @Param - ConstructionStrategy constructionStrategy; + @Param ConstructionStrategy constructionStrategy; @Param("99999") long seed; @@ -64,12 +66,12 @@ public void createBitmaps() { RoaringBitmapWriter bitmapWriter = constructionStrategy.create(); bitmaps = new RoaringBitmap[count]; bufferBitmaps = new ImmutableRoaringBitmap[count]; - double p = Math.pow(probability, 1D/count); + double p = Math.pow(probability, 1D / count); for (int i = 0; i < count; ++i) { - for (int j = (int)(Math.log(random.nextDouble())/Math.log(1-p)); - j < size; - j += (int)(Math.log(random.nextDouble())/Math.log(1-p)) + 1) { - bitmapWriter.add(j); + for (int j = (int) (Math.log(random.nextDouble()) / Math.log(1 - p)); + j < size; + j += (int) (Math.log(random.nextDouble()) / Math.log(1 - p)) + 1) { + bitmapWriter.add(j); } bitmaps[i] = bitmapWriter.get(); bufferBitmaps[i] = bitmaps[i].toMutableRoaringBitmap(); @@ -78,7 +80,6 @@ public void createBitmaps() { } } - @Benchmark public RoaringBitmap and(BitmapState state) { return FastAggregation.and(state.buffer, state.bitmaps); @@ -91,13 +92,13 @@ public ImmutableRoaringBitmap andBuffer(BitmapState state) { @Benchmark public RoaringBitmap andMemoryShy(BitmapState state) { - Arrays.fill(state.buffer,0); + Arrays.fill(state.buffer, 0); return FastAggregation.workAndMemoryShyAnd(state.buffer, state.bitmaps); } @Benchmark public ImmutableRoaringBitmap andBufferMemoryShy(BitmapState state) { - Arrays.fill(state.buffer,0); + Arrays.fill(state.buffer, 0); return BufferFastAggregation.workAndMemoryShyAnd(state.buffer, state.bufferBitmaps); } @@ -111,7 +112,6 @@ public int andCardinalityMaterialize(BitmapState state) { return FastAggregation.and(state.bitmaps).getCardinality(); } - @Benchmark public int andCardinalityBuffer(BitmapState state) { return BufferFastAggregation.andCardinality(state.bufferBitmaps); @@ -132,7 +132,6 @@ public int orCardinalityMaterialize(BitmapState state) { return FastAggregation.or(state.bitmaps).getCardinality(); } - @Benchmark public int orCardinalityBuffer(BitmapState state) { return BufferFastAggregation.orCardinality(state.bufferBitmaps); @@ -142,5 +141,4 @@ public int orCardinalityBuffer(BitmapState state) { public int orCardinalityBufferMaterialize(BitmapState state) { return BufferFastAggregation.or(state.bufferBitmaps).getCardinality(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/BitmapContainerAndBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/BitmapContainerAndBenchmark.java index e94253f95..0efc0bcfc 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/BitmapContainerAndBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/BitmapContainerAndBenchmark.java @@ -1,17 +1,23 @@ package org.roaringbitmap.aggregation.and; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.BitmapContainer; import org.roaringbitmap.Container; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.SplittableRandom; -import java.util.concurrent.ThreadLocalRandom; @State(Scope.Benchmark) public class BitmapContainerAndBenchmark { @Param({"0.1", "0.5"}) double thisDensity; + @Param({"0.1", "0.5"}) double thatDensity; diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/Roaring64BitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/Roaring64BitmapBenchmark.java index 11c46dc0d..eaf5add4e 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/Roaring64BitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/Roaring64BitmapBenchmark.java @@ -1,6 +1,7 @@ package org.roaringbitmap.aggregation.and.bestcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -8,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class Roaring64BitmapBenchmark { @@ -51,5 +53,4 @@ public Roaring64Bitmap inplace_and() { public Roaring64Bitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/RoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/RoaringBitmapBenchmark.java index 42ad6f415..8614f59a3 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/RoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/bestcase/RoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.aggregation.and.bestcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class RoaringBitmapBenchmark { @@ -58,5 +59,4 @@ public RoaringBitmap inplace_and() { public RoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/Roaring64BitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/Roaring64BitmapBenchmark.java index d25027f74..be83caa6f 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/Roaring64BitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/Roaring64BitmapBenchmark.java @@ -1,6 +1,7 @@ package org.roaringbitmap.aggregation.and.identical; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -8,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class Roaring64BitmapBenchmark { @@ -44,5 +46,4 @@ public Roaring64Bitmap inplace_and() { public Roaring64Bitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/RoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/RoaringBitmapBenchmark.java index 0b132aa98..a940d58fb 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/RoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/identical/RoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.aggregation.and.identical; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class RoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public RoaringBitmap inplace_and() { public RoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/Roaring64BitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/Roaring64BitmapBenchmark.java index 8cae9235b..3bf1f007f 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/Roaring64BitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/Roaring64BitmapBenchmark.java @@ -1,6 +1,7 @@ package org.roaringbitmap.aggregation.and.worstcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -8,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class Roaring64BitmapBenchmark { @@ -44,5 +46,4 @@ public Roaring64Bitmap inplace_and() { public Roaring64Bitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/RoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/RoaringBitmapBenchmark.java index 44f02c153..644297f62 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/RoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/and/worstcase/RoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.aggregation.and.worstcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class RoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public RoaringBitmap inplace_and() { public RoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/Roaring64BitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/Roaring64BitmapBenchmark.java index bd202284c..425fbffc8 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/Roaring64BitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/Roaring64BitmapBenchmark.java @@ -1,6 +1,7 @@ package org.roaringbitmap.aggregation.andnot.bestcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -8,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class Roaring64BitmapBenchmark { @@ -52,5 +54,4 @@ public Roaring64Bitmap inplace_andNot() { public Roaring64Bitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/RoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/RoaringBitmapBenchmark.java index a29c897d7..5509ae0af 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/RoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/bestcase/RoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.aggregation.andnot.bestcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class RoaringBitmapBenchmark { @@ -58,5 +59,4 @@ public RoaringBitmap inplace_andNot() { public RoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/Roaring64BitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/Roaring64BitmapBenchmark.java index c3eac37d7..e2385f5a4 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/Roaring64BitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/Roaring64BitmapBenchmark.java @@ -1,6 +1,7 @@ package org.roaringbitmap.aggregation.andnot.identical; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -8,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class Roaring64BitmapBenchmark { @@ -44,5 +46,4 @@ public Roaring64Bitmap inplace_andNot() { public Roaring64Bitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/RoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/RoaringBitmapBenchmark.java index 8a0bc59a7..a9b02eff6 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/RoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/identical/RoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.aggregation.andnot.identical; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class RoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public RoaringBitmap inplace_andNot() { public RoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/Roaring64BitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/Roaring64BitmapBenchmark.java index 6c32bd719..9d1d097db 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/Roaring64BitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/Roaring64BitmapBenchmark.java @@ -1,6 +1,7 @@ package org.roaringbitmap.aggregation.andnot.worstcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -8,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class Roaring64BitmapBenchmark { @@ -44,5 +46,4 @@ public Roaring64Bitmap inplace_andNot() { public Roaring64Bitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/RoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/RoaringBitmapBenchmark.java index f10f56fbd..9af145f41 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/RoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/andnot/worstcase/RoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.aggregation.andnot.worstcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class RoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public RoaringBitmap inplace_andNot() { public RoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/BitmapContainerOrBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/BitmapContainerOrBenchmark.java index c55007268..c6981b6f9 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/BitmapContainerOrBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/BitmapContainerOrBenchmark.java @@ -1,17 +1,23 @@ package org.roaringbitmap.aggregation.or; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.BitmapContainer; import org.roaringbitmap.Container; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.SplittableRandom; -import java.util.concurrent.ThreadLocalRandom; @State(Scope.Benchmark) public class BitmapContainerOrBenchmark { @Param({"0.1", "0.5"}) double thisDensity; + @Param({"0.1", "0.5"}) double thatDensity; diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/RoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/RoaringBitmapBenchmark.java index 47fc28a60..9fdf4d759 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/RoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/or/RoaringBitmapBenchmark.java @@ -1,5 +1,9 @@ package org.roaringbitmap.aggregation.or; +import org.roaringbitmap.FastAggregation; +import org.roaringbitmap.RandomData; +import org.roaringbitmap.RoaringBitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -8,9 +12,6 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.FastAggregation; -import org.roaringbitmap.RandomData; -import org.roaringbitmap.RoaringBitmap; import java.util.ArrayList; import java.util.List; @@ -19,32 +20,32 @@ @State(Scope.Benchmark) public class RoaringBitmapBenchmark { - @Param({"10", "50", "100"}) - int bitmapSize; - private List bitmaps = new ArrayList<>(); + @Param({"10", "50", "100"}) + int bitmapSize; - @Setup - public void setup() { - for (int n = 0; n < bitmapSize; n++) { - bitmaps.add(RandomData.randomBitmap(1 << 12, 1 / 3.0, 1 / 3.0)); - } - } + private List bitmaps = new ArrayList<>(); - @Benchmark - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.MICROSECONDS) - public void or() { - RoaringBitmap b1 = new RoaringBitmap(); - for (int n = 0; n < bitmapSize; n++) { - b1.or(bitmaps.get(n)); - } + @Setup + public void setup() { + for (int n = 0; n < bitmapSize; n++) { + bitmaps.add(RandomData.randomBitmap(1 << 12, 1 / 3.0, 1 / 3.0)); } - - @Benchmark - @BenchmarkMode(Mode.AverageTime) - @OutputTimeUnit(TimeUnit.MICROSECONDS) - public void lazyor() { - FastAggregation.naive_or(bitmaps.iterator()); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.MICROSECONDS) + public void or() { + RoaringBitmap b1 = new RoaringBitmap(); + for (int n = 0; n < bitmapSize; n++) { + b1.or(bitmaps.get(n)); } - + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.MICROSECONDS) + public void lazyor() { + FastAggregation.naive_or(bitmaps.iterator()); + } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/aggregation/xor/BitmapContainerXorBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/aggregation/xor/BitmapContainerXorBenchmark.java index 42d03378a..257cab65c 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/aggregation/xor/BitmapContainerXorBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/aggregation/xor/BitmapContainerXorBenchmark.java @@ -1,9 +1,15 @@ package org.roaringbitmap.aggregation.xor; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.BitmapContainer; import org.roaringbitmap.Container; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.concurrent.ThreadLocalRandom; @State(Scope.Benchmark) @@ -11,6 +17,7 @@ public class BitmapContainerXorBenchmark { @Param({"0.1", "0.5"}) double thisDensity; + @Param({"0.1", "0.5"}) double thatDensity; diff --git a/jmh/src/jmh/java/org/roaringbitmap/arraycontainer/AddBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/arraycontainer/AddBenchmark.java index bb160621e..475851998 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/arraycontainer/AddBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/arraycontainer/AddBenchmark.java @@ -1,9 +1,12 @@ package org.roaringbitmap.arraycontainer; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.ZipRealDataRangeRetriever; +import org.roaringbitmap.buffer.MappeableArrayContainer; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.collect.Lists; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -11,12 +14,11 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.ZipRealDataRangeRetriever; -import org.roaringbitmap.buffer.MappeableArrayContainer; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.collect.Lists; + +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class AddBenchmark { @@ -32,17 +34,20 @@ public void setup() throws ExecutionException { ac1 = new ArrayContainer(); mac1 = new MappeableArrayContainer(); DATASET_CACHE = CacheBuilder.newBuilder().maximumSize(1).build(); - ints = DATASET_CACHE.get(dataset, new Callable>() { + ints = + DATASET_CACHE.get( + dataset, + new Callable>() { - @Override - public List call() throws Exception { - System.out.println("Loading" + dataset); - ZipRealDataRangeRetriever dataRetriever = - new ZipRealDataRangeRetriever<>(dataset, "/random-generated-data/"); + @Override + public List call() throws Exception { + System.out.println("Loading" + dataset); + ZipRealDataRangeRetriever dataRetriever = + new ZipRealDataRangeRetriever<>(dataset, "/random-generated-data/"); - return Lists.newArrayList(dataRetriever.fetchNextRange()); - } - }); + return Lists.newArrayList(dataRetriever.fetchNextRange()); + } + }); } @Benchmark diff --git a/jmh/src/jmh/java/org/roaringbitmap/bithacking/SelectBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/bithacking/SelectBenchmark.java index 26f656395..613795f35 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/bithacking/SelectBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/bithacking/SelectBenchmark.java @@ -1,8 +1,5 @@ package org.roaringbitmap.bithacking; -import java.util.Random; -import java.util.concurrent.TimeUnit; - import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -11,6 +8,9 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; +import java.util.Random; +import java.util.concurrent.TimeUnit; + @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class SelectBenchmark { @@ -24,47 +24,45 @@ public void setup() { bitmap = new long[N]; key = new int[N]; for (int k = 0; k < bitmap.length; ++k) { - while (bitmap[k] == 0) - bitmap[k] = r.nextInt(); + while (bitmap[k] == 0) bitmap[k] = r.nextInt(); } - for (int k = 0; k < key.length; ++k) - key[k] = r.nextInt() % (Long.bitCount(bitmap[k])); + for (int k = 0; k < key.length; ++k) key[k] = r.nextInt() % (Long.bitCount(bitmap[k])); for (int k = 0; k < 64; ++k) { - if (select(0xFFFFFFFFFFFFFFFFL, k) != k) - throw new RuntimeException("bug " + k); + if (select(0xFFFFFFFFFFFFFFFFL, k) != k) throw new RuntimeException("bug " + k); } for (int k = 0; k < 64; ++k) { - if (selectBitPosition(0xFFFFFFFFFFFFFFFFL, k) != k) - throw new RuntimeException("bug " + k); + if (selectBitPosition(0xFFFFFFFFFFFFFFFFL, k) != k) throw new RuntimeException("bug " + k); } for (int k = 0; k < bitmap.length; ++k) if (selectBitPosition(bitmap[k], key[k]) != select(bitmap[k], key[k])) - throw new RuntimeException("bug " + bitmap[k] + " " + key[k] + " : " - + selectBitPosition(bitmap[k], key[k]) + " : " + select(bitmap[k], key[k])); + throw new RuntimeException( + "bug " + + bitmap[k] + + " " + + key[k] + + " : " + + selectBitPosition(bitmap[k], key[k]) + + " : " + + select(bitmap[k], key[k])); } @Benchmark @BenchmarkMode(Mode.AverageTime) public int onefunction() { int answer = 0; - for (int k = 0; k < bitmap.length; ++k) - answer += selectBitPosition(bitmap[k], key[k]); + for (int k = 0; k < bitmap.length; ++k) answer += selectBitPosition(bitmap[k], key[k]); return answer; } - - @Benchmark @BenchmarkMode(Mode.AverageTime) public int manyfunctions() { int answer = 0; - for (int k = 0; k < bitmap.length; ++k) - answer += select(bitmap[k], key[k]); + for (int k = 0; k < bitmap.length; ++k) answer += select(bitmap[k], key[k]); return answer; } - public static int selectBitPosition(long w, int j) { int seen = 0; // Divide 64bit @@ -112,7 +110,7 @@ public static int selectBitPosition(long w, int j) { /** * Given a word w, return the position of the jth true bit. - * + * * @param w word * @param j index * @return position of jth true bit in w @@ -129,7 +127,7 @@ public static int select(long w, int j) { /** * Given a word w, return the position of the jth true bit. - * + * * @param w word * @param j index * @return position of jth true bit in w @@ -144,10 +142,9 @@ public static int select(int w, int j) { } } - /** * Given a word w, return the position of the jth true bit. - * + * * @param w word * @param j index * @return position of jth true bit in w @@ -156,12 +153,9 @@ public static int select(short w, int j) { int sumtotal = 0; for (int counter = 0; counter < 16; ++counter) { sumtotal += (w >> counter) & 1; - if (sumtotal > j) - return counter; + if (sumtotal > j) return counter; } throw new IllegalArgumentException( "cannot locate " + j + "th bit in " + w + " weight is " + Integer.bitCount(w)); } - - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/bithacking/UnsignedVSFlip.java b/jmh/src/jmh/java/org/roaringbitmap/bithacking/UnsignedVSFlip.java index 15ef0dfbf..4af9d68fb 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/bithacking/UnsignedVSFlip.java +++ b/jmh/src/jmh/java/org/roaringbitmap/bithacking/UnsignedVSFlip.java @@ -1,8 +1,5 @@ package org.roaringbitmap.bithacking; - -import java.util.concurrent.TimeUnit; - import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -11,13 +8,14 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; +import java.util.concurrent.TimeUnit; + @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.NANOSECONDS) public class UnsignedVSFlip { @Param({"1", "31", "65", "101", "103"}) public short key; - @Benchmark @BenchmarkMode(Mode.Throughput) public int Time() { @@ -36,7 +34,6 @@ public int flipTime() { return key ^ Short.MIN_VALUE; } - @Benchmark @BenchmarkMode(Mode.AverageTime) public int flipTimeAvg() { @@ -54,5 +51,4 @@ public short flipTimeShort() { public short flipTimeShortAvg() { return (short) (key ^ Short.MIN_VALUE); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/bitmapcontainer/SelectBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/bitmapcontainer/SelectBenchmark.java new file mode 100644 index 000000000..106bc91a9 --- /dev/null +++ b/jmh/src/jmh/java/org/roaringbitmap/bitmapcontainer/SelectBenchmark.java @@ -0,0 +1,88 @@ +package org.roaringbitmap.bitmapcontainer; + +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.buffer.MappeableBitmapContainer; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.Random; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 10, timeUnit = TimeUnit.MILLISECONDS, time = 1000) +@Measurement(iterations = 20, timeUnit = TimeUnit.MILLISECONDS, time = 1000) +public class SelectBenchmark { + + private BitmapContainer bc1; + private MappeableBitmapContainer mbc1; + + @Param({"100", "5000", "10000"}) + public int valuesCount; + + public char[] indexes; + + @Setup + public void setup() throws ExecutionException { + bc1 = new BitmapContainer(); + mbc1 = new MappeableBitmapContainer(); + indexes = new char[valuesCount]; + Random r = new Random(123); + for (int i = 0; i < valuesCount; i++) { + char value = (char) r.nextInt(Character.MAX_VALUE); + bc1.add(value); + mbc1.add(value); + } + int actualCardinality = bc1.getCardinality(); // some values can be inserted multiple times + for (int i = 0; i < actualCardinality; i++) { + indexes[i] = (char) r.nextInt(actualCardinality); + } + } + + @Benchmark + public long bitmapContainer_selectOneSide() { + long accumulator = 0; + for (int i = 0; i < bc1.getCardinality(); i++) { + accumulator += bc1.selectOneSide(indexes[i]); + } + return accumulator; + } + + @Benchmark + public long bitmapContainer_selectBothSides() { + long accumulator = 0; + for (int i = 0; i < bc1.getCardinality(); i++) { + accumulator += bc1.select(indexes[i]); + } + return accumulator; + } + + @Benchmark + public long mappeableBitmapContainer_selectOneSide() { + long accumulator = 0; + for (int i = 0; i < mbc1.getCardinality(); i++) { + accumulator += mbc1.selectOneSide(indexes[i]); + } + return accumulator; + } + + @Benchmark + public long mappeableBitmapContainer_selectBothSides() { + long accumulator = 0; + for (int i = 0; i < mbc1.getCardinality(); i++) { + accumulator += mbc1.select(indexes[i]); + } + return accumulator; + } +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/buffer/BufferUtilBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/buffer/BufferUtilBenchmark.java index 625e8e51a..227f845c2 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/buffer/BufferUtilBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/buffer/BufferUtilBenchmark.java @@ -1,9 +1,6 @@ package org.roaringbitmap.buffer; -import java.nio.CharBuffer; -import java.util.Arrays; -import java.util.concurrent.TimeUnit; - +import me.lemire.integercompression.synth.ClusteredDataGenerator; import org.apache.commons.math3.distribution.IntegerDistribution; import org.apache.commons.math3.distribution.UniformIntegerDistribution; import org.apache.commons.math3.random.Well19937c; @@ -16,7 +13,9 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import me.lemire.integercompression.synth.ClusteredDataGenerator; +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; /** * The experiment to test the threshold when it is worth to use galloping strategy of intersecting @@ -31,11 +30,14 @@ public class BufferUtilBenchmark { @Param({"0"}) // use {"0", "1"} to test both uniform and clustered combinations public int smallType; // 0 - uniform, 1 - clustered + @Param({"0"}) // use {"0", "1"} to test both uniform and clustered combinations public int bigType; // 0 - uniform, 1 - clustered + @Param({"0"}) // use {"0", "1", "2"} for three experiments. Update GENERATE_EXAMPLES if changing - // this + // this public int index; + @Param({"35"}) // use {"20", "25", "30"} to check different thresholds public int param; @@ -51,20 +53,19 @@ public void setup() { public void galloping() { BenchmarkContainer small = data.small[index]; BenchmarkContainer big = data.big[index]; - BufferUtil.unsignedOneSidedGallopingIntersect2by2(small.content, small.length, big.content, - big.length, data.dest); + BufferUtil.unsignedOneSidedGallopingIntersect2by2( + small.content, small.length, big.content, big.length, data.dest); } @Benchmark public void local() { BenchmarkContainer small = data.small[index]; BenchmarkContainer big = data.big[index]; - BufferUtil.unsignedLocalIntersect2by2(small.content, small.length, big.content, big.length, - data.dest); + BufferUtil.unsignedLocalIntersect2by2( + small.content, small.length, big.content, big.length, data.dest); } } - class BenchmarkData { BenchmarkData(BenchmarkContainer[] small, BenchmarkContainer[] big) { this.small = small; @@ -77,7 +78,6 @@ class BenchmarkData { final char[] dest; } - class BenchmarkContainer { BenchmarkContainer(char[] content) { this.content = CharBuffer.wrap(content); @@ -88,17 +88,18 @@ class BenchmarkContainer { final int length; } - /** * Deterministic generator for benchmark data. For given *param* it generates *howmany* entries */ class BenchmarkDataGenerator { static BenchmarkData generate(int param, int howMany, int smallType, int bigType) { - IntegerDistribution ud = new UniformIntegerDistribution(new Well19937c(param + 17), - Short.MIN_VALUE, Short.MAX_VALUE); + IntegerDistribution ud = + new UniformIntegerDistribution( + new Well19937c(param + 17), Short.MIN_VALUE, Short.MAX_VALUE); ClusteredDataGenerator cd = new ClusteredDataGenerator(); - IntegerDistribution p = new UniformIntegerDistribution(new Well19937c(param + 123), - SMALLEST_ARRAY, BIGGEST_ARRAY / param); + IntegerDistribution p = + new UniformIntegerDistribution( + new Well19937c(param + 123), SMALLEST_ARRAY, BIGGEST_ARRAY / param); BenchmarkContainer[] smalls = new BenchmarkContainer[howMany]; BenchmarkContainer[] bigs = new BenchmarkContainer[howMany]; for (int i = 0; i < howMany; i++) { @@ -139,8 +140,6 @@ private static char[] generateUniform(IntegerDistribution ud, int howMany) { return intArrayToShortArraySorted(ud.sample(howMany)); } - private final static int SMALLEST_ARRAY = 2; - private final static int BIGGEST_ARRAY = 4096; + private static final int SMALLEST_ARRAY = 2; + private static final int BIGGEST_ARRAY = 4096; } - - diff --git a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/bestcase/MutableRoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/bestcase/MutableRoaringBitmapBenchmark.java index af7a6ec76..f846ed403 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/bestcase/MutableRoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/bestcase/MutableRoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.buffer.aggregation.and.bestcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class MutableRoaringBitmapBenchmark { @@ -58,5 +59,4 @@ public MutableRoaringBitmap inplace_and() { public MutableRoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/identical/MutableRoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/identical/MutableRoaringBitmapBenchmark.java index 95bd10213..ba2f9dd65 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/identical/MutableRoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/identical/MutableRoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.buffer.aggregation.and.identical; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class MutableRoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public MutableRoaringBitmap inplace_and() { public MutableRoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/worstcase/MutableRoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/worstcase/MutableRoaringBitmapBenchmark.java index 1edc461c1..119a65e3b 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/worstcase/MutableRoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/and/worstcase/MutableRoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.buffer.aggregation.and.worstcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class MutableRoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public MutableRoaringBitmap inplace_and() { public MutableRoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/bestcase/MutableRoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/bestcase/MutableRoaringBitmapBenchmark.java index a5c2a343d..9f81dc3fe 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/bestcase/MutableRoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/bestcase/MutableRoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.buffer.aggregation.andnot.bestcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class MutableRoaringBitmapBenchmark { @@ -58,5 +59,4 @@ public MutableRoaringBitmap inplace_andNot() { public MutableRoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/identical/MutableRoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/identical/MutableRoaringBitmapBenchmark.java index 7cc51ec0a..e5b154036 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/identical/MutableRoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/identical/MutableRoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.buffer.aggregation.andnot.identical; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class MutableRoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public MutableRoaringBitmap inplace_andNot() { public MutableRoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/worstcase/MutableRoaringBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/worstcase/MutableRoaringBitmapBenchmark.java index 6e08ed28e..dc596b68e 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/worstcase/MutableRoaringBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/buffer/aggregation/andnot/worstcase/MutableRoaringBitmapBenchmark.java @@ -1,6 +1,6 @@ package org.roaringbitmap.buffer.aggregation.andnot.worstcase; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,7 +9,8 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) public class MutableRoaringBitmapBenchmark { @@ -50,5 +51,4 @@ public MutableRoaringBitmap inplace_andNot() { public MutableRoaringBitmap justclone() { return bitmap1.clone(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Cardinality64Benchmark.java b/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Cardinality64Benchmark.java index a165b5d86..8820a1c0c 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Cardinality64Benchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Cardinality64Benchmark.java @@ -1,7 +1,7 @@ // https://github.com/RoaringBitmap/RoaringBitmap/pull/176 package org.roaringbitmap.cardinality64; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64NavigableMap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -13,7 +13,8 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import org.roaringbitmap.longlong.Roaring64NavigableMap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -100,10 +101,15 @@ public CacheCardinalitiesBenchmarkState() { public static final int MEASUREMENTS_ITERATIONS = 3; public static void main(String... args) throws Exception { - Options opts = new OptionsBuilder().include(".*Cardinality64Benchmark.*") - .warmupTime(new TimeValue(1, TimeUnit.SECONDS)).warmupIterations(3) - .measurementTime(new TimeValue(1, TimeUnit.SECONDS)).measurementIterations(3).forks(1) - .build(); + Options opts = + new OptionsBuilder() + .include(".*Cardinality64Benchmark.*") + .warmupTime(new TimeValue(1, TimeUnit.SECONDS)) + .warmupIterations(3) + .measurementTime(new TimeValue(1, TimeUnit.SECONDS)) + .measurementIterations(3) + .forks(1) + .build(); new Runner(opts).run(); } diff --git a/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Roaring64BmpCardinalityBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Roaring64BmpCardinalityBenchmark.java index dcc04ea71..b974d91a8 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Roaring64BmpCardinalityBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/cardinality64/Roaring64BmpCardinalityBenchmark.java @@ -1,6 +1,7 @@ package org.roaringbitmap.cardinality64; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -11,7 +12,8 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -42,10 +44,15 @@ public CacheCardinalitiesBenchmarkState() { } public static void main(String... args) throws Exception { - Options opts = new OptionsBuilder().include(".*Roaring64BmpCardinalityBenchmark.*") - .warmupTime(new TimeValue(1, TimeUnit.SECONDS)).warmupIterations(3) - .measurementTime(new TimeValue(1, TimeUnit.SECONDS)).measurementIterations(3).forks(1) - .build(); + Options opts = + new OptionsBuilder() + .include(".*Roaring64BmpCardinalityBenchmark.*") + .warmupTime(new TimeValue(1, TimeUnit.SECONDS)) + .warmupIterations(3) + .measurementTime(new TimeValue(1, TimeUnit.SECONDS)) + .measurementIterations(3) + .forks(1) + .build(); new Runner(opts).run(); } diff --git a/jmh/src/jmh/java/org/roaringbitmap/combinedcardinality/CombinedCardinalityBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/combinedcardinality/CombinedCardinalityBenchmark.java index 51fce4e22..f5f31a70e 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/combinedcardinality/CombinedCardinalityBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/combinedcardinality/CombinedCardinalityBenchmark.java @@ -1,102 +1,113 @@ package org.roaringbitmap.combinedcardinality; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.RandomData; import org.roaringbitmap.RoaringBitmap; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.concurrent.TimeUnit; @OutputTimeUnit(TimeUnit.MICROSECONDS) @BenchmarkMode(Mode.AverageTime) -@Fork(value = 1, jvmArgsPrepend = - { - "-XX:-TieredCompilation", - "-XX:+UseParallelGC", - "-mx2G", - "-ms2G", - "-XX:+AlwaysPreTouch" - }) +@Fork( + value = 1, + jvmArgsPrepend = { + "-XX:-TieredCompilation", + "-XX:+UseParallelGC", + "-mx2G", + "-ms2G", + "-XX:+AlwaysPreTouch" + }) @State(Scope.Benchmark) public class CombinedCardinalityBenchmark { - public enum Scenario { - EQUAL { - @Override - RoaringBitmap[] bitmaps() { - RoaringBitmap bitmap = RandomData.randomBitmap(1 << 12, 0.2, 0.3); - return new RoaringBitmap[] {bitmap, bitmap.clone()}; - } - }, - SHIFTED { - @Override - RoaringBitmap[] bitmaps() { - RoaringBitmap bitmap = RandomData.randomBitmap(1 << 12, 0.2, 0.3); - return new RoaringBitmap[] {bitmap, RoaringBitmap.addOffset(bitmap, 1 << 16)}; - } - }, - SMALL_LARGE { - @Override - RoaringBitmap[] bitmaps() { - return new RoaringBitmap[] { - RandomData.randomBitmap(1 << 4, 0.2, 0.3), - RandomData.randomBitmap(1 << 12, 0.2, 0.3) - }; - } - }, - LARGE_SMALL { - @Override - RoaringBitmap[] bitmaps() { - return new RoaringBitmap[] { - RandomData.randomBitmap(1 << 12, 0.2, 0.3), - RandomData.randomBitmap(1 << 4, 0.2, 0.3) - }; - } - } - ; - abstract RoaringBitmap[] bitmaps(); - } + public enum Scenario { + EQUAL { + @Override + RoaringBitmap[] bitmaps() { + RoaringBitmap bitmap = RandomData.randomBitmap(1 << 12, 0.2, 0.3); + return new RoaringBitmap[] {bitmap, bitmap.clone()}; + } + }, + SHIFTED { + @Override + RoaringBitmap[] bitmaps() { + RoaringBitmap bitmap = RandomData.randomBitmap(1 << 12, 0.2, 0.3); + return new RoaringBitmap[] {bitmap, RoaringBitmap.addOffset(bitmap, 1 << 16)}; + } + }, + SMALL_LARGE { + @Override + RoaringBitmap[] bitmaps() { + return new RoaringBitmap[] { + RandomData.randomBitmap(1 << 4, 0.2, 0.3), RandomData.randomBitmap(1 << 12, 0.2, 0.3) + }; + } + }, + LARGE_SMALL { + @Override + RoaringBitmap[] bitmaps() { + return new RoaringBitmap[] { + RandomData.randomBitmap(1 << 12, 0.2, 0.3), RandomData.randomBitmap(1 << 4, 0.2, 0.3) + }; + } + }; - @Param - Scenario scenario; + abstract RoaringBitmap[] bitmaps(); + } - RoaringBitmap left; - RoaringBitmap right; + @Param Scenario scenario; - @Setup(Level.Trial) - public void init() { - RoaringBitmap[] bitmaps = scenario.bitmaps(); - left = bitmaps[0]; - right = bitmaps[1]; - } + RoaringBitmap left; + RoaringBitmap right; + @Setup(Level.Trial) + public void init() { + RoaringBitmap[] bitmaps = scenario.bitmaps(); + left = bitmaps[0]; + right = bitmaps[1]; + } - @Benchmark - public int xorCardinality() { - return RoaringBitmap.xorCardinality(left, right); - } + @Benchmark + public int xorCardinality() { + return RoaringBitmap.xorCardinality(left, right); + } - @Benchmark - public int xorCardinalityBaseline() { - return left.getCardinality() + right.getCardinality() - 2 * RoaringBitmap.andCardinality(left, right); - } + @Benchmark + public int xorCardinalityBaseline() { + return left.getCardinality() + + right.getCardinality() + - 2 * RoaringBitmap.andCardinality(left, right); + } - @Benchmark - public int andNotCardinality() { - return RoaringBitmap.andNotCardinality(left, right); - } + @Benchmark + public int andNotCardinality() { + return RoaringBitmap.andNotCardinality(left, right); + } - @Benchmark - public int andNotCardinalityBaseline() { - return left.getCardinality() - RoaringBitmap.andCardinality(left, right); - } + @Benchmark + public int andNotCardinalityBaseline() { + return left.getCardinality() - RoaringBitmap.andCardinality(left, right); + } - @Benchmark - public int orCardinality() { - return RoaringBitmap.orCardinality(left, right); - } + @Benchmark + public int orCardinality() { + return RoaringBitmap.orCardinality(left, right); + } - @Benchmark - public int orCardinalityBaseline() { - return left.getCardinality() + right.getCardinality() - RoaringBitmap.andCardinality(left, right); - } + @Benchmark + public int orCardinalityBaseline() { + return left.getCardinality() + + right.getCardinality() + - RoaringBitmap.andCardinality(left, right); + } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/contains/ContainsBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/contains/ContainsBenchmark.java index 8b4fed0c5..1bca28e5a 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/contains/ContainsBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/contains/ContainsBenchmark.java @@ -1,29 +1,29 @@ - // https://github.com/RoaringBitmap/RoaringBitmap/pull/374 package org.roaringbitmap.contains; -import org.openjdk.jmh.annotations.*; -import org.roaringbitmap.*; - -import java.util.Arrays; - import static java.util.concurrent.TimeUnit.MICROSECONDS; import static org.openjdk.jmh.annotations.Mode.AverageTime; +import org.roaringbitmap.RandomData; +import org.roaringbitmap.RoaringBitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + @BenchmarkMode(AverageTime) @OutputTimeUnit(MICROSECONDS) public class ContainsBenchmark { - - - @Benchmark public boolean containsBitmaps(EqualBitmapsState state) { return state.left.contains(state.right); } - - @State(Scope.Benchmark) public static class EqualBitmapsState { @@ -36,7 +36,4 @@ public void init() { right = RandomData.randomBitmap(50, 0.5, 0.5); } } - - - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/deserialization/BitmapContainersDeserializationBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/deserialization/BitmapContainersDeserializationBenchmark.java new file mode 100644 index 000000000..7b702952b --- /dev/null +++ b/jmh/src/jmh/java/org/roaringbitmap/deserialization/BitmapContainersDeserializationBenchmark.java @@ -0,0 +1,62 @@ +package org.roaringbitmap.deserialization; + +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 5000) +@Measurement(iterations = 10, timeUnit = TimeUnit.MILLISECONDS, time = 5000) +@BenchmarkMode(Mode.Throughput) +public class BitmapContainersDeserializationBenchmark { + + private ByteBuffer buffer; + + @Setup + public void prepare() throws IOException { + MutableRoaringBitmap bitmap = new MutableRoaringBitmap(); + Random r = new Random(); + for (int containerIndex = 0; containerIndex < 1000; containerIndex++) { + for (int j = 0; j < 10_000; j++) { + int value = r.nextInt(65536); + bitmap.add(value + containerIndex * 65536); + } + } + byte[] x = serialise(bitmap); + buffer = ByteBuffer.allocate(x.length); + bitmap.serialize(buffer); + } + + @Benchmark + public void deserialize(Blackhole blackhole) throws IOException { + buffer.rewind(); + MutableRoaringBitmap l = new MutableRoaringBitmap(); + l.deserialize(buffer); + blackhole.consume(buffer); + } + + private static byte[] serialise(MutableRoaringBitmap input) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(input.serializedSizeInBytes()); + DataOutputStream dos = new DataOutputStream(bos)) { + input.serialize(dos); + return bos.toByteArray(); + } + } +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/equals/EqualsBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/equals/EqualsBenchmark.java index bc249831d..2f461503e 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/equals/EqualsBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/equals/EqualsBenchmark.java @@ -1,19 +1,30 @@ // https://github.com/RoaringBitmap/RoaringBitmap/issues/161 package org.roaringbitmap.equals; -import org.openjdk.jmh.annotations.*; -import org.roaringbitmap.*; - -import java.util.Arrays; - import static java.util.concurrent.TimeUnit.MICROSECONDS; import static org.openjdk.jmh.annotations.Mode.AverageTime; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.RandomData; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.RunContainer; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import java.util.Arrays; + @BenchmarkMode(AverageTime) @OutputTimeUnit(MICROSECONDS) public class EqualsBenchmark { - @Benchmark public boolean runVsArrayEquals_FewRuns(EqualsFewRunsBenchmarkState benchmarkState) { return benchmarkState.runContainer.equals(benchmarkState.arrayContainer); @@ -47,11 +58,9 @@ public EqualsFewRunsBenchmarkState() { arrayContainer = addRange(arrayContainer, 501, 1500); runContainer = addRange(runContainer, 501, 1500); - arrayContainer = addRange(arrayContainer, 3000, 4500); runContainer = addRange(runContainer, 3000, 4500); } - } @State(Scope.Benchmark) @@ -67,11 +76,11 @@ public void init() { } } - @State(Scope.Benchmark) public static class EqualArrayContainersBenchmarkState { @Param({"20", "200", "1000", "2000"}) int size; + @Param({"0.1", "0.5", "0.9", "1"}) float firstMismatch; @@ -111,10 +120,8 @@ public EqualsManyRunsBenchmarkState() { runStart += runLength + shift; } } - } - private static char[] array(int size) { if (size >= 4096) { throw new IllegalStateException(); @@ -129,5 +136,4 @@ private static char[] array(int size) { static Container addRange(Container c, int min, int sup) { return c.iadd(min, sup); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/iteration/BatchIteratorBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/iteration/BatchIteratorBenchmark.java index 189cc4a08..cda7db004 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/iteration/BatchIteratorBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/iteration/BatchIteratorBenchmark.java @@ -1,8 +1,20 @@ package org.roaringbitmap.iteration; +import org.roaringbitmap.IntIterator; +import org.roaringbitmap.PeekableIntIterator; +import org.roaringbitmap.RandomData; +import org.roaringbitmap.RoaringBatchIterator; +import org.roaringbitmap.RoaringBitmap; -import org.openjdk.jmh.annotations.*; -import org.roaringbitmap.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; import java.util.concurrent.TimeUnit; @@ -11,7 +23,6 @@ @State(Scope.Benchmark) public class BatchIteratorBenchmark { - @Param({"64", "128", "256", "512"}) int bufferSize; @@ -65,5 +76,4 @@ public int batchIterateAsIntIterator() { } return blackhole; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapIteratorBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapIteratorBenchmark.java index b765a50b8..98383c9b0 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapIteratorBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapIteratorBenchmark.java @@ -1,7 +1,5 @@ package org.roaringbitmap.iteration; - -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.BitmapContainer; import org.roaringbitmap.CharIterator; import org.roaringbitmap.Container; @@ -9,6 +7,16 @@ import org.roaringbitmap.buffer.MappeableBitmapContainer; import org.roaringbitmap.buffer.MappeableContainer; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.nio.LongBuffer; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -19,7 +27,6 @@ @Fork(jvmArgsPrepend = "-XX:-TieredCompilation") public class BitmapIteratorBenchmark { - @Param({"0.1", "0.2", "0.3", "0.4", "0.5"}) double density; @@ -30,7 +37,7 @@ public class BitmapIteratorBenchmark { public void init() { long[] bitmap = new long[1024]; int cardinality = 0; - int targetCardinality = (int)(density * 65536); + int targetCardinality = (int) (density * 65536); ThreadLocalRandom random = ThreadLocalRandom.current(); while (cardinality < targetCardinality) { int index = random.nextInt(65536); diff --git a/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapNextBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapNextBenchmark.java index 602ced8a5..9403e1189 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapNextBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/iteration/BitmapNextBenchmark.java @@ -1,10 +1,18 @@ package org.roaringbitmap.iteration; +import org.roaringbitmap.RoaringBitmap; -import org.openjdk.jmh.annotations.*; -import org.roaringbitmap.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; -import java.util.*; +import java.util.BitSet; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -14,7 +22,6 @@ @Fork(jvmArgsPrepend = "-XX:-TieredCompilation") public class BitmapNextBenchmark { - @Param({"0.1", "0.2", "0.3", "0.4", "0.5"}) double density; @@ -31,12 +38,12 @@ public void init() { long target_cardinality = Math.round(density * size); long actual_cardinality = 0; ThreadLocalRandom random = ThreadLocalRandom.current(); - while(actual_cardinality < target_cardinality) { + while (actual_cardinality < target_cardinality) { int x = random.nextInt(size); actual_cardinality += bitmap.checkedAdd(x) ? 1 : 0; bs.set(x); } - for(int k = 0; k < random_size; k++) { + for (int k = 0; k < random_size; k++) { random_array[k] = random.nextInt(size); } } @@ -44,8 +51,8 @@ public void init() { @Benchmark public long bitset_count() { long count = 0; - for(int k = 0; k < random_size; k++) { - count = count + (long)bs.nextSetBit(random_array[k]); + for (int k = 0; k < random_size; k++) { + count = count + (long) bs.nextSetBit(random_array[k]); } return count; } @@ -53,10 +60,9 @@ public long bitset_count() { @Benchmark public long roaring_count() { long count = 0; - for(int k = 0; k < random_size; k++) { - count = count + (long)bitmap.nextValue(random_array[k]); + for (int k = 0; k < random_size; k++) { + count = count + (long) bitmap.nextValue(random_array[k]); } return count; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/iteration/Concatenation.java b/jmh/src/jmh/java/org/roaringbitmap/iteration/Concatenation.java index 598689f60..b91c5d759 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/iteration/Concatenation.java +++ b/jmh/src/jmh/java/org/roaringbitmap/iteration/Concatenation.java @@ -1,54 +1,67 @@ package org.roaringbitmap.iteration; -import org.openjdk.jmh.annotations.*; -import org.roaringbitmap.*; +import static org.roaringbitmap.RoaringBitmapWriter.writer; + +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.PeekableIntIterator; +import org.roaringbitmap.RandomData; +import org.roaringbitmap.RoaringBatchIterator; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.RoaringBitmapWriter; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; import java.util.BitSet; import java.util.stream.IntStream; -import static org.roaringbitmap.RoaringBitmapWriter.writer; - @State(Scope.Benchmark) -@Fork(value = 1, jvmArgsPrepend = - { - "-XX:+UseG1GC", - "-XX:-TieredCompilation", - "-XX:+AlwaysPreTouch", - "-ms4G", - "-mx4G" - }) +@Fork( + value = 1, + jvmArgsPrepend = { + "-XX:+UseG1GC", + "-XX:-TieredCompilation", + "-XX:+AlwaysPreTouch", + "-ms4G", + "-mx4G" + }) public class Concatenation { /** - * Using lots and lots of parameter sets is clever, but it takes a long - * time to run, produces results that are difficult to interpret. - * When we want a ballpark result... a single set of parameters is more than - * enough. - * Using a long, long time to run each and every benchmark makes you less - * likely to run benchmarks which makes you less likely to work with hard - * numbers. - * - */ - + * Using lots and lots of parameter sets is clever, but it takes a long + * time to run, produces results that are difficult to interpret. + * When we want a ballpark result... a single set of parameters is more than + * enough. + * Using a long, long time to run each and every benchmark makes you less + * likely to run benchmarks which makes you less likely to work with hard + * numbers. + * + */ @Param({"16"}) int count; @Param({"8"}) int size; - @Setup(Level.Trial) public void init() { - bitSets = IntStream.range(0, count) - .mapToObj(i -> { - RoaringBitmap rb = RandomData.randomContiguousBitmap(0, size, 0.1, 0.8); - return new BitSetWithOffset(rb, toBitSet(rb), i * size * 65536); - }).toArray(BitSetWithOffset[]::new); + bitSets = + IntStream.range(0, count) + .mapToObj( + i -> { + RoaringBitmap rb = RandomData.randomContiguousBitmap(0, size, 0.1, 0.8); + return new BitSetWithOffset(rb, toBitSet(rb), i * size * 65536); + }) + .toArray(BitSetWithOffset[]::new); } private BitSetWithOffset[] bitSets; - private static class BitSetWithOffset { public final RoaringBitmap bitmap; public final BitSet bitset; @@ -64,10 +77,10 @@ public BitSetWithOffset(RoaringBitmap bitmap, BitSet bitset, int offset) { @Benchmark public BitSet bitset() { BitSet result = new BitSet(); - for(int i = 0; i < bitSets.length; ++i) { + for (int i = 0; i < bitSets.length; ++i) { BitSetWithOffset bit = bitSets[i]; int currentBit = bit.bitset.nextSetBit(0); - while(currentBit != -1) { + while (currentBit != -1) { result.set(currentBit + bit.offset); currentBit = bit.bitset.nextSetBit(currentBit + 1); } @@ -78,10 +91,10 @@ public BitSet bitset() { @Benchmark public RoaringBitmap roaringNaive() { RoaringBitmap result = new RoaringBitmap(); - for(int i = 0; i < bitSets.length; ++i) { + for (int i = 0; i < bitSets.length; ++i) { BitSetWithOffset bit = bitSets[i]; PeekableIntIterator peekableIter = bit.bitmap.getIntIterator(); - while(peekableIter.hasNext()){ + while (peekableIter.hasNext()) { int currentBit = peekableIter.next(); result.add(currentBit + bit.offset); } @@ -92,7 +105,7 @@ public RoaringBitmap roaringNaive() { @Benchmark public RoaringBitmap roaringOffset() { RoaringBitmap result = new RoaringBitmap(); - for(int i = 0; i < bitSets.length; ++i) { + for (int i = 0; i < bitSets.length; ++i) { BitSetWithOffset bit = bitSets[i]; RoaringBitmap shifted = RoaringBitmap.addOffset(bit.bitmap, bit.offset); result.or(shifted); @@ -104,15 +117,15 @@ public RoaringBitmap roaringOffset() { public RoaringBitmap roaringBatchOrderedWriter() { int[] buffer = new int[256]; RoaringBitmapWriter writer = writer().constantMemory().get(); - for(int i = 0; i < bitSets.length; ++i) { - BitSetWithOffset bit = bitSets[i]; - RoaringBatchIterator iterator = bit.bitmap.getBatchIterator(); - while (iterator.hasNext()) { - int count = iterator.nextBatch(buffer); - for (int j = 0; j < count; ++j) { - writer.add(buffer[j] + bit.offset); - } + for (int i = 0; i < bitSets.length; ++i) { + BitSetWithOffset bit = bitSets[i]; + RoaringBatchIterator iterator = bit.bitmap.getBatchIterator(); + while (iterator.hasNext()) { + int count = iterator.nextBatch(buffer); + for (int j = 0; j < count; ++j) { + writer.add(buffer[j] + bit.offset); } + } } writer.flush(); return writer.getUnderlying(); diff --git a/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark32.java b/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark32.java index e81bd9bce..3c4ccc6fa 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark32.java +++ b/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark32.java @@ -1,10 +1,9 @@ package org.roaringbitmap.iteration; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.IntIterator; +import org.roaringbitmap.IntIteratorFlyweight; +import org.roaringbitmap.ReverseIntIteratorFlyweight; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -12,7 +11,12 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.*; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Random; +import java.util.concurrent.TimeUnit; /** * Created by Borislav Ivanov on 4/2/15. @@ -27,7 +31,6 @@ public int testBoxed_a(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; } @@ -39,10 +42,8 @@ public int testStandard_a(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -55,10 +56,8 @@ public int testFlyweight_a(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -67,12 +66,10 @@ public int testBoxed_b(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; } - @Benchmark public int testStandard_b(BenchmarkState benchmarkState) { @@ -80,10 +77,8 @@ public int testStandard_b(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -96,10 +91,8 @@ public int testFlyweight_b(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -108,12 +101,10 @@ public int testBoxed_c(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; } - @Benchmark public int testStandard_c(BenchmarkState benchmarkState) { @@ -121,10 +112,8 @@ public int testStandard_c(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -137,10 +126,8 @@ public int testFlyweight_c(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -150,10 +137,8 @@ public int testReverseStandard_a(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -166,10 +151,8 @@ public int testReverseFlyweight_a(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -179,10 +162,8 @@ public int testReverseStandard_b(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -195,10 +176,8 @@ public int testReverseFlyweight_b(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -208,10 +187,8 @@ public int testReverseStandard_c(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -224,13 +201,10 @@ public int testReverseFlyweight_c(BenchmarkState benchmarkState) { int result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } - @State(Scope.Benchmark) public static class BenchmarkState { @@ -250,13 +224,10 @@ public BenchmarkState() { bitmap_a = RoaringBitmap.bitmapOf(data); bitmap_b = new RoaringBitmap(); - for (int k = 0; k < (1 << 30); k += 32) - bitmap_b.add(k); + for (int k = 0; k < (1 << 30); k += 32) bitmap_b.add(k); bitmap_c = new RoaringBitmap(); - for (int k = 0; k < (1 << 30); k += 3) - bitmap_c.add(k); - + for (int k = 0; k < (1 << 30); k += 3) bitmap_c.add(k); } private int[] takeSortedAndDistinct(Random source, int count) { @@ -284,5 +255,4 @@ private int[] toArray(LinkedHashSet integers) { return ints; } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark64.java b/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark64.java index 0c45f7d1a..bb33abac1 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark64.java +++ b/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmark64.java @@ -1,10 +1,7 @@ package org.roaringbitmap.iteration; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.LongIterator; +import org.roaringbitmap.longlong.Roaring64NavigableMap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -12,8 +9,12 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.LongIterator; -import org.roaringbitmap.longlong.Roaring64NavigableMap; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Random; +import java.util.concurrent.TimeUnit; /** * Created by Borislav Ivanov on 4/2/15. @@ -28,7 +29,6 @@ public long testBoxed_a(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; } @@ -40,10 +40,8 @@ public long testStandard_a(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -52,7 +50,6 @@ public long testBoxed_b(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; } @@ -64,10 +61,8 @@ public long testStandard_b(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -76,7 +71,6 @@ public long testBoxed_c(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; } @@ -88,10 +82,8 @@ public long testStandard_c(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -101,10 +93,8 @@ public long testReverseStandard_a(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -114,10 +104,8 @@ public long testReverseStandard_b(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @Benchmark @@ -127,10 +115,8 @@ public long testReverseStandard_c(BenchmarkState benchmarkState) { long result = 0; while (intIterator.hasNext()) { result = intIterator.next(); - } return result; - } @State(Scope.Benchmark) @@ -148,13 +134,10 @@ public BenchmarkState() { bitmap_a = Roaring64NavigableMap.bitmapOf(data); bitmap_b = new Roaring64NavigableMap(); - for (int k = 0; k < (1 << 30); k += 32) - bitmap_b.addLong(k); + for (int k = 0; k < (1 << 30); k += 32) bitmap_b.addLong(k); bitmap_c = new Roaring64NavigableMap(); - for (int k = 0; k < (1 << 30); k += 3) - bitmap_c.addLong(k); - + for (int k = 0; k < (1 << 30); k += 3) bitmap_c.addLong(k); } private long[] takeSortedAndDistinct(Random source, int count) { diff --git a/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmarkRoaring64Bmp.java b/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmarkRoaring64Bmp.java index 30f0290e0..0c33d2ae9 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmarkRoaring64Bmp.java +++ b/jmh/src/jmh/java/org/roaringbitmap/iteration/IteratorsBenchmarkRoaring64Bmp.java @@ -1,18 +1,20 @@ package org.roaringbitmap.iteration; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.longlong.LongIterator; +import org.roaringbitmap.longlong.Roaring64Bitmap; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.LongIterator; -import org.roaringbitmap.longlong.Roaring64Bitmap; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode({Mode.SampleTime, Mode.Throughput, Mode.AverageTime}) @OutputTimeUnit(TimeUnit.MILLISECONDS) @@ -24,7 +26,6 @@ public long testBoxed_a(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; } @@ -36,10 +37,8 @@ public long testStandard_a(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; - } @Benchmark @@ -48,7 +47,6 @@ public long testBoxed_b(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; } @@ -60,10 +58,8 @@ public long testStandard_b(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; - } @Benchmark @@ -72,7 +68,6 @@ public long testBoxed_c(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; } @@ -84,10 +79,8 @@ public long testStandard_c(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; - } @Benchmark @@ -97,7 +90,6 @@ public long testReverseStandard_a(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; } @@ -109,10 +101,8 @@ public long testReverseStandard_b(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; - } @Benchmark @@ -122,10 +112,8 @@ public long testReverseStandard_c(BenchmarkState benchmarkState) { long result = 0; while (longIterator.hasNext()) { result = longIterator.next(); - } return result; - } @State(Scope.Benchmark) @@ -143,13 +131,10 @@ public BenchmarkState() { bitmap_a = Roaring64Bitmap.bitmapOf(data); bitmap_b = new Roaring64Bitmap(); - for (int k = 0; k < (1 << 30); k += 32) - bitmap_b.addLong(k); + for (int k = 0; k < (1 << 30); k += 32) bitmap_b.addLong(k); bitmap_c = new Roaring64Bitmap(); - for (int k = 0; k < (1 << 30); k += 3) - bitmap_c.addLong(k); - + for (int k = 0; k < (1 << 30); k += 3) bitmap_c.addLong(k); } private long[] takeSortedAndDistinct(Random source, int count) { diff --git a/jmh/src/jmh/java/org/roaringbitmap/longlong/ShiftLeftFromSpecifiedPositionBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/longlong/ShiftLeftFromSpecifiedPositionBenchmark.java index 0554a0948..f36fe57b2 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/longlong/ShiftLeftFromSpecifiedPositionBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/longlong/ShiftLeftFromSpecifiedPositionBenchmark.java @@ -1,6 +1,14 @@ package org.roaringbitmap.longlong; -import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; @@ -35,4 +43,4 @@ public static int shiftLeftFromSpecifiedPosition(int v, int pos, int count) { System.arraycopy(initialVal, pos + 1, initialVal, pos, count); return IntegerUtil.fromBDBytes(initialVal); } -} \ No newline at end of file +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/map/MapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/map/MapBenchmark.java index e5594aee5..8aa4d89f1 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/map/MapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/map/MapBenchmark.java @@ -1,8 +1,9 @@ // https://github.com/RoaringBitmap/RoaringBitmap/issues/160 package org.roaringbitmap.map; -import java.util.BitSet; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.BitSetUtil; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.RoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -10,10 +11,9 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.BitSetUtil; -import org.roaringbitmap.IntConsumer; -import org.roaringbitmap.RoaringBitmap; +import java.util.BitSet; +import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -27,30 +27,30 @@ public static int inttointmap(int x) { @Benchmark public RoaringBitmap testMap(BenchmarkState benchmarkState) { final RoaringBitmap answer = new RoaringBitmap(); - benchmarkState.bitmap.forEach(new IntConsumer() { - @Override - public void accept(int value) { - answer.add(inttointmap(value)); - } - }); + benchmarkState.bitmap.forEach( + new IntConsumer() { + @Override + public void accept(int value) { + answer.add(inttointmap(value)); + } + }); return answer; } - @BenchmarkMode(Mode.AverageTime) @Benchmark public RoaringBitmap testMapViaBitset(BenchmarkState benchmarkState) { final BitSet altRes = new java.util.BitSet(); - benchmarkState.bitmap.forEach(new IntConsumer() { - @Override - public void accept(int value) { - altRes.set(inttointmap(value)); - } - }); + benchmarkState.bitmap.forEach( + new IntConsumer() { + @Override + public void accept(int value) { + altRes.set(inttointmap(value)); + } + }); return BitSetUtil.bitmapOf(altRes); } - @State(Scope.Benchmark) public static class BenchmarkState { @@ -58,12 +58,9 @@ public static class BenchmarkState { public BenchmarkState() { bitmap.add(10L, 100000L); - for (long k = 100000L; k < 2 * 100000L; k += 2) - bitmap.add((int) k); - for (long k = 2 * 100000L; k < 200 * 100000L; k += 100000L) - bitmap.add((int) k); + for (long k = 100000L; k < 2 * 100000L; k += 2) bitmap.add((int) k); + for (long k = 2 * 100000L; k < 200 * 100000L; k += 100000L) bitmap.add((int) k); bitmap.runOptimize(); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/needwork/RandomAccess.java b/jmh/src/jmh/java/org/roaringbitmap/needwork/RandomAccess.java index 3f1d8b09c..589eeb879 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/needwork/RandomAccess.java +++ b/jmh/src/jmh/java/org/roaringbitmap/needwork/RandomAccess.java @@ -1,8 +1,7 @@ package org.roaringbitmap.needwork; - -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.needwork.state.NeedWorkBenchmarkState; +import org.roaringbitmap.realdata.wrapper.Bitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -12,8 +11,9 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.infra.Blackhole; -import org.roaringbitmap.needwork.state.NeedWorkBenchmarkState; -import org.roaringbitmap.realdata.wrapper.Bitmap; + +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -31,8 +31,6 @@ public void binarySearch(BenchmarkState bs, Blackhole bh) { @State(Scope.Benchmark) public static class BenchmarkState extends NeedWorkBenchmarkState { - - int[] queries = new int[1024]; public BenchmarkState() {} @@ -45,15 +43,10 @@ public void setup() throws Exception { int universe = 0; for (Bitmap bitmap : bitmaps) { int lv = bitmap.last(); - if (lv > universe) - universe = lv; + if (lv > universe) universe = lv; } Random rand = new Random(123); - for (int k = 0; k < queries.length; ++k) - queries[k] = rand.nextInt(universe + 1); - + for (int k = 0; k < queries.length; ++k) queries[k] = rand.nextInt(universe + 1); } - } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate1.java b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate1.java index 157176a37..0dc27fc07 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate1.java +++ b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate1.java @@ -1,5 +1,17 @@ package org.roaringbitmap.needwork; +import org.roaringbitmap.ZipRealDataRetriever; +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; import java.io.DataOutputStream; import java.io.File; @@ -12,18 +24,6 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Param; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ZipRealDataRetriever; -import org.roaringbitmap.buffer.ImmutableRoaringBitmap; -import org.roaringbitmap.buffer.MutableRoaringBitmap; - @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class SlowMappedORaggregate1 { @@ -34,12 +34,11 @@ public MutableRoaringBitmap RoaringWithRun(BenchmarkState benchmarkState) { return answer; } - - @State(Scope.Benchmark) public static class BenchmarkState { - @Param({// putting the data sets in alpha. order - "wikileaks-noquotes",}) + @Param({ // putting the data sets in alpha. order + "wikileaks-noquotes", + }) String dataset; public List convertToImmutableRoaring(List source) @@ -49,8 +48,7 @@ public List convertToImmutableRoaring(List convertToImmutableRoaring(List convertToImmutableRoaring(List rc; public BenchmarkState() {} @@ -91,6 +87,5 @@ public void setup() throws Exception { } rc = convertToImmutableRoaring(tmprc); } - } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate2.java b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate2.java index 65162b873..7e87e3640 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate2.java +++ b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowMappedORaggregate2.java @@ -1,5 +1,17 @@ package org.roaringbitmap.needwork; +import org.roaringbitmap.ZipRealDataRetriever; +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; import java.io.DataOutputStream; import java.io.File; @@ -12,18 +24,6 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Param; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ZipRealDataRetriever; -import org.roaringbitmap.buffer.ImmutableRoaringBitmap; -import org.roaringbitmap.buffer.MutableRoaringBitmap; - @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class SlowMappedORaggregate2 { @@ -34,12 +34,11 @@ public MutableRoaringBitmap RoaringWithRun(BenchmarkState benchmarkState) { return answer; } - - @State(Scope.Benchmark) public static class BenchmarkState { - @Param({// putting the data sets in alpha. order - "census1881_srt",}) + @Param({ // putting the data sets in alpha. order + "census1881_srt", + }) String dataset; public List convertToImmutableRoaring(List source) @@ -49,8 +48,7 @@ public List convertToImmutableRoaring(List convertToImmutableRoaring(List convertToImmutableRoaring(List rc; public BenchmarkState() {} @@ -91,6 +87,5 @@ public void setup() throws Exception { } rc = convertToImmutableRoaring(tmprc); } - } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate1.java b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate1.java index b32f9d4d9..5482ee2a8 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate1.java +++ b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate1.java @@ -1,8 +1,7 @@ package org.roaringbitmap.needwork; - -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.ZipRealDataRetriever; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -12,8 +11,9 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.ZipRealDataRetriever; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -25,15 +25,13 @@ public RoaringBitmap RoaringWithRun(BenchmarkState benchmarkState) { return answer; } - - @State(Scope.Benchmark) public static class BenchmarkState { - @Param({// putting the data sets in alpha. order - "wikileaks-noquotes",}) + @Param({ // putting the data sets in alpha. order + "wikileaks-noquotes", + }) String dataset; - ArrayList rc = new ArrayList(); public BenchmarkState() {} @@ -51,6 +49,5 @@ public void setup() throws Exception { } System.out.println("loaded " + rc.size() + " bitmaps"); } - } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate2.java b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate2.java index 73c1c6db5..a8fe81ebb 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate2.java +++ b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate2.java @@ -1,8 +1,7 @@ package org.roaringbitmap.needwork; - -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.ZipRealDataRetriever; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -12,8 +11,9 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.ZipRealDataRetriever; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -25,15 +25,13 @@ public RoaringBitmap RoaringWithRun(BenchmarkState benchmarkState) { return answer; } - - @State(Scope.Benchmark) public static class BenchmarkState { - @Param({// putting the data sets in alpha. order - "census1881_srt",}) + @Param({ // putting the data sets in alpha. order + "census1881_srt", + }) String dataset; - ArrayList rc = new ArrayList(); public BenchmarkState() {} @@ -51,6 +49,5 @@ public void setup() throws Exception { } System.out.println("loaded " + rc.size() + " bitmaps"); } - } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate3.java b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate3.java index fda496c5a..c9f18b95a 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate3.java +++ b/jmh/src/jmh/java/org/roaringbitmap/needwork/SlowORaggregate3.java @@ -1,8 +1,8 @@ package org.roaringbitmap.needwork; - -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.FastAggregation; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.ZipRealDataRetriever; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -12,9 +12,9 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.FastAggregation; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.ZipRealDataRetriever; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -26,15 +26,13 @@ public RoaringBitmap RoaringWithRun(BenchmarkState benchmarkState) { return answer; } - - @State(Scope.Benchmark) public static class BenchmarkState { - @Param({// putting the data sets in alpha. order - "weather_sept_85_srt",}) + @Param({ // putting the data sets in alpha. order + "weather_sept_85_srt", + }) String dataset; - ArrayList rc = new ArrayList(); public BenchmarkState() {} @@ -52,6 +50,5 @@ public void setup() throws Exception { } System.out.println("loaded " + rc.size() + " bitmaps"); } - } } diff --git a/jmh/src/jmh/java/org/roaringbitmap/needwork/state/NeedWorkBenchmarkState.java b/jmh/src/jmh/java/org/roaringbitmap/needwork/state/NeedWorkBenchmarkState.java index 6063ea33c..f4d872ff8 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/needwork/state/NeedWorkBenchmarkState.java +++ b/jmh/src/jmh/java/org/roaringbitmap/needwork/state/NeedWorkBenchmarkState.java @@ -15,19 +15,30 @@ import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING_WITH_RUN; +import org.roaringbitmap.AbstractBenchmarkState; + import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.AbstractBenchmarkState; @State(Scope.Benchmark) public class NeedWorkBenchmarkState extends AbstractBenchmarkState { - @Param({// putting the data sets in alpha. order - CENSUS_INCOME, CENSUS1881, DIMENSION_008, DIMENSION_003, DIMENSION_033, USCENSUS2000, - WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, - WIKILEAKS_NOQUOTES_SRT}) + @Param({ // putting the data sets in alpha. order + CENSUS_INCOME, + CENSUS1881, + DIMENSION_008, + DIMENSION_003, + DIMENSION_033, + USCENSUS2000, + WEATHER_SEPT_85, + WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, + CENSUS1881_SRT, + WEATHER_SEPT_85_SRT, + WIKILEAKS_NOQUOTES_SRT + }) public String dataset; @Param({ROARING, ROARING_WITH_RUN}) @@ -36,12 +47,10 @@ public class NeedWorkBenchmarkState extends AbstractBenchmarkState { @Param({"false", "true"}) public boolean immutable; - public NeedWorkBenchmarkState() {} @Setup public void setup() throws Exception { super.setup(dataset, type, immutable); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/range/ContainsRange.java b/jmh/src/jmh/java/org/roaringbitmap/range/ContainsRange.java index a55973fbf..715d925e0 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/range/ContainsRange.java +++ b/jmh/src/jmh/java/org/roaringbitmap/range/ContainsRange.java @@ -1,26 +1,36 @@ package org.roaringbitmap.range; - -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.RandomData; import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.Util; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.concurrent.TimeUnit; @OutputTimeUnit(TimeUnit.MICROSECONDS) @BenchmarkMode(Mode.AverageTime) -@Fork(value = 1, jvmArgsPrepend = - { - "-XX:-TieredCompilation", - "-XX:+UseSerialGC", - "-mx2G", - "-ms2G", - "-XX:+AlwaysPreTouch" - }) +@Fork( + value = 1, + jvmArgsPrepend = { + "-XX:-TieredCompilation", + "-XX:+UseSerialGC", + "-mx2G", + "-ms2G", + "-XX:+AlwaysPreTouch" + }) @State(Scope.Benchmark) public class ContainsRange { - + @Param({"8", "32", "8192"}) int keys; @@ -29,7 +39,7 @@ public class ContainsRange { @Param({"true", "false"}) boolean match; - + public enum Scenario { START { @Override @@ -53,16 +63,17 @@ long getSup(RoaringBitmap bitmap) { return Util.toUnsignedLong(bitmap.last()) - 1; } }; + abstract long getMin(RoaringBitmap bitmap); + abstract long getSup(RoaringBitmap bitmap); } - + private RoaringBitmap bitmap; - + private long min; private long sup; - @Setup(Level.Trial) public void init() { bitmap = RandomData.randomBitmap(keys, 0.3, 0.2); @@ -71,7 +82,7 @@ public void init() { if (match) { bitmap.add(min, sup); } else if (bitmap.contains(min, sup)) { - bitmap.flip((int)((min + sup) / 2)); + bitmap.flip((int) ((min + sup) / 2)); assert !bitmap.contains(min, sup); } } @@ -83,13 +94,11 @@ public boolean contains() { @Benchmark public boolean containsViaRank() { - if (!bitmap.contains((int)min) || ! bitmap.contains((int)(sup - 1))) { + if (!bitmap.contains((int) min) || !bitmap.contains((int) (sup - 1))) { return false; } - int startRank = bitmap.rank((int)min); - int endRank = bitmap.rank((int)(sup - 1)); + int startRank = bitmap.rank((int) min); + int endRank = bitmap.rank((int) (sup - 1)); return endRank - startRank + 1 == sup - min; } - - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/rangebitmap/RangeBitmapBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/rangebitmap/RangeBitmapBenchmark.java index 2852ebc47..cc143d0eb 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/rangebitmap/RangeBitmapBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/rangebitmap/RangeBitmapBenchmark.java @@ -1,12 +1,22 @@ package org.roaringbitmap.rangebitmap; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.RangeBitmap; import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.RoaringBitmapWriter; import org.roaringbitmap.bsi.BitmapSliceIndex; import org.roaringbitmap.bsi.RoaringBitmapSliceIndex; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.Arrays; import java.util.Random; import java.util.SplittableRandom; @@ -15,13 +25,14 @@ @OutputTimeUnit(TimeUnit.MICROSECONDS) @BenchmarkMode(Mode.AverageTime) -@Fork(value = 1, jvmArgsPrepend = - { - "-XX:-TieredCompilation", - "-XX:+UseSerialGC", - "-mx2G", - "-ms2G", - "-XX:+AlwaysPreTouch" +@Fork( + value = 1, + jvmArgsPrepend = { + "-XX:-TieredCompilation", + "-XX:+UseSerialGC", + "-mx2G", + "-ms2G", + "-XX:+AlwaysPreTouch" }) @State(Scope.Benchmark) public class RangeBitmapBenchmark { @@ -51,7 +62,8 @@ public void setup() { maxValue = Math.max(values[i], maxValue); } bsi = new RoaringBitmapSliceIndex(); - Base2ReferenceImplementation.Builder referenceImplementationBuilder = Base2ReferenceImplementation.builder(); + Base2ReferenceImplementation.Builder referenceImplementationBuilder = + Base2ReferenceImplementation.builder(); RangeBitmap.Appender appender = RangeBitmap.appender(maxValue); int lz = Long.numberOfLeadingZeros(maxValue); long mask = (1L << lz) - 1; @@ -59,7 +71,7 @@ public void setup() { for (long value : values) { referenceImplementationBuilder.add(value); appender.add(value); - bsi.setValue(rid++, (int)(value & mask)); + bsi.setValue(rid++, (int) (value & mask)); } this.referenceImplementation = referenceImplementationBuilder.seal(); this.rangeBitmap = appender.build(); @@ -75,7 +87,7 @@ public RoaringBitmap referenceBase2() { @Benchmark public RoaringBitmap bsi() { // this is about as good as a user can do from outside the library - return bsi.compare(BitmapSliceIndex.Operation.LE, (int)threshold, 0, null); + return bsi.compare(BitmapSliceIndex.Operation.LE, (int) threshold, 0, null); } @Benchmark @@ -202,12 +214,12 @@ LongSupplier of(long seed, double... params) { public static LongSupplier parse(long seed, String spec) { int paramsStart = spec.indexOf('('); int paramsEnd = spec.indexOf(')'); - double[] params = Arrays.stream(spec.substring(paramsStart + 1, paramsEnd).split(",")) - .mapToDouble(s -> Double.parseDouble(s.trim())) - .toArray(); + double[] params = + Arrays.stream(spec.substring(paramsStart + 1, paramsEnd).split(",")) + .mapToDouble(s -> Double.parseDouble(s.trim())) + .toArray(); String dist = spec.substring(0, paramsStart).toUpperCase(); return Distribution.valueOf(dist).of(seed, params); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/ParallelAggregatorBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/ParallelAggregatorBenchmark.java index 5d81668d6..69785c5dd 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/ParallelAggregatorBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/ParallelAggregatorBenchmark.java @@ -1,8 +1,18 @@ package org.roaringbitmap.realdata; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import org.openjdk.jmh.annotations.*; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import org.roaringbitmap.FastAggregation; import org.roaringbitmap.ParallelAggregation; import org.roaringbitmap.RoaringBitmap; @@ -12,25 +22,43 @@ import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.roaringbitmap.buffer.MutableRoaringBitmap; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.Arrays; import java.util.concurrent.TimeUnit; import java.util.stream.StreamSupport; -import static org.roaringbitmap.RealDataset.*; - @State(Scope.Benchmark) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class ParallelAggregatorBenchmark { private static final Cache DATASET_CACHE = - CacheBuilder.newBuilder().maximumSize(1).build(); - - @Param({// putting the data sets in alpha. order - CENSUS_INCOME, CENSUS1881, DIMENSION_008, - DIMENSION_003, DIMENSION_033, USCENSUS2000, - WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, - WIKILEAKS_NOQUOTES_SRT + CacheBuilder.newBuilder().maximumSize(1).build(); + + @Param({ // putting the data sets in alpha. order + CENSUS_INCOME, + CENSUS1881, + DIMENSION_008, + DIMENSION_003, + DIMENSION_033, + USCENSUS2000, + WEATHER_SEPT_85, + WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, + CENSUS1881_SRT, + WEATHER_SEPT_85_SRT, + WIKILEAKS_NOQUOTES_SRT }) public String dataset; @@ -39,14 +67,19 @@ public class ParallelAggregatorBenchmark { @Setup(Level.Trial) public void setup() throws Exception { - bitmaps = DATASET_CACHE.get(dataset, () -> { - System.out.println("Loading" + dataset); - ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); - return StreamSupport.stream(dataRetriever.fetchBitPositions().spliterator(), false) - .map(RoaringBitmap::bitmapOf) - .toArray(RoaringBitmap[]::new); - }); - immutableRoaringBitmaps = Arrays.stream(bitmaps).map(RoaringBitmap::toMutableRoaringBitmap) + bitmaps = + DATASET_CACHE.get( + dataset, + () -> { + System.out.println("Loading" + dataset); + ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); + return StreamSupport.stream(dataRetriever.fetchBitPositions().spliterator(), false) + .map(RoaringBitmap::bitmapOf) + .toArray(RoaringBitmap[]::new); + }); + immutableRoaringBitmaps = + Arrays.stream(bitmaps) + .map(RoaringBitmap::toMutableRoaringBitmap) .toArray(ImmutableRoaringBitmap[]::new); } @@ -80,7 +113,6 @@ public RoaringBitmap fastXor() { return FastAggregation.xor(bitmaps); } - @Benchmark public MutableRoaringBitmap bufferParallelOr() { return BufferParallelAggregation.or(immutableRoaringBitmaps); @@ -105,5 +137,4 @@ public MutableRoaringBitmap bufferFastOr() { public MutableRoaringBitmap bufferFastXor() { return BufferFastAggregation.xor(immutableRoaringBitmaps); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAnd.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAnd.java index 16afeb031..d4ba4e245 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAnd.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAnd.java @@ -1,12 +1,13 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -20,5 +21,4 @@ public int pairwiseAnd(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNot.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNot.java index 5b02a4c10..76ec7af24 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNot.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNot.java @@ -1,12 +1,13 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -20,5 +21,4 @@ public int pairwiseAndNot(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkCardinality.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkCardinality.java index 647be5402..d362368db 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkCardinality.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkCardinality.java @@ -1,13 +1,14 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.Bitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.Bitmap; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkContains.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkContains.java index c14de6143..4e0372bf8 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkContains.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkContains.java @@ -1,8 +1,7 @@ package org.roaringbitmap.realdata; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.Bitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -12,8 +11,10 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.infra.Blackhole; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.Bitmap; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -48,5 +49,4 @@ public void setup() throws Exception { } } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkForEach.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkForEach.java index b4b0eaaf3..ed4cda616 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkForEach.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkForEach.java @@ -1,14 +1,15 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.Bitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.IntConsumer; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.Bitmap; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -32,5 +33,4 @@ public void accept(int value) { total += value; } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIOr.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIOr.java index 83c053bd0..91b5978eb 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIOr.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIOr.java @@ -1,13 +1,14 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.Bitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.Bitmap; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -21,5 +22,4 @@ public int pairwiseIOr(RealDataBenchmarkState bs) { } return bitmap.cardinality(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkInot.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkInot.java index a492b5d19..7f3209d9b 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkInot.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkInot.java @@ -1,12 +1,13 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -20,5 +21,4 @@ public int flipLargeRange(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIterate.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIterate.java index cc4fbb37f..b37722b58 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIterate.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkIterate.java @@ -1,14 +1,15 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.Bitmap; +import org.roaringbitmap.realdata.wrapper.BitmapIterator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.Bitmap; -import org.roaringbitmap.realdata.wrapper.BitmapIterator; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -26,5 +27,4 @@ public int iterate(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOr.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOr.java index cecc26420..3e38f6eec 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOr.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOr.java @@ -1,13 +1,14 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.BitmapIterator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.BitmapIterator; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -33,5 +34,4 @@ public int pairwiseOr_NoCardinality(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOrNot.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOrNot.java index a37c73057..4a58505ca 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOrNot.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkOrNot.java @@ -1,17 +1,18 @@ package org.roaringbitmap.realdata; +import static org.roaringbitmap.Util.toUnsignedLong; + +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.realdata.state.RealDataRoaringBitmaps; + import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.infra.Blackhole; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.realdata.state.RealDataRoaringBitmaps; import java.util.concurrent.TimeUnit; -import static org.roaringbitmap.Util.toUnsignedLong; - @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class RealDataBenchmarkOrNot { @@ -21,8 +22,9 @@ public void pairwiseOrNot(RealDataRoaringBitmaps state, Blackhole bh) { RoaringBitmap[] bitmaps = state.getBitmaps(); for (int k = 0; k + 1 < bitmaps.length; ++k) { RoaringBitmap bitmap = bitmaps[k].clone(); - bitmap.orNot(bitmaps[k+1], bitmap.last()); - bh.consume(RoaringBitmap.orNot(bitmaps[k], bitmaps[k + 1], toUnsignedLong(bitmaps[k].last()))); + bitmap.orNot(bitmaps[k + 1], bitmap.last()); + bh.consume( + RoaringBitmap.orNot(bitmaps[k], bitmaps[k + 1], toUnsignedLong(bitmaps[k].last()))); } } @@ -33,7 +35,7 @@ public void pairwiseOrNotExternal(RealDataRoaringBitmaps state, Blackhole bh) { long limit = toUnsignedLong(bitmaps[k].last()); RoaringBitmap range = new RoaringBitmap(); range.add(0, limit); - RoaringBitmap bitmap = RoaringBitmap.and(range, bitmaps[k+1]); + RoaringBitmap bitmap = RoaringBitmap.and(range, bitmaps[k + 1]); bitmap.flip(0L, limit); bitmap.or(RoaringBitmap.and(range, bitmaps[k])); bh.consume(bitmap); diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterate.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterate.java index a51b6faf0..4c1c7da22 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterate.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterate.java @@ -1,14 +1,15 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.Bitmap; +import org.roaringbitmap.realdata.wrapper.BitmapIterator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.Bitmap; -import org.roaringbitmap.realdata.wrapper.BitmapIterator; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -26,5 +27,4 @@ public int reverseIterate(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaive.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaive.java index a13e3eecb..54d61e2a7 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaive.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaive.java @@ -1,13 +1,14 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.BitmapAggregator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.BitmapAggregator; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -18,5 +19,4 @@ public int wideAnd_naive(RealDataBenchmarkState bs) { BitmapAggregator aggregator = bs.bitmaps.get(0).naiveAndAggregator(); return aggregator.aggregate(bs.bitmaps).cardinality(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaive.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaive.java index 405d8c5d2..ad7528118 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaive.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaive.java @@ -1,13 +1,14 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.BitmapAggregator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.BitmapAggregator; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -18,5 +19,4 @@ public int wideOr_naive(RealDataBenchmarkState bs) { BitmapAggregator aggregator = bs.bitmaps.get(0).naiveOrAggregator(); return aggregator.aggregate(bs.bitmaps).cardinality(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPq.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPq.java index b9a73d986..c1cd0f7b1 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPq.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPq.java @@ -1,13 +1,14 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.BitmapAggregator; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.BitmapAggregator; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -18,5 +19,4 @@ public int wideOr_pq(RealDataBenchmarkState bs) { BitmapAggregator aggregator = bs.bitmaps.get(0).priorityQueueOrAggregator(); return aggregator.aggregate(bs.bitmaps).cardinality(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkXor.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkXor.java index 53727aea8..d3e961208 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkXor.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataBenchmarkXor.java @@ -1,12 +1,13 @@ package org.roaringbitmap.realdata; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -20,5 +21,4 @@ public int pairwiseXor(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataSerializationBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataSerializationBenchmark.java index 09b09c2da..c6e6eea7c 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataSerializationBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/RealDataSerializationBenchmark.java @@ -13,15 +13,9 @@ import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.concurrent.TimeUnit; -import java.util.stream.StreamSupport; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.ZipRealDataRetriever; +import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; @@ -35,51 +29,65 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.ZipRealDataRetriever; -import org.roaringbitmap.buffer.ImmutableRoaringBitmap; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.TimeUnit; +import java.util.stream.StreamSupport; /** - * + * * @author Richard Startin * */ public class RealDataSerializationBenchmark { - public void - launchBenchmark() throws Exception { - - Options opt = new OptionsBuilder() - // Specify which benchmarks to run. - // You can be more specific if you'd like to run only one benchmark per test. - .include(this.getClass().getName() + ".*") - // Set the following options as needed - .mode (Mode.AverageTime) - .timeUnit(TimeUnit.MICROSECONDS) - .warmupTime(TimeValue.seconds(1)) - .warmupIterations(2) - .measurementTime(TimeValue.seconds(10)) - .measurementIterations(5) - .threads(1) - .forks(1) - .shouldFailOnError(true) - .shouldDoGC(true) - //.jvmArgs("-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining") - //.addProfiler(WinPerfAsmProfiler.class) - .build(); - - new Runner(opt).run(); - } - + public void launchBenchmark() throws Exception { + + Options opt = + new OptionsBuilder() + // Specify which benchmarks to run. + // You can be more specific if you'd like to run only one benchmark per test. + .include(this.getClass().getName() + ".*") + // Set the following options as needed + .mode(Mode.AverageTime) + .timeUnit(TimeUnit.MICROSECONDS) + .warmupTime(TimeValue.seconds(1)) + .warmupIterations(2) + .measurementTime(TimeValue.seconds(10)) + .measurementIterations(5) + .threads(1) + .forks(1) + .shouldFailOnError(true) + .shouldDoGC(true) + // .jvmArgs("-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining") + // .addProfiler(WinPerfAsmProfiler.class) + .build(); + + new Runner(opt).run(); + } + @State(Scope.Benchmark) public static class BenchmarkState { - @Param({ - CENSUS_INCOME, CENSUS1881, DIMENSION_008, - DIMENSION_003, DIMENSION_033, USCENSUS2000, - WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, - WIKILEAKS_NOQUOTES_SRT + CENSUS_INCOME, + CENSUS1881, + DIMENSION_008, + DIMENSION_003, + DIMENSION_033, + USCENSUS2000, + WEATHER_SEPT_85, + WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, + CENSUS1881_SRT, + WEATHER_SEPT_85_SRT, + WIKILEAKS_NOQUOTES_SRT }) public String dataset; @@ -91,7 +99,8 @@ public static class BenchmarkState { @Setup(Level.Trial) public void setup() throws Exception { ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); - RoaringBitmap[] bitmaps = StreamSupport.stream(dataRetriever.fetchBitPositions().spliterator(), false) + RoaringBitmap[] bitmaps = + StreamSupport.stream(dataRetriever.fetchBitPositions().spliterator(), false) .map(RoaringBitmap::bitmapOf) .toArray(RoaringBitmap[]::new); buffers = new byte[bitmaps.length][]; @@ -107,19 +116,19 @@ public void setup() throws Exception { } } - @Benchmark public void bufferBackedDataInput(BenchmarkState state, Blackhole bh) throws IOException { - byte[][] buffers = state.buffers; - for (int i = 0; i < buffers.length; ++i) { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.deserialize(new BufferDataInput(ByteBuffer.wrap(state.buffers[i]))); - bh.consume(bitmap); - } + byte[][] buffers = state.buffers; + for (int i = 0; i < buffers.length; ++i) { + RoaringBitmap bitmap = new RoaringBitmap(); + bitmap.deserialize(new BufferDataInput(ByteBuffer.wrap(state.buffers[i]))); + bh.consume(bitmap); + } } @Benchmark - public void streamBackedDataInputWithBuffer(BenchmarkState state, Blackhole bh) throws IOException { + public void streamBackedDataInputWithBuffer(BenchmarkState state, Blackhole bh) + throws IOException { byte[][] buffers = state.buffers; for (int i = 0; i < buffers.length; ++i) { RoaringBitmap bitmap = new RoaringBitmap(); @@ -154,7 +163,8 @@ public void directToBuffer(BenchmarkState state, Blackhole bh) throws IOExceptio public void viaImmutable(BenchmarkState state, Blackhole bh) { byte[][] buffers = state.buffers; for (int i = 0; i < buffers.length; ++i) { - RoaringBitmap bitmap = new ImmutableRoaringBitmap(ByteBuffer.wrap(state.buffers[i])).toRoaringBitmap(); + RoaringBitmap bitmap = + new ImmutableRoaringBitmap(ByteBuffer.wrap(state.buffers[i])).toRoaringBitmap(); bh.consume(bitmap); } } @@ -243,5 +253,4 @@ public String readUTF() throws IOException { return null; } } - -} \ No newline at end of file +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataBenchmarkState.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataBenchmarkState.java index de95a766b..ac68fe7e0 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataBenchmarkState.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataBenchmarkState.java @@ -27,10 +27,20 @@ @State(Scope.Benchmark) public class RealDataBenchmarkState extends org.roaringbitmap.AbstractBenchmarkState { - @Param({// putting the data sets in alpha. order - CENSUS_INCOME, CENSUS1881, DIMENSION_008, DIMENSION_003, DIMENSION_033, USCENSUS2000, - WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, - WIKILEAKS_NOQUOTES_SRT}) + @Param({ // putting the data sets in alpha. order + CENSUS_INCOME, + CENSUS1881, + DIMENSION_008, + DIMENSION_003, + DIMENSION_033, + USCENSUS2000, + WEATHER_SEPT_85, + WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, + CENSUS1881_SRT, + WEATHER_SEPT_85_SRT, + WIKILEAKS_NOQUOTES_SRT + }) public String dataset; @Param({CONCISE, WAH, EWAH, EWAH32, ROARING, ROARING_WITH_RUN}) @@ -39,12 +49,10 @@ public class RealDataBenchmarkState extends org.roaringbitmap.AbstractBenchmarkS @Param({"false", "true"}) public boolean immutable; - public RealDataBenchmarkState() {} @Setup public void setup() throws Exception { super.setup(dataset, type, immutable); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringBitmaps.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringBitmaps.java index 15f19d5b5..f62f48259 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringBitmaps.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringBitmaps.java @@ -1,23 +1,47 @@ package org.roaringbitmap.realdata.state; -import org.openjdk.jmh.annotations.*; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.ZipRealDataRetriever; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + import java.util.Arrays; import java.util.stream.StreamSupport; -import static org.roaringbitmap.RealDataset.*; - @State(Scope.Benchmark) public class RealDataRoaringBitmaps { - @Param({// putting the data sets in alpha. order - CENSUS_INCOME, CENSUS1881, DIMENSION_008, - DIMENSION_003, DIMENSION_033, USCENSUS2000, - WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, - WIKILEAKS_NOQUOTES_SRT + @Param({ // putting the data sets in alpha. order + CENSUS_INCOME, + CENSUS1881, + DIMENSION_008, + DIMENSION_003, + DIMENSION_033, + USCENSUS2000, + WEATHER_SEPT_85, + WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, + CENSUS1881_SRT, + WEATHER_SEPT_85_SRT, + WIKILEAKS_NOQUOTES_SRT }) public String dataset; @@ -27,10 +51,13 @@ public class RealDataRoaringBitmaps { @Setup(Level.Trial) public void setup() throws Exception { ZipRealDataRetriever dataRetriever = new ZipRealDataRetriever(dataset); - bitmaps = StreamSupport.stream(dataRetriever.fetchBitPositions().spliterator(), false) + bitmaps = + StreamSupport.stream(dataRetriever.fetchBitPositions().spliterator(), false) .map(RoaringBitmap::bitmapOf) .toArray(RoaringBitmap[]::new); - immutableRoaringBitmaps = Arrays.stream(bitmaps).map(RoaringBitmap::toMutableRoaringBitmap) + immutableRoaringBitmaps = + Arrays.stream(bitmaps) + .map(RoaringBitmap::toMutableRoaringBitmap) .toArray(ImmutableRoaringBitmap[]::new); } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringOnlyBenchmarkState.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringOnlyBenchmarkState.java index 4f3e7a15e..f8fb77c3a 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringOnlyBenchmarkState.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/state/RealDataRoaringOnlyBenchmarkState.java @@ -1,25 +1,40 @@ package org.roaringbitmap.realdata.state; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import static org.roaringbitmap.RealDataset.*; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.CONCISE; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH32; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING_WITH_RUN; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.WAH; - @State(Scope.Benchmark) public class RealDataRoaringOnlyBenchmarkState extends org.roaringbitmap.RoaringOnlyBenchmarkState { - @Param({// putting the data sets in alpha. order - CENSUS_INCOME, CENSUS1881, DIMENSION_008, DIMENSION_003, DIMENSION_033, USCENSUS2000, - WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, - WIKILEAKS_NOQUOTES_SRT}) + @Param({ // putting the data sets in alpha. order + CENSUS_INCOME, + CENSUS1881, + DIMENSION_008, + DIMENSION_003, + DIMENSION_033, + USCENSUS2000, + WEATHER_SEPT_85, + WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, + CENSUS1881_SRT, + WEATHER_SEPT_85_SRT, + WIKILEAKS_NOQUOTES_SRT + }) public String dataset; public RealDataRoaringOnlyBenchmarkState() {} @@ -28,5 +43,4 @@ public RealDataRoaringOnlyBenchmarkState() {} public void setup() throws Exception { super.setup(dataset); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Bitmap.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Bitmap.java index 4dc78d90e..ca4703376 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Bitmap.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Bitmap.java @@ -1,10 +1,10 @@ package org.roaringbitmap.realdata.wrapper; +import org.roaringbitmap.IntConsumer; + import java.io.DataOutputStream; import java.io.IOException; -import org.roaringbitmap.IntConsumer; - public interface Bitmap { boolean contains(int i); @@ -40,5 +40,4 @@ public interface Bitmap { void serialize(DataOutputStream dos) throws IOException; Bitmap clone(); - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapAggregator.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapAggregator.java index 71538f0e9..c54087c26 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapAggregator.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapAggregator.java @@ -3,5 +3,4 @@ public interface BitmapAggregator { Bitmap aggregate(Iterable bitmaps); - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapFactory.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapFactory.java index f44e52201..74f9b1138 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapFactory.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapFactory.java @@ -1,23 +1,16 @@ package org.roaringbitmap.realdata.wrapper; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.ArrayList; -import java.util.List; - -import io.druid.extendedset.intset.ConciseSet; -import io.druid.extendedset.intset.ImmutableConciseSet; import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import com.googlecode.javaewah.EWAHCompressedBitmap; import com.googlecode.javaewah32.EWAHCompressedBitmap32; +import io.druid.extendedset.intset.ConciseSet; +import io.druid.extendedset.intset.ImmutableConciseSet; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.nio.ByteBuffer; public final class BitmapFactory { @@ -119,7 +112,6 @@ private static Bitmap newImmutableRoaringBitmap(Bitmap bitmap) throws Exception return new ImmutableRoaringBitmapWrapper(roaring); } - private static ByteBuffer toByteBuffer(Bitmap bitmap) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); @@ -128,5 +120,4 @@ private static ByteBuffer toByteBuffer(Bitmap bitmap) throws Exception { } public static void cleanup() {} - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapIterator.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapIterator.java index 95a9dda43..439b593cb 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapIterator.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/BitmapIterator.java @@ -5,5 +5,4 @@ public interface BitmapIterator { boolean hasNext(); int next(); - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetIteratorWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetIteratorWrapper.java index c62dabfd8..2879e7294 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetIteratorWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetIteratorWrapper.java @@ -19,5 +19,4 @@ public boolean hasNext() { public int next() { return iterator.next(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetWrapper.java index 303b69ad4..aff924339 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ConciseSetWrapper.java @@ -1,5 +1,8 @@ package org.roaringbitmap.realdata.wrapper; +import org.roaringbitmap.IntConsumer; + +import io.druid.extendedset.intset.ConciseSet; import java.io.DataOutputStream; import java.io.IOException; @@ -7,9 +10,6 @@ import java.util.Iterator; import java.util.PriorityQueue; -import io.druid.extendedset.intset.ConciseSet; -import org.roaringbitmap.IntConsumer; - final class ConciseSetWrapper implements Bitmap { private final ConciseSet bitmap; @@ -69,11 +69,8 @@ public Bitmap flip(int rStart, int rEnd) { // put this back, but have to hunt down the JMH param setting // so the comparison does not abort. return new ConciseSetWrapper(bitmap); // wrong result - } - - @Override public Bitmap andNot(Bitmap other) { return new ConciseSetWrapper(bitmap.difference(((ConciseSetWrapper) other).bitmap)); @@ -115,13 +112,15 @@ public BitmapAggregator priorityQueueOrAggregator() { @Override public Bitmap aggregate(Iterable bitmaps) { PriorityQueue pq = - new PriorityQueue(128, new Comparator() { - @Override - public int compare(ConciseSet a, ConciseSet b) { - return (int) (a.size() * a.collectionCompressionRatio()) - - (int) (b.size() * b.collectionCompressionRatio()); - } - }); + new PriorityQueue( + 128, + new Comparator() { + @Override + public int compare(ConciseSet a, ConciseSet b) { + return (int) (a.size() * a.collectionCompressionRatio()) + - (int) (b.size() * b.collectionCompressionRatio()); + } + }); for (Bitmap bitmap1 : bitmaps) { pq.add(((ConciseSetWrapper) bitmap1).bitmap); } @@ -155,5 +154,4 @@ public void serialize(DataOutputStream dos) throws IOException { public Bitmap clone() { return new ConciseSetWrapper(bitmap.clone()); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Ewah32BitmapWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Ewah32BitmapWrapper.java index c502ca72e..b5360691e 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Ewah32BitmapWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/Ewah32BitmapWrapper.java @@ -1,14 +1,14 @@ package org.roaringbitmap.realdata.wrapper; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Iterator; - import org.roaringbitmap.IntConsumer; import com.googlecode.javaewah32.EWAHCompressedBitmap32; import com.googlecode.javaewah32.FastAggregation32; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; + final class Ewah32BitmapWrapper implements Bitmap { private final EWAHCompressedBitmap32 bitmap; @@ -84,8 +84,6 @@ public Bitmap flip(int rangeStart, int rangeEnd) { return new Ewah32BitmapWrapper(temp); } - - @Override public Bitmap andNot(Bitmap other) { return new Ewah32BitmapWrapper(bitmap.andNot(((Ewah32BitmapWrapper) other).bitmap)); @@ -126,27 +124,25 @@ public BitmapAggregator priorityQueueOrAggregator() { return new BitmapAggregator() { @Override public Bitmap aggregate(final Iterable bitmaps) { - Iterator iterator = new Iterator() { - final Iterator i = bitmaps.iterator(); - - @Override - public boolean hasNext() { - return i.hasNext(); - } - - @Override - public EWAHCompressedBitmap32 next() { - return ((Ewah32BitmapWrapper) i.next()).bitmap; - } - - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - - }; + Iterator iterator = + new Iterator() { + final Iterator i = bitmaps.iterator(); + + @Override + public boolean hasNext() { + return i.hasNext(); + } + + @Override + public EWAHCompressedBitmap32 next() { + return ((Ewah32BitmapWrapper) i.next()).bitmap; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; return new Ewah32BitmapWrapper(FastAggregation32.or(iterator)); } }; @@ -170,5 +166,4 @@ public Bitmap clone() { throw new RuntimeException(e); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahBitmapWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahBitmapWrapper.java index 314ad39db..36d62a5cd 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahBitmapWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahBitmapWrapper.java @@ -1,14 +1,14 @@ package org.roaringbitmap.realdata.wrapper; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Iterator; - import org.roaringbitmap.IntConsumer; import com.googlecode.javaewah.EWAHCompressedBitmap; import com.googlecode.javaewah.FastAggregation; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; + final class EwahBitmapWrapper implements Bitmap { private final EWAHCompressedBitmap bitmap; @@ -85,8 +85,6 @@ public Bitmap flip(int rangeStart, int rangeEnd) { return new EwahBitmapWrapper(temp); } - - @Override public Bitmap andNot(Bitmap other) { return new EwahBitmapWrapper(bitmap.andNot(((EwahBitmapWrapper) other).bitmap)); @@ -127,24 +125,25 @@ public BitmapAggregator priorityQueueOrAggregator() { return new BitmapAggregator() { @Override public Bitmap aggregate(final Iterable bitmaps) { - Iterator iterator = new Iterator() { - final Iterator i = bitmaps.iterator(); - - @Override - public boolean hasNext() { - return i.hasNext(); - } - - @Override - public EWAHCompressedBitmap next() { - return ((EwahBitmapWrapper) i.next()).bitmap; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; + Iterator iterator = + new Iterator() { + final Iterator i = bitmaps.iterator(); + + @Override + public boolean hasNext() { + return i.hasNext(); + } + + @Override + public EWAHCompressedBitmap next() { + return ((EwahBitmapWrapper) i.next()).bitmap; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; return new EwahBitmapWrapper(FastAggregation.or(iterator)); } }; @@ -168,5 +167,4 @@ public Bitmap clone() { throw new RuntimeException(e); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahIteratorWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahIteratorWrapper.java index 8cc28e129..7722351f6 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahIteratorWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/EwahIteratorWrapper.java @@ -19,5 +19,4 @@ public boolean hasNext() { public int next() { return iterator.next(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableConciseSetWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableConciseSetWrapper.java index 97859281a..c458b908b 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableConciseSetWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableConciseSetWrapper.java @@ -1,18 +1,18 @@ package org.roaringbitmap.realdata.wrapper; +import static io.druid.extendedset.intset.ImmutableConciseSet.intersection; +import static io.druid.extendedset.intset.ImmutableConciseSet.union; + +import org.roaringbitmap.IntConsumer; + +import io.druid.extendedset.intset.ImmutableConciseSet; + import java.io.DataOutputStream; import java.io.IOException; import java.util.Comparator; import java.util.Iterator; import java.util.PriorityQueue; -import io.druid.extendedset.intset.ImmutableConciseSet; -import org.roaringbitmap.IntConsumer; - -import static io.druid.extendedset.intset.ImmutableConciseSet.intersection; -import static io.druid.extendedset.intset.ImmutableConciseSet.union; - - final class ImmutableConciseSetWrapper implements Bitmap { private final ImmutableConciseSet bitmap; @@ -55,10 +55,8 @@ public Bitmap and(Bitmap other) { @Override public Bitmap flip(int s, int e) { ImmutableConciseSet temp = ImmutableConciseSet.complement(bitmap, e); - if (e == 0) - return new ImmutableConciseSetWrapper(temp); - else - return new ImmutableConciseSetWrapper(ImmutableConciseSet.complement(temp, e - 1)); + if (e == 0) return new ImmutableConciseSetWrapper(temp); + else return new ImmutableConciseSetWrapper(ImmutableConciseSet.complement(temp, e - 1)); } @Override @@ -121,8 +119,6 @@ public ImmutableConciseSet next() { public void remove() { throw new UnsupportedOperationException(); } - - }; } @@ -132,12 +128,14 @@ public BitmapAggregator priorityQueueOrAggregator() { @Override public Bitmap aggregate(Iterable bitmaps) { PriorityQueue pq = - new PriorityQueue(128, new Comparator() { - @Override - public int compare(ImmutableConciseSet a, ImmutableConciseSet b) { - return a.getLastWordIndex() - b.getLastWordIndex(); - } - }); + new PriorityQueue( + 128, + new Comparator() { + @Override + public int compare(ImmutableConciseSet a, ImmutableConciseSet b) { + return a.getLastWordIndex() - b.getLastWordIndex(); + } + }); for (Bitmap bitmap1 : bitmaps) { pq.add(((ImmutableConciseSetWrapper) bitmap1).bitmap); } @@ -171,5 +169,4 @@ public void serialize(DataOutputStream dos) throws IOException { public Bitmap clone() { throw new UnsupportedOperationException("Not implemented in ImmutableConciseSet"); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableRoaringBitmapWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableRoaringBitmapWrapper.java index a56ace739..9f6343777 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableRoaringBitmapWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/ImmutableRoaringBitmapWrapper.java @@ -1,13 +1,13 @@ package org.roaringbitmap.realdata.wrapper; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Iterator; - import org.roaringbitmap.IntConsumer; import org.roaringbitmap.buffer.BufferFastAggregation; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; + final class ImmutableRoaringBitmapWrapper implements Bitmap { private final ImmutableRoaringBitmap bitmap; @@ -64,14 +64,12 @@ public Bitmap xor(Bitmap other) { ImmutableRoaringBitmap.xor(bitmap, ((ImmutableRoaringBitmapWrapper) other).bitmap)); } - @Override public Bitmap flip(int rangeStart, int rangeEnd) { return new ImmutableRoaringBitmapWrapper( - ImmutableRoaringBitmap.flip(bitmap, (long)rangeStart, (long)rangeEnd)); + ImmutableRoaringBitmap.flip(bitmap, (long) rangeStart, (long) rangeEnd)); } - @Override public Bitmap andNot(Bitmap other) { return new ImmutableRoaringBitmapWrapper( @@ -147,5 +145,4 @@ public void serialize(DataOutputStream dos) throws IOException { public Bitmap clone() { return new ImmutableRoaringBitmapWrapper(bitmap.clone()); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringBitmapWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringBitmapWrapper.java index d59ec7629..213646f94 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringBitmapWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringBitmapWrapper.java @@ -1,13 +1,13 @@ package org.roaringbitmap.realdata.wrapper; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Iterator; - import org.roaringbitmap.FastAggregation; import org.roaringbitmap.IntConsumer; import org.roaringbitmap.RoaringBitmap; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Iterator; + final class RoaringBitmapWrapper implements Bitmap { private final RoaringBitmap bitmap; @@ -61,11 +61,9 @@ public Bitmap ior(Bitmap other) { @Override public Bitmap flip(int rangeStart, int rangeEnd) { - return new RoaringBitmapWrapper(RoaringBitmap.flip(bitmap, (long)rangeStart, (long)rangeEnd)); + return new RoaringBitmapWrapper(RoaringBitmap.flip(bitmap, (long) rangeStart, (long) rangeEnd)); } - - @Override public Bitmap xor(Bitmap other) { return new RoaringBitmapWrapper( @@ -120,13 +118,11 @@ public boolean hasNext() { return i.hasNext(); } - @Override public void remove() { throw new UnsupportedOperationException(); } - @Override public RoaringBitmap next() { return ((RoaringBitmapWrapper) i.next()).bitmap; @@ -148,5 +144,4 @@ public void serialize(DataOutputStream dos) throws IOException { public Bitmap clone() { return new RoaringBitmapWrapper(bitmap.clone()); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringIteratorWrapper.java b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringIteratorWrapper.java index d5c106c8b..b9338985e 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringIteratorWrapper.java +++ b/jmh/src/jmh/java/org/roaringbitmap/realdata/wrapper/RoaringIteratorWrapper.java @@ -19,5 +19,4 @@ public boolean hasNext() { public int next() { return iterator.next(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/AllRunHorizontalOrBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/AllRunHorizontalOrBenchmark.java index b50cd6891..d07b9eb72 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/AllRunHorizontalOrBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/AllRunHorizontalOrBenchmark.java @@ -1,10 +1,10 @@ package org.roaringbitmap.runcontainer; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.Container; +import org.roaringbitmap.RoaringBitmap; +import com.googlecode.javaewah.EWAHCompressedBitmap; +import com.googlecode.javaewah32.EWAHCompressedBitmap32; import io.druid.extendedset.intset.ConciseSet; import io.druid.extendedset.intset.ImmutableConciseSet; import org.openjdk.jmh.annotations.Benchmark; @@ -13,11 +13,11 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.Container; -import org.roaringbitmap.RoaringBitmap; -import com.googlecode.javaewah.EWAHCompressedBitmap; -import com.googlecode.javaewah32.EWAHCompressedBitmap32; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -31,7 +31,6 @@ static ConciseSet toConcise(int[] dat) { return ans; } - static ConciseSet toWAH(int[] dat) { ConciseSet ans = new ConciseSet(true); for (int i : dat) { @@ -43,8 +42,7 @@ static ConciseSet toWAH(int[] dat) { @Benchmark public int OrConcise(BenchmarkState benchmarkState) { ConciseSet base = benchmarkState.cc.get(0); - for (int k = 1; k < benchmarkState.cc.size(); ++k) - base.union(benchmarkState.cc.get(k)); + for (int k = 1; k < benchmarkState.cc.size(); ++k) base.union(benchmarkState.cc.get(k)); return base.size(); } @@ -57,8 +55,7 @@ public int OrImmutableConcise(BenchmarkState benchmarkState) { @Benchmark public int OrWAH(BenchmarkState benchmarkState) { ConciseSet base = benchmarkState.wah.get(0); - for (int k = 1; k < benchmarkState.wah.size(); ++k) - base.union(benchmarkState.wah.get(k)); + for (int k = 1; k < benchmarkState.wah.size(); ++k) base.union(benchmarkState.wah.get(k)); return base.size(); } @@ -67,7 +64,6 @@ public int horizontalOr_Roaringwithrun(BenchmarkState benchmarkState) { return RoaringBitmap.or(benchmarkState.rc.iterator()).getCardinality(); } - @Benchmark public int horizontalOr_Roaring(BenchmarkState benchmarkState) { return RoaringBitmap.or(benchmarkState.ac.iterator()).getCardinality(); @@ -79,7 +75,6 @@ public int horizontalOr_EWAH(BenchmarkState benchmarkState) { EWAHCompressedBitmap bitmapor = EWAHCompressedBitmap.or(benchmarkState.ewah.toArray(a)); int answer = bitmapor.cardinality(); return answer; - } @Benchmark @@ -90,8 +85,6 @@ public int horizontalOr_EWAH32(BenchmarkState benchmarkState) { return answer; } - - @State(Scope.Benchmark) public static class BenchmarkState { @@ -106,7 +99,6 @@ public static class BenchmarkState { Random rand = new Random(); Container aggregate; - public BenchmarkState() { int N = 30; Random rand = new Random(1234); @@ -116,7 +108,7 @@ public BenchmarkState() { for (int z = 0; z < 50; ++z) { int end = start + rand.nextInt(10000); - rb.add((long)start, (long)end); + rb.add((long) start, (long) end); start = end + rand.nextInt(1000); } ConciseSet ccs = toConcise(rb.toArray()); @@ -131,9 +123,7 @@ public BenchmarkState() { rc.add(rb); ewah.add(EWAHCompressedBitmap.bitmapOf(rb.toArray())); ewah32.add(EWAHCompressedBitmap32.bitmapOf(rb.toArray())); - } } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/ArrayContainerAndNotRunContainerBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/ArrayContainerAndNotRunContainerBenchmark.java index d9d810568..0e1192e8c 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/ArrayContainerAndNotRunContainerBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/ArrayContainerAndNotRunContainerBenchmark.java @@ -1,13 +1,13 @@ package org.roaringbitmap.runcontainer; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.RoaringOnlyBenchmarkState; import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.roaringbitmap.realdata.state.RealDataRoaringOnlyBenchmarkState; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; + @BenchmarkMode(Mode.Throughput) public class ArrayContainerAndNotRunContainerBenchmark { @@ -24,7 +24,9 @@ public RoaringBitmap pairwiseACAndNotRC(RealDataRoaringOnlyBenchmarkState bs) { public ImmutableRoaringBitmap immutablePairwiseACAndNotRC(RealDataRoaringOnlyBenchmarkState bs) { ImmutableRoaringBitmap last = null; for (int k = 0; k + 1 < bs.immutableBitmaps.size(); ++k) { - last = ImmutableRoaringBitmap.andNot(bs.immutableOnlyArrayContainers.get(k), bs.immutableOnlyRunContainers.get(k + 1)); + last = + ImmutableRoaringBitmap.andNot( + bs.immutableOnlyArrayContainers.get(k), bs.immutableOnlyRunContainers.get(k + 1)); } return last; } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndContainerBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndContainerBenchmark.java index 332e4c481..dc085e579 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndContainerBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndContainerBenchmark.java @@ -1,7 +1,9 @@ package org.roaringbitmap.runcontainer; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.RunContainer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,14 +11,12 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.BitmapContainer; -import org.roaringbitmap.Container; -import org.roaringbitmap.RunContainer; + +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) - public class BasicAndContainerBenchmark { @Benchmark @@ -31,7 +31,6 @@ public int andBitmapContainerVSBitmapContainer(BenchmarkState benchmarkState) { return benchmarkState.ac1.and(benchmarkState.ac2).getCardinality(); } - @Benchmark public int part2_andRunContainerVSRunContainerContainer(BenchmarkState benchmarkState) { if (benchmarkState.rc2.serializedSizeInBytes() > benchmarkState.ac2.serializedSizeInBytes()) @@ -58,7 +57,6 @@ public int part3_andArrayContainerVSBitmapContainer(BenchmarkState benchmarkStat return benchmarkState.ac4.and(benchmarkState.ac2).getCardinality(); } - @State(Scope.Benchmark) public static class BenchmarkState { public int offvalues = 32; @@ -68,7 +66,6 @@ public static class BenchmarkState { Container rc1, rc2, rc3, ac1, ac2, ac3, ac4; Random rand = new Random(); - public BenchmarkState() { final int max = 1 << 16; final int howmanywords = (1 << 16) / 64; @@ -77,7 +74,6 @@ public BenchmarkState() { int[] values3 = RandomUtil.generateCrazyRun(rand, max); int[] values4 = RandomUtil.generateUniformHash(rand, bitsetperword3 * howmanywords, max); - rc1 = new RunContainer(); rc1 = RandomUtil.fillMeUp(rc1, values1); @@ -93,34 +89,26 @@ public BenchmarkState() { if (!(ac1 instanceof BitmapContainer)) throw new RuntimeException("expected bitmap container"); - ac2 = new ArrayContainer(); ac2 = RandomUtil.fillMeUp(ac2, values2); if (!(ac2 instanceof BitmapContainer)) throw new RuntimeException("expected bitmap container"); - ac3 = new ArrayContainer(); ac3 = RandomUtil.fillMeUp(ac3, values3); ac4 = new ArrayContainer(); ac4 = RandomUtil.fillMeUp(ac4, values4); - if (!(ac4 instanceof ArrayContainer)) - throw new RuntimeException("expected array container"); + if (!(ac4 instanceof ArrayContainer)) throw new RuntimeException("expected array container"); - if (!rc1.equals(ac1)) - throw new RuntimeException("first containers do not match"); + if (!rc1.equals(ac1)) throw new RuntimeException("first containers do not match"); - if (!rc2.equals(ac2)) - throw new RuntimeException("second containers do not match"); + if (!rc2.equals(ac2)) throw new RuntimeException("second containers do not match"); - if (!rc1.and(rc2).equals(ac1.and(ac2))) - throw new RuntimeException("ands do not match"); - if (!ac1.and(rc2).equals(ac1.and(ac2))) - throw new RuntimeException("ands do not match"); + if (!rc1.and(rc2).equals(ac1.and(ac2))) throw new RuntimeException("ands do not match"); + if (!ac1.and(rc2).equals(ac1.and(ac2))) throw new RuntimeException("ands do not match"); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndNotContainerBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndNotContainerBenchmark.java index 8c1bc9c00..99b9851e7 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndNotContainerBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicAndNotContainerBenchmark.java @@ -1,7 +1,9 @@ package org.roaringbitmap.runcontainer; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.RunContainer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,10 +11,9 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.BitmapContainer; -import org.roaringbitmap.Container; -import org.roaringbitmap.RunContainer; + +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @@ -124,7 +125,9 @@ public BenchmarkState() { rc3 = new RunContainer(); rc3 = RandomUtil.fillMeUp(rc3, values3); - rc4 = new RunContainer(new char[]{4, 500, 2000, 1000, 5000, 3000, 16000, 10000, 32000, 600}, 5); + rc4 = + new RunContainer( + new char[] {4, 500, 2000, 1000, 5000, 3000, 16000, 10000, 32000, 600}, 5); ac1 = new ArrayContainer(); ac1 = RandomUtil.fillMeUp(ac1, values1); @@ -144,14 +147,11 @@ public BenchmarkState() { ac4 = new ArrayContainer(); ac4 = RandomUtil.fillMeUp(ac4, values4); - if (!(ac4 instanceof ArrayContainer)) - throw new RuntimeException("expected array container"); + if (!(ac4 instanceof ArrayContainer)) throw new RuntimeException("expected array container"); - if (!rc1.equals(ac1)) - throw new RuntimeException("first containers do not match"); + if (!rc1.equals(ac1)) throw new RuntimeException("first containers do not match"); - if (!rc2.equals(ac2)) - throw new RuntimeException("second containers do not match"); + if (!rc2.equals(ac2)) throw new RuntimeException("second containers do not match"); if (!rc1.andNot(rc2).equals(ac1.andNot(ac2))) throw new RuntimeException("andNots do not match"); @@ -161,8 +161,6 @@ public BenchmarkState() { throw new RuntimeException("andNots do not match"); if (!rc2.andNot(ac1).equals(ac2.andNot(ac1))) throw new RuntimeException("andNots do not match"); - } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicHorizontalOrBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicHorizontalOrBenchmark.java index c599a0765..f01798c17 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicHorizontalOrBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicHorizontalOrBenchmark.java @@ -1,9 +1,9 @@ package org.roaringbitmap.runcontainer; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.RunContainer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -11,36 +11,31 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.BitmapContainer; -import org.roaringbitmap.Container; -import org.roaringbitmap.RunContainer; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class BasicHorizontalOrBenchmark { private static Container horizontal_or(Iterator i) { - if (!i.hasNext()) - throw new RuntimeException("please provide data"); + if (!i.hasNext()) throw new RuntimeException("please provide data"); Container c = i.next(); - if (!i.hasNext()) - throw new RuntimeException("please provide more than one container"); + if (!i.hasNext()) throw new RuntimeException("please provide more than one container"); Container c2 = i.next(); c = c.lazyOR(c2); - while (i.hasNext()) - c = c.lazyIOR(i.next()); + while (i.hasNext()) c = c.lazyIOR(i.next()); c = c.repairAfterLazy(); return c; } - - @Benchmark public int horizontalOrRunContainer(BenchmarkState benchmarkState) { Container answer = horizontal_or(benchmarkState.rc.iterator()); - if (!answer.equals(benchmarkState.aggregate)) - throw new RuntimeException("bug"); + if (!answer.equals(benchmarkState.aggregate)) throw new RuntimeException("bug"); return answer.getCardinality(); } @@ -53,20 +48,17 @@ public int horizontalOrRunContainer_withconversion(BenchmarkState benchmarkState c = (BitmapContainer) c.lazyIOR(benchmarkState.rc.get(k)); } c = (BitmapContainer) c.repairAfterLazy(); - if (!c.equals(benchmarkState.aggregate)) - throw new RuntimeException("bug"); + if (!c.equals(benchmarkState.aggregate)) throw new RuntimeException("bug"); return c.getCardinality(); } @Benchmark public int horizontalOrBitmapContainer(BenchmarkState benchmarkState) { Container answer = horizontal_or(benchmarkState.ac.iterator()); - if (!answer.equals(benchmarkState.aggregate)) - throw new RuntimeException("bug"); + if (!answer.equals(benchmarkState.aggregate)) throw new RuntimeException("bug"); return answer.getCardinality(); } - @State(Scope.Benchmark) public static class BenchmarkState { public int bitsetperword = 63; @@ -76,7 +68,6 @@ public static class BenchmarkState { Random rand = new Random(); Container aggregate; - public BenchmarkState() { final int max = 1 << 16; final int howmanywords = (1 << 16) / 64; @@ -85,15 +76,13 @@ public BenchmarkState() { int[] values = RandomUtil.generateUniformHash(rand, bitsetperword * howmanywords, max); Container rct = new RunContainer(); rct = RandomUtil.fillMeUp(rct, values); - if (!(rct instanceof RunContainer)) - throw new RuntimeException("unexpected container type"); + if (!(rct instanceof RunContainer)) throw new RuntimeException("unexpected container type"); Container act = new ArrayContainer(); act = RandomUtil.fillMeUp(act, values); if (!(act instanceof BitmapContainer)) throw new RuntimeException("unexpected container type"); - if (!act.equals(rct)) - throw new RuntimeException("unequal containers"); + if (!act.equals(rct)) throw new RuntimeException("unequal containers"); if (act.serializedSizeInBytes() < rct.serializedSizeInBytes()) throw new RuntimeException("You cannot win"); rc.add(rct); @@ -101,8 +90,7 @@ public BenchmarkState() { } Container b1 = rc.get(0); Container b2 = ac.get(0); - if (!b1.equals(b2)) - throw new RuntimeException("bug 0"); + if (!b1.equals(b2)) throw new RuntimeException("bug 0"); for (int k = 1; k < N; ++k) { b1 = b1.lazyIOR(rc.get(1)); b2 = b2.lazyIOR(ac.get(1)); @@ -113,5 +101,4 @@ public BenchmarkState() { aggregate = horizontal_or(rc.iterator()); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicIteratorBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicIteratorBenchmark.java index 698ecff41..c8c56e413 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicIteratorBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicIteratorBenchmark.java @@ -1,7 +1,9 @@ package org.roaringbitmap.runcontainer; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.CharIterator; +import org.roaringbitmap.Container; +import org.roaringbitmap.RunContainer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,14 +11,12 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.CharIterator; -import org.roaringbitmap.Container; -import org.roaringbitmap.RunContainer; + +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) - public class BasicIteratorBenchmark { @Benchmark @@ -25,8 +25,7 @@ public int iteratorRunContainer(BenchmarkState benchmarkState) { throw new RuntimeException("Can't expect run containers to win if they are larger."); CharIterator si = benchmarkState.rc2.getCharIterator(); int answer = 0; - while (si.hasNext()) - answer += si.next() & 0xFFFF; + while (si.hasNext()) answer += si.next() & 0xFFFF; return answer; } @@ -34,8 +33,7 @@ public int iteratorRunContainer(BenchmarkState benchmarkState) { public int iteratorBitmapContainer(BenchmarkState benchmarkState) { CharIterator si = benchmarkState.ac2.getCharIterator(); int answer = 0; - while (si.hasNext()) - answer += si.next() & 0xFFFF; + while (si.hasNext()) answer += si.next() & 0xFFFF; return answer; } @@ -51,20 +49,13 @@ public BenchmarkState() { final int howmanywords = (1 << 16) / 64; int[] values2 = RandomUtil.generateUniformHash(rand, bitsetperword2 * howmanywords, max); - - rc2 = new RunContainer(); rc2 = RandomUtil.fillMeUp(rc2, values2); - ac2 = new ArrayContainer(); ac2 = RandomUtil.fillMeUp(ac2, values2); - - if (!rc2.equals(ac2)) - throw new RuntimeException("second containers do not match"); - + if (!rc2.equals(ac2)) throw new RuntimeException("second containers do not match"); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicOrContainerBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicOrContainerBenchmark.java index 447bcc9d1..f4fe450b1 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicOrContainerBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicOrContainerBenchmark.java @@ -1,7 +1,9 @@ package org.roaringbitmap.runcontainer; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.RunContainer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,14 +11,12 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.BitmapContainer; -import org.roaringbitmap.Container; -import org.roaringbitmap.RunContainer; + +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) - public class BasicOrContainerBenchmark { @Benchmark @@ -66,7 +66,6 @@ public static class BenchmarkState { Container rc1, rc2, rc3, ac1, ac2, ac3, ac4; Random rand = new Random(); - public BenchmarkState() { final int max = 1 << 16; final int howmanywords = (1 << 16) / 64; @@ -75,7 +74,6 @@ public BenchmarkState() { int[] values3 = RandomUtil.generateCrazyRun(rand, max); int[] values4 = RandomUtil.generateUniformHash(rand, bitsetperword3 * howmanywords, max); - rc1 = new RunContainer(); rc1 = RandomUtil.fillMeUp(rc1, values1); @@ -91,34 +89,26 @@ public BenchmarkState() { if (!(ac1 instanceof BitmapContainer)) throw new RuntimeException("expected bitmap container"); - ac2 = new ArrayContainer(); ac2 = RandomUtil.fillMeUp(ac2, values2); if (!(ac2 instanceof BitmapContainer)) throw new RuntimeException("expected bitmap container"); - ac3 = new ArrayContainer(); ac3 = RandomUtil.fillMeUp(ac3, values3); ac4 = new ArrayContainer(); ac4 = RandomUtil.fillMeUp(ac4, values4); - if (!(ac4 instanceof ArrayContainer)) - throw new RuntimeException("expected array container"); + if (!(ac4 instanceof ArrayContainer)) throw new RuntimeException("expected array container"); - if (!rc1.equals(ac1)) - throw new RuntimeException("first containers do not match"); + if (!rc1.equals(ac1)) throw new RuntimeException("first containers do not match"); - if (!rc2.equals(ac2)) - throw new RuntimeException("second containers do not match"); + if (!rc2.equals(ac2)) throw new RuntimeException("second containers do not match"); - if (!rc1.or(rc2).equals(ac1.or(ac2))) - throw new RuntimeException("ors do not match"); - if (!ac1.or(rc2).equals(ac1.or(ac2))) - throw new RuntimeException("ors do not match"); + if (!rc1.or(rc2).equals(ac1.or(ac2))) throw new RuntimeException("ors do not match"); + if (!ac1.or(rc2).equals(ac1.or(ac2))) throw new RuntimeException("ors do not match"); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicXorContainerBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicXorContainerBenchmark.java index b8421cd9b..038498f35 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicXorContainerBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BasicXorContainerBenchmark.java @@ -1,7 +1,9 @@ package org.roaringbitmap.runcontainer; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.RunContainer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,14 +11,12 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.BitmapContainer; -import org.roaringbitmap.Container; -import org.roaringbitmap.RunContainer; + +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) - public class BasicXorContainerBenchmark { @Benchmark @@ -31,7 +31,6 @@ public int xorBitmapContainerVSBitmapContainer(BenchmarkState benchmarkState) { return benchmarkState.ac1.xor(benchmarkState.ac2).getCardinality(); } - @Benchmark public int part2_xorRunContainerVSRunContainerContainer(BenchmarkState benchmarkState) { if (benchmarkState.rc2.serializedSizeInBytes() > benchmarkState.ac2.serializedSizeInBytes()) @@ -73,7 +72,6 @@ public static class BenchmarkState { Container rc1, rc2, rc3, ac1, ac2, ac3, ac4; Random rand = new Random(); - public BenchmarkState() { final int max = 1 << 16; final int howmanywords = (1 << 16) / 64; @@ -82,7 +80,6 @@ public BenchmarkState() { int[] values3 = RandomUtil.generateCrazyRun(rand, max); int[] values4 = RandomUtil.generateUniformHash(rand, bitsetperword3 * howmanywords, max); - rc1 = new RunContainer(); rc1 = RandomUtil.fillMeUp(rc1, values1); @@ -98,34 +95,26 @@ public BenchmarkState() { if (!(ac1 instanceof BitmapContainer)) throw new RuntimeException("expected bitmap container"); - ac2 = new ArrayContainer(); ac2 = RandomUtil.fillMeUp(ac2, values2); if (!(ac2 instanceof BitmapContainer)) throw new RuntimeException("expected bitmap container"); - ac3 = new ArrayContainer(); ac3 = RandomUtil.fillMeUp(ac3, values3); ac4 = new ArrayContainer(); ac4 = RandomUtil.fillMeUp(ac4, values4); - if (!(ac4 instanceof ArrayContainer)) - throw new RuntimeException("expected array container"); + if (!(ac4 instanceof ArrayContainer)) throw new RuntimeException("expected array container"); - if (!rc1.equals(ac1)) - throw new RuntimeException("first containers do not match"); + if (!rc1.equals(ac1)) throw new RuntimeException("first containers do not match"); - if (!rc2.equals(ac2)) - throw new RuntimeException("second containers do not match"); + if (!rc2.equals(ac2)) throw new RuntimeException("second containers do not match"); - if (!rc1.xor(rc2).equals(ac1.xor(ac2))) - throw new RuntimeException("xors do not match"); - if (!ac1.xor(rc2).equals(ac1.xor(ac2))) - throw new RuntimeException("xors do not match"); + if (!rc1.xor(rc2).equals(ac1.xor(ac2))) throw new RuntimeException("xors do not match"); + if (!ac1.xor(rc2).equals(ac1.xor(ac2))) throw new RuntimeException("xors do not match"); } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BitmapToRuncontainerConversions.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BitmapToRuncontainerConversions.java index b1a2a1006..c757980e1 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BitmapToRuncontainerConversions.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/BitmapToRuncontainerConversions.java @@ -1,7 +1,7 @@ package org.roaringbitmap.runcontainer; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.RunContainer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -9,57 +9,55 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.BitmapContainer; -import org.roaringbitmap.RunContainer; + +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) - public class BitmapToRuncontainerConversions { /* * These are commented out in BitmapContainer and soon be be deleted - * + * * @Benchmark public int numberOfRunsData1(BenchmarkState benchmarkState) { return * benchmarkState.ac1.numberOfRuns(); } - * + * * @Benchmark public int numberOfRunsData2(BenchmarkState benchmarkState) { return * benchmarkState.ac2.numberOfRuns(); } - * - * + * + * * @Benchmark public int numberOfRunsOld1(BenchmarkState benchmarkState) { return * benchmarkState.ac1.numberOfRuns_old(); } - * + * * @Benchmark public int numberOfRunOld2(BenchmarkState benchmarkState) { return * benchmarkState.ac2.numberOfRuns_old(); } - * + * * @Benchmark public int numberOfRunsLowerBound1(BenchmarkState benchmarkState) { return * benchmarkState.ac1.numberOfRunsLowerBound(); } - * - * + * + * * @Benchmark public int numberOfRunsLowerBound2(BenchmarkState benchmarkState) { return * benchmarkState.ac2.numberOfRunsLowerBound(); } - * + * */ @Benchmark public int numberOfRunsLowerBound1281(BenchmarkState benchmarkState) { return benchmarkState.ac1.numberOfRunsLowerBound(1000); } - @Benchmark public int numberOfRunsLowerBound1282(BenchmarkState benchmarkState) { return benchmarkState.ac2.numberOfRunsLowerBound(1000); } - /* * soon to be deleted... - * + * * @Benchmark public int numberOfRunsLowerBound5121(BenchmarkState benchmarkState) { return * benchmarkState.ac1.numberOfRunsLowerBound512(10); } - * - * + * + * * @Benchmark public int numberOfRunsLowerBound5122(BenchmarkState benchmarkState) { return * benchmarkState.ac2.numberOfRunsLowerBound512(1000); } */ @@ -69,22 +67,21 @@ public int numberOfRunsAdjustment(BenchmarkState benchmarkState) { return benchmarkState.ac2.numberOfRunsAdjustment(); } - /* * soon to be deleted... - * + * * @Benchmark public int numberOfRunsAdjustmentUnrolled(BenchmarkState benchmarkState) { return * benchmarkState.ac2.numberOfRunsAdjustmentUnrolled(); } - * - * + * + * * @Benchmark public int numberOfRunsLowerBoundUnrolled(BenchmarkState benchmarkState) { return * benchmarkState.ac2.numberOfRunsLowerBoundUnrolled(); } - * - * + * + * * @Benchmark public int numberOfRunsLowerBoundUnrolled2(BenchmarkState benchmarkState) { return * benchmarkState.ac2.numberOfRunsLowerBoundUnrolled2(); } - * - * + * + * * @Benchmark public int numberOfRunsLowerBoundUnrolled2threshold1000(BenchmarkState * benchmarkState) { return benchmarkState.ac2.numberOfRunsLowerBoundUnrolled2(1000); } */ @@ -94,8 +91,6 @@ public int numberOfRunsLowerBoundThreshold1000(BenchmarkState benchmarkState) { return benchmarkState.ac2.numberOfRunsLowerBound(1000); } - - @Benchmark public int runOptimize(BenchmarkState benchmarkState) { return benchmarkState.ac2.runOptimize() instanceof RunContainer ? 1 : 0; @@ -104,7 +99,7 @@ public int runOptimize(BenchmarkState benchmarkState) { /* * @Benchmark public int runOptimizeOld(BenchmarkState benchmarkState) { return * benchmarkState.ac2.runOptimize_old() instanceof RunContainer ? 1 : 0; } - * + * */ @Benchmark @@ -115,11 +110,9 @@ public int runOptimize1(BenchmarkState benchmarkState) { /* * @Benchmark public int runOptimizeOld1(BenchmarkState benchmarkState) { return * benchmarkState.ac1.runOptimize_old() instanceof RunContainer ? 1 : 0; } - * + * */ - - @State(Scope.Benchmark) public static class BenchmarkState { public int offvalues = 32; @@ -129,7 +122,6 @@ public static class BenchmarkState { BitmapContainer ac1, ac2; Random rand = new Random(); - public BenchmarkState() { final int max = 1 << 16; final int howmanywords = (1 << 16) / 64; @@ -141,8 +133,6 @@ public BenchmarkState() { ac2 = new BitmapContainer(); ac2 = (BitmapContainer) RandomUtil.fillMeUp(ac2, values2); - } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/GetCardinalityMappeableContainerBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/GetCardinalityMappeableContainerBenchmark.java index dbd09623f..903525730 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/GetCardinalityMappeableContainerBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/GetCardinalityMappeableContainerBenchmark.java @@ -1,9 +1,17 @@ package org.roaringbitmap.runcontainer; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.buffer.MappeableContainer; import org.roaringbitmap.buffer.MappeableRunContainer; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + import java.util.Random; import java.util.concurrent.TimeUnit; @@ -54,10 +62,18 @@ public BenchmarkState() { mc3 = new MappeableRunContainer(); mc4 = new MappeableRunContainer(); - for (int i : values1) { mc1.add((char) i); } - for (int i : values2) { mc2.add((char) i); } - for (int i : values3) { mc3.add((char) i); } - for (int i : values4) { mc4.add((char) i); } + for (int i : values1) { + mc1.add((char) i); + } + for (int i : values2) { + mc2.add((char) i); + } + for (int i : values3) { + mc3.add((char) i); + } + for (int i : values4) { + mc4.add((char) i); + } } } -} \ No newline at end of file +} diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/MappedRunContainerRealDataBenchmarkRunOptimize.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/MappedRunContainerRealDataBenchmarkRunOptimize.java index cd67a06d5..9793bc109 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/MappedRunContainerRealDataBenchmarkRunOptimize.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/MappedRunContainerRealDataBenchmarkRunOptimize.java @@ -1,12 +1,7 @@ package org.roaringbitmap.runcontainer; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.ZipRealDataRetriever; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -16,8 +11,13 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.ZipRealDataRetriever; -import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -81,7 +81,6 @@ public int mutable_serializeToBAOSNoClonePreOpti(BenchmarkState benchmarkState) return bos.size(); } - @Benchmark public int mutable_runOptimizeAndserializeToBAOSFromClone(BenchmarkState benchmarkState) throws IOException { @@ -98,10 +97,20 @@ public int mutable_runOptimizeAndserializeToBAOSFromClone(BenchmarkState benchma @State(Scope.Benchmark) public static class BenchmarkState { - @Param({// putting the data sets in alpha. order - "census-income", "census1881", "dimension_008", "dimension_003", "dimension_033", - "uscensus2000", "weather_sept_85", "wikileaks-noquotes", "census-income_srt", - "census1881_srt", "weather_sept_85_srt", "wikileaks-noquotes_srt"}) + @Param({ // putting the data sets in alpha. order + "census-income", + "census1881", + "dimension_008", + "dimension_003", + "dimension_033", + "uscensus2000", + "weather_sept_85", + "wikileaks-noquotes", + "census-income_srt", + "census1881_srt", + "weather_sept_85_srt", + "wikileaks-noquotes_srt" + }) String dataset; List mac = new ArrayList(); @@ -123,7 +132,5 @@ public void setup() throws Exception { mrc.add(mopti); } } - } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RandomUtil.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RandomUtil.java index af83d947d..9613e0c92 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RandomUtil.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RandomUtil.java @@ -1,29 +1,26 @@ package org.roaringbitmap.runcontainer; +import org.roaringbitmap.Container; + import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.Random; -import org.roaringbitmap.Container; - public class RandomUtil { /** * generates randomly N distinct integers from 0 to Max. */ static int[] generateUniformHash(Random rand, int N, int Max) { - if (N > Max) - throw new RuntimeException("not possible"); + if (N > Max) throw new RuntimeException("not possible"); if (N > Max / 2) { return negate(generateUniformHash(rand, Max - N, Max), Max); } int[] ans = new int[N]; HashSet s = new HashSet(); - while (s.size() < N) - s.add(rand.nextInt(Max)); + while (s.size() < N) s.add(rand.nextInt(Max)); Iterator i = s.iterator(); - for (int k = 0; k < N; ++k) - ans[k] = i.next().intValue(); + for (int k = 0; k < N; ++k) ans[k] = i.next().intValue(); Arrays.sort(ans); return ans; } @@ -31,8 +28,7 @@ static int[] generateUniformHash(Random rand, int N, int Max) { static int[] generateCrazyRun(Random rand, int Max) { int[] answer = new int[Max / 2]; int start = Max / 3; - for (int k = 0; k < answer.length; ++k) - answer[k] = k + start; + for (int k = 0; k < answer.length; ++k) answer[k] = k + start; return answer; } @@ -45,25 +41,19 @@ static int[] negate(int[] x, int Max) { int c = 0; for (int j = 0; j < x.length; ++j) { int v = x[j]; - for (; i < v; ++i) - ans[c++] = i; + for (; i < v; ++i) ans[c++] = i; ++i; } - while (c < ans.length) - ans[c++] = i++; + while (c < ans.length) ans[c++] = i++; return ans; } public static Container fillMeUp(Container c, int[] values) { - if (c.getCardinality() != 0) - throw new RuntimeException("Please provide an empty container. "); + if (c.getCardinality() != 0) throw new RuntimeException("Please provide an empty container. "); if (values.length == 0) throw new RuntimeException("You are trying to create an empty bitmap! "); - for (int k = 0; k < values.length; ++k) - c = c.add((char) values[k]); - if (c.getCardinality() != values.length) - throw new RuntimeException("add failure"); + for (int k = 0; k < values.length; ++k) c = c.add((char) values[k]); + if (c.getCardinality() != values.length) throw new RuntimeException("add failure"); return c; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndBenchmark.java index c3a002547..dd0da2f17 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndBenchmark.java @@ -1,8 +1,7 @@ package org.roaringbitmap.runcontainer; -import java.util.ArrayList; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.Container; +import org.roaringbitmap.RoaringBitmap; import io.druid.extendedset.intset.ConciseSet; import org.openjdk.jmh.annotations.Benchmark; @@ -11,8 +10,10 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.Container; -import org.roaringbitmap.RoaringBitmap; + +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -30,8 +31,9 @@ static ConciseSet toConcise(int[] dat) { public int AndRunContainer(BenchmarkState benchmarkState) { int answer = 0; for (int k = 1; k < benchmarkState.rc.size(); ++k) - answer += RoaringBitmap.and(benchmarkState.rc.get(k - 1), benchmarkState.rc.get(k)) - .getCardinality(); + answer += + RoaringBitmap.and(benchmarkState.rc.get(k - 1), benchmarkState.rc.get(k)) + .getCardinality(); return answer; } @@ -39,8 +41,9 @@ public int AndRunContainer(BenchmarkState benchmarkState) { public int AndBitmapContainer(BenchmarkState benchmarkState) { int answer = 0; for (int k = 1; k < benchmarkState.ac.size(); ++k) - answer += RoaringBitmap.and(benchmarkState.ac.get(k - 1), benchmarkState.ac.get(k)) - .getCardinality(); + answer += + RoaringBitmap.and(benchmarkState.ac.get(k - 1), benchmarkState.ac.get(k)) + .getCardinality(); return answer; } @@ -62,7 +65,6 @@ public static class BenchmarkState { Random rand = new Random(); Container aggregate; - public BenchmarkState() { int N = 30; Random rand = new Random(1234); @@ -72,7 +74,7 @@ public BenchmarkState() { for (int z = 0; z < 50; ++z) { int end = start + rand.nextInt(10000); - rb.add((long)start, (long)end); + rb.add((long) start, (long) end); start = end + rand.nextInt(1000); } cc.add(toConcise(rb.toArray())); @@ -95,9 +97,7 @@ public BenchmarkState() { rb = rb.clone(); rb.runOptimize(); rc.add(rb); - } } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndNotBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndNotBenchmark.java index d6a78a932..b8b505fc4 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndNotBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayAndNotBenchmark.java @@ -1,8 +1,7 @@ package org.roaringbitmap.runcontainer; -import java.util.ArrayList; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.Container; +import org.roaringbitmap.RoaringBitmap; import io.druid.extendedset.intset.ConciseSet; import org.openjdk.jmh.annotations.Benchmark; @@ -11,8 +10,10 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.Container; -import org.roaringbitmap.RoaringBitmap; + +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -30,8 +31,9 @@ static ConciseSet toConcise(int[] dat) { public int AndNotRunContainer(BenchmarkState benchmarkState) { int answer = 0; for (int k = 1; k < benchmarkState.rc.size(); ++k) - answer += RoaringBitmap.andNot(benchmarkState.rc.get(k - 1), benchmarkState.rc.get(k)) - .getCardinality(); + answer += + RoaringBitmap.andNot(benchmarkState.rc.get(k - 1), benchmarkState.rc.get(k)) + .getCardinality(); return answer; } @@ -39,8 +41,9 @@ public int AndNotRunContainer(BenchmarkState benchmarkState) { public int AndNotBitmapContainer(BenchmarkState benchmarkState) { int answer = 0; for (int k = 1; k < benchmarkState.ac.size(); ++k) - answer += RoaringBitmap.andNot(benchmarkState.ac.get(k - 1), benchmarkState.ac.get(k)) - .getCardinality(); + answer += + RoaringBitmap.andNot(benchmarkState.ac.get(k - 1), benchmarkState.ac.get(k)) + .getCardinality(); return answer; } @@ -62,7 +65,6 @@ public static class BenchmarkState { Random rand = new Random(); Container aggregate; - public BenchmarkState() { int N = 30; Random rand = new Random(1234); @@ -72,7 +74,7 @@ public BenchmarkState() { for (int z = 0; z < 50; ++z) { int end = start + rand.nextInt(10000); - rb.add((long)start, (long)end); + rb.add((long) start, (long) end); start = end + rand.nextInt(1000); } cc.add(toConcise(rb.toArray())); @@ -95,9 +97,7 @@ public BenchmarkState() { rb = rb.clone(); rb.runOptimize(); rc.add(rb); - } } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayOrBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayOrBenchmark.java index fe211fadc..9613a88c1 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayOrBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayOrBenchmark.java @@ -1,8 +1,7 @@ package org.roaringbitmap.runcontainer; -import java.util.ArrayList; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.Container; +import org.roaringbitmap.RoaringBitmap; import io.druid.extendedset.intset.ConciseSet; import org.openjdk.jmh.annotations.Benchmark; @@ -11,8 +10,10 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.Container; -import org.roaringbitmap.RoaringBitmap; + +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -62,7 +63,6 @@ public static class BenchmarkState { Random rand = new Random(); Container aggregate; - public BenchmarkState() { int N = 30; Random rand = new Random(1234); @@ -72,7 +72,7 @@ public BenchmarkState() { for (int z = 0; z < 50; ++z) { int end = start + rand.nextInt(10000); - rb.add((long)start, (long)end); + rb.add((long) start, (long) end); start = end + rand.nextInt(1000); } cc.add(toConcise(rb.toArray())); @@ -95,9 +95,7 @@ public BenchmarkState() { rb = rb.clone(); rb.runOptimize(); rc.add(rb); - } } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayXorBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayXorBenchmark.java index d17f3512b..38f017a06 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayXorBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunArrayXorBenchmark.java @@ -1,8 +1,7 @@ package org.roaringbitmap.runcontainer; -import java.util.ArrayList; -import java.util.Random; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.Container; +import org.roaringbitmap.RoaringBitmap; import io.druid.extendedset.intset.ConciseSet; import org.openjdk.jmh.annotations.Benchmark; @@ -11,8 +10,10 @@ import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.Container; -import org.roaringbitmap.RoaringBitmap; + +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -30,8 +31,9 @@ static ConciseSet toConcise(int[] dat) { public int XorRunContainer(BenchmarkState benchmarkState) { int answer = 0; for (int k = 1; k < benchmarkState.rc.size(); ++k) - answer += RoaringBitmap.xor(benchmarkState.rc.get(k - 1), benchmarkState.rc.get(k)) - .getCardinality(); + answer += + RoaringBitmap.xor(benchmarkState.rc.get(k - 1), benchmarkState.rc.get(k)) + .getCardinality(); return answer; } @@ -39,8 +41,9 @@ public int XorRunContainer(BenchmarkState benchmarkState) { public int XorBitmapContainer(BenchmarkState benchmarkState) { int answer = 0; for (int k = 1; k < benchmarkState.ac.size(); ++k) - answer += RoaringBitmap.xor(benchmarkState.ac.get(k - 1), benchmarkState.ac.get(k)) - .getCardinality(); + answer += + RoaringBitmap.xor(benchmarkState.ac.get(k - 1), benchmarkState.ac.get(k)) + .getCardinality(); return answer; } @@ -62,7 +65,6 @@ public static class BenchmarkState { Random rand = new Random(); Container aggregate; - public BenchmarkState() { int N = 30; Random rand = new Random(1234); @@ -72,7 +74,7 @@ public BenchmarkState() { for (int z = 0; z < 50; ++z) { int end = start + rand.nextInt(10000); - rb.add((long)start, (long)end); + rb.add((long) start, (long) end); start = end + rand.nextInt(1000); } cc.add(toConcise(rb.toArray())); @@ -95,9 +97,7 @@ public BenchmarkState() { rb = rb.clone(); rb.runOptimize(); rc.add(rb); - } } } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunContainerRealDataBenchmarkRunOptimize.java b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunContainerRealDataBenchmarkRunOptimize.java index 61708e0ec..effcbd591 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunContainerRealDataBenchmarkRunOptimize.java +++ b/jmh/src/jmh/java/org/roaringbitmap/runcontainer/RunContainerRealDataBenchmarkRunOptimize.java @@ -1,11 +1,7 @@ package org.roaringbitmap.runcontainer; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.ZipRealDataRetriever; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -15,8 +11,12 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.ZipRealDataRetriever; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -107,10 +107,20 @@ public int runOptimizeAndserializeToBAOSFromClone(BenchmarkState benchmarkState) @State(Scope.Benchmark) public static class BenchmarkState { - @Param({// putting the data sets in alpha. order - "census-income", "census1881", "dimension_008", "dimension_003", "dimension_033", - "uscensus2000", "weather_sept_85", "wikileaks-noquotes", "census-income_srt", - "census1881_srt", "weather_sept_85_srt", "wikileaks-noquotes_srt"}) + @Param({ // putting the data sets in alpha. order + "census-income", + "census1881", + "dimension_008", + "dimension_003", + "dimension_033", + "uscensus2000", + "weather_sept_85", + "wikileaks-noquotes", + "census-income_srt", + "census1881_srt", + "weather_sept_85_srt", + "wikileaks-noquotes_srt" + }) String dataset; ArrayList ac = new ArrayList(); @@ -132,7 +142,5 @@ public void setup() throws Exception { rc.add(opti); } } - } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/serialization/Roaring64BmpSerializationBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/serialization/Roaring64BmpSerializationBenchmark.java index af7166c25..43b490d27 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/serialization/Roaring64BmpSerializationBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/serialization/Roaring64BmpSerializationBenchmark.java @@ -1,5 +1,14 @@ package org.roaringbitmap.serialization; +import org.roaringbitmap.longlong.Roaring64Bitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -8,13 +17,6 @@ import java.util.LinkedHashSet; import java.util.Random; import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.longlong.Roaring64Bitmap; @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -24,8 +26,8 @@ public class Roaring64BmpSerializationBenchmark { @Benchmark public int testDeserialize(BenchmarkState benchmarkState) throws IOException { benchmarkState.presoutbb.rewind(); - try (ByteBufferBackedInputStream in = new ByteBufferBackedInputStream( - benchmarkState.presoutbb)) { + try (ByteBufferBackedInputStream in = + new ByteBufferBackedInputStream(benchmarkState.presoutbb)) { benchmarkState.bitmap_b.deserialize(new DataInputStream(in)); } catch (Exception e) { throw new RuntimeException(e); @@ -37,8 +39,8 @@ public int testDeserialize(BenchmarkState benchmarkState) throws IOException { @Benchmark public int testSerialize(BenchmarkState benchmarkState) throws IOException { benchmarkState.outbb.rewind(); - try (ByteBufferBackedOutputStream out = new ByteBufferBackedOutputStream( - benchmarkState.outbb)) { + try (ByteBufferBackedOutputStream out = + new ByteBufferBackedOutputStream(benchmarkState.outbb)) { benchmarkState.bitmap_a.serialize(new DataOutputStream(out)); } catch (Exception e) { throw new RuntimeException(e); @@ -57,7 +59,6 @@ public static class BenchmarkState { final ByteBuffer presoutbb; - public BenchmarkState() { final long[] data = takeSortedAndDistinct(new Random(0xcb000a2b9b5bdfb6l), 100000); @@ -107,5 +108,3 @@ private long[] toArray(LinkedHashSet longLinkedHashSet) { } } } - - diff --git a/jmh/src/jmh/java/org/roaringbitmap/serialization/SerializationBenchmark.java b/jmh/src/jmh/java/org/roaringbitmap/serialization/SerializationBenchmark.java index cb47ffaa9..2da848865 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/serialization/SerializationBenchmark.java +++ b/jmh/src/jmh/java/org/roaringbitmap/serialization/SerializationBenchmark.java @@ -1,5 +1,15 @@ package org.roaringbitmap.serialization; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.buffer.MutableRoaringBitmap; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -11,26 +21,16 @@ import java.util.Random; import java.util.concurrent.TimeUnit; -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.buffer.MutableRoaringBitmap; - - @State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class SerializationBenchmark { - @BenchmarkMode(Mode.AverageTime) @Benchmark public int testDeserialize(BenchmarkState benchmarkState) throws IOException { benchmarkState.presoutbb.rewind(); - try(ByteBufferBackedInputStream in = new ByteBufferBackedInputStream(benchmarkState.presoutbb)) { + try (ByteBufferBackedInputStream in = + new ByteBufferBackedInputStream(benchmarkState.presoutbb)) { benchmarkState.bitmap_b.deserialize(new DataInputStream(in)); } return benchmarkState.presoutbb.limit(); @@ -40,35 +40,35 @@ public int testDeserialize(BenchmarkState benchmarkState) throws IOException { @Benchmark public int testMutableDeserializeMutable(BenchmarkState benchmarkState) throws IOException { benchmarkState.presoutbb.rewind(); - try(ByteBufferBackedInputStream in = new ByteBufferBackedInputStream(benchmarkState.presoutbb)) { + try (ByteBufferBackedInputStream in = + new ByteBufferBackedInputStream(benchmarkState.presoutbb)) { benchmarkState.bitmap_br.deserialize(new DataInputStream(in)); } return benchmarkState.presoutbb.limit(); } - @BenchmarkMode(Mode.AverageTime) @Benchmark public int testSerialize(BenchmarkState benchmarkState) throws IOException { benchmarkState.outbb.rewind(); - try(ByteBufferBackedOutputStream out = new ByteBufferBackedOutputStream(benchmarkState.outbb)) { + try (ByteBufferBackedOutputStream out = + new ByteBufferBackedOutputStream(benchmarkState.outbb)) { benchmarkState.bitmap_a.serialize(new DataOutputStream(out)); } return benchmarkState.outbb.limit(); } - @BenchmarkMode(Mode.AverageTime) @Benchmark public int testMutableSerialize(BenchmarkState benchmarkState) throws IOException { benchmarkState.outbb.rewind(); - try(ByteBufferBackedOutputStream out = new ByteBufferBackedOutputStream(benchmarkState.outbb)) { + try (ByteBufferBackedOutputStream out = + new ByteBufferBackedOutputStream(benchmarkState.outbb)) { benchmarkState.bitmap_ar.serialize(new DataOutputStream(out)); } return benchmarkState.outbb.limit(); } - @State(Scope.Benchmark) public static class BenchmarkState { @@ -84,7 +84,6 @@ public static class BenchmarkState { final ByteBuffer presoutbb; - public BenchmarkState() { final int[] data = takeSortedAndDistinct(new Random(0xcb000a2b9b5bdfb6l), 100000); @@ -130,10 +129,8 @@ private int[] toArray(LinkedHashSet integers) { return ints; } } - } - class ByteBufferBackedInputStream extends InputStream { ByteBuffer buf; @@ -182,7 +179,6 @@ public int read(byte[] bytes, int off, int len) throws IOException { } } - class ByteBufferBackedOutputStream extends OutputStream { ByteBuffer buf; @@ -204,7 +200,4 @@ public synchronized void write(byte[] bytes) throws IOException { public synchronized void write(byte[] bytes, int off, int len) throws IOException { buf.put(bytes, off, len); } - } - - diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkAnd.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkAnd.java index d3ea92eb0..0ca08b564 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkAnd.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkAnd.java @@ -1,12 +1,13 @@ package org.roaringbitmap.spe150271.roaring; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.spe150271.roaring.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.spe150271.roaring.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -20,5 +21,4 @@ public int pairwiseAnd(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkOr.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkOr.java index 76721c79a..e3e40221f 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkOr.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkOr.java @@ -1,13 +1,14 @@ package org.roaringbitmap.spe150271.roaring; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.wrapper.BitmapIterator; +import org.roaringbitmap.spe150271.roaring.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.wrapper.BitmapIterator; -import org.roaringbitmap.spe150271.roaring.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -33,5 +34,4 @@ public int pairwiseOr_NoCardinality(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkWideOrNaive.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkWideOrNaive.java index c8e8a78a1..092fd926d 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkWideOrNaive.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/RealDataBenchmarkWideOrNaive.java @@ -1,13 +1,14 @@ package org.roaringbitmap.spe150271.roaring; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.wrapper.BitmapAggregator; +import org.roaringbitmap.spe150271.roaring.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.wrapper.BitmapAggregator; -import org.roaringbitmap.spe150271.roaring.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -18,5 +19,4 @@ public int wideOr_naive(RealDataBenchmarkState bs) { BitmapAggregator aggregator = bs.bitmaps.get(0).naiveOrAggregator(); return aggregator.aggregate(bs.bitmaps).cardinality(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/state/RealDataBenchmarkState.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/state/RealDataBenchmarkState.java index 2ddea6812..089379bc7 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/state/RealDataBenchmarkState.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/roaring/state/RealDataBenchmarkState.java @@ -11,22 +11,23 @@ @State(Scope.Benchmark) public class RealDataBenchmarkState extends org.roaringbitmap.AbstractBenchmarkState { - @Param({// putting the data sets in alpha. order - CENSUS_INCOME}) + @Param({ // putting the data sets in alpha. order + CENSUS_INCOME + }) public String dataset; @Param({ROARING}) public String type; - @Param({"false",}) + @Param({ + "false", + }) public boolean immutable; - public RealDataBenchmarkState() {} @Setup public void setup() throws Exception { super.setup(dataset, type, immutable); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkAnd.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkAnd.java index 9954142a7..d6f65697a 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkAnd.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkAnd.java @@ -1,12 +1,13 @@ package org.roaringbitmap.spe150271.runroaring; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.spe150271.runroaring.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.spe150271.runroaring.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -20,5 +21,4 @@ public int pairwiseAnd(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkOr.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkOr.java index 854d9f10e..ae62ef34d 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkOr.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkOr.java @@ -1,13 +1,14 @@ package org.roaringbitmap.spe150271.runroaring; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.wrapper.BitmapIterator; +import org.roaringbitmap.spe150271.runroaring.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.wrapper.BitmapIterator; -import org.roaringbitmap.spe150271.runroaring.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -33,5 +34,4 @@ public int pairwiseOr_NoCardinality(RealDataBenchmarkState bs) { } return total; } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkWideOrNaive.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkWideOrNaive.java index 9c425c3b3..05a5c4b22 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkWideOrNaive.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/RealDataBenchmarkWideOrNaive.java @@ -1,13 +1,14 @@ package org.roaringbitmap.spe150271.runroaring; -import java.util.concurrent.TimeUnit; +import org.roaringbitmap.realdata.wrapper.BitmapAggregator; +import org.roaringbitmap.spe150271.runroaring.state.RealDataBenchmarkState; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.roaringbitmap.realdata.wrapper.BitmapAggregator; -import org.roaringbitmap.spe150271.runroaring.state.RealDataBenchmarkState; + +import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) @@ -18,5 +19,4 @@ public int wideOr_naive(RealDataBenchmarkState bs) { BitmapAggregator aggregator = bs.bitmaps.get(0).naiveOrAggregator(); return aggregator.aggregate(bs.bitmaps).cardinality(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/state/RealDataBenchmarkState.java b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/state/RealDataBenchmarkState.java index 4389886af..5a7122f1b 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/state/RealDataBenchmarkState.java +++ b/jmh/src/jmh/java/org/roaringbitmap/spe150271/runroaring/state/RealDataBenchmarkState.java @@ -11,22 +11,23 @@ @State(Scope.Benchmark) public class RealDataBenchmarkState extends org.roaringbitmap.AbstractBenchmarkState { - @Param({// putting the data sets in alpha. order - CENSUS_INCOME}) + @Param({ // putting the data sets in alpha. order + CENSUS_INCOME + }) public String dataset; @Param({ROARING_WITH_RUN}) public String type; - @Param({"false",}) + @Param({ + "false", + }) public boolean immutable; - public RealDataBenchmarkState() {} @Setup public void setup() throws Exception { super.setup(dataset, type, immutable); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/writer/WriteSequential.java b/jmh/src/jmh/java/org/roaringbitmap/writer/WriteSequential.java index 53930733b..5cfbdb5b7 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/writer/WriteSequential.java +++ b/jmh/src/jmh/java/org/roaringbitmap/writer/WriteSequential.java @@ -1,8 +1,17 @@ package org.roaringbitmap.writer; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.RoaringBitmapWriter; -import org.openjdk.jmh.annotations.*; -import org.roaringbitmap.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; import java.util.Arrays; import java.util.Random; @@ -25,8 +34,8 @@ RoaringBitmapWriter newWriter() { RoaringBitmapWriter newWriter() { return RoaringBitmapWriter.writer().optimiseForArrays().get(); } - } - ; + }; + abstract RoaringBitmapWriter newWriter(); } @@ -92,5 +101,4 @@ public RoaringBitmap incrementalUseOrderedWriter() { writer.flush(); return writer.getUnderlying(); } - } diff --git a/jmh/src/jmh/java/org/roaringbitmap/writer/WriteUnordered.java b/jmh/src/jmh/java/org/roaringbitmap/writer/WriteUnordered.java index b3c087b93..0d18014a3 100644 --- a/jmh/src/jmh/java/org/roaringbitmap/writer/WriteUnordered.java +++ b/jmh/src/jmh/java/org/roaringbitmap/writer/WriteUnordered.java @@ -1,10 +1,23 @@ package org.roaringbitmap.writer; -import org.openjdk.jmh.annotations.*; import org.roaringbitmap.RoaringBitmap; import org.roaringbitmap.Util; -import java.util.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; import java.util.concurrent.TimeUnit; @State(Scope.Benchmark) @@ -14,6 +27,7 @@ public class WriteUnordered { @Param({"10000", "100000", "1000000", "10000000"}) int size; + @Param({"0.1", "0.5", "0.9"}) double randomness; @@ -76,4 +90,3 @@ public RoaringBitmap partialSortThenBitmapOf() { return RoaringBitmap.bitmapOf(copy); } } - diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNotTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNotTest.java index 7d8fa6d88..8fa5c5599 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNotTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndNotTest.java @@ -1,24 +1,43 @@ package org.roaringbitmap.realdata; -import com.google.common.collect.ImmutableMap; - -import java.util.Map; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeFalse; -import static org.roaringbitmap.RealDataset.*; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.CONCISE; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.WAH; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; public class RealDataBenchmarkAndNotTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, 5666586).put(CENSUS1881, 1003836) - .put(DIMENSION_008, 2721459).put(DIMENSION_003, 3866831).put(DIMENSION_033, 3866842) - .put(USCENSUS2000, 5970).put(WEATHER_SEPT_85, 11960876).put(WIKILEAKS_NOQUOTES, 271605) - .put(CENSUS_INCOME_SRT, 5164671).put(CENSUS1881_SRT, 679375) - .put(WEATHER_SEPT_85_SRT, 14935706).put(WIKILEAKS_NOQUOTES_SRT, 286904).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, 5666586) + .put(CENSUS1881, 1003836) + .put(DIMENSION_008, 2721459) + .put(DIMENSION_003, 3866831) + .put(DIMENSION_033, 3866842) + .put(USCENSUS2000, 5970) + .put(WEATHER_SEPT_85, 11960876) + .put(WIKILEAKS_NOQUOTES, 271605) + .put(CENSUS_INCOME_SRT, 5164671) + .put(CENSUS1881_SRT, 679375) + .put(WEATHER_SEPT_85_SRT, 14935706) + .put(WIKILEAKS_NOQUOTES_SRT, 286904) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndTest.java index e0b8c33fb..85d3c8bb7 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkAndTest.java @@ -1,21 +1,40 @@ package org.roaringbitmap.realdata; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import com.google.common.collect.ImmutableMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.roaringbitmap.RealDataset.*; - - public class RealDataBenchmarkAndTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, 1245448).put(CENSUS1881, 23) - .put(DIMENSION_008, 112317).put(DIMENSION_003, 0).put(DIMENSION_033, 0) - .put(USCENSUS2000, 0).put(WEATHER_SEPT_85, 642019).put(WIKILEAKS_NOQUOTES, 3327) - .put(CENSUS_INCOME_SRT, 927715).put(CENSUS1881_SRT, 206).put(WEATHER_SEPT_85_SRT, 1062989) - .put(WIKILEAKS_NOQUOTES_SRT, 152).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, 1245448) + .put(CENSUS1881, 23) + .put(DIMENSION_008, 112317) + .put(DIMENSION_003, 0) + .put(DIMENSION_033, 0) + .put(USCENSUS2000, 0) + .put(WEATHER_SEPT_85, 642019) + .put(WIKILEAKS_NOQUOTES, 3327) + .put(CENSUS_INCOME_SRT, 927715) + .put(CENSUS1881_SRT, 206) + .put(WEATHER_SEPT_85_SRT, 1062989) + .put(WIKILEAKS_NOQUOTES_SRT, 152) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkForEachTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkForEachTest.java index 0ce9f6a5c..577fecb95 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkForEachTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkForEachTest.java @@ -1,24 +1,45 @@ package org.roaringbitmap.realdata; -import com.google.common.collect.ImmutableMap; - -import java.util.Map; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeFalse; -import static org.roaringbitmap.RealDataset.*; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.*; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.CONCISE; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH32; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.WAH; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; public class RealDataBenchmarkForEachTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, -942184551) - .put(CENSUS1881, 246451066).put(DIMENSION_008, -423436314).put(DIMENSION_003, -1287135055) - .put(DIMENSION_033, -1287135055).put(USCENSUS2000, -1260727955) - .put(WEATHER_SEPT_85, 644036874).put(WIKILEAKS_NOQUOTES, 413846869) - .put(CENSUS_INCOME_SRT, -679313956).put(CENSUS1881_SRT, 445584405) - .put(WEATHER_SEPT_85_SRT, 1132748056).put(WIKILEAKS_NOQUOTES_SRT, 1921022163).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, -942184551) + .put(CENSUS1881, 246451066) + .put(DIMENSION_008, -423436314) + .put(DIMENSION_003, -1287135055) + .put(DIMENSION_033, -1287135055) + .put(USCENSUS2000, -1260727955) + .put(WEATHER_SEPT_85, 644036874) + .put(WIKILEAKS_NOQUOTES, 413846869) + .put(CENSUS_INCOME_SRT, -679313956) + .put(CENSUS1881_SRT, 445584405) + .put(WEATHER_SEPT_85_SRT, 1132748056) + .put(WIKILEAKS_NOQUOTES_SRT, 1921022163) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIOrTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIOrTest.java index c8ebfa13f..2bba7e5a8 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIOrTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIOrTest.java @@ -1,23 +1,47 @@ package org.roaringbitmap.realdata; -import com.google.common.collect.ImmutableMap; - -import java.util.Map; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeFalse; -import static org.roaringbitmap.RealDataset.*; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.*; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.CONCISE; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH32; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING_WITH_RUN; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.WAH; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; public class RealDataBenchmarkIOrTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, 199523).put(CENSUS1881, 988653) - .put(DIMENSION_008, 148278).put(DIMENSION_003, 3866847).put(DIMENSION_033, 3866847) - .put(USCENSUS2000, 5985).put(WEATHER_SEPT_85, 1015367).put(WIKILEAKS_NOQUOTES, 242540) - .put(CENSUS_INCOME_SRT, 199523).put(CENSUS1881_SRT, 656346) - .put(WEATHER_SEPT_85_SRT, 1015367).put(WIKILEAKS_NOQUOTES_SRT, 236436).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, 199523) + .put(CENSUS1881, 988653) + .put(DIMENSION_008, 148278) + .put(DIMENSION_003, 3866847) + .put(DIMENSION_033, 3866847) + .put(USCENSUS2000, 5985) + .put(WEATHER_SEPT_85, 1015367) + .put(WIKILEAKS_NOQUOTES, 242540) + .put(CENSUS_INCOME_SRT, 199523) + .put(CENSUS1881_SRT, 656346) + .put(WEATHER_SEPT_85_SRT, 1015367) + .put(WIKILEAKS_NOQUOTES_SRT, 236436) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { @@ -30,5 +54,4 @@ protected void doTest(String dataset, String type, boolean immutable) { RealDataBenchmarkIOr bench = new RealDataBenchmarkIOr(); assertEquals(expected, bench.pairwiseIOr(bs)); } - } diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIterateTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIterateTest.java index 55571fece..0677d43be 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIterateTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkIterateTest.java @@ -1,22 +1,40 @@ package org.roaringbitmap.realdata; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import com.google.common.collect.ImmutableMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.roaringbitmap.RealDataset.*; - - public class RealDataBenchmarkIterateTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, -942184551) - .put(CENSUS1881, 246451066).put(DIMENSION_008, -423436314).put(DIMENSION_003, -1287135055) - .put(DIMENSION_033, -1287135055).put(USCENSUS2000, -1260727955) - .put(WEATHER_SEPT_85, 644036874).put(WIKILEAKS_NOQUOTES, 413846869) - .put(CENSUS_INCOME_SRT, -679313956).put(CENSUS1881_SRT, 445584405) - .put(WEATHER_SEPT_85_SRT, 1132748056).put(WIKILEAKS_NOQUOTES_SRT, 1921022163).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, -942184551) + .put(CENSUS1881, 246451066) + .put(DIMENSION_008, -423436314) + .put(DIMENSION_003, -1287135055) + .put(DIMENSION_033, -1287135055) + .put(USCENSUS2000, -1260727955) + .put(WEATHER_SEPT_85, 644036874) + .put(WIKILEAKS_NOQUOTES, 413846869) + .put(CENSUS_INCOME_SRT, -679313956) + .put(CENSUS1881_SRT, 445584405) + .put(WEATHER_SEPT_85_SRT, 1132748056) + .put(WIKILEAKS_NOQUOTES_SRT, 1921022163) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkOrTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkOrTest.java index 44684daae..929ffbc81 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkOrTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkOrTest.java @@ -1,33 +1,62 @@ package org.roaringbitmap.realdata; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import com.google.common.collect.ImmutableMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.roaringbitmap.RealDataset.*; - - public class RealDataBenchmarkOrTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, 12487395).put(CENSUS1881, 2007691) - .put(DIMENSION_008, 5555233).put(DIMENSION_003, 7733676).put(DIMENSION_033, 7579526) - .put(USCENSUS2000, 11954).put(WEATHER_SEPT_85, 24729002).put(WIKILEAKS_NOQUOTES, 541893) - .put(CENSUS_INCOME_SRT, 11257282).put(CENSUS1881_SRT, 1360167) - .put(WEATHER_SEPT_85_SRT, 30863347).put(WIKILEAKS_NOQUOTES_SRT, 574463).build(); - - private static final Map EXPECTED_RESULTS_NO_CARDINALITY = ImmutableMap - .builder().put(CENSUS_INCOME, 20377).put(CENSUS1881, 192344014) - .put(DIMENSION_008, 60471647).put(DIMENSION_003, -2080279977).put(DIMENSION_033, 48993139) - .put(USCENSUS2000, 1085687199).put(WEATHER_SEPT_85, 164092).put(WIKILEAKS_NOQUOTES, 43309741) - .put(CENSUS_INCOME_SRT, 325103).put(CENSUS1881_SRT, 113309680) - .put(WEATHER_SEPT_85_SRT, 11922488).put(WIKILEAKS_NOQUOTES_SRT, 28702307).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, 12487395) + .put(CENSUS1881, 2007691) + .put(DIMENSION_008, 5555233) + .put(DIMENSION_003, 7733676) + .put(DIMENSION_033, 7579526) + .put(USCENSUS2000, 11954) + .put(WEATHER_SEPT_85, 24729002) + .put(WIKILEAKS_NOQUOTES, 541893) + .put(CENSUS_INCOME_SRT, 11257282) + .put(CENSUS1881_SRT, 1360167) + .put(WEATHER_SEPT_85_SRT, 30863347) + .put(WIKILEAKS_NOQUOTES_SRT, 574463) + .build(); + + private static final Map EXPECTED_RESULTS_NO_CARDINALITY = + ImmutableMap.builder() + .put(CENSUS_INCOME, 20377) + .put(CENSUS1881, 192344014) + .put(DIMENSION_008, 60471647) + .put(DIMENSION_003, -2080279977) + .put(DIMENSION_033, 48993139) + .put(USCENSUS2000, 1085687199) + .put(WEATHER_SEPT_85, 164092) + .put(WIKILEAKS_NOQUOTES, 43309741) + .put(CENSUS_INCOME_SRT, 325103) + .put(CENSUS1881_SRT, 113309680) + .put(WEATHER_SEPT_85_SRT, 11922488) + .put(WIKILEAKS_NOQUOTES_SRT, 28702307) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { RealDataBenchmarkOr bench = new RealDataBenchmarkOr(); - assertEquals((int)EXPECTED_RESULTS.get(dataset), bench.pairwiseOr(bs)); - assertEquals((int)EXPECTED_RESULTS_NO_CARDINALITY.get(dataset), bench.pairwiseOr_NoCardinality(bs)); + assertEquals((int) EXPECTED_RESULTS.get(dataset), bench.pairwiseOr(bs)); + assertEquals( + (int) EXPECTED_RESULTS_NO_CARDINALITY.get(dataset), bench.pairwiseOr_NoCardinality(bs)); } } diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterateTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterateTest.java index 1cf2256ec..55cd6b438 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterateTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkReverseIterateTest.java @@ -1,25 +1,43 @@ package org.roaringbitmap.realdata; -import com.google.common.collect.ImmutableMap; - -import java.util.Map; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeFalse; -import static org.roaringbitmap.RealDataset.*; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.CONCISE; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.WAH; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; public class RealDataBenchmarkReverseIterateTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, -942184551) - .put(CENSUS1881, 246451066).put(DIMENSION_008, -423436314).put(DIMENSION_003, -1287135055) - .put(DIMENSION_033, -1287135055).put(USCENSUS2000, -1260727955) - .put(WEATHER_SEPT_85, 644036874).put(WIKILEAKS_NOQUOTES, 413846869) - .put(CENSUS_INCOME_SRT, -679313956).put(CENSUS1881_SRT, 445584405) - .put(WEATHER_SEPT_85_SRT, 1132748056).put(WIKILEAKS_NOQUOTES_SRT, 1921022163).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, -942184551) + .put(CENSUS1881, 246451066) + .put(DIMENSION_008, -423436314) + .put(DIMENSION_003, -1287135055) + .put(DIMENSION_033, -1287135055) + .put(USCENSUS2000, -1260727955) + .put(WEATHER_SEPT_85, 644036874) + .put(WIKILEAKS_NOQUOTES, 413846869) + .put(CENSUS_INCOME_SRT, -679313956) + .put(CENSUS1881_SRT, 445584405) + .put(WEATHER_SEPT_85_SRT, 1132748056) + .put(WIKILEAKS_NOQUOTES_SRT, 1921022163) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { @@ -29,5 +47,4 @@ protected void doTest(String dataset, String type, boolean immutable) { RealDataBenchmarkReverseIterate bench = new RealDataBenchmarkReverseIterate(); assertEquals(expected, bench.reverseIterate(bs)); } - } diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkSanityTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkSanityTest.java index 8ee0037fc..a4ae1b1ba 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkSanityTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkSanityTest.java @@ -1,5 +1,28 @@ package org.roaringbitmap.realdata; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.CONCISE; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.EWAH32; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING_ONLY; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.ROARING_WITH_RUN; +import static org.roaringbitmap.realdata.wrapper.BitmapFactory.WAH; + +import org.roaringbitmap.realdata.state.RealDataBenchmarkState; +import org.roaringbitmap.realdata.wrapper.BitmapFactory; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.parallel.Execution; @@ -7,21 +30,27 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.roaringbitmap.realdata.state.RealDataBenchmarkState; -import org.roaringbitmap.realdata.wrapper.BitmapFactory; import java.util.Arrays; import java.util.stream.Stream; -import static org.roaringbitmap.RealDataset.*; -import static org.roaringbitmap.realdata.wrapper.BitmapFactory.*; - @Execution(ExecutionMode.CONCURRENT) public abstract class RealDataBenchmarkSanityTest { - public static final String[] REAL_DATA_SETS = {CENSUS_INCOME, CENSUS1881, DIMENSION_008, - DIMENSION_003, DIMENSION_033, USCENSUS2000, WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, - CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, WIKILEAKS_NOQUOTES_SRT}; + public static final String[] REAL_DATA_SETS = { + CENSUS_INCOME, + CENSUS1881, + DIMENSION_008, + DIMENSION_003, + DIMENSION_033, + USCENSUS2000, + WEATHER_SEPT_85, + WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, + CENSUS1881_SRT, + WEATHER_SEPT_85_SRT, + WIKILEAKS_NOQUOTES_SRT + }; public static final String[] BITMAP_TYPES = ROARING_ONLY.equals(System.getProperty(BitmapFactory.BITMAP_TYPES)) @@ -30,11 +59,11 @@ public abstract class RealDataBenchmarkSanityTest { public static final Boolean[] BITMAP_IMMUTABILITY = {false, true}; - // Ensure all tests related to the same dataset are run consecutively in order to take advantage // of any cache public static Stream params() { - Arguments[] product = new Arguments[REAL_DATA_SETS.length * BITMAP_TYPES.length * BITMAP_IMMUTABILITY.length]; + Arguments[] product = + new Arguments[REAL_DATA_SETS.length * BITMAP_TYPES.length * BITMAP_IMMUTABILITY.length]; int i = 0; for (String ds : REAL_DATA_SETS) { for (String type : BITMAP_TYPES) { @@ -71,5 +100,4 @@ public void tearDown() { } protected abstract void doTest(String dataset, String type, boolean immutable); - } diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaiveTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaiveTest.java index 70b1f20bb..9594ee1f4 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaiveTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideAndNaiveTest.java @@ -1,6 +1,5 @@ package org.roaringbitmap.realdata; - import static org.junit.jupiter.api.Assertions.assertEquals; public class RealDataBenchmarkWideAndNaiveTest extends RealDataBenchmarkSanityTest { diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaiveTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaiveTest.java index eac0ed8dc..c9af808e4 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaiveTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrNaiveTest.java @@ -1,22 +1,40 @@ package org.roaringbitmap.realdata; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import com.google.common.collect.ImmutableMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.roaringbitmap.RealDataset.*; - - public class RealDataBenchmarkWideOrNaiveTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, 199523).put(CENSUS1881, 988653) - .put(DIMENSION_008, 148278).put(DIMENSION_003, 3866847).put(DIMENSION_033, 3866847) - .put(USCENSUS2000, 5985).put(WEATHER_SEPT_85, 1015367).put(WIKILEAKS_NOQUOTES, 242540) - .put(CENSUS_INCOME_SRT, 199523).put(CENSUS1881_SRT, 656346) - .put(WEATHER_SEPT_85_SRT, 1015367).put(WIKILEAKS_NOQUOTES_SRT, 236436).build(); - + ImmutableMap.builder() + .put(CENSUS_INCOME, 199523) + .put(CENSUS1881, 988653) + .put(DIMENSION_008, 148278) + .put(DIMENSION_003, 3866847) + .put(DIMENSION_033, 3866847) + .put(USCENSUS2000, 5985) + .put(WEATHER_SEPT_85, 1015367) + .put(WIKILEAKS_NOQUOTES, 242540) + .put(CENSUS_INCOME_SRT, 199523) + .put(CENSUS1881_SRT, 656346) + .put(WEATHER_SEPT_85_SRT, 1015367) + .put(WIKILEAKS_NOQUOTES_SRT, 236436) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPqTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPqTest.java index 1c018a755..31283603e 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPqTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkWideOrPqTest.java @@ -1,21 +1,40 @@ package org.roaringbitmap.realdata; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; + import com.google.common.collect.ImmutableMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.roaringbitmap.RealDataset.*; - - public class RealDataBenchmarkWideOrPqTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, 199523).put(CENSUS1881, 988653) - .put(DIMENSION_008, 148278).put(DIMENSION_003, 3866847).put(DIMENSION_033, 3866847) - .put(USCENSUS2000, 5985).put(WEATHER_SEPT_85, 1015367).put(WIKILEAKS_NOQUOTES, 242540) - .put(CENSUS_INCOME_SRT, 199523).put(CENSUS1881_SRT, 656346) - .put(WEATHER_SEPT_85_SRT, 1015367).put(WIKILEAKS_NOQUOTES_SRT, 236436).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, 199523) + .put(CENSUS1881, 988653) + .put(DIMENSION_008, 148278) + .put(DIMENSION_003, 3866847) + .put(DIMENSION_033, 3866847) + .put(USCENSUS2000, 5985) + .put(WEATHER_SEPT_85, 1015367) + .put(WIKILEAKS_NOQUOTES, 242540) + .put(CENSUS_INCOME_SRT, 199523) + .put(CENSUS1881_SRT, 656346) + .put(WEATHER_SEPT_85_SRT, 1015367) + .put(WIKILEAKS_NOQUOTES_SRT, 236436) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { diff --git a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkXorTest.java b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkXorTest.java index 7dec4b2b1..65cc47ea1 100644 --- a/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkXorTest.java +++ b/jmh/src/test/java/org/roaringbitmap/realdata/RealDataBenchmarkXorTest.java @@ -1,24 +1,43 @@ package org.roaringbitmap.realdata; -import com.google.common.collect.ImmutableMap; - -import java.util.Map; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeFalse; -import static org.roaringbitmap.RealDataset.*; +import static org.roaringbitmap.RealDataset.CENSUS1881; +import static org.roaringbitmap.RealDataset.CENSUS1881_SRT; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME; +import static org.roaringbitmap.RealDataset.CENSUS_INCOME_SRT; +import static org.roaringbitmap.RealDataset.DIMENSION_003; +import static org.roaringbitmap.RealDataset.DIMENSION_008; +import static org.roaringbitmap.RealDataset.DIMENSION_033; +import static org.roaringbitmap.RealDataset.USCENSUS2000; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85; +import static org.roaringbitmap.RealDataset.WEATHER_SEPT_85_SRT; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES; +import static org.roaringbitmap.RealDataset.WIKILEAKS_NOQUOTES_SRT; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.CONCISE; import static org.roaringbitmap.realdata.wrapper.BitmapFactory.WAH; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; public class RealDataBenchmarkXorTest extends RealDataBenchmarkSanityTest { private static final Map EXPECTED_RESULTS = - ImmutableMap.builder().put(CENSUS_INCOME, 11241947).put(CENSUS1881, 2007668) - .put(DIMENSION_008, 5442916).put(DIMENSION_003, 7733676).put(DIMENSION_033, 7579526) - .put(USCENSUS2000, 11954).put(WEATHER_SEPT_85, 24086983).put(WIKILEAKS_NOQUOTES, 538566) - .put(CENSUS_INCOME_SRT, 10329567).put(CENSUS1881_SRT, 1359961) - .put(WEATHER_SEPT_85_SRT, 29800358).put(WIKILEAKS_NOQUOTES_SRT, 574311).build(); + ImmutableMap.builder() + .put(CENSUS_INCOME, 11241947) + .put(CENSUS1881, 2007668) + .put(DIMENSION_008, 5442916) + .put(DIMENSION_003, 7733676) + .put(DIMENSION_033, 7579526) + .put(USCENSUS2000, 11954) + .put(WEATHER_SEPT_85, 24086983) + .put(WIKILEAKS_NOQUOTES, 538566) + .put(CENSUS_INCOME_SRT, 10329567) + .put(CENSUS1881_SRT, 1359961) + .put(WEATHER_SEPT_85_SRT, 29800358) + .put(WIKILEAKS_NOQUOTES_SRT, 574311) + .build(); @Override protected void doTest(String dataset, String type, boolean immutable) { diff --git a/real-roaring-dataset/src/main/java/org/roaringbitmap/RealDataset.java b/real-roaring-dataset/src/main/java/org/roaringbitmap/RealDataset.java index eb05b6483..3f3620aac 100644 --- a/real-roaring-dataset/src/main/java/org/roaringbitmap/RealDataset.java +++ b/real-roaring-dataset/src/main/java/org/roaringbitmap/RealDataset.java @@ -2,9 +2,7 @@ public final class RealDataset { - private RealDataset() { - - } + private RealDataset() {} public static final String CENSUS_INCOME = "census-income"; public static final String CENSUS1881 = "census1881"; @@ -19,9 +17,10 @@ private RealDataset() { public static final String WEATHER_SEPT_85_SRT = "weather_sept_85_srt"; public static final String WIKILEAKS_NOQUOTES_SRT = "wikileaks-noquotes_srt"; - public static final String[] ALL = new String[]{ - CENSUS_INCOME, CENSUS1881, DIMENSION_008, DIMENSION_003, - DIMENSION_033, USCENSUS2000, WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, - CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, WIKILEAKS_NOQUOTES_SRT - }; + public static final String[] ALL = + new String[] { + CENSUS_INCOME, CENSUS1881, DIMENSION_008, DIMENSION_003, + DIMENSION_033, USCENSUS2000, WEATHER_SEPT_85, WIKILEAKS_NOQUOTES, + CENSUS_INCOME_SRT, CENSUS1881_SRT, WEATHER_SEPT_85_SRT, WIKILEAKS_NOQUOTES_SRT + }; } diff --git a/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRangeRetriever.java b/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRangeRetriever.java index cdffa56bf..a85c9f992 100644 --- a/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRangeRetriever.java +++ b/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRangeRetriever.java @@ -21,8 +21,8 @@ public class ZipRealDataRangeRetriever { private final String dataset; - public ZipRealDataRangeRetriever(String dataset, String folder) throws IOException, - URISyntaxException { + public ZipRealDataRangeRetriever(String dataset, String folder) + throws IOException, URISyntaxException { this.dataset = dataset; this.REAL_ROARING_DATASET = folder; } @@ -32,7 +32,7 @@ public String getName() { } /** - * + * * Returns next range from file * @return some Iterable * @throws IOException it can happen @@ -86,7 +86,6 @@ private ZipEntry nextEntry() { } }; } - }; } @@ -101,5 +100,4 @@ private ZipInputStream getResourceAsStream() { private String resource() { return REAL_ROARING_DATASET + dataset + ZIP_EXTENSION; } - } diff --git a/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRetriever.java b/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRetriever.java index 4ec120b48..b3bd76c72 100644 --- a/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRetriever.java +++ b/real-roaring-dataset/src/main/java/org/roaringbitmap/ZipRealDataRetriever.java @@ -5,9 +5,8 @@ import java.io.InputStreamReader; import java.net.URISyntaxException; import java.net.URL; -import java.util.List; import java.util.ArrayList; -import java.util.Iterator; +import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -40,12 +39,8 @@ public String getName() { public List fetchBitPositions() throws IOException { List bitPositions = new ArrayList<>(); - - try ( - final ZipInputStream zis = getResourceAsStream(); - final BufferedReader buf = new BufferedReader(new InputStreamReader(zis)); - ) { - + try (final ZipInputStream zis = getResourceAsStream(); + final BufferedReader buf = new BufferedReader(new InputStreamReader(zis)); ) { while (true) { ZipEntry nextEntry = zis.getNextEntry(); @@ -80,5 +75,4 @@ private ZipInputStream getResourceAsStream() { private String resource() { return REAL_ROARING_DATASET + dataset + ZIP_EXTENSION; } - } diff --git a/RoaringBitmap/build.gradle.kts b/roaringbitmap/build.gradle.kts similarity index 91% rename from RoaringBitmap/build.gradle.kts rename to roaringbitmap/build.gradle.kts index b9beaf5a3..7bf9a05ef 100644 --- a/RoaringBitmap/build.gradle.kts +++ b/roaringbitmap/build.gradle.kts @@ -13,16 +13,6 @@ buildscript { // files with Java 8 compatibility apply(plugin = "org.javamodularity.moduleplugin") -// Work around -// https://github.com/java9-modularity/gradle-modules-plugin/issues/220 -// by excluding module-info.class from non-executable JARs. -tasks.named("javadocJar") { - exclude("module-info.class") -} - -tasks.named("sourcesJar") { - exclude("module-info.class") -} // Unset Java 8 release applied from root project to allow modularity plugin to // control the class file versions. @@ -96,7 +86,6 @@ tasks.named("jar") { tasks.test { systemProperty("kryo.unsafe", "false") - mustRunAfter(tasks.checkstyleMain) useJUnitPlatform() failFast = true diff --git a/RoaringBitmap/src/java11/java/org/roaringbitmap/ArraysShim.java b/roaringbitmap/src/java11/java/org/roaringbitmap/ArraysShim.java similarity index 92% rename from RoaringBitmap/src/java11/java/org/roaringbitmap/ArraysShim.java rename to roaringbitmap/src/java11/java/org/roaringbitmap/ArraysShim.java index 152df11e7..6966833cc 100644 --- a/RoaringBitmap/src/java11/java/org/roaringbitmap/ArraysShim.java +++ b/roaringbitmap/src/java11/java/org/roaringbitmap/ArraysShim.java @@ -34,8 +34,8 @@ public static boolean equals(char[] x, int xmin, int xmax, char[] y, int ymin, i * @param bToIndex exclusive * @return -1 if no mismatch found,othewise the mismatch offset */ - public static int mismatch(byte[] a, int aFromIndex, int aToIndex, - byte[] b, int bFromIndex, int bToIndex) { + public static int mismatch( + byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) { if (bFromIndex > bToIndex) { return -1; } diff --git a/RoaringBitmap/src/main/java/module-info.java b/roaringbitmap/src/main/java/module-info.java similarity index 100% rename from RoaringBitmap/src/main/java/module-info.java rename to roaringbitmap/src/main/java/module-info.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/AppendableStorage.java b/roaringbitmap/src/main/java/org/roaringbitmap/AppendableStorage.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/AppendableStorage.java rename to roaringbitmap/src/main/java/org/roaringbitmap/AppendableStorage.java index 5d651c279..a3ae042ad 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/AppendableStorage.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/AppendableStorage.java @@ -13,5 +13,4 @@ public interface AppendableStorage { * @param container the data to append */ void append(char key, T container); - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ArrayBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/ArrayBatchIterator.java similarity index 80% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ArrayBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ArrayBatchIterator.java index c6d248b4d..7f2686c2c 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ArrayBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ArrayBatchIterator.java @@ -1,6 +1,5 @@ package org.roaringbitmap; - import static org.roaringbitmap.Util.unsignedBinarySearch; public final class ArrayBatchIterator implements ContainerBatchIterator { @@ -13,11 +12,11 @@ public ArrayBatchIterator(ArrayContainer array) { } @Override - public int next(int key, int[] buffer) { + public int next(int key, int[] buffer, int offset) { int consumed = 0; char[] data = array.content; - while (consumed < buffer.length && index < array.getCardinality()) { - buffer[consumed++] = key + (data[index++]); + while ((offset + consumed) < buffer.length && index < array.getCardinality()) { + buffer[offset + consumed++] = key + (data[index++]); } return consumed; } @@ -30,7 +29,7 @@ public boolean hasNext() { @Override public ContainerBatchIterator clone() { try { - return (ContainerBatchIterator)super.clone(); + return (ContainerBatchIterator) super.clone(); } catch (CloneNotSupportedException e) { // won't happen throw new IllegalStateException(e); diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ArrayContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/ArrayContainer.java similarity index 82% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ArrayContainer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ArrayContainer.java index c7ffaff12..ebb2dd955 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ArrayContainer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ArrayContainer.java @@ -7,16 +7,17 @@ import org.roaringbitmap.buffer.MappeableArrayContainer; import org.roaringbitmap.buffer.MappeableContainer; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.util.Arrays; import java.util.Iterator; - - - /** * Simple container made of an array of 16-bit integers */ @@ -24,8 +25,8 @@ public final class ArrayContainer extends Container implements Cloneable { private static final int DEFAULT_INIT_SIZE = 4; private static final int ARRAY_LAZY_LOWERBOUND = 1024; - static final int DEFAULT_MAX_SIZE = 4096;// containers with DEFAULT_MAX_SZE or less integers - // should be ArrayContainers + static final int DEFAULT_MAX_SIZE = 4096; // containers with DEFAULT_MAX_SZE or less integers + // should be ArrayContainers private static final long serialVersionUID = 1L; @@ -37,7 +38,6 @@ protected static int serializedSizeInBytes(int cardinality) { char[] content; - /** * Create an array container with default capacity */ @@ -48,6 +48,7 @@ public ArrayContainer() { public static ArrayContainer empty() { return new ArrayContainer(); } + /** * Create an array container with specified capacity * @@ -101,7 +102,7 @@ public ArrayContainer(char[] newContent) { @Override public Container add(int begin, int end) { - if(end == begin) { + if (end == begin) { return clone(); } if ((begin > end) || (end > (1 << 16))) { @@ -112,7 +113,7 @@ public Container add(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = Util.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = Util.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { @@ -125,8 +126,8 @@ public Container add(int begin, int end) { return a.iadd(begin, end); } ArrayContainer answer = new ArrayContainer(newcardinality, content); - System.arraycopy(content, indexend, answer.content, indexstart + rangelength, - cardinality - indexend); + System.arraycopy( + content, indexend, answer.content, indexstart + rangelength, cardinality - indexend); for (int k = 0; k < rangelength; ++k) { answer.content[k + indexstart] = (char) (begin + k); } @@ -134,15 +135,12 @@ public Container add(int begin, int end) { return answer; } - - /** * running time is in O(n) time if insert is not in order. */ @Override public Container add(final char x) { - if (cardinality == 0 || (cardinality > 0 - && (x) > (content[cardinality - 1]))) { + if (cardinality == 0 || (cardinality > 0 && (x) > (content[cardinality - 1]))) { if (cardinality >= DEFAULT_MAX_SIZE) { return toBitmapContainer().add(x); } @@ -185,8 +183,13 @@ public ArrayContainer and(final ArrayContainer value2) { ArrayContainer value1 = this; final int desiredCapacity = Math.min(value1.getCardinality(), value2.getCardinality()); ArrayContainer answer = new ArrayContainer(desiredCapacity); - answer.cardinality = Util.unsignedIntersect2by2(value1.content, value1.getCardinality(), - value2.content, value2.getCardinality(), answer.content); + answer.cardinality = + Util.unsignedIntersect2by2( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + answer.content); return answer; } @@ -203,8 +206,8 @@ public Container and(RunContainer x) { @Override public int andCardinality(final ArrayContainer value2) { - return Util.unsignedLocalIntersect2by2Cardinality(content, cardinality, value2.content, - value2.getCardinality()); + return Util.unsignedLocalIntersect2by2Cardinality( + content, cardinality, value2.content, value2.getCardinality()); } @Override @@ -223,8 +226,13 @@ public ArrayContainer andNot(final ArrayContainer value2) { ArrayContainer value1 = this; final int desiredCapacity = value1.getCardinality(); ArrayContainer answer = new ArrayContainer(desiredCapacity); - answer.cardinality = Util.unsignedDifference(value1.content, value1.getCardinality(), - value2.content, value2.getCardinality(), answer.content); + answer.cardinality = + Util.unsignedDifference( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + answer.content); return answer; } @@ -298,16 +306,15 @@ public boolean contains(final char x) { @Override public boolean contains(int minimum, int supremum) { int maximum = supremum - 1; - int start = Util.advanceUntil(content, -1, cardinality, (char)minimum); - int end = Util.advanceUntil(content, start - 1, cardinality, (char)maximum); + int start = Util.advanceUntil(content, -1, cardinality, (char) minimum); + int end = Util.advanceUntil(content, start - 1, cardinality, (char) maximum); return start < cardinality - && end < cardinality - && end - start == maximum - minimum - && content[start] == (char)minimum - && content[end] == (char)maximum; + && end < cardinality + && end - start == maximum - minimum + && content[start] == (char) minimum + && content[end] == (char) maximum; } - @Override protected boolean contains(RunContainer runContainer) { if (runContainer.getCardinality() > cardinality) { @@ -317,7 +324,7 @@ protected boolean contains(RunContainer runContainer) { for (int i = 0; i < runContainer.numberOfRuns(); ++i) { int start = (runContainer.getValue(i)); int length = (runContainer.getLength(i)); - if (!contains(start, start + length)) { + if (!contains(start, start + length + 1)) { return false; } } @@ -330,11 +337,11 @@ protected boolean contains(ArrayContainer arrayContainer) { return false; } int i1 = 0, i2 = 0; - while(i1 < cardinality && i2 < arrayContainer.cardinality) { - if(content[i1] == arrayContainer.content[i2]) { + while (i1 < cardinality && i2 < arrayContainer.cardinality) { + if (content[i1] == arrayContainer.content[i2]) { ++i1; ++i2; - } else if(content[i1] < arrayContainer.content[i2]) { + } else if (content[i1] < arrayContainer.content[i2]) { ++i1; } else { return false; @@ -367,7 +374,6 @@ private void emit(char val) { content[cardinality++] = val; } - @Override public boolean equals(Object o) { if (o instanceof ArrayContainer) { @@ -384,7 +390,6 @@ public void fillLeastSignificant16bits(int[] x, int i, int mask) { for (int k = 0; k < this.cardinality; ++k) { x[k + i] = (this.content[k]) | mask; } - } @Override @@ -445,7 +450,6 @@ public ContainerBatchIterator getBatchIterator() { return new ArrayBatchIterator(this); } - @Override public int getSizeInBytes() { return this.cardinality * 2 + 4; @@ -463,7 +467,7 @@ public int hashCode() { @Override public Container iadd(int begin, int end) { // TODO: may need to convert to a RunContainer - if(end == begin) { + if (end == begin) { return this; } if ((begin > end) || (end > (1 << 16))) { @@ -473,7 +477,7 @@ public Container iadd(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = Util.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = Util.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { @@ -519,12 +523,12 @@ public Container iadd(int begin, int end) { * so far cases - 1,2 and 6 are done Now, if e < cardinality, we copy from e to * cardinality.Otherwise do noting this covers remaining 3,4 and 5 cases */ - System.arraycopy(content, indexend, destination, indexstart + rangelength, cardinality - - indexend); + System.arraycopy( + content, indexend, destination, indexstart + rangelength, cardinality - indexend); this.content = destination; } else { - System - .arraycopy(content, indexend, content, indexstart + rangelength, cardinality - indexend); + System.arraycopy( + content, indexend, content, indexstart + rangelength, cardinality - indexend); for (int k = 0; k < rangelength; ++k) { content[k + indexstart] = (char) (begin + k); } @@ -533,12 +537,16 @@ public Container iadd(int begin, int end) { return this; } - @Override public ArrayContainer iand(final ArrayContainer value2) { ArrayContainer value1 = this; - value1.cardinality = Util.unsignedIntersect2by2(value1.content, value1.getCardinality(), - value2.content, value2.getCardinality(), value1.content); + value1.cardinality = + Util.unsignedIntersect2by2( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + value1.content); return this; } @@ -548,7 +556,7 @@ public Container iand(BitmapContainer value2) { for (int k = 0; k < cardinality; ++k) { char v = this.content[k]; this.content[pos] = v; - pos += (int)value2.bitValue(v); + pos += (int) value2.bitValue(v); } cardinality = pos; return this; @@ -556,15 +564,29 @@ public Container iand(BitmapContainer value2) { @Override public Container iand(RunContainer x) { - // possible performance issue, not taking advantage of possible inplace - return x.and(this); + PeekableCharIterator it = x.getCharIterator(); + int removed = 0; + for (int i = 0; i < cardinality; i++) { + it.advanceIfNeeded(content[i]); + if (it.peekNext() == content[i]) { + content[i - removed] = content[i]; + } else { + removed++; + } + } + cardinality -= removed; + return this; } - @Override public ArrayContainer iandNot(final ArrayContainer value2) { - this.cardinality = Util.unsignedDifference(this.content, this.getCardinality(), value2.content, - value2.getCardinality(), this.content); + this.cardinality = + Util.unsignedDifference( + this.content, + this.getCardinality(), + value2.content, + value2.getCardinality(), + this.content); return this; } @@ -574,7 +596,7 @@ public ArrayContainer iandNot(BitmapContainer value2) { for (int k = 0; k < cardinality; ++k) { char v = this.content[k]; this.content[pos] = v; - pos += 1 - (int)value2.bitValue(v); + pos += 1 - (int) value2.bitValue(v); } this.cardinality = pos; return this; @@ -582,23 +604,28 @@ public ArrayContainer iandNot(BitmapContainer value2) { @Override public Container iandNot(RunContainer x) { - // possible performance issue, not taking advantage of possible inplace - // could adapt algo above - return andNot(x); + PeekableCharIterator it = x.getCharIterator(); + int removed = 0; + for (int i = 0; i < cardinality; i++) { + it.advanceIfNeeded(content[i]); + if (it.peekNext() != content[i]) { + content[i - removed] = content[i]; + } else { + removed++; + } + } + cardinality -= removed; + return this; } private void increaseCapacity() { increaseCapacity(false); } - // temporarily allow an illegally large size, as long as the operation creating // the illegal container does not return it. private void increaseCapacity(boolean allowIllegalSize) { - int newCapacity = (this.content.length == 0) ? DEFAULT_INIT_SIZE - : this.content.length < 64 ? this.content.length * 2 - : this.content.length < 1067 ? this.content.length * 3 / 2 - : this.content.length * 5 / 4; + int newCapacity = computeCapacity(this.content.length); // never allocate more than we will ever need if (newCapacity > ArrayContainer.DEFAULT_MAX_SIZE && !allowIllegalSize) { newCapacity = ArrayContainer.DEFAULT_MAX_SIZE; @@ -611,12 +638,16 @@ private void increaseCapacity(boolean allowIllegalSize) { this.content = Arrays.copyOf(this.content, newCapacity); } + private int computeCapacity(int oldCapacity) { + return oldCapacity == 0 + ? DEFAULT_INIT_SIZE + : oldCapacity < 64 + ? oldCapacity * 2 + : oldCapacity < 1024 ? oldCapacity * 3 / 2 : oldCapacity * 5 / 4; + } + private int calculateCapacity(int min) { - int newCapacity = - (this.content.length == 0) ? DEFAULT_INIT_SIZE - : this.content.length < 64 ? this.content.length * 2 - : this.content.length < 1024 ? this.content.length * 3 / 2 - : this.content.length * 5 / 4; + int newCapacity = computeCapacity(this.content.length); if (newCapacity < min) { newCapacity = min; } @@ -639,7 +670,8 @@ public Container inot(final int firstOfRange, final int lastOfRange) { if (startIndex < 0) { startIndex = -startIndex - 1; } - int lastIndex = Util.unsignedBinarySearch(content, 0, cardinality, (char) (lastOfRange - 1)); + int lastIndex = + Util.unsignedBinarySearch(content, startIndex, cardinality, (char) (lastOfRange - 1)); if (lastIndex < 0) { lastIndex = -lastIndex - 1 - 1; } @@ -659,7 +691,11 @@ public Container inot(final int firstOfRange, final int lastOfRange) { content = Arrays.copyOf(content, newCardinality); } // slide right the contents after the range - System.arraycopy(content, lastIndex + 1, content, lastIndex + 1 + cardinalityChange, + System.arraycopy( + content, + lastIndex + 1, + content, + lastIndex + 1 + cardinalityChange, cardinality - 1 - lastIndex); negateRange(buffer, startIndex, lastIndex, firstOfRange, lastOfRange); } else { // no expansion needed @@ -667,8 +703,12 @@ public Container inot(final int firstOfRange, final int lastOfRange) { if (cardinalityChange < 0) { // contraction, left sliding. // Leave array oversize - System.arraycopy(content, startIndex + newValuesInRange - cardinalityChange, content, - startIndex + newValuesInRange, newCardinality - (startIndex + newValuesInRange)); + System.arraycopy( + content, + startIndex + newValuesInRange - cardinalityChange, + content, + startIndex + newValuesInRange, + newCardinality - (startIndex + newValuesInRange)); } } cardinality = newCardinality; @@ -678,11 +718,10 @@ public Container inot(final int firstOfRange, final int lastOfRange) { @Override public boolean intersects(ArrayContainer value2) { ArrayContainer value1 = this; - return Util.unsignedIntersects(value1.content, value1.getCardinality(), value2.content, - value2.getCardinality()); + return Util.unsignedIntersects( + value1.content, value1.getCardinality(), value2.content, value2.getCardinality()); } - @Override public boolean intersects(BitmapContainer x) { return x.intersects(this); @@ -695,53 +734,38 @@ public boolean intersects(RunContainer x) { @Override public boolean intersects(int minimum, int supremum) { - if((minimum < 0) || (supremum < minimum) || (supremum > (1<<16))) { + if ((minimum < 0) || (supremum < minimum) || (supremum > (1 << 16))) { throw new RuntimeException("This should never happen (bug)."); } - int pos = Util.unsignedBinarySearch(content, 0, cardinality, (char)minimum); + int pos = Util.unsignedBinarySearch(content, 0, cardinality, (char) minimum); int index = pos >= 0 ? pos : -pos - 1; return index < cardinality && (content[index]) < supremum; } - @Override public Container ior(final ArrayContainer value2) { int totalCardinality = this.getCardinality() + value2.getCardinality(); - if (totalCardinality > DEFAULT_MAX_SIZE) {// it could be a bitmap! - BitmapContainer bc = new BitmapContainer(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = value2.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] |= (1L << v); - } - for (int k = 0; k < this.cardinality; ++k) { - char v = this.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] |= (1L << v); - } - bc.cardinality = 0; - for (long k : bc.bitmap) { - bc.cardinality += Long.bitCount(k); - } - if (bc.cardinality <= DEFAULT_MAX_SIZE) { - return bc.toArrayContainer(); - } else if (bc.isFull()) { - return RunContainer.full(); - } - return bc; + if (totalCardinality > DEFAULT_MAX_SIZE) { + return toBitmapContainer().lazyIOR(value2).repairAfterLazy(); } if (totalCardinality >= content.length) { int newCapacity = calculateCapacity(totalCardinality); char[] destination = new char[newCapacity]; cardinality = - Util.unsignedUnion2by2(content, 0, cardinality, value2.content, 0, value2.cardinality, - destination); + Util.unsignedUnion2by2( + content, 0, cardinality, value2.content, 0, value2.cardinality, destination); this.content = destination; } else { System.arraycopy(content, 0, content, value2.cardinality, cardinality); cardinality = - Util.unsignedUnion2by2(content, value2.cardinality, cardinality, value2.content, 0, - value2.cardinality, content); + Util.unsignedUnion2by2( + content, + value2.cardinality, + cardinality, + value2.content, + 0, + value2.cardinality, + content); } return this; } @@ -759,7 +783,7 @@ public Container ior(RunContainer x) { @Override public Container iremove(int begin, int end) { - if(end == begin) { + if (end == begin) { return this; } if ((begin > end) || (end > (1 << 16))) { @@ -769,14 +793,18 @@ public Container iremove(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = Util.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = Util.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { indexend++; } int rangelength = indexend - indexstart; - System.arraycopy(content, indexstart + rangelength, content, indexstart, + System.arraycopy( + content, + indexstart + rangelength, + content, + indexstart, cardinality - indexstart - rangelength); cardinality -= rangelength; return this; @@ -815,14 +843,12 @@ public Container ixor(BitmapContainer x) { return x.xor(this); } - @Override public Container ixor(RunContainer x) { // possible performance issue, not taking advantage of possible inplace return x.xor(this); } - @Override public Container limit(int maxcardinality) { if (maxcardinality < this.getCardinality()) { @@ -834,12 +860,16 @@ public Container limit(int maxcardinality) { void loadData(final BitmapContainer bitmapContainer) { this.cardinality = bitmapContainer.cardinality; - bitmapContainer.fillArray(content); + Util.fillArray(bitmapContainer.bitmap, content); } // for use in inot range known to be nonempty - private void negateRange(final char[] buffer, final int startIndex, final int lastIndex, - final int startRange, final int lastRange) { + private void negateRange( + final char[] buffer, + final int startIndex, + final int lastIndex, + final int startRange, + final int lastRange) { // compute the negation into buffer int outPos = 0; @@ -886,7 +916,8 @@ public Container not(final int firstOfRange, final int lastOfRange) { if (startIndex < 0) { startIndex = -startIndex - 1; } - int lastIndex = Util.unsignedBinarySearch(content, 0, cardinality, (char) (lastOfRange - 1)); + int lastIndex = + Util.unsignedBinarySearch(content, startIndex, cardinality, (char) (lastOfRange - 1)); if (lastIndex < 0) { lastIndex = -lastIndex - 2; } @@ -950,36 +981,19 @@ int numberOfRuns() { public Container or(final ArrayContainer value2) { final ArrayContainer value1 = this; int totalCardinality = value1.getCardinality() + value2.getCardinality(); - if (totalCardinality > DEFAULT_MAX_SIZE) {// it could be a bitmap! - BitmapContainer bc = new BitmapContainer(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = value2.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] |= (1L << v); - } - for (int k = 0; k < this.cardinality; ++k) { - char v = this.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] |= (1L << v); - } - bc.cardinality = 0; - for (long k : bc.bitmap) { - bc.cardinality += Long.bitCount(k); - } - if (bc.cardinality <= DEFAULT_MAX_SIZE) { - return bc.toArrayContainer(); - } else if (bc.isFull()) { - return RunContainer.full(); - } - return bc; + if (totalCardinality > DEFAULT_MAX_SIZE) { + return toBitmapContainer().lazyIOR(value2).repairAfterLazy(); } ArrayContainer answer = new ArrayContainer(totalCardinality); answer.cardinality = - Util.unsignedUnion2by2( - value1.content, 0, value1.getCardinality(), - value2.content, 0, value2.getCardinality(), - answer.content - ); + Util.unsignedUnion2by2( + value1.content, + 0, + value1.getCardinality(), + value2.content, + 0, + value2.getCardinality(), + answer.content); return answer; } @@ -1058,7 +1072,7 @@ public void readExternal(ObjectInput in) throws IOException { @Override public Container remove(int begin, int end) { - if(end == begin) { + if (end == begin) { return clone(); } if ((begin > end) || (end > (1 << 16))) { @@ -1068,7 +1082,7 @@ public Container remove(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = Util.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = Util.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { @@ -1076,7 +1090,11 @@ public Container remove(int begin, int end) { } int rangelength = indexend - indexstart; ArrayContainer answer = clone(); - System.arraycopy(content, indexstart + rangelength, answer.content, indexstart, + System.arraycopy( + content, + indexstart + rangelength, + answer.content, + indexstart, cardinality - indexstart - rangelength); answer.cardinality = cardinality - rangelength; return answer; @@ -1087,7 +1105,6 @@ void removeAtIndex(final int loc) { --cardinality; } - @Override public Container remove(final char x) { final int loc = Util.unsignedBinarySearch(content, 0, cardinality, x); @@ -1112,8 +1129,8 @@ public Container runOptimize() { int sizeAsRunContainer = RunContainer.serializedSizeInBytes(numRuns); if (getArraySizeInBytes() > sizeAsRunContainer) { return new RunContainer(this, numRuns); // this could be maybe - // faster if initial - // container is a bitmap + // faster if initial + // container is a bitmap } else { return this; } @@ -1150,6 +1167,14 @@ public BitmapContainer toBitmapContainer() { return bc; } + @Override + public void copyBitmapTo(long[] dest, int position) { + for (int k = 0; k < cardinality; ++k) { + final char x = content[k]; + dest[position + x / 64] |= 1L << x; + } + } + @Override public int nextValue(char fromValue) { int index = Util.advanceUntil(content, -1, cardinality, fromValue); @@ -1281,10 +1306,10 @@ public String toString() { StringBuilder sb = new StringBuilder("{}".length() + "-123456789,".length() * cardinality); sb.append('{'); for (int i = 0; i < this.cardinality - 1; i++) { - sb.append((int)(this.content[i])); + sb.append((int) (this.content[i])); sb.append(','); } - sb.append((int)(this.content[this.cardinality - 1])); + sb.append((int) (this.content[this.cardinality - 1])); sb.append('}'); return sb.toString(); } @@ -1324,30 +1349,17 @@ public void writeExternal(ObjectOutput out) throws IOException { public Container xor(final ArrayContainer value2) { final ArrayContainer value1 = this; final int totalCardinality = value1.getCardinality() + value2.getCardinality(); - if (totalCardinality > DEFAULT_MAX_SIZE) {// it could be a bitmap! - BitmapContainer bc = new BitmapContainer(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = value2.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] ^= (1L << v); - } - for (int k = 0; k < this.cardinality; ++k) { - char v = this.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] ^= (1L << v); - } - bc.cardinality = 0; - for (long k : bc.bitmap) { - bc.cardinality += Long.bitCount(k); - } - if (bc.cardinality <= DEFAULT_MAX_SIZE) { - return bc.toArrayContainer(); - } - return bc; + if (totalCardinality > DEFAULT_MAX_SIZE) { + return toBitmapContainer().ixor(value2); } ArrayContainer answer = new ArrayContainer(totalCardinality); - answer.cardinality = Util.unsignedExclusiveUnion2by2(value1.content, value1.getCardinality(), - value2.content, value2.getCardinality(), answer.content); + answer.cardinality = + Util.unsignedExclusiveUnion2by2( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + answer.content); return answer; } @@ -1361,7 +1373,6 @@ public Container xor(RunContainer x) { return x.xor(this); } - protected Container xor(CharIterator it) { return or(it, true); } @@ -1369,7 +1380,7 @@ protected Container xor(CharIterator it) { @Override public void forEach(char msb, IntConsumer ic) { int high = msb << 16; - for(int k = 0; k < cardinality; ++k) { + for (int k = 0; k < cardinality; ++k) { ic.accept(content[k] | high); } } @@ -1377,7 +1388,7 @@ public void forEach(char msb, IntConsumer ic) { @Override public void forAll(int offset, final RelativeRangeConsumer rrc) { int next = 0; - for(int k = 0; k < cardinality; ++k) { + for (int k = 0; k < cardinality; ++k) { int value = content[k]; if (next < value) { // fill in the missing values until value @@ -1422,7 +1433,7 @@ public void forAllFrom(char startValue, final RelativeRangeConsumer rrc) { @Override public void forAllUntil(int offset, char endValue, final RelativeRangeConsumer rrc) { int next = 0; - for(int k = 0; k < cardinality; ++k) { + for (int k = 0; k < cardinality; ++k) { int value = content[k]; if (endValue <= value) { // value is already beyond the end @@ -1448,7 +1459,7 @@ public void forAllUntil(int offset, char endValue, final RelativeRangeConsumer r public void forAllInRange(char startValue, char endValue, final RelativeRangeConsumer rrc) { if (endValue <= startValue) { throw new IllegalArgumentException( - "startValue (" + startValue + ") must be less than endValue (" + endValue + ")"); + "startValue (" + startValue + ") must be less than endValue (" + endValue + ")"); } int startOffset = startValue; int loc = Util.unsignedBinarySearch(content, 0, cardinality, startValue); @@ -1480,42 +1491,28 @@ public void forAllInRange(char startValue, char endValue, final RelativeRangeCon protected Container lazyor(ArrayContainer value2) { final ArrayContainer value1 = this; int totalCardinality = value1.getCardinality() + value2.getCardinality(); - if (totalCardinality > ARRAY_LAZY_LOWERBOUND) {// it could be a bitmap! - BitmapContainer bc = new BitmapContainer(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = value2.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] |= (1L << v); - } - for (int k = 0; k < this.cardinality; ++k) { - char v = this.content[k]; - final int i = (v) >>> 6; - bc.bitmap[i] |= (1L << v); - } - bc.cardinality = -1; - return bc; + if (totalCardinality > ARRAY_LAZY_LOWERBOUND) { + return toBitmapContainer().lazyIOR(value2); } ArrayContainer answer = new ArrayContainer(totalCardinality); answer.cardinality = - Util.unsignedUnion2by2( - value1.content, 0, value1.getCardinality(), - value2.content, 0, value2.getCardinality(), - answer.content - ); + Util.unsignedUnion2by2( + value1.content, + 0, + value1.getCardinality(), + value2.content, + 0, + value2.getCardinality(), + answer.content); return answer; - } - } - final class ArrayContainerCharIterator implements PeekableCharRankIterator { int pos; private ArrayContainer parent; - ArrayContainerCharIterator() { - - } + ArrayContainerCharIterator() {} ArrayContainerCharIterator(ArrayContainer p) { wrap(p); @@ -1536,7 +1533,7 @@ public PeekableCharRankIterator clone() { try { return (PeekableCharRankIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -1560,7 +1557,6 @@ public char peekNext() { return parent.content[pos]; } - @Override public void remove() { parent.removeAtIndex(pos - 1); @@ -1571,17 +1567,13 @@ void wrap(ArrayContainer p) { parent = p; pos = 0; } - } - final class ReverseArrayContainerCharIterator implements PeekableCharIterator { int pos; private ArrayContainer parent; - ReverseArrayContainerCharIterator() { - - } + ReverseArrayContainerCharIterator() {} ReverseArrayContainerCharIterator(ArrayContainer p) { wrap(p); @@ -1597,7 +1589,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ArraysShim.java b/roaringbitmap/src/main/java/org/roaringbitmap/ArraysShim.java similarity index 82% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ArraysShim.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ArraysShim.java index ba8272f08..aa189615a 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ArraysShim.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ArraysShim.java @@ -43,22 +43,19 @@ public static boolean equals(char[] x, int xmin, int xmax, char[] y, int ymin, i * @param bToIndex exclusive * @return -1 if no mismatch found,otherwise the mismatch offset */ - public static int mismatch(byte[] a, int aFromIndex, int aToIndex, - byte[] b, int bFromIndex, int bToIndex) { + public static int mismatch( + byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) { int aLength = aToIndex - aFromIndex; int bLength = bToIndex - bFromIndex; int length = Math.min(aLength, bLength); - int i = 0; - boolean foundMismatch = false; - for (; i < length; i++) { + for (int i = 0; i < length; i++) { if (a[aFromIndex + i] != b[bFromIndex + i]) { - foundMismatch = true; - break; + return i; } } - if (!foundMismatch && aLength == bLength) { - return -1; + if (aLength != bLength) { + return length; } - return (!foundMismatch && aLength != bLength) ? length : i; + return -1; } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/BatchIntIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/BatchIntIterator.java similarity index 95% rename from RoaringBitmap/src/main/java/org/roaringbitmap/BatchIntIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/BatchIntIterator.java index e51ba5ea6..c40897a24 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/BatchIntIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/BatchIntIterator.java @@ -45,7 +45,7 @@ public int next() { @Override public IntIterator clone() { try { - BatchIntIterator it = (BatchIntIterator)super.clone(); + BatchIntIterator it = (BatchIntIterator) super.clone(); it.delegate = delegate.clone(); it.buffer = buffer.clone(); return it; diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/BatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/BatchIterator.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/BatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/BatchIterator.java index 07fcf7314..bc2f55f40 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/BatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/BatchIterator.java @@ -69,6 +69,4 @@ default IntIterator asIntIterator(int[] buffer) { * @param target threshold */ void advanceIfNeeded(int target); - - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/BitSetUtil.java b/roaringbitmap/src/main/java/org/roaringbitmap/BitSetUtil.java similarity index 54% rename from RoaringBitmap/src/main/java/org/roaringbitmap/BitSetUtil.java rename to roaringbitmap/src/main/java/org/roaringbitmap/BitSetUtil.java index 211e8f78b..f2ad81ffc 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/BitSetUtil.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/BitSetUtil.java @@ -1,42 +1,156 @@ package org.roaringbitmap; +import static java.lang.Long.numberOfTrailingZeros; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.BitSet; - /*** * * This class provides convenience functions to manipulate BitSet and RoaringBitmap objects. * */ public class BitSetUtil { - // todo: add a method to convert a RoaringBitmap to a BitSet using BitSet.valueOf // a block consists has a maximum of 1024 words, each representing 64 bits, // thus representing at maximum 65536 bits public static final int BLOCK_LENGTH = BitmapContainer.MAX_CAPACITY / Long.SIZE; // + // 64-bit // word - private static ArrayContainer arrayContainerOf(final int from, final int to, - final int cardinality, final long[] words) { - // precondition: cardinality is max 4096 - final char[] content = new char[cardinality]; - int index = 0; + /** + * Convert a {@link RoaringBitmap} to a {@link BitSet}. + *

+ * Equivalent to calling {@code BitSet.valueOf(BitSetUtil.toLongArray(bitmap))}. + */ + public static BitSet bitsetOf(RoaringBitmap bitmap) { + return BitSet.valueOf(toLongArray(bitmap)); + } - for (int i = from, socket = 0; i < to; ++i, socket += Long.SIZE) { + /** + * Convert a {@link RoaringBitmap} to a {@link BitSet} without copying to an intermediate array. + */ + public static BitSet bitsetOfWithoutCopy(RoaringBitmap bitmap) { + if (bitmap.isEmpty()) { + return new BitSet(0); + } + int last = bitmap.last(); + if (last < 0) { + throw new IllegalArgumentException("bitmap has negative bits set"); + } + BitSet bitSet = new BitSet(last); + bitmap.forEach((IntConsumer) bitSet::set); + return bitSet; + } + + /** + * Returns an array of little-endian ordered bytes, given a {@link RoaringBitmap}. + *

+ * See {@link BitSet#toByteArray()}. + */ + public static byte[] toByteArray(RoaringBitmap bitmap) { + long[] words = toLongArray(bitmap); + ByteBuffer buffer = + ByteBuffer.allocate(words.length * Long.SIZE).order(ByteOrder.LITTLE_ENDIAN); + buffer.asLongBuffer().put(words); + return buffer.array(); + } + + /** + * Returns an array of long, given a {@link RoaringBitmap}. + *

+ * See {@link BitSet#toLongArray()}. + */ + public static long[] toLongArray(RoaringBitmap bitmap) { + if (bitmap.isEmpty()) { + return new long[0]; + } + + int last = bitmap.last(); + if (last < 0) { + throw new IllegalArgumentException("bitmap has negative bits set"); + } + int lastBit = Math.max(last, Long.SIZE); + int remainder = lastBit % Long.SIZE; + int numBits = remainder > 0 ? lastBit - remainder : lastBit; + int wordsInUse = numBits / Long.SIZE + 1; + long[] words = new long[wordsInUse]; + + ContainerPointer pointer = bitmap.getContainerPointer(); + int numContainers = Math.max(words.length / BLOCK_LENGTH, 1); + int position = 0; + for (int i = 0; i <= numContainers; i++) { + char key = Util.lowbits(i); + if (key == pointer.key()) { + Container container = pointer.getContainer(); + int remaining = wordsInUse - position; + int length = Math.min(BLOCK_LENGTH, remaining); + if (container instanceof BitmapContainer) { + ((BitmapContainer) container).copyBitmapTo(words, position, length); + } else { + container.copyBitmapTo(words, position); + } + position += length; + pointer.advance(); + if (pointer.getContainer() == null) { + break; + } + } else { + position += BLOCK_LENGTH; + } + } + assert pointer.getContainer() == null; + assert position == wordsInUse; + return words; + } + + /** + * Creates array container's content char buffer. + * + * @param from first value of the range + * @param to last value of the range + * @param cardinality new buffer cardinality, expected to be less than 4096 and more than present + * values in given bitmap + * @param words bitmap + * @return array container's content char buffer + */ + public static char[] arrayContainerBufferOf( + final int from, final int to, final int cardinality, final long[] words) { + return arrayContainerBufferOf(from, to, new char[cardinality], words); + } + + /** + * Creates array container's content char buffer. + * + * @param from first value of the range + * @param to last value of the range + * @param buffer new buffer, expected to have size less than 4096 and more than present + * values in given bitmap + * @param words bitmap + * @return array container's content char buffer - the same as {@code buffer} + */ + public static char[] arrayContainerBufferOf( + final int from, final int to, final char[] buffer, final long[] words) { + // precondition: cardinality is max 4096 + int base = 0; + int pos = 0; + for (int i = from; i < to; i++) { long word = words[i]; - while (word != 0) { - long t = word & -word; - content[index++] = (char) (socket + Long.bitCount(t - 1)); - word ^= t; + while (word != 0L) { + buffer[pos++] = (char) (base + numberOfTrailingZeros(word)); + word &= (word - 1); } + base += 64; } - return new ArrayContainer(content); + return buffer; } + private static ArrayContainer arrayContainerOf( + final int from, final int to, final int cardinality, final long[] words) { + return new ArrayContainer(arrayContainerBufferOf(from, to, cardinality, words)); + } /** * Generate a RoaringBitmap out of a BitSet @@ -65,7 +179,9 @@ public static RoaringBitmap bitmapOf(final long[] words) { final int to = Math.min(from + BLOCK_LENGTH, words.length); final int blockCardinality = cardinality(from, to, words); if (blockCardinality > 0) { - ans.highLowContainer.insertNewKeyValueAt(containerIndex++, Util.highbits(from * Long.SIZE), + ans.highLowContainer.insertNewKeyValueAt( + containerIndex++, + Util.highbits(from * Long.SIZE), BitSetUtil.containerOf(from, to, blockCardinality, words)); } } @@ -122,13 +238,15 @@ public static RoaringBitmap bitmapOf(ByteBuffer bb, boolean fastRank, long[] wor if (blockLength == BLOCK_LENGTH) { // Each block becomes a single container, if any bit is set if (blockCardinality > 0) { - ans.highLowContainer.insertNewKeyValueAt(containerIndex++, Util.highbits(offset), + ans.highLowContainer.insertNewKeyValueAt( + containerIndex++, + Util.highbits(offset), BitSetUtil.containerOf(0, blockLength, blockCardinality, wordsBuffer)); } /* - Offset can overflow when bitsets size is more than Integer.MAX_VALUE - 64 - It's harmless though, as it will happen after the last block is added - */ + Offset can overflow when bitsets size is more than Integer.MAX_VALUE - 64 + It's harmless though, as it will happen after the last block is added + */ offset += (BLOCK_LENGTH * Long.SIZE); blockLength = blockCardinality = 0; } @@ -151,7 +269,9 @@ public static RoaringBitmap bitmapOf(ByteBuffer bb, boolean fastRank, long[] wor // Add block to map, if any bit is set if (blockCardinality > 0) { - ans.highLowContainer.insertNewKeyValueAt(containerIndex, Util.highbits(offset), + ans.highLowContainer.insertNewKeyValueAt( + containerIndex, + Util.highbits(offset), BitSetUtil.containerOf(0, blockLength, blockCardinality, wordsBuffer)); } return ans; @@ -165,9 +285,8 @@ private static int cardinality(final int from, final int to, final long[] words) return sum; } - - private static Container containerOf(final int from, final int to, final int blockCardinality, - final long[] words) { + private static Container containerOf( + final int from, final int to, final int blockCardinality, final long[] words) { // find the best container available if (blockCardinality <= ArrayContainer.DEFAULT_MAX_SIZE) { // containers with DEFAULT_MAX_SIZE or less integers should be @@ -181,7 +300,6 @@ private static Container containerOf(final int from, final int to, final int blo } } - /** * Compares a RoaringBitmap and a BitSet. They are equal if and only if they contain the same set * of integers. diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/BitmapBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/BitmapBatchIterator.java similarity index 67% rename from RoaringBitmap/src/main/java/org/roaringbitmap/BitmapBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/BitmapBatchIterator.java index 4774c639f..c9b754d13 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/BitmapBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/BitmapBatchIterator.java @@ -13,9 +13,9 @@ public BitmapBatchIterator(BitmapContainer bitmap) { } @Override - public int next(int key, int[] buffer) { + public int next(int key, int[] buffer, int offset) { int consumed = 0; - while (consumed < buffer.length) { + while ((consumed + offset) < buffer.length) { while (word == 0) { ++wordIndex; if (wordIndex == 1024) { @@ -23,7 +23,7 @@ public int next(int key, int[] buffer) { } word = bitmap.bitmap[wordIndex]; } - buffer[consumed++] = key + (64 * wordIndex) + numberOfTrailingZeros(word); + buffer[offset + consumed++] = key + (64 * wordIndex) + numberOfTrailingZeros(word); word &= (word - 1); } return consumed; @@ -31,13 +31,23 @@ public int next(int key, int[] buffer) { @Override public boolean hasNext() { - return wordIndex < 1024; + if (wordIndex > 1023) { + return false; + } + while (word == 0) { + ++wordIndex; + if (wordIndex == 1024) { // reached end without a non-empty word + return false; + } + word = bitmap.bitmap[wordIndex]; + } + return true; // found some non-empty word, so hasNext } @Override public ContainerBatchIterator clone() { try { - return (ContainerBatchIterator)super.clone(); + return (ContainerBatchIterator) super.clone(); } catch (CloneNotSupportedException e) { // won't happen throw new IllegalStateException(e); diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/BitmapContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/BitmapContainer.java similarity index 90% rename from RoaringBitmap/src/main/java/org/roaringbitmap/BitmapContainer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/BitmapContainer.java index 884d383b9..80298a303 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/BitmapContainer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/BitmapContainer.java @@ -4,32 +4,39 @@ package org.roaringbitmap; +import static java.lang.Long.bitCount; +import static java.lang.Long.numberOfTrailingZeros; + import org.roaringbitmap.buffer.MappeableBitmapContainer; import org.roaringbitmap.buffer.MappeableContainer; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.LongBuffer; import java.util.Arrays; import java.util.Iterator; -import static java.lang.Long.bitCount; -import static java.lang.Long.numberOfTrailingZeros; - - /** * Simple bitset-like container. */ public final class BitmapContainer extends Container implements Cloneable { public static final int MAX_CAPACITY = 1 << 16; + private static final int MAX_CAPACITY_BYTE = MAX_CAPACITY / Byte.SIZE; + + private static final int MAX_CAPACITY_LONG = MAX_CAPACITY / Long.SIZE; - private static final long serialVersionUID = 2L; + private static final long serialVersionUID = 3L; // bail out early when the number of runs is excessive, without // an exact count (just a decent lower bound) private static final int BLOCKSIZE = 128; + // 64 words can have max 32 runs per word, max 2k runs /** @@ -69,19 +76,16 @@ protected static int serializedSizeInBytes(int unusedCardinality) { // nruns value for which RunContainer.serializedSizeInBytes == // BitmapContainer.getArraySizeInBytes() - private final int MAXRUNS = (getArraySizeInBytes() - 2) / 4; - + private static final int MAXRUNS = (MAX_CAPACITY_BYTE - 2) / 4; /** * Create a bitmap container with all bits set to false */ public BitmapContainer() { this.cardinality = 0; - this.bitmap = new long[MAX_CAPACITY / 64]; + this.bitmap = new long[MAX_CAPACITY_LONG]; } - - /** * Create a bitmap container with a run of ones from firstOfRun to lastOfRun. Caller must ensure * that the range isn't so small that an ArrayContainer should have been created instead @@ -111,8 +115,6 @@ public BitmapContainer(long[] newBitmap, int newCardinality) { this.bitmap = newBitmap; } - - /** * Creates a new non-mappeable container from a mappeable one. This copies the data. * @@ -123,7 +125,6 @@ public BitmapContainer(MappeableBitmapContainer bc) { this.bitmap = bc.toLongArray(); } - @Override public Container add(int begin, int end) { // TODO: may need to convert to a RunContainer @@ -140,15 +141,13 @@ public Container add(int begin, int end) { return answer; } - - @Override public Container add(final char i) { final long previous = bitmap[i >>> 6]; long newval = previous | (1L << i); bitmap[i >>> 6] = newval; if (USE_BRANCHLESS) { - cardinality += (int)((previous ^ newval) >>> i); + cardinality += (int) ((previous ^ newval) >>> i); } else if (previous != newval) { ++cardinality; } @@ -162,7 +161,7 @@ public ArrayContainer and(final ArrayContainer value2) { for (int k = 0; k < c; ++k) { char v = value2.content[k]; answer.content[answer.cardinality] = v; - answer.cardinality += (int)this.bitValue(v); + answer.cardinality += (int) this.bitValue(v); } return answer; } @@ -195,7 +194,7 @@ public int andCardinality(final ArrayContainer value2) { int c = value2.cardinality; for (int k = 0; k < c; ++k) { char v = value2.content[k]; - answer += (int)this.bitValue(v); + answer += (int) this.bitValue(v); } return answer; } @@ -342,13 +341,13 @@ public boolean contains(int minimum, int supremum) { @Override protected boolean contains(BitmapContainer bitmapContainer) { - if((cardinality != -1) && (bitmapContainer.cardinality != -1)) { - if(cardinality < bitmapContainer.cardinality) { + if ((cardinality != -1) && (bitmapContainer.cardinality != -1)) { + if (cardinality < bitmapContainer.cardinality) { return false; } } - for(int i = 0; i < bitmapContainer.bitmap.length; ++i ) { - if((this.bitmap[i] & bitmapContainer.bitmap[i]) != bitmapContainer.bitmap[i]) { + for (int i = 0; i < bitmapContainer.bitmap.length; ++i) { + if ((this.bitmap[i] & bitmapContainer.bitmap[i]) != bitmapContainer.bitmap[i]) { return false; } } @@ -386,19 +385,17 @@ protected boolean contains(ArrayContainer arrayContainer) { } } for (int i = 0; i < arrayContainer.cardinality; ++i) { - if(!contains(arrayContainer.content[i])) { + if (!contains(arrayContainer.content[i])) { return false; } } return true; } - int bitValue(final char i) { - return (int)(bitmap[i >>> 6] >>> i ) & 1; + return (int) (bitmap[i >>> 6] >>> i) & 1; } - @Override public void deserialize(DataInput in) throws IOException { // little endian @@ -424,23 +421,13 @@ public boolean equals(Object o) { return false; } - /** * Fill the array with set bits * * @param array container (should be sufficiently large) */ void fillArray(final char[] array) { - int pos = 0; - int base = 0; - for (int k = 0; k < bitmap.length; ++k) { - long bitset = bitmap[k]; - while (bitset != 0) { - array[pos++] = (char) (base + numberOfTrailingZeros(bitset)); - bitset &= (bitset - 1); - } - base += 64; - } + BitSetUtil.arrayContainerBufferOf(0, bitmap.length, array, bitmap); } @Override @@ -457,13 +444,12 @@ public void fillLeastSignificant16bits(int[] x, int i, int mask) { } } - @Override public Container flip(char i) { int index = i >>> 6; long bef = bitmap[index]; long mask = 1L << i; - if (cardinality == ArrayContainer.DEFAULT_MAX_SIZE + 1) {// this is + if (cardinality == ArrayContainer.DEFAULT_MAX_SIZE + 1) { // this is // the // uncommon // path @@ -474,14 +460,14 @@ public Container flip(char i) { } } // TODO: check whether a branchy version could be faster - cardinality += 1 - 2 * (int)((bef & mask) >>> i); + cardinality += 1 - 2 * (int) ((bef & mask) >>> i); bitmap[index] ^= mask; return this; } @Override public int getArraySizeInBytes() { - return MAX_CAPACITY / 8; + return MAX_CAPACITY_BYTE; } @Override @@ -582,7 +568,7 @@ public Container iand(RunContainer x) { int runEnd = runStart + (x.getLength(rlepos)); for (int runValue = runStart; runValue <= runEnd; ++runValue) { answer.content[answer.cardinality] = (char) runValue; - answer.cardinality += (int)this.bitValue((char) runValue); + answer.cardinality += (int) this.bitValue((char) runValue); } } return answer; @@ -661,7 +647,7 @@ public Container iandNot(RunContainer x) { } Container ilazyor(ArrayContainer value2) { - this.cardinality = -1;// invalid + this.cardinality = -1; // invalid int c = value2.cardinality; for (int k = 0; k < c; ++k) { char v = value2.content[k]; @@ -672,7 +658,7 @@ Container ilazyor(ArrayContainer value2) { } Container ilazyor(BitmapContainer x) { - this.cardinality = -1;// invalid + this.cardinality = -1; // invalid for (int k = 0; k < this.bitmap.length; k++) { this.bitmap[k] |= x.bitmap[k]; } @@ -729,7 +715,7 @@ public boolean intersects(RunContainer x) { @Override public boolean intersects(int minimum, int supremum) { - if((minimum < 0) || (supremum < minimum) || (supremum > (1<<16))) { + if ((minimum < 0) || (supremum < minimum) || (supremum > (1 << 16))) { throw new RuntimeException("This should never happen (bug)."); } int start = minimum >>> 6; @@ -761,7 +747,7 @@ public BitmapContainer ior(final ArrayContainer value2) { long aft = bef | (1L << value2.content[k]); this.bitmap[i] = aft; if (USE_BRANCHLESS) { - cardinality += (int)((bef - aft) >>> 63); + cardinality += (int) ((bef - aft) >>> 63); } else { if (bef != aft) { cardinality++; @@ -848,7 +834,7 @@ public Container ixor(final ArrayContainer value2) { final int index = (vc) >>> 6; long ba = this.bitmap[index]; // TODO: check whether a branchy version could be faster - this.cardinality += 1 - 2 * (int)((ba & mask) >>> vc); + this.cardinality += 1 - 2 * (int) ((ba & mask) >>> vc); this.bitmap[index] = ba ^ mask; } if (this.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) { @@ -857,7 +843,6 @@ public Container ixor(final ArrayContainer value2) { return this; } - @Override public Container ixor(BitmapContainer b2) { // do this first because we have to compute the xor no matter what, and this loop gets @@ -892,7 +877,7 @@ public Container ixor(RunContainer x) { protected Container lazyor(ArrayContainer value2) { BitmapContainer answer = this.clone(); - answer.cardinality = -1;// invalid + answer.cardinality = -1; // invalid int c = value2.cardinality; for (int k = 0; k < c; ++k) { char v = value2.content[k]; @@ -904,14 +889,13 @@ protected Container lazyor(ArrayContainer value2) { protected Container lazyor(BitmapContainer x) { BitmapContainer answer = new BitmapContainer(); - answer.cardinality = -1;// invalid + answer.cardinality = -1; // invalid for (int k = 0; k < this.bitmap.length; k++) { answer.bitmap[k] = this.bitmap[k] | x.bitmap[k]; } return answer; } - protected Container lazyor(RunContainer x) { BitmapContainer bc = clone(); bc.cardinality = -1; // invalid @@ -941,13 +925,11 @@ public Container limit(int maxcardinality) { } return ac; } - BitmapContainer bc = new BitmapContainer(maxcardinality, this.bitmap); + long[] newBitmap = new long[MAX_CAPACITY / 64]; + BitmapContainer bc = new BitmapContainer(newBitmap, maxcardinality); int s = (select(maxcardinality)); int usedwords = (s + 63) / 64; - int todelete = this.bitmap.length - usedwords; - for (int k = 0; k < todelete; ++k) { - bc.bitmap[bc.bitmap.length - 1 - k] = 0; - } + System.arraycopy(this.bitmap, 0, newBitmap, 0, usedwords); int lastword = s % 64; if (lastword != 0) { bc.bitmap[s / 64] &= (0xFFFFFFFFFFFFFFFFL >>> (64 - lastword)); @@ -1006,7 +988,6 @@ private int nextClearBit(final int i) { return MAX_CAPACITY; } - @Override public Container not(final int firstOfRange, final int lastOfRange) { BitmapContainer answer = clone(); @@ -1021,7 +1002,7 @@ int numberOfRuns() { for (int i = 0; i < bitmap.length - 1; i++) { long word = nextWord; nextWord = bitmap[i + 1]; - numRuns += Long.bitCount((~word) & (word << 1)) + (int)((word >>> 63) & ~nextWord); + numRuns += Long.bitCount((~word) & (word << 1)) + (int) ((word >>> 63) & ~nextWord); } long word = nextWord; @@ -1045,7 +1026,7 @@ public int numberOfRunsAdjustment() { final long word = nextWord; nextWord = bitmap[i + 1]; - ans += (int)((word >>> 63) & ~nextWord); + ans += (int) ((word >>> 63) & ~nextWord); } final long word = nextWord; @@ -1088,7 +1069,7 @@ public Container or(final ArrayContainer value2) { long aft = w | (1L << v); answer.bitmap[i] = aft; if (USE_BRANCHLESS) { - answer.cardinality += (int)((w - aft) >>> 63); + answer.cardinality += (int) ((w - aft) >>> 63); } else { if (w != aft) { answer.cardinality++; @@ -1178,7 +1159,6 @@ public void readExternal(ObjectInput in) throws IOException { deserialize(in); } - @Override public Container remove(int begin, int end) { if (end == begin) { @@ -1202,7 +1182,7 @@ public Container remove(final char i) { int index = i >>> 6; long bef = bitmap[index]; long mask = 1L << i; - if (cardinality == ArrayContainer.DEFAULT_MAX_SIZE + 1) {// this is + if (cardinality == ArrayContainer.DEFAULT_MAX_SIZE + 1) { // this is // the // uncommon // path @@ -1222,7 +1202,7 @@ public Container remove(final char i) { public Container repairAfterLazy() { if (getCardinality() < 0) { computeCardinality(); - if(getCardinality() <= ArrayContainer.DEFAULT_MAX_SIZE) { + if (getCardinality() <= ArrayContainer.DEFAULT_MAX_SIZE) { return this.toArrayContainer(); } else if (isFull()) { return RunContainer.full(); @@ -1255,6 +1235,41 @@ public Container runOptimize() { @Override public char select(int j) { + if ( // cardinality != -1 && // omitted as (-1>>>1) > j as j < (1<<16) + cardinality >>> 1 < j && j < cardinality) { + int leftover = cardinality - j; + for (int k = bitmap.length - 1; k >= 0; --k) { + long w = bitmap[k]; + if (w != 0) { + int bits = Long.bitCount(w); + if (bits >= leftover) { + return (char) (k * 64 + Util.select(w, bits - leftover)); + } + leftover -= bits; + } + } + } else { + int leftover = j; + for (int k = 0; k < bitmap.length; ++k) { + long w = bitmap[k]; + if (w != 0) { + int bits = Long.bitCount(bitmap[k]); + if (bits > leftover) { + return (char) (k * 64 + Util.select(bitmap[k], leftover)); + } + leftover -= bits; + } + } + } + throw new IllegalArgumentException("Insufficient cardinality."); + } + + /** TODO For comparison only, should be removed before merge. + * + * @param j ... + * @return ... + */ + public char selectOneSide(int j) { int leftover = j; for (int k = 0; k < bitmap.length; ++k) { int w = Long.bitCount(bitmap[k]); @@ -1318,7 +1333,7 @@ public String toString() { final CharIterator i = this.getCharIterator(); sb.append('{'); while (i.hasNext()) { - sb.append((int)(i.next())); + sb.append((int) (i.next())); if (i.hasNext()) { sb.append(','); } @@ -1328,9 +1343,7 @@ public String toString() { } @Override - public void trim() { - - } + public void trim() {} @Override public void writeArray(DataOutput out) throws IOException { @@ -1361,7 +1374,7 @@ public Container xor(final ArrayContainer value2) { final long mask = 1L << vc; final long val = answer.bitmap[index]; // TODO: check whether a branchy version could be faster - answer.cardinality += (int)(1 - 2 * ((val & mask) >>> vc)); + answer.cardinality += (int) (1 - 2 * ((val & mask) >>> vc)); answer.bitmap[index] = val ^ mask; } if (answer.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) { @@ -1610,19 +1623,13 @@ public void forAllInRange(char startValue, char endValue, final RelativeRangeCon return; } else { addWholeWordToRangeConsumer( - word, - wordStart - startValue, - wordEndExclusive - startValue, - rrc); + word, wordStart - startValue, wordEndExclusive - startValue, rrc); } } } private void addWholeWordToRangeConsumer( - long word, - int bufferWordStart, - int bufferWordEnd, - final RelativeRangeConsumer rrc) { + long word, int bufferWordStart, int bufferWordEnd, final RelativeRangeConsumer rrc) { // some special cases for efficiency if (word == 0) { rrc.acceptAllAbsent(bufferWordStart, bufferWordEnd); @@ -1651,6 +1658,15 @@ public BitmapContainer toBitmapContainer() { return this; } + @Override + public void copyBitmapTo(long[] words, int position) { + System.arraycopy(bitmap, 0, words, position, bitmap.length); + } + + public void copyBitmapTo(long[] words, int position, int length) { + System.arraycopy(bitmap, 0, words, position, length); + } + @Override public int nextValue(char fromValue) { return nextSetBit((fromValue)); @@ -1675,7 +1691,7 @@ public int previousAbsentValue(char fromValue) { public int first() { assertNonEmpty(cardinality == 0); int i = 0; - while(i < bitmap.length - 1 && bitmap[i] == 0) { + while (i < bitmap.length - 1 && bitmap[i] == 0) { ++i; // seek forward } // sizeof(long) * #empty words at start + number of bits preceding the first bit set @@ -1686,16 +1702,14 @@ public int first() { public int last() { assertNonEmpty(cardinality == 0); int i = bitmap.length - 1; - while(i > 0 && bitmap[i] == 0) { + while (i > 0 && bitmap[i] == 0) { --i; // seek backward } // sizeof(long) * #words from start - number of bits after the last bit set return (i + 1) * 64 - Long.numberOfLeadingZeros(bitmap[i]) - 1; } - } - class BitmapContainerCharIterator implements PeekableCharIterator { long w; @@ -1703,9 +1717,7 @@ class BitmapContainerCharIterator implements PeekableCharIterator { long[] bitmap; - BitmapContainerCharIterator() { - - } + BitmapContainerCharIterator() {} BitmapContainerCharIterator(long[] p) { wrap(p); @@ -1716,7 +1728,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -1739,8 +1751,6 @@ public char next() { return answer; } - - @Override public int nextAsInt() { return (next()); @@ -1752,7 +1762,6 @@ public void remove() { throw new RuntimeException("unsupported operation: remove"); } - public void wrap(long[] b) { bitmap = b; for (x = 0; x < bitmap.length; ++x) { @@ -1764,20 +1773,23 @@ public void wrap(long[] b) { @Override public void advanceIfNeeded(char minval) { - if ((minval) >= (x + 1) * 64) { - x = (minval) / 64; - w = bitmap[x]; + if (!hasNext()) { + return; + } + if (minval >= x * 64) { + if (minval >= (x + 1) * 64) { + x = minval / 64; + w = bitmap[x]; + } + w &= ~0L << (minval & 63); while (w == 0) { - ++x; - if (x == bitmap.length) { + x++; + if (!hasNext()) { return; } w = bitmap[x]; } } - while (hasNext() && ((peekNext()) < (minval))) { - next(); // could be optimized - } } @Override @@ -1807,29 +1819,30 @@ public char next() { @Override public void advanceIfNeeded(char minval) { - if ((minval) >= (x + 1) * 64) { - - int nextX = (minval) / 64; - nextRank += bitCount(w); - for(x = x + 1; x < nextX; ++x) { - w = bitmap[x]; + if (!hasNext()) { + return; + } + if (minval >= x * 64) { + if (minval >= (x + 1) * 64) { + int nextX = minval / 64; nextRank += bitCount(w); + for (x = x + 1; x < nextX; x++) { + w = bitmap[x]; + nextRank += bitCount(w); + } + w = bitmap[nextX]; } - - x = nextX; - w = bitmap[x]; - + nextRank += bitCount(w); + w &= ~0L << (minval & 63); + nextRank -= bitCount(w); while (w == 0) { ++x; - if (x == bitmap.length) { + if (!hasNext()) { return; } w = bitmap[x]; } } - while (hasNext() && ((peekNext()) < (minval))) { - next(); // could be optimized - } } @Override @@ -1845,9 +1858,7 @@ final class ReverseBitmapContainerCharIterator implements PeekableCharIterator { long[] bitmap; - ReverseBitmapContainerCharIterator() { - - } + ReverseBitmapContainerCharIterator() {} ReverseBitmapContainerCharIterator(long[] bitmap) { wrap(bitmap); @@ -1870,7 +1881,7 @@ public boolean hasNext() { @Override public char next() { int shift = Long.numberOfLeadingZeros(word) + 1; - char answer = (char)((position + 1) * 64 - shift); + char answer = (char) ((position + 1) * 64 - shift); word &= (0xFFFFFFFFFFFFFFFEL >>> shift); while (word == 0) { --position; @@ -1886,22 +1897,25 @@ public char next() { public int nextAsInt() { return next(); } - + @Override public void advanceIfNeeded(char maxval) { - if ((maxval) <= (position - 1) * 64) { - position = (maxval) / 64; - word = bitmap[position]; - while (word == 0) { - --position; - if (position == 0) { - break; + if (maxval < (position + 1) * 64) { + if (maxval < position * 64) { + position = maxval / 64; + } + long currentWord = bitmap[position]; + currentWord &= ~0L >>> (63 - (maxval & 63)); + if (position > 0) { + while (currentWord == 0) { + position--; + if (position == 0) { + break; + } + currentWord = bitmap[position]; } - word = bitmap[position]; } - } - while (hasNext() && ((peekNext()) > (maxval))) { - next(); // could be optimized + word = currentWord; } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/BitmapDataProvider.java b/roaringbitmap/src/main/java/org/roaringbitmap/BitmapDataProvider.java similarity index 100% rename from RoaringBitmap/src/main/java/org/roaringbitmap/BitmapDataProvider.java rename to roaringbitmap/src/main/java/org/roaringbitmap/BitmapDataProvider.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/BitmapDataProviderSupplier.java b/roaringbitmap/src/main/java/org/roaringbitmap/BitmapDataProviderSupplier.java similarity index 98% rename from RoaringBitmap/src/main/java/org/roaringbitmap/BitmapDataProviderSupplier.java rename to roaringbitmap/src/main/java/org/roaringbitmap/BitmapDataProviderSupplier.java index f38fbfcf0..e8d64716f 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/BitmapDataProviderSupplier.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/BitmapDataProviderSupplier.java @@ -7,7 +7,7 @@ /** * Enable customizing the {@link BitmapDataProvider} used by {@link Roaring64NavigableMap} - * + * * @author Benoit Lacelle * */ diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/CharIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/CharIterator.java similarity index 98% rename from RoaringBitmap/src/main/java/org/roaringbitmap/CharIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/CharIterator.java index 1ea32a841..ed52cc7e8 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/CharIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/CharIterator.java @@ -10,7 +10,7 @@ public interface CharIterator extends Cloneable { /** * Creates a copy of the iterator. - * + * * @return a clone of the current iterator */ CharIterator clone(); @@ -20,7 +20,6 @@ public interface CharIterator extends Cloneable { */ boolean hasNext(); - /** * @return next char value */ @@ -35,5 +34,4 @@ public interface CharIterator extends Cloneable { * If possible, remove the current value */ void remove(); - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ConstantMemoryContainerAppender.java b/roaringbitmap/src/main/java/org/roaringbitmap/ConstantMemoryContainerAppender.java similarity index 88% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ConstantMemoryContainerAppender.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ConstantMemoryContainerAppender.java index a0e2ca1f0..98409dee7 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ConstantMemoryContainerAppender.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ConstantMemoryContainerAppender.java @@ -1,11 +1,12 @@ package org.roaringbitmap; +import static org.roaringbitmap.Util.highbits; +import static org.roaringbitmap.Util.lowbits; +import static org.roaringbitmap.Util.partialRadixSort; + import java.util.Arrays; import java.util.function.Supplier; -import static org.roaringbitmap.Util.*; - - /** * This class can be used to write quickly values to a bitmap. * The values are expected to be (increasing) sorted order. @@ -31,8 +32,9 @@ * } * */ -public class ConstantMemoryContainerAppender> implements RoaringBitmapWriter { +public class ConstantMemoryContainerAppender< + T extends BitmapDataProvider & AppendableStorage> + implements RoaringBitmapWriter { private final boolean doPartialSort; private final boolean runCompress; @@ -50,9 +52,8 @@ public class ConstantMemoryContainerAppender newUnderlying) { + ConstantMemoryContainerAppender( + boolean doPartialSort, boolean runCompress, Supplier newUnderlying) { this.newUnderlying = newUnderlying; this.underlying = newUnderlying.get(); this.doPartialSort = doPartialSort; @@ -108,7 +109,7 @@ public void addMany(int... values) { public void add(long min, long max) { appendToUnderlying(); underlying.add(min, max); - int mark = (int)((max >>> 16) + 1); + int mark = (int) ((max >>> 16) + 1); if (currentKey < mark) { currentKey = mark; } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/Container.java b/roaringbitmap/src/main/java/org/roaringbitmap/Container.java similarity index 96% rename from RoaringBitmap/src/main/java/org/roaringbitmap/Container.java rename to roaringbitmap/src/main/java/org/roaringbitmap/Container.java index cdb7a3f9f..788a3cd42 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/Container.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/Container.java @@ -16,8 +16,8 @@ /** * Base container class. */ -public abstract class Container implements Iterable, Cloneable, Externalizable, - WordStorage { +public abstract class Container + implements Iterable, Cloneable, Externalizable, WordStorage { /** * Create a container initialized with a range of consecutive values @@ -87,7 +87,6 @@ public Container and(Container x) { return and((RunContainer) x); } - /** * Computes the bitwise AND of this container with another (intersection). This container as well * as the provided container are left unaffected. @@ -135,7 +134,6 @@ public int xorCardinality(Container other) { return getCardinality() + other.getCardinality() - 2 * andCardinality(other); } - /** * Computes the bitwise ANDNOT of this container with another (difference). This container as well * as the provided container are left unaffected. @@ -170,7 +168,6 @@ public Container andNot(Container x) { return andNot((RunContainer) x); } - /** * Computes the bitwise ANDNOT of this container with another (difference). This container as well * as the provided container are left unaffected. @@ -231,24 +228,22 @@ public Container orNot(Container x, int endOfRange) { */ public abstract boolean contains(int minimum, int supremum); - /** * Checks whether the container is a subset of this container or not * @param subset the container to be tested * @return true if the parameter is a subset of this container */ public boolean contains(Container subset) { - if(subset instanceof RunContainer) { - return contains((RunContainer)subset); - } else if(subset instanceof ArrayContainer) { + if (subset instanceof RunContainer) { + return contains((RunContainer) subset); + } else if (subset instanceof ArrayContainer) { return contains((ArrayContainer) subset); - } else if(subset instanceof BitmapContainer){ - return contains((BitmapContainer)subset); + } else if (subset instanceof BitmapContainer) { + return contains((BitmapContainer) subset); } return false; } - protected abstract boolean contains(RunContainer runContainer); protected abstract boolean contains(ArrayContainer arrayContainer); @@ -263,7 +258,6 @@ public boolean contains(Container subset) { */ public abstract void deserialize(DataInput in) throws IOException; - /** * Fill the least significant 16 bits of the integer array, starting at index i, with the short * values from this container. The caller is responsible to allocate enough room. The most @@ -276,8 +270,6 @@ public boolean contains(Container subset) { */ public abstract void fillLeastSignificant16bits(int[] x, int i, int mask); - - /** * Add a short to the container if it is not present, otherwise remove it. May generate a new * container. @@ -320,8 +312,7 @@ public String getContainerName() { /** * Name of the various possible containers */ - public static final String[] ContainerNames = {"bitmap","array","run"}; - + public static final String[] ContainerNames = {"bitmap", "array", "run"}; /** * Iterate through the values of this container and pass them @@ -365,10 +356,7 @@ public String getContainerName() { * @param endValue First value greater than last value to consume. * @param rrc consumer */ - public abstract void forAllUntil( - int offset, - char endValue, - final RelativeRangeConsumer rrc); + public abstract void forAllUntil(int offset, char endValue, final RelativeRangeConsumer rrc); /** * Consumer presence information for all values in the @@ -379,9 +367,7 @@ public abstract void forAllUntil( * @param rrc consumer */ public abstract void forAllInRange( - char startValue, - char endValue, - final RelativeRangeConsumer rrc); + char startValue, char endValue, final RelativeRangeConsumer rrc); /** * Iterator to visit the char values in the container in descending order. @@ -437,7 +423,6 @@ public abstract void forAllInRange( */ public abstract Container iand(ArrayContainer x); - /** * Computes the in-place bitwise AND of this container with another (intersection). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate @@ -485,7 +470,6 @@ public Container iand(Container x) { */ public abstract Container iandNot(ArrayContainer x); - /** * Computes the in-place bitwise ANDNOT of this container with another (difference). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate @@ -523,7 +507,6 @@ public Container iandNot(Container x) { */ public abstract Container iandNot(RunContainer x); - /** * Computes the in-place bitwise ORNOT of this container with another. The current * container is generally modified, whereas the provided container (x) is unaffected. May generate @@ -540,9 +523,6 @@ public Container iorNot(Container x, int endOfRange) { return ior(x.not(0, 0x10000)); } - - - /** * Computes the in-place bitwise NOT of this container (complement). Only those bits within the * range are affected. The current container is generally modified. May generate a new container. @@ -676,7 +656,6 @@ public Container ior(Container x) { */ public abstract Container ixor(BitmapContainer x); - /** * Computes the in-place bitwise OR of this container with another (union). The current container * is generally modified, whereas the provided container (x) is unaffected. May generate a new @@ -717,7 +696,7 @@ public Container ixor(Container x) { public Container lazyIOR(Container x) { if (this instanceof ArrayContainer) { if (x instanceof ArrayContainer) { - return ((ArrayContainer)this).lazyor((ArrayContainer) x); + return ((ArrayContainer) this).lazyor((ArrayContainer) x); } else if (x instanceof BitmapContainer) { return ior((BitmapContainer) x); } @@ -751,7 +730,7 @@ public Container lazyIOR(Container x) { public Container lazyOR(Container x) { if (this instanceof ArrayContainer) { if (x instanceof ArrayContainer) { - return ((ArrayContainer)this).lazyor((ArrayContainer) x); + return ((ArrayContainer) this).lazyor((ArrayContainer) x); } else if (x instanceof BitmapContainer) { return ((BitmapContainer) x).lazyor((ArrayContainer) this); } @@ -793,7 +772,6 @@ public Container lazyOR(Container x) { abstract int numberOfRuns(); // exact - /** * Computes the bitwise OR of this container with another (union). This container as well as the * provided container are left unaffected. @@ -837,7 +815,6 @@ public Container or(Container x) { */ public abstract Container or(RunContainer x); - /** * Rank returns the number of integers that are smaller or equal to x (Rank(infinity) would be * GetCardinality()). @@ -898,7 +875,6 @@ public Container or(Container x) { */ public abstract void serialize(DataOutput out) throws IOException; - /** * Report the number of bytes required to serialize this container. * @@ -913,7 +889,6 @@ public Container or(Container x) { */ public abstract MappeableContainer toMappeableContainer(); - /** * If possible, recover wasted memory. */ @@ -934,7 +909,6 @@ public Container or(Container x) { */ public abstract void writeArray(ByteBuffer buffer); - /** * Computes the bitwise XOR of this container with another (symmetric difference). This container * as well as the provided container are left unaffected. @@ -953,7 +927,6 @@ public Container or(Container x) { */ public abstract Container xor(BitmapContainer x); - /** * Computes the bitwise XOR of this container with another (symmetric difference). This container * as well as the provided container are left unaffected. @@ -986,6 +959,17 @@ public Container xor(Container x) { */ public abstract BitmapContainer toBitmapContainer(); + /** + * Copy the current container to a destination {@code long[]}. Equivalent to calling + * {@link #toBitmapContainer()} and copying the result to the given position. The destination + * array should be sized to accomodate the maximum number of words required to represent + * the container bitmap. + * + * @param dest the destination array + * @param position the position to copy to + */ + public abstract void copyBitmapTo(long[] dest, int position); + /** * Gets the first value greater than or equal to the lower bound, or -1 if no such value exists. * @param fromValue the lower bound (inclusive) @@ -1014,7 +998,6 @@ public Container xor(Container x) { */ public abstract int previousAbsentValue(char fromValue); - /** * Get the first integer held in the container * @return the first integer in the container @@ -1035,7 +1018,7 @@ public Container xor(Container x) { * @throws NoSuchElementException if empty */ protected void assertNonEmpty(boolean condition) { - if(condition) { + if (condition) { throw new NoSuchElementException("Empty " + getContainerName()); } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ContainerAppender.java b/roaringbitmap/src/main/java/org/roaringbitmap/ContainerAppender.java similarity index 83% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ContainerAppender.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ContainerAppender.java index 09bb3d91f..3dc5c72ec 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ContainerAppender.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ContainerAppender.java @@ -1,10 +1,11 @@ package org.roaringbitmap; +import static org.roaringbitmap.Util.highbits; +import static org.roaringbitmap.Util.lowbits; +import static org.roaringbitmap.Util.partialRadixSort; import java.util.function.Supplier; -import static org.roaringbitmap.Util.*; - /** * This class can be used to write quickly values to a bitmap. * The values are expected to be (increasing) sorted order. @@ -29,10 +30,9 @@ * } * */ -public class ContainerAppender, - T extends BitmapDataProvider & AppendableStorage> - implements RoaringBitmapWriter { - +public class ContainerAppender< + C extends WordStorage, T extends BitmapDataProvider & AppendableStorage> + implements RoaringBitmapWriter { private final boolean doPartialSort; private final boolean runCompress; @@ -46,10 +46,11 @@ public class ContainerAppender, * Initialize an ContainerAppender with a receiving bitmap * */ - ContainerAppender(boolean doPartialSort, - boolean runCompress, - Supplier newUnderlying, - Supplier newContainer) { + ContainerAppender( + boolean doPartialSort, + boolean runCompress, + Supplier newUnderlying, + Supplier newContainer) { this.doPartialSort = doPartialSort; this.runCompress = runCompress; this.newUnderlying = newUnderlying; @@ -96,7 +97,7 @@ public void add(int value) { public void add(long min, long max) { appendToUnderlying(); underlying.add(min, max); - int mark = (int)((max >>> 16) + 1); + int mark = (int) ((max >>> 16) + 1); if (currentKey < mark) { currentKey = mark; } @@ -130,11 +131,10 @@ public void reset() { private int appendToUnderlying() { if (!container.isEmpty()) { assert currentKey <= 0xFFFF; - underlying.append((char) currentKey, - runCompress ? container.runOptimize() : container); + underlying.append((char) currentKey, runCompress ? container.runOptimize() : container); container = newContainer.get(); return 1; } return 0; } -} \ No newline at end of file +} diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ContainerBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/ContainerBatchIterator.java similarity index 64% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ContainerBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ContainerBatchIterator.java index aa185f5f6..b28a34491 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ContainerBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ContainerBatchIterator.java @@ -7,9 +7,21 @@ public interface ContainerBatchIterator extends Cloneable { * and returns how much of the buffer was used. * @param key the prefix of the values * @param buffer the buffer to write values onto + * @param offset the offset into the buffer to write values onto * @return how many values were written. */ - int next(int key, int[] buffer); + int next(int key, int[] buffer, int offset); + + /** + * Fills the buffer with values prefixed by the key, + * and returns how much of the buffer was used. + * @param key the prefix of the values + * @param buffer the buffer to write values onto + * @return how many values were written. + */ + default int next(int key, int[] buffer) { + return next(key, buffer, 0); + } /** * Whether the underlying container is exhausted or not @@ -34,5 +46,4 @@ public interface ContainerBatchIterator extends Cloneable { * @param target the value to advance to. */ void advanceIfNeeded(char target); - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ContainerPointer.java b/roaringbitmap/src/main/java/org/roaringbitmap/ContainerPointer.java similarity index 92% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ContainerPointer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ContainerPointer.java index ebbdd44d5..174c4c165 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ContainerPointer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ContainerPointer.java @@ -5,27 +5,26 @@ package org.roaringbitmap; /** - * + * * This interface allows you to iterate over the containers in a roaring bitmap. * */ -public interface ContainerPointer extends Comparable, Cloneable { +public interface ContainerPointer extends Comparable, Cloneable { /** * Move to the next container */ void advance(); - /** * Create a copy - * + * * @return return a clone of this pointer */ - ContainerPointer clone(); + ContainerPointer clone(); /** * Return the cardinality of the current container - * + * * @return the cardinality */ int getCardinality(); @@ -33,21 +32,21 @@ public interface ContainerPointer extends Comparable, Cloneabl /** * This method can be used to check whether there is current a valid container as it returns null * when there is not. - * + * * @return null or the current container */ Container getContainer(); /** * Check whether the current container is a bitmap container. - * + * * @return whether it is a bitmap container */ boolean isBitmapContainer(); /** * Check whether the current container is a run container. - * + * * @return whether it is a run container */ boolean isRunContainer(); @@ -55,7 +54,7 @@ public interface ContainerPointer extends Comparable, Cloneabl /** * The key is a 16-bit integer that indicates the position of the container in the roaring bitmap. * To be interpreted as an unsigned integer. - * + * * @return the key */ char key(); diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/FastAggregation.java b/roaringbitmap/src/main/java/org/roaringbitmap/FastAggregation.java similarity index 85% rename from RoaringBitmap/src/main/java/org/roaringbitmap/FastAggregation.java rename to roaringbitmap/src/main/java/org/roaringbitmap/FastAggregation.java index f1806d4e0..2d8e5d38c 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/FastAggregation.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/FastAggregation.java @@ -4,8 +4,13 @@ package org.roaringbitmap; -import java.util.*; - +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.PriorityQueue; /** * Fast algorithms to aggregate many bitmaps. @@ -14,7 +19,6 @@ */ public final class FastAggregation { - /** * Compute the AND aggregate. * @@ -50,7 +54,7 @@ public static RoaringBitmap and(RoaringBitmap... bitmaps) { */ public static RoaringBitmap and(long[] aggregationBuffer, RoaringBitmap... bitmaps) { if (bitmaps.length > 10) { - if(aggregationBuffer.length < 1024) { + if (aggregationBuffer.length < 1024) { throw new IllegalArgumentException("buffer should have at least 1024 elements."); } try { @@ -111,7 +115,6 @@ public static RoaringBitmap horizontal_or(Iterator bitm return naive_or(bitmaps); } - /** * Minimizes memory usage while computing the or aggregate on a moderate number of bitmaps. * @@ -230,7 +233,6 @@ public static RoaringBitmap horizontal_or(RoaringBitmap... bitmaps) { return answer; } - /** * Minimizes memory usage while computing the xor aggregate on a moderate number of bitmaps. * @@ -288,7 +290,6 @@ public static RoaringBitmap horizontal_xor(RoaringBitmap... bitmaps) { return answer; } - /** * Compute overall AND between bitmaps two-by-two. * @@ -312,7 +313,6 @@ public static RoaringBitmap naive_and(Iterator bitmaps) return answer; } - /** * Compute overall AND between bitmaps two-by-two. * @@ -355,29 +355,11 @@ public static RoaringBitmap naive_and(RoaringBitmap... bitmaps) { */ public static RoaringBitmap workShyAnd(long[] buffer, RoaringBitmap... bitmaps) { long[] words = buffer; - RoaringBitmap first = bitmaps[0]; - for (int i = 0; i < first.highLowContainer.size; ++i) { - char key = first.highLowContainer.keys[i]; - words[key >>> 6] |= 1L << key; - } - int numContainers = first.highLowContainer.size; - for (int i = 1; i < bitmaps.length && numContainers > 0; ++i) { - numContainers = Util.intersectArrayIntoBitmap(words, - bitmaps[i].highLowContainer.keys, bitmaps[i].highLowContainer.size); - } - if (numContainers == 0) { + char[] keys = Util.intersectKeys(words, bitmaps); + if (keys.length == 0) { return new RoaringBitmap(); } - char[] keys = new char[numContainers]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } + int numContainers = keys.length; Container[][] containers = new Container[numContainers][bitmaps.length]; for (int i = 0; i < bitmaps.length; ++i) { RoaringBitmap bitmap = bitmaps[i]; @@ -390,13 +372,15 @@ public static RoaringBitmap workShyAnd(long[] buffer, RoaringBitmap... bitmaps) } } - RoaringArray array = - new RoaringArray(keys, new Container[numContainers], 0); + RoaringArray array = new RoaringArray(keys, new Container[numContainers], 0); for (int i = 0; i < numContainers; ++i) { Container[] slice = containers[i]; Arrays.fill(words, -1L); Container tmp = new BitmapContainer(words, -1); for (Container container : slice) { + // We only assign to 'tmp' when 'tmp != tmp.iand(container)' + // as a garbage-collection optimization: we want to avoid + // the write barrier. (Richard Startin) Container and = tmp.iand(container); if (and != tmp) { tmp = and; @@ -412,29 +396,11 @@ public static RoaringBitmap workShyAnd(long[] buffer, RoaringBitmap... bitmaps) private static int workShyAndCardinality(RoaringBitmap... bitmaps) { long[] words = new long[1024]; - RoaringBitmap first = bitmaps[0]; - for (int i = 0; i < first.highLowContainer.size; ++i) { - char key = first.highLowContainer.keys[i]; - words[key >>> 6] |= 1L << key; - } - int numKeys = first.highLowContainer.size; - for (int i = 1; i < bitmaps.length && numKeys > 0; ++i) { - numKeys = Util.intersectArrayIntoBitmap(words, - bitmaps[i].highLowContainer.keys, bitmaps[i].highLowContainer.size); - } - if (numKeys == 0) { + char[] keys = Util.intersectKeys(words, bitmaps); + if (keys.length == 0) { return 0; } - char[] keys = new char[numKeys]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } + int numKeys = keys.length; int cardinality = 0; for (int i = 0; i < numKeys; i++) { Arrays.fill(words, -1L); @@ -445,6 +411,9 @@ private static int workShyAndCardinality(RoaringBitmap... bitmaps) { continue; } Container container = bitmap.highLowContainer.getContainerAtIndex(index); + // We only assign to 'tmp' when 'tmp != tmp.iand(container)' + // as a garbage-collection optimization: we want to avoid + // the write barrier. (Richard Startin) Container and = tmp.iand(container); if (and != tmp) { tmp = and; @@ -468,16 +437,7 @@ private static int horizontalOrCardinality(RoaringBitmap... bitmaps) { } } int numKeys = Util.cardinalityInBitmapRange(words, minKey, maxKey + 1); - char[] keys = new char[numKeys]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } + char[] keys = BitSetUtil.arrayContainerBufferOf(0, words.length, numKeys, words); int cardinality = 0; for (char key : keys) { @@ -499,8 +459,6 @@ private static int horizontalOrCardinality(RoaringBitmap... bitmaps) { return cardinality; } - - /** * Computes the intersection by first intersecting the keys, avoids * materialising containers, limits memory usage. You must provide a long[] array @@ -514,45 +472,30 @@ private static int horizontalOrCardinality(RoaringBitmap... bitmaps) { * @return the intersection of the bitmaps */ public static RoaringBitmap workAndMemoryShyAnd(long[] buffer, RoaringBitmap... bitmaps) { - if(buffer.length < 1024) { + if (buffer.length < 1024) { throw new IllegalArgumentException("buffer should have at least 1024 elements."); - } - long[] words = buffer; - RoaringBitmap first = bitmaps[0]; - for (int i = 0; i < first.highLowContainer.size; ++i) { - char key = first.highLowContainer.keys[i]; - words[key >>> 6] |= 1L << key; - } - int numContainers = first.highLowContainer.size; - for (int i = 1; i < bitmaps.length && numContainers > 0; ++i) { - numContainers = Util.intersectArrayIntoBitmap(words, - bitmaps[i].highLowContainer.keys, bitmaps[i].highLowContainer.size); } - if (numContainers == 0) { + long[] words = buffer; + char[] keys = Util.intersectKeys(words, bitmaps); + if (keys.length == 0) { return new RoaringBitmap(); } - char[] keys = new char[numContainers]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } - RoaringArray array = - new RoaringArray(keys, new Container[numContainers], 0); + int numContainers = keys.length; + + RoaringArray array = new RoaringArray(keys, new Container[numContainers], 0); for (int i = 0; i < numContainers; ++i) { char MatchingKey = keys[i]; Arrays.fill(words, -1L); Container tmp = new BitmapContainer(words, -1); - for(RoaringBitmap bitmap: bitmaps) { + for (RoaringBitmap bitmap : bitmaps) { int idx = bitmap.highLowContainer.getIndex(MatchingKey); - if(idx < 0) { + if (idx < 0) { continue; } Container container = bitmap.highLowContainer.getContainerAtIndex(idx); + // We only assign to 'tmp' when 'tmp != tmp.iand(container)' + // as a garbage-collection optimization: we want to avoid + // the write barrier. (Richard Startin) Container and = tmp.iand(container); if (and != tmp) { tmp = and; @@ -600,7 +543,6 @@ public static RoaringBitmap naive_or(RoaringBitmap... bitmaps) { return answer; } - /** * Compute overall XOR between bitmaps two-by-two. * @@ -617,7 +559,6 @@ public static RoaringBitmap naive_xor(Iterator bitmaps) return answer; } - /** * Compute overall XOR between bitmaps two-by-two. * @@ -679,12 +620,15 @@ public static RoaringBitmap priorityqueue_or(Iterator b for (int k = 0; k < sizes.length; ++k) { sizes[k] = buffer.get(k).getLongSizeInBytes(); } - PriorityQueue pq = new PriorityQueue<>(128, new Comparator() { - @Override - public int compare(Integer a, Integer b) { - return (int) (sizes[a] - sizes[b]); - } - }); + PriorityQueue pq = + new PriorityQueue<>( + 128, + new Comparator() { + @Override + public int compare(Integer a, Integer b) { + return (int) (sizes[a] - sizes[b]); + } + }); for (int k = 0; k < sizes.length; ++k) { pq.add(k); } @@ -736,12 +680,15 @@ public static RoaringBitmap priorityqueue_or(RoaringBitmap... bitmaps) { for (int k = 0; k < sizes.length; ++k) { sizes[k] = buffer[k].getLongSizeInBytes(); } - PriorityQueue pq = new PriorityQueue<>(128, new Comparator() { - @Override - public int compare(Integer a, Integer b) { - return (int) (sizes[a] - sizes[b]); - } - }); + PriorityQueue pq = + new PriorityQueue<>( + 128, + new Comparator() { + @Override + public int compare(Integer a, Integer b) { + return (int) (sizes[a] - sizes[b]); + } + }); for (int k = 0; k < sizes.length; ++k) { pq.add(k); } @@ -789,12 +736,14 @@ public static RoaringBitmap priorityqueue_xor(RoaringBitmap... bitmaps) { } PriorityQueue pq = - new PriorityQueue<>(bitmaps.length, new Comparator() { - @Override - public int compare(RoaringBitmap a, RoaringBitmap b) { - return (int)(a.getLongSizeInBytes() - b.getLongSizeInBytes()); - } - }); + new PriorityQueue<>( + bitmaps.length, + new Comparator() { + @Override + public int compare(RoaringBitmap a, RoaringBitmap b) { + return (int) (a.getLongSizeInBytes() - b.getLongSizeInBytes()); + } + }); Collections.addAll(pq, bitmaps); while (pq.size() > 1) { RoaringBitmap x1 = pq.poll(); @@ -829,8 +778,5 @@ public static RoaringBitmap xor(RoaringBitmap... bitmaps) { /** * Private constructor to prevent instantiation of utility class */ - private FastAggregation() { - - } - + private FastAggregation() {} } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/FastRankRoaringBitmap.java b/roaringbitmap/src/main/java/org/roaringbitmap/FastRankRoaringBitmap.java similarity index 91% rename from RoaringBitmap/src/main/java/org/roaringbitmap/FastRankRoaringBitmap.java rename to roaringbitmap/src/main/java/org/roaringbitmap/FastRankRoaringBitmap.java index b7bc154d7..e7052ba01 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/FastRankRoaringBitmap.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/FastRankRoaringBitmap.java @@ -5,16 +5,16 @@ /** * This extends {@link RoaringBitmap} to provide better performance for .rank and .select * operations, at the cost of maintain a cache of cardinalities. - * + * * On {@link RoaringBitmap#select(int)} and {@link RoaringBitmap#rank(int)} operations, * {@link RoaringBitmap} needs to iterate along all underlying buckets to cumulate their * cardinalities. This may lead to sub-optimal performance for application doing a large amount of * .rank/.select over read-only {@link RoaringBitmap}, especially if the {@link RoaringBitmap} holds * a large number of underlying buckets. - * + * * This implementation will discard the cache of cardinality on any write operations, and it will * memoize the computed cardinalities on any .rank or .select operation - * + * * @author Benoit Lacelle * */ @@ -168,8 +168,9 @@ private void preComputeCardinalities() { highToCumulatedCardinality[0] = highLowContainer.getContainerAtIndex(0).getCardinality(); for (int i = 1; i < highToCumulatedCardinality.length; i++) { - highToCumulatedCardinality[i] = highToCumulatedCardinality[i - 1] - + highLowContainer.getContainerAtIndex(i).getCardinality(); + highToCumulatedCardinality[i] = + highToCumulatedCardinality[i - 1] + + highLowContainer.getContainerAtIndex(i).getCardinality(); } } @@ -187,8 +188,9 @@ public long rankLong(int x) { char xhigh = Util.highbits(x); - int index = Util.hybridUnsignedBinarySearch(this.highLowContainer.keys, 0, - this.highLowContainer.size(), xhigh); + int index = + Util.hybridUnsignedBinarySearch( + this.highLowContainer.keys, 0, this.highLowContainer.size(), xhigh); boolean hasBitmapOnIdex; if (index < 0) { @@ -228,7 +230,7 @@ public int select(int j) { return this.last(); } else if (j > maxCardinality) { throw new IllegalArgumentException( - "select " + j + " when the cardinality is " + this.getCardinality()); + "select " + j + " when the cardinality is " + this.getCardinality()); } int index = Arrays.binarySearch(highToCumulatedCardinality, j); @@ -257,14 +259,12 @@ public int select(int j) { } int keycontrib = this.highLowContainer.getKeyAtIndex(fixedIndex) << 16; - int lowcontrib = ( - this.highLowContainer.getContainerAtIndex(fixedIndex).select((int) leftover)); + int lowcontrib = (this.highLowContainer.getContainerAtIndex(fixedIndex).select((int) leftover)); int value = lowcontrib + keycontrib; - return value; } - + @Override public long getLongSizeInBytes() { long size = 8; @@ -309,14 +309,13 @@ public int peekNextRank() { @Override public PeekableIntRankIterator clone() { try { - FastRoaringIntRankIterator x = - (FastRoaringIntRankIterator) super.clone(); + FastRoaringIntRankIterator x = (FastRoaringIntRankIterator) super.clone(); if (this.iter != null) { x.iter = this.iter.clone(); } return x; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -337,8 +336,11 @@ public int next() { private void nextContainer() { if (pos < FastRankRoaringBitmap.this.highLowContainer.size()) { - iter = FastRankRoaringBitmap.this.highLowContainer.getContainerAtIndex(pos) - .getCharRankIterator(); + iter = + FastRankRoaringBitmap.this + .highLowContainer + .getContainerAtIndex(pos) + .getCharRankIterator(); hs = FastRankRoaringBitmap.this.highLowContainer.getKeyAtIndex(pos) << 16; } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ImmutableBitmapDataProvider.java b/roaringbitmap/src/main/java/org/roaringbitmap/ImmutableBitmapDataProvider.java similarity index 77% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ImmutableBitmapDataProvider.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ImmutableBitmapDataProvider.java index 2a7502138..369261834 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ImmutableBitmapDataProvider.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ImmutableBitmapDataProvider.java @@ -35,7 +35,7 @@ public interface ImmutableBitmapDataProvider { * @return the cardinality */ int getCardinality(); - + /** * Returns the number of distinct integers added to the bitmap (e.g., number of bits set). * This returns a full 64-bit result. @@ -46,8 +46,8 @@ public interface ImmutableBitmapDataProvider { /** * Visit all values in the bitmap and pass them to the consumer. - * - * * Usage: + * + * * Usage: *

    * {@code
    *  bitmap.forEach(new IntConsumer() {
@@ -55,7 +55,7 @@ public interface ImmutableBitmapDataProvider {
    *    {@literal @}Override
    *    public void accept(int value) {
    *      // do something here
-   *      
+   *
    *    }});
    *   }
    * }
@@ -65,13 +65,21 @@ public interface ImmutableBitmapDataProvider {
   void forEach(IntConsumer ic);
 
   /**
-   * For better performance, consider the Use the {@link #forEach forEach} method.
-   * @return a custom iterator over set bits, the bits are traversed in ascending sorted order
+   * For better performance, consider using the {@link #forEach forEach} method.
+   * @return a custom iterator over set bits, the bits are traversed in unsigned integer ascending
+   *     sorted order
    */
   PeekableIntIterator getIntIterator();
 
   /**
-   * @return a custom iterator over set bits, the bits are traversed in descending sorted order
+   * @return a custom iterator over set bits, the bits are traversed in signed integer ascending
+   *     sorted order
+   */
+  PeekableIntIterator getSignedIntIterator();
+
+  /**
+   * @return a custom iterator over set bits, the bits are traversed in unsigned integer descending
+   *     sorted order
    */
   IntIterator getReverseIntIterator();
 
@@ -79,10 +87,11 @@ public interface ImmutableBitmapDataProvider {
    * @return an Ordered, Distinct, Sorted and Sized IntStream in ascending order
    */
   public default IntStream stream() {
-    int characteristics = Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED 
-        | Spliterator.SIZED;
-    Spliterator.OfInt x = Spliterators.spliterator(new RoaringOfInt(getIntIterator()), 
-        getCardinality(), characteristics);
+    int characteristics =
+        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.SIZED;
+    Spliterator.OfInt x =
+        Spliterators.spliterator(
+            new RoaringOfInt(getIntIterator()), getCardinality(), characteristics);
     return StreamSupport.intStream(x, false);
   }
 
@@ -91,11 +100,12 @@ public default IntStream stream() {
    */
   public default IntStream reverseStream() {
     int characteristics = Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SIZED;
-    Spliterator.OfInt x = Spliterators.spliterator(new RoaringOfInt(getReverseIntIterator()), 
-        getCardinality(), characteristics);
+    Spliterator.OfInt x =
+        Spliterators.spliterator(
+            new RoaringOfInt(getReverseIntIterator()), getCardinality(), characteristics);
     return StreamSupport.intStream(x, false);
   }
-  
+
   /**
    * This iterator may be faster than others
    * @return iterator which works on batches of data.
@@ -104,13 +114,13 @@ public default IntStream reverseStream() {
 
   /**
    * Estimate of the memory usage of this data structure.
-   * 
+   *
    * Internally, this is computed as a 64-bit counter.
    *
    * @return estimated memory usage.
    */
   int getSizeInBytes();
-  
+
   /**
    * Estimate of the memory usage of this data structure. Provides
    * full 64-bit number.
@@ -138,44 +148,44 @@ public default IntStream reverseStream() {
    * Rank returns the number of integers that are smaller or equal to x (rank(infinity) would be
    * getCardinality()).  If you provide the smallest value as a parameter, this function will
    * return 1. If provide a value smaller than the smallest value, it will return 0.
-   * 
+   *
    * The value is internally computed as a 64-bit number.
-   * 
+   *
    * @param x upper limit
    *
    * @return the rank
-   * @see Ranking in statistics 
+   * @see Ranking in statistics
    */
   int rank(int x);
-  
+
   /**
    * Rank returns the number of integers that are smaller or equal to x (rankLong(infinity) would be
    * getLongCardinality()).  If you provide the smallest value as a parameter, this function will
    * return 1. If provide a value smaller than the smallest value, it will return 0.
    * Same as "rank" but produces a full 64-bit value.
-   * 
+   *
    * @param x upper limit
    *
    * @return the rank
-   * @see Ranking in statistics 
+   * @see Ranking in statistics
    */
   long rankLong(int x);
 
   /**
-  * Computes the number of values in the interval [start,end) where
-  * start is included and end excluded.
-  * rangeCardinality(0,0x100000000) provides the total cardinality (getLongCardinality).
-  * The answer is a 64-bit value between 1 and 0x100000000. 
-  * 
-  * @param start lower limit (included)
-  * @param end upper limit (excluded)
-  * @return the number of elements in [start,end), between 0 and 0x100000000.
-  */
+   * Computes the number of values in the interval [start,end) where
+   * start is included and end excluded.
+   * rangeCardinality(0,0x100000000) provides the total cardinality (getLongCardinality).
+   * The answer is a 64-bit value between 1 and 0x100000000.
+   *
+   * @param start lower limit (included)
+   * @param end upper limit (excluded)
+   * @return the number of elements in [start,end), between 0 and 0x100000000.
+   */
   long rangeCardinality(long start, long end);
 
   /**
-   * Return the jth value stored in this bitmap. The provided value 
-   * needs to be smaller than the cardinality otherwise an 
+   * Return the jth value stored in this bitmap. The provided value
+   * needs to be smaller than the cardinality otherwise an
    * IllegalArgumentException
    * exception is thrown. The smallest value is at index 0.
    * Note that this function differs in convention from the rank function which
@@ -184,26 +194,38 @@ public default IntStream reverseStream() {
    * @param j index of the value
    *
    * @return the value
-   * @see Selection algorithm 
+   * @see Selection algorithm
    */
   int select(int j);
 
   /**
-   * Get the first (smallest) integer in this RoaringBitmap,
-   * that is, return the minimum of the set.
-   * @return the first (smallest) integer
+   * Get the smallest unsigned (first) integer in this RoaringBitmap.
+   * @return the smallest unsigned (first) integer
    * @throws NoSuchElementException if empty
    */
   int first();
 
   /**
-   * Get the last (largest) integer in this RoaringBitmap,
-   * that is, return the maximum of the set.
-   * @return the last (largest) integer
+   * Get the largest unsigned (last) integer in this RoaringBitmap.
+   * @return the largest unsigned (last) integer
    * @throws NoSuchElementException if empty
    */
   int last();
 
+  /**
+   * Get the smallest signed integer in this RoaringBitmap.
+   * @return the smallest signed integer
+   * @throws NoSuchElementException if empty
+   */
+  int firstSigned();
+
+  /**
+   * Get the largest signed integer in this RoaringBitmap.
+   * @return the largest signed integer
+   * @throws NoSuchElementException if empty
+   */
+  int lastSigned();
+
   /**
    * Returns the first value equal to or larger than the provided value
    * (interpreted as an unsigned integer). If no such
@@ -215,7 +237,7 @@ public default IntStream reverseStream() {
    *       or {@code -1} if there is no such value
    */
   long nextValue(int fromValue);
-  
+
   /**
    * Returns the first value less than or equal to the provided value
    * (interpreted as an unsigned integer). If no such
@@ -235,7 +257,7 @@ public default IntStream reverseStream() {
    *
    * @param  fromValue the lower bound (inclusive)
    * @return the smallest absent value larger than or equal to the specified
-   *       value.
+   *       value or {@code -1} if there is no such value.
    */
   long nextAbsentValue(int fromValue);
 
@@ -246,7 +268,7 @@ public default IntStream reverseStream() {
    *
    * @param  fromValue the lower bound (inclusive)
    * @return the smallest absent value larger than or equal to the specified
-   *       value.
+   *       value or {@code -1} if there is no such value.
    */
   long previousAbsentValue(int fromValue);
 
@@ -263,11 +285,11 @@ public default IntStream reverseStream() {
   /**
    * Serialize this bitmap to a ByteBuffer.
    * This is the preferred method
-   * to serialize to a byte array (byte[]) or to a String 
+   * to serialize to a byte array (byte[]) or to a String
    * (via Base64.getEncoder().encodeToString)..
    *
-   *  
-   * Irrespective of the endianess of the provided buffer, data is 
+   *
+   * Irrespective of the endianess of the provided buffer, data is
    * written using LITTlE_ENDIAN as per the RoaringBitmap specification.
    *
    * The current bitmap is not modified.
@@ -298,11 +320,18 @@ public default IntStream reverseStream() {
    */
   int[] toArray();
 
+  /**
+   * Returns the number of containers in the bitmap.
+   *
+   * @return the number of containers
+   */
+  int getContainerCount();
+
   /**
    * An internal class to help provide streams.
    * Sad but true the interface of IntIterator and PrimitiveIterator.OfInt
-   * Does not match. Otherwise it would be easier to just make IntIterator 
-   * implement PrimitiveIterator.OfInt. 
+   * Does not match. Otherwise it would be easier to just make IntIterator
+   * implement PrimitiveIterator.OfInt.
    */
   static final class RoaringOfInt implements PrimitiveIterator.OfInt {
     private final IntIterator iterator;
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/IntConsumer.java b/roaringbitmap/src/main/java/org/roaringbitmap/IntConsumer.java
similarity index 95%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/IntConsumer.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/IntConsumer.java
index a1294165b..741fe227a 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/IntConsumer.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/IntConsumer.java
@@ -3,16 +3,16 @@
 /**
  * An IntConsumer receives the int values contained in a data structure.
  * Each value is visited once.
- * 
+ *
  * Usage:
- * 
+ *
  * 
  * {@code
  *  bitmap.forEach(new IntConsumer() {
  *
  *    public void accept(int value) {
  *      // do something here
- *      
+ *
  *    }});
  *   }
  * }
@@ -21,7 +21,7 @@
 public interface IntConsumer {
   /**
    * Receives the integer
-   * 
+   *
    * @param value the integer value
    */
   void accept(int value);
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/IntConsumerRelativeRangeAdapter.java b/roaringbitmap/src/main/java/org/roaringbitmap/IntConsumerRelativeRangeAdapter.java
similarity index 100%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/IntConsumerRelativeRangeAdapter.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/IntConsumerRelativeRangeAdapter.java
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/IntIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/IntIterator.java
similarity index 98%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/IntIterator.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/IntIterator.java
index d2f51c09e..efe49236a 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/IntIterator.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/IntIterator.java
@@ -13,7 +13,7 @@
 public interface IntIterator extends Cloneable {
   /**
    * Creates a copy of the iterator.
-   * 
+   *
    * @return a clone of the current iterator
    */
   IntIterator clone();
@@ -27,5 +27,4 @@ public interface IntIterator extends Cloneable {
    * @return next integer value
    */
   int next();
-
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/IntIteratorFlyweight.java b/roaringbitmap/src/main/java/org/roaringbitmap/IntIteratorFlyweight.java
similarity index 95%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/IntIteratorFlyweight.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/IntIteratorFlyweight.java
index 660d2ab77..8b06f704c 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/IntIteratorFlyweight.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/IntIteratorFlyweight.java
@@ -7,9 +7,9 @@
 /**
  * Fast iterator minimizing the stress on the garbage collector. You can create one reusable
  * instance of this class and then {@link #wrap(RoaringBitmap)}
- * 
+ *
  * For better performance, consider the {@link RoaringBitmap#forEach} method.
- * 
+ *
  * @author Borislav Ivanov
  **/
 public class IntIteratorFlyweight implements PeekableIntIterator {
@@ -32,13 +32,11 @@ public class IntIteratorFlyweight implements PeekableIntIterator {
    * Creates an instance that is not ready for iteration. You must first call
    * {@link #wrap(RoaringBitmap)}.
    */
-  public IntIteratorFlyweight() {
-
-  }
+  public IntIteratorFlyweight() {}
 
   /**
    * Creates an instance that is ready for iteration.
-   * 
+   *
    * @param r bitmap to be iterated over
    */
   public IntIteratorFlyweight(RoaringBitmap r) {
@@ -49,12 +47,12 @@ public IntIteratorFlyweight(RoaringBitmap r) {
   public PeekableIntIterator clone() {
     try {
       IntIteratorFlyweight x = (IntIteratorFlyweight) super.clone();
-      if(this.iter != null) {
+      if (this.iter != null) {
         x.iter = this.iter.clone();
       }
       return x;
     } catch (CloneNotSupportedException e) {
-      return null;// will not happen
+      return null; // will not happen
     }
   }
 
@@ -94,7 +92,7 @@ private void nextContainer() {
 
   /**
    * Prepares a bitmap for iteration
-   * 
+   *
    * @param r bitmap to be iterated over
    */
   public void wrap(RoaringBitmap r) {
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/InvalidRoaringFormat.java b/roaringbitmap/src/main/java/org/roaringbitmap/InvalidRoaringFormat.java
similarity index 85%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/InvalidRoaringFormat.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/InvalidRoaringFormat.java
index 5b7f670e1..0938773c3 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/InvalidRoaringFormat.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/InvalidRoaringFormat.java
@@ -5,7 +5,7 @@
 /**
  *
  * Exception thrown when attempting to deserialize a roaring bitmap from
- * an input stream missing a cookie or having other similar anomalies. 
+ * an input stream missing a cookie or having other similar anomalies.
  * Some code may translate it to an IOException
  * for convenience when the cause of the problem can be cleanly interpreted as
  * an IO issue. However, when memory-mapping the file from a ByteBuffer,
@@ -29,13 +29,10 @@ public InvalidRoaringFormat(String string) {
   private static final long serialVersionUID = 1L;
 
   /**
-  * Convert the exception to an IOException (convenience function)
-  * @return an IOException with a related error message.
-  */
+   * Convert the exception to an IOException (convenience function)
+   * @return an IOException with a related error message.
+   */
   public IOException toIOException() {
     return new IOException(toString());
   }
-
-
-
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ParallelAggregation.java b/roaringbitmap/src/main/java/org/roaringbitmap/ParallelAggregation.java
similarity index 86%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/ParallelAggregation.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/ParallelAggregation.java
index 3452a5c49..b732c881c 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/ParallelAggregation.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/ParallelAggregation.java
@@ -1,6 +1,13 @@
 package org.roaringbitmap;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.ForkJoinTask;
 import java.util.function.BiConsumer;
@@ -38,9 +45,8 @@
  */
 public class ParallelAggregation {
 
-  private static final Collector>,
-          RoaringArray, RoaringBitmap>
-          XOR = new ContainerCollector(ParallelAggregation::xor);
+  private static final Collector>, RoaringArray, RoaringBitmap>
+      XOR = new ContainerCollector(ParallelAggregation::xor);
 
   private static final OrCollector OR = new OrCollector();
 
@@ -48,8 +54,8 @@ public class ParallelAggregation {
    * Collects containers grouped by their key into a RoaringBitmap, applying the
    * supplied aggregation function to each group.
    */
-  public static class ContainerCollector implements
-          Collector>, RoaringArray, RoaringBitmap> {
+  public static class ContainerCollector
+      implements Collector>, RoaringArray, RoaringBitmap> {
 
     private final Function, Container> reducer;
 
@@ -100,8 +106,7 @@ public Set characteristics() {
   /**
    * Collects a list of containers into a single container.
    */
-  public static class OrCollector
-          implements Collector, Container, Container> {
+  public static class OrCollector implements Collector, Container, Container> {
 
     @Override
     public Supplier supplier() {
@@ -152,7 +157,6 @@ public static SortedMap> groupByKey(RoaringBitmap...
     return new TreeMap<>(grouped);
   }
 
-
   /**
    * Computes the bitwise union of the input bitmaps
    * @param bitmaps the input bitmaps
@@ -169,8 +173,8 @@ public static RoaringBitmap or(RoaringBitmap... bitmaps) {
       slices.add(slice.getValue());
     }
     IntStream.range(0, i)
-             .parallel()
-             .forEach(position -> values[position] = or(slices.get(position)));
+        .parallel()
+        .forEach(position -> values[position] = or(slices.get(position)));
     return new RoaringBitmap(new RoaringArray(keys, values, i));
   }
 
@@ -180,10 +184,7 @@ public static RoaringBitmap or(RoaringBitmap... bitmaps) {
    * @return the symmetric difference of the bitmaps
    */
   public static RoaringBitmap xor(RoaringBitmap... bitmaps) {
-    return groupByKey(bitmaps)
-            .entrySet()
-            .parallelStream()
-            .collect(XOR);
+    return groupByKey(bitmaps).entrySet().parallelStream().collect(XOR);
   }
 
   private static Container xor(List containers) {
@@ -216,16 +217,17 @@ private static Container or(List containers) {
     int mod = Math.floorMod(containers.size(), parallelism);
     // we have an enormous slice (probably skewed), parallelise it
     return IntStream.range(0, parallelism)
-            .parallel()
-            .mapToObj(i -> containers.subList(i * step + Math.min(i, mod),
-                    (i + 1) * step + Math.min(i + 1, mod)))
-            .collect(OR);
+        .parallel()
+        .mapToObj(
+            i ->
+                containers.subList(
+                    i * step + Math.min(i, mod), (i + 1) * step + Math.min(i + 1, mod)))
+        .collect(OR);
   }
 
   private static int availableParallelism() {
     return ForkJoinTask.inForkJoinPool()
-            ? ForkJoinTask.getPool().getParallelism()
-            : ForkJoinPool.getCommonPoolParallelism();
+        ? ForkJoinTask.getPool().getParallelism()
+        : ForkJoinPool.getCommonPoolParallelism();
   }
-
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/PeekableCharIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/PeekableCharIterator.java
similarity index 94%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/PeekableCharIterator.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/PeekableCharIterator.java
index dc8083598..5feb101f7 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/PeekableCharIterator.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/PeekableCharIterator.java
@@ -3,40 +3,37 @@
  */
 package org.roaringbitmap;
 
-
-
 /**
  * Simple extension to the CharIterator interface
  *
  */
 public interface PeekableCharIterator extends CharIterator {
   /**
-   * If needed, 
+   * If needed,
    * when iterating forward through the chars it will
    * advance as long as the next value is smaller than val (as an unsigned
    * short)
    * when iterating in reverse through the chars it will
    * advance as long as the next value is larger than val (as an unsigned
    * short)
-   * 
+   *
    * @param thresholdVal threshold
    */
   public void advanceIfNeeded(char thresholdVal);
 
   /**
-   * 
+   *
    * Look at the next value without advancing
-   * 
+   *
    * @return next value
    */
   public char peekNext();
-  
+
   /**
    * Creates a copy of the iterator.
-   * 
+   *
    * @return a clone of the current iterator
    */
   @Override
   PeekableCharIterator clone();
 }
-
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/PeekableCharRankIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/PeekableCharRankIterator.java
similarity index 100%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/PeekableCharRankIterator.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/PeekableCharRankIterator.java
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/PeekableIntIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/PeekableIntIterator.java
similarity index 93%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/PeekableIntIterator.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/PeekableIntIterator.java
index b1ea93050..f6e0e1e80 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/PeekableIntIterator.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/PeekableIntIterator.java
@@ -1,8 +1,7 @@
 package org.roaringbitmap;
 
-
 /**
- * Simple extension to the IntIterator interface. 
+ * Simple extension to the IntIterator interface.
  * It allows you to "skip" values using the advanceIfNeeded
  * method, and to look at the value without advancing (peekNext).
  *
@@ -15,9 +14,9 @@ public interface PeekableIntIterator extends IntIterator {
    *
    *  The advanceIfNeeded method is used for performance reasons, to skip
    *  over unnecessary repeated calls to next.
-   *  
+   *
    *  Suppose for example that you wish to compute the intersection between
-   *  an ordered list of integers (e.g., int[] x = {1,4,5}) and a 
+   *  an ordered list of integers (e.g., int[] x = {1,4,5}) and a
    *  PeekableIntIterator.
    *  You might do it as follows...
    *     

@@ -33,24 +32,24 @@ public interface PeekableIntIterator extends IntIterator {
    *       j.advanceIfNeeded(val);
    *     }
    *     
- * - * The benefit of calling advanceIfNeeded is that each such call + * + * The benefit of calling advanceIfNeeded is that each such call * can be much faster than repeated calls to "next". The underlying * implementation can "skip" over some data. - * - * + * + * * @param minval threshold */ public void advanceIfNeeded(int minval); /** - * + * * Look at the next value without advancing - * + * * The peek is useful when working with several iterators at once. * Suppose that you have 100 iterators, and you want to compute * their intersections without materializing the result. - * You might do it as follows... + * You might do it as follows... *

    *    PriorityQueue pq = new PriorityQueue(100,
    *      new Comparator<PeekableIntIterator>() {
@@ -59,9 +58,9 @@ public interface PeekableIntIterator extends IntIterator {
    *                 return a.peek() - b.peek();
    *             }
    *         });
-   * 
+   *
    *    //...  populate pq
-   *    
+   *
    *    while(! pq.isEmpty() ) {
    *      // get iterator with a smallest value
    *      PeekableIntIterator pi = pq.poll();
@@ -70,21 +69,19 @@ public interface PeekableIntIterator extends IntIterator {
    *      if(pi.hasNext()) pq.add(pi)
    *    }
    *    
- * + * * Notice how the peek method allows you to compare iterators in a way * that the next method could not do. - * + * * @return next value */ public int peekNext(); - + /** * Creates a copy of the iterator. - * + * * @return a clone of the current iterator */ @Override PeekableIntIterator clone(); } - - diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/PeekableIntRankIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/PeekableIntRankIterator.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/PeekableIntRankIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/PeekableIntRankIterator.java index c8b1561dd..2a56c8db0 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/PeekableIntRankIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/PeekableIntRankIterator.java @@ -14,5 +14,3 @@ public interface PeekableIntRankIterator extends PeekableIntIterator { @Override PeekableIntRankIterator clone(); } - - diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java b/roaringbitmap/src/main/java/org/roaringbitmap/RangeBitmap.java similarity index 75% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RangeBitmap.java index 9962418e6..db0d178e9 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RangeBitmap.java @@ -1,5 +1,10 @@ package org.roaringbitmap; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.roaringbitmap.Util.cardinalityInBitmapRange; +import static org.roaringbitmap.Util.resetBitmapRange; +import static org.roaringbitmap.Util.setBitmapRange; + import org.roaringbitmap.buffer.MappeableArrayContainer; import org.roaringbitmap.buffer.MappeableBitmapContainer; import org.roaringbitmap.buffer.MappeableContainer; @@ -12,11 +17,6 @@ import java.util.function.Consumer; import java.util.function.IntFunction; -import static java.nio.ByteOrder.LITTLE_ENDIAN; -import static org.roaringbitmap.Util.cardinalityInBitmapRange; -import static org.roaringbitmap.Util.resetBitmapRange; -import static org.roaringbitmap.Util.setBitmapRange; - /** * A 2D bitmap which associates values with a row index and can perform range queries. */ @@ -36,9 +36,8 @@ public final class RangeBitmap { * @param bufferSupplier provides ByteBuffers. * @return an appender. */ - public static Appender appender(long maxValue, - IntFunction bufferSupplier, - Consumer cleaner) { + public static Appender appender( + long maxValue, IntFunction bufferSupplier, Consumer cleaner) { return new Appender(maxValue, bufferSupplier, cleaner); } @@ -50,9 +49,8 @@ public static Appender appender(long maxValue, * @return an appender. */ public static Appender appender(long maxValue) { - return appender(maxValue, - capacity -> ByteBuffer.allocate(capacity).order(LITTLE_ENDIAN), b -> { - }); + return appender( + maxValue, capacity -> ByteBuffer.allocate(capacity).order(LITTLE_ENDIAN), b -> {}); } /** @@ -66,8 +64,8 @@ public static RangeBitmap map(ByteBuffer buffer) { ByteBuffer source = buffer.slice().order(LITTLE_ENDIAN); int cookie = source.getChar(); if (cookie != COOKIE) { - throw new InvalidRoaringFormat("invalid cookie for range bitmap (expected " - + COOKIE + " but got " + cookie + ")"); + throw new InvalidRoaringFormat( + "invalid cookie for range bitmap (expected " + COOKIE + " but got " + cookie + ")"); } int base = source.get() & 0xFF; if (base != 2) { @@ -75,13 +73,18 @@ public static RangeBitmap map(ByteBuffer buffer) { } int sliceCount = source.get() & 0xFF; int maxKey = source.getChar(); - long mask = sliceCount == 64 ? -1L : (1L << sliceCount) - 1; + long mask = -1L >>> (64 - sliceCount); byte bytesPerMask = (byte) ((sliceCount + 7) >>> 3); long maxRid = source.getInt() & 0xFFFFFFFFL; int masksOffset = source.position(); int containersOffset = masksOffset + maxKey * bytesPerMask; - return new RangeBitmap(mask, maxRid, (ByteBuffer) source.position(buffer.position()), - masksOffset, containersOffset, bytesPerMask); + return new RangeBitmap( + mask, + maxRid, + (ByteBuffer) source.position(buffer.position()), + masksOffset, + containersOffset, + bytesPerMask); } private final ByteBuffer buffer; @@ -91,8 +94,13 @@ public static RangeBitmap map(ByteBuffer buffer) { private final long max; private final byte bytesPerMask; - RangeBitmap(long mask, long max, ByteBuffer buffer, int masksOffset, int containersOffset, - byte bytesPerMask) { + RangeBitmap( + long mask, + long max, + ByteBuffer buffer, + int masksOffset, + int containersOffset, + byte bytesPerMask) { this.mask = mask; this.max = max; this.buffer = buffer; @@ -468,9 +476,7 @@ public RoaringBitmap computePoint(long value, boolean negate, RoaringBitmap cont for (int prefix = 0; prefix <= maxContextKey && remaining > 0; prefix++) { long containerMask = getContainerMask(buffer, mPos, mask, bytesPerMask); if (prefix < contextArray.keys[contextPos]) { - for (int i = 0; i < Long.bitCount(containerMask); i++) { - skipContainer(); - } + skipContainers(containerMask); } else { int limit = Math.min((int) remaining, 0x10000); evaluateHorizontalSlicePoint(limit, value, containerMask); @@ -479,13 +485,14 @@ public RoaringBitmap computePoint(long value, boolean negate, RoaringBitmap cont empty = false; } if (!empty) { - Container toAppend = new BitmapContainer(bits, -1) + Container toAppend = + new BitmapContainer(bits, -1) .iand(contextArray.values[contextPos]) .repairAfterLazy() .runOptimize(); if (!toAppend.isEmpty()) { - output.append((char) prefix, - toAppend instanceof BitmapContainer ? toAppend.clone() : toAppend); + output.append( + (char) prefix, toAppend instanceof BitmapContainer ? toAppend.clone() : toAppend); } } contextPos++; @@ -532,9 +539,7 @@ private long countPoint(long threshold, boolean negate, RoaringBitmap context) { int limit = Math.min(0x10000, (int) remaining); long containerMask = getContainerMask(buffer, mPos, mask, bytesPerMask); if (prefix < contextArray.keys[contextPos]) { - for (int i = 0; i < Long.bitCount(containerMask); i++) { - skipContainer(); - } + skipContainers(containerMask); } else { evaluateHorizontalSlicePoint(limit, threshold, containerMask); if (negate) { @@ -596,9 +601,7 @@ private RoaringBitmap computeRange(long threshold, boolean upper, RoaringBitmap for (int prefix = 0; prefix <= maxContextKey && remaining > 0; prefix++) { long containerMask = getContainerMask(buffer, mPos, mask, bytesPerMask); if (prefix < contextArray.keys[contextPos]) { - for (int i = 0; i < Long.bitCount(containerMask); i++) { - skipContainer(); - } + skipContainers(containerMask); } else { evaluateHorizontalSliceRange(remaining, threshold, containerMask); if (!upper) { @@ -606,13 +609,14 @@ private RoaringBitmap computeRange(long threshold, boolean upper, RoaringBitmap empty = false; } if (!empty) { - Container toAppend = new BitmapContainer(bits, -1) - .iand(contextArray.values[contextPos]) - .repairAfterLazy() - .runOptimize(); + Container toAppend = + new BitmapContainer(bits, -1) + .iand(contextArray.values[contextPos]) + .repairAfterLazy() + .runOptimize(); if (!toAppend.isEmpty()) { - output.append((char) prefix, - toAppend instanceof BitmapContainer ? toAppend.clone() : toAppend); + output.append( + (char) prefix, toAppend instanceof BitmapContainer ? toAppend.clone() : toAppend); } } contextPos++; @@ -658,15 +662,16 @@ private long countRange(long threshold, boolean upper, RoaringBitmap context) { for (int prefix = 0; prefix <= maxContextKey && remaining > 0; prefix++) { long containerMask = getContainerMask(buffer, mPos, mask, bytesPerMask); if (prefix < contextArray.keys[contextPos]) { - for (int i = 0; i < Long.bitCount(containerMask); i++) { - skipContainer(); - } + skipContainers(containerMask); } else { evaluateHorizontalSliceRange(remaining, threshold, containerMask); Container container = contextArray.values[contextPos]; - int cardinality = upper - ? container.andCardinality(new BitmapContainer(bits, -1)) - : container.andNot(new BitmapContainer(bits, -1).repairAfterLazy()).getCardinality(); + int cardinality = + upper + ? container.andCardinality(new BitmapContainer(bits, -1)) + : container + .andNot(new BitmapContainer(bits, -1).repairAfterLazy()) + .getCardinality(); count += cardinality; contextPos++; } @@ -679,7 +684,7 @@ private long countRange(long threshold, boolean upper, RoaringBitmap context) { private void evaluateHorizontalSliceRange(long remaining, long threshold, long containerMask) { // most significant absent bit in the threshold for which there is no container; // everything before this is wasted work, so we just skip over the containers - int skip = 64 - Long.numberOfLeadingZeros(((~threshold & ~containerMask) & mask)); + int skip = 64 - Long.numberOfLeadingZeros((~(threshold | containerMask) & mask)); int slice = 0; if (skip > 0) { for (; slice < skip; ++slice) { @@ -783,35 +788,40 @@ private void andNextIntoBits() { int size = buffer.getChar(position) & 0xFFFF; position += Character.BYTES; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableArrayContainer array = new MappeableArrayContainer(cb, size); - array.andInto(bits); - position += skip; - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer() - .limit(1024); - MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); - bitmap.andInto(bits); - position += BITMAP_SIZE; - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableRunContainer run = new MappeableRunContainer(cb, size); - run.andInto(bits); - position += skip; - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableArrayContainer array = new MappeableArrayContainer(cb, size); + array.andInto(bits); + position += skip; + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer().limit(1024); + MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); + bitmap.andInto(bits); + position += BITMAP_SIZE; + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableRunContainer run = new MappeableRunContainer(cb, size); + run.andInto(bits); + position += skip; + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -821,35 +831,40 @@ private void orNextIntoBits() { int size = buffer.getChar(position) & 0xFFFF; position += Character.BYTES; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableArrayContainer array = new MappeableArrayContainer(cb, size); - array.orInto(bits); - position += skip; - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer() - .limit(1024); - MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); - bitmap.orInto(bits); - position += BITMAP_SIZE; - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableRunContainer run = new MappeableRunContainer(cb, size); - run.orInto(bits); - position += skip; - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableArrayContainer array = new MappeableArrayContainer(cb, size); + array.orInto(bits); + position += skip; + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer().limit(1024); + MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); + bitmap.orInto(bits); + position += BITMAP_SIZE; + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableRunContainer run = new MappeableRunContainer(cb, size); + run.orInto(bits); + position += skip; + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -859,35 +874,40 @@ private void removeNextFromBits() { int size = buffer.getChar(position) & 0xFFFF; position += Character.BYTES; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableArrayContainer array = new MappeableArrayContainer(cb, size); - array.removeFrom(bits); - position += skip; - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer() - .limit(1024); - MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); - bitmap.removeFrom(bits); - position += BITMAP_SIZE; - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableRunContainer run = new MappeableRunContainer(cb, size); - run.removeFrom(bits); - position += skip; - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableArrayContainer array = new MappeableArrayContainer(cb, size); + array.removeFrom(bits); + position += skip; + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer().limit(1024); + MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); + bitmap.removeFrom(bits); + position += BITMAP_SIZE; + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableRunContainer run = new MappeableRunContainer(cb, size); + run.removeFrom(bits); + position += skip; + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -900,6 +920,12 @@ private void skipContainer() { position += 3 + (size << (type == RUN ? 2 : 1)); } } + + private void skipContainers(long mask) { + for (int i = 0; i < Long.bitCount(mask); i++) { + skipContainer(); + } + } } private final class DoubleEvaluation { @@ -929,7 +955,7 @@ public RoaringBitmap compute(long lower, long upper) { bits = low.bits; } else { bits = low.bits; - for (int i = 0; i < bits.length & i < high.bits.length; i++) { + for (int i = 0; i < Math.min(bits.length, high.bits.length); i++) { bits[i] &= high.bits[i]; } } @@ -963,7 +989,7 @@ public long count(long lower, long upper) { } else if (high.full) { count += cardinalityInBitmapRange(low.bits, 0, remainder); } else { - for (int i = 0; i < low.bits.length & i < high.bits.length; i++) { + for (int i = 0; i < Math.min(low.bits.length, high.bits.length); i++) { high.bits[i] &= low.bits[i]; } count += cardinalityInBitmapRange(high.bits, 0, remainder); @@ -1001,7 +1027,7 @@ public long count(long lower, long upper, RoaringBitmap context) { } else if (high.full) { count += new BitmapContainer(low.bits, -1).andCardinality(container); } else { - for (int i = 0; i < low.bits.length & i < high.bits.length; i++) { + for (int i = 0; i < Math.min(low.bits.length, high.bits.length); i++) { high.bits[i] &= low.bits[i]; } count += new BitmapContainer(high.bits, -1).andCardinality(container); @@ -1015,17 +1041,17 @@ public long count(long lower, long upper, RoaringBitmap context) { return count; } - private void evaluateHorizontalSlice(long containerMask, long remaining, long lower, - long upper) { + private void evaluateHorizontalSlice( + long containerMask, long remaining, long lower, long upper) { // most significant absent bit in the threshold for which there is no container; // everything before this is wasted work, so we just skip over the containers - int skipLow = 64 - Long.numberOfLeadingZeros(((~lower & ~containerMask) & mask)); + int skipLow = 64 - Long.numberOfLeadingZeros((~(lower | containerMask) & mask)); if (skipLow == 64) { lower = 0L; } else if (skipLow > 0) { lower &= -(1L << skipLow); } - int skipHigh = 64 - Long.numberOfLeadingZeros(((~upper & ~containerMask) & mask)); + int skipHigh = 64 - Long.numberOfLeadingZeros((~(upper | containerMask) & mask)); if (skipHigh == 64) { upper = 0L; } else if (skipHigh > 0) { @@ -1083,38 +1109,43 @@ private void orLowOrHigh() { int size = buffer.getChar(position) & 0xFFFF; position += Character.BYTES; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableArrayContainer array = new MappeableArrayContainer(cb, size); - low.or(array); - high.or(array); - position += skip; - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer() - .limit(1024); - MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); - low.or(bitmap); - high.or(bitmap); - position += BITMAP_SIZE; - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableRunContainer run = new MappeableRunContainer(cb, size); - low.or(run); - high.or(run); - position += skip; - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableArrayContainer array = new MappeableArrayContainer(cb, size); + low.or(array); + high.or(array); + position += skip; + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer().limit(1024); + MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); + low.or(bitmap); + high.or(bitmap); + position += BITMAP_SIZE; + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableRunContainer run = new MappeableRunContainer(cb, size); + low.or(run); + high.or(run); + position += skip; + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -1124,38 +1155,43 @@ private void orLowAndHigh() { int size = buffer.getChar(position) & 0xFFFF; position += Character.BYTES; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableArrayContainer array = new MappeableArrayContainer(cb, size); - low.or(array); - high.and(array); - position += skip; - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer() - .limit(1024); - MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); - low.or(bitmap); - high.and(bitmap); - position += BITMAP_SIZE; - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableRunContainer run = new MappeableRunContainer(cb, size); - low.or(run); - high.and(run); - position += skip; - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableArrayContainer array = new MappeableArrayContainer(cb, size); + low.or(array); + high.and(array); + position += skip; + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer().limit(1024); + MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); + low.or(bitmap); + high.and(bitmap); + position += BITMAP_SIZE; + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableRunContainer run = new MappeableRunContainer(cb, size); + low.or(run); + high.and(run); + position += skip; + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -1165,38 +1201,43 @@ private void andLowOrHigh() { int size = buffer.getChar(position) & 0xFFFF; position += Character.BYTES; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableArrayContainer array = new MappeableArrayContainer(cb, size); - low.and(array); - high.or(array); - position += skip; - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer() - .limit(1024); - MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); - low.and(bitmap); - high.or(bitmap); - position += BITMAP_SIZE; - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableRunContainer run = new MappeableRunContainer(cb, size); - low.and(run); - high.or(run); - position += skip; - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableArrayContainer array = new MappeableArrayContainer(cb, size); + low.and(array); + high.or(array); + position += skip; + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer().limit(1024); + MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); + low.and(bitmap); + high.or(bitmap); + position += BITMAP_SIZE; + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableRunContainer run = new MappeableRunContainer(cb, size); + low.and(run); + high.or(run); + position += skip; + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -1206,38 +1247,43 @@ private void andLowAndHigh() { int size = buffer.getChar(position) & 0xFFFF; position += Character.BYTES; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableArrayContainer array = new MappeableArrayContainer(cb, size); - low.and(array); - high.and(array); - position += skip; - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer() - .limit(1024); - MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); - low.and(bitmap); - high.and(bitmap); - position += BITMAP_SIZE; - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position)).asCharBuffer() - .limit(skip >>> 1); - MappeableRunContainer run = new MappeableRunContainer(cb, size); - low.and(run); - high.and(run); - position += skip; - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableArrayContainer array = new MappeableArrayContainer(cb, size); + low.and(array); + high.and(array); + position += skip; + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) ((ByteBuffer) buffer.position(position)).asLongBuffer().limit(1024); + MappeableBitmapContainer bitmap = new MappeableBitmapContainer(lb, size); + low.and(bitmap); + high.and(bitmap); + position += BITMAP_SIZE; + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position)).asCharBuffer().limit(skip >>> 1); + MappeableRunContainer run = new MappeableRunContainer(cb, size); + low.and(run); + high.and(run); + position += skip; + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -1245,29 +1291,35 @@ private void orNextIntoBits(Bits bits) { int type = buffer.get(position); int size = buffer.getChar(position + 1) & 0xFFFF; switch (type) { - case ARRAY: { - int skip = size << 1; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position + 3)).asCharBuffer() - .limit(skip >>> 1); - bits.or(new MappeableArrayContainer(cb, size)); - } - break; - case BITMAP: { - LongBuffer lb = (LongBuffer) ((ByteBuffer) buffer.position(position + 3)).asLongBuffer() - .limit(1024); - bits.or(new MappeableBitmapContainer(lb, size)); - } - break; - case RUN: { - int skip = size << 2; - CharBuffer cb = (CharBuffer) ((ByteBuffer) buffer.position(position + 3)).asCharBuffer() - .limit(skip >>> 1); - bits.or(new MappeableRunContainer(cb, size)); - } - break; + case ARRAY: + { + int skip = size << 1; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position + 3)).asCharBuffer().limit(skip >>> 1); + bits.or(new MappeableArrayContainer(cb, size)); + } + break; + case BITMAP: + { + LongBuffer lb = + (LongBuffer) + ((ByteBuffer) buffer.position(position + 3)).asLongBuffer().limit(1024); + bits.or(new MappeableBitmapContainer(lb, size)); + } + break; + case RUN: + { + int skip = size << 2; + CharBuffer cb = + (CharBuffer) + ((ByteBuffer) buffer.position(position + 3)).asCharBuffer().limit(skip >>> 1); + bits.or(new MappeableRunContainer(cb, size)); + } + break; default: - throw new IllegalStateException("Unknown type " + type - + " (this is a bug, please report it.)"); + throw new IllegalStateException( + "Unknown type " + type + " (this is a bug, please report it.)"); } } @@ -1290,16 +1342,14 @@ private static final class Bits { public void clear() { if (!empty) { Arrays.fill(bits, 0L); - empty = true; - full = false; + makeEmpty(); } } public void fill() { if (!full) { Arrays.fill(bits, -1L); - empty = false; - full = true; + makeFull(); } } @@ -1310,20 +1360,18 @@ public void reset(int boundary) { if (!empty) { resetBitmapRange(bits, boundary, 0x10000); } - empty = false; - full = false; + makeNonEmpty(); + makeNonFull(); } public void flip(int from, int to) { + Util.flipBitmapRange(bits, from, to); if (!full) { - Util.flipBitmapRange(bits, from, to); if (empty) { - empty = false; - full = true; + makeFull(); } } else { - full = false; - empty = true; + makeEmpty(); } } @@ -1332,20 +1380,38 @@ public void or(MappeableContainer container) { fill(); } else if (!full) { container.orInto(bits); - empty = false; + makeNonEmpty(); } } public void and(MappeableContainer container) { - if (!empty & !container.isFull()) { + if (!empty && !container.isFull()) { container.andInto(bits); - full = false; + makeNonFull(); } } + + private void makeEmpty() { + this.empty = true; + this.full = false; + } + + private void makeNonEmpty() { + this.empty = false; + } + + private void makeFull() { + this.full = true; + this.empty = false; + } + + private void makeNonFull() { + this.full = false; + } } - private static long getContainerMask(ByteBuffer buffer, int position, long mask, - int bytesPerMask) { + private static long getContainerMask( + ByteBuffer buffer, int position, long mask, int bytesPerMask) { switch (bytesPerMask) { case 0: case 1: @@ -1450,11 +1516,7 @@ public int serializedSizeInBytes() { int slicesSize = 1; int maxKeySize = 2; int maxRidSize = 4; - int headerSize = cookieSize - + baseSize - + slicesSize - + maxKeySize - + maxRidSize; + int headerSize = cookieSize + baseSize + slicesSize + maxKeySize + maxRidSize; int keysSize = key * bytesPerMask; return headerSize + keysSize + serializedContainerSize; } @@ -1473,19 +1535,17 @@ public void serialize(ByteBuffer buffer) { throw new IllegalStateException( "Attempted to serialize without calling serializedSizeInBytes first"); } - ByteBuffer target = buffer.order() == LITTLE_ENDIAN - ? buffer - : buffer.slice().order(LITTLE_ENDIAN); + ByteBuffer target = + buffer.order() == LITTLE_ENDIAN ? buffer : buffer.slice().order(LITTLE_ENDIAN); target.putChar((char) COOKIE); target.put((byte) 2); target.put((byte) Long.bitCount(rangeMask)); target.putChar((char) key); target.putInt(rid); int spaceForKeys = key * bytesPerMask; - target.put(((ByteBuffer) maskBuffer.slice() - .order(LITTLE_ENDIAN).limit(spaceForKeys))); - target.put(((ByteBuffer) containers.slice() - .order(LITTLE_ENDIAN).limit(serializedContainerSize))); + target.put(((ByteBuffer) maskBuffer.slice().order(LITTLE_ENDIAN).limit(spaceForKeys))); + target.put( + ((ByteBuffer) containers.slice().order(LITTLE_ENDIAN).limit(serializedContainerSize))); if (buffer != target) { buffer.position(target.position()); } @@ -1539,9 +1599,10 @@ private void append() { if (!container.isEmpty()) { Container toSerialize = container.runOptimize(); int serializedSize = toSerialize.serializedSizeInBytes(); - int type = (toSerialize instanceof BitmapContainer) - ? BITMAP - : (toSerialize instanceof RunContainer) ? RUN : ARRAY; + int type = + (toSerialize instanceof BitmapContainer) + ? BITMAP + : (toSerialize instanceof RunContainer) ? RUN : ARRAY; int required = serializedSize + (type == BITMAP ? 3 : 1); if (containers.capacity() - serializedContainerSize < required) { int growthFactor = 8192 * slice.length; @@ -1609,7 +1670,7 @@ private Container containerForSlice(int sliceNumber) { */ private static long rangeMask(long maxValue) { int lz = Long.numberOfLeadingZeros(maxValue | 1); - return lz == 0 ? -1L : (1L << (64 - lz)) - 1; + return -1L >>> lz; } private static byte bytesPerMask(long maxValue) { diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RelativeRangeConsumer.java b/roaringbitmap/src/main/java/org/roaringbitmap/RelativeRangeConsumer.java similarity index 100% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RelativeRangeConsumer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RelativeRangeConsumer.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/ReverseIntIteratorFlyweight.java b/roaringbitmap/src/main/java/org/roaringbitmap/ReverseIntIteratorFlyweight.java similarity index 90% rename from RoaringBitmap/src/main/java/org/roaringbitmap/ReverseIntIteratorFlyweight.java rename to roaringbitmap/src/main/java/org/roaringbitmap/ReverseIntIteratorFlyweight.java index 88212bce6..a743db60e 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/ReverseIntIteratorFlyweight.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/ReverseIntIteratorFlyweight.java @@ -7,9 +7,9 @@ /** * Fast iterator minimizing the stress on the garbage collector. You can create one reusable * instance of this class and then {@link #wrap(RoaringBitmap)} - * + * * This iterator enumerates the stored values in reverse (starting from the end). - * + * * @author Borislav Ivanov **/ public class ReverseIntIteratorFlyweight implements IntIterator { @@ -20,8 +20,7 @@ public class ReverseIntIteratorFlyweight implements IntIterator { private ReverseArrayContainerCharIterator arrIter = new ReverseArrayContainerCharIterator(); - private ReverseBitmapContainerCharIterator bitmapIter = - new ReverseBitmapContainerCharIterator(); + private ReverseBitmapContainerCharIterator bitmapIter = new ReverseBitmapContainerCharIterator(); private ReverseRunContainerCharIterator runIter = new ReverseRunContainerCharIterator(); @@ -29,18 +28,15 @@ public class ReverseIntIteratorFlyweight implements IntIterator { private RoaringBitmap roaringBitmap = null; - /** * Creates an instance that is not ready for iteration. You must first call * {@link #wrap(RoaringBitmap)}. */ - public ReverseIntIteratorFlyweight() { - - } + public ReverseIntIteratorFlyweight() {} /** * Creates an instance that is ready for iteration. - * + * * @param r bitmap to be iterated over */ public ReverseIntIteratorFlyweight(RoaringBitmap r) { @@ -51,12 +47,12 @@ public ReverseIntIteratorFlyweight(RoaringBitmap r) { public IntIterator clone() { try { ReverseIntIteratorFlyweight x = (ReverseIntIteratorFlyweight) super.clone(); - if(this.iter != null) { + if (this.iter != null) { x.iter = this.iter.clone(); } return x; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -65,8 +61,6 @@ public boolean hasNext() { return pos >= 0; } - - @Override public int next() { final int x = iter.nextAsInt() | hs; @@ -79,8 +73,6 @@ public int next() { private void nextContainer() { - - if (pos >= 0) { Container container = this.roaringBitmap.highLowContainer.getContainerAtIndex(pos); @@ -100,7 +92,7 @@ private void nextContainer() { /** * Prepares a bitmap for iteration - * + * * @param r bitmap to be iterated over */ public void wrap(RoaringBitmap r) { @@ -109,5 +101,4 @@ public void wrap(RoaringBitmap r) { this.pos = (short) (this.roaringBitmap.highLowContainer.size() - 1); this.nextContainer(); } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringArray.java b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringArray.java similarity index 91% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RoaringArray.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RoaringArray.java index b90c01c64..dd04e2c51 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringArray.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringArray.java @@ -4,17 +4,20 @@ package org.roaringbitmap; +import static java.nio.ByteOrder.LITTLE_ENDIAN; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.LongBuffer; import java.util.Arrays; import java.util.NoSuchElementException; -import static java.nio.ByteOrder.LITTLE_ENDIAN; - - /** * Specialized array to store the containers used by a RoaringBitmap. This is not meant to be used * by end users. @@ -30,7 +33,6 @@ public final class RoaringArray implements Cloneable, Externalizable, Appendable static final int INITIAL_CAPACITY = 4; - char[] keys = null; Container[] values = null; @@ -45,7 +47,6 @@ protected RoaringArray() { this(new char[initialCapacity], new Container[initialCapacity], 0); } - RoaringArray(char[] keys, Container[] values, int size) { this.keys = keys; this.values = values; @@ -72,8 +73,7 @@ protected int advanceUntil(char x, int pos) { int spansize = 1; // could set larger // bootstrap an upper limit - while (lower + spansize < size - && (keys[lower + spansize]) < x) { + while (lower + spansize < size && (keys[lower + spansize]) < x) { spansize *= 2; // hoping for compiler will reduce to shift } int upper = (lower + spansize < size) ? lower + spansize : size - 1; @@ -84,8 +84,8 @@ protected int advanceUntil(char x, int pos) { return upper; } - if (keys[upper] < x) {// means array has no item key >= - // x + if (keys[upper] < x) { // means array has no item key >= + // x return size; } @@ -110,8 +110,7 @@ protected int advanceUntil(char x, int pos) { @Override public void append(char key, Container value) { if (size > 0 && key < keys[size - 1]) { - throw new IllegalArgumentException("append only: " - + (key) + " < " + (keys[size - 1])); + throw new IllegalArgumentException("append only: " + (key) + " < " + (keys[size - 1])); } extendArray(1); keys[size] = key; @@ -120,8 +119,7 @@ public void append(char key, Container value) { } void append(RoaringArray roaringArray) { - assert size == 0 || roaringArray.size == 0 - || keys[size - 1] < roaringArray.keys[0]; + assert size == 0 || roaringArray.size == 0 || keys[size - 1] < roaringArray.keys[0]; if (roaringArray.size != 0 && size != 0) { keys = Arrays.copyOf(keys, size + roaringArray.size); values = Arrays.copyOf(values, size + roaringArray.size); @@ -204,8 +202,6 @@ void appendCopy(RoaringArray sa, int startingIndex, int end) { } } - - /** * Append the values from another array, no copy is made (use with care) * @@ -222,7 +218,6 @@ protected void append(RoaringArray sa, int startingIndex, int end) { } } - private int binarySearch(int begin, int end, char key) { return Util.unsignedBinarySearch(keys, begin, end, key); } @@ -280,10 +275,12 @@ public void deserialize(DataInput in) throws IOException { if ((cookie & 0xFFFF) != SERIAL_COOKIE && cookie != SERIAL_COOKIE_NO_RUNCONTAINER) { throw new InvalidRoaringFormat("I failed to find a valid cookie."); } - this.size = ((cookie & 0xFFFF) == SERIAL_COOKIE) ? (cookie >>> 16) + 1 - : Integer.reverseBytes(in.readInt()); + this.size = + ((cookie & 0xFFFF) == SERIAL_COOKIE) + ? (cookie >>> 16) + 1 + : Integer.reverseBytes(in.readInt()); // logically we cannot have more than (1<<16) containers. - if(this.size > (1<<16)) { + if (this.size > (1 << 16)) { throw new InvalidRoaringFormat("Size too large"); } if ((this.keys == null) || (this.keys.length < this.size)) { @@ -291,7 +288,6 @@ public void deserialize(DataInput in) throws IOException { this.values = new Container[this.size]; } - byte[] bitmapOfRunContainers = null; boolean hasrun = (cookie & 0xFFFF) == SERIAL_COOKIE; if (hasrun) { @@ -368,17 +364,19 @@ public void deserialize(DataInput in, byte[] buffer) throws IOException { throw new IllegalArgumentException( "We need a buffer with a length multiple of 8. was length=" + buffer.length); } - + this.clear(); // little endian final int cookie = Integer.reverseBytes(in.readInt()); if ((cookie & 0xFFFF) != SERIAL_COOKIE && cookie != SERIAL_COOKIE_NO_RUNCONTAINER) { throw new InvalidRoaringFormat("I failed to find a valid cookie."); } - this.size = ((cookie & 0xFFFF) == SERIAL_COOKIE) ? (cookie >>> 16) + 1 - : Integer.reverseBytes(in.readInt()); + this.size = + ((cookie & 0xFFFF) == SERIAL_COOKIE) + ? (cookie >>> 16) + 1 + : Integer.reverseBytes(in.readInt()); // logically we cannot have more than (1<<16) containers. - if(this.size > (1<<16)) { + if (this.size > (1 << 16)) { throw new InvalidRoaringFormat("Size too large"); } if ((this.keys == null) || (this.keys.length < this.size)) { @@ -386,7 +384,6 @@ public void deserialize(DataInput in, byte[] buffer) throws IOException { this.values = new Container[this.size]; } - byte[] bitmapOfRunContainers = null; boolean hasrun = (cookie & 0xFFFF) == SERIAL_COOKIE; if (hasrun) { @@ -416,39 +413,39 @@ public void deserialize(DataInput in, byte[] buffer) throws IOException { Container val; if (isBitmap[k]) { final long[] bitmapArray = new long[BitmapContainer.MAX_CAPACITY / 64]; - + if (buffer == null) { // a buffer to load a Container in a single .readFully // We initialize it with the length of a BitmapContainer buffer = new byte[(BitmapContainer.MAX_CAPACITY / 64) * 8]; } - + if (buffer.length < (BitmapContainer.MAX_CAPACITY / 64) * 8) { // We have been provided a rather small buffer - - for (int iBlock = 0 ; iBlock <= 8 * bitmapArray.length / buffer.length ; iBlock++) { + + for (int iBlock = 0; iBlock <= 8 * bitmapArray.length / buffer.length; iBlock++) { int start = buffer.length * iBlock; - int end = Math.min(buffer.length * (iBlock +1 ), 8 * bitmapArray.length); - + int end = Math.min(buffer.length * (iBlock + 1), 8 * bitmapArray.length); + in.readFully(buffer, 0, end - start); - + // little endian ByteBuffer asByteBuffer = ByteBuffer.wrap(buffer); asByteBuffer.order(LITTLE_ENDIAN); - + LongBuffer asLongBuffer = asByteBuffer.asLongBuffer(); asLongBuffer.rewind(); asLongBuffer.get(bitmapArray, start / 8, (end - start) / 8); } - + } else { // Read the whole bitmapContainer in a single pass in.readFully(buffer, 0, bitmapArray.length * 8); - + // little endian ByteBuffer asByteBuffer = ByteBuffer.wrap(buffer); asByteBuffer.order(LITTLE_ENDIAN); - + LongBuffer asLongBuffer = asByteBuffer.asLongBuffer(); asLongBuffer.rewind(); asLongBuffer.get(bitmapArray); @@ -459,35 +456,35 @@ public void deserialize(DataInput in, byte[] buffer) throws IOException { // cf RunContainer.writeArray() int nbrruns = (Character.reverseBytes(in.readChar())); final char[] lengthsAndValues = new char[2 * nbrruns]; - + if (buffer == null && lengthsAndValues.length > (BitmapContainer.MAX_CAPACITY / 64) * 8) { // a buffer to load a Container in a single .readFully // We initialize it with the length of a BitmapContainer buffer = new byte[(BitmapContainer.MAX_CAPACITY / 64) * 8]; } - + if (buffer == null) { // The RunContainer is small: skip the buffer allocation for (int j = 0; j < lengthsAndValues.length; ++j) { lengthsAndValues[j] = Character.reverseBytes(in.readChar()); } } else { - for (int iBlock = 0 ; iBlock <= 2 * lengthsAndValues.length / buffer.length ; iBlock++) { + for (int iBlock = 0; iBlock <= 2 * lengthsAndValues.length / buffer.length; iBlock++) { int start = buffer.length * iBlock; - int end = Math.min(buffer.length * (iBlock +1 ), 2 * lengthsAndValues.length); - + int end = Math.min(buffer.length * (iBlock + 1), 2 * lengthsAndValues.length); + in.readFully(buffer, 0, end - start); // little endian ByteBuffer asByteBuffer = ByteBuffer.wrap(buffer); asByteBuffer.order(LITTLE_ENDIAN); - + CharBuffer asCharBuffer = asByteBuffer.asCharBuffer(); asCharBuffer.rewind(); asCharBuffer.get(lengthsAndValues, start / 2, (end - start) / 2); } } - + val = new RunContainer(lengthsAndValues, nbrruns); } else { final char[] charArray = new char[cardinalities[k]]; @@ -497,48 +494,48 @@ public void deserialize(DataInput in, byte[] buffer) throws IOException { // We initialize it with the length of a BitmapContainer buffer = new byte[(BitmapContainer.MAX_CAPACITY / 64) * 8]; } - + if (buffer == null) { // The ArrayContainer is small: skip the buffer allocation for (int j = 0; j < charArray.length; ++j) { charArray[j] = Character.reverseBytes(in.readChar()); } } else { - for (int iBlock = 0 ; iBlock <= 2 * charArray.length / buffer.length ; iBlock++) { + for (int iBlock = 0; iBlock <= 2 * charArray.length / buffer.length; iBlock++) { int start = buffer.length * iBlock; - int end = Math.min(buffer.length * (iBlock +1 ) , 2 * charArray.length); - + int end = Math.min(buffer.length * (iBlock + 1), 2 * charArray.length); + in.readFully(buffer, 0, end - start); // little endian ByteBuffer asByteBuffer = ByteBuffer.wrap(buffer); asByteBuffer.order(LITTLE_ENDIAN); - + CharBuffer asCharBuffer = asByteBuffer.asCharBuffer(); asCharBuffer.rewind(); asCharBuffer.get(charArray, start / 2, (end - start) / 2); } } - + val = new ArrayContainer(charArray); } this.keys[k] = keys[k]; this.values[k] = val; } } - + /** * Deserialize (retrieve) this bitmap. See format specification at * https://github.com/RoaringBitmap/RoaringFormatSpec * * The current bitmap is overwritten. - * + * * It is not necessary that limit() on the input ByteBuffer indicates the end of the serialized * data. - * + * * After loading this RoaringBitmap, you can advance to the rest of the data (if there * is more) by setting bbf.position(bbf.position() + bitmap.serializedSizeInBytes()); - * + * * Note that the input ByteBuffer is effectively copied (with the slice operation) so you should * expect the provided ByteBuffer position/mark/limit/order to remain unchanged. * @@ -546,7 +543,7 @@ public void deserialize(DataInput in, byte[] buffer) throws IOException { */ public void deserialize(ByteBuffer bbf) { this.clear(); - + // slice not to mutate the input ByteBuffer ByteBuffer buffer = bbf.slice(); buffer.order(LITTLE_ENDIAN); @@ -559,9 +556,9 @@ public void deserialize(ByteBuffer bbf) { // TODO For now, we consider the limit is already set by the caller // int theLimit = size > 0 ? computeSerializedSizeInBytes() : headerSize(hasRunContainers); // buffer.limit(theLimit); - + // logically we cannot have more than (1<<16) containers. - if(this.size > (1<<16)) { + if (this.size > (1 << 16)) { throw new InvalidRoaringFormat("Size too large"); } if ((this.keys == null) || (this.keys.length < this.size)) { @@ -569,7 +566,6 @@ public void deserialize(ByteBuffer bbf) { this.values = new Container[this.size]; } - byte[] bitmapOfRunContainers = null; boolean hasrun = (cookie & 0xFFFF) == SERIAL_COOKIE; if (hasrun) { @@ -599,10 +595,10 @@ public void deserialize(ByteBuffer bbf) { Container val; if (isBitmap[k]) { final long[] bitmapArray = new long[BitmapContainer.MAX_CAPACITY / 64]; - + buffer.asLongBuffer().get(bitmapArray); buffer.position(buffer.position() + bitmapArray.length * 8); - + val = new BitmapContainer(bitmapArray, cardinalities[k]); } else if (bitmapOfRunContainers != null && ((bitmapOfRunContainers[k / 8] & (1 << (k % 8))) != 0)) { @@ -612,15 +608,14 @@ public void deserialize(ByteBuffer bbf) { buffer.asCharBuffer().get(lengthsAndValues); buffer.position(buffer.position() + lengthsAndValues.length * 2); - + val = new RunContainer(lengthsAndValues, nbrruns); } else { final char[] charArray = new char[cardinalities[k]]; - buffer.asCharBuffer().get(charArray); buffer.position(buffer.position() + charArray.length * 2); - + val = new ArrayContainer(charArray); } this.keys[k] = keys[k]; @@ -628,7 +623,6 @@ public void deserialize(ByteBuffer bbf) { } } - @Override public boolean equals(Object o) { if (o instanceof RoaringArray) { @@ -663,15 +657,6 @@ void extendArray(int k) { } } - // involves a binary search - protected Container getContainer(char x) { - int i = getContainerIndex(x); - if (i < 0) { - return null; - } - return this.values[i]; - } - protected int getContainerIndex(char x) { int i = this.binarySearch(0, size, x); return i; @@ -690,10 +675,10 @@ public ContainerPointer getContainerPointer() { } /** - * Create a ContainerPointer for this RoaringArray - * @param startIndex starting index in the container list - * @return a ContainerPointer - */ + * Create a ContainerPointer for this RoaringArray + * @param startIndex starting index in the container list + * @return a ContainerPointer + */ public ContainerPointer getContainerPointer(final int startIndex) { return new ContainerPointer() { int k = startIndex; @@ -701,7 +686,6 @@ public ContainerPointer getContainerPointer(final int startIndex) { @Override public void advance() { ++k; - } @Override @@ -709,7 +693,7 @@ public ContainerPointer clone() { try { return (ContainerPointer) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -734,7 +718,6 @@ public Container getContainer() { return RoaringArray.this.values[k]; } - @Override public boolean isBitmapContainer() { return getContainer() instanceof BitmapContainer; @@ -745,11 +728,9 @@ public boolean isRunContainer() { return getContainer() instanceof RunContainer; } - @Override public char key() { return RoaringArray.this.keys[k]; - } }; } @@ -789,16 +770,15 @@ private boolean hasRunContainer() { private int headerSize() { if (hasRunContainer()) { - if (size < NO_OFFSET_THRESHOLD) {// for small bitmaps, we omit the offsets + if (size < NO_OFFSET_THRESHOLD) { // for small bitmaps, we omit the offsets return 4 + (size + 7) / 8 + 4 * size; } - return 4 + (size + 7) / 8 + 8 * size;// - 4 because we pack the size with the cookie + return 4 + (size + 7) / 8 + 8 * size; // - 4 because we pack the size with the cookie } else { return 4 + 4 + 8 * size; } } - // insert a new key, it is assumed that it does not exist void insertNewKeyValueAt(int i, char key, Container value) { extendArray(1); @@ -847,8 +827,6 @@ void resize(int newLength) { this.size = newLength; } - - /** * Serialize. * @@ -916,7 +894,7 @@ public void serialize(ByteBuffer buffer) { runMarker |= (1 << j); } } - buf.put((byte)runMarker); + buf.put((byte) runMarker); } int runMarkersLength = buf.position() - offset; if (this.size < NO_OFFSET_THRESHOLD) { @@ -975,8 +953,8 @@ public void writeExternal(ObjectOutput out) throws IOException { } /** - * Gets the first value in the array - * @return the first value in the array + * Gets the smallest unsigned (first) integer in the array. + * @return the smallest unsigned (first) integer in the array * @throws NoSuchElementException if empty */ public int first() { @@ -987,8 +965,8 @@ public int first() { } /** - * Gets the last value in the array - * @return the last value in the array + * Gets the largest unsigned (last) integer in the array. + * @return the largest unsigned (last) integer in the array * @throws NoSuchElementException if empty */ public int last() { @@ -998,8 +976,40 @@ public int last() { return lastKey << 16 | container.last(); } + /** + * Gets the smallest signed integer in the array. + * @return the smallest signed integer in the array + * @throws NoSuchElementException if empty + */ + public int firstSigned() { + assertNonEmpty(); + int index = advanceUntil((char) (1 << 15), -1); + if (index == size) { // no negatives + index = 0; + } + char key = keys[index]; + Container container = values[index]; + return key << 16 | container.first(); + } + + /** + * Gets the largest signed integer in the array. + * @return the largest signed integer in the array + * @throws NoSuchElementException if empty + */ + public int lastSigned() { + assertNonEmpty(); + int index = advanceUntil((char) (1 << 15), -1) - 1; + if (index == -1) { // no positives + index += size; + } + char key = keys[index]; + Container container = values[index]; + return key << 16 | container.last(); + } + private void assertNonEmpty() { - if(size == 0) { + if (size == 0) { throw new NoSuchElementException("Empty RoaringArray"); } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBatchIterator.java similarity index 85% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RoaringBatchIterator.java index f68a3841a..759808d98 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBatchIterator.java @@ -18,9 +18,9 @@ public RoaringBatchIterator(RoaringArray highLowContainer) { @Override public int nextBatch(int[] buffer) { int consumed = 0; - while (iterator != null && consumed == 0) { - consumed = iterator.next(key, buffer); - if (consumed == 0 || !iterator.hasNext()) { + while (iterator != null && consumed < buffer.length) { + consumed += iterator.next(key, buffer, consumed); + if (consumed < buffer.length || !iterator.hasNext()) { nextContainer(); } } @@ -35,7 +35,7 @@ public boolean hasNext() { @Override public BatchIterator clone() { try { - RoaringBatchIterator it = (RoaringBatchIterator)super.clone(); + RoaringBatchIterator it = (RoaringBatchIterator) super.clone(); if (null != iterator) { it.iterator = iterator.clone(); } @@ -74,11 +74,11 @@ private void nextIterator() { if (index < highLowContainer.size()) { Container container = highLowContainer.getContainerAtIndex(index); if (container instanceof ArrayContainer) { - nextIterator((ArrayContainer)container); + nextIterator((ArrayContainer) container); } else if (container instanceof BitmapContainer) { - nextIterator((BitmapContainer)container); - } else if (container instanceof RunContainer){ - nextIterator((RunContainer)container); + nextIterator((BitmapContainer) container); + } else if (container instanceof RunContainer) { + nextIterator((RunContainer) container); } key = highLowContainer.getKeyAtIndex(index) << 16; } else { diff --git a/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitSet.java b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitSet.java new file mode 100644 index 000000000..9f1587735 --- /dev/null +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitSet.java @@ -0,0 +1,226 @@ +package org.roaringbitmap; + +import java.util.BitSet; +import java.util.stream.IntStream; + +/** + * A {@link BitSet} implementation based on {@link RoaringBitmap}. + */ +public class RoaringBitSet extends BitSet { + private static final long serialVersionUID = 1L; + + private final RoaringBitmap roaringBitmap; + + public RoaringBitSet() { + super(0); + roaringBitmap = new RoaringBitmap(); + } + + private RoaringBitSet(RoaringBitmap roaringBitmap) { + super(0); + this.roaringBitmap = roaringBitmap; + } + + @Override + public void set(int bitIndex) { + roaringBitmap.add(bitIndex); + } + + @Override + public void set(int bitIndex, boolean value) { + if (value) { + roaringBitmap.add(bitIndex); + } else { + roaringBitmap.remove(bitIndex); + } + } + + @Override + public void set(int fromIndex, int toIndex) { + roaringBitmap.add((long) fromIndex, (long) toIndex); + } + + @Override + public void set(int fromIndex, int toIndex, boolean value) { + if (value) { + roaringBitmap.add((long) fromIndex, (long) toIndex); + } else { + roaringBitmap.remove((long) fromIndex, (long) toIndex); + } + } + + @Override + public void clear(int bitIndex) { + roaringBitmap.remove(bitIndex); + } + + @Override + public void clear(int fromIndex, int toIndex) { + roaringBitmap.remove((long) fromIndex, (long) toIndex); + } + + @Override + public void clear() { + roaringBitmap.clear(); + } + + @Override + public boolean get(int bitIndex) { + return roaringBitmap.contains(bitIndex); + } + + @Override + public BitSet get(int fromIndex, int toIndex) { + RoaringBitmap newBitmap = roaringBitmap.selectRange(fromIndex, toIndex); + // shift the bits to start from index 0 + newBitmap = RoaringBitmap.addOffset(newBitmap, -fromIndex); + return new RoaringBitSet(newBitmap); + } + + @Override + public int nextSetBit(int fromIndex) { + return (int) roaringBitmap.nextValue(fromIndex); + } + + @Override + public int nextClearBit(int fromIndex) { + return (int) roaringBitmap.nextAbsentValue(fromIndex); + } + + @Override + public int previousSetBit(int fromIndex) { + return (int) roaringBitmap.previousValue(fromIndex); + } + + @Override + public int previousClearBit(int fromIndex) { + return (int) roaringBitmap.previousAbsentValue(fromIndex); + } + + @Override + public int length() { + if (roaringBitmap.isEmpty()) { + return 0; + } + return roaringBitmap.last() + 1; + } + + @Override + public boolean isEmpty() { + return roaringBitmap.isEmpty(); + } + + @Override + public boolean intersects(BitSet set) { + if (set instanceof RoaringBitSet) { + return RoaringBitmap.intersects(roaringBitmap, ((RoaringBitSet) set).roaringBitmap); + } + return RoaringBitmap.intersects(roaringBitmap, fromBitSet(set)); + } + + @Override + public int cardinality() { + return roaringBitmap.getCardinality(); + } + + @Override + public void and(BitSet set) { + if (set instanceof RoaringBitSet) { + roaringBitmap.and(((RoaringBitSet) set).roaringBitmap); + } else { + roaringBitmap.and(fromBitSet(set)); + } + } + + @Override + public void or(BitSet set) { + if (set instanceof RoaringBitSet) { + roaringBitmap.or(((RoaringBitSet) set).roaringBitmap); + } else { + roaringBitmap.or(fromBitSet(set)); + } + } + + @Override + public void xor(BitSet set) { + if (set instanceof RoaringBitSet) { + roaringBitmap.xor(((RoaringBitSet) set).roaringBitmap); + } else { + roaringBitmap.xor(fromBitSet(set)); + } + } + + @Override + public void andNot(BitSet set) { + if (set instanceof RoaringBitSet) { + roaringBitmap.andNot(((RoaringBitSet) set).roaringBitmap); + } else { + roaringBitmap.andNot(fromBitSet(set)); + } + } + + @Override + public int hashCode() { + return roaringBitmap.hashCode(); + } + + @Override + public int size() { + if (roaringBitmap.isEmpty()) { + return 0; + } + int lastBit = Math.max(length(), 64); + int remainder = lastBit % 64; + return remainder == 0 ? lastBit : lastBit + 64 - remainder; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof RoaringBitSet) { + return roaringBitmap.equals(((RoaringBitSet) obj).roaringBitmap); + } + return false; + } + + @Override + public Object clone() { + return new RoaringBitSet(roaringBitmap.clone()); + } + + @Override + public IntStream stream() { + return roaringBitmap.stream(); + } + + @Override + public String toString() { + return roaringBitmap.toString(); + } + + @Override + public void flip(int bitIndex) { + roaringBitmap.flip((long) bitIndex, (long) bitIndex + 1); + } + + @Override + public void flip(int fromIndex, int toIndex) { + roaringBitmap.flip((long) fromIndex, (long) toIndex); + } + + @Override + public long[] toLongArray() { + return BitSetUtil.toLongArray(roaringBitmap); + } + + @Override + public byte[] toByteArray() { + return BitSetUtil.toByteArray(roaringBitmap); + } + + private static RoaringBitmap fromBitSet(BitSet bitSet) { + return BitSetUtil.bitmapOf(bitSet); + } +} diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmap.java b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmap.java similarity index 81% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmap.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmap.java index 18a3462f0..7f21455ba 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmap.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmap.java @@ -4,18 +4,23 @@ package org.roaringbitmap; +import static org.roaringbitmap.RoaringBitmapWriter.writer; +import static org.roaringbitmap.Util.lowbitsAsInteger; + import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import org.roaringbitmap.buffer.MappeableContainerPointer; import org.roaringbitmap.buffer.MutableRoaringBitmap; +import org.roaringbitmap.longlong.LongUtils; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Serializable; import java.nio.ByteBuffer; import java.util.Iterator; -import java.util.NoSuchElementException; - -import static org.roaringbitmap.RoaringBitmapWriter.writer; -import static org.roaringbitmap.Util.lowbitsAsInteger; -import org.roaringbitmap.longlong.LongUtils; /** * RoaringBitmap, a compressed alternative to the BitSet. @@ -46,32 +51,42 @@ * * */ - - -public class RoaringBitmap implements Cloneable, Serializable, Iterable, Externalizable, - ImmutableBitmapDataProvider, BitmapDataProvider, AppendableStorage { - - private final class RoaringIntIterator implements PeekableIntIterator { +public class RoaringBitmap + implements Cloneable, + Serializable, + Iterable, + Externalizable, + ImmutableBitmapDataProvider, + BitmapDataProvider, + AppendableStorage { + + private class RoaringIntIterator implements PeekableIntIterator { + private final char startingContainerIndex; private int hs = 0; private PeekableCharIterator iter; private int pos = 0; - private RoaringIntIterator() { + public RoaringIntIterator() { + this.startingContainerIndex = findStartingContainerIndex(); nextContainer(); } + char findStartingContainerIndex() { + return 0; + } + @Override public PeekableIntIterator clone() { try { RoaringIntIterator x = (RoaringIntIterator) super.clone(); - if(this.iter != null) { + if (this.iter != null) { x.iter = this.iter.clone(); } return x; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -91,15 +106,17 @@ public int next() { } private void nextContainer() { - if (pos < RoaringBitmap.this.highLowContainer.size()) { - iter = RoaringBitmap.this.highLowContainer.getContainerAtIndex(pos).getCharIterator(); - hs = RoaringBitmap.this.highLowContainer.getKeyAtIndex(pos) << 16; + final int containerSize = RoaringBitmap.this.highLowContainer.size(); + if (pos < containerSize) { + final int index = (pos + startingContainerIndex) % containerSize; + iter = RoaringBitmap.this.highLowContainer.getContainerAtIndex(index).getCharIterator(); + hs = RoaringBitmap.this.highLowContainer.getKeyAtIndex(index) << 16; } } @Override public void advanceIfNeeded(int minval) { - while (hasNext() && ((hs >>> 16) < (minval >>> 16))) { + while (hasNext() && shouldAdvanceContainer(hs, minval)) { ++pos; nextContainer(); } @@ -112,12 +129,32 @@ public void advanceIfNeeded(int minval) { } } + boolean shouldAdvanceContainer(final int hs, final int minval) { + return (hs >>> 16) < (minval >>> 16); + } + @Override public int peekNext() { return (iter.peekNext()) | hs; } + } + private final class RoaringSignedIntIterator extends RoaringIntIterator { + @Override + char findStartingContainerIndex() { + // skip to starting at negative signed integers + char index = (char) RoaringBitmap.this.highLowContainer.advanceUntil((char) (1 << 15), -1); + if (index == RoaringBitmap.this.highLowContainer.size()) { + index = 0; + } + return index; + } + + @Override + boolean shouldAdvanceContainer(final int hs, final int minval) { + return (hs >> 16) < (minval >> 16); + } } private final class RoaringReverseIntIterator implements IntIterator { @@ -136,12 +173,12 @@ private RoaringReverseIntIterator() { public IntIterator clone() { try { RoaringReverseIntIterator clone = (RoaringReverseIntIterator) super.clone(); - if(this.iter != null) { + if (this.iter != null) { clone.iter = this.iter.clone(); } return clone; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -167,19 +204,18 @@ private void nextContainer() { hs = RoaringBitmap.this.highLowContainer.getKeyAtIndex(pos) << 16; } } - } private static final long serialVersionUID = 6L; private static void rangeSanityCheck(final long rangeStart, final long rangeEnd) { - if (rangeStart < 0 || rangeStart > (1L << 32)-1) { - throw new IllegalArgumentException("rangeStart="+ rangeStart - +" should be in [0, 0xffffffff]"); + if (rangeStart < 0 || rangeStart > (1L << 32) - 1) { + throw new IllegalArgumentException( + "rangeStart=" + rangeStart + " should be in [0, 0xffffffff]"); } if (rangeEnd > (1L << 32) || rangeEnd < 0) { - throw new IllegalArgumentException("rangeEnd="+ rangeEnd - +" should be in [0, 0xffffffff + 1]"); + throw new IllegalArgumentException( + "rangeEnd=" + rangeEnd + " should be in [0, 0xffffffff + 1]"); } } @@ -190,7 +226,7 @@ private static void rangeSanityCheck(final long rangeStart, final long rangeEnd) * negative. Values that would fall outside * of the valid 32-bit range are discarded * so that the result can have lower cardinality. - * + * * This method can be relatively expensive when * offset is not divisible by 65536. Use sparingly. * @@ -201,53 +237,52 @@ private static void rangeSanityCheck(final long rangeStart, final long rangeEnd) public static RoaringBitmap addOffset(final RoaringBitmap x, long offset) { // we need "offset" to be a long because we want to support values // between -0xFFFFFFFF up to +-0xFFFFFFFF - long container_offset_long = offset < 0 - ? (offset - (1<<16) + 1) / (1<<16) : offset / (1 << 16); - if((container_offset_long < -(1<<16) ) || (container_offset_long >= (1<<16) )) { + long container_offset_long = + offset < 0 ? (offset - (1 << 16) + 1) / (1 << 16) : offset / (1 << 16); + if ((container_offset_long < -(1 << 16)) || (container_offset_long >= (1 << 16))) { return new RoaringBitmap(); // it is necessarily going to be empty } // next cast is necessarily safe, the result is between -0xFFFF and 0xFFFF int container_offset = (int) container_offset_long; // next case is safe - int in_container_offset = (int)(offset - container_offset_long * (1L<<16)); - if(in_container_offset == 0) { + int in_container_offset = (int) (offset - container_offset_long * (1L << 16)); + if (in_container_offset == 0) { RoaringBitmap answer = new RoaringBitmap(); - for(int pos = 0; pos < x.highLowContainer.size(); pos++) { + for (int pos = 0; pos < x.highLowContainer.size(); pos++) { int key = (x.highLowContainer.getKeyAtIndex(pos)); key += container_offset; - answer.highLowContainer.append((char)key, - x.highLowContainer.getContainerAtIndex(pos).clone()); + answer.highLowContainer.append( + (char) key, x.highLowContainer.getContainerAtIndex(pos).clone()); } return answer; } else { RoaringBitmap answer = new RoaringBitmap(); - for(int pos = 0; pos < x.highLowContainer.size(); pos++) { + for (int pos = 0; pos < x.highLowContainer.size(); pos++) { int key = (x.highLowContainer.getKeyAtIndex(pos)); key += container_offset; + if (key + 1 < 0 || key > 0xFFFF) { + continue; + } Container c = x.highLowContainer.getContainerAtIndex(pos); - Container[] offsetted = Util.addOffset(c, - (char)in_container_offset); - boolean keyok = (key >= 0) && (key <= 0xFFFF); - boolean keypok = (key + 1 >= 0) && (key + 1 <= 0xFFFF); - if( !offsetted[0].isEmpty() && keyok) { + Container[] offsetted = Util.addOffset(c, (char) in_container_offset); + boolean keyok = key >= 0; + boolean keypok = key + 1 <= 0xFFFF; + if (!offsetted[0].isEmpty() && keyok) { int current_size = answer.highLowContainer.size(); int lastkey = 0; - if(current_size > 0) { - lastkey = (answer.highLowContainer.getKeyAtIndex( - current_size - 1)); + if (current_size > 0) { + lastkey = (answer.highLowContainer.getKeyAtIndex(current_size - 1)); } - if((current_size > 0) && (lastkey == key)) { - Container prev = answer.highLowContainer - .getContainerAtIndex(current_size - 1); + if ((current_size > 0) && (lastkey == key)) { + Container prev = answer.highLowContainer.getContainerAtIndex(current_size - 1); Container orresult = prev.ior(offsetted[0]); - answer.highLowContainer.setContainerAtIndex(current_size - 1, - orresult); + answer.highLowContainer.setContainerAtIndex(current_size - 1, orresult); } else { - answer.highLowContainer.append((char)key, offsetted[0]); + answer.highLowContainer.append((char) key, offsetted[0]); } } - if( !offsetted[1].isEmpty() && keypok) { - answer.highLowContainer.append((char)(key + 1), offsetted[1]); + if (!offsetted[1].isEmpty() && keypok) { + answer.highLowContainer.append((char) (key + 1), offsetted[1]); } } answer.repairAfterLazy(); @@ -269,7 +304,6 @@ public static RoaringBitmap add(RoaringBitmap rb, final long rangeStart, final l return rb.clone(); // empty range } - final int hbStart = (Util.highbits(rangeStart)); final int lbStart = (Util.lowbits(rangeStart)); final int hbLast = (Util.highbits(rangeEnd - 1)); @@ -281,7 +315,8 @@ public static RoaringBitmap add(RoaringBitmap rb, final long rangeStart, final l if (hbStart == hbLast) { final int i = rb.highLowContainer.getIndex((char) hbStart); final Container c = - i >= 0 ? rb.highLowContainer.getContainerAtIndex(i).add(lbStart, lbLast + 1) + i >= 0 + ? rb.highLowContainer.getContainerAtIndex(i).add(lbStart, lbLast + 1) : Container.rangeOfOnes(lbStart, lbLast + 1); answer.highLowContainer.append((char) hbStart, c); answer.highLowContainer.appendCopiesAfter(rb.highLowContainer, (char) hbLast); @@ -291,10 +326,12 @@ public static RoaringBitmap add(RoaringBitmap rb, final long rangeStart, final l int ilast = rb.highLowContainer.getIndex((char) hbLast); { - final Container c = ifirst >= 0 - ? rb.highLowContainer.getContainerAtIndex(ifirst).add(lbStart, - Util.maxLowBitAsInteger() + 1) - : Container.rangeOfOnes(lbStart, Util.maxLowBitAsInteger() + 1); + final Container c = + ifirst >= 0 + ? rb.highLowContainer + .getContainerAtIndex(ifirst) + .add(lbStart, Util.maxLowBitAsInteger() + 1) + : Container.rangeOfOnes(lbStart, Util.maxLowBitAsInteger() + 1); answer.highLowContainer.append((char) hbStart, c); } for (int hb = hbStart + 1; hb < hbLast; ++hb) { @@ -303,7 +340,8 @@ public static RoaringBitmap add(RoaringBitmap rb, final long rangeStart, final l } { final Container c = - ilast >= 0 ? rb.highLowContainer.getContainerAtIndex(ilast).add(0, lbLast + 1) + ilast >= 0 + ? rb.highLowContainer.getContainerAtIndex(ilast).add(0, lbLast + 1) : Container.rangeOfOnes(0, lbLast + 1); answer.highLowContainer.append((char) hbLast, c); } @@ -359,16 +397,15 @@ public static RoaringBitmap and(final RoaringBitmap x1, final RoaringBitmap x2) } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = x1.highLowContainer.advanceUntil(s2, pos1); - } else { + } else { pos2 = x2.highLowContainer.advanceUntil(s1, pos2); } } return answer; } - /** * Cardinality of Bitwise AND (intersection) operation. The provided bitmaps are *not* modified. * This operation is thread-safe as long as the provided bitmaps remain unchanged. @@ -389,13 +426,12 @@ public static int andCardinality(final RoaringBitmap x1, final RoaringBitmap x2) if (s1 == s2) { final Container c1 = x1.highLowContainer.getContainerAtIndex(pos1); final Container c2 = x2.highLowContainer.getContainerAtIndex(pos2); - // TODO: could be made faster if we did not have to materialize container answer += c1.andCardinality(c2); ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = x1.highLowContainer.advanceUntil(s2, pos1); - } else { + } else { pos2 = x2.highLowContainer.advanceUntil(s1, pos2); } } @@ -427,11 +463,11 @@ public static RoaringBitmap andNot(final RoaringBitmap x1, final RoaringBitmap x } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { final int nextPos1 = x1.highLowContainer.advanceUntil(s2, pos1); answer.highLowContainer.appendCopy(x1.highLowContainer, pos1, nextPos1); pos1 = nextPos1; - } else { + } else { pos2 = x2.highLowContainer.advanceUntil(s1, pos2); } } @@ -455,10 +491,10 @@ public void add(final int... dat) { /** * Set the specified values to true, within given boundaries. This can be expected to be slightly - * faster than calling "add" repeatedly on the values dat[offset], dat[offset+1],..., - * dat[offset+n-1]. - * The provided integers values don't have to be in sorted order, but it may be preferable - * to sort them from a performance point of view. + * faster than calling "add" repeatedly on the values dat[offset], dat[offset+1],..., + * dat[offset+n-1]. + * The provided integers values don't have to be in sorted order, but it may be preferable + * to sort them from a performance point of view. * * @param dat set values * @param offset from which index the values should be set to true @@ -466,13 +502,13 @@ public void add(final int... dat) { */ public void addN(final int[] dat, final int offset, final int n) { // let us validate the values first. - if((n < 0) || (offset < 0)) { + if ((n < 0) || (offset < 0)) { throw new IllegalArgumentException("Negative values do not make sense."); } - if(n == 0) { + if (n == 0) { return; // nothing to do } - if(offset + n > dat.length) { + if (offset + n > dat.length) { throw new IllegalArgumentException("Data source is too small."); } Container currentcont = null; @@ -483,24 +519,24 @@ public void addN(final int[] dat, final int offset, final int n) { if (currentcontainerindex >= 0) { currentcont = highLowContainer.getContainerAtIndex(currentcontainerindex); Container newcont = currentcont.add(Util.lowbits(val)); - if(newcont != currentcont) { + if (newcont != currentcont) { highLowContainer.setContainerAtIndex(currentcontainerindex, newcont); currentcont = newcont; } } else { - currentcontainerindex = - currentcontainerindex - 1; + currentcontainerindex = -currentcontainerindex - 1; final ArrayContainer newac = new ArrayContainer(); currentcont = newac.add(Util.lowbits(val)); highLowContainer.insertNewKeyValueAt(currentcontainerindex, currenthb, currentcont); } j++; - for( ; j < n; ++j) { + for (; j < n; ++j) { val = dat[j + offset]; char newhb = Util.highbits(val); - if(currenthb == newhb) {// easy case + if (currenthb == newhb) { // easy case // this could be quite frequent Container newcont = currentcont.add(Util.lowbits(val)); - if(newcont != currentcont) { + if (newcont != currentcont) { highLowContainer.setContainerAtIndex(currentcontainerindex, newcont); currentcont = newcont; } @@ -510,12 +546,12 @@ public void addN(final int[] dat, final int offset, final int n) { if (currentcontainerindex >= 0) { currentcont = highLowContainer.getContainerAtIndex(currentcontainerindex); Container newcont = currentcont.add(Util.lowbits(val)); - if(newcont != currentcont) { + if (newcont != currentcont) { highLowContainer.setContainerAtIndex(currentcontainerindex, newcont); currentcont = newcont; } } else { - currentcontainerindex = - currentcontainerindex - 1; + currentcontainerindex = -currentcontainerindex - 1; final ArrayContainer newac = new ArrayContainer(); currentcont = newac.add(Util.lowbits(val)); highLowContainer.insertNewKeyValueAt(currentcontainerindex, currenthb, currentcont); @@ -544,8 +580,8 @@ public static RoaringBitmap bitmapOf(final int... dat) { * @return a new bitmap */ public static RoaringBitmap bitmapOfUnordered(final int... data) { - RoaringBitmapWriter writer = writer().constantMemory() - .doPartialRadixSort().get(); + RoaringBitmapWriter writer = + writer().constantMemory().doPartialRadixSort().get(); writer.addMany(data); writer.flush(); return writer.getUnderlying(); @@ -555,8 +591,31 @@ public static RoaringBitmap bitmapOfUnordered(final int... data) { * @see #add(long, long) */ public static RoaringBitmap bitmapOfRange(long min, long max) { - RoaringBitmap bitmap = new RoaringBitmap(); - bitmap.add(min, max); + rangeSanityCheck(min, max); + if (min >= max) { + return new RoaringBitmap(); + } + final int hbStart = Util.highbits(min); + final int lbStart = Util.lowbits(min); + final int hbLast = Util.highbits(max - 1); + final int lbLast = Util.lowbits(max - 1); + + RoaringArray array = new RoaringArray(hbLast - hbStart + 1); + RoaringBitmap bitmap = new RoaringBitmap(array); + + int firstEnd = hbStart < hbLast ? 1 << 16 : lbLast + 1; + Container firstContainer = RunContainer.rangeOfOnes(lbStart, firstEnd); + bitmap.append((char) hbStart, firstContainer); + if (hbStart < hbLast) { + int i = hbStart + 1; + while (i < hbLast) { + Container runContainer = RunContainer.rangeOfOnes(0, 1 << 16); + bitmap.append((char) i, runContainer); + i++; + } + Container lastContainer = RunContainer.rangeOfOnes(0, lbLast + 1); + bitmap.append((char) hbLast, lastContainer); + } return bitmap; } @@ -600,8 +659,8 @@ public static RoaringBitmap flip(RoaringBitmap bm, final long rangeStart, final } else { // *think* the range of ones must never be // empty. - answer.highLowContainer.insertNewKeyValueAt(-j - 1, (char) hb, - Container.rangeOfOnes(containerStart, containerLast + 1)); + answer.highLowContainer.insertNewKeyValueAt( + -j - 1, (char) hb, Container.rangeOfOnes(containerStart, containerLast + 1)); } } // copy the containers after the active area. @@ -629,10 +688,6 @@ public static RoaringBitmap flip(RoaringBitmap rb, final int rangeStart, final i return flip(rb, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - - - - /** * Checks whether the two bitmaps intersect. This can be much faster than calling "and" and * checking the cardinality of the result. @@ -656,29 +711,32 @@ public static boolean intersects(final RoaringBitmap x1, final RoaringBitmap x2) } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = x1.highLowContainer.advanceUntil(s2, pos1); - } else { + } else { pos2 = x2.highLowContainer.advanceUntil(s1, pos2); } } return false; } - // important: inputs should not have been computed lazily protected static RoaringBitmap lazyor(final RoaringBitmap x1, final RoaringBitmap x2) { final RoaringBitmap answer = new RoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = x1.highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - answer.highLowContainer.append(s1, x1.highLowContainer.getContainerAtIndex(pos1) - .lazyOR(x2.highLowContainer.getContainerAtIndex(pos2))); + answer.highLowContainer.append( + s1, + x1.highLowContainer + .getContainerAtIndex(pos1) + .lazyOR(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -686,14 +744,14 @@ protected static RoaringBitmap lazyor(final RoaringBitmap x1, final RoaringBitma } s1 = x1.highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { answer.highLowContainer.appendCopy(x1.highLowContainer, pos1); pos1++; if (pos1 == length1) { break main; } s1 = x1.highLowContainer.getKeyAtIndex(pos1); - } else { + } else { answer.highLowContainer.appendCopy(x2.highLowContainer, pos2); pos2++; if (pos2 == length2) { @@ -712,12 +770,13 @@ protected static RoaringBitmap lazyor(final RoaringBitmap x1, final RoaringBitma } // important: inputs should not be reused - protected static RoaringBitmap lazyorfromlazyinputs(final RoaringBitmap x1, - final RoaringBitmap x2) { + protected static RoaringBitmap lazyorfromlazyinputs( + final RoaringBitmap x1, final RoaringBitmap x2) { final RoaringBitmap answer = new RoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = x1.highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); @@ -738,7 +797,7 @@ protected static RoaringBitmap lazyorfromlazyinputs(final RoaringBitmap x1, } s1 = x1.highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { Container c1 = x1.highLowContainer.getContainerAtIndex(pos1); answer.highLowContainer.append(s1, c1); pos1++; @@ -746,9 +805,9 @@ protected static RoaringBitmap lazyorfromlazyinputs(final RoaringBitmap x1, break main; } s1 = x1.highLowContainer.getKeyAtIndex(pos1); - } else { + } else { Container c2 = x2.highLowContainer.getContainerAtIndex(pos2); - answer.highLowContainer.append(s2,c2); + answer.highLowContainer.append(s2, c2); pos2++; if (pos2 == length2) { break main; @@ -765,7 +824,6 @@ protected static RoaringBitmap lazyorfromlazyinputs(final RoaringBitmap x1, return answer; } - /** * Compute overall OR between bitmaps. * @@ -807,14 +865,18 @@ public static RoaringBitmap or(final RoaringBitmap x1, final RoaringBitmap x2) { final RoaringBitmap answer = new RoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = x1.highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - answer.highLowContainer.append(s1, x1.highLowContainer.getContainerAtIndex(pos1) - .or(x2.highLowContainer.getContainerAtIndex(pos2))); + answer.highLowContainer.append( + s1, + x1.highLowContainer + .getContainerAtIndex(pos1) + .or(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -822,14 +884,14 @@ public static RoaringBitmap or(final RoaringBitmap x1, final RoaringBitmap x2) { } s1 = x1.highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { answer.highLowContainer.appendCopy(x1.highLowContainer, pos1); pos1++; if (pos1 == length1) { break main; } s1 = x1.highLowContainer.getKeyAtIndex(pos1); - } else { + } else { answer.highLowContainer.appendCopy(x2.highLowContainer, pos2); pos2++; if (pos2 == length2) { @@ -927,7 +989,7 @@ public static int andNotCardinality(final RoaringBitmap x1, final RoaringBitmap ++pos1; } } - return (int)cardinality; + return (int) cardinality; } /** @@ -944,7 +1006,6 @@ public static RoaringBitmap remove(RoaringBitmap rb, final long rangeStart, fina return rb.clone(); // empty range } - final int hbStart = (Util.highbits(rangeStart)); final int lbStart = (Util.lowbits(rangeStart)); final int hbLast = (Util.highbits(rangeEnd - 1)); @@ -966,8 +1027,10 @@ public static RoaringBitmap remove(RoaringBitmap rb, final long rangeStart, fina int ifirst = rb.highLowContainer.getIndex((char) hbStart); int ilast = rb.highLowContainer.getIndex((char) hbLast); if ((ifirst >= 0) && (lbStart != 0)) { - final Container c = rb.highLowContainer.getContainerAtIndex(ifirst).remove(lbStart, - Util.maxLowBitAsInteger() + 1); + final Container c = + rb.highLowContainer + .getContainerAtIndex(ifirst) + .remove(lbStart, Util.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { answer.highLowContainer.append((char) hbStart, c); } @@ -1001,7 +1064,6 @@ public static RoaringBitmap remove(RoaringBitmap rb, final int rangeStart, final return remove(rb, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - /** * Bitwise XOR (symmetric difference) operation. The provided bitmaps are *not* modified. This * operation is thread-safe as long as the provided bitmaps remain unchanged. @@ -1019,14 +1081,17 @@ public static RoaringBitmap xor(final RoaringBitmap x1, final RoaringBitmap x2) int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = x1.highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - final Container c = x1.highLowContainer.getContainerAtIndex(pos1) - .xor(x2.highLowContainer.getContainerAtIndex(pos2)); + final Container c = + x1.highLowContainer + .getContainerAtIndex(pos1) + .xor(x2.highLowContainer.getContainerAtIndex(pos2)); if (!c.isEmpty()) { answer.highLowContainer.append(s1, c); } @@ -1037,14 +1102,14 @@ public static RoaringBitmap xor(final RoaringBitmap x1, final RoaringBitmap x2) } s1 = x1.highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { answer.highLowContainer.appendCopy(x1.highLowContainer, pos1); pos1++; if (pos1 == length1) { break main; } s1 = x1.highLowContainer.getKeyAtIndex(pos1); - } else { + } else { answer.highLowContainer.appendCopy(x2.highLowContainer, pos2); pos2++; if (pos2 == length2) { @@ -1072,7 +1137,6 @@ public RoaringBitmap() { highLowContainer = new RoaringArray(); } - /** * Wrap an existing high low container */ @@ -1109,15 +1173,14 @@ public void add(final int x) { final char hb = Util.highbits(x); final int i = highLowContainer.getIndex(hb); if (i >= 0) { - highLowContainer.setContainerAtIndex(i, - highLowContainer.getContainerAtIndex(i).add(Util.lowbits(x))); + highLowContainer.setContainerAtIndex( + i, highLowContainer.getContainerAtIndex(i).add(Util.lowbits(x))); } else { final ArrayContainer newac = new ArrayContainer(); highLowContainer.insertNewKeyValueAt(-i - 1, hb, newac.add(Util.lowbits(x))); } } - /** * Add to the current bitmap all integers in [rangeStart,rangeEnd). * @@ -1147,8 +1210,8 @@ public void add(final long rangeStart, final long rangeEnd) { highLowContainer.getContainerAtIndex(i).iadd(containerStart, containerLast + 1); highLowContainer.setContainerAtIndex(i, c); } else { - highLowContainer.insertNewKeyValueAt(-i - 1, (char) hb, - Container.rangeOfOnes(containerStart, containerLast + 1)); + highLowContainer.insertNewKeyValueAt( + -i - 1, (char) hb, Container.rangeOfOnes(containerStart, containerLast + 1)); } } } @@ -1170,7 +1233,6 @@ public void add(final int rangeStart, final int rangeEnd) { add(rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - /** * Checks if the range intersects with the bitmap. * @param minimum the inclusive unsigned lower bound of the range @@ -1182,12 +1244,12 @@ public boolean intersects(long minimum, long supremum) { if (supremum <= minimum) { return false; } - int minKey = (int)(minimum >>> 16); - int supKey = (int)(supremum >>> 16); + int minKey = (int) (minimum >>> 16); + int supKey = (int) (supremum >>> 16); int length = highLowContainer.size; char[] keys = highLowContainer.keys; int limit = lowbitsAsInteger(supremum); - int index = Util.unsignedBinarySearch(keys, 0, length, (char)minKey); + int index = Util.unsignedBinarySearch(keys, 0, length, (char) minKey); int pos = index >= 0 ? index : -index - 1; int offset = index >= 0 ? lowbitsAsInteger(minimum) : 0; if (pos < length && supKey == (keys[pos])) { @@ -1204,19 +1266,20 @@ public boolean intersects(long minimum, long supremum) { offset = 0; ++pos; } - return pos < length && supKey == keys[pos] - && highLowContainer.getContainerAtIndex(pos) - .intersects(offset, limit); + return pos < length + && supKey == keys[pos] + && highLowContainer.getContainerAtIndex(pos).intersects(offset, limit); } - /** * In-place bitwise AND (intersection) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void and(final RoaringBitmap x2) { - if(x2 == this) { return; } + if (x2 == this) { + return; + } int pos1 = 0, pos2 = 0, intersectionSize = 0; final int length1 = highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -1232,16 +1295,15 @@ public void and(final RoaringBitmap x2) { } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = highLowContainer.advanceUntil(s2, pos1); - } else { + } else { pos2 = x2.highLowContainer.advanceUntil(s1, pos2); } } highLowContainer.resize(intersectionSize); } - /** * Computes AND between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd * (exclusive) @@ -1251,8 +1313,8 @@ public void and(final RoaringBitmap x2) { * @param rangeEnd exclusive ending of range * @return new result bitmap */ - public static RoaringBitmap and(final Iterator bitmaps, - final long rangeStart, final long rangeEnd) { + public static RoaringBitmap and( + final Iterator bitmaps, final long rangeStart, final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); Iterator bitmapsIterator; @@ -1276,21 +1338,18 @@ public static RoaringBitmap and(final Iterator bitmaps, * @deprecated use the version where longs specify the range. Negative range end are illegal. */ @Deprecated - public static RoaringBitmap and(final Iterator bitmaps, - final int rangeStart, final int rangeEnd) { + public static RoaringBitmap and( + final Iterator bitmaps, final int rangeStart, final int rangeEnd) { return and(bitmaps, (long) rangeStart, (long) rangeEnd); } - - - /** * In-place bitwise ANDNOT (difference) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void andNot(final RoaringBitmap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -1309,14 +1368,14 @@ public void andNot(final RoaringBitmap x2) { } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { if (pos1 != intersectionSize) { final Container c1 = highLowContainer.getContainerAtIndex(pos1); highLowContainer.replaceKeyAndContainerAtIndex(intersectionSize, s1, c1); } ++intersectionSize; ++pos1; - } else { + } else { pos2 = x2.highLowContainer.advanceUntil(s1, pos2); } } @@ -1327,7 +1386,6 @@ public void andNot(final RoaringBitmap x2) { highLowContainer.resize(intersectionSize); } - /** * Bitwise ANDNOT (difference) operation for the given range, rangeStart (inclusive) and rangeEnd * (exclusive). The provided bitmaps are *not* modified. This operation is thread-safe as long as @@ -1339,8 +1397,8 @@ public void andNot(final RoaringBitmap x2) { * @param rangeEnd end point of the range (exclusive) * @return result of the operation */ - public static RoaringBitmap andNot(final RoaringBitmap x1, final RoaringBitmap x2, - long rangeStart, long rangeEnd) { + public static RoaringBitmap andNot( + final RoaringBitmap x1, final RoaringBitmap x2, long rangeStart, long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); RoaringBitmap rb1 = selectRangeWithoutCopy(x1, rangeStart, rangeEnd); @@ -1363,8 +1421,8 @@ public static RoaringBitmap andNot(final RoaringBitmap x1, final RoaringBitmap x * endpoints are not allowed. */ @Deprecated - public static RoaringBitmap andNot(final RoaringBitmap x1, final RoaringBitmap x2, - final int rangeStart, final int rangeEnd) { + public static RoaringBitmap andNot( + final RoaringBitmap x1, final RoaringBitmap x2, final int rangeStart, final int rangeEnd) { return andNot(x1, x2, (long) rangeStart, (long) rangeEnd); } @@ -1375,21 +1433,19 @@ public static RoaringBitmap andNot(final RoaringBitmap x1, final RoaringBitmap x * @param rangeEnd end point of the range (exclusive). */ public void orNot(final RoaringBitmap other, long rangeEnd) { - if(other == this) { + if (other == this) { throw new UnsupportedOperationException("orNot between a bitmap and itself?"); } rangeSanityCheck(0, rangeEnd); - int maxKey = (int)((rangeEnd - 1) >>> 16); - int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int)(rangeEnd & 0xFFFF); + int maxKey = (int) ((rangeEnd - 1) >>> 16); + int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int) (rangeEnd & 0xFFFF); int size = 0; int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(), length2 = other.highLowContainer.size(); int s1 = length1 > 0 ? highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; int s2 = length2 > 0 ? other.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; int remainder = 0; - for (int i = highLowContainer.size - 1; - i >= 0 && highLowContainer.keys[i] > maxKey; - --i) { + for (int i = highLowContainer.size - 1; i >= 0 && highLowContainer.keys[i] > maxKey; --i) { ++remainder; } int correction = 0; @@ -1409,44 +1465,51 @@ public void orNot(final RoaringBitmap other, long rangeEnd) { Container[] newValues = new Container[maxSize]; for (int key = 0; key <= maxKey && size < maxSize; ++key) { if (key == s1 && key == s2) { // actually need to do an or not - newValues[size] = highLowContainer.getContainerAtIndex(pos1) - .iorNot(other.highLowContainer.getContainerAtIndex(pos2), - key == maxKey ? lastRun : 0x10000); + newValues[size] = + highLowContainer + .getContainerAtIndex(pos1) + .iorNot( + other.highLowContainer.getContainerAtIndex(pos2), + key == maxKey ? lastRun : 0x10000); ++pos1; ++pos2; s1 = pos1 < length1 ? highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; s2 = pos2 < length2 ? other.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else if (key == s1) { // or in a hole - newValues[size] = highLowContainer.getContainerAtIndex(pos1) - .ior(key == maxKey - ? RunContainer.rangeOfOnes(0, lastRun) - : RunContainer.full()); + newValues[size] = + key == maxKey + ? highLowContainer + .getContainerAtIndex(pos1) + .ior(RunContainer.rangeOfOnes(0, lastRun)) + : RunContainer.full(); ++pos1; s1 = pos1 < length1 ? highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; } else if (key == s2) { // insert the complement - newValues[size] = other.highLowContainer.getContainerAtIndex(pos2) + newValues[size] = + other + .highLowContainer + .getContainerAtIndex(pos2) .not(0, key == maxKey ? lastRun : 0x10000); ++pos2; s2 = pos2 < length2 ? other.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else { // key missing from both - newValues[size] = key == maxKey - ? RunContainer.rangeOfOnes(0, lastRun) - : RunContainer.full(); + newValues[size] = + key == maxKey ? RunContainer.rangeOfOnes(0, lastRun) : RunContainer.full(); } // might have appended an empty container (rare case) if (newValues[size].isEmpty()) { newValues[size] = null; } else { - newKeys[size] = (char)key; + newKeys[size] = (char) key; ++size; } } // copy over everything which will remain without being complemented if (remainder > 0) { - System.arraycopy(highLowContainer.keys, highLowContainer.size - remainder, - newKeys, size, remainder); - System.arraycopy(highLowContainer.values, highLowContainer.size - remainder, - newValues, size, remainder); + System.arraycopy( + highLowContainer.keys, highLowContainer.size - remainder, newKeys, size, remainder); + System.arraycopy( + highLowContainer.values, highLowContainer.size - remainder, newValues, size, remainder); } highLowContainer.keys = newKeys; highLowContainer.values = newValues; @@ -1464,11 +1527,10 @@ public void orNot(final RoaringBitmap other, long rangeEnd) { * @param rangeEnd end point of the range (exclusive) * @return result of the operation */ - public static RoaringBitmap orNot( - final RoaringBitmap x1, final RoaringBitmap x2, long rangeEnd) { + public static RoaringBitmap orNot(final RoaringBitmap x1, final RoaringBitmap x2, long rangeEnd) { rangeSanityCheck(0, rangeEnd); - int maxKey = (int)((rangeEnd - 1) >>> 16); - int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int)(rangeEnd & 0xFFFF); + int maxKey = (int) ((rangeEnd - 1) >>> 16); + int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int) (rangeEnd & 0xFFFF); int size = 0; int pos1 = 0, pos2 = 0; int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -1476,8 +1538,8 @@ public static RoaringBitmap orNot( int s2 = length2 > 0 ? x2.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; int remainder = 0; for (int i = x1.highLowContainer.size - 1; - i >= 0 && x1.highLowContainer.keys[i] > maxKey; - --i) { + i >= 0 && x1.highLowContainer.keys[i] > maxKey; + --i) { ++remainder; } int correction = 0; @@ -1497,43 +1559,51 @@ public static RoaringBitmap orNot( Container[] newValues = new Container[maxSize]; for (int key = 0; key <= maxKey && size < maxSize; ++key) { if (key == s1 && key == s2) { // actually need to do an or not - newValues[size] = x1.highLowContainer.getContainerAtIndex(pos1) - .orNot(x2.highLowContainer.getContainerAtIndex(pos2), - key == maxKey ? lastRun : 0x10000); + newValues[size] = + x1.highLowContainer + .getContainerAtIndex(pos1) + .orNot( + x2.highLowContainer.getContainerAtIndex(pos2), + key == maxKey ? lastRun : 0x10000); ++pos1; ++pos2; s1 = pos1 < length1 ? x1.highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; s2 = pos2 < length2 ? x2.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else if (key == s1) { // or in a hole - newValues[size] = x1.highLowContainer.getContainerAtIndex(pos1) - .ior(key == maxKey - ? RunContainer.rangeOfOnes(0, lastRun) - : RunContainer.full()); + newValues[size] = + key == maxKey + ? x1.highLowContainer + .getContainerAtIndex(pos1) + .ior(RunContainer.rangeOfOnes(0, lastRun)) + : RunContainer.full(); ++pos1; s1 = pos1 < length1 ? x1.highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; } else if (key == s2) { // insert the complement - newValues[size] = x2.highLowContainer.getContainerAtIndex(pos2) - .not(0, key == maxKey ? lastRun : 0x10000); + newValues[size] = + x2.highLowContainer.getContainerAtIndex(pos2).not(0, key == maxKey ? lastRun : 0x10000); ++pos2; s2 = pos2 < length2 ? x2.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else { // key missing from both - newValues[size] = key == maxKey - ? RunContainer.rangeOfOnes(0, lastRun) - : RunContainer.full(); + newValues[size] = + key == maxKey ? RunContainer.rangeOfOnes(0, lastRun) : RunContainer.full(); } // might have appended an empty container (rare case) if (newValues[size].isEmpty()) { newValues[size] = null; } else { - newKeys[size++] = (char)key; + newKeys[size++] = (char) key; } } // copy over everything which will remain without being complemented if (remainder > 0) { - System.arraycopy(x1.highLowContainer.keys, x1.highLowContainer.size - remainder, - newKeys, size, remainder); - System.arraycopy(x1.highLowContainer.values, x1.highLowContainer.size - remainder, - newValues, size, remainder); + System.arraycopy( + x1.highLowContainer.keys, x1.highLowContainer.size - remainder, newKeys, size, remainder); + System.arraycopy( + x1.highLowContainer.values, + x1.highLowContainer.size - remainder, + newValues, + size, + remainder); for (int i = size; i < size + remainder; ++i) { newValues[i] = newValues[i].clone(); } @@ -1545,8 +1615,6 @@ public static RoaringBitmap orNot( return result; } - - /** * Add the value to the container (set the value to "true"), whether it already appears or not. * @@ -1558,13 +1626,22 @@ public boolean checkedAdd(final int x) { final int i = highLowContainer.getIndex(hb); if (i >= 0) { Container c = highLowContainer.getContainerAtIndex(i); - int oldCard = c.getCardinality(); // we need to keep the newContainer if a switch between containers type // occur, in order to get the new cardinality - Container newCont = c.add(Util.lowbits(x)); - highLowContainer.setContainerAtIndex(i, newCont); - if (newCont.getCardinality() > oldCard) { - return true; + Container newCont; + if (c instanceof RunContainer) { // do not compute cardinality + if (!c.contains(Util.lowbits(x))) { + newCont = c.add(Util.lowbits(x)); + highLowContainer.setContainerAtIndex(i, newCont); + return true; + } + } else { // it is faster to use getCardinality() than contains() for other container types + int oldCard = c.getCardinality(); + newCont = c.add(Util.lowbits(x)); + highLowContainer.setContainerAtIndex(i, newCont); + if (newCont.getCardinality() > oldCard) { + return true; + } } } else { final ArrayContainer newac = new ArrayContainer(); @@ -1629,8 +1706,12 @@ public RoaringBitmap clone() { @Override public boolean contains(final int x) { final char hb = Util.highbits(x); - final Container c = highLowContainer.getContainer(hb); - return c != null && c.contains(Util.lowbits(x)); + int index = highLowContainer.getContainerIndex(hb); + if (index < 0) { + return false; + } + final Container c = highLowContainer.getContainerAtIndex(index); + return c.contains(Util.lowbits(x)); } /** @@ -1653,21 +1734,21 @@ public boolean contains(long minimum, long supremum) { } int begin = highLowContainer.getIndex(firstKey); int end = highLowContainer.getIndex(lastKey); - end = end < 0 ? -end -1 : end; + end = end < 0 ? -end - 1 : end; if (begin < 0 || end - begin != span) { return false; } - int min = (char)minimum; - int sup = (char)supremum; + int min = (char) minimum; + int sup = (char) supremum; if (firstKey == lastKey) { - return highLowContainer.getContainerAtIndex(begin) - .contains(min, (supremum & 0xFFFF) == 0 ? 0x10000 : sup); + return highLowContainer + .getContainerAtIndex(begin) + .contains(min, (supremum & 0xFFFF) == 0 ? 0x10000 : sup); } if (!highLowContainer.getContainerAtIndex(begin).contains(min, 1 << 16)) { return false; } - if (sup != 0 && end < len && !highLowContainer.getContainerAtIndex(end) - .contains(0, sup)) { + if (sup != 0 && end < len && !highLowContainer.getContainerAtIndex(end).contains(0, sup)) { return false; } for (int i = begin + 1; i < end; ++i) { @@ -1678,7 +1759,6 @@ public boolean contains(long minimum, long supremum) { return true; } - /** * Deserialize (retrieve) this bitmap. See format specification at * https://github.com/RoaringBitmap/RoaringFormatSpec @@ -1695,8 +1775,8 @@ public boolean contains(long minimum, long supremum) { public void deserialize(DataInput in, byte[] buffer) throws IOException { try { this.highLowContainer.deserialize(in, buffer); - } catch(InvalidRoaringFormat cookie) { - throw cookie.toIOException();// we convert it to an IOException + } catch (InvalidRoaringFormat cookie) { + throw cookie.toIOException(); // we convert it to an IOException } } @@ -1712,8 +1792,8 @@ public void deserialize(DataInput in, byte[] buffer) throws IOException { public void deserialize(DataInput in) throws IOException { try { this.highLowContainer.deserialize(in); - } catch(InvalidRoaringFormat cookie) { - throw cookie.toIOException();// we convert it to an IOException + } catch (InvalidRoaringFormat cookie) { + throw cookie.toIOException(); // we convert it to an IOException } } @@ -1738,8 +1818,8 @@ public void deserialize(DataInput in) throws IOException { public void deserialize(ByteBuffer bbf) throws IOException { try { this.highLowContainer.deserialize(bbf); - } catch(InvalidRoaringFormat cookie) { - throw cookie.toIOException();// we convert it to an IOException + } catch (InvalidRoaringFormat cookie) { + throw cookie.toIOException(); // we convert it to an IOException } } @@ -1767,16 +1847,16 @@ public boolean isHammingSimilar(RoaringBitmap other, int tolerance) { int pos1 = 0; int pos2 = 0; int budget = tolerance; - while(budget >= 0 && pos1 < size1 && pos2 < size2) { + while (budget >= 0 && pos1 < size1 && pos2 < size2) { final char key1 = this.highLowContainer.getKeyAtIndex(pos1); final char key2 = other.highLowContainer.getKeyAtIndex(pos2); Container left = highLowContainer.getContainerAtIndex(pos1); Container right = other.highLowContainer.getContainerAtIndex(pos2); - if(key1 == key2) { + if (key1 == key2) { budget -= left.xorCardinality(right); ++pos1; ++pos2; - } else if(key1 < key2) { + } else if (key1 < key2) { budget -= left.getCardinality(); ++pos1; } else { @@ -1784,11 +1864,11 @@ public boolean isHammingSimilar(RoaringBitmap other, int tolerance) { ++pos2; } } - while(budget >= 0 && pos1 < size1) { + while (budget >= 0 && pos1 < size1) { Container container = highLowContainer.getContainerAtIndex(pos1++); budget -= container.getCardinality(); } - while(budget >= 0 && pos2 < size2) { + while (budget >= 0 && pos2 < size2) { Container container = other.highLowContainer.getContainerAtIndex(pos2++); budget -= container.getCardinality(); } @@ -1851,14 +1931,13 @@ public void flip(final long rangeStart, final long rangeEnd) { highLowContainer.removeAtIndex(i); } } else { - highLowContainer.insertNewKeyValueAt(-i - 1, (char) hb, - Container.rangeOfOnes(containerStart, containerLast + 1)); + highLowContainer.insertNewKeyValueAt( + -i - 1, (char) hb, Container.rangeOfOnes(containerStart, containerLast + 1)); } } } - - /** + /** * Modifies the current bitmap by complementing the bits in the given range, from rangeStart * (inclusive) rangeEnd (exclusive). * @@ -1877,10 +1956,6 @@ public void flip(final int rangeStart, final int rangeEnd) { } } - - - - /** * Returns the number of distinct integers added to the bitmap (e.g., number of bits set). * @@ -1942,18 +2017,21 @@ public void forAllInRange(int uStart, int length, final RelativeRangeConsumer rr final long endInclusiveL = startL + (long) (length - 1); if (endInclusiveL > LongUtils.MAX_UNSIGNED_INT) { final long remainingLength = LongUtils.MAX_UNSIGNED_INT - startL + 1L; - throw new IllegalArgumentException("Cannot read past the end of the unsigned integer range. " - + remainingLength + " values remaining; requested " + length); + throw new IllegalArgumentException( + "Cannot read past the end of the unsigned integer range. " + + remainingLength + + " values remaining; requested " + + length); } final int uEndInclusive = (int) endInclusiveL; - final char endHigh = Util.highbits(uEndInclusive); + final char endHigh = Util.highbits(uEndInclusive); int startIndex = highLowContainer.getContainerIndex(startHigh); startIndex = startIndex < 0 ? -startIndex - 1 : startIndex; int uFilledUntil = uStart; for (int containerIndex = startIndex; - containerIndex < highLowContainer.size(); - containerIndex++) { + containerIndex < highLowContainer.size(); + containerIndex++) { if (Integer.compareUnsigned(uEndInclusive, uFilledUntil) < 0) { // We are done, no need to look at the next container. return; @@ -1967,7 +2045,7 @@ public void forAllInRange(int uStart, int length, final RelativeRangeConsumer rr final int fillFromRelative = uFilledUntil - uStart; // This should always result in a non-negative number, since unsigned // `uFilledUntil >= uStart`. - assert(fillFromRelative >= 0); + assert (fillFromRelative >= 0); rrc.acceptAllAbsent(fillFromRelative, length); } return; @@ -1978,8 +2056,8 @@ public void forAllInRange(int uStart, int length, final RelativeRangeConsumer rr final int fillToRelative = uContainerStart - uStart; // These should always result in a non-negative number, since unsigned // `uFilledUntil >= uStart`. - assert(fillFromRelative >= 0); - assert(fillToRelative >= 0); + assert (fillFromRelative >= 0); + assert (fillToRelative >= 0); rrc.acceptAllAbsent(fillFromRelative, fillToRelative); uFilledUntil = uContainerStart; } @@ -1988,7 +2066,7 @@ public void forAllInRange(int uStart, int length, final RelativeRangeConsumer rr final int containerRangeStartOffset = uFilledUntil - uStart; // These should always result in a non-negative number, since unsigned // `uFilledUntil >= uStart`. - assert(containerRangeStartOffset >= 0); + assert (containerRangeStartOffset >= 0); final boolean startInContainer = Integer.compareUnsigned(uContainerStart, uStart) < 0; final boolean endInContainer = @@ -1999,31 +2077,28 @@ public void forAllInRange(int uStart, int length, final RelativeRangeConsumer rr final char containerRangeStart = LongUtils.lowPart(uStart); final int uEndExclusive = uEndInclusive + 1; // This block should only be entered when this addition is legal. - assert(Integer.compareUnsigned(uEndInclusive, uEndExclusive) < 0); + assert (Integer.compareUnsigned(uEndInclusive, uEndExclusive) < 0); final char containerRangeEnd = LongUtils.lowPart(uEndExclusive); - container.forAllInRange( - containerRangeStart, - containerRangeEnd, - rrc); + container.forAllInRange(containerRangeStart, containerRangeEnd, rrc); return; - } else if (startInContainer) {// && !endInContainer + } else if (startInContainer) { // && !endInContainer // Range begins within the container. final char containerRangeStart = LongUtils.lowPart(uStart); container.forAllFrom(containerRangeStart, rrc); final int numValuesAdded = BitmapContainer.MAX_CAPACITY - (int) containerRangeStart; // Must be non-negative, since both are basically char-sized values. - assert(numValuesAdded >= 0); + assert (numValuesAdded >= 0); final int uOldFilledUntil = uFilledUntil; uFilledUntil += numValuesAdded; if (Integer.compareUnsigned(uFilledUntil, uOldFilledUntil) < 0) { // Wrapped the fill counter, so we must have completed the filling. return; } - } else if (endInContainer) {// && !startInContainer + } else if (endInContainer) { // && !startInContainer // Range ends within the container. final int uEndExclusive = uEndInclusive + 1; // This block should only be entered when this addition is legal. - assert(Integer.compareUnsigned(uEndInclusive, uEndExclusive) < 0); + assert (Integer.compareUnsigned(uEndInclusive, uEndExclusive) < 0); final char containerRangeEnd = LongUtils.lowPart(uEndExclusive); container.forAllUntil(containerRangeStartOffset, containerRangeEnd, rrc); return; @@ -2044,7 +2119,7 @@ public void forAllInRange(int uStart, int length, final RelativeRangeConsumer rr final int fillToRelative = length; // These should always result in a non-negative number, since unsigned // `uFilledUntil >= uStart`. - assert(fillFromRelative >= 0); + assert (fillFromRelative >= 0); rrc.acceptAllAbsent(fillFromRelative, fillToRelative); } } @@ -2060,7 +2135,6 @@ public void forEachInRange(int start, int length, final IntConsumer ic) { forAllInRange(start, length, new IntConsumerRelativeRangeAdapter(start, ic)); } - /** * Return a low-level container pointer that can be used to access the underlying data structure. * @@ -2070,18 +2144,27 @@ public ContainerPointer getContainerPointer() { return this.highLowContainer.getContainerPointer(); } - /** * - * For better performance, consider the Use the {@link #forEach forEach} method. + * For better performance, consider using the {@link #forEach forEach} method. * - * @return a custom iterator over set bits, the bits are traversed in ascending sorted order + * @return a custom iterator over set bits, the bits are traversed in unsigned integer ascending + * sorted order */ @Override public PeekableIntIterator getIntIterator() { return new RoaringIntIterator(); } + /** + * @return a custom iterator over set bits, the bits are traversed in signed integer ascending + * sorted order + */ + @Override + public PeekableIntIterator getSignedIntIterator() { + return new RoaringSignedIntIterator(); + } + /** * @return a custom iterator over set bits, the bits are traversed in descending sorted order */ @@ -2090,7 +2173,6 @@ public IntIterator getReverseIntIterator() { return new RoaringReverseIntIterator(); } - @Override public RoaringBatchIterator getBatchIterator() { return new RoaringBatchIterator(highLowContainer); @@ -2178,7 +2260,7 @@ public long getLongSizeInBytes() { */ @Override public int getSizeInBytes() { - return (int) getLongSizeInBytes() ; + return (int) getLongSizeInBytes(); } /** @@ -2199,7 +2281,6 @@ public int hashCode() { return highLowContainer.hashCode(); } - /** * Check whether this bitmap has had its runs compressed. * @@ -2225,7 +2306,6 @@ public boolean isEmpty() { return highLowContainer.size() == 0; } - /** * iterate over the positions of the true values. * @@ -2270,26 +2350,30 @@ public void remove() { // todo: implement throw new UnsupportedOperationException(); } - }.init(); } - // don't forget to call repairAfterLazy() afterward // important: x2 should not have been computed lazily protected void lazyor(final RoaringBitmap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - this.highLowContainer.setContainerAtIndex(pos1, highLowContainer.getContainerAtIndex(pos1) - .lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); + this.highLowContainer.setContainerAtIndex( + pos1, + highLowContainer + .getContainerAtIndex(pos1) + .lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -2297,15 +2381,15 @@ protected void lazyor(final RoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); - } else { - highLowContainer.insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + } else { + highLowContainer.insertNewKeyValueAt( + pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; @@ -2325,20 +2409,23 @@ protected void lazyor(final RoaringBitmap x2) { // important: x2 should not have been computed lazily // this method is like lazyor except that it will convert // the current container to a bitset - protected void naivelazyor(RoaringBitmap x2) { - if(this == x2) { return; } + protected void naivelazyor(RoaringBitmap x2) { + if (this == x2) { + return; + } int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { BitmapContainer c1 = highLowContainer.getContainerAtIndex(pos1).toBitmapContainer(); - this.highLowContainer.setContainerAtIndex(pos1, - c1.lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); + this.highLowContainer.setContainerAtIndex( + pos1, c1.lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -2346,15 +2433,15 @@ protected void naivelazyor(RoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); - } else { - highLowContainer.insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + } else { + highLowContainer.insertNewKeyValueAt( + pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; @@ -2380,8 +2467,9 @@ protected void naivelazyor(RoaringBitmap x2) { public RoaringBitmap limit(int maxcardinality) { RoaringBitmap answer = new RoaringBitmap(); int currentcardinality = 0; - for (int i = 0; (currentcardinality < maxcardinality) - && (i < this.highLowContainer.size()); i++) { + for (int i = 0; + (currentcardinality < maxcardinality) && (i < this.highLowContainer.size()); + i++) { Container c = this.highLowContainer.getContainerAtIndex(i); if (c.getCardinality() + currentcardinality <= maxcardinality) { answer.highLowContainer.appendCopy(this.highLowContainer, i); @@ -2402,18 +2490,24 @@ public RoaringBitmap limit(int maxcardinality) { * @param x2 other bitmap */ public void or(final RoaringBitmap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - this.highLowContainer.setContainerAtIndex(pos1, highLowContainer.getContainerAtIndex(pos1) - .ior(x2.highLowContainer.getContainerAtIndex(pos2))); + this.highLowContainer.setContainerAtIndex( + pos1, + highLowContainer + .getContainerAtIndex(pos1) + .ior(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -2421,15 +2515,15 @@ public void or(final RoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); - } else { - highLowContainer.insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + } else { + highLowContainer.insertNewKeyValueAt( + pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; @@ -2445,8 +2539,6 @@ public void or(final RoaringBitmap x2) { } } - - /** * Computes OR between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd * (exclusive) @@ -2456,8 +2548,8 @@ public void or(final RoaringBitmap x2) { * @param rangeEnd exclusive ending of range * @return new result bitmap */ - public static RoaringBitmap or(final Iterator bitmaps, - final long rangeStart, final long rangeEnd) { + public static RoaringBitmap or( + final Iterator bitmaps, final long rangeStart, final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); Iterator bitmapsIterator; @@ -2465,7 +2557,6 @@ public static RoaringBitmap or(final Iterator bitmaps, return or(bitmapsIterator); } - /** * Computes OR between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd * (exclusive) @@ -2477,12 +2568,11 @@ public static RoaringBitmap or(final Iterator bitmaps, * Negative range points are forbidden. */ @Deprecated - public static RoaringBitmap or(final Iterator bitmaps, - final int rangeStart, final int rangeEnd) { + public static RoaringBitmap or( + final Iterator bitmaps, final int rangeStart, final int rangeEnd) { return or(bitmaps, (long) rangeStart, (long) rangeEnd); } - /** * Rank returns the number of integers that are smaller or equal to x (Rank(infinity) would be * GetCardinality()). If you provide the smallest value as a parameter, this function will @@ -2511,19 +2601,20 @@ public long rankLong(int x) { @Override public long rangeCardinality(long start, long end) { - if(Long.compareUnsigned(start, end) >= 0) { + if (Long.compareUnsigned(start, end) >= 0) { return 0; } long size = 0; int startIndex = this.highLowContainer.getIndex(Util.highbits(start)); - if(startIndex < 0) { + if (startIndex < 0) { startIndex = -startIndex - 1; } else { int inContainerStart = (Util.lowbits(start)); - if(inContainerStart != 0) { - size -= this.highLowContainer - .getContainerAtIndex(startIndex) - .rank((char)(inContainerStart - 1)); + if (inContainerStart != 0) { + size -= + this.highLowContainer + .getContainerAtIndex(startIndex) + .rank((char) (inContainerStart - 1)); } } char xhigh = Util.highbits(end - 1); @@ -2532,15 +2623,13 @@ public long rangeCardinality(long start, long end) { if (key < xhigh) { size += this.highLowContainer.getContainerAtIndex(i).getCardinality(); } else if (key == xhigh) { - return size + this.highLowContainer - .getContainerAtIndex(i).rank(Util.lowbits((int)(end - 1))); + return size + + this.highLowContainer.getContainerAtIndex(i).rank(Util.lowbits((int) (end - 1))); } } return size; } - - @Override public int rank(int x) { return (int) rankLong(x); @@ -2563,8 +2652,8 @@ public void remove(final int x) { if (i < 0) { return; } - highLowContainer.setContainerAtIndex(i, - highLowContainer.getContainerAtIndex(i).remove(Util.lowbits(x))); + highLowContainer.setContainerAtIndex( + i, highLowContainer.getContainerAtIndex(i).remove(Util.lowbits(x))); if (highLowContainer.getContainerAtIndex(i).isEmpty()) { highLowContainer.removeAtIndex(i); } @@ -2584,7 +2673,6 @@ public void remove(final long rangeStart, final long rangeEnd) { return; // empty range } - final int hbStart = (Util.highbits(rangeStart)); final int lbStart = (Util.lowbits(rangeStart)); final int hbLast = (Util.highbits(rangeEnd - 1)); @@ -2606,8 +2694,10 @@ public void remove(final long rangeStart, final long rangeEnd) { int ilast = highLowContainer.getIndex((char) hbLast); if (ifirst >= 0) { if (lbStart != 0) { - final Container c = highLowContainer.getContainerAtIndex(ifirst).iremove(lbStart, - Util.maxLowBitAsInteger() + 1); + final Container c = + highLowContainer + .getContainerAtIndex(ifirst) + .iremove(lbStart, Util.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { highLowContainer.setContainerAtIndex(ifirst, c); ifirst++; @@ -2633,8 +2723,6 @@ public void remove(final long rangeStart, final long rangeEnd) { highLowContainer.removeIndexRange(ifirst, ilast); } - - /** * Remove from the current bitmap all integers in [rangeStart,rangeEnd). * @@ -2652,7 +2740,6 @@ public void remove(final int rangeStart, final int rangeEnd) { remove(rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - /** * Remove run-length encoding even when it is more space efficient * @@ -2711,7 +2798,7 @@ public boolean contains(RoaringBitmap subset) { if (s1 == s2) { Container c1 = this.highLowContainer.getContainerAtIndex(pos1); Container c2 = subset.highLowContainer.getContainerAtIndex(pos2); - if(!c1.contains(c2)) { + if (!c1.contains(c2)) { return false; } ++pos1; @@ -2725,7 +2812,6 @@ public boolean contains(RoaringBitmap subset) { return pos2 == length2; } - /** * Return the jth value stored in this bitmap. The provided value * needs to be smaller than the cardinality otherwise an @@ -2747,14 +2833,17 @@ public int select(int j) { int thiscard = c.getCardinality(); if (thiscard > leftover) { int keycontrib = this.highLowContainer.getKeyAtIndex(i) << 16; - int lowcontrib = (c.select((int)leftover)); + int lowcontrib = (c.select((int) leftover)); return lowcontrib + keycontrib; } leftover -= thiscard; } - throw new IllegalArgumentException("You are trying to select the " - + j + "th value when the cardinality is " - + this.getCardinality() + "."); + throw new IllegalArgumentException( + "You are trying to select the " + + j + + "th value when the cardinality is " + + this.getCardinality() + + "."); } @Override @@ -2765,7 +2854,8 @@ public long nextValue(int fromValue) { while (containerIndex < highLowContainer.size() && nextSetBit == -1L) { char containerKey = highLowContainer.getKeyAtIndex(containerIndex); Container container = highLowContainer.getContainerAtIndex(containerIndex); - int bit = (containerKey - key > 0 + int bit = + (containerKey - key > 0 ? container.first() : container.nextValue(Util.lowbits(fromValue))); nextSetBit = bit == -1 ? -1L : Util.toUnsignedLong((containerKey << 16) | bit); @@ -2784,16 +2874,18 @@ public long previousValue(int fromValue) { char key = Util.highbits(fromValue); int containerIndex = highLowContainer.advanceUntil(key, -1); if (containerIndex == highLowContainer.size()) { - return last(); + return Util.toUnsignedLong(last()); } if (highLowContainer.getKeyAtIndex(containerIndex) > key) { - return -1L; + // target absent, key of first container after target too high + --containerIndex; } long prevSetBit = -1L; while (containerIndex != -1 && prevSetBit == -1L) { char containerKey = highLowContainer.getKeyAtIndex(containerIndex); Container container = highLowContainer.getContainerAtIndex(containerIndex); - int bit = (containerKey < key + int bit = + (containerKey < key ? container.last() : container.previousValue(Util.lowbits(fromValue))); prevSetBit = bit == -1 ? -1L : Util.toUnsignedLong((containerKey << 16) | bit); @@ -2807,9 +2899,9 @@ public long previousValue(int fromValue) { @Override public long nextAbsentValue(int fromValue) { long nextAbsentBit = computeNextAbsentValue(fromValue); - assert nextAbsentBit <= 0xFFFFFFFFL; - assert nextAbsentBit >= Util.toUnsignedLong(fromValue); - assert !contains((int) nextAbsentBit); + if (nextAbsentBit == 0x100000000L) { + return -1L; + } return nextAbsentBit; } @@ -2900,6 +2992,16 @@ public int last() { return highLowContainer.last(); } + @Override + public int firstSigned() { + return highLowContainer.firstSigned(); + } + + @Override + public int lastSigned() { + return highLowContainer.lastSigned(); + } + /** * Serialize this bitmap. * @@ -2930,7 +3032,6 @@ public void serialize(ByteBuffer buffer) { highLowContainer.serialize(buffer); } - /** * Assume that one wants to store "cardinality" integers in [0, universe_size), this function * returns an upper bound on the serialized size in bytes. @@ -2972,31 +3073,98 @@ public int serializedSizeInBytes() { * @param rangeEnd exclusive * @return new iterator of bitmaps */ - private static Iterator selectRangeWithoutCopy(final - Iterator bitmaps, - final long rangeStart, final long rangeEnd) { + private static Iterator selectRangeWithoutCopy( + final Iterator bitmaps, final long rangeStart, final long rangeEnd) { Iterator bitmapsIterator; - bitmapsIterator = new Iterator() { - @Override - public boolean hasNext() { - return bitmaps.hasNext(); + bitmapsIterator = + new Iterator() { + @Override + public boolean hasNext() { + return bitmaps.hasNext(); + } + + @Override + public RoaringBitmap next() { + RoaringBitmap next = bitmaps.next(); + return selectRangeWithoutCopy(next, rangeStart, rangeEnd); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Remove not supported"); + } + }; + return bitmapsIterator; + } + + /** + * Creates a copy of the bitmap, limited to the values in the specified range, + * rangeStart (inclusive) and rangeEnd (exclusive). + * + * @param rangeStart inclusive + * @param rangeEnd exclusive + * @return new bitmap + */ + public RoaringBitmap selectRange(final long rangeStart, final long rangeEnd) { + final int hbStart = (Util.highbits(rangeStart)); + final int lbStart = (Util.lowbits(rangeStart)); + final int hbLast = (Util.highbits(rangeEnd - 1)); + final int lbLast = (Util.lowbits(rangeEnd - 1)); + RoaringBitmap answer = new RoaringBitmap(); + + assert (rangeStart >= 0 && rangeEnd >= 0); + + if (rangeEnd <= rangeStart) { + return answer; + } + + if (hbStart == hbLast) { + final int i = this.highLowContainer.getIndex((char) hbStart); + if (i >= 0) { + final Container c = + this.highLowContainer + .getContainerAtIndex(i) + .remove(0, lbStart) + .iremove(lbLast + 1, Util.maxLowBitAsInteger() + 1); + if (!c.isEmpty()) { + answer.highLowContainer.append((char) hbStart, c); + } + } + return answer; + } + int ifirst = this.highLowContainer.getIndex((char) hbStart); + int ilast = this.highLowContainer.getIndex((char) hbLast); + if (ifirst >= 0) { + final Container c = this.highLowContainer.getContainerAtIndex(ifirst).remove(0, lbStart); + if (!c.isEmpty()) { + answer.highLowContainer.append((char) hbStart, c.clone()); } + } - @Override - public RoaringBitmap next() { - RoaringBitmap next = bitmaps.next(); - return selectRangeWithoutCopy(next, rangeStart, rangeEnd); + // revised to loop on ints + for (int hb = hbStart + 1; hb <= hbLast - 1; ++hb) { + final int i = this.highLowContainer.getIndex((char) hb); + final int j = answer.highLowContainer.getIndex((char) hb); + assert j < 0; + + if (i >= 0) { + final Container c = this.highLowContainer.getContainerAtIndex(i); + answer.highLowContainer.insertNewKeyValueAt(-j - 1, (char) hb, c.clone()); } + } - @Override - public void remove() { - throw new UnsupportedOperationException("Remove not supported"); + if (ilast >= 0) { + final Container c = + this.highLowContainer + .getContainerAtIndex(ilast) + .remove(lbLast + 1, Util.maxLowBitAsInteger() + 1); + if (!c.isEmpty()) { + answer.highLowContainer.append((char) hbLast, c); } - }; - return bitmapsIterator; + } + return answer; } - /** * * Extracts the values in the specified range, rangeStart (inclusive) and rangeEnd (exclusive) @@ -3007,17 +3175,15 @@ public void remove() { * @param rangeEnd exclusive * @return new bitmap */ - - // had formerly failed if rangeEnd==0 - private static RoaringBitmap selectRangeWithoutCopy(RoaringBitmap rb, final long rangeStart, - final long rangeEnd) { + private static RoaringBitmap selectRangeWithoutCopy( + RoaringBitmap rb, final long rangeStart, final long rangeEnd) { final int hbStart = (Util.highbits(rangeStart)); final int lbStart = (Util.lowbits(rangeStart)); final int hbLast = (Util.highbits(rangeEnd - 1)); final int lbLast = (Util.lowbits(rangeEnd - 1)); RoaringBitmap answer = new RoaringBitmap(); - assert(rangeStart >= 0 && rangeEnd >= 0); + assert (rangeStart >= 0 && rangeEnd >= 0); if (rangeEnd <= rangeStart) { return answer; @@ -3026,8 +3192,11 @@ private static RoaringBitmap selectRangeWithoutCopy(RoaringBitmap rb, final long if (hbStart == hbLast) { final int i = rb.highLowContainer.getIndex((char) hbStart); if (i >= 0) { - final Container c = rb.highLowContainer.getContainerAtIndex(i).remove(0, lbStart) - .iremove(lbLast + 1, Util.maxLowBitAsInteger() + 1); + final Container c = + rb.highLowContainer + .getContainerAtIndex(i) + .remove(0, lbStart) + .iremove(lbLast + 1, Util.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { answer.highLowContainer.append((char) hbStart, c); } @@ -3045,19 +3214,21 @@ private static RoaringBitmap selectRangeWithoutCopy(RoaringBitmap rb, final long // revised to loop on ints for (int hb = hbStart + 1; hb <= hbLast - 1; ++hb) { - final int i = rb.highLowContainer.getIndex((char)hb); + final int i = rb.highLowContainer.getIndex((char) hb); final int j = answer.highLowContainer.getIndex((char) hb); assert j < 0; if (i >= 0) { final Container c = rb.highLowContainer.getContainerAtIndex(i); - answer.highLowContainer.insertNewKeyValueAt(-j - 1, (char)hb, c); + answer.highLowContainer.insertNewKeyValueAt(-j - 1, (char) hb, c); } } if (ilast >= 0) { - final Container c = rb.highLowContainer.getContainerAtIndex(ilast).remove(lbLast + 1, - Util.maxLowBitAsInteger() + 1); + final Container c = + rb.highLowContainer + .getContainerAtIndex(ilast) + .remove(lbLast + 1, Util.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { answer.highLowContainer.append((char) hbLast, c); } @@ -3065,7 +3236,6 @@ private static RoaringBitmap selectRangeWithoutCopy(RoaringBitmap rb, final long return answer; } - /** * Return the set values as an array, if the cardinality is smaller than 2147483648. * The integer values are in sorted order. @@ -3116,7 +3286,7 @@ public String toString() { while (i.hasNext()) { answer.append(','); // to avoid using too much memory, we limit the size - if(answer.length() > 0x80000) { + if (answer.length() > 0x80000) { answer.append('.').append('.').append('.'); break; } @@ -3134,7 +3304,6 @@ public void trim() { this.highLowContainer.trim(); } - @Override public void writeExternal(ObjectOutput out) throws IOException { this.highLowContainer.writeExternal(out); @@ -3146,7 +3315,7 @@ public void writeExternal(ObjectOutput out) throws IOException { * @param x2 other bitmap */ public void xor(final RoaringBitmap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -3154,14 +3323,17 @@ public void xor(final RoaringBitmap x2) { int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - final Container c = highLowContainer.getContainerAtIndex(pos1) - .ixor(x2.highLowContainer.getContainerAtIndex(pos2)); + final Container c = + highLowContainer + .getContainerAtIndex(pos1) + .ixor(x2.highLowContainer.getContainerAtIndex(pos2)); if (!c.isEmpty()) { this.highLowContainer.setContainerAtIndex(pos1, c); pos1++; @@ -3175,15 +3347,15 @@ public void xor(final RoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); - } else { - highLowContainer.insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + } else { + highLowContainer.insertNewKeyValueAt( + pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; @@ -3208,8 +3380,8 @@ public void xor(final RoaringBitmap x2) { * @param rangeEnd exclusive ending of range * @return new result bitmap */ - public static RoaringBitmap xor(final Iterator bitmaps, - final long rangeStart, final long rangeEnd) { + public static RoaringBitmap xor( + final Iterator bitmaps, final long rangeStart, final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); Iterator bitmapsIterator; bitmapsIterator = selectRangeWithoutCopy(bitmaps, rangeStart, rangeEnd); @@ -3228,10 +3400,18 @@ public static RoaringBitmap xor(final Iterator bitmaps, * Negative values not allowed for rangeStart and rangeEnd */ @Deprecated - public static RoaringBitmap xor(final Iterator bitmaps, - final int rangeStart, final int rangeEnd) { + public static RoaringBitmap xor( + final Iterator bitmaps, final int rangeStart, final int rangeEnd) { return xor(bitmaps, (long) rangeStart, (long) rangeEnd); } - + /** + * Returns the number of containers in the bitmap. + * + * @return the number of containers + */ + @Override + public int getContainerCount() { + return highLowContainer.size(); + } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapPrivate.java b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapPrivate.java similarity index 100% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapPrivate.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapPrivate.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapSupplier.java b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapSupplier.java similarity index 98% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapSupplier.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapSupplier.java index 59ae54d2f..d1cac33a1 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapSupplier.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapSupplier.java @@ -6,7 +6,7 @@ /** * A {@link BitmapDataProviderSupplier} providing {@link RoaringBitmap} as * {@link BitmapDataProvider} - * + * * @author Benoit Lacelle * */ @@ -16,5 +16,4 @@ public class RoaringBitmapSupplier implements BitmapDataProviderSupplier { public BitmapDataProvider newEmpty() { return new RoaringBitmap(); } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapWriter.java b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapWriter.java similarity index 92% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapWriter.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapWriter.java index f06ecc207..a04f290cc 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RoaringBitmapWriter.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RoaringBitmapWriter.java @@ -1,6 +1,10 @@ package org.roaringbitmap; -import org.roaringbitmap.buffer.*; +import org.roaringbitmap.buffer.MappeableArrayContainer; +import org.roaringbitmap.buffer.MappeableContainer; +import org.roaringbitmap.buffer.MappeableRunContainer; +import org.roaringbitmap.buffer.MutableRoaringArray; +import org.roaringbitmap.buffer.MutableRoaringBitmap; import java.util.function.Supplier; @@ -14,9 +18,9 @@ static Wizard bufferWriter() { return new BufferWizard(); } - abstract class Wizard, - T extends BitmapDataProvider & AppendableStorage> - implements Supplier> { + abstract class Wizard< + C extends WordStorage, T extends BitmapDataProvider & AppendableStorage> + implements Supplier> { protected int initialCapacity = RoaringArray.INITIAL_CAPACITY; protected boolean constantMemory; @@ -152,8 +156,8 @@ public Wizard doPartialRadixSort() { @Override public RoaringBitmapWriter get() { int capacity = initialCapacity; - return new ContainerAppender<>(partiallySortValues, runCompress, - () -> createUnderlying(capacity), containerSupplier); + return new ContainerAppender<>( + partiallySortValues, runCompress, () -> createUnderlying(capacity), containerSupplier); } private static void sanityCheck(int count) { @@ -208,7 +212,7 @@ public RoaringBitmapWriter get() { if (constantMemory) { int capacity = initialCapacity; return new ConstantMemoryContainerAppender<>( - partiallySortValues, runCompress, () -> createUnderlying(capacity)); + partiallySortValues, runCompress, () -> createUnderlying(capacity)); } return super.get(); } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RunBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/RunBatchIterator.java similarity index 74% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RunBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RunBatchIterator.java index 5aed07f95..64ee24404 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RunBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RunBatchIterator.java @@ -1,7 +1,5 @@ package org.roaringbitmap; - - public final class RunBatchIterator implements ContainerBatchIterator { private RunContainer runs; @@ -13,16 +11,17 @@ public RunBatchIterator(RunContainer runs) { } @Override - public int next(int key, int[] buffer) { + public int next(int key, int[] buffer, int offset) { int consumed = 0; do { int runStart = (runs.getValue(run)); int runLength = (runs.getLength(run)); int chunkStart = runStart + cursor; - int chunkEnd = chunkStart + Math.min(runLength - cursor, buffer.length - consumed - 1); + int usableBufferLength = buffer.length - offset - consumed; + int chunkEnd = chunkStart + Math.min(runLength - cursor, usableBufferLength - 1); int chunk = chunkEnd - chunkStart + 1; for (int i = 0; i < chunk; ++i) { - buffer[consumed + i] = key + chunkStart + i; + buffer[offset + consumed + i] = key + chunkStart + i; } consumed += chunk; if (runStart + runLength == chunkEnd) { @@ -31,7 +30,7 @@ public int next(int key, int[] buffer) { } else { cursor += chunk; } - } while (consumed < buffer.length && run != runs.numberOfRuns()); + } while ((offset + consumed) < buffer.length && run != runs.numberOfRuns()); return consumed; } @@ -43,7 +42,7 @@ public boolean hasNext() { @Override public ContainerBatchIterator clone() { try { - return (ContainerBatchIterator)super.clone(); + return (ContainerBatchIterator) super.clone(); } catch (CloneNotSupportedException e) { // won't happen throw new IllegalStateException(e); @@ -60,14 +59,15 @@ public void advanceIfNeeded(char target) { do { int runStart = runs.getValue(run); int runLength = runs.getLength(run); - if (runStart <= target && runStart + runLength > target) { - cursor = target - runStart; - break; - } if (runStart > target) { cursor = 0; break; } + int offset = target - runStart; + if (offset <= runLength) { + cursor = offset; + break; + } ++run; cursor = 0; } while (run != runs.numberOfRuns()); diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RunContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/RunContainer.java similarity index 91% rename from RoaringBitmap/src/main/java/org/roaringbitmap/RunContainer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/RunContainer.java index 5542ecfbb..9634c7d1e 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/RunContainer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/RunContainer.java @@ -6,14 +6,17 @@ import org.roaringbitmap.buffer.MappeableContainer; import org.roaringbitmap.buffer.MappeableRunContainer; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.util.Arrays; import java.util.Iterator; - /** * This container takes the form of runs of consecutive values (effectively, run-length encoding). * @@ -26,8 +29,8 @@ public final class RunContainer extends Container implements Cloneable { private static final long serialVersionUID = 1L; - private static int branchyUnsignedInterleavedBinarySearch(final char[] array, final int begin, - final int end, final char k) { + private static int branchyUnsignedInterleavedBinarySearch( + final char[] array, final int begin, final int end, final char k) { int low = begin; int high = end - 1; while (low <= high) { @@ -45,8 +48,8 @@ private static int branchyUnsignedInterleavedBinarySearch(final char[] array, fi } // starts with binary search and finishes with a sequential search - private static int hybridUnsignedInterleavedBinarySearch(final char[] array, final int begin, - final int end, final char k) { + private static int hybridUnsignedInterleavedBinarySearch( + final char[] array, final int begin, final int end, final char k) { int low = begin; int high = end - 1; // 16 in the next line matches the size of a cache line @@ -79,25 +82,23 @@ protected static int serializedSizeInBytes(int numberOfRuns) { return 2 + 2 * 2 * numberOfRuns; // each run requires 2 2-byte entries. } - private static int unsignedInterleavedBinarySearch(final char[] array, final int begin, - final int end, final char k) { + private static int unsignedInterleavedBinarySearch( + final char[] array, final int begin, final int end, final char k) { if (Util.USE_HYBRID_BINSEARCH) { return hybridUnsignedInterleavedBinarySearch(array, begin, end, k); } else { return branchyUnsignedInterleavedBinarySearch(array, begin, end, k); } - } - private char[] valueslength;// we interleave values and lengths, so + private char[] valueslength; // we interleave values and lengths, so // that if you have the values 11,12,13,14,15, you store that as 11,4 where 4 means that beyond 11 // itself, there are // 4 contiguous values that follows. // Other example: e.g., 1, 10, 20,0, 31,2 would be a concise representation of 1, 2, ..., 11, 20, // 31, 32, 33 - int nbrruns = 0;// how many runs, this number should fit in 16 bits. - + int nbrruns = 0; // how many runs, this number should fit in 16 bits. /** * Create a container with default capacity @@ -106,7 +107,6 @@ public RunContainer() { this(DEFAULT_INIT_SIZE); } - protected RunContainer(ArrayContainer arr, int nbrRuns) { this.nbrruns = nbrRuns; valueslength = new char[2 * nbrRuns]; @@ -143,7 +143,7 @@ protected RunContainer(ArrayContainer arr, int nbrRuns) { */ public RunContainer(final int firstOfRun, final int lastOfRun) { this.nbrruns = 1; - this.valueslength = new char[]{(char) firstOfRun, (char) (lastOfRun - 1 - firstOfRun)}; + this.valueslength = new char[] {(char) firstOfRun, (char) (lastOfRun - 1 - firstOfRun)}; } // convert a bitmap container to a run container somewhat efficiently. @@ -205,13 +205,11 @@ public RunContainer(final int capacity) { valueslength = new char[2 * capacity]; } - private RunContainer(int nbrruns, char[] valueslength) { this.nbrruns = nbrruns; this.valueslength = Arrays.copyOf(valueslength, valueslength.length); } - /** * Creates a new non-mappeable container from a mappeable one. This copies the data. * @@ -252,10 +250,10 @@ public Container add(char k) { // runOptimize int index = unsignedInterleavedBinarySearch(valueslength, 0, nbrruns, k); if (index >= 0) { - return this;// already there + return this; // already there } - index = -index - 2;// points to preceding value, possibly -1 - if (index >= 0) {// possible match + index = -index - 2; // points to preceding value, possibly -1 + if (index >= 0) { // possible match int offset = (k) - (getValue(index)); int le = (getLength(index)); if (offset <= le) { @@ -266,8 +264,7 @@ public Container add(char k) { if (index + 1 < nbrruns) { if ((getValue(index + 1)) == (k) + 1) { // indeed fusion is needed - setLength(index, - (char) (getValue(index + 1) + getLength(index + 1) - getValue(index))); + setLength(index, (char) (getValue(index + 1) + getLength(index + 1) - getValue(index))); recoverRoomAtIndex(index + 1); return this; } @@ -314,16 +311,16 @@ public Container and(ArrayContainer x) { int rlelength = (this.getLength(rlepos)); while (arraypos < x.cardinality) { int arrayval = (x.content[arraypos]); - while (rleval + rlelength < arrayval) {// this will frequently be false + while (rleval + rlelength < arrayval) { // this will frequently be false ++rlepos; if (rlepos == this.nbrruns) { - return ac;// we are done + return ac; // we are done } rleval = (this.getValue(rlepos)); rlelength = (this.getLength(rlepos)); } if (rleval > arrayval) { - arraypos = Util.advanceUntil(x.content, arraypos, x.cardinality, (char)rleval); + arraypos = Util.advanceUntil(x.content, arraypos, x.cardinality, (char) rleval); } else { ac.content[ac.cardinality] = (char) arrayval; ac.cardinality++; @@ -333,7 +330,6 @@ public Container and(ArrayContainer x) { return ac; } - @Override public Container and(BitmapContainer x) { // could be implemented as return toBitmapOrArrayContainer().iand(x); @@ -349,8 +345,8 @@ public Container and(BitmapContainer x) { int runStart = (this.getValue(rlepos)); int runEnd = runStart + (this.getLength(rlepos)); for (int runValue = runStart; runValue <= runEnd; ++runValue) { - if (x.contains((char) runValue)) {// it looks like contains() should be cheap enough if - // accessed sequentially + if (x.contains((char) runValue)) { // it looks like contains() should be cheap enough if + // accessed sequentially answer.content[answer.cardinality++] = (char) runValue; } } @@ -394,7 +390,7 @@ public Container and(RunContainer x) { if (end <= xstart) { if (ENABLE_GALLOPING_AND) { rlepos = skipAhead(this, rlepos, xstart); // skip over runs until we have end > xstart (or - // rlepos is advanced beyond end) + // rlepos is advanced beyond end) } else { ++rlepos; } @@ -415,10 +411,10 @@ public Container and(RunContainer x) { xstart = x.getValue(xrlepos); xend = xstart + x.getLength(xrlepos) + 1; } - } else {// they overlap + } else { // they overlap final int lateststart = Math.max(start, xstart); int earliestend; - if (end == xend) {// improbable + if (end == xend) { // improbable earliestend = end; rlepos++; xrlepos++; @@ -438,7 +434,7 @@ public Container and(RunContainer x) { end = start + this.getLength(rlepos) + 1; } - } else {// end > xend + } else { // end > xend earliestend = xend; xrlepos++; if (xrlepos < x.nbrruns) { @@ -452,7 +448,7 @@ public Container and(RunContainer x) { } } return answer.toEfficientContainer(); // subsequent trim() may be required to avoid wasted - // space. + // space. } @Override @@ -467,10 +463,10 @@ public int andCardinality(ArrayContainer x) { int rlelength = (this.getLength(rlepos)); while (arraypos < x.cardinality) { int arrayval = (x.content[arraypos]); - while (rleval + rlelength < arrayval) {// this will frequently be false + while (rleval + rlelength < arrayval) { // this will frequently be false ++rlepos; if (rlepos == this.nbrruns) { - return andCardinality;// we are done + return andCardinality; // we are done } rleval = (this.getValue(rlepos)); rlelength = (this.getLength(rlepos)); @@ -485,7 +481,6 @@ public int andCardinality(ArrayContainer x) { return andCardinality; } - @Override public int andCardinality(BitmapContainer x) { // could be implemented as return toBitmapOrArrayContainer().iand(x); @@ -511,7 +506,7 @@ public int andCardinality(RunContainer x) { if (end <= xstart) { if (ENABLE_GALLOPING_AND) { rlepos = skipAhead(this, rlepos, xstart); // skip over runs until we have end > xstart (or - // rlepos is advanced beyond end) + // rlepos is advanced beyond end) } else { ++rlepos; } @@ -532,10 +527,10 @@ public int andCardinality(RunContainer x) { xstart = (x.getValue(xrlepos)); xend = xstart + (x.getLength(xrlepos)) + 1; } - } else {// they overlap + } else { // they overlap final int lateststart = Math.max(start, xstart); int earliestend; - if (end == xend) {// improbable + if (end == xend) { // improbable earliestend = end; rlepos++; xrlepos++; @@ -555,7 +550,7 @@ public int andCardinality(RunContainer x) { end = start + (this.getLength(rlepos)) + 1; } - } else {// end > xend + } else { // end > xend earliestend = xend; xrlepos++; if (xrlepos < x.nbrruns) { @@ -602,8 +597,8 @@ public Container andNot(BitmapContainer x) { int runStart = (this.getValue(rlepos)); int runEnd = runStart + (this.getLength(rlepos)); for (int runValue = runStart; runValue <= runEnd; ++runValue) { - if (!x.contains((char) runValue)) {// it looks like contains() should be cheap enough if - // accessed sequentially + if (!x.contains((char) runValue)) { // it looks like contains() should be cheap enough if + // accessed sequentially answer.content[answer.cardinality++] = (char) runValue; } } @@ -683,7 +678,11 @@ public Container andNot(RunContainer x) { answer.nbrruns++; rlepos++; if (rlepos < this.nbrruns) { - System.arraycopy(this.valueslength, 2 * rlepos, answer.valueslength, 2 * answer.nbrruns, + System.arraycopy( + this.valueslength, + 2 * rlepos, + answer.valueslength, + 2 * answer.nbrruns, 2 * (this.nbrruns - rlepos)); answer.nbrruns = answer.nbrruns + this.nbrruns - rlepos; } @@ -738,7 +737,7 @@ public boolean contains(char x) { return true; } index = -index - 2; // points to preceding value, possibly -1 - if (index != -1) {// possible match + if (index != -1) { // possible match int offset = x - getValue(index); int le = getLength(index); return offset <= le; @@ -765,17 +764,17 @@ public boolean contains(int minimum, int supremum) { @Override protected boolean contains(RunContainer runContainer) { int i1 = 0, i2 = 0; - while(i1 < numberOfRuns() && i2 < runContainer.numberOfRuns()) { + while (i1 < numberOfRuns() && i2 < runContainer.numberOfRuns()) { int start1 = (getValue(i1)); int stop1 = start1 + (getLength(i1)); int start2 = (runContainer.getValue(i2)); int stop2 = start2 + (runContainer.getLength(i2)); - if(start1 > start2) { + if (start1 > start2) { return false; } else { - if(stop1 > stop2) { + if (stop1 > stop2) { i2++; - } else if(stop1 == stop2) { + } else if (stop1 == stop2) { i1++; i2++; } else { @@ -794,11 +793,11 @@ protected boolean contains(ArrayContainer arrayContainer) { return false; } int ia = 0, ir = 0; - while(ia < arrayContainer.getCardinality() && ir < runCount) { + while (ia < arrayContainer.getCardinality() && ir < runCount) { int start = (this.getValue(ir)); int stop = start + (getLength(ir)); int ac = (arrayContainer.content[ia]); - if(ac < start) { + if (ac < start) { return false; } else if (ac > stop) { ++ir; @@ -817,30 +816,37 @@ protected boolean contains(BitmapContainer bitmapContainer) { } final int runCount = numberOfRuns(); char ib = 0, ir = 0; - while(ib < bitmapContainer.bitmap.length && ir < runCount) { + int start = getValue(ir); + int stop = start + getLength(ir); + while (ib < bitmapContainer.bitmap.length && ir < runCount) { long w = bitmapContainer.bitmap[ib]; - while (w != 0 && ir < runCount) { - int start = (getValue(ir)); - int stop = start+ (getLength(ir)); - long t = w & -w; + while (w != 0) { long r = ib * 64L + Long.numberOfTrailingZeros(w); if (r < start) { return false; - } else if(r > stop) { + } else if (r > stop) { ++ir; + if (ir == runCount) { + break; + } + start = getValue(ir); + stop = start + getLength(ir); + } else if (ib * 64 + 64 < stop) { + ib = (char) (stop / 64); + w = bitmapContainer.bitmap[ib]; } else { - w ^= t; + w &= w - 1; } } - if(w == 0) { + if (w == 0) { ++ib; } else { return false; } } - if(ib < bitmapContainer.bitmap.length) { - for(; ib < bitmapContainer.bitmap.length ; ib++) { - if(bitmapContainer.bitmap[ib] != 0) { + if (ib < bitmapContainer.bitmap.length) { + for (; ib < bitmapContainer.bitmap.length; ib++) { + if (bitmapContainer.bitmap[ib] != 0) { return false; } } @@ -848,7 +854,6 @@ protected boolean contains(BitmapContainer bitmapContainer) { return true; } - // a very cheap check... if you have more than 4096, then you should use a bitmap container. // this function avoids computing the cardinality private Container convertToLazyBitmapIfNeeded() { @@ -867,23 +872,9 @@ private Container convertToLazyBitmapIfNeeded() { return this; } - - // Push all values length to the end of the array (resize array if needed) private void copyToOffset(int offset) { - final int minCapacity = 2 * (offset + nbrruns); - if (valueslength.length < minCapacity) { - // expensive case where we need to reallocate - int newCapacity = valueslength.length; - while (newCapacity < minCapacity) { - newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE - : newCapacity < 64 ? newCapacity * 2 - : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4; - } - char[] newvalueslength = new char[newCapacity]; - copyValuesLength(this.valueslength, 0, newvalueslength, offset, nbrruns); - this.valueslength = newvalueslength; - } else { + if (!ensureCapacity(offset, 2 * (offset + nbrruns))) { // efficient case where we just copy copyValuesLength(this.valueslength, 0, this.valueslength, offset, nbrruns); } @@ -894,11 +885,9 @@ private void copyValuesLength(char[] src, int srcIndex, char[] dst, int dstIndex } private void decrementLength(int index) { - valueslength[2 * index + 1]--;// caller is responsible to ensure that value is non-zero + valueslength[2 * index + 1]--; // caller is responsible to ensure that value is non-zero } - - private void decrementValue(int index) { valueslength[2 * index]--; } @@ -915,19 +904,19 @@ public void deserialize(DataInput in) throws IOException { } // not actually used anywhere, but potentially useful - void ensureCapacity(int minNbRuns) { + boolean ensureCapacity(int offset, int minNbRuns) { final int minCapacity = 2 * minNbRuns; if (valueslength.length < minCapacity) { int newCapacity = valueslength.length; while (newCapacity < minCapacity) { - newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE - : newCapacity < 64 ? newCapacity * 2 - : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4; + newCapacity = computeCapacity(newCapacity); } char[] nv = new char[newCapacity]; - copyValuesLength(valueslength, 0, nv, 0, nbrruns); + copyValuesLength(valueslength, 0, nv, offset, nbrruns); valueslength = nv; + return true; } + return false; } @Override @@ -954,8 +943,7 @@ public boolean equals(Object o) { } private boolean equals(RunContainer rc) { - return ArraysShim.equals(valueslength, 0, 2 * nbrruns, - rc.valueslength, 0, 2 * rc.nbrruns); + return ArraysShim.equals(valueslength, 0, 2 * nbrruns, rc.valueslength, 0, 2 * rc.nbrruns); } private boolean equals(ArrayContainer arrayContainer) { @@ -969,7 +957,7 @@ private boolean equals(ArrayContainer arrayContainer) { if (arrayContainer.content[pos] != runStart) { return false; } - if (arrayContainer.content[pos + length] != (char)((runStart) + length)) { + if (arrayContainer.content[pos + length] != (char) ((runStart) + length)) { return false; } pos += length + 1; @@ -1003,10 +991,9 @@ public int getArraySizeInBytes() { return 2 + 4 * this.nbrruns; // "array" includes its size } - @Override public int getCardinality() { - int sum = nbrruns;// lengths are returned -1 + int sum = nbrruns; // lengths are returned -1 for (int k = 1; k < nbrruns * 2; k += 2) { sum += valueslength[k]; } @@ -1073,7 +1060,7 @@ public int hashCode() { public Container iadd(int begin, int end) { // TODO: it might be better and simpler to do return // toBitmapOrArrayContainer(getCardinality()).iadd(begin,end) - if(end == begin) { + if (end == begin) { return this; } if ((begin > end) || (end > (1 << 16))) { @@ -1087,7 +1074,8 @@ public Container iadd(int begin, int end) { int bIndex = unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (char) begin); int eIndex = - unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (char) (end - 1)); + unsignedInterleavedBinarySearch( + this.valueslength, bIndex >= 0 ? bIndex : -bIndex - 1, this.nbrruns, (char) (end - 1)); if (bIndex >= 0 && eIndex >= 0) { mergeValuesLength(bIndex, eIndex); @@ -1177,14 +1165,11 @@ public Container iand(BitmapContainer x) { return and(x); } - - @Override public Container iand(RunContainer x) { return and(x); } - @Override public Container iandNot(ArrayContainer x) { return andNot(x); @@ -1244,22 +1229,18 @@ private Container ilazyorToRun(ArrayContainer x) { return convertToLazyBitmapIfNeeded(); } - private void increaseCapacity() { - int newCapacity = (valueslength.length == 0) ? DEFAULT_INIT_SIZE - : valueslength.length < 64 ? valueslength.length * 2 - : valueslength.length < 1024 ? valueslength.length * 3 / 2 - : valueslength.length * 5 / 4; - char[] nv = new char[newCapacity]; - System.arraycopy(valueslength, 0, nv, 0, 2 * nbrruns); - valueslength = nv; + private int computeCapacity(int oldCapacity) { + return oldCapacity == 0 + ? DEFAULT_INIT_SIZE + : oldCapacity < 64 + ? oldCapacity * 2 + : oldCapacity < 1024 ? oldCapacity * 3 / 2 : oldCapacity * 5 / 4; } - private void incrementLength(int index) { valueslength[2 * index + 1]++; } - private void incrementValue(int index) { valueslength[2 * index]++; } @@ -1345,7 +1326,7 @@ public Container inot(int rangeStart, int rangeEnd) { // use local variables so we are always reading 1 location ahead. char bufferedValue = 0, bufferedLength = 0; // 65535 start and 65535 length would be illegal, - // could use as sentinel + // could use as sentinel char nextValue = 0, nextLength = 0; if (k < myNbrRuns) { // prime the readahead variables bufferedValue = getValue(k); @@ -1383,7 +1364,7 @@ public boolean intersects(ArrayContainer x) { int rlelength = this.getLength(rlepos); while (arraypos < x.cardinality) { int arrayval = (x.content[arraypos]); - while (rleval + rlelength < arrayval) {// this will frequently be false + while (rleval + rlelength < arrayval) { // this will frequently be false ++rlepos; if (rlepos == this.nbrruns) { return false; @@ -1424,7 +1405,7 @@ public boolean intersects(RunContainer x) { if (end <= xstart) { if (ENABLE_GALLOPING_AND) { rlepos = skipAhead(this, rlepos, xstart); // skip over runs until we have end > xstart (or - // rlepos is advanced beyond end) + // rlepos is advanced beyond end) } else { ++rlepos; } @@ -1445,7 +1426,7 @@ public boolean intersects(RunContainer x) { xstart = (x.getValue(xrlepos)); xend = xstart + (x.getLength(xrlepos)) + 1; } - } else {// they overlap + } else { // they overlap return true; } } @@ -1454,7 +1435,7 @@ public boolean intersects(RunContainer x) { @Override public boolean intersects(int minimum, int supremum) { - if((minimum < 0) || (supremum < minimum) || (supremum > (1<<16))) { + if ((minimum < 0) || (supremum < minimum) || (supremum > (1 << 16))) { throw new RuntimeException("This should never happen (bug)."); } for (int i = 0; i < numberOfRuns(); ++i) { @@ -1555,14 +1536,14 @@ public Container ior(RunContainer x) { this.smartAppend(x.getValue(xrlepos), x.getLength(xrlepos)); ++xrlepos; } - return this.toBitmapIfNeeded(); + return this.toEfficientContainer(); } @Override public Container iremove(int begin, int end) { // TODO: it might be better and simpler to do return // toBitmapOrArrayContainer(getCardinality()).iremove(begin,end) - if(end == begin) { + if (end == begin) { return this; } if ((begin > end) || (end > (1 << 16))) { @@ -1575,7 +1556,8 @@ public Container iremove(int begin, int end) { int bIndex = unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (char) begin); int eIndex = - unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (char) (end - 1)); + unsignedInterleavedBinarySearch( + this.valueslength, bIndex >= 0 ? bIndex : -bIndex - 1, this.nbrruns, (char) (end - 1)); // note, eIndex is looking for (end-1) @@ -1606,7 +1588,7 @@ public Container iremove(int begin, int end) { } // last run is one shorter - if (getLength(eIndex) == 0) {// special case where we remove last run + if (getLength(eIndex) == 0) { // special case where we remove last run recoverRoomsInRange(eIndex - 1, eIndex); } else { incrementValue(eIndex); @@ -1621,7 +1603,7 @@ public Container iremove(int begin, int end) { if (eIndex >= 0) { // end-1 is not before first run. if (bIndex >= 0) { // nor is begin if (bIndex == eIndex) { // all removal nested properly between - // one run start and the next + // one run start and the next if (valueLengthContains(begin, bIndex)) { if (valueLengthContains(end, eIndex)) { // proper nesting within a run, generates 2 sub-runs @@ -1642,7 +1624,7 @@ public Container iremove(int begin, int end) { // there is additional stuff in the eIndex run initValueLength(end, eIndex); eIndex--; - } // run ends at or before the range being removed, can delete it + } // run ends at or before the range being removed, can delete it recoverRoomsInRange(bIndex, eIndex); } @@ -1656,10 +1638,7 @@ public Container iremove(int begin, int end) { recoverRoomsInRange(bIndex, eIndex); } } - } // eIndex == -1: whole range is before first run, nothing to delete... - - } return this; } @@ -1693,7 +1672,6 @@ public void remove() { i.remove(); } }; - } @Override @@ -1706,8 +1684,6 @@ public Container ixor(BitmapContainer x) { return xor(x); } - - @Override public Container ixor(RunContainer x) { return xor(x); @@ -1763,7 +1739,11 @@ private RunContainer lazyandNot(ArrayContainer x) { answer.nbrruns++; rlepos++; if (rlepos < this.nbrruns) { - System.arraycopy(this.valueslength, 2 * rlepos, answer.valueslength, 2 * answer.nbrruns, + System.arraycopy( + this.valueslength, + 2 * rlepos, + answer.valueslength, + 2 * answer.nbrruns, 2 * (this.nbrruns - rlepos)); answer.nbrruns = answer.nbrruns + this.nbrruns - rlepos; } @@ -1860,7 +1840,6 @@ private Container lazyxor(ArrayContainer x) { return answer; } - @Override public Container limit(int maxcardinality) { if (maxcardinality >= getCardinality()) { @@ -1876,15 +1855,17 @@ public Container limit(int maxcardinality) { } } - RunContainer rc = new RunContainer(Arrays.copyOf(valueslength, 2 * (r+1)), r+1); - rc.setLength(r , - (char) ((rc.getLength(r)) - cardinality + maxcardinality)); + RunContainer rc = new RunContainer(Arrays.copyOf(valueslength, 2 * (r + 1)), r + 1); + rc.setLength(r, (char) ((rc.getLength(r)) - cardinality + maxcardinality)); return rc; } private void makeRoomAtIndex(int index) { if (2 * (nbrruns + 1) > valueslength.length) { - increaseCapacity(); + int newCapacity = computeCapacity(valueslength.length); + char[] newValuesLength = new char[newCapacity]; + copyValuesLength(valueslength, 0, newValuesLength, 0, nbrruns); + valueslength = newValuesLength; } copyValuesLength(valueslength, index, valueslength, index + 1, nbrruns - index); nbrruns++; @@ -1988,7 +1969,7 @@ public Container or(RunContainer x) { if (answer.isFull()) { return full(); } - return answer.toBitmapIfNeeded(); + return answer.toEfficientContainer(); } // Prepend a value length with all values starting from a given value @@ -2028,8 +2009,8 @@ private void recoverRoomAtIndex(int index) { // To recover rooms between begin(exclusive) and end(inclusive) private void recoverRoomsInRange(int begin, int end) { if (end + 1 < this.nbrruns) { - copyValuesLength(this.valueslength, end + 1, this.valueslength, begin + 1, - this.nbrruns - 1 - end); + copyValuesLength( + this.valueslength, end + 1, this.valueslength, begin + 1, this.nbrruns - 1 - end); } this.nbrruns -= end - begin; } @@ -2050,10 +2031,10 @@ public Container remove(char x) { incrementValue(index); decrementLength(index); } - return this;// already there + return this; // already there } - index = -index - 2;// points to preceding value, possibly -1 - if (index >= 0) {// possible match + index = -index - 2; // points to preceding value, possibly -1 + if (index >= 0) { // possible match int offset = (x) - (getValue(index)); int le = (getLength(index)); if (offset < le) { @@ -2084,7 +2065,6 @@ public Container repairAfterLazy() { * Convert to Array or Bitmap container if the serialized form would be shorter. Exactly the same * functionality as toEfficientContainer. */ - @Override public Container runOptimize() { return toEfficientContainer(); @@ -2109,7 +2089,6 @@ public void serialize(DataOutput out) throws IOException { writeArray(out); } - @Override public int serializedSizeInBytes() { return serializedSizeInBytes(nbrruns); @@ -2119,8 +2098,6 @@ private void setLength(int index, char v) { setLength(valueslength, index, v); } - - private void setLength(char[] valueslength, int index, char v) { valueslength[2 * index + 1] = v; } @@ -2133,8 +2110,6 @@ private void setValue(char[] valueslength, int index, char v) { valueslength[2 * index] = v; } - - // bootstrapping (aka "galloping") binary search. Always skips at least one. // On our "real data" benchmarks, enabling galloping is a minor loss // .."ifdef ENABLE_GALLOPING_AND" :) @@ -2150,14 +2125,12 @@ private int skipAhead(RunContainer skippingOn, int pos, int targetToExceed) { // expect it might be quite common to find the container cannot be advanced as far as // requested. Optimize for it. probePos = skippingOn.nbrruns - 1; - end = (skippingOn.getValue(probePos)) - + (skippingOn.getLength(probePos)) + 1; + end = (skippingOn.getValue(probePos)) + (skippingOn.getLength(probePos)) + 1; if (end <= targetToExceed) { return skippingOn.nbrruns; } } - end = (skippingOn.getValue(probePos)) - + (skippingOn.getLength(probePos)) + 1; + end = (skippingOn.getValue(probePos)) + (skippingOn.getLength(probePos)) + 1; span *= 2; } while (end <= targetToExceed); int right = probePos; @@ -2167,8 +2140,7 @@ private int skipAhead(RunContainer skippingOn, int pos, int targetToExceed) { // invariant is maintained. while (right - left > 1) { int mid = (right + left) / 2; - int midVal = (skippingOn.getValue(mid)) - + (skippingOn.getLength(mid)) + 1; + int midVal = (skippingOn.getValue(mid)) + (skippingOn.getLength(mid)) + 1; if (midVal > targetToExceed) { right = mid; } else { @@ -2181,8 +2153,9 @@ private int skipAhead(RunContainer skippingOn, int pos, int targetToExceed) { private void smartAppend(char val) { int oldend; if ((nbrruns == 0) - || (val > (oldend = (valueslength[2 * (nbrruns - 1)]) - + (valueslength[2 * (nbrruns - 1) + 1])) + 1)) { // we add a new one + || (val + > (oldend = (valueslength[2 * (nbrruns - 1)]) + (valueslength[2 * (nbrruns - 1) + 1])) + + 1)) { // we add a new one valueslength[2 * nbrruns] = val; valueslength[2 * nbrruns + 1] = 0; nbrruns++; @@ -2195,10 +2168,11 @@ private void smartAppend(char val) { void smartAppend(char start, char length) { int oldend; - if ((nbrruns == 0) || ((start) > (oldend = - (getValue(nbrruns - 1)) + (getLength(nbrruns - 1))) - + 1)) { // we add a new one - ensureCapacity(nbrruns + 1); + if ((nbrruns == 0) + || ((start) + > (oldend = (getValue(nbrruns - 1)) + (getLength(nbrruns - 1))) + + 1)) { // we add a new one + ensureCapacity(0, nbrruns + 1); valueslength[2 * nbrruns] = start; valueslength[2 * nbrruns + 1] = length; nbrruns++; @@ -2213,8 +2187,8 @@ void smartAppend(char start, char length) { private void smartAppendExclusive(char val) { int oldend; if ((nbrruns == 0) - || (val > (oldend = getValue(nbrruns - 1) - + getLength(nbrruns - 1) + 1))) { // we add a new one + || (val + > (oldend = getValue(nbrruns - 1) + getLength(nbrruns - 1) + 1))) { // we add a new one valueslength[2 * nbrruns] = val; valueslength[2 * nbrruns + 1] = 0; nbrruns++; @@ -2249,14 +2223,14 @@ private void smartAppendExclusive(char val) { setLength(nbrruns, (char) (oldend - newend - 1)); nbrruns++; } // otherwise newend == oldend - } private void smartAppendExclusive(char start, char length) { int oldend; if ((nbrruns == 0) - || (start > (oldend = (getValue(nbrruns - 1)) - + (getLength(nbrruns - 1)) + 1))) { // we add a new one + || (start + > (oldend = + (getValue(nbrruns - 1)) + (getLength(nbrruns - 1)) + 1))) { // we add a new one valueslength[2 * nbrruns] = start; valueslength[2 * nbrruns + 1] = length; nbrruns++; @@ -2297,16 +2271,6 @@ private void smartAppendExclusive(char start, char length) { } } - // convert to bitmap *if needed* (useful if you know it can't be an array) - private Container toBitmapIfNeeded() { - int sizeAsRunContainer = RunContainer.serializedSizeInBytes(this.nbrruns); - int sizeAsBitmapContainer = BitmapContainer.serializedSizeInBytes(0); - if (sizeAsBitmapContainer > sizeAsRunContainer) { - return this; - } - return toBitmapContainer(); - } - /** * Convert the container to either a Bitmap or an Array Container, depending on the cardinality. * @@ -2372,7 +2336,7 @@ public String toString() { StringBuilder sb = new StringBuilder("[]".length() + "-123456789,".length() * nbrruns); for (int k = 0; k < this.nbrruns; ++k) { sb.append('['); - sb.append((int)(this.getValue(k))); + sb.append((int) (this.getValue(k))); sb.append(','); sb.append((this.getValue(k)) + (this.getLength(k))); sb.append(']'); @@ -2380,7 +2344,6 @@ public String toString() { return sb.toString(); } - @Override public void trim() { if (valueslength.length == 2 * nbrruns) { @@ -2389,7 +2352,6 @@ public void trim() { valueslength = Arrays.copyOf(valueslength, 2 * nbrruns); } - // To check if a value length contains a given value private boolean valueLengthContains(int value, int index) { int initialValue = (getValue(index)); @@ -2410,7 +2372,7 @@ public void writeArray(DataOutput out) throws IOException { public void writeArray(ByteBuffer buffer) { assert buffer.order() == ByteOrder.LITTLE_ENDIAN; CharBuffer buf = buffer.asCharBuffer(); - buf.put((char)nbrruns); + buf.put((char) nbrruns); buf.put(valueslength, 0, nbrruns * 2); int bytesWritten = (nbrruns * 2 + 1) * 2; buffer.position(buffer.position() + bytesWritten); @@ -2419,7 +2381,6 @@ public void writeArray(ByteBuffer buffer) { @Override public void writeExternal(ObjectOutput out) throws IOException { serialize(out); - } @Override @@ -2500,10 +2461,10 @@ public Container xor(RunContainer x) { @Override public void forEach(char msb, IntConsumer ic) { int high = msb << 16; - for(int k = 0; k < this.nbrruns; ++k) { + for (int k = 0; k < this.nbrruns; ++k) { int base = this.getValue(k) | high; int le = this.getLength(k); - for(int l = base; l - le <= base; ++l) { + for (int l = base; l - le <= base; ++l) { ic.accept(l); } } @@ -2599,7 +2560,7 @@ public void forAllUntil(int offset, char endValue, final RelativeRangeConsumer r public void forAllInRange(char startValue, char endValue, final RelativeRangeConsumer rrc) { if (endValue <= startValue) { throw new IllegalArgumentException( - "startValue (" + startValue + ") must be less than endValue (" + endValue + ")"); + "startValue (" + startValue + ") must be less than endValue (" + endValue + ")"); } int startOffset = startValue; int next = startValue; @@ -2648,17 +2609,29 @@ public void forAllInRange(char startValue, char endValue, final RelativeRangeCon @Override public BitmapContainer toBitmapContainer() { - int card = this.getCardinality(); + int card = 0; BitmapContainer answer = new BitmapContainer(); for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) { int start = (this.getValue(rlepos)); int end = start + (this.getLength(rlepos)) + 1; + card += end - start; Util.setBitmapRange(answer.bitmap, start, end); } + assert card == this.getCardinality(); answer.cardinality = card; return answer; } + @Override + public void copyBitmapTo(long[] dest, int position) { + int offset = position * Long.SIZE; + for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) { + int start = offset + this.getValue(rlepos); + int end = start + this.getLength(rlepos) + 1; + Util.setBitmapRange(dest, start, end); + } + } + @Override public int nextValue(char fromValue) { int index = unsignedInterleavedBinarySearch(valueslength, 0, nbrruns, fromValue); @@ -2734,10 +2707,8 @@ public int last() { int length = (getLength(index)); return start + length; } - } - class RunContainerCharIterator implements PeekableCharIterator { int pos; int le = 0; @@ -2746,9 +2717,7 @@ class RunContainerCharIterator implements PeekableCharIterator { RunContainer parent; - RunContainerCharIterator() { - - } + RunContainerCharIterator() {} RunContainerCharIterator(RunContainer p) { wrap(p); @@ -2759,7 +2728,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -2800,7 +2769,7 @@ public int nextAsInt() { @Override public void remove() { - throw new RuntimeException("Not implemented");// TODO + throw new RuntimeException("Not implemented"); // TODO } void wrap(RunContainer p) { @@ -2831,13 +2800,10 @@ public void advanceIfNeeded(char minval) { le = (minval) - base; } - - @Override public char peekNext() { return (char) (base + le); } - } class RunContainerCharRankIterator extends RunContainerCharIterator @@ -2896,7 +2862,6 @@ public RunContainerCharRankIterator clone() { } } - final class ReverseRunContainerCharIterator implements PeekableCharIterator { int pos; private int le; @@ -2904,10 +2869,7 @@ final class ReverseRunContainerCharIterator implements PeekableCharIterator { private int maxlength; private int base; - - ReverseRunContainerCharIterator() { - - } + ReverseRunContainerCharIterator() {} ReverseRunContainerCharIterator(RunContainer p) { wrap(p); @@ -2918,7 +2880,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -2975,15 +2937,14 @@ public void advanceIfNeeded(char maxval) { le = maxlength + base - (maxval); } - @Override public char peekNext() { return (char) (base + maxlength - le); } - + @Override public void remove() { - throw new RuntimeException("Not implemented");// TODO + throw new RuntimeException("Not implemented"); // TODO } void wrap(RunContainer p) { @@ -2995,5 +2956,4 @@ void wrap(RunContainer p) { base = (parent.getValue(pos)); } } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/Util.java b/roaringbitmap/src/main/java/org/roaringbitmap/Util.java similarity index 80% rename from RoaringBitmap/src/main/java/org/roaringbitmap/Util.java rename to roaringbitmap/src/main/java/org/roaringbitmap/Util.java index d82ca0acc..5a5f39b5a 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/Util.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/Util.java @@ -4,10 +4,10 @@ package org.roaringbitmap; -import java.util.Arrays; - import static java.lang.Long.numberOfTrailingZeros; +import java.util.Arrays; + /** * Various useful methods for roaring bitmaps. */ @@ -19,7 +19,6 @@ public final class Util { */ public static final boolean USE_HYBRID_BINSEARCH = true; - /** * Add value "offset" to all values in the container, producing * two new containers. The existing container remains unchanged. @@ -29,68 +28,98 @@ public final class Util { * @param offsets value to add to each value in the container * @return return an array made of two containers */ - public static Container[] addOffset(Container source, char offsets) { - // could be a whole lot faster, this is a simple implementation - if(source instanceof ArrayContainer) { - ArrayContainer c = (ArrayContainer) source; - ArrayContainer low = new ArrayContainer(c.cardinality); - ArrayContainer high = new ArrayContainer(c.cardinality); - for(int k = 0; k < c.cardinality; k++) { - int val = c.content[k]; - val += (int) (offsets); - if(val <= 0xFFFF) { - low.content[low.cardinality++] = (char) val; - } else { - high.content[high.cardinality++] = (char) val; - } - } - return new Container[] {low, high}; + public static Container[] addOffset(Container source, char offsets) { + if (source instanceof ArrayContainer) { + return addOffsetArray((ArrayContainer) source, offsets); } else if (source instanceof BitmapContainer) { - BitmapContainer c = (BitmapContainer) source; - BitmapContainer low = new BitmapContainer(); - BitmapContainer high = new BitmapContainer(); - low.cardinality = -1; - high.cardinality = -1; - final int b = (int) (offsets) >>> 6; - final int i = (int) (offsets) % 64; - if(i == 0) { - System.arraycopy(c.bitmap, 0, low.bitmap, b, 1024 - b); - System.arraycopy(c.bitmap, 1024 - b, high.bitmap, 0, b ); - } else { - low.bitmap[b + 0] = c.bitmap[0] << i; - for(int k = 1; k < 1024 - b; k++) { - low.bitmap[b + k] = (c.bitmap[k] << i) | (c.bitmap[k - 1] >>> (64-i)); - } - for(int k = 1024 - b; k < 1024 ; k++) { - high.bitmap[k - (1024 - b)] = - (c.bitmap[k] << i) - | (c.bitmap[k - 1] >>> (64-i)); - } - high.bitmap[b] = (c.bitmap[1024 - 1] >>> (64-i)); - } - return new Container[] {low.repairAfterLazy(), high.repairAfterLazy()}; + return addOffsetBitmap((BitmapContainer) source, offsets); } else if (source instanceof RunContainer) { - RunContainer input = (RunContainer) source; - RunContainer low = new RunContainer(); - RunContainer high = new RunContainer(); - for(int k = 0 ; k < input.nbrruns; k++) { - int val = (input.getValue(k)); - val += (int) (offsets); - int finalval = val + (input.getLength(k)); - if(val <= 0xFFFF) { - if(finalval <= 0xFFFF) { - low.smartAppend((char)val,input.getLength(k)); - } else { - low.smartAppend((char)val,(char)(0xFFFF-val)); - high.smartAppend((char) 0,(char)finalval); - } + return addOffsetRun((RunContainer) source, offsets); + } + throw new RuntimeException("unknown container type"); + } + + private static Container[] addOffsetArray(ArrayContainer source, char offsets) { + int splitIndex; + if (source.first() + offsets > 0xFFFF) { + splitIndex = 0; + } else if (source.last() + offsets < 0xFFFF) { + splitIndex = source.cardinality; + } else { + splitIndex = + Util.unsignedBinarySearch( + source.content, 0, source.cardinality, (char) (0x10000 - offsets)); + if (splitIndex < 0) { + splitIndex = -splitIndex - 1; + } + } + + ArrayContainer low = splitIndex == 0 ? new ArrayContainer() : new ArrayContainer(splitIndex); + ArrayContainer high = + source.cardinality - splitIndex == 0 + ? new ArrayContainer() + : new ArrayContainer(source.cardinality - splitIndex); + + int lowCardinality = 0; + for (int k = 0; k < splitIndex; k++) { + int val = source.content[k] + offsets; + low.content[lowCardinality++] = (char) val; + } + low.cardinality = lowCardinality; + + int highCardinality = 0; + for (int k = splitIndex; k < source.cardinality; k++) { + int val = source.content[k] + offsets; + high.content[highCardinality++] = (char) val; + } + high.cardinality = highCardinality; + + return new Container[] {low, high}; + } + + private static Container[] addOffsetBitmap(BitmapContainer source, char offsets) { + BitmapContainer c = source; + BitmapContainer low = new BitmapContainer(); + BitmapContainer high = new BitmapContainer(); + low.cardinality = -1; + high.cardinality = -1; + final int b = (int) offsets >>> 6; + final int i = (int) offsets % 64; + if (i == 0) { + System.arraycopy(c.bitmap, 0, low.bitmap, b, 1024 - b); + System.arraycopy(c.bitmap, 1024 - b, high.bitmap, 0, b); + } else { + low.bitmap[b] = c.bitmap[0] << i; + for (int k = 1; k < 1024 - b; k++) { + low.bitmap[b + k] = (c.bitmap[k] << i) | (c.bitmap[k - 1] >>> (64 - i)); + } + for (int k = 1024 - b; k < 1024; k++) { + high.bitmap[k - (1024 - b)] = (c.bitmap[k] << i) | (c.bitmap[k - 1] >>> (64 - i)); + } + high.bitmap[b] = c.bitmap[1024 - 1] >>> (64 - i); + } + return new Container[] {low.repairAfterLazy(), high.repairAfterLazy()}; + } + + private static Container[] addOffsetRun(RunContainer source, char offsets) { + RunContainer input = source; + RunContainer low = new RunContainer(); + RunContainer high = new RunContainer(); + for (int k = 0; k < input.nbrruns; k++) { + int val = input.getValue(k) + offsets; + int finalval = val + input.getLength(k); + if (val <= 0xFFFF) { + if (finalval <= 0xFFFF) { + low.smartAppend((char) val, input.getLength(k)); } else { - high.smartAppend((char)val,input.getLength(k)); + low.smartAppend((char) val, (char) (0xFFFF - val)); + high.smartAppend((char) 0, (char) finalval); } + } else { + high.smartAppend((char) val, input.getLength(k)); } - return new Container[] {low, high}; } - throw new RuntimeException("unknown container type"); // never happens + return new Container[] {low, high}; } /** @@ -115,8 +144,7 @@ public static int advanceUntil(char[] array, int pos, int length, char min) { int spansize = 1; // could set larger // bootstrap an upper limit - while (lower + spansize < length - && (array[lower + spansize]) < (int) (min)) { + while (lower + spansize < length && (array[lower + spansize]) < (int) (min)) { spansize *= 2; // hoping for compiler will reduce to } // shift @@ -151,10 +179,8 @@ public static int advanceUntil(char[] array, int pos, int length, char min) { } } return upper; - } - - + /** * Find the largest integer smaller than pos such that array[pos]<= max. If none can be found, * return length. Based on code by O. Kaser. @@ -177,8 +203,7 @@ public static int reverseUntil(char[] array, int pos, int length, char max) { int spansize = 1; // could set larger // bootstrap an upper limit - while (lower - spansize > 0 - && (array[lower - spansize]) > (int) (max)) { + while (lower - spansize > 0 && (array[lower - spansize]) > (int) (max)) { spansize *= 2; // hoping for compiler will reduce to } // shift @@ -213,7 +238,6 @@ public static int reverseUntil(char[] array, int pos, int length, char max) { } } return upper; - } /** @@ -234,8 +258,8 @@ public static int iterateUntil(char[] array, int pos, int length, int min) { return pos; } - protected static int branchyUnsignedBinarySearch(final char[] array, final int begin, - final int end, final char k) { + protected static int branchyUnsignedBinarySearch( + final char[] array, final int begin, final int end, final char k) { // next line accelerates the possibly common case where the value would // be inserted at the end if ((end > 0) && ((array[end - 1]) < (int) (k))) { @@ -265,8 +289,8 @@ protected static int branchyUnsignedBinarySearch(final char[] array, final int b * @param bitmap1 first bitmap * @param bitmap2 second bitmap */ - public static void fillArrayAND(final char[] container, final long[] bitmap1, - final long[] bitmap2) { + public static void fillArrayAND( + final char[] container, final long[] bitmap1, final long[] bitmap2) { int pos = 0; if (bitmap1.length != bitmap2.length) { throw new IllegalArgumentException("not supported"); @@ -287,8 +311,8 @@ public static void fillArrayAND(final char[] container, final long[] bitmap1, * @param bitmap1 first bitmap * @param bitmap2 second bitmap */ - public static void fillArrayANDNOT(final char[] container, final long[] bitmap1, - final long[] bitmap2) { + public static void fillArrayANDNOT( + final char[] container, final long[] bitmap1, final long[] bitmap2) { int pos = 0; if (bitmap1.length != bitmap2.length) { throw new IllegalArgumentException("not supported"); @@ -309,8 +333,8 @@ public static void fillArrayANDNOT(final char[] container, final long[] bitmap1, * @param bitmap1 first bitmap * @param bitmap2 second bitmap */ - public static void fillArrayXOR(final char[] container, final long[] bitmap1, - final long[] bitmap2) { + public static void fillArrayXOR( + final char[] container, final long[] bitmap1, final long[] bitmap2) { int pos = 0; if (bitmap1.length != bitmap2.length) { throw new IllegalArgumentException("not supported"); @@ -344,7 +368,6 @@ public static void flipBitmapRange(long[] bitmap, int start, int end) { bitmap[endword] ^= ~0L >>> -end; } - /** * Hamming weight of the 64-bit words involved in the range * start, start+1,..., end-1, that is, it will compute the @@ -370,7 +393,6 @@ public static int cardinalityInBitmapWordRange(long[] bitmap, int start, int end return answer; } - /** * Hamming weight of the bitset in the range * start, start+1,..., end-1 @@ -387,7 +409,7 @@ public static int cardinalityInBitmapRange(long[] bitmap, int start, int end) { int firstword = start / 64; int endword = (end - 1) / 64; if (firstword == endword) { - return Long.bitCount(bitmap[firstword] & ( (~0L << start) & (~0L >>> -end) )); + return Long.bitCount(bitmap[firstword] & ((~0L << start) & (~0L >>> -end))); } int answer = Long.bitCount(bitmap[firstword] & (~0L << start)); for (int i = firstword + 1; i < endword; i++) { @@ -406,8 +428,8 @@ protected static char highbits(long x) { } // starts with binary search and finishes with a sequential search - protected static int hybridUnsignedBinarySearch(final char[] array, final int begin, - final int end, final char k) { + protected static int hybridUnsignedBinarySearch( + final char[] array, final int begin, final int end, final char k) { // next line accelerates the possibly common case where the value would // be inserted at the end if ((end > 0) && ((array[end - 1]) < (int) k)) { @@ -450,13 +472,12 @@ protected static char lowbits(long x) { return (char) x; } - protected static int lowbitsAsInteger(int x) { return x & 0xFFFF; } protected static int lowbitsAsInteger(long x) { - return (int)(x & 0xFFFF); + return (int) (x & 0xFFFF); } public static int maxLowBitAsInteger() { @@ -486,7 +507,6 @@ public static void resetBitmapRange(long[] bitmap, int start, int end) { bitmap[i] = 0; } bitmap[endword] &= ~(~0L >>> -end); - } /** @@ -610,12 +630,11 @@ public static void setBitmapRange(long[] bitmap, int start, int end) { @Deprecated public static int setBitmapRangeAndCardinalityChange(long[] bitmap, int start, int end) { int cardbefore = cardinalityInBitmapWordRange(bitmap, start, end); - setBitmapRange(bitmap, start,end); + setBitmapRange(bitmap, start, end); int cardafter = cardinalityInBitmapWordRange(bitmap, start, end); return cardafter - cardbefore; } - /** * flip bits at start, start+1,..., end-1 and report the * cardinality change @@ -628,12 +647,11 @@ public static int setBitmapRangeAndCardinalityChange(long[] bitmap, int start, i @Deprecated public static int flipBitmapRangeAndCardinalityChange(long[] bitmap, int start, int end) { int cardbefore = cardinalityInBitmapWordRange(bitmap, start, end); - flipBitmapRange(bitmap, start,end); + flipBitmapRange(bitmap, start, end); int cardafter = cardinalityInBitmapWordRange(bitmap, start, end); return cardafter - cardbefore; } - /** * reset bits at start, start+1,..., end-1 and report the * cardinality change @@ -646,7 +664,7 @@ public static int flipBitmapRangeAndCardinalityChange(long[] bitmap, int start, @Deprecated public static int resetBitmapRangeAndCardinalityChange(long[] bitmap, int start, int end) { int cardbefore = cardinalityInBitmapWordRange(bitmap, start, end); - resetBitmapRange(bitmap, start,end); + resetBitmapRange(bitmap, start, end); int cardafter = cardinalityInBitmapWordRange(bitmap, start, end); return cardafter - cardbefore; } @@ -662,8 +680,8 @@ public static int resetBitmapRangeAndCardinalityChange(long[] bitmap, int start, * @param k value we search for * @return count */ - public static int unsignedBinarySearch(final char[] array, final int begin, final int end, - final char k) { + public static int unsignedBinarySearch( + final char[] array, final int begin, final int end, final char k) { if (USE_HYBRID_BINSEARCH) { return hybridUnsignedBinarySearch(array, begin, end, k); } else { @@ -682,8 +700,12 @@ public static int unsignedBinarySearch(final char[] array, final int begin, fina * @param buffer output array * @return cardinality of the difference */ - public static int unsignedDifference(final char[] set1, final int length1, final char[] set2, - final int length2, final char[] buffer) { + public static int unsignedDifference( + final char[] set1, + final int length1, + final char[] set2, + final int length2, + final char[] buffer) { int pos = 0; int k1 = 0, k2 = 0; if (0 == length2) { @@ -715,7 +737,7 @@ public static int unsignedDifference(final char[] set1, final int length1, final } s1 = set1[k1]; s2 = set2[k2]; - } else {// if (val1>val2) + } else { // if (val1>val2) ++k2; if (k2 >= length2) { System.arraycopy(set1, k1, buffer, pos, length1 - k1); @@ -736,8 +758,7 @@ public static int unsignedDifference(final char[] set1, final int length1, final * @param buffer output array * @return cardinality of the difference */ - public static int unsignedDifference(CharIterator set1, CharIterator set2, - final char[] buffer) { + public static int unsignedDifference(CharIterator set1, CharIterator set2, final char[] buffer) { int pos = 0; if (!set2.hasNext()) { while (set1.hasNext()) { @@ -769,7 +790,7 @@ public static int unsignedDifference(CharIterator set1, CharIterator set2, } v1 = set1.next(); v2 = set2.next(); - } else {// if (val1>val2) + } else { // if (val1>val2) if (!set2.hasNext()) { buffer[pos++] = v1; while (set1.hasNext()) { @@ -794,8 +815,12 @@ public static int unsignedDifference(CharIterator set1, CharIterator set2, * @param buffer output array * @return cardinality of the exclusive union */ - public static int unsignedExclusiveUnion2by2(final char[] set1, final int length1, - final char[] set2, final int length2, final char[] buffer) { + public static int unsignedExclusiveUnion2by2( + final char[] set1, + final int length1, + final char[] set2, + final int length2, + final char[] buffer) { int pos = 0; int k1 = 0, k2 = 0; if (0 == length2) { @@ -830,7 +855,7 @@ public static int unsignedExclusiveUnion2by2(final char[] set1, final int length } s1 = set1[k1]; s2 = set2[k2]; - } else {// if (val1>val2) + } else { // if (val1>val2) buffer[pos++] = s2; ++k2; if (k2 >= length2) { @@ -843,8 +868,6 @@ public static int unsignedExclusiveUnion2by2(final char[] set1, final int length // return pos; } - - /** * Intersect two sorted lists and write the result to the provided output array * @@ -855,8 +878,12 @@ public static int unsignedExclusiveUnion2by2(final char[] set1, final int length * @param buffer output array * @return cardinality of the intersection */ - public static int unsignedIntersect2by2(final char[] set1, final int length1, final char[] set2, - final int length2, final char[] buffer) { + public static int unsignedIntersect2by2( + final char[] set1, + final int length1, + final char[] set2, + final int length2, + final char[] buffer) { final int THRESHOLD = 25; if (set1.length * THRESHOLD < set2.length) { return unsignedOneSidedGallopingIntersect2by2(set1, length1, set2, length2, buffer); @@ -867,8 +894,6 @@ public static int unsignedIntersect2by2(final char[] set1, final int length1, fi } } - - /** * Checks if two arrays intersect * @@ -887,7 +912,8 @@ public static boolean unsignedIntersects(char[] set1, int length1, char[] set2, int k2 = 0; char s1 = set1[k1]; char s2 = set2[k2]; - mainwhile: while (true) { + mainwhile: + while (true) { if (s2 < s1) { do { ++k2; @@ -912,9 +938,12 @@ public static boolean unsignedIntersects(char[] set1, int length1, char[] set2, return false; } - - protected static int unsignedLocalIntersect2by2(final char[] set1, final int length1, - final char[] set2, final int length2, final char[] buffer) { + protected static int unsignedLocalIntersect2by2( + final char[] set1, + final int length1, + final char[] set2, + final int length2, + final char[] buffer) { if ((0 == length1) || (0 == length2)) { return 0; } @@ -924,7 +953,8 @@ protected static int unsignedLocalIntersect2by2(final char[] set1, final int len char s1 = set1[k1]; char s2 = set2[k2]; - mainwhile: while (true) { + mainwhile: + while (true) { int v1 = (s1); int v2 = s2; if (v2 < v1) { @@ -964,7 +994,6 @@ protected static int unsignedLocalIntersect2by2(final char[] set1, final int len return pos; } - /** * Compute the cardinality of the intersection * @param set1 first set @@ -973,8 +1002,8 @@ protected static int unsignedLocalIntersect2by2(final char[] set1, final int len * @param length2 how many values to consider in the second set * @return cardinality of the intersection */ - public static int unsignedLocalIntersect2by2Cardinality(final char[] set1, final int length1, - final char[] set2, final int length2) { + public static int unsignedLocalIntersect2by2Cardinality( + final char[] set1, final int length1, final char[] set2, final int length2) { if ((0 == length1) || (0 == length2)) { return 0; } @@ -984,7 +1013,8 @@ public static int unsignedLocalIntersect2by2Cardinality(final char[] set1, final char s1 = set1[k1]; char s2 = set2[k2]; - mainwhile: while (true) { + mainwhile: + while (true) { int v1 = s1; int v2 = s2; if (v2 < v1) { @@ -1024,9 +1054,12 @@ public static int unsignedLocalIntersect2by2Cardinality(final char[] set1, final return pos; } - - protected static int unsignedOneSidedGallopingIntersect2by2(final char[] smallSet, - final int smallLength, final char[] largeSet, final int largeLength, final char[] buffer) { + protected static int unsignedOneSidedGallopingIntersect2by2( + final char[] smallSet, + final int smallLength, + final char[] largeSet, + final int largeLength, + final char[] buffer) { if (0 == smallLength) { return 0; } @@ -1063,10 +1096,8 @@ protected static int unsignedOneSidedGallopingIntersect2by2(final char[] smallSe } s1 = largeSet[k1]; } - } return pos; - } /** @@ -1082,9 +1113,13 @@ protected static int unsignedOneSidedGallopingIntersect2by2(final char[] smallSe * @return cardinality of the union */ public static int unsignedUnion2by2( - final char[] set1, final int offset1, final int length1, - final char[] set2, final int offset2, final int length2, - final char[] buffer) { + final char[] set1, + final int offset1, + final int length1, + final char[] set2, + final int offset2, + final int length2, + final char[] buffer) { if (0 == length2) { System.arraycopy(set1, offset1, buffer, 0, length1); return length1; @@ -1122,7 +1157,7 @@ public static int unsignedUnion2by2( } s1 = set1[k1]; s2 = set2[k2]; - } else {// if (set1[k1]>set2[k2]) + } else { // if (set1[k1]>set2[k2]) buffer[pos++] = s2; ++k2; if (k2 >= length2 + offset2) { @@ -1135,7 +1170,6 @@ public static int unsignedUnion2by2( // return pos; } - /** * Converts the argument to a {@code long} by an unsigned conversion. In an unsigned conversion to * a {@code long}, the high-order 32 bits of the {@code long} are zero and the low-order 32 bits @@ -1153,6 +1187,7 @@ public static int unsignedUnion2by2( public static long toUnsignedLong(int x) { return ((long) x) & 0xffffffffL; } + /** * Sorts the data by the 16 bit prefix using Radix sort. * The resulting data will be partially sorted if you just @@ -1201,10 +1236,53 @@ public static void partialRadixSort(int[] data) { System.arraycopy(copy, 0, data, 0, data.length); } } + + /** + * It computes the intersection of the containers' keys between given bitmaps. + * + * @param words bitmap buffer + * @param bitmaps bitmaps + * @return keys intersection + */ + static char[] intersectKeys(long[] words, RoaringBitmap[] bitmaps) { + RoaringBitmap first = bitmaps[0]; + for (int i = 0; i < first.highLowContainer.size; ++i) { + char key = first.highLowContainer.keys[i]; + words[key >>> 6] |= 1L << key; + } + int numContainers = first.highLowContainer.size; + for (int i = 1; i < bitmaps.length && numContainers > 0; ++i) { + numContainers = + Util.intersectArrayIntoBitmap( + words, bitmaps[i].highLowContainer.keys, bitmaps[i].highLowContainer.size); + } + if (numContainers == 0) { + return new char[0]; + } + return BitSetUtil.arrayContainerBufferOf(0, words.length, numContainers, words); + } + /** * Private constructor to prevent instantiation of utility class */ - private Util() { + private Util() {} + /** + * Fill the array with set bits + * + * @param bitmap source bitmap + * @param array container (should be sufficiently large) + */ + public static void fillArray(long[] bitmap, final char[] array) { + int pos = 0; + int base = 0; + for (int k = 0; k < bitmap.length; ++k) { + long bitset = bitmap[k]; + while (bitset != 0) { + array[pos++] = (char) (base + numberOfTrailingZeros(bitset)); + bitset &= (bitset - 1); + } + base += 64; + } } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/WordStorage.java b/roaringbitmap/src/main/java/org/roaringbitmap/WordStorage.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/WordStorage.java rename to roaringbitmap/src/main/java/org/roaringbitmap/WordStorage.java index 12cf74b95..755792490 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/WordStorage.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/WordStorage.java @@ -7,5 +7,4 @@ public interface WordStorage { boolean isEmpty(); T runOptimize(); - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/AbstractShuttle.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/AbstractShuttle.java similarity index 86% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/AbstractShuttle.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/AbstractShuttle.java index d15efc5c6..c76935181 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/AbstractShuttle.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/AbstractShuttle.java @@ -10,7 +10,7 @@ public abstract class AbstractShuttle implements Shuttle { protected static final int MAX_DEPTH = 7; protected NodeEntry[] stack = new NodeEntry[MAX_DEPTH]; - //started from 0 + // started from 0 protected int depth = -1; protected boolean hasRun = false; protected Art art; @@ -30,9 +30,10 @@ public void initShuttle() { public void initShuttleFrom(long key) { depth = -1; // reset byte[] high = LongUtils.highPart(key); + long highAsLong = LongUtils.rightShiftHighPart(key); visitToLeafFrom(high, 0, art.getRoot()); // If the target container doesn't exist, we may end up in the previous existing leaf here - if (currentBeforeHigh(getCurrentLeafNode().getKeyBytes(), high)) { + if (currentBeforeHigh(getCurrentLeafNode().getKey(), highAsLong)) { // Move the following leaf instead hasRun = true; // make it actually move moveToNextLeaf(); @@ -40,7 +41,7 @@ public void initShuttleFrom(long key) { hasRun = false; // reset } - protected abstract boolean currentBeforeHigh(byte[] current, byte[] high); + protected abstract boolean currentBeforeHigh(long current, long high); @Override public boolean moveToNextLeaf() { @@ -56,22 +57,22 @@ public boolean moveToNextLeaf() { return false; } } - //skip the top leaf node + // skip the top leaf node Node node = stack[depth].node; if (node.nodeType == NodeType.LEAF_NODE) { depth--; } - //visit parent node + // visit parent node while (depth >= 0) { NodeEntry currentNodeEntry = stack[depth]; if (currentNodeEntry.node.nodeType == NodeType.LEAF_NODE) { - //found current leaf node's next sibling node to benefit the removing operation + // found current leaf node's next sibling node to benefit the removing operation if (depth - 1 >= 0) { findNextSiblingKeyOfLeafNode(); } return true; } - //visit the next child node + // visit the next child node int pos; int nextPos; if (!currentNodeEntry.visited) { @@ -82,19 +83,19 @@ public boolean moveToNextLeaf() { } else if (currentNodeEntry.startFromNextSiblingPosition) { nextPos = currentNodeEntry.position; currentNodeEntry.startFromNextSiblingPosition = false; - } else { + } else { pos = currentNodeEntry.position; nextPos = visitedNodeNextPosition(currentNodeEntry.node, pos); } if (nextPos != Node.ILLEGAL_IDX) { stack[depth].position = nextPos; depth++; - //add a fresh entry on the top of the visiting stack + // add a fresh entry on the top of the visiting stack NodeEntry freshEntry = new NodeEntry(); freshEntry.node = currentNodeEntry.node.getChild(nextPos); stack[depth] = freshEntry; } else { - //current internal node doesn't have anymore unvisited child,move to a top node + // current internal node doesn't have anymore unvisited child,move to a top node depth--; } } @@ -121,13 +122,13 @@ public void remove() { } Node node = toolkit.freshMatchedParentNode; if (depth - 1 >= 0) { - //update the parent node to a fresh node as the parent node may changed by the - //art adaptive removing logic + // update the parent node to a fresh node as the parent node may changed by the + // art adaptive removing logic NodeEntry oldEntry = stack[depth - 1]; oldEntry.visited = oldEntry.node == node; oldEntry.node = node; oldEntry.startFromNextSiblingPosition = true; - if (node.nodeType != NodeType.LEAF_NODE) { + if (node.nodeType != NodeType.LEAF_NODE) { oldEntry.position = node.getChildPos(oldEntry.leafNodeNextSiblingKey); } } @@ -144,7 +145,7 @@ private void visitToLeaf(Node node, boolean inRunDirection) { stack[depth] = nodeEntry; } if (node.nodeType == NodeType.LEAF_NODE) { - //leaf node's corresponding NodeEntry will not have the position member set. + // leaf node's corresponding NodeEntry will not have the position member set. if (depth - 1 >= 0) { findNextSiblingKeyOfLeafNode(); } @@ -153,7 +154,7 @@ private void visitToLeaf(Node node, boolean inRunDirection) { if (depth == MAX_DEPTH) { return; } - //find next min child + // find next min child int pos = boundaryNodePosition(node, inRunDirection); stack[depth].position = pos; stack[depth].visited = true; @@ -176,7 +177,7 @@ private void visitToLeafFrom(byte[] high, int keyDepth, Node node) { stack[depth] = nodeEntry; } if (node.nodeType == NodeType.LEAF_NODE) { - //leaf node's corresponding NodeEntry will not have the position member set. + // leaf node's corresponding NodeEntry will not have the position member set. if (depth - 1 >= 0) { findNextSiblingKeyOfLeafNode(); } @@ -187,13 +188,8 @@ private void visitToLeafFrom(byte[] high, int keyDepth, Node node) { } if (node.prefixLength > 0) { - int commonLength = Art.commonPrefixLength( - high, - keyDepth, - high.length, - node.prefix, - 0, - node.prefixLength); + int commonLength = + Art.commonPrefixLength(high, keyDepth, high.length, node.prefix, 0, node.prefixLength); if (commonLength != node.prefixLength) { byte nodeValue = node.prefix[commonLength]; byte highValue = high[keyDepth + commonLength]; @@ -202,10 +198,10 @@ private void visitToLeafFrom(byte[] high, int keyDepth, Node node) { visitToLeaf(node, visitDirection); return; } - //common prefix is the same ,then increase the depth + // common prefix is the same ,then increase the depth keyDepth += node.prefixLength; } - //find next child + // find next child SearchResult result = node.getNearestChildPos(high[keyDepth]); int pos; boolean continueAtBoundary = false; diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Art.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Art.java similarity index 78% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Art.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Art.java index 3f0984ab8..1cf10553e 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Art.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/Art.java @@ -1,10 +1,11 @@ package org.roaringbitmap.art; +import org.roaringbitmap.ArraysShim; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.nio.ByteBuffer; -import org.roaringbitmap.ArraysShim; /** * See: https://db.in.tum.de/~leis/papers/ART.pdf a cpu cache friendly main memory data structure. @@ -61,21 +62,26 @@ private Node findByKey(Node node, byte[] key, int depth) { if (depth == LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES) { return leafNode; } - int mismatchIndex = ArraysShim - .mismatch(leafNodeKeyBytes, depth, LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES, - key, depth, LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES); + int mismatchIndex = + ArraysShim.mismatch( + leafNodeKeyBytes, + depth, + LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES, + key, + depth, + LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES); if (mismatchIndex != -1) { return null; } return leafNode; } if (node.prefixLength > 0) { - int commonLength = commonPrefixLength(key, depth, key.length, node.prefix, 0, - node.prefixLength); + int commonLength = + commonPrefixLength(key, depth, key.length, node.prefix, 0, node.prefixLength); if (commonLength != node.prefixLength) { return null; } - //common prefix is the same ,then increase the depth + // common prefix is the same ,then increase the depth depth += node.prefixLength; } int pos = node.getChildPos(key[depth]); @@ -115,10 +121,10 @@ protected Toolkit removeSpecifyKey(Node node, byte[] key, int dep) { return null; } if (node.nodeType == NodeType.LEAF_NODE) { - //root is null + // root is null LeafNode leafNode = (LeafNode) node; if (leafMatch(leafNode, key, dep)) { - //remove this node + // remove this node if (node == this.root) { this.root = null; } @@ -129,10 +135,8 @@ protected Toolkit removeSpecifyKey(Node node, byte[] key, int dep) { } } if (node.prefixLength > 0) { - int commonLength = commonPrefixLength( - key, dep, key.length, - node.prefix, 0, node.prefixLength - ); + int commonLength = + commonPrefixLength(key, dep, key.length, node.prefix, 0, node.prefixLength); if (commonLength != node.prefixLength) { return null; } @@ -142,7 +146,7 @@ protected Toolkit removeSpecifyKey(Node node, byte[] key, int dep) { if (pos != Node.ILLEGAL_IDX) { Node child = node.getChild(pos); if (child.nodeType == NodeType.LEAF_NODE && leafMatch((LeafNode) child, key, dep)) { - //found matched leaf node from the current node. + // found matched leaf node from the current node. Node freshNode = node.remove(pos); keySize--; if (node == this.root && freshNode != node) { @@ -154,10 +158,11 @@ protected Toolkit removeSpecifyKey(Node node, byte[] key, int dep) { return toolkit; } else { Toolkit toolkit = removeSpecifyKey(child, key, dep + 1); - if (toolkit != null && toolkit.needToVerifyReplacing - && toolkit.freshMatchedParentNode != null && toolkit.freshMatchedParentNode - != toolkit.originalMatchedParentNode) { - //meaning find the matched key and the shrinking happened + if (toolkit != null + && toolkit.needToVerifyReplacing + && toolkit.freshMatchedParentNode != null + && toolkit.freshMatchedParentNode != toolkit.originalMatchedParentNode) { + // meaning find the matched key and the shrinking happened node.replaceNode(pos, toolkit.freshMatchedParentNode); toolkit.needToVerifyReplacing = false; return toolkit; @@ -172,11 +177,13 @@ protected Toolkit removeSpecifyKey(Node node, byte[] key, int dep) { class Toolkit { - Node freshMatchedParentNode;//indicating a fresh parent node while the original + Node freshMatchedParentNode; // indicating a fresh parent node while the original // parent node shrunk and changed - long matchedContainerId; //holding the matched key's corresponding container index id - Node originalMatchedParentNode; //holding the matched key's leaf node's original old parent node - boolean needToVerifyReplacing = false; //indicate whether the shrinking node's parent + long matchedContainerId; // holding the matched key's corresponding container index id + Node + originalMatchedParentNode; // holding the matched key's leaf node's original old parent node + boolean needToVerifyReplacing = false; // indicate whether the shrinking node's parent + // node has replaced its corresponding child node Toolkit(Node freshMatchedParentNode, long matchedContainerId, Node originalMatchedParentNode) { @@ -188,9 +195,14 @@ class Toolkit { private boolean leafMatch(LeafNode leafNode, byte[] key, int dep) { byte[] leafNodeKeyBytes = leafNode.getKeyBytes(); - int mismatchIndex = ArraysShim - .mismatch(leafNodeKeyBytes, dep, LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES, - key, dep, LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES); + int mismatchIndex = + ArraysShim.mismatch( + leafNodeKeyBytes, + dep, + LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES, + key, + dep, + LeafNode.LEAF_NODE_KEY_LENGTH_IN_BYTES); if (mismatchIndex == -1) { return true; } else { @@ -207,41 +219,41 @@ private Node insert(Node node, byte[] key, int depth, long containerIdx) { LeafNode leafNode = (LeafNode) node; byte[] prefix = leafNode.getKeyBytes(); int commonPrefix = commonPrefixLength(prefix, depth, prefix.length, key, depth, key.length); - //The leaf node maybe was shrunk from some other node type before and + // The leaf node maybe was shrunk from some other node type before and // contained an old prefixLength,so we reset it to 0 here. leafNode.prefixLength = 0; leafNode.prefix = EMPTY_BYTES; Node4 node4 = new Node4(commonPrefix); - //copy common prefix + // copy common prefix node4.prefixLength = (byte) commonPrefix; System.arraycopy(key, depth, node4.prefix, 0, commonPrefix); - //generate two leaf nodes as the children of the fresh node4 + // generate two leaf nodes as the children of the fresh node4 Node4.insert(node4, leafNode, prefix[depth + commonPrefix]); LeafNode anotherLeaf = new LeafNode(key, containerIdx); Node4.insert(node4, anotherLeaf, key[depth + commonPrefix]); - //replace the current node with this internal node4 + // replace the current node with this internal node4 return node4; } - //to a inner node case + // to a inner node case if (node.prefixLength > 0) { - //find the mismatch position - int mismatchPos = ArraysShim.mismatch(node.prefix, 0, node.prefixLength, - key, depth, key.length); + // find the mismatch position + int mismatchPos = + ArraysShim.mismatch(node.prefix, 0, node.prefixLength, key, depth, key.length); if (mismatchPos != node.prefixLength) { Node4 node4 = new Node4(mismatchPos); - //copy prefix + // copy prefix node4.prefixLength = (byte) mismatchPos; System.arraycopy(node.prefix, 0, node4.prefix, 0, mismatchPos); - //split the current internal node, spawn a fresh node4 and let the - //current internal node as its children. + // split the current internal node, spawn a fresh node4 and let the + // current internal node as its children. Node4.insert(node4, node, node.prefix[mismatchPos]); int nodeOriginalPrefixLength = node.prefixLength; node.prefixLength = (byte) (nodeOriginalPrefixLength - (mismatchPos + (byte) 1)); - //move the remained common prefix of the initial internal node + // move the remained common prefix of the initial internal node if (node.prefixLength > 0) { System.arraycopy(node.prefix, mismatchPos + 1, node.prefix, 0, node.prefixLength); } else { - //TODO:to reduce the 0 prefix memory space,we could mark the prefix as null + // TODO:to reduce the 0 prefix memory space,we could mark the prefix as null node.prefix = new byte[0]; } LeafNode leafNode = new LeafNode(key, containerIdx); @@ -252,7 +264,7 @@ private Node insert(Node node, byte[] key, int depth, long containerIdx) { } int pos = node.getChildPos(key[depth]); if (pos != Node.ILLEGAL_IDX) { - //insert the key as current internal node's children's child node. + // insert the key as current internal node's children's child node. Node child = node.getChild(pos); Node freshOne = insert(child, key, depth + 1, containerIdx); if (freshOne != child) { @@ -260,15 +272,15 @@ private Node insert(Node node, byte[] key, int depth, long containerIdx) { } return node; } - //insert the key as a child leaf node of the current internal node + // insert the key as a child leaf node of the current internal node LeafNode leafNode = new LeafNode(key, containerIdx); Node freshOne = Node.insertLeaf(node, leafNode, key[depth]); return freshOne; } - //find common prefix length - static int commonPrefixLength(byte[] key1, int aFromIndex, int aToIndex, - byte[] key2, int bFromIndex, int bToIndex) { + // find common prefix length + static int commonPrefixLength( + byte[] key1, int aFromIndex, int aToIndex, byte[] key2, int bFromIndex, int bToIndex) { int aLength = aToIndex - aFromIndex; int bLength = bToIndex - bFromIndex; int minLength = Math.min(aLength, bLength); @@ -284,10 +296,9 @@ public Node getRoot() { return root; } - private LeafNode getExtremeLeaf(boolean reverse) { Node parent = getRoot(); - for (int depth = 0 ; depth < AbstractShuttle.MAX_DEPTH ; depth++) { + for (int depth = 0; depth < AbstractShuttle.MAX_DEPTH; depth++) { if (parent.nodeType == NodeType.LEAF_NODE) { break; } @@ -336,36 +347,36 @@ public LeafNodeIterator leafNodeIteratorFrom(long bound, boolean reverse, Contai private void serialize(Node node, DataOutput dataOutput) throws IOException { if (node.nodeType != NodeType.LEAF_NODE) { - //serialize the internal node itself first + // serialize the internal node itself first node.serialize(dataOutput); - //then all the internal node's children + // then all the internal node's children int nexPos = node.getNextLargerPos(Node.ILLEGAL_IDX); while (nexPos != Node.ILLEGAL_IDX) { - //serialize all the not null child node + // serialize all the not null child node Node child = node.getChild(nexPos); serialize(child, dataOutput); nexPos = node.getNextLargerPos(nexPos); } } else { - //serialize the leaf node + // serialize the leaf node node.serialize(dataOutput); } } private void serialize(Node node, ByteBuffer byteBuffer) throws IOException { if (node.nodeType != NodeType.LEAF_NODE) { - //serialize the internal node itself first + // serialize the internal node itself first node.serialize(byteBuffer); - //then all the internal node's children + // then all the internal node's children int nexPos = node.getNextLargerPos(Node.ILLEGAL_IDX); while (nexPos != Node.ILLEGAL_IDX) { - //serialize all the not null child node + // serialize all the not null child node Node child = node.getChild(nexPos); serialize(child, byteBuffer); nexPos = node.getNextLargerPos(nexPos); } } else { - //serialize the leaf node + // serialize the leaf node node.serialize(byteBuffer); } } @@ -378,9 +389,9 @@ private Node deserialize(DataInput dataInput) throws IOException { if (oneNode.nodeType == NodeType.LEAF_NODE) { return oneNode; } else { - //internal node + // internal node int count = oneNode.count; - //all the not null child nodes + // all the not null child nodes Node[] children = new Node[count]; for (int i = 0; i < count; i++) { Node child = deserialize(dataInput); @@ -399,9 +410,9 @@ private Node deserialize(ByteBuffer byteBuffer) throws IOException { if (oneNode.nodeType == NodeType.LEAF_NODE) { return oneNode; } else { - //internal node + // internal node int count = oneNode.count; - //all the not null child nodes + // all the not null child nodes Node[] children = new Node[count]; for (int i = 0; i < count; i++) { Node child = deserialize(byteBuffer); @@ -422,13 +433,13 @@ public long getKeySize() { private long serializeSizeInBytes(Node node) { if (node.nodeType != NodeType.LEAF_NODE) { - //serialize the internal node itself first + // serialize the internal node itself first int currentNodeSize = node.serializeSizeInBytes(); - //then all the internal node's children + // then all the internal node's children long childrenTotalSize = 0L; int nexPos = node.getNextLargerPos(Node.ILLEGAL_IDX); while (nexPos != Node.ILLEGAL_IDX) { - //serialize all the not null child node + // serialize all the not null child node Node child = node.getChild(nexPos); long childSize = serializeSizeInBytes(child); nexPos = node.getNextLargerPos(nexPos); @@ -436,7 +447,7 @@ private long serializeSizeInBytes(Node node) { } return currentNodeSize + childrenTotalSize; } else { - //serialize the leaf node + // serialize the leaf node int nodeSize = node.serializeSizeInBytes(); return nodeSize; } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/BackwardShuttle.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/BackwardShuttle.java similarity index 83% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/BackwardShuttle.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/BackwardShuttle.java index 21287bf68..c9d7fab2d 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/BackwardShuttle.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/BackwardShuttle.java @@ -1,7 +1,5 @@ package org.roaringbitmap.art; -import org.roaringbitmap.longlong.LongUtils; - /** * visit the leaf node space in descending order */ @@ -12,8 +10,8 @@ public class BackwardShuttle extends AbstractShuttle { } @Override - protected boolean currentBeforeHigh(byte[] current, byte[] high) { - return LongUtils.compareHigh(current, high) > 0; + protected boolean currentBeforeHigh(long current, long high) { + return current > high; } @Override diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/ContainerIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/ContainerIterator.java similarity index 98% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/ContainerIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/ContainerIterator.java index f2e476257..36eeb6a21 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/ContainerIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/ContainerIterator.java @@ -1,8 +1,9 @@ package org.roaringbitmap.art; -import java.util.Iterator; import org.roaringbitmap.Container; +import java.util.Iterator; + public class ContainerIterator implements Iterator { private Containers containers; @@ -64,7 +65,6 @@ public boolean hasNext() { if (container != null) { currentContainer = container; consumedCurrent = false; - this.currentSecondLevelArrIteOver = false; currentSecondLevelArrIdx++; foundOneContainer = true; break; diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Containers.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Containers.java similarity index 98% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Containers.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Containers.java index 7665d0e6d..f9213b3b6 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Containers.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/Containers.java @@ -1,5 +1,10 @@ package org.roaringbitmap.art; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.RunContainer; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -7,11 +12,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.roaringbitmap.ArrayContainer; -import org.roaringbitmap.BitmapContainer; -import org.roaringbitmap.Container; -import org.roaringbitmap.RoaringBitmap; -import org.roaringbitmap.RunContainer; /** * To support the largest 2^48 different keys,we almost need 2^18 Container arrays which holds 2^31 @@ -62,7 +62,7 @@ public void remove(long containerIdx) { * @return the corresponding Container */ public Container getContainer(long idx) { - //split the idx into two part + // split the idx into two part int firstDimIdx = (int) (idx >>> 32); int secondDimIdx = (int) idx; Container[] containers = containerArrays.get(firstDimIdx); @@ -214,7 +214,7 @@ public void serialize(DataOutput dataOutput) throws IOException { Container[] containers = containerArrays.get(i); int secondLevelSize = containers.length; dataOutput.writeByte(NOT_TRIMMED_MARK); - //TODO:serialize the trimmed related data + // TODO:serialize the trimmed related data dataOutput.writeInt(Integer.reverseBytes(secondLevelSize)); for (int j = 0; j < containers.length; j++) { Container container = containers[j]; @@ -247,7 +247,7 @@ public void serialize(ByteBuffer byteBuffer) throws IOException { Container[] containers = containerArrays.get(i); int secondLevelSize = containers.length; byteBuffer.put(NOT_TRIMMED_MARK); - //TODO:serialize the trimmed related data + // TODO:serialize the trimmed related data byteBuffer.putInt(secondLevelSize); for (int j = 0; j < containers.length; j++) { Container container = containers[j]; @@ -277,7 +277,7 @@ public void deserialize(DataInput dataInput) throws IOException { int firstLevelSize = Integer.reverseBytes(dataInput.readInt()); ArrayList containersArray = new ArrayList<>(firstLevelSize); for (int i = 0; i < firstLevelSize; i++) { - //TODO:deserialize the trimmed related data + // TODO:deserialize the trimmed related data byte trimTag = dataInput.readByte(); int secondLevelSize = Integer.reverseBytes(dataInput.readInt()); Container[] containers = new Container[secondLevelSize]; @@ -312,7 +312,7 @@ public void deserialize(ByteBuffer byteBuffer) throws IOException { int firstLevelSize = byteBuffer.getInt(); ArrayList containersArray = new ArrayList<>(firstLevelSize); for (int i = 0; i < firstLevelSize; i++) { - //TODO:deserialize the trimmed related data + // TODO:deserialize the trimmed related data byte trimTag = byteBuffer.get(); int secondLevelSize = byteBuffer.getInt(); Container[] containers = new Container[secondLevelSize]; diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/ForwardShuttle.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/ForwardShuttle.java similarity index 83% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/ForwardShuttle.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/ForwardShuttle.java index 081165418..0f708d320 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/ForwardShuttle.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/ForwardShuttle.java @@ -1,7 +1,5 @@ package org.roaringbitmap.art; -import org.roaringbitmap.longlong.LongUtils; - /** * visit the leaf node space in ascending order. */ @@ -12,8 +10,8 @@ public class ForwardShuttle extends AbstractShuttle { } @Override - protected boolean currentBeforeHigh(byte[] current, byte[] high) { - return LongUtils.compareHigh(current, high) < 0; + protected boolean currentBeforeHigh(long current, long high) { + return current < high; } @Override diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/KeyIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/KeyIterator.java similarity index 82% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/KeyIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/KeyIterator.java index 1c5829445..65cb21259 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/KeyIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/KeyIterator.java @@ -26,10 +26,19 @@ public byte[] next() { return current.getKeyBytes(); } + public byte[] peekNext() { + return leafNodeIterator.peekNext().getKeyBytes(); + } + + public long nextKey() { + return current.getKey(); + } + public long currentContainerIdx() { return current.getContainerIdx(); } + @Override public void remove() { leafNodeIterator.remove(); } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/LeafNode.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/LeafNode.java similarity index 94% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/LeafNode.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/LeafNode.java index 7ba4d9a37..a8e805322 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/LeafNode.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/LeafNode.java @@ -1,15 +1,16 @@ package org.roaringbitmap.art; +import org.roaringbitmap.longlong.LongUtils; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.nio.ByteBuffer; -import org.roaringbitmap.longlong.LongUtils; public class LeafNode extends Node { - //key are saved as the lazy expanding logic,here we only care about the - //high 48 bit data,so only the high 48 bit is valuable + // key are saved as the lazy expanding logic,here we only care about the + // high 48 bit data,so only the high 48 bit is valuable private long key; long containerIdx; public static final int LEAF_NODE_KEY_LENGTH_IN_BYTES = 6; @@ -136,4 +137,8 @@ public long getContainerIdx() { public byte[] getKeyBytes() { return LongUtils.highPart(key); } + + public long getKey() { + return key >>> 16; + } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/LeafNodeIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/LeafNodeIterator.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/LeafNodeIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/LeafNodeIterator.java index 07e5dad0b..014a31cad 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/LeafNodeIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/LeafNodeIterator.java @@ -61,7 +61,6 @@ public LeafNodeIterator(Art art, boolean reverse, Containers containers, long fr calledHasNext = false; } - private boolean advance() { boolean hasLeafNode = shuttle.moveToNextLeaf(); if (hasLeafNode) { diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node.java similarity index 96% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Node.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Node.java index dbcaa31ea..37e505516 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node.java @@ -7,14 +7,14 @@ public abstract class Node { - //node type + // node type protected NodeType nodeType; - //length of compressed path(prefix) + // length of compressed path(prefix) protected byte prefixLength; - //the compressed path path (prefix) + // the compressed path path (prefix) protected byte[] prefix; - //number of non-null children, the largest value will not beyond 255 - //to benefit calculation,we keep the value as a short type + // number of non-null children, the largest value will not beyond 255 + // to benefit calculation,we keep the value as a short type protected short count; public static final int ILLEGAL_IDX = -1; @@ -34,7 +34,8 @@ public Node(NodeType nodeType, int compressedPrefixSize) { /** * sort the small arrays through the insertion sort alg. */ - protected static byte[] sortSmallByteArray(byte[] key, Node[] children, int left, int right) {//x + protected static byte[] sortSmallByteArray( + byte[] key, Node[] children, int left, int right) { // x for (int i = left, j = i; i < right; j = ++i) { byte ai = key[i + 1]; Node child = children[i + 1]; @@ -274,8 +275,7 @@ public static void copyPrefix(Node src, Node dst) { * @param k the target key byte value * @return the array offset of the target input key 'k' or -1 to not found */ - public static int binarySearch(byte[] key, int fromIndex, int toIndex, - byte k) { + public static int binarySearch(byte[] key, int fromIndex, int toIndex, byte k) { int inputUnsignedByte = Byte.toUnsignedInt(k); int low = fromIndex; int high = toIndex - 1; @@ -296,8 +296,7 @@ public static int binarySearch(byte[] key, int fromIndex, int toIndex, return ILLEGAL_IDX; } - static SearchResult binarySearchWithResult(byte[] key, int fromIndex, int toIndex, - byte k) { + static SearchResult binarySearchWithResult(byte[] key, int fromIndex, int toIndex, byte k) { int inputUnsignedByte = Byte.toUnsignedInt(k); int low = fromIndex; int high = toIndex - 1; @@ -324,9 +323,9 @@ static SearchResult binarySearchWithResult(byte[] key, int fromIndex, int toInde } private void serializeHeader(DataOutput dataOutput) throws IOException { - //first byte: node type + // first byte: node type dataOutput.writeByte((byte) this.nodeType.ordinal()); - //non null object count + // non null object count dataOutput.writeShort(Short.reverseBytes(this.count)); dataOutput.writeByte(this.prefixLength); if (prefixLength > 0) { diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node16.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node16.java similarity index 88% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Node16.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Node16.java index c12689679..189168dcb 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node16.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node16.java @@ -1,11 +1,12 @@ package org.roaringbitmap.art; +import org.roaringbitmap.longlong.LongUtils; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import org.roaringbitmap.longlong.LongUtils; public class Node16 extends Node { @@ -44,36 +45,37 @@ public SearchResult getNearestChildPos(byte k) { if (count <= 8) { return Node.binarySearchWithResult(firstBytes, 0, count, k); } else { - SearchResult firstResult = Node.binarySearchWithResult( - firstBytes, 0, 8, k); + SearchResult firstResult = Node.binarySearchWithResult(firstBytes, 0, 8, k); // given the values are "in order" if we found a match or a value larger than // the target we are done. - if (firstResult.outcome == SearchResult.Outcome.FOUND - || firstResult.hasNextLargerPos()) { + if (firstResult.outcome == SearchResult.Outcome.FOUND || firstResult.hasNextLargerPos()) { return firstResult; } else { byte[] secondBytes = LongUtils.toBDBytes(secondV); - SearchResult secondResult = Node.binarySearchWithResult( - secondBytes, 0, (count - 8), k); + SearchResult secondResult = Node.binarySearchWithResult(secondBytes, 0, (count - 8), k); - switch(secondResult.outcome) { + switch (secondResult.outcome) { case FOUND: return SearchResult.found(8 + secondResult.getKeyPos()); case NOT_FOUND: int lowPos = secondResult.getNextSmallerPos(); int highPos = secondResult.getNextLargerPos(); // don't map -1 into the legal range by adding 8! - if (lowPos>=0){ lowPos += 8;} - if (highPos>=0){ highPos += 8;} + if (lowPos >= 0) { + lowPos += 8; + } + if (highPos >= 0) { + highPos += 8; + } - if(firstResult.hasNextLargerPos() == false && secondResult.hasNextSmallerPos() == false) - { + if (firstResult.hasNextLargerPos() == false + && secondResult.hasNextSmallerPos() == false) { // this happens when the result is in the gap of the two ranges, the correct // "smaller value" is that of first result. lowPos = firstResult.getNextSmallerPos(); } - return SearchResult.notFound( lowPos, highPos); + return SearchResult.notFound(lowPos, highPos); default: throw new IllegalStateException("There only two possible search outcomes"); @@ -145,7 +147,7 @@ public int getNextSmallerPos(int pos) { public static Node insert(Node node, Node child, byte key) { Node16 currentNode16 = (Node16) node; if (currentNode16.count < 8) { - //first + // first byte[] bytes = LongUtils.toBDBytes(currentNode16.firstV); bytes[currentNode16.count] = key; currentNode16.children[currentNode16.count] = child; @@ -154,7 +156,7 @@ public static Node insert(Node node, Node child, byte key) { currentNode16.firstV = LongUtils.fromBDBytes(bytes); return currentNode16; } else if (currentNode16.count < 16) { - //second + // second ByteBuffer byteBuffer = ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN); byteBuffer.putLong(currentNode16.firstV); byteBuffer.putLong(currentNode16.secondV); @@ -169,7 +171,7 @@ public static Node insert(Node node, Node child, byte key) { Node48 node48 = new Node48(currentNode16.prefixLength); for (int i = 0; i < 8; i++) { int unsignedIdx = Byte.toUnsignedInt((byte) (currentNode16.firstV >>> ((7 - i) << 3))); - //i won't be beyond 48 + // i won't be beyond 48 Node48.setOneByte(unsignedIdx, (byte) i, node48.childIndex); node48.children[i] = currentNode16.children[i]; } @@ -177,7 +179,7 @@ public static Node insert(Node node, Node child, byte key) { for (int i = 8; i < currentNode16.count; i++) { byte v = secondBytes[i - 8]; int unsignedIdx = Byte.toUnsignedInt(v); - //i won't be beyond 48 + // i won't be beyond 48 Node48.setOneByte(unsignedIdx, (byte) i, node48.childIndex); node48.children[i] = currentNode16.children[i]; } @@ -199,9 +201,9 @@ public Node remove(int pos) { secondV = byteBuffer.getLong(8); count--; if (count <= 3) { - //shrink to node4 + // shrink to node4 Node4 node4 = new Node4(prefixLength); - //copy the keys + // copy the keys node4.key = (int) (firstV >> 32); System.arraycopy(children, 0, node4.children, 0, count); node4.count = count; @@ -213,7 +215,7 @@ public Node remove(int pos) { @Override public void serializeNodeBody(DataOutput dataOutput) throws IOException { - //little endian + // little endian dataOutput.writeLong(Long.reverseBytes(firstV)); dataOutput.writeLong(Long.reverseBytes(secondV)); } @@ -243,12 +245,6 @@ public int serializeNodeBodySizeInBytes() { @Override public void replaceChildren(Node[] children) { - int pos = this.getNextLargerPos(ILLEGAL_IDX); - int offset = 0; - while (pos != ILLEGAL_IDX) { - this.children[pos] = children[offset]; - pos = this.getNextLargerPos(pos); - offset++; - } + System.arraycopy(children, 0, this.children, 0, count); } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node256.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node256.java similarity index 93% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Node256.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Node256.java index de4cf1cf6..c23757b5c 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node256.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node256.java @@ -11,11 +11,10 @@ public class Node256 extends Node { Node[] children = new Node[256]; - //a helper utility field + // a helper utility field long[] bitmapMask = new long[4]; private static final long LONG_MASK = 0xffffffffffffffffL; - public Node256(int compressedPrefixSize) { super(NodeType.NODE256, compressedPrefixSize); } @@ -57,13 +56,11 @@ public void replaceNode(int pos, Node freshOne) { public int getMinPos() { for (int i = 0; i < 4; i++) { long longVal = bitmapMask[i]; - int v = Long.numberOfTrailingZeros(longVal); - if (v == 64) { + if (longVal == 0) { continue; - } else { - int res = i * 64 + v; - return res; } + int v = Long.numberOfTrailingZeros(longVal); + return i * 64 + v; } return ILLEGAL_IDX; } @@ -95,13 +92,11 @@ public int getNextLargerPos(int pos) { public int getMaxPos() { for (int i = 3; i >= 0; i--) { long longVal = bitmapMask[i]; - int v = Long.numberOfLeadingZeros(longVal); - if (v == 64) { + if (longVal == 0) { continue; - } else { - int res = i * 64 + (63 - v); - return res; } + int v = Long.numberOfLeadingZeros(longVal); + return i * 64 + (63 - v); } return ILLEGAL_IDX; } @@ -179,25 +174,25 @@ public Node remove(int pos) { @Override public void replaceChildren(Node[] children) { if (children.length == this.children.length) { - //short circuit path + // short circuit path this.children = children; return; } int offset = 0; int x = 0; for (long longv : bitmapMask) { - int w = Long.bitCount(longv); - for (int i = 0; i < w; i++) { + int w = 0; + while (longv != 0) { int pos = x * 64 + numberOfTrailingZeros(longv); - this.children[pos] = children[offset + i]; + this.children[pos] = children[offset + w]; longv &= (longv - 1); + w++; } offset += w; x++; } } - @Override public void serializeNodeBody(DataOutput dataOutput) throws IOException { for (long longv : bitmapMask) { @@ -232,4 +227,3 @@ public int serializeNodeBodySizeInBytes() { return 4 * 8; } } - diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node4.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node4.java similarity index 93% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Node4.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Node4.java index 434453611..048faa7bc 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node4.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node4.java @@ -1,11 +1,12 @@ package org.roaringbitmap.art; +import org.roaringbitmap.longlong.IntegerUtil; +import org.roaringbitmap.longlong.LongUtils; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.nio.ByteBuffer; -import org.roaringbitmap.longlong.IntegerUtil; -import org.roaringbitmap.longlong.LongUtils; public class Node4 extends Node { @@ -90,14 +91,14 @@ public int getNextSmallerPos(int pos) { public static Node insert(Node node, Node childNode, byte key) { Node4 current = (Node4) node; if (current.count < 4) { - //insert leaf into current node + // insert leaf into current node current.key = IntegerUtil.setByte(current.key, key, current.count); current.children[current.count] = childNode; current.count++; insertionSort(current); return current; } else { - //grow to Node16 + // grow to Node16 Node16 node16 = new Node16(current.prefixLength); node16.count = 4; node16.firstV = LongUtils.initWithFirst4Byte(current.key); @@ -118,7 +119,7 @@ public Node remove(int pos) { children[pos] = children[pos + 1]; } if (count == 1) { - //shrink to the child node + // shrink to the child node Node child = children[0]; byte newLength = (byte) (child.prefixLength + this.prefixLength + 1); byte[] newPrefix = new byte[newLength]; @@ -164,16 +165,9 @@ public int serializeNodeBodySizeInBytes() { return 4; } - @Override public void replaceChildren(Node[] children) { - int pos = getNextLargerPos(ILLEGAL_IDX); - int offset = 0; - while (pos != ILLEGAL_IDX) { - this.children[pos] = children[offset]; - pos = getNextLargerPos(pos); - offset++; - } + System.arraycopy(children, 0, this.children, 0, count); } /** diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node48.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node48.java similarity index 90% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Node48.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Node48.java index 87d25e1fb..5a9616419 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Node48.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/Node48.java @@ -7,11 +7,10 @@ import java.nio.ByteOrder; import java.nio.LongBuffer; import java.util.Arrays; -import org.roaringbitmap.longlong.LongUtils; public class Node48 extends Node { - //the actual byte value of childIndex content won't be beyond 48 + // the actual byte value of childIndex content won't be beyond 48 // 256 bytes packed into longs static final int BYTES_PER_LONG = 8; static final int LONGS_USED = 256 / BYTES_PER_LONG; @@ -19,7 +18,7 @@ public class Node48 extends Node { static final int POS_MASK = 0x7; // the mask to access the pos in the long for the byte long[] childIndex = new long[LONGS_USED]; Node[] children = new Node[48]; - static final byte EMPTY_VALUE = (byte)0xFF; + static final byte EMPTY_VALUE = (byte) 0xFF; static final long INIT_LONG_VALUE = 0xFFffFFffFFffFFffL; public Node48(int compressedPrefixSize) { @@ -71,7 +70,7 @@ public int getMinPos() { for (int i = 0; i < LONGS_USED; i++) { long longv = childIndex[i]; if (longv == INIT_LONG_VALUE) { - //skip over empty bytes + // skip over empty bytes pos += BYTES_PER_LONG; continue; } else { @@ -97,7 +96,7 @@ public int getNextLargerPos(int pos) { for (; i < LONGS_USED; i++) { long longv = childIndex[i]; if (longv == INIT_LONG_VALUE) { - //skip over empty bytes + // skip over empty bytes pos = (pos + BYTES_PER_LONG) & 0xF8; continue; } @@ -148,8 +147,8 @@ public int getNextSmallerPos(int pos) { for (; i >= 0 && i < LONGS_USED; i--) { long longv = childIndex[i]; if (longv == INIT_LONG_VALUE) { - //skip over empty bytes - pos -= Math.min(BYTES_PER_LONG,(pos & POS_MASK) + 1); + // skip over empty bytes + pos -= Math.min(BYTES_PER_LONG, (pos & POS_MASK) + 1); continue; } // because we are starting potentially at non aligned location, we need to start at 7 @@ -177,7 +176,7 @@ public int getNextSmallerPos(int pos) { public static Node insert(Node currentNode, Node child, byte key) { Node48 node48 = (Node48) currentNode; if (node48.count < 48) { - //insert leaf node into current node + // insert leaf node into current node int pos = node48.count; if (node48.children[pos] != null) { pos = 0; @@ -187,11 +186,11 @@ public static Node insert(Node currentNode, Node child, byte key) { } node48.children[pos] = child; int unsignedByte = Byte.toUnsignedInt(key); - setOneByte(unsignedByte, (byte)pos, node48.childIndex); + setOneByte(unsignedByte, (byte) pos, node48.childIndex); node48.count++; return node48; } else { - //grow to Node256 + // grow to Node256 Node256 node256 = new Node256(node48.prefixLength); int currentPos = ILLEGAL_IDX; while ((currentPos = node48.getNextLargerPos(currentPos)) != ILLEGAL_IDX) { @@ -213,7 +212,7 @@ public Node remove(int pos) { children[idx] = null; count--; if (count <= 12) { - //shrink to node16 + // shrink to node16 Node16 node16 = new Node16(this.prefixLength); int j = 0; ByteBuffer byteBuffer = ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN); @@ -268,16 +267,18 @@ public int serializeNodeBodySizeInBytes() { } @Override - public void replaceChildren(Node[] children) { + void replaceChildren(Node[] children) { int step = 0; for (int i = 0; i < LONGS_USED; i++) { - long longv = childIndex[i]; - for (int j = BYTES_PER_LONG - 1; j >= 0; j--) { - byte bytePos = (byte) (longv >>> (j << INDEX_SHIFT)); - int unsignedPos = Byte.toUnsignedInt(bytePos); - if (bytePos != EMPTY_VALUE) { - this.children[unsignedPos] = children[step]; - step++; + long longv = Long.reverseBytes(childIndex[i]); + if (longv != INIT_LONG_VALUE) { + for (int j = 0; j < BYTES_PER_LONG; j++) { + long currentByte = longv & 0xFF; + if (currentByte != 0xFF) { + this.children[(int) currentByte] = children[step]; + step++; + } + longv >>>= 8; } } } diff --git a/roaringbitmap/src/main/java/org/roaringbitmap/art/NodeType.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/NodeType.java new file mode 100644 index 000000000..1a73dd2c2 --- /dev/null +++ b/roaringbitmap/src/main/java/org/roaringbitmap/art/NodeType.java @@ -0,0 +1,10 @@ +package org.roaringbitmap.art; + +public enum NodeType { + NODE4, + NODE16, + NODE48, + NODE256, + LEAF_NODE, + DUMMY_ROOT; +} diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/SearchResult.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/SearchResult.java similarity index 100% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/SearchResult.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/SearchResult.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/art/Shuttle.java b/roaringbitmap/src/main/java/org/roaringbitmap/art/Shuttle.java similarity index 100% rename from RoaringBitmap/src/main/java/org/roaringbitmap/art/Shuttle.java rename to roaringbitmap/src/main/java/org/roaringbitmap/art/Shuttle.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ArrayBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/ArrayBatchIterator.java similarity index 82% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ArrayBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/ArrayBatchIterator.java index 44cd4a42a..075e1633c 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ArrayBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/ArrayBatchIterator.java @@ -1,12 +1,11 @@ package org.roaringbitmap.buffer; +import static org.roaringbitmap.buffer.BufferUtil.unsignedBinarySearch; + import org.roaringbitmap.ContainerBatchIterator; import java.nio.CharBuffer; -import static org.roaringbitmap.buffer.BufferUtil.unsignedBinarySearch; - - public final class ArrayBatchIterator implements ContainerBatchIterator { private int index = 0; @@ -17,11 +16,11 @@ public ArrayBatchIterator(MappeableArrayContainer array) { } @Override - public int next(int key, int[] buffer) { + public int next(int key, int[] buffer, int offset) { int consumed = 0; CharBuffer data = array.content; - while (consumed < buffer.length && index < array.getCardinality()) { - buffer[consumed++] = key + (data.get(index++)); + while ((offset + consumed) < buffer.length && index < array.getCardinality()) { + buffer[offset + consumed++] = key + (data.get(index++)); } return consumed; } @@ -34,7 +33,7 @@ public boolean hasNext() { @Override public ContainerBatchIterator clone() { try { - return (ContainerBatchIterator)super.clone(); + return (ContainerBatchIterator) super.clone(); } catch (CloneNotSupportedException e) { // won't happen throw new IllegalStateException(e); diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BitmapBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BitmapBatchIterator.java similarity index 69% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BitmapBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/BitmapBatchIterator.java index 4411d6d65..28475871f 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BitmapBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BitmapBatchIterator.java @@ -1,9 +1,9 @@ package org.roaringbitmap.buffer; -import org.roaringbitmap.ContainerBatchIterator; - import static java.lang.Long.numberOfTrailingZeros; +import org.roaringbitmap.ContainerBatchIterator; + public final class BitmapBatchIterator implements ContainerBatchIterator { private int wordIndex = 0; @@ -15,9 +15,9 @@ public BitmapBatchIterator(MappeableBitmapContainer bitmap) { } @Override - public int next(int key, int[] buffer) { + public int next(int key, int[] buffer, int offset) { int consumed = 0; - while (consumed < buffer.length) { + while ((offset + consumed) < buffer.length) { while (word == 0) { ++wordIndex; if (wordIndex == 1024) { @@ -25,7 +25,7 @@ public int next(int key, int[] buffer) { } word = bitmap.bitmap.get(wordIndex); } - buffer[consumed++] = key + (64 * wordIndex) + numberOfTrailingZeros(word); + buffer[offset + consumed++] = key + (64 * wordIndex) + numberOfTrailingZeros(word); word &= (word - 1); } return consumed; @@ -33,13 +33,23 @@ public int next(int key, int[] buffer) { @Override public boolean hasNext() { - return wordIndex < 1024; + if (wordIndex > 1023) { + return false; + } + while (word == 0) { + ++wordIndex; + if (wordIndex == 1024) { // reached end without a non-empty word + return false; + } + word = bitmap.bitmap.get(wordIndex); + } + return true; // found some non-empty word, so hasNext } @Override public ContainerBatchIterator clone() { try { - return (ContainerBatchIterator)super.clone(); + return (ContainerBatchIterator) super.clone(); } catch (CloneNotSupportedException e) { // won't happen throw new IllegalStateException(e); @@ -63,5 +73,4 @@ void wrap(MappeableBitmapContainer bitmap) { this.word = bitmap.bitmap.get(0); this.wordIndex = 0; } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferBitSetUtil.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferBitSetUtil.java similarity index 78% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferBitSetUtil.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferBitSetUtil.java index 78192dcc6..b95370b69 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferBitSetUtil.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferBitSetUtil.java @@ -1,6 +1,5 @@ package org.roaringbitmap.buffer; - import org.roaringbitmap.BitSetUtil; import org.roaringbitmap.IntIterator; @@ -10,9 +9,6 @@ import java.nio.LongBuffer; import java.util.BitSet; -import static java.lang.Long.numberOfTrailingZeros; - - /*** * * This class provides convenience functions to manipulate BitSet and MutableRoaringBitmap objects. @@ -23,27 +19,17 @@ public class BufferBitSetUtil { // a block consists has a maximum of 1024 words, each representing 64 bits, // thus representing at maximum 65536 bits - static final private int BLOCK_LENGTH = MappeableBitmapContainer.MAX_CAPACITY / Long.SIZE; // + private static final int BLOCK_LENGTH = MappeableBitmapContainer.MAX_CAPACITY / Long.SIZE; // + // 64-bit // word - private static MappeableArrayContainer arrayContainerOf(final int from, final int to, - final int cardinality, final long[] words) { - // precondition: cardinality is max 4096 - final char[] content = new char[cardinality]; - int index = 0; - - for (int i = from, socket = 0; i < to; ++i, socket += Long.SIZE) { - long word = words[i]; - while (word != 0) { - content[index++] = (char) (socket + numberOfTrailingZeros(word)); - word &= (word - 1); - } - } + private static MappeableArrayContainer arrayContainerOf( + final int from, final int to, final int cardinality, final long[] words) { + char[] content = BitSetUtil.arrayContainerBufferOf(from, to, cardinality, words); return new MappeableArrayContainer(CharBuffer.wrap(content), cardinality); } - /** * Generate a MutableRoaringBitmap out of a BitSet * @@ -71,9 +57,11 @@ public static MutableRoaringBitmap bitmapOf(final long[] words) { final int to = Math.min(from + BLOCK_LENGTH, words.length); final int blockCardinality = cardinality(from, to, words); if (blockCardinality > 0) { - ((MutableRoaringArray) ans.highLowContainer).insertNewKeyValueAt(containerIndex++, - BufferUtil.highbits(from * Long.SIZE), - BufferBitSetUtil.containerOf(from, to, blockCardinality, words)); + ((MutableRoaringArray) ans.highLowContainer) + .insertNewKeyValueAt( + containerIndex++, + BufferUtil.highbits(from * Long.SIZE), + BufferBitSetUtil.containerOf(from, to, blockCardinality, words)); } } return ans; @@ -125,14 +113,16 @@ public static MutableRoaringBitmap bitmapOf(ByteBuffer bb, long[] wordsBuffer) { if (blockLength == BLOCK_LENGTH) { // Each block becomes a single container, if any bit is set if (blockCardinality > 0) { - ((MutableRoaringArray) ans.highLowContainer).insertNewKeyValueAt(containerIndex++, - BufferUtil.highbits(offset), BufferBitSetUtil.containerOf(0, blockLength, - blockCardinality, wordsBuffer)); + ((MutableRoaringArray) ans.highLowContainer) + .insertNewKeyValueAt( + containerIndex++, + BufferUtil.highbits(offset), + BufferBitSetUtil.containerOf(0, blockLength, blockCardinality, wordsBuffer)); } /* - Offset can overflow when bitsets size is more than Integer.MAX_VALUE - 64 - It's harmless though, as it will happen after the last block is added - */ + Offset can overflow when bitsets size is more than Integer.MAX_VALUE - 64 + It's harmless though, as it will happen after the last block is added + */ offset += (BLOCK_LENGTH * Long.SIZE); blockLength = blockCardinality = 0; } @@ -155,9 +145,11 @@ public static MutableRoaringBitmap bitmapOf(ByteBuffer bb, long[] wordsBuffer) { // Add block to map, if any bit is set if (blockCardinality > 0) { - ((MutableRoaringArray) ans.highLowContainer).insertNewKeyValueAt(containerIndex, - BufferUtil.highbits(offset), - BufferBitSetUtil.containerOf(0, blockLength, blockCardinality, wordsBuffer)); + ((MutableRoaringArray) ans.highLowContainer) + .insertNewKeyValueAt( + containerIndex, + BufferUtil.highbits(offset), + BufferBitSetUtil.containerOf(0, blockLength, blockCardinality, wordsBuffer)); } return ans; } @@ -170,9 +162,8 @@ private static int cardinality(final int from, final int to, final long[] words) return sum; } - - private static MappeableContainer containerOf(final int from, final int to, - final int blockCardinality, final long[] words) { + private static MappeableContainer containerOf( + final int from, final int to, final int blockCardinality, final long[] words) { // find the best container available if (blockCardinality <= MappeableArrayContainer.DEFAULT_MAX_SIZE) { // containers with DEFAULT_MAX_SIZE or less integers should be @@ -186,7 +177,6 @@ private static MappeableContainer containerOf(final int from, final int to, } } - /** * Compares a RoaringBitmap and a BitSet. They are equal if and only if they contain the same set * of integers. diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferFastAggregation.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferFastAggregation.java similarity index 81% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferFastAggregation.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferFastAggregation.java index 7d3ef7c4b..616969943 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferFastAggregation.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferFastAggregation.java @@ -4,21 +4,26 @@ package org.roaringbitmap.buffer; +import org.roaringbitmap.BitSetUtil; import org.roaringbitmap.Util; import java.nio.CharBuffer; import java.nio.LongBuffer; -import java.util.*; - +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.PriorityQueue; /** * Fast algorithms to aggregate many bitmaps. - * + * * @author Daniel Lemire */ public final class BufferFastAggregation { - /** * Compute the AND aggregate. * @@ -40,10 +45,10 @@ public static MutableRoaringBitmap and(ImmutableRoaringBitmap... bitmaps) { * @param bitmaps input bitmaps * @return aggregated bitmap */ - public static MutableRoaringBitmap and(long[] aggregationBuffer, - ImmutableRoaringBitmap... bitmaps) { + public static MutableRoaringBitmap and( + long[] aggregationBuffer, ImmutableRoaringBitmap... bitmaps) { if (bitmaps.length > 10) { - if(aggregationBuffer.length < 1024) { + if (aggregationBuffer.length < 1024) { throw new IllegalArgumentException("buffer should have at least 1024 elements."); } try { @@ -57,7 +62,7 @@ public static MutableRoaringBitmap and(long[] aggregationBuffer, /** * Compute the AND aggregate. - * + * * In practice, calls {#link workShyAnd} * * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap) @@ -76,8 +81,8 @@ public static MutableRoaringBitmap and(Iterator bitmaps) { + public static MutableRoaringBitmap and( + long[] aggregationBuffer, Iterator bitmaps) { if (bitmaps.hasNext()) { try { return workShyAnd(aggregationBuffer, bitmaps); @@ -88,12 +93,11 @@ public static MutableRoaringBitmap and(long[] aggregationBuffer, return new MutableRoaringBitmap(); } - /** * Compute the AND aggregate. - * + * * In practice, calls {#link naive_and} - * + * * @param bitmaps input bitmaps * @return aggregated bitmap */ @@ -141,7 +145,7 @@ public static int orCardinality(ImmutableRoaringBitmap... bitmaps) { /** * Convenience method converting one type of iterator into another, to avoid unnecessary warnings. - * + * * @param i input bitmaps * @return an iterator over the provided iterator, with a different type */ @@ -160,12 +164,8 @@ public ImmutableRoaringBitmap next() { } @Override - public void remove() { - - } - + public void remove() {} }; - } private static ImmutableRoaringBitmap[] convertToImmutable(MutableRoaringBitmap[] array) { @@ -174,12 +174,11 @@ private static ImmutableRoaringBitmap[] convertToImmutable(MutableRoaringBitmap[ return answer; } - /** * Minimizes memory usage while computing the or aggregate on a moderate number of bitmaps. - * + * * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps. - * + * * @param bitmaps input bitmaps * @return aggregated bitmap * @see #or(ImmutableRoaringBitmap...) @@ -234,10 +233,9 @@ public static MutableRoaringBitmap horizontal_or(ImmutableRoaringBitmap... bitma return answer; } - /** * Calls naive_or. - * + * * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap) * @return aggregated bitmap */ @@ -248,9 +246,9 @@ public static MutableRoaringBitmap horizontal_or(@SuppressWarnings("rawtypes") I /** * Minimizes memory usage while computing the or aggregate on a moderate number of bitmaps. - * + * * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps. - * + * * @param bitmaps input bitmaps * @return aggregated bitmap * @see #or(ImmutableRoaringBitmap...) @@ -259,12 +257,11 @@ public static MutableRoaringBitmap horizontal_or(MutableRoaringBitmap... bitmaps return horizontal_or(convertToImmutable(bitmaps)); } - /** * Minimizes memory usage while computing the xor aggregate on a moderate number of bitmaps. - * + * * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps. - * + * * @param bitmaps input bitmaps * @return aggregated bitmap * @see #xor(ImmutableRoaringBitmap...) @@ -320,9 +317,9 @@ public static MutableRoaringBitmap horizontal_xor(ImmutableRoaringBitmap... bitm /** * Minimizes memory usage while computing the xor aggregate on a moderate number of bitmaps. - * + * * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps. - * + * * @param bitmaps input bitmaps * @return aggregated bitmap * @see #xor(ImmutableRoaringBitmap...) @@ -331,14 +328,13 @@ public static MutableRoaringBitmap horizontal_xor(MutableRoaringBitmap... bitmap return horizontal_xor(convertToImmutable(bitmaps)); } - /** * Compute overall AND between bitmaps two-by-two. * * Performance hint: if you have very large and tiny bitmaps, * it may be beneficial performance-wise to put a tiny bitmap * in first position. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps @@ -374,7 +370,7 @@ public static MutableRoaringBitmap naive_and(ImmutableRoaringBitmap... bitmaps) * Performance hint: if you have very large and tiny bitmaps, * it may be beneficial performance-wise to put a tiny bitmap * in first position. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap) @@ -398,7 +394,7 @@ public static MutableRoaringBitmap naive_and(@SuppressWarnings("rawtypes") Itera * Performance hint: if you have very large and tiny bitmaps, * it may be beneficial performance-wise to put a tiny bitmap * in first position. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps @@ -423,42 +419,15 @@ public static MutableRoaringBitmap naive_and(MutableRoaringBitmap... bitmaps) { * @param bitmaps the inputs * @return the intersection of the bitmaps */ - static MutableRoaringBitmap workShyAnd(long[] aggregationBuffer, - ImmutableRoaringBitmap... bitmaps) { + static MutableRoaringBitmap workShyAnd( + long[] aggregationBuffer, ImmutableRoaringBitmap... bitmaps) { long[] words = aggregationBuffer; - ImmutableRoaringBitmap first = bitmaps[0]; - for (int i = 0; i < first.highLowContainer.size(); ++i) { - char key = first.highLowContainer.getKeyAtIndex(i); - words[key >>> 6] |= 1L << key; - } - int numContainers = first.highLowContainer.size(); - for (int i = 1; i < bitmaps.length && numContainers > 0; ++i) { - final char[] keys; - if (bitmaps[i].highLowContainer instanceof MutableRoaringArray) { - keys = ((MutableRoaringArray) bitmaps[i].highLowContainer).keys; - } else { - keys = new char[bitmaps[i].highLowContainer.size()]; - for (int j = 0; j < keys.length; ++j) { - keys[j] = bitmaps[i].highLowContainer.getKeyAtIndex(j); - } - } - numContainers = BufferUtil.intersectArrayIntoBitmap(words, - CharBuffer.wrap(keys), - bitmaps[i].highLowContainer.size()); - } - if (numContainers == 0) { + char[] keys = BufferUtil.intersectKeys(words, bitmaps); + if (keys.length == 0) { return new MutableRoaringBitmap(); } - char[] keys = new char[numContainers]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } + int numContainers = keys.length; + MappeableContainer[][] containers = new MappeableContainer[numContainers][bitmaps.length]; for (int i = 0; i < bitmaps.length; ++i) { ImmutableRoaringBitmap bitmap = bitmaps[i]; @@ -472,12 +441,15 @@ static MutableRoaringBitmap workShyAnd(long[] aggregationBuffer, } MutableRoaringArray array = - new MutableRoaringArray(keys, new MappeableContainer[numContainers], 0); + new MutableRoaringArray(keys, new MappeableContainer[numContainers], 0); for (int i = 0; i < numContainers; ++i) { MappeableContainer[] slice = containers[i]; Arrays.fill(words, -1L); MappeableContainer tmp = new MappeableBitmapContainer(LongBuffer.wrap(words), -1); for (MappeableContainer container : slice) { + // We only assign to 'tmp' when 'tmp != tmp.iand(container)' + // as a garbage-collection optimization: we want to avoid + // the write barrier. (Richard Startin) MappeableContainer and = tmp.iand(container); if (and != tmp) { tmp = and; @@ -499,8 +471,8 @@ static MutableRoaringBitmap workShyAnd(long[] aggregationBuffer, * @param bitmaps the inputs * @return the intersection of the bitmaps */ - static MutableRoaringBitmap workShyAnd(long[] aggregationBuffer, - Iterator bitmaps) { + static MutableRoaringBitmap workShyAnd( + long[] aggregationBuffer, Iterator bitmaps) { long[] words = aggregationBuffer; List collected = new ArrayList<>(); ImmutableRoaringBitmap first = bitmaps.next(); @@ -524,23 +496,15 @@ static MutableRoaringBitmap workShyAnd(long[] aggregationBuffer, keys[j] = bitmap.highLowContainer.getKeyAtIndex(j); } } - numContainers = BufferUtil.intersectArrayIntoBitmap(words, - CharBuffer.wrap(keys), - bitmap.highLowContainer.size()); + numContainers = + BufferUtil.intersectArrayIntoBitmap( + words, CharBuffer.wrap(keys), bitmap.highLowContainer.size()); } if (numContainers == 0) { return new MutableRoaringBitmap(); } - char[] keys = new char[numContainers]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } + char[] keys = BitSetUtil.arrayContainerBufferOf(0, words.length, numContainers, words); + MappeableContainer[][] containers = new MappeableContainer[numContainers][bitmapCount]; for (int i = 0; i < bitmapCount; ++i) { ImmutableRoaringBitmap bitmap = collected.get(i); @@ -554,12 +518,15 @@ static MutableRoaringBitmap workShyAnd(long[] aggregationBuffer, } MutableRoaringArray array = - new MutableRoaringArray(keys, new MappeableContainer[numContainers], 0); + new MutableRoaringArray(keys, new MappeableContainer[numContainers], 0); for (int i = 0; i < numContainers; ++i) { MappeableContainer[] slice = containers[i]; Arrays.fill(words, -1L); MappeableContainer tmp = new MappeableBitmapContainer(LongBuffer.wrap(words), -1); for (MappeableContainer container : slice) { + // We only assign to 'tmp' when 'tmp != tmp.iand(container)' + // as a garbage-collection optimization: we want to avoid + // the write barrier. (Richard Startin) MappeableContainer and = tmp.iand(container); if (and != tmp) { tmp = and; @@ -575,39 +542,10 @@ static MutableRoaringBitmap workShyAnd(long[] aggregationBuffer, private static int workShyAndCardinality(ImmutableRoaringBitmap... bitmaps) { long[] words = new long[1024]; - ImmutableRoaringBitmap first = bitmaps[0]; - for (int i = 0; i < first.highLowContainer.size(); ++i) { - char key = first.highLowContainer.getKeyAtIndex(i); - words[key >>> 6] |= 1L << key; - } - int numKeys = first.highLowContainer.size(); - for (int i = 1; i < bitmaps.length && numKeys > 0; ++i) { - final char[] keys; - if (bitmaps[i].highLowContainer instanceof MutableRoaringArray) { - keys = ((MutableRoaringArray) bitmaps[i].highLowContainer).keys; - } else { - keys = new char[bitmaps[i].highLowContainer.size()]; - for (int j = 0; j < keys.length; ++j) { - keys[j] = bitmaps[i].highLowContainer.getKeyAtIndex(j); - } - } - numKeys = BufferUtil.intersectArrayIntoBitmap(words, - CharBuffer.wrap(keys), - bitmaps[i].highLowContainer.size()); - } - if (numKeys == 0) { + char[] keys = BufferUtil.intersectKeys(words, bitmaps); + if (keys.length == 0) { return 0; } - char[] keys = new char[numKeys]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } LongBuffer longBuffer = LongBuffer.wrap(words); int cardinality = 0; @@ -620,6 +558,9 @@ private static int workShyAndCardinality(ImmutableRoaringBitmap... bitmaps) { continue; } MappeableContainer container = bitmap.highLowContainer.getContainerAtIndex(index); + // We only assign to 'tmp' when 'tmp != tmp.iand(container)' + // as a garbage-collection optimization: we want to avoid + // the write barrier. (Richard Startin) MappeableContainer and = tmp.iand(container); if (and != tmp) { tmp = and; @@ -643,16 +584,7 @@ private static int horizontalOrCardinality(ImmutableRoaringBitmap... bitmaps) { } } int numKeys = Util.cardinalityInBitmapRange(words, minKey, maxKey + 1); - char[] keys = new char[numKeys]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } + char[] keys = BitSetUtil.arrayContainerBufferOf(0, words.length, numKeys, words); LongBuffer longBuffer = LongBuffer.wrap(words); int cardinality = 0; @@ -679,7 +611,7 @@ private static int horizontalOrCardinality(ImmutableRoaringBitmap... bitmaps) { * Computes the intersection by first intersecting the keys, avoids * materialising containers, limits memory usage. You must provide a long[] array * of length at least 1024, initialized with zeroes. We do not check whether the array - * is initialized with zeros: it is the caller's responsability. + * is initialized with zeros: it is the caller's responsability. * You should expect this function to be slower than workShyAnd and the reduction * in memory usage might be small. * @@ -687,57 +619,33 @@ private static int horizontalOrCardinality(ImmutableRoaringBitmap... bitmaps) { * @param bitmaps the inputs * @return the intersection of the bitmaps */ - public static MutableRoaringBitmap workAndMemoryShyAnd(long[] buffer, - ImmutableRoaringBitmap... bitmaps) { - if(buffer.length < 1024) { + public static MutableRoaringBitmap workAndMemoryShyAnd( + long[] buffer, ImmutableRoaringBitmap... bitmaps) { + if (buffer.length < 1024) { throw new IllegalArgumentException("buffer should have at least 1024 elements."); - } - long[] words = buffer; - ImmutableRoaringBitmap first = bitmaps[0]; - for (int i = 0; i < first.highLowContainer.size(); ++i) { - char key = first.highLowContainer.getKeyAtIndex(i); - words[key >>> 6] |= 1L << key; - } - int numContainers = first.highLowContainer.size(); - for (int i = 1; i < bitmaps.length && numContainers > 0; ++i) { - final char[] keys; - if (bitmaps[i].highLowContainer instanceof MutableRoaringArray) { - keys = ((MutableRoaringArray) bitmaps[i].highLowContainer).keys; - } else { - keys = new char[bitmaps[i].highLowContainer.size()]; - for (int j = 0; j < keys.length; ++j) { - keys[j] = bitmaps[i].highLowContainer.getKeyAtIndex(j); - } - } - numContainers = BufferUtil.intersectArrayIntoBitmap(words, - CharBuffer.wrap(keys), - bitmaps[i].highLowContainer.size()); } - if (numContainers == 0) { + long[] words = buffer; + char[] keys = BufferUtil.intersectKeys(words, bitmaps); + if (keys.length == 0) { return new MutableRoaringBitmap(); } - char[] keys = new char[numContainers]; - int base = 0; - int pos = 0; - for (long word : words) { - while (word != 0L) { - keys[pos++] = (char)(base + Long.numberOfTrailingZeros(word)); - word &= (word - 1); - } - base += 64; - } + int numContainers = keys.length; + MutableRoaringArray array = - new MutableRoaringArray(keys, new MappeableContainer[numContainers], 0); + new MutableRoaringArray(keys, new MappeableContainer[numContainers], 0); for (int i = 0; i < numContainers; ++i) { char MatchingKey = keys[i]; Arrays.fill(words, -1L); MappeableContainer tmp = new MappeableBitmapContainer(LongBuffer.wrap(words), -1); - for(ImmutableRoaringBitmap bitmap: bitmaps) { + for (ImmutableRoaringBitmap bitmap : bitmaps) { int idx = bitmap.highLowContainer.getIndex(MatchingKey); - if(idx < 0) { + if (idx < 0) { continue; } MappeableContainer container = bitmap.highLowContainer.getContainerAtIndex(idx); + // We only assign to 'tmp' when 'tmp != tmp.iand(container)' + // as a garbage-collection optimization: we want to avoid + // the write barrier. (Richard Startin) MappeableContainer and = tmp.iand(container); if (and != tmp) { tmp = and; @@ -753,7 +661,7 @@ public static MutableRoaringBitmap workAndMemoryShyAnd(long[] buffer, /** * Compute overall OR between bitmaps two-by-two. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps @@ -770,7 +678,7 @@ public static MutableRoaringBitmap naive_or(ImmutableRoaringBitmap... bitmaps) { /** * Compute overall OR between bitmaps two-by-two. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap) @@ -785,8 +693,6 @@ public static MutableRoaringBitmap naive_or(@SuppressWarnings("rawtypes") Iterat return answer; } - - /** * Compute overall OR between bitmaps two-by-two. * @@ -806,7 +712,7 @@ public static MutableRoaringBitmap naive_or(MutableRoaringBitmap... bitmaps) { /** * Compute overall XOR between bitmaps two-by-two. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps @@ -822,7 +728,7 @@ public static MutableRoaringBitmap naive_xor(ImmutableRoaringBitmap... bitmaps) /** * Compute overall XOR between bitmaps two-by-two. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap) @@ -836,10 +742,9 @@ public static MutableRoaringBitmap naive_xor(@SuppressWarnings("rawtypes") Itera return answer; } - /** * Compute overall XOR between bitmaps two-by-two. - * + * * This function runs in linear time with respect to the number of bitmaps. * * @param bitmaps input bitmaps @@ -853,7 +758,6 @@ public static MutableRoaringBitmap naive_xor(MutableRoaringBitmap... bitmaps) { return answer; } - /** * Compute overall OR between bitmaps. * @@ -864,7 +768,6 @@ public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) { return naive_or(bitmaps); } - /** * Compute overall OR between bitmaps. * @@ -887,9 +790,9 @@ public static MutableRoaringBitmap or(MutableRoaringBitmap... bitmaps) { /** * Uses a priority queue to compute the or aggregate. - * + * * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps. - * + * * @param bitmaps input bitmaps * @return aggregated bitmap * @see #horizontal_or(ImmutableRoaringBitmap...) @@ -907,12 +810,15 @@ public static MutableRoaringBitmap priorityqueue_or(ImmutableRoaringBitmap... bi for (int k = 0; k < sizes.length; ++k) { sizes[k] = buffer[k].serializedSizeInBytes(); } - PriorityQueue pq = new PriorityQueue<>(128, new Comparator() { - @Override - public int compare(Integer a, Integer b) { - return sizes[a] - sizes[b]; - } - }); + PriorityQueue pq = + new PriorityQueue<>( + 128, + new Comparator() { + @Override + public int compare(Integer a, Integer b) { + return sizes[a] - sizes[b]; + } + }); for (int k = 0; k < sizes.length; ++k) { pq.add(k); } @@ -920,8 +826,9 @@ public int compare(Integer a, Integer b) { Integer x1 = pq.poll(); Integer x2 = pq.poll(); if (istmp[x1] && istmp[x2]) { - buffer[x1] = MutableRoaringBitmap.lazyorfromlazyinputs((MutableRoaringBitmap) buffer[x1], - (MutableRoaringBitmap) buffer[x2]); + buffer[x1] = + MutableRoaringBitmap.lazyorfromlazyinputs( + (MutableRoaringBitmap) buffer[x1], (MutableRoaringBitmap) buffer[x2]); sizes[x1] = buffer[x1].serializedSizeInBytes(); pq.add(x1); } else if (istmp[x2]) { @@ -946,9 +853,9 @@ public int compare(Integer a, Integer b) { /** * Uses a priority queue to compute the or aggregate. - * + * * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps. - * + * * @param bitmaps input bitmaps * @return aggregated bitmap * @see #horizontal_or(ImmutableRoaringBitmap...) @@ -968,12 +875,15 @@ public static MutableRoaringBitmap priorityqueue_or( for (int k = 0; k < sizes.length; ++k) { sizes[k] = buffer.get(k).getLongSizeInBytes(); } - PriorityQueue pq = new PriorityQueue<>(128, new Comparator() { - @Override - public int compare(Integer a, Integer b) { - return (int)(sizes[a] - sizes[b]); - } - }); + PriorityQueue pq = + new PriorityQueue<>( + 128, + new Comparator() { + @Override + public int compare(Integer a, Integer b) { + return (int) (sizes[a] - sizes[b]); + } + }); for (int k = 0; k < sizes.length; ++k) { pq.add(k); } @@ -984,8 +894,10 @@ public int compare(Integer a, Integer b) { Integer x1 = pq.poll(); Integer x2 = pq.poll(); if (istmp[x1] && istmp[x2]) { - buffer.set(x1, MutableRoaringBitmap.lazyorfromlazyinputs( - (MutableRoaringBitmap) buffer.get(x1), (MutableRoaringBitmap) buffer.get(x2))); + buffer.set( + x1, + MutableRoaringBitmap.lazyorfromlazyinputs( + (MutableRoaringBitmap) buffer.get(x1), (MutableRoaringBitmap) buffer.get(x2))); sizes[x1] = buffer.get(x1).getLongSizeInBytes(); pq.add(x1); } else if (istmp[x2]) { @@ -1010,9 +922,9 @@ public int compare(Integer a, Integer b) { /** * Uses a priority queue to compute the xor aggregate. - * + * * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps. - * + * * @param bitmaps input bitmaps * @return aggregated bitmap * @see #horizontal_xor(ImmutableRoaringBitmap...) @@ -1023,12 +935,14 @@ public static MutableRoaringBitmap priorityqueue_xor(ImmutableRoaringBitmap... b throw new IllegalArgumentException("Expecting at least 2 bitmaps"); } final PriorityQueue pq = - new PriorityQueue<>(bitmaps.length, new Comparator() { - @Override - public int compare(ImmutableRoaringBitmap a, ImmutableRoaringBitmap b) { - return (int)(a.getLongSizeInBytes() - b.getLongSizeInBytes()); - } - }); + new PriorityQueue<>( + bitmaps.length, + new Comparator() { + @Override + public int compare(ImmutableRoaringBitmap a, ImmutableRoaringBitmap b) { + return (int) (a.getLongSizeInBytes() - b.getLongSizeInBytes()); + } + }); Collections.addAll(pq, bitmaps); while (pq.size() > 1) { final ImmutableRoaringBitmap x1 = pq.poll(); @@ -1038,10 +952,9 @@ public int compare(ImmutableRoaringBitmap a, ImmutableRoaringBitmap b) { return (MutableRoaringBitmap) pq.poll(); } - /** * Compute overall XOR between bitmaps. - * + * * * @param bitmaps input bitmaps * @return aggregated bitmap @@ -1050,7 +963,6 @@ public static MutableRoaringBitmap xor(ImmutableRoaringBitmap... bitmaps) { return naive_xor(bitmaps); } - /** * Compute overall XOR between bitmaps. * @@ -1061,10 +973,9 @@ public static MutableRoaringBitmap xor(@SuppressWarnings("rawtypes") Iterator bi return naive_xor(bitmaps); } - /** * Compute overall XOR between bitmaps. - * + * * * @param bitmaps input bitmaps * @return aggregated bitmap @@ -1076,8 +987,5 @@ public static MutableRoaringBitmap xor(MutableRoaringBitmap... bitmaps) { /** * Private constructor to prevent instantiation of utility class */ - private BufferFastAggregation() { - - } - + private BufferFastAggregation() {} } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferIntIteratorFlyweight.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferIntIteratorFlyweight.java similarity index 96% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferIntIteratorFlyweight.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferIntIteratorFlyweight.java index 2868333d7..cf2604c48 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferIntIteratorFlyweight.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferIntIteratorFlyweight.java @@ -10,7 +10,7 @@ /** * Fast iterator minimizing the stress on the garbage collector. You can create one reusable * instance of this class and then {@link #wrap(ImmutableRoaringBitmap)} - * + * * For better performance, consider the {@link ImmutableRoaringBitmap#forEach} method. * * @author Borislav Ivanov @@ -28,7 +28,6 @@ public class BufferIntIteratorFlyweight implements PeekableIntIterator { private MappeableRunContainerCharIterator runIter = new MappeableRunContainerCharIterator(); - private int pos; private ImmutableRoaringBitmap roaringBitmap = null; @@ -37,13 +36,11 @@ public class BufferIntIteratorFlyweight implements PeekableIntIterator { * Creates an instance that is not ready for iteration. You must first call * {@link #wrap(ImmutableRoaringBitmap)}. */ - public BufferIntIteratorFlyweight() { - - } + public BufferIntIteratorFlyweight() {} /** * Creates an instance that is ready for iteration. - * + * * @param r bitmap to be iterated over */ public BufferIntIteratorFlyweight(ImmutableRoaringBitmap r) { @@ -54,12 +51,12 @@ public BufferIntIteratorFlyweight(ImmutableRoaringBitmap r) { public PeekableIntIterator clone() { try { BufferIntIteratorFlyweight x = (BufferIntIteratorFlyweight) super.clone(); - if(this.iter != null) { + if (this.iter != null) { x.iter = this.iter.clone(); } return x; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -100,7 +97,7 @@ private void nextContainer() { /** * Prepares a bitmap for iteration - * + * * @param r bitmap to be iterated over */ public void wrap(ImmutableRoaringBitmap r) { @@ -129,6 +126,4 @@ public void advanceIfNeeded(int minval) { public int peekNext() { return (iter.peekNext()) | hs; } - - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferParallelAggregation.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferParallelAggregation.java similarity index 83% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferParallelAggregation.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferParallelAggregation.java index a04d3b699..0e6ea1b5d 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferParallelAggregation.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferParallelAggregation.java @@ -1,7 +1,14 @@ package org.roaringbitmap.buffer; import java.nio.LongBuffer; -import java.util.*; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.function.BiConsumer; @@ -40,9 +47,9 @@ */ public class BufferParallelAggregation { - private static final Collector>, - MutableRoaringArray, MutableRoaringBitmap> - XOR = new ContainerCollector(BufferParallelAggregation::xor); + private static final Collector< + Map.Entry>, MutableRoaringArray, MutableRoaringBitmap> + XOR = new ContainerCollector(BufferParallelAggregation::xor); private static final OrCollector OR = new OrCollector(); @@ -50,9 +57,11 @@ public class BufferParallelAggregation { * Collects containers grouped by their key into a RoaringBitmap, applying the * supplied aggregation function to each group. */ - public static class ContainerCollector implements - Collector>, - MutableRoaringArray, MutableRoaringBitmap> { + public static class ContainerCollector + implements Collector< + Map.Entry>, + MutableRoaringArray, + MutableRoaringBitmap> { private final Function, MappeableContainer> reducer; @@ -70,8 +79,8 @@ public Supplier supplier() { } @Override - public BiConsumer< - MutableRoaringArray, Map.Entry>> accumulator() { + public BiConsumer>> + accumulator() { return (l, r) -> { assert l.size == 0 || l.keys[l.size - 1] < r.getKey(); MappeableContainer container = reducer.apply(r.getValue()); @@ -105,7 +114,7 @@ public Set characteristics() { * Collects a list of containers into a single container. */ public static class OrCollector - implements Collector, MappeableContainer, MappeableContainer> { + implements Collector, MappeableContainer, MappeableContainer> { @Override public Supplier supplier() { @@ -139,7 +148,7 @@ public Set characteristics() { * @return The containers from the bitmaps grouped by key */ public static SortedMap> groupByKey( - ImmutableRoaringBitmap... bitmaps) { + ImmutableRoaringBitmap... bitmaps) { Map> grouped = new HashMap<>(); for (ImmutableRoaringBitmap bitmap : bitmaps) { MappeableContainerPointer it = bitmap.highLowContainer.getContainerPointer(); @@ -174,8 +183,8 @@ public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) { slices.add(slice.getValue()); } IntStream.range(0, i) - .parallel() - .forEach(position -> values[position] = or(slices.get(position))); + .parallel() + .forEach(position -> values[position] = or(slices.get(position))); return new MutableRoaringBitmap(new MutableRoaringArray(keys, values, i)); } @@ -185,14 +194,9 @@ public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) { * @return the symmetric difference of the bitmaps */ public static MutableRoaringBitmap xor(ImmutableRoaringBitmap... bitmaps) { - return groupByKey(bitmaps) - .entrySet() - .parallelStream() - .collect(XOR); + return groupByKey(bitmaps).entrySet().parallelStream().collect(XOR); } - - private static MappeableContainer xor(List containers) { MappeableContainer result = containers.get(0).clone(); for (int i = 1; i < containers.size(); ++i) { @@ -223,17 +227,17 @@ private static MappeableContainer or(List containers) { int step = Math.floorDiv(containers.size(), parallelism); int mod = Math.floorMod(containers.size(), parallelism); return IntStream.range(0, parallelism) - .parallel() - .mapToObj(i -> containers.subList(i * step + Math.min(i, mod), - (i + 1) * step + Math.min(i + 1, mod))) - .collect(OR); + .parallel() + .mapToObj( + i -> + containers.subList( + i * step + Math.min(i, mod), (i + 1) * step + Math.min(i + 1, mod))) + .collect(OR); } private static int availableParallelism() { return ForkJoinTask.inForkJoinPool() - ? ForkJoinTask.getPool().getParallelism() - : ForkJoinPool.getCommonPoolParallelism(); + ? ForkJoinTask.getPool().getParallelism() + : ForkJoinPool.getCommonPoolParallelism(); } - } - diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java similarity index 95% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java index 2caa7bc52..fed549b63 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java @@ -10,9 +10,9 @@ /** * Fast iterator minimizing the stress on the garbage collector. You can create one reusable * instance of this class and then {@link #wrap(ImmutableRoaringBitmap)} - * + * * This iterator enumerates the stored values in reverse (starting from the end). - * + * * @author Borislav Ivanov **/ public class BufferReverseIntIteratorFlyweight implements IntIterator { @@ -34,18 +34,15 @@ public class BufferReverseIntIteratorFlyweight implements IntIterator { private ImmutableRoaringBitmap roaringBitmap = null; - /** * Creates an instance that is not ready for iteration. You must first call * {@link #wrap(ImmutableRoaringBitmap)}. */ - public BufferReverseIntIteratorFlyweight() { - - } + public BufferReverseIntIteratorFlyweight() {} /** * Creates an instance that is ready for iteration. - * + * * @param r bitmap to be iterated over */ public BufferReverseIntIteratorFlyweight(ImmutableRoaringBitmap r) { @@ -56,12 +53,12 @@ public BufferReverseIntIteratorFlyweight(ImmutableRoaringBitmap r) { public IntIterator clone() { try { BufferReverseIntIteratorFlyweight x = (BufferReverseIntIteratorFlyweight) super.clone(); - if(this.iter != null) { + if (this.iter != null) { x.iter = this.iter.clone(); } return x; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -70,8 +67,6 @@ public boolean hasNext() { return pos >= 0; } - - @Override public int next() { final int x = iter.nextAsInt() | hs; @@ -105,7 +100,7 @@ private void nextContainer() { /** * Prepares a bitmap for iteration - * + * * @param r bitmap to be iterated over */ public void wrap(ImmutableRoaringBitmap r) { @@ -114,5 +109,4 @@ public void wrap(ImmutableRoaringBitmap r) { this.pos = (short) (this.roaringBitmap.highLowContainer.size() - 1); this.nextContainer(); } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferUtil.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferUtil.java similarity index 78% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferUtil.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferUtil.java index 80055274d..22f3ea15e 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/BufferUtil.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/BufferUtil.java @@ -4,6 +4,9 @@ package org.roaringbitmap.buffer; +import static java.lang.Long.numberOfTrailingZeros; + +import org.roaringbitmap.BitSetUtil; import org.roaringbitmap.Util; import java.nio.Buffer; @@ -12,8 +15,6 @@ import java.nio.LongBuffer; import java.util.Arrays; -import static java.lang.Long.numberOfTrailingZeros; - /** * Various useful methods for roaring bitmaps. * @@ -30,73 +31,106 @@ public final class BufferUtil { * @param offsets value to add to each value in the container * @return return an array made of two containers */ - public static MappeableContainer[] addOffset(MappeableContainer source, char offsets) { - // could be a whole lot faster, this is a simple implementation - if(source instanceof MappeableArrayContainer) { - MappeableArrayContainer c = (MappeableArrayContainer) source; - MappeableArrayContainer low = new MappeableArrayContainer(c.cardinality); - MappeableArrayContainer high = new MappeableArrayContainer(c.cardinality); - for(int k = 0; k < c.cardinality; k++) { - int val = (c.content.get(k)); - val += (int) (offsets); - if(val <= 0xFFFF) { - low.content.put(low.cardinality++, (char) val); - } else { - high.content.put(high.cardinality++, (char) val); - } - } - return new MappeableContainer[] {low, high}; + public static MappeableContainer[] addOffset(MappeableContainer source, char offsets) { + if (source instanceof MappeableArrayContainer) { + return addOffsetArray((MappeableArrayContainer) source, offsets); } else if (source instanceof MappeableBitmapContainer) { - MappeableBitmapContainer c = (MappeableBitmapContainer) source; - MappeableBitmapContainer low = new MappeableBitmapContainer(); - MappeableBitmapContainer high = new MappeableBitmapContainer(); - low.cardinality = -1; - high.cardinality = -1; - final int b = (int) (offsets) >>> 6; - final int i = (int) (offsets) % 64; - if(i == 0) { - for(int k = 0; k < 1024 - b; k++) { - low.bitmap.put(b + k, c.bitmap.get(k)); - } - for(int k = 1024 - b; k < 1024 ; k++) { - high.bitmap.put(k - (1024 - b),c.bitmap.get(k)); - } - } else { - low.bitmap.put(b + 0, c.bitmap.get(0) << i); - for(int k = 1; k < 1024 - b; k++) { - low.bitmap.put(b + k, (c.bitmap.get(k) << i) - | (c.bitmap.get(k - 1) >>> (64-i))); - } - for(int k = 1024 - b; k < 1024 ; k++) { - high.bitmap.put(k - (1024 - b), - (c.bitmap.get(k) << i) - | (c.bitmap.get(k - 1) >>> (64-i))); - } - high.bitmap.put(b, (c.bitmap.get(1024 - 1) >>> (64-i))); - } - return new MappeableContainer[] {low.repairAfterLazy(), high.repairAfterLazy()}; + return addOffsetBitmap((MappeableBitmapContainer) source, offsets); } else if (source instanceof MappeableRunContainer) { - MappeableRunContainer c = (MappeableRunContainer) source; - MappeableRunContainer low = new MappeableRunContainer(); - MappeableRunContainer high = new MappeableRunContainer(); - for(int k = 0 ; k < c.nbrruns; k++) { - int val = (c.getValue(k)); - val += (int) (offsets); - int finalval = val + (c.getLength(k)); - if(val <= 0xFFFF) { - if(finalval <= 0xFFFF) { - low.smartAppend((char)val,c.getLength(k)); - } else { - low.smartAppend((char)val,(char)(0xFFFF-val)); - high.smartAppend((char) 0,(char)finalval); - } + return addOffsetRun((MappeableRunContainer) source, offsets); + } + throw new RuntimeException("unknown container type"); // never happens + } + + private static MappeableContainer[] addOffsetArray(MappeableArrayContainer source, char offsets) { + int splitIndex; + if (source.first() + offsets > 0xFFFF) { + splitIndex = 0; + } else if (source.last() + offsets < 0xFFFF) { + splitIndex = source.cardinality; + } else { + splitIndex = + BufferUtil.unsignedBinarySearch( + source.content, 0, source.cardinality, (char) (0x10000 - offsets)); + if (splitIndex < 0) { + splitIndex = -splitIndex - 1; + } + } + MappeableArrayContainer low = + splitIndex == 0 ? new MappeableArrayContainer() : new MappeableArrayContainer(splitIndex); + MappeableArrayContainer high = + source.cardinality - splitIndex == 0 + ? new MappeableArrayContainer() + : new MappeableArrayContainer(source.cardinality - splitIndex); + + int lowCardinality = 0; + for (int k = 0; k < splitIndex; k++) { + int val = source.content.get(k) + offsets; + low.content.put(lowCardinality++, (char) val); + } + low.cardinality = lowCardinality; + + int highCardinality = 0; + for (int k = splitIndex; k < source.cardinality; k++) { + int val = source.content.get(k) + offsets; + high.content.put(highCardinality++, (char) val); + } + high.cardinality = highCardinality; + + return new MappeableContainer[] {low, high}; + } + + private static MappeableContainer[] addOffsetBitmap( + MappeableBitmapContainer source, char offsets) { + MappeableBitmapContainer c = source; + MappeableBitmapContainer low = new MappeableBitmapContainer(); + MappeableBitmapContainer high = new MappeableBitmapContainer(); + low.cardinality = -1; + high.cardinality = -1; + final int b = (int) offsets >>> 6; + final int i = (int) offsets % 64; + if (i == 0) { + for (int k = 0; k < 1024 - b; k++) { + low.bitmap.put(b + k, c.bitmap.get(k)); + } + for (int k = 1024 - b; k < 1024; k++) { + high.bitmap.put(k - (1024 - b), c.bitmap.get(k)); + } + } else { + //noinspection PointlessArithmeticExpression + low.bitmap.put(b + 0, c.bitmap.get(0) << i); + for (int k = 1; k < 1024 - b; k++) { + low.bitmap.put(b + k, (c.bitmap.get(k) << i) | (c.bitmap.get(k - 1) >>> (64 - i))); + } + for (int k = 1024 - b; k < 1024; k++) { + high.bitmap.put( + k - (1024 - b), (c.bitmap.get(k) << i) | (c.bitmap.get(k - 1) >>> (64 - i))); + } + high.bitmap.put(b, (c.bitmap.get(1024 - 1) >>> (64 - i))); + } + return new MappeableContainer[] {low.repairAfterLazy(), high.repairAfterLazy()}; + } + + private static MappeableContainer[] addOffsetRun(MappeableRunContainer source, char offsets) { + MappeableRunContainer c = source; + MappeableRunContainer low = new MappeableRunContainer(); + MappeableRunContainer high = new MappeableRunContainer(); + for (int k = 0; k < c.nbrruns; k++) { + int val = c.getValue(k); + val += offsets; + int finalval = val + c.getLength(k); + if (val <= 0xFFFF) { + if (finalval <= 0xFFFF) { + low.smartAppend((char) val, c.getLength(k)); } else { - high.smartAppend((char)val,c.getLength(k)); + low.smartAppend((char) val, (char) (0xFFFF - val)); + high.smartAppend((char) 0, (char) finalval); } + } else { + high.smartAppend((char) val, c.getLength(k)); } - return new MappeableContainer[] {low, high}; } - throw new RuntimeException("unknown container type"); // never happens + return new MappeableContainer[] {low, high}; } /** @@ -121,8 +155,7 @@ protected static int advanceUntil(CharBuffer array, int pos, int length, char mi int spansize = 1; // could set larger // bootstrap an upper limit - while (lower + spansize < length - && (array.get(lower + spansize)) < (min)) { + while (lower + spansize < length && (array.get(lower + spansize)) < (min)) { spansize *= 2; // hoping for compiler will reduce to } // shift @@ -135,7 +168,7 @@ protected static int advanceUntil(CharBuffer array, int pos, int length, char mi return upper; } - if ((array.get(upper)) < (min)) {// means + if ((array.get(upper)) < (min)) { // means // array // has no // item @@ -161,7 +194,6 @@ protected static int advanceUntil(CharBuffer array, int pos, int length, char mi } } return upper; - } /** @@ -182,9 +214,8 @@ public static int iterateUntil(CharBuffer array, int pos, int length, int min) { return pos; } - - protected static void arraycopy(CharBuffer src, int srcPos, CharBuffer dest, int destPos, - int length) { + protected static void arraycopy( + CharBuffer src, int srcPos, CharBuffer dest, int destPos, int length) { if (BufferUtil.isBackedBySimpleArray(src) && BufferUtil.isBackedBySimpleArray(dest)) { System.arraycopy(src.array(), srcPos, dest.array(), destPos, length); } else { @@ -200,8 +231,8 @@ protected static void arraycopy(CharBuffer src, int srcPos, CharBuffer dest, int } } - protected static int branchyUnsignedBinarySearch(final CharBuffer array, final int begin, - final int end, final char k) { + protected static int branchyUnsignedBinarySearch( + final CharBuffer array, final int begin, final int end, final char k) { // next line accelerates the possibly common case where the value would be inserted at the end if ((end > 0) && ((array.get(end - 1)) < (int) (k))) { return -end - 1; @@ -223,18 +254,17 @@ protected static int branchyUnsignedBinarySearch(final CharBuffer array, final i return -(low + 1); } - - protected static int branchyUnsignedBinarySearch(final ByteBuffer array, int position, - final int begin, final int end, final char k) { + protected static int branchyUnsignedBinarySearch( + final ByteBuffer array, int position, final int begin, final int end, final char k) { // next line accelerates the possibly common case where the value would be inserted at the end - if ((end > 0) && ((array.getChar(position + (end - 1)*2)) < (int) (k))) { + if ((end > 0) && ((array.getChar(position + (end - 1) * 2)) < (int) (k))) { return -end - 1; } int low = begin; int high = end - 1; while (low <= high) { final int middleIndex = (low + high) >>> 1; - final int middleValue = (array.getChar(position + 2* middleIndex)); + final int middleValue = (array.getChar(position + 2 * middleIndex)); if (middleValue < (int) (k)) { low = middleIndex + 1; @@ -309,7 +339,7 @@ protected static void fillArrayXOR(char[] container, LongBuffer bitmap1, LongBuf throw new IllegalArgumentException("not supported"); } if (BufferUtil.isBackedBySimpleArray(bitmap1) && BufferUtil.isBackedBySimpleArray(bitmap2)) { - org.roaringbitmap.Util.fillArrayXOR(container, bitmap1.array(), bitmap2.array()); + org.roaringbitmap.Util.fillArrayXOR(container, bitmap1.array(), bitmap2.array()); } else { int len = bitmap1.limit(); for (int k = 0; k < len; ++k) { @@ -322,7 +352,6 @@ protected static void fillArrayXOR(char[] container, LongBuffer bitmap1, LongBuf } } - /** * flip bits at start, start+1,..., end-1 * @@ -347,7 +376,6 @@ public static void flipBitmapRange(LongBuffer bitmap, int start, int end) { bitmap.put(endword, bitmap.get(endword) ^ (~0L >>> -end)); } - /** * Hamming weight of the 64-bit words involved in the range start, start+1,..., end-1 * that is, it will compute the cardinality of the bitset from index @@ -404,7 +432,6 @@ public static int cardinalityInBitmapRange(LongBuffer bitmap, int start, int end return answer; } - /** * set bits at start, start+1,..., end-1 and report the cardinality change * @@ -424,7 +451,6 @@ public static int setBitmapRangeAndCardinalityChange(LongBuffer bitmap, int star return cardafter - cardbefore; } - /** * flip bits at start, start+1,..., end-1 and report the cardinality change * @@ -444,7 +470,6 @@ public static int flipBitmapRangeAndCardinalityChange(LongBuffer bitmap, int sta return cardafter - cardbefore; } - /** * reset bits at start, start+1,..., end-1 and report the cardinality change * @@ -474,8 +499,8 @@ public static int resetBitmapRangeAndCardinalityChange(LongBuffer bitmap, int st * * @return the size in bytes */ - protected static int getSizeInBytesFromCardinalityEtc(int card, int numRuns, - boolean isRunEncoded) { + protected static int getSizeInBytesFromCardinalityEtc( + int card, int numRuns, boolean isRunEncoded) { if (isRunEncoded) { return 2 + numRuns * 2 * 2; // each run uses 2 chars, plus the initial char giving num runs } @@ -485,14 +510,12 @@ protected static int getSizeInBytesFromCardinalityEtc(int card, int numRuns, } else { return card * 2; } - } protected static char highbits(int x) { return (char) (x >>> 16); } - protected static char highbits(long x) { return (char) (x >>> 16); } @@ -519,7 +542,7 @@ protected static char lowbits(long x) { } protected static int lowbitsAsInteger(long x) { - return (int)(x & 0xFFFF); + return (int) (x & 0xFFFF); } protected static char maxLowBit() { @@ -558,7 +581,6 @@ public static void resetBitmapRange(LongBuffer bitmap, int start, int end) { bitmap.put(endword, bitmap.get(endword) & (~(~0L >>> -end))); } - /** * set bits at start, start+1,..., end-1 * @@ -599,10 +621,11 @@ public static void setBitmapRange(LongBuffer bitmap, int start, int end) { * @param k value we search for * @return count */ - public static int unsignedBinarySearch(final CharBuffer array, final int begin, final int end, - final char k) { + public static int unsignedBinarySearch( + final CharBuffer array, final int begin, final int end, final char k) { return branchyUnsignedBinarySearch(array, begin, end, k); } + /** * Look for value k in buffer in the range [begin,end). If the value is found, return its index. * If not, return -(i+1) where i is the index where the value would be inserted. The buffer is @@ -615,13 +638,17 @@ public static int unsignedBinarySearch(final CharBuffer array, final int begin, * @param k value we search for * @return count */ - public static int unsignedBinarySearch(final ByteBuffer array, int position, - final int begin, final int end, final char k) { + public static int unsignedBinarySearch( + final ByteBuffer array, int position, final int begin, final int end, final char k) { return branchyUnsignedBinarySearch(array, position, begin, end, k); } - protected static int unsignedDifference(final CharBuffer set1, final int length1, - final CharBuffer set2, final int length2, final char[] buffer) { + protected static int unsignedDifference( + final CharBuffer set1, + final int length1, + final CharBuffer set2, + final int length2, + final char[] buffer) { int pos = 0; int k1 = 0, k2 = 0; if (0 == length2) { @@ -654,7 +681,7 @@ protected static int unsignedDifference(final CharBuffer set1, final int length1 } s1 = set1.get(k1); s2 = set2.get(k2); - } else {// if (val1>val2) + } else { // if (val1>val2) ++k2; if (k2 >= length2) { set1.position(k1); @@ -667,7 +694,6 @@ protected static int unsignedDifference(final CharBuffer set1, final int length1 return pos; } - /** * Intersects the bitmap with the array, returning the cardinality of the result * @param bitmap the bitmap, modified @@ -745,8 +771,12 @@ public static int intersectArrayIntoBitmap(LongBuffer bitmap, CharBuffer array, return cardinality; } - protected static int unsignedExclusiveUnion2by2(final CharBuffer set1, final int length1, - final CharBuffer set2, final int length2, final char[] buffer) { + protected static int unsignedExclusiveUnion2by2( + final CharBuffer set1, + final int length1, + final CharBuffer set2, + final int length2, + final char[] buffer) { int pos = 0; int k1 = 0, k2 = 0; if (0 == length2) { @@ -784,7 +814,7 @@ protected static int unsignedExclusiveUnion2by2(final CharBuffer set1, final int } s1 = set1.get(k1); s2 = set2.get(k2); - } else {// if (val1>val2) + } else { // if (val1>val2) buffer[pos++] = s2; ++k2; if (k2 >= length2) { @@ -798,9 +828,12 @@ protected static int unsignedExclusiveUnion2by2(final CharBuffer set1, final int // return pos; } - - protected static int unsignedIntersect2by2(final CharBuffer set1, final int length1, - final CharBuffer set2, final int length2, final char[] buffer) { + protected static int unsignedIntersect2by2( + final CharBuffer set1, + final int length1, + final CharBuffer set2, + final int length2, + final char[] buffer) { final int THRESHOLD = 34; if (length1 * THRESHOLD < length2) { return unsignedOneSidedGallopingIntersect2by2(set1, length1, set2, length2, buffer); @@ -820,8 +853,8 @@ protected static int unsignedIntersect2by2(final CharBuffer set1, final int leng * @param length2 length of second array * @return true if they intersect */ - public static boolean unsignedIntersects(CharBuffer set1, int length1, CharBuffer set2, - int length2) { + public static boolean unsignedIntersects( + CharBuffer set1, int length1, CharBuffer set2, int length2) { if ((0 == length1) || (0 == length2)) { return false; } @@ -832,7 +865,8 @@ public static boolean unsignedIntersects(CharBuffer set1, int length1, CharBuffe char s1 = set1.get(k1); char s2 = set2.get(k2); - mainwhile: while (true) { + mainwhile: + while (true) { if (s2 < s1) { do { ++k2; @@ -857,8 +891,12 @@ public static boolean unsignedIntersects(CharBuffer set1, int length1, CharBuffe return false; } - protected static int unsignedLocalIntersect2by2(final CharBuffer set1, final int length1, - final CharBuffer set2, final int length2, final char[] buffer) { + protected static int unsignedLocalIntersect2by2( + final CharBuffer set1, + final int length1, + final CharBuffer set2, + final int length2, + final char[] buffer) { if ((0 == length1) || (0 == length2)) { return 0; } @@ -868,7 +906,8 @@ protected static int unsignedLocalIntersect2by2(final CharBuffer set1, final int char s1 = set1.get(k1); char s2 = set2.get(k2); - mainwhile: while (true) { + mainwhile: + while (true) { if (s2 < s1) { do { ++k2; @@ -901,14 +940,13 @@ protected static int unsignedLocalIntersect2by2(final CharBuffer set1, final int break; } s2 = set2.get(k2); - } } return pos; } - protected static int unsignedLocalIntersect2by2Cardinality(final CharBuffer set1, - final int length1, final CharBuffer set2, final int length2) { + protected static int unsignedLocalIntersect2by2Cardinality( + final CharBuffer set1, final int length1, final CharBuffer set2, final int length2) { if ((0 == length1) || (0 == length2)) { return 0; } @@ -918,7 +956,8 @@ protected static int unsignedLocalIntersect2by2Cardinality(final CharBuffer set1 char s1 = set1.get(k1); char s2 = set2.get(k2); - mainwhile: while (true) { + mainwhile: + while (true) { if (s2 < s1) { do { ++k2; @@ -950,15 +989,16 @@ protected static int unsignedLocalIntersect2by2Cardinality(final CharBuffer set1 break; } s2 = set2.get(k2); - } } return pos; } - - protected static int unsignedOneSidedGallopingIntersect2by2(final CharBuffer smallSet, - final int smallLength, final CharBuffer largeSet, final int largeLength, + protected static int unsignedOneSidedGallopingIntersect2by2( + final CharBuffer smallSet, + final int smallLength, + final CharBuffer largeSet, + final int largeLength, final char[] buffer) { if (0 == smallLength) { return 0; @@ -997,16 +1037,18 @@ protected static int unsignedOneSidedGallopingIntersect2by2(final CharBuffer sma } s1 = largeSet.get(k1); } - } return pos; - } protected static int unsignedUnion2by2( - final CharBuffer set1, final int offset1, final int length1, - final CharBuffer set2, final int offset2, final int length2, - final char[] buffer) { + final CharBuffer set1, + final int offset1, + final int length1, + final CharBuffer set2, + final int offset2, + final int length2, + final char[] buffer) { if (0 == length2) { set1.position(offset1); set1.get(buffer, 0, length1); @@ -1049,7 +1091,7 @@ protected static int unsignedUnion2by2( } s1 = set1.get(k1); s2 = set2.get(k2); - } else {// if (set1.get(k1)>set2.get(k2)) + } else { // if (set1.get(k1)>set2.get(k2)) buffer[pos++] = s2; ++k2; if (k2 >= length2 + offset2) { @@ -1064,9 +1106,41 @@ protected static int unsignedUnion2by2( } /** - * Private constructor to prevent instantiation of utility class + * It computes the intersection of the containers' keys between given bitmaps. + * + * @param words bitmap buffer + * @param bitmaps bitmaps + * @return keys intersection */ - private BufferUtil() { - + static char[] intersectKeys(long[] words, ImmutableRoaringBitmap[] bitmaps) { + ImmutableRoaringBitmap first = bitmaps[0]; + for (int i = 0; i < first.highLowContainer.size(); ++i) { + char key = first.highLowContainer.getKeyAtIndex(i); + words[key >>> 6] |= 1L << key; + } + int numContainers = first.highLowContainer.size(); + for (int i = 1; i < bitmaps.length && numContainers > 0; ++i) { + final char[] keys; + if (bitmaps[i].highLowContainer instanceof MutableRoaringArray) { + keys = ((MutableRoaringArray) bitmaps[i].highLowContainer).keys; + } else { + keys = new char[bitmaps[i].highLowContainer.size()]; + for (int j = 0; j < keys.length; ++j) { + keys[j] = bitmaps[i].highLowContainer.getKeyAtIndex(j); + } + } + numContainers = + BufferUtil.intersectArrayIntoBitmap( + words, CharBuffer.wrap(keys), bitmaps[i].highLowContainer.size()); + } + if (numContainers == 0) { + return new char[0]; + } + return BitSetUtil.arrayContainerBufferOf(0, words.length, numContainers, words); } + + /** + * Private constructor to prevent instantiation of utility class + */ + private BufferUtil() {} } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringArray.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringArray.java similarity index 89% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringArray.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringArray.java index a44d881fe..8c795b60a 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringArray.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringArray.java @@ -17,7 +17,6 @@ import java.nio.channels.WritableByteChannel; import java.util.NoSuchElementException; - /** * This is the underlying data structure for an ImmutableRoaringBitmap. This class is not meant for * end-users. @@ -28,7 +27,7 @@ public final class ImmutableRoaringArray implements PointableRoaringArray { protected static final short SERIAL_COOKIE = MutableRoaringArray.SERIAL_COOKIE; protected static final short SERIAL_COOKIE_NO_RUNCONTAINER = MutableRoaringArray.SERIAL_COOKIE_NO_RUNCONTAINER; - private final static int startofrunbitmap = 4; // if there is a runcontainer bitmap + private static final int startofrunbitmap = 4; // if there is a runcontainer bitmap ByteBuffer buffer; int size; @@ -75,7 +74,7 @@ public int advanceUntil(char x, int pos) { return upper; } - if (getKey(upper) < (x)) {// means array has no item key >= x + if (getKey(upper) < (x)) { // means array has no item key >= x return size; } @@ -115,20 +114,17 @@ private int branchyUnsignedBinarySearch(final char k) { return -(low + 1); } - - @Override public ImmutableRoaringArray clone() { ImmutableRoaringArray sa; try { sa = (ImmutableRoaringArray) super.clone(); } catch (CloneNotSupportedException e) { - return null;// should never happen + return null; // should never happen } return sa; } - private int computeSerializedSizeInBytes(boolean hasRunContainers) { if (this.size == 0) { return headerSize(hasRunContainers); @@ -155,9 +151,7 @@ public int getCardinality(int k) { return buffer.getChar(this.getStartOfKeys() + 4 * k + 2) + 1; } - - - @Override + @Override public int getContainerIndex(char x) { return unsignedBinarySearch(x); } @@ -165,8 +159,8 @@ public int getContainerIndex(char x) { @Override public MappeableContainer getContainerAtIndex(int i) { boolean hasrun = hasRunCompression(); - ByteBuffer tmp = buffer.duplicate();// sad but ByteBuffer is not thread-safe so it is either a - // duplicate or a lock + ByteBuffer tmp = buffer.duplicate(); // sad but ByteBuffer is not thread-safe so it is either a + // duplicate or a lock // note that tmp will indeed be garbage-collected some time after the end of this function tmp.order(buffer.order()); tmp.position(getOffsetContainer(i, hasrun)); @@ -179,7 +173,7 @@ public MappeableContainer getContainerAtIndex(int i) { } int cardinality = getCardinality(i); final boolean isBitmap = cardinality > MappeableArrayContainer.DEFAULT_MAX_SIZE; // if not a - // runcontainer + // runcontainer if (isBitmap) { final LongBuffer bitmapArray = tmp.asLongBuffer(); bitmapArray.limit(MappeableBitmapContainer.MAX_CAPACITY / 64); @@ -202,7 +196,7 @@ public boolean containsForContainerAtIndex(int i, char x) { } int cardinality = getCardinality(i); final boolean isBitmap = cardinality > MappeableArrayContainer.DEFAULT_MAX_SIZE; // if not a - // runcontainer + // runcontainer if (isBitmap) { return MappeableBitmapContainer.contains(buffer, containerpos, x); } else { @@ -210,8 +204,6 @@ public boolean containsForContainerAtIndex(int i, char x) { } } - - @Override public MappeableContainerPointer getContainerPointer() { return getContainerPointer(0); @@ -228,13 +220,12 @@ public void advance() { ++k; } - @Override public MappeableContainerPointer clone() { try { return (MappeableContainerPointer) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -259,7 +250,6 @@ public MappeableContainer getContainer() { return ImmutableRoaringArray.this.getContainerAtIndex(k); } - @Override public int getSizeInBytes() { // might be a tad expensive @@ -275,7 +265,7 @@ public int getSizeInBytes() { @Override public boolean hasContainer() { - return 0 <= k & k < ImmutableRoaringArray.this.size; + return 0 <= k && k < ImmutableRoaringArray.this.size; } @Override @@ -294,10 +284,8 @@ public boolean isRunContainer() { @Override public char key() { return ImmutableRoaringArray.this.getKeyAtIndex(k); - } - @Override public void previous() { --k; @@ -336,7 +324,6 @@ private int getOffsetContainer(int k, boolean hasRunCompression) { } } - private int getOffsetContainerSlow(int k, boolean hasRunCompression) { int pos = this.headerSize(hasRunCompression); for (int z = 0; z < k; ++z) { @@ -362,21 +349,20 @@ private int getStartOfKeys() { } } - @Override public boolean equals(Object o) { if (o instanceof ImmutableRoaringArray) { - ImmutableRoaringArray srb = (ImmutableRoaringArray)o; + ImmutableRoaringArray srb = (ImmutableRoaringArray) o; if (srb.size() != this.size()) { return false; } MappeableContainerPointer cp = this.getContainerPointer(); MappeableContainerPointer cpo = srb.getContainerPointer(); - while(cp.hasContainer() && cpo.hasContainer()) { - if(cp.key() != cpo.key()) { + while (cp.hasContainer() && cpo.hasContainer()) { + if (cp.key() != cpo.key()) { return false; } - if(!cp.getContainer().equals(cpo.getContainer())) { + if (!cp.getContainer().equals(cpo.getContainer())) { return false; } } @@ -404,16 +390,16 @@ public boolean hasRunCompression() { // hasrun should be equal to hasRunCompression() protected int headerSize(boolean hasrun) { if (hasrun) { - if (size < MutableRoaringArray.NO_OFFSET_THRESHOLD) {// for small bitmaps, we omit the offsets + if (size + < MutableRoaringArray.NO_OFFSET_THRESHOLD) { // for small bitmaps, we omit the offsets return 4 + (size + 7) / 8 + 4 * size; } - return 4 + (size + 7) / 8 + 8 * size;// - 4 because we pack the size with the cookie + return 4 + (size + 7) / 8 + 8 * size; // - 4 because we pack the size with the cookie } else { return 4 + 4 + 8 * size; } } - /** * Returns true if this bitmap is empty. * @@ -493,8 +479,32 @@ public int last() { return lastKey << 16 | container.last(); } + @Override + public int firstSigned() { + assertNonEmpty(); + int index = advanceUntil((char) (1 << 15), -1); + if (index == size) { // no negatives + index = 0; + } + char key = getKeyAtIndex(index); + MappeableContainer container = getContainerAtIndex(index); + return key << 16 | container.first(); + } + + @Override + public int lastSigned() { + assertNonEmpty(); + int index = advanceUntil((char) (1 << 15), -1) - 1; + if (index == -1) { // no positives + index += size; + } + char key = getKeyAtIndex(index); + MappeableContainer container = getContainerAtIndex(index); + return key << 16 | container.last(); + } + private void assertNonEmpty() { - if(size == 0) { + if (size == 0) { throw new NoSuchElementException("Empty ImmutableRoaringArray"); } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringBitmap.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringBitmap.java similarity index 80% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringBitmap.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringBitmap.java index e4443e369..9c9448afb 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringBitmap.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/ImmutableRoaringBitmap.java @@ -4,17 +4,26 @@ package org.roaringbitmap.buffer; -import org.roaringbitmap.*; +import static org.roaringbitmap.Util.toUnsignedLong; +import static org.roaringbitmap.buffer.BufferUtil.highbits; +import static org.roaringbitmap.buffer.BufferUtil.lowbits; +import static org.roaringbitmap.buffer.BufferUtil.lowbitsAsInteger; +import static org.roaringbitmap.buffer.MutableRoaringBitmap.rangeSanityCheck; + +import org.roaringbitmap.BatchIterator; +import org.roaringbitmap.CharIterator; +import org.roaringbitmap.ImmutableBitmapDataProvider; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.IntIterator; +import org.roaringbitmap.PeekableCharIterator; +import org.roaringbitmap.PeekableIntIterator; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.Util; import java.io.DataOutput; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Iterator; -import java.util.NoSuchElementException; - -import static org.roaringbitmap.Util.toUnsignedLong; -import static org.roaringbitmap.buffer.BufferUtil.*; -import static org.roaringbitmap.buffer.MutableRoaringBitmap.rangeSanityCheck; /** * ImmutableRoaringBitmap provides a compressed immutable (cannot be modified) bitmap. It is meant @@ -73,9 +82,10 @@ public class ImmutableRoaringBitmap implements Iterable, Cloneable, ImmutableBitmapDataProvider { - private final class ImmutableRoaringIntIterator implements PeekableIntIterator { - private MappeableContainerPointer cp = - ImmutableRoaringBitmap.this.highLowContainer.getContainerPointer(); + private class ImmutableRoaringIntIterator implements PeekableIntIterator { + private boolean wrap; + private MappeableContainerPointer cp; + private int iterations = 0; private int hs = 0; @@ -84,22 +94,31 @@ private final class ImmutableRoaringIntIterator implements PeekableIntIterator { private boolean ok; public ImmutableRoaringIntIterator() { + char index = findStartingContainerIndex(); + wrap = index != 0; + cp = ImmutableRoaringBitmap.this.highLowContainer.getContainerPointer(index); nextContainer(); } + char findStartingContainerIndex() { + return 0; + } + @Override public PeekableIntIterator clone() { try { ImmutableRoaringIntIterator x = (ImmutableRoaringIntIterator) super.clone(); - if(this.iter != null) { + if (this.iter != null) { x.iter = this.iter.clone(); } - if(this.cp != null) { + if (this.cp != null) { x.cp = this.cp.clone(); } + x.wrap = this.wrap; + x.iterations = this.iterations; return x; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -118,18 +137,28 @@ public int next() { return x; } - private void nextContainer() { - ok = cp.hasContainer(); - if (ok) { - iter = cp.getContainer().getCharIterator(); - hs = (cp.key()) << 16; + final int containerSize = ImmutableRoaringBitmap.this.highLowContainer.size(); + if (wrap || iterations < containerSize) { + ok = cp.hasContainer(); + if (!ok && wrap && iterations < containerSize) { + cp = ImmutableRoaringBitmap.this.highLowContainer.getContainerPointer(); + wrap = false; + ok = cp.hasContainer(); + } + if (ok) { + iter = cp.getContainer().getCharIterator(); + hs = (cp.key()) << 16; + ++iterations; + } + } else { + ok = false; } } @Override public void advanceIfNeeded(int minval) { - while (hasNext() && ((hs >>> 16) < (minval >>> 16))) { + while (hasNext() && shouldAdvanceContainer(hs, minval)) { cp.advance(); nextContainer(); } @@ -142,18 +171,39 @@ public void advanceIfNeeded(int minval) { } } + boolean shouldAdvanceContainer(final int hs, final int minval) { + return (hs >>> 16) < (minval >>> 16); + } + @Override public int peekNext() { return (iter.peekNext()) | hs; } + } + private class ImmutableRoaringSignedIntIterator extends ImmutableRoaringIntIterator { - } + @Override + char findStartingContainerIndex() { + // skip to starting at negative signed integers + char index = + (char) ImmutableRoaringBitmap.this.highLowContainer.advanceUntil((char) (1 << 15), -1); + if (index == ImmutableRoaringBitmap.this.highLowContainer.size()) { + index = 0; + } + return index; + } + @Override + boolean shouldAdvanceContainer(final int hs, final int minval) { + return (hs >> 16) < (minval >> 16); + } + } private final class ImmutableRoaringReverseIntIterator implements IntIterator { - private MappeableContainerPointer cp = ImmutableRoaringBitmap.this.highLowContainer - .getContainerPointer(ImmutableRoaringBitmap.this.highLowContainer.size() - 1); + private MappeableContainerPointer cp = + ImmutableRoaringBitmap.this.highLowContainer.getContainerPointer( + ImmutableRoaringBitmap.this.highLowContainer.size() - 1); private int hs = 0; @@ -169,15 +219,15 @@ public ImmutableRoaringReverseIntIterator() { public IntIterator clone() { try { ImmutableRoaringReverseIntIterator x = (ImmutableRoaringReverseIntIterator) super.clone(); - if(this.iter != null) { + if (this.iter != null) { x.iter = this.iter.clone(); } - if(this.cp != null) { + if (this.cp != null) { x.cp = this.cp.clone(); } return x; } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -196,7 +246,6 @@ public int next() { return x; } - private void nextContainer() { ok = cp.hasContainer(); if (ok) { @@ -204,8 +253,6 @@ private void nextContainer() { hs = (cp.key()) << 16; } } - - } /** @@ -217,9 +264,11 @@ private void nextContainer() { * @param rangeEnd exclusive ending of range * @return new result bitmap */ - public static MutableRoaringBitmap and(final Iterator bitmaps, - final long rangeStart, final long rangeEnd) { - rangeSanityCheck(rangeStart,rangeEnd); + public static MutableRoaringBitmap and( + final Iterator bitmaps, + final long rangeStart, + final long rangeEnd) { + rangeSanityCheck(rangeStart, rangeEnd); Iterator bitmapsIterator; bitmapsIterator = selectRangeWithoutCopy(bitmaps, rangeStart, rangeEnd); return BufferFastAggregation.and(bitmapsIterator); @@ -237,13 +286,13 @@ public static MutableRoaringBitmap and(final Iterator bitmaps, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap and( + final Iterator bitmaps, + final int rangeStart, + final int rangeEnd) { return and(bitmaps, (long) rangeStart, (long) rangeEnd); } - - /** * Bitwise AND (intersection) operation. The provided bitmaps are *not* modified. This operation * is thread-safe as long as the provided bitmaps remain unchanged. @@ -255,8 +304,8 @@ public static MutableRoaringBitmap and(final Iterator s2 pos2 = x2.highLowContainer.advanceUntil(s1, pos2); @@ -292,8 +341,8 @@ public static MutableRoaringBitmap and(final ImmutableRoaringBitmap x1, * @return as if you did and(x2,x2).getCardinality() * @see BufferFastAggregation#and(ImmutableRoaringBitmap...) */ - public static int andCardinality(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2) { + public static int andCardinality( + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2) { int answer = 0; int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -308,7 +357,7 @@ public static int andCardinality(final ImmutableRoaringBitmap x1, answer += c1.andCardinality(c2); ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = x1.highLowContainer.advanceUntil(s2, pos1); } else { // s1 > s2 pos2 = x2.highLowContainer.advanceUntil(s1, pos2); @@ -317,8 +366,6 @@ public static int andCardinality(final ImmutableRoaringBitmap x1, return answer; } - - /** * Cardinality of the bitwise XOR (symmetric difference) operation. * The provided bitmaps are *not* modified. This operation is thread-safe @@ -328,8 +375,8 @@ public static int andCardinality(final ImmutableRoaringBitmap x1, * @param x2 other bitmap * @return cardinality of the symmetric difference */ - public static int xorCardinality(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2) { + public static int xorCardinality( + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2) { return x1.getCardinality() + x2.getCardinality() - 2 * andCardinality(x1, x2); } @@ -342,8 +389,8 @@ public static int xorCardinality(final ImmutableRoaringBitmap x1, * @param x2 other bitmap * @return cardinality of the left difference */ - public static int andNotCardinality(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2) { + public static int andNotCardinality( + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2) { return x1.getCardinality() - andCardinality(x1, x2); } @@ -358,15 +405,17 @@ public static int andNotCardinality(final ImmutableRoaringBitmap x1, * @param rangeEnd end of range (exclusive) * @return result of the operation */ - public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2, long rangeStart, long rangeEnd) { - rangeSanityCheck(rangeStart,rangeEnd); + public static MutableRoaringBitmap andNot( + final ImmutableRoaringBitmap x1, + final ImmutableRoaringBitmap x2, + long rangeStart, + long rangeEnd) { + rangeSanityCheck(rangeStart, rangeEnd); MutableRoaringBitmap rb1 = selectRangeWithoutCopy(x1, rangeStart, rangeEnd); MutableRoaringBitmap rb2 = selectRangeWithoutCopy(x2, rangeStart, rangeEnd); return andNot(rb1, rb2); } - /** * Bitwise ANDNOT (difference) operation for the given range, rangeStart (inclusive) and rangeEnd * (exclusive). The provided bitmaps are *not* modified. This operation is thread-safe as long as @@ -381,14 +430,14 @@ public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1, * endpoints are not allowed. */ @Deprecated - public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap andNot( + final ImmutableRoaringBitmap x1, + final ImmutableRoaringBitmap x2, + final int rangeStart, + final int rangeEnd) { return andNot(x1, x2, (long) rangeStart, (long) rangeEnd); } - - /** * Bitwise ANDNOT (difference) operation. The provided bitmaps are *not* modified. This operation * is thread-safe as long as the provided bitmaps remain unchanged. @@ -397,8 +446,8 @@ public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1, * @param x2 other bitmap * @return result of the operation */ - public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2) { + public static MutableRoaringBitmap andNot( + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -415,7 +464,7 @@ public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1, } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { final int nextPos1 = x1.highLowContainer.advanceUntil(s2, pos1); answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer, pos1, nextPos1); pos1 = nextPos1; @@ -441,10 +490,10 @@ public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1, * @return result of the operation */ public static MutableRoaringBitmap orNot( - final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2, long rangeEnd) { + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2, long rangeEnd) { rangeSanityCheck(0, rangeEnd); - int maxKey = (int)((rangeEnd - 1) >>> 16); - int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int)(rangeEnd & 0xFFFF); + int maxKey = (int) ((rangeEnd - 1) >>> 16); + int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int) (rangeEnd & 0xFFFF); int size = 0; int pos1 = 0, pos2 = 0; int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -452,8 +501,8 @@ public static MutableRoaringBitmap orNot( int s2 = length2 > 0 ? x2.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; int remainder = 0; for (int i = x1.highLowContainer.size() - 1; - i >= 0 && x1.highLowContainer.getKeyAtIndex(i) > maxKey; - --i) { + i >= 0 && x1.highLowContainer.getKeyAtIndex(i) > maxKey; + --i) { ++remainder; } int correction = 0; @@ -465,8 +514,8 @@ public static MutableRoaringBitmap orNot( } // it's almost certain that the bitmap will grow, so make a conservative overestimate, // this avoids temporary allocation, and can trim afterwards - int maxSize = Math.min(maxKey + 1 + remainder - correction - + x1.highLowContainer.size(), 0x10000); + int maxSize = + Math.min(maxKey + 1 + remainder - correction + x1.highLowContainer.size(), 0x10000); if (maxSize == 0) { return new MutableRoaringBitmap(); } @@ -474,27 +523,33 @@ public static MutableRoaringBitmap orNot( MappeableContainer[] newValues = new MappeableContainer[maxSize]; for (int key = 0; key <= maxKey && size < maxSize; ++key) { if (key == s1 && key == s2) { // actually need to do an or not - newValues[size] = x1.highLowContainer.getContainerAtIndex(pos1) - .orNot(x2.highLowContainer.getContainerAtIndex(pos2), - key == maxKey ? lastRun : 0x10000); + newValues[size] = + x1.highLowContainer + .getContainerAtIndex(pos1) + .orNot( + x2.highLowContainer.getContainerAtIndex(pos2), + key == maxKey ? lastRun : 0x10000); ++pos1; ++pos2; s1 = pos1 < length1 ? x1.highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; s2 = pos2 < length2 ? x2.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else if (key == s1) { // or in a hole - newValues[size] = x1.highLowContainer.getContainerAtIndex(pos1) - .ior(key == maxKey - ? MappeableRunContainer.rangeOfOnes(0, lastRun) - : MappeableRunContainer.full()); + newValues[size] = + key == maxKey + ? x1.highLowContainer + .getContainerAtIndex(pos1) + .ior(MappeableRunContainer.rangeOfOnes(0, lastRun)) + : MappeableRunContainer.full(); ++pos1; s1 = pos1 < length1 ? x1.highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; } else if (key == s2) { // insert the complement - newValues[size] = x2.highLowContainer.getContainerAtIndex(pos2) - .not(0, key == maxKey ? lastRun : 0x10000); + newValues[size] = + x2.highLowContainer.getContainerAtIndex(pos2).not(0, key == maxKey ? lastRun : 0x10000); ++pos2; s2 = pos2 < length2 ? x2.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else { // key missing from both - newValues[size] = key == maxKey + newValues[size] = + key == maxKey ? MappeableRunContainer.rangeOfOnes(0, lastRun) : MappeableRunContainer.full(); } @@ -502,7 +557,7 @@ public static MutableRoaringBitmap orNot( if (newValues[size].isEmpty()) { newValues[size] = null; } else { - newKeys[size++] = (char)key; + newKeys[size++] = (char) key; } } // copy over everything which will remain without being complemented @@ -537,8 +592,6 @@ public static ImmutableRoaringBitmap bitmapOf(final int... data) { return MutableRoaringBitmap.bitmapOf(data); } - - /** * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The * given bitmap is unchanged. @@ -548,8 +601,8 @@ public static ImmutableRoaringBitmap bitmapOf(final int... data) { * @param rangeEnd exclusive ending of range * @return a new Bitmap */ - public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, final long rangeStart, - final long rangeEnd) { + public static MutableRoaringBitmap flip( + ImmutableRoaringBitmap bm, final long rangeStart, final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); if (rangeStart >= rangeEnd) { throw new RuntimeException("Invalid range " + rangeStart + " -- " + rangeEnd); @@ -582,8 +635,10 @@ public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, final long ra } else { // *think* the range of ones must never be // empty. - answer.getMappeableRoaringArray().insertNewKeyValueAt(-j - 1, hb, - MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); + answer + .getMappeableRoaringArray() + .insertNewKeyValueAt( + -j - 1, hb, MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); } } // copy the containers after the active area. @@ -592,9 +647,7 @@ public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, final long ra return answer; } - - - /** + /** * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The * given bitmap is unchanged. * @@ -605,8 +658,8 @@ public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, final long ra * @deprecated use the version where longs specify the range */ @Deprecated - public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap flip( + ImmutableRoaringBitmap bm, final int rangeStart, final int rangeEnd) { if (rangeStart >= 0) { return flip(bm, (long) rangeStart, (long) rangeEnd); } @@ -615,8 +668,6 @@ public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, return flip(bm, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - - /** * Return new iterator with only values from rangeStart (inclusive) to rangeEnd (exclusive) * @@ -627,26 +678,97 @@ public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, */ private static Iterator selectRangeWithoutCopy( final Iterator bitmaps, - final long rangeStart, final long rangeEnd) { + final long rangeStart, + final long rangeEnd) { Iterator bitmapsIterator; - bitmapsIterator = new Iterator() { - @Override - public boolean hasNext() { - return bitmaps.hasNext(); + bitmapsIterator = + new Iterator() { + @Override + public boolean hasNext() { + return bitmaps.hasNext(); + } + + @Override + public ImmutableRoaringBitmap next() { + ImmutableRoaringBitmap next = bitmaps.next(); + return selectRangeWithoutCopy(next, rangeStart, rangeEnd); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Remove not supported"); + } + }; + return bitmapsIterator; + } + + /** + * Creates a copy of the bitmap, limited to the values in the specified range, + * rangeStart (inclusive) and rangeEnd (exclusive). + * + * @param rangeStart inclusive + * @param rangeEnd exclusive + * @return new bitmap + */ + public MutableRoaringBitmap selectRange(final long rangeStart, final long rangeEnd) { + final int hbStart = (BufferUtil.highbits(rangeStart)); + final int lbStart = (BufferUtil.lowbits(rangeStart)); + final int hbLast = (BufferUtil.highbits(rangeEnd - 1)); + final int lbLast = (BufferUtil.lowbits(rangeEnd - 1)); + MutableRoaringBitmap answer = new MutableRoaringBitmap(); + + assert (rangeStart >= 0 && rangeEnd >= 0); + + if (rangeEnd <= rangeStart) { + return answer; + } + + if (hbStart == hbLast) { + final int i = this.highLowContainer.getIndex((char) hbStart); + if (i >= 0) { + final MappeableContainer c = + this.highLowContainer + .getContainerAtIndex(i) + .remove(0, lbStart) + .iremove(lbLast + 1, Util.maxLowBitAsInteger() + 1); + if (!c.isEmpty()) { + ((MutableRoaringArray) answer.highLowContainer).append((char) hbStart, c); + } + } + return answer; + } + int ifirst = this.highLowContainer.getIndex((char) hbStart); + int ilast = this.highLowContainer.getIndex((char) hbLast); + if (ifirst >= 0) { + MappeableContainer c = this.highLowContainer.getContainerAtIndex(ifirst).remove(0, lbStart); + if (!c.isEmpty()) { + ((MutableRoaringArray) answer.highLowContainer).append((char) hbStart, c.clone()); } + } - @Override - public ImmutableRoaringBitmap next() { - ImmutableRoaringBitmap next = bitmaps.next(); - return selectRangeWithoutCopy(next, rangeStart, rangeEnd); + // revised to loop on ints + for (int hb = hbStart + 1; hb <= hbLast - 1; ++hb) { + final int i = this.highLowContainer.getIndex((char) hb); + final int j = answer.highLowContainer.getIndex((char) hb); + assert j < 0; + + if (i >= 0) { + final MappeableContainer c = this.highLowContainer.getContainerAtIndex(i); + ((MutableRoaringArray) answer.highLowContainer) + .insertNewKeyValueAt(-j - 1, (char) hb, c.clone()); } + } - @Override - public void remove() { - throw new UnsupportedOperationException("Remove not supported"); + if (ilast >= 0) { + MappeableContainer c = + this.highLowContainer + .getContainerAtIndex(ilast) + .remove(lbLast + 1, Util.maxLowBitAsInteger() + 1); + if (!c.isEmpty()) { + ((MutableRoaringArray) answer.highLowContainer).append((char) hbLast, c); } - }; - return bitmapsIterator; + } + return answer; } /** @@ -659,9 +781,8 @@ public void remove() { * @param rangeEnd exclusive * @return new bitmap */ - - private static MutableRoaringBitmap selectRangeWithoutCopy(ImmutableRoaringBitmap rb, - final long rangeStart, final long rangeEnd) { + private static MutableRoaringBitmap selectRangeWithoutCopy( + ImmutableRoaringBitmap rb, final long rangeStart, final long rangeEnd) { final int hbStart = (highbits(rangeStart)); final int lbStart = (lowbits(rangeStart)); final int hbLast = (highbits(rangeEnd - 1)); @@ -675,8 +796,11 @@ private static MutableRoaringBitmap selectRangeWithoutCopy(ImmutableRoaringBitma if (hbStart == hbLast) { final int i = rb.highLowContainer.getIndex((char) hbStart); if (i >= 0) { - final MappeableContainer c = rb.highLowContainer.getContainerAtIndex(i).remove(0, lbStart) - .iremove(lbLast + 1, BufferUtil.maxLowBitAsInteger() + 1); + final MappeableContainer c = + rb.highLowContainer + .getContainerAtIndex(i) + .remove(0, lbStart) + .iremove(lbLast + 1, BufferUtil.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { ((MutableRoaringArray) answer.highLowContainer).append((char) hbStart, c); } @@ -705,14 +829,15 @@ private static MutableRoaringBitmap selectRangeWithoutCopy(ImmutableRoaringBitma } if (ilast >= 0) { - final MappeableContainer c = rb.highLowContainer.getContainerAtIndex(ilast).remove(lbLast + 1, - BufferUtil.maxLowBitAsInteger() + 1); + final MappeableContainer c = + rb.highLowContainer + .getContainerAtIndex(ilast) + .remove(lbLast + 1, BufferUtil.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { ((MutableRoaringArray) answer.highLowContainer).append((char) hbLast, c); } } return answer; - } /** @@ -723,8 +848,8 @@ private static MutableRoaringBitmap selectRangeWithoutCopy(ImmutableRoaringBitma * @param x2 other bitmap * @return true if they intersect */ - public static boolean intersects(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2) { + public static boolean intersects( + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2) { int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -740,7 +865,7 @@ public static boolean intersects(final ImmutableRoaringBitmap x1, } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = x1.highLowContainer.advanceUntil(s2, pos1); } else { // s1 > s2 pos2 = x2.highLowContainer.advanceUntil(s1, pos2); @@ -750,16 +875,18 @@ public static boolean intersects(final ImmutableRoaringBitmap x1, } // important: inputs should not be reused - protected static MutableRoaringBitmap lazyor(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2) { + protected static MutableRoaringBitmap lazyor( + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); MappeableContainerPointer i1 = x1.highLowContainer.getContainerPointer(); MappeableContainerPointer i2 = x2.highLowContainer.getContainerPointer(); - main: if (i1.hasContainer() && i2.hasContainer()) { + main: + if (i1.hasContainer() && i2.hasContainer()) { while (true) { if (i1.key() == i2.key()) { - answer.getMappeableRoaringArray().append(i1.key(), - i1.getContainer().lazyOR(i2.getContainer())); + answer + .getMappeableRoaringArray() + .append(i1.key(), i1.getContainer().lazyOR(i2.getContainer())); i1.advance(); i2.advance(); if (!i1.hasContainer() || !i2.hasContainer()) { @@ -819,16 +946,18 @@ public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) { * @see BufferFastAggregation#or(ImmutableRoaringBitmap...) * @see BufferFastAggregation#horizontal_or(ImmutableRoaringBitmap...) */ - public static MutableRoaringBitmap or(final ImmutableRoaringBitmap x1, - final ImmutableRoaringBitmap x2) { + public static MutableRoaringBitmap or( + final ImmutableRoaringBitmap x1, final ImmutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); MappeableContainerPointer i1 = x1.highLowContainer.getContainerPointer(); MappeableContainerPointer i2 = x2.highLowContainer.getContainerPointer(); - main: if (i1.hasContainer() && i2.hasContainer()) { + main: + if (i1.hasContainer() && i2.hasContainer()) { while (true) { if (i1.key() == i2.key()) { - answer.getMappeableRoaringArray().append(i1.key(), - i1.getContainer().or(i2.getContainer())); + answer + .getMappeableRoaringArray() + .append(i1.key(), i1.getContainer().or(i2.getContainer())); i1.advance(); i2.advance(); if (!i1.hasContainer() || !i2.hasContainer()) { @@ -884,8 +1013,10 @@ public static MutableRoaringBitmap or(Iterator * @param rangeEnd exclusive ending of range * @return new result bitmap */ - public static MutableRoaringBitmap or(final Iterator bitmaps, - final long rangeStart, final long rangeEnd) { + public static MutableRoaringBitmap or( + final Iterator bitmaps, + final long rangeStart, + final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); Iterator bitmapsIterator; bitmapsIterator = selectRangeWithoutCopy(bitmaps, rangeStart, rangeEnd); @@ -904,14 +1035,13 @@ public static MutableRoaringBitmap or(final Iterator bitmaps, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap or( + final Iterator bitmaps, + final int rangeStart, + final int rangeEnd) { return or(bitmaps, (long) rangeStart, (long) rangeEnd); } - - - /** * Cardinality of the bitwise OR (union) operation. The provided bitmaps are *not* modified. This * operation is thread-safe as long as the provided bitmaps remain unchanged. @@ -924,8 +1054,8 @@ public static MutableRoaringBitmap or(final Iterator bitmaps, - final long rangeStart, final long rangeEnd) { + public static MutableRoaringBitmap xor( + final Iterator bitmaps, + final long rangeStart, + final long rangeEnd) { Iterator bitmapsIterator; bitmapsIterator = selectRangeWithoutCopy(bitmaps, rangeStart, rangeEnd); return BufferFastAggregation.xor(bitmapsIterator); } - /** * Computes XOR between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd * (exclusive) @@ -960,13 +1091,13 @@ public static MutableRoaringBitmap xor(final Iterator bitmaps, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap xor( + final Iterator bitmaps, + final int rangeStart, + final int rangeEnd) { return xor(bitmaps, (long) rangeStart, (long) rangeEnd); } - - /** * Bitwise XOR (symmetric difference) operation. The provided bitmaps are *not* modified. This * operation is thread-safe as long as the provided bitmaps remain unchanged. @@ -979,12 +1110,13 @@ public static MutableRoaringBitmap xor(final Iterator= 0 - && highLowContainer.containsForContainerAtIndex(index, lowbits(x)); + return index >= 0 && highLowContainer.containsForContainerAtIndex(index, lowbits(x)); } /** @@ -1103,22 +1231,22 @@ public boolean contains(long minimum, long supremum) { } int begin = highLowContainer.getIndex(firstKey); int end = highLowContainer.getIndex(lastKey); - end = end < 0 ? -end -1 : end; + end = end < 0 ? -end - 1 : end; if (begin < 0 || end - begin != span) { return false; } - int min = (char)minimum; - int sup = (char)supremum; + int min = (char) minimum; + int sup = (char) supremum; if (firstKey == lastKey) { - return highLowContainer.getContainerAtIndex(begin) - .contains(min, (supremum & 0xFFFF) == 0 ? 0x10000 : sup); + return highLowContainer + .getContainerAtIndex(begin) + .contains(min, (supremum & 0xFFFF) == 0 ? 0x10000 : sup); } if (!highLowContainer.getContainerAtIndex(begin).contains(min, 1 << 16)) { return false; } - if (sup != 0 && end < len && !highLowContainer.getContainerAtIndex(end) - .contains(0, sup)) { + if (sup != 0 && end < len && !highLowContainer.getContainerAtIndex(end).contains(0, sup)) { return false; } for (int i = begin + 1; i < end; ++i) { @@ -1144,7 +1272,7 @@ public boolean contains(ImmutableRoaringBitmap subset) { if (s1 == s2) { MappeableContainer c1 = this.highLowContainer.getContainerAtIndex(pos1); MappeableContainer c2 = subset.highLowContainer.getContainerAtIndex(pos2); - if(!c1.contains(c2)) { + if (!c1.contains(c2)) { return false; } ++pos1; @@ -1158,7 +1286,6 @@ public boolean contains(ImmutableRoaringBitmap subset) { return pos2 == length2; } - @Override public boolean equals(Object o) { if (o instanceof ImmutableRoaringBitmap) { @@ -1201,16 +1328,16 @@ public boolean isHammingSimilar(ImmutableRoaringBitmap other, int tolerance) { int pos1 = 0; int pos2 = 0; int budget = tolerance; - while(budget >= 0 && pos1 < size1 && pos2 < size2) { + while (budget >= 0 && pos1 < size1 && pos2 < size2) { final char key1 = highLowContainer.getKeyAtIndex(pos1); final char key2 = other.highLowContainer.getKeyAtIndex(pos2); MappeableContainer left = highLowContainer.getContainerAtIndex(pos1); MappeableContainer right = other.highLowContainer.getContainerAtIndex(pos2); - if(key1 == key2) { + if (key1 == key2) { budget -= left.xorCardinality(right); ++pos1; ++pos2; - } else if(key1 < key2) { + } else if (key1 < key2) { budget -= left.getCardinality(); ++pos1; } else { @@ -1218,18 +1345,17 @@ public boolean isHammingSimilar(ImmutableRoaringBitmap other, int tolerance) { ++pos2; } } - while(budget >= 0 && pos1 < size1) { + while (budget >= 0 && pos1 < size1) { MappeableContainer container = highLowContainer.getContainerAtIndex(pos1++); budget -= container.getCardinality(); } - while(budget >= 0 && pos2 < size2) { + while (budget >= 0 && pos2 < size2) { MappeableContainer container = other.highLowContainer.getContainerAtIndex(pos2++); budget -= container.getCardinality(); } return budget >= 0; } - /** * Checks if the range intersects with the bitmap. * @param minimum the inclusive unsigned lower bound of the range @@ -1241,8 +1367,8 @@ public boolean intersects(long minimum, long supremum) { if (supremum <= minimum) { return false; } - int minKey = (int)(minimum >>> 16); - int supKey = (int)(supremum >>> 16); + int minKey = (int) (minimum >>> 16); + int supKey = (int) (supremum >>> 16); int length = highLowContainer.size(); // seek to start int pos = 0; @@ -1250,7 +1376,7 @@ public boolean intersects(long minimum, long supremum) { ++pos; } // it is possible for pos == length to be true - if(pos == length) { + if (pos == length) { return false; } // we have that pos < length. @@ -1270,9 +1396,9 @@ public boolean intersects(long minimum, long supremum) { offset = 0; ++pos; } - return pos < length && supKey == highLowContainer.getKeyAtIndex(pos) - && highLowContainer.getContainerAtIndex(pos) - .intersects(offset, limit); + return pos < length + && supKey == highLowContainer.getKeyAtIndex(pos) + && highLowContainer.getContainerAtIndex(pos).intersects(offset, limit); } /** @@ -1317,8 +1443,6 @@ public void forEach(IntConsumer ic) { } } - - /** * Return a low-level container pointer that can be used to access the underlying data structure. * @@ -1331,13 +1455,22 @@ public MappeableContainerPointer getContainerPointer() { /** * For better performance, consider the Use the {@link #forEach forEach} method. * - * @return a custom iterator over set bits, the bits are traversed in ascending sorted order + * @return a custom iterator over set bits, the bits are traversed in unsigned integer ascending + * sorted order */ @Override public PeekableIntIterator getIntIterator() { return new ImmutableRoaringIntIterator(); } + /** + * @return a custom iterator over set bits, the bits are traversed in signed integer ascending + * sorted order + */ + @Override + public PeekableIntIterator getSignedIntIterator() { + return new ImmutableRoaringSignedIntIterator(); + } /** * @return a custom iterator over set bits, the bits are traversed in descending sorted order @@ -1352,7 +1485,6 @@ public BatchIterator getBatchIterator() { return new RoaringBatchIterator(null == highLowContainer ? null : getContainerPointer()); } - /** * Estimate of the memory usage of this data structure. This can be expected to be within 1% of * the true memory usage in common usage scenarios. @@ -1399,8 +1531,10 @@ public long getLongSizeInBytes() { (MappeableRunContainer) this.highLowContainer.getContainerAtIndex(i); size += 4 + BufferUtil.getSizeInBytesFromCardinalityEtc(0, thisRunContainer.nbrruns, true); } else { - size += 4 + BufferUtil - .getSizeInBytesFromCardinalityEtc(this.highLowContainer.getCardinality(i), 0, false); + size += + 4 + + BufferUtil.getSizeInBytesFromCardinalityEtc( + this.highLowContainer.getCardinality(i), 0, false); } } return size; @@ -1445,7 +1579,7 @@ public long getLongSizeInBytes() { */ @Override public int getSizeInBytes() { - return (int) getLongSizeInBytes() ; + return (int) getLongSizeInBytes(); } /** @@ -1466,7 +1600,6 @@ public int hashCode() { return highLowContainer.hashCode(); } - /** * Check whether this bitmap has had its runs compressed. * @@ -1509,8 +1642,11 @@ public boolean hasNext() { public Iterator init() { if (pos < ImmutableRoaringBitmap.this.highLowContainer.size()) { - iter = ImmutableRoaringBitmap.this.highLowContainer.getContainerAtIndex(pos) - .getCharIterator(); + iter = + ImmutableRoaringBitmap.this + .highLowContainer + .getContainerAtIndex(pos) + .getCharIterator(); hs = (ImmutableRoaringBitmap.this.highLowContainer.getKeyAtIndex(pos)) << 16; } return this; @@ -1530,7 +1666,6 @@ public Integer next() { public void remove() { throw new RuntimeException("Cannot modify."); } - }.init(); } @@ -1544,8 +1679,9 @@ public void remove() { public MutableRoaringBitmap limit(int maxcardinality) { MutableRoaringBitmap answer = new MutableRoaringBitmap(); int currentcardinality = 0; - for (int i = 0; (currentcardinality < maxcardinality) - && (i < this.highLowContainer.size()); i++) { + for (int i = 0; + (currentcardinality < maxcardinality) && (i < this.highLowContainer.size()); + i++) { MappeableContainer c = this.highLowContainer.getContainerAtIndex(i); if (c.getCardinality() + currentcardinality <= maxcardinality) { ((MutableRoaringArray) answer.highLowContainer) @@ -1580,41 +1716,38 @@ public long rankLong(int x) { char key = this.highLowContainer.getKeyAtIndex(i); if (key < xhigh) { size += this.highLowContainer.getCardinality(i); - } else if(key == xhigh) { + } else if (key == xhigh) { return size + this.highLowContainer.getContainerAtIndex(i).rank(lowbits(x)); } } return size; } - @Override public long rangeCardinality(long start, long end) { - if(Long.compareUnsigned(start, end) >= 0) { + if (Long.compareUnsigned(start, end) >= 0) { return 0; } long size = 0; int startIndex = this.highLowContainer.getIndex(highbits(start)); - if(startIndex < 0) { + if (startIndex < 0) { startIndex = -startIndex - 1; } else { int inContainerStart = (lowbits(start)); - if(inContainerStart != 0) { - size -= this.highLowContainer - .getContainerAtIndex(startIndex) - .rank((char)(inContainerStart - 1)); + if (inContainerStart != 0) { + size -= + this.highLowContainer + .getContainerAtIndex(startIndex) + .rank((char) (inContainerStart - 1)); } } char xhigh = highbits(end - 1); for (int i = startIndex; i < this.highLowContainer.size(); i++) { char key = this.highLowContainer.getKeyAtIndex(i); if (key < xhigh) { - size += this.highLowContainer - .getContainerAtIndex(i).getCardinality(); + size += this.highLowContainer.getContainerAtIndex(i).getCardinality(); } else if (key == xhigh) { - return size + this.highLowContainer - .getContainerAtIndex(i) - .rank(lowbits((int)(end - 1))); + return size + this.highLowContainer.getContainerAtIndex(i).rank(lowbits((int) (end - 1))); } } return size; @@ -1646,39 +1779,39 @@ public int select(int j) { if (thiscard > leftover) { int keycontrib = this.highLowContainer.getKeyAtIndex(i) << 16; MappeableContainer c = this.highLowContainer.getContainerAtIndex(i); - int lowcontrib = (c.select((int)leftover)); + int lowcontrib = (c.select((int) leftover)); return lowcontrib + keycontrib; } leftover -= thiscard; } - throw new IllegalArgumentException("You are trying to select the " - + j + "th value when the cardinality is " - + this.getCardinality() + "."); + throw new IllegalArgumentException( + "You are trying to select the " + + j + + "th value when the cardinality is " + + this.getCardinality() + + "."); } - - /** - * Get the first (smallest) integer in this RoaringBitmap, - * that is, returns the minimum of the set. - * @return the first (smallest) integer - * @throws NoSuchElementException if empty - */ @Override public int first() { return highLowContainer.first(); } - /** - * Get the last (largest) integer in this RoaringBitmap, - * that is, returns the maximum of the set. - * @return the last (largest) integer - * @throws NoSuchElementException if empty - */ @Override public int last() { return highLowContainer.last(); } + @Override + public int firstSigned() { + return highLowContainer.firstSigned(); + } + + @Override + public int lastSigned() { + return highLowContainer.lastSigned(); + } + @Override public long nextValue(int fromValue) { char key = highbits(fromValue); @@ -1687,7 +1820,8 @@ public long nextValue(int fromValue) { while (containerIndex < highLowContainer.size() && nextSetBit == -1L) { char containerKey = highLowContainer.getKeyAtIndex(containerIndex); MappeableContainer container = highLowContainer.getContainerAtIndex(containerIndex); - int bit = ((containerKey) - (key) > 0 + int bit = + ((containerKey) - (key) > 0 ? container.first() : container.nextValue(lowbits(fromValue))); nextSetBit = bit == -1 ? -1L : toUnsignedLong((containerKey << 16) | bit); @@ -1706,18 +1840,18 @@ public long previousValue(int fromValue) { char key = highbits(fromValue); int containerIndex = highLowContainer.advanceUntil(key, -1); if (containerIndex == highLowContainer.size()) { - return last(); + return Util.toUnsignedLong(last()); } if (highLowContainer.getKeyAtIndex(containerIndex) > key) { - return -1L; + // target absent, key of first container after target too high + --containerIndex; } long prevSetBit = -1L; - while (containerIndex != -1 && containerIndex < highLowContainer.size() && prevSetBit == -1L) { + while (containerIndex != -1 && prevSetBit == -1L) { char containerKey = highLowContainer.getKeyAtIndex(containerIndex); MappeableContainer container = highLowContainer.getContainerAtIndex(containerIndex); - int bit = (containerKey < key - ? container.last() - : container.previousValue(lowbits(fromValue))); + int bit = + (containerKey < key ? container.last() : container.previousValue(lowbits(fromValue))); prevSetBit = bit == -1 ? -1L : toUnsignedLong((containerKey << 16) | bit); --containerIndex; } @@ -1729,9 +1863,9 @@ public long previousValue(int fromValue) { @Override public long nextAbsentValue(int fromValue) { long nextAbsentBit = computeNextAbsentValue(fromValue); - assert nextAbsentBit <= 0xFFFFFFFFL; - assert nextAbsentBit >= Util.toUnsignedLong(fromValue); - assert !contains((int) nextAbsentBit); + if (nextAbsentBit == 0x100000000L) { + return -1L; + } return nextAbsentBit; } @@ -1855,7 +1989,6 @@ public int serializedSizeInBytes() { return this.highLowContainer.serializedSizeInBytes(); } - /** * Return the set values as an array if the cardinality is less * than 2147483648. The integer values are in sorted order. @@ -1890,7 +2023,6 @@ public MutableRoaringBitmap toMutableRoaringBitmap() { return c; } - /** * Copies this bitmap to a mutable RoaringBitmap. * @@ -1900,7 +2032,6 @@ public RoaringBitmap toRoaringBitmap() { return new RoaringBitmap(this); } - /** * A string describing the bitmap. * @@ -1917,7 +2048,7 @@ public String toString() { while (i.hasNext()) { answer.append(','); // to avoid using too much memory, we limit the size - if(answer.length() > 0x80000) { + if (answer.length() > 0x80000) { answer.append('.').append('.').append('.'); break; } @@ -1927,4 +2058,13 @@ public String toString() { return answer.toString(); } + /** + * Returns the number of containers in the bitmap. + * + * @return the number of containers + */ + @Override + public int getContainerCount() { + return highLowContainer.size(); + } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableArrayContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableArrayContainer.java similarity index 78% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableArrayContainer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableArrayContainer.java index f86dc6bb0..4285e450d 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableArrayContainer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableArrayContainer.java @@ -4,7 +4,15 @@ package org.roaringbitmap.buffer; -import org.roaringbitmap.*; +import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY; + +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.CharIterator; +import org.roaringbitmap.Container; +import org.roaringbitmap.ContainerBatchIterator; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.PeekableCharIterator; +import org.roaringbitmap.Util; import java.io.DataOutput; import java.io.IOException; @@ -16,9 +24,6 @@ import java.util.Arrays; import java.util.Iterator; -import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY; - - /** * Simple container made of an array of 16-bit integers. Unlike org.roaringbitmap.ArrayContainer, * this class uses a CharBuffer to store data. @@ -27,7 +32,7 @@ public final class MappeableArrayContainer extends MappeableContainer implements private static final int DEFAULT_INIT_SIZE = 4; private static final int ARRAY_LAZY_LOWERBOUND = 1024; protected static final int DEFAULT_MAX_SIZE = 4096; // containers with DEFAULT_MAX_SZE or less - // integers should be ArrayContainers + // integers should be ArrayContainers private static final long serialVersionUID = 1L; @@ -41,11 +46,8 @@ protected static int serializedSizeInBytes(int cardinality) { protected int cardinality = 0; - protected CharBuffer content; - - /** * Create an array container with default capacity */ @@ -67,7 +69,6 @@ public MappeableArrayContainer(ArrayContainer bc) { this.content = bc.toCharBuffer(); } - /** * Create an array container with specified capacity * @@ -96,7 +97,7 @@ public MappeableArrayContainer(final int firstOfRun, final int lastOfRun) { private MappeableArrayContainer(int newCard, CharBuffer newContent) { this.cardinality = newCard; - CharBuffer tmp = newContent.duplicate();// for thread-safety + CharBuffer tmp = newContent.duplicate(); // for thread-safety this.content = CharBuffer.allocate(Math.max(newCard, tmp.limit())); tmp.rewind(); this.content.put(tmp); @@ -130,7 +131,8 @@ public MappeableContainer add(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = + BufferUtil.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { @@ -146,8 +148,8 @@ public MappeableContainer add(int begin, int end) { if (!BufferUtil.isBackedBySimpleArray(answer.content)) { throw new RuntimeException("Should not happen. Internal bug."); } - BufferUtil.arraycopy(content, indexend, answer.content, indexstart + rangelength, - cardinality - indexend); + BufferUtil.arraycopy( + content, indexend, answer.content, indexstart + rangelength, cardinality - indexend); char[] answerarray = answer.content.array(); for (int k = 0; k < rangelength; ++k) { answerarray[k + indexstart] = (char) (begin + k); @@ -165,8 +167,7 @@ public MappeableContainer add(final char x) { if (BufferUtil.isBackedBySimpleArray(this.content)) { char[] sarray = content.array(); - if (cardinality == 0 || (cardinality > 0 - && (x) > (sarray[cardinality - 1]))) { + if (cardinality == 0 || (cardinality > 0 && (x) > (sarray[cardinality - 1]))) { if (cardinality >= DEFAULT_MAX_SIZE) { return toBitmapContainer().add(x); } @@ -198,8 +199,7 @@ public MappeableContainer add(final char x) { } } } else { - if (cardinality == 0 || (cardinality > 0 - && (x) > (content.get(cardinality - 1)))) { + if (cardinality == 0 || (cardinality > 0 && (x) > (content.get(cardinality - 1)))) { if (cardinality >= DEFAULT_MAX_SIZE) { return toBitmapContainer().add(x); } @@ -281,7 +281,6 @@ private int advance(CharIterator it) { } } - @Override public MappeableArrayContainer and(final MappeableArrayContainer value2) { @@ -290,12 +289,21 @@ public MappeableArrayContainer and(final MappeableArrayContainer value2) { MappeableArrayContainer answer = new MappeableArrayContainer(desiredCapacity); if (BufferUtil.isBackedBySimpleArray(this.content) && BufferUtil.isBackedBySimpleArray(value2.content)) { - answer.cardinality = org.roaringbitmap.Util.unsignedIntersect2by2(value1.content.array(), - value1.getCardinality(), value2.content.array(), value2.getCardinality(), - answer.content.array()); + answer.cardinality = + org.roaringbitmap.Util.unsignedIntersect2by2( + value1.content.array(), + value1.getCardinality(), + value2.content.array(), + value2.getCardinality(), + answer.content.array()); } else { - answer.cardinality = BufferUtil.unsignedIntersect2by2(value1.content, value1.getCardinality(), - value2.content, value2.getCardinality(), answer.content.array()); + answer.cardinality = + BufferUtil.unsignedIntersect2by2( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + answer.content.array()); } return answer; } @@ -310,7 +318,6 @@ public MappeableContainer and(final MappeableRunContainer value2) { return value2.and(this); } - @Override public MappeableArrayContainer andNot(final MappeableArrayContainer value2) { final MappeableArrayContainer value1 = this; @@ -319,11 +326,20 @@ public MappeableArrayContainer andNot(final MappeableArrayContainer value2) { if (BufferUtil.isBackedBySimpleArray(value1.content) && BufferUtil.isBackedBySimpleArray(value2.content)) { answer.cardinality = - org.roaringbitmap.Util.unsignedDifference(value1.content.array(), value1.getCardinality(), - value2.content.array(), value2.getCardinality(), answer.content.array()); + org.roaringbitmap.Util.unsignedDifference( + value1.content.array(), + value1.getCardinality(), + value2.content.array(), + value2.getCardinality(), + answer.content.array()); } else { - answer.cardinality = BufferUtil.unsignedDifference(value1.content, value1.getCardinality(), - value2.content, value2.getCardinality(), answer.content.array()); + answer.cardinality = + BufferUtil.unsignedDifference( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + answer.content.array()); } return answer; } @@ -339,13 +355,13 @@ public MappeableArrayContainer andNot(MappeableBitmapContainer value2) { for (int k = 0; k < cardinality; ++k) { char v = c[k]; sarray[pos] = v; - pos += 1 - (int)value2.bitValue(v); + pos += 1 - (int) value2.bitValue(v); } } else { for (int k = 0; k < cardinality; ++k) { char v = this.content.get(k); sarray[pos] = v; - pos += 1 - (int)value2.bitValue(v); + pos += 1 - (int) value2.bitValue(v); } } answer.cardinality = pos; @@ -379,7 +395,6 @@ public MappeableContainer andNot(final MappeableRunContainer x) { write += cardinality - read; answer.cardinality = write; return answer; - } @Override @@ -410,7 +425,6 @@ public static boolean contains(ByteBuffer buf, int position, final char x, int c return BufferUtil.unsignedBinarySearch(buf, position, 0, cardinality, x) >= 0; } - // in order // not thread-safe private void emit(char val) { @@ -452,7 +466,6 @@ public boolean equals(Object o) { return false; } - @Override public void fillLeastSignificant16bits(int[] x, int i, int mask) { if (BufferUtil.isBackedBySimpleArray(this.content)) { @@ -588,7 +601,8 @@ public MappeableContainer iadd(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = + BufferUtil.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { @@ -635,12 +649,12 @@ public MappeableContainer iadd(int begin, int end) { destination.put(k + indexstart, (char) (begin + k)); } } - BufferUtil.arraycopy(content, indexend, destination, indexstart + rangelength, cardinality - - indexend); + BufferUtil.arraycopy( + content, indexend, destination, indexstart + rangelength, cardinality - indexend); this.content = destination; } else { - BufferUtil.arraycopy(content, indexend, content, indexstart + rangelength, cardinality - - indexend); + BufferUtil.arraycopy( + content, indexend, content, indexstart + rangelength, cardinality - indexend); if (BufferUtil.isBackedBySimpleArray(content)) { char[] contentarray = content.array(); for (int k = 0; k < rangelength; ++k) { @@ -662,29 +676,42 @@ public MappeableArrayContainer iand(final MappeableArrayContainer value2) { if (!BufferUtil.isBackedBySimpleArray(value1.content)) { throw new RuntimeException("Should not happen. Internal bug."); } - value1.cardinality = BufferUtil.unsignedIntersect2by2(value1.content, value1.getCardinality(), - value2.content, value2.getCardinality(), value1.content.array()); + value1.cardinality = + BufferUtil.unsignedIntersect2by2( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + value1.content.array()); return this; } - @Override public MappeableContainer iand(MappeableBitmapContainer value2) { int pos = 0; for (int k = 0; k < cardinality; ++k) { char v = this.content.get(k); this.content.put(pos, v); - pos += (int)value2.bitValue(v); + pos += (int) value2.bitValue(v); } cardinality = pos; return this; } - - // Note it is never inplace, may wish to fix @Override public MappeableContainer iand(final MappeableRunContainer value2) { - return value2.and(this); + PeekableCharIterator it = value2.getCharIterator(); + int removed = 0; + for (int i = 0; i < cardinality; i++) { + it.advanceIfNeeded(content.get(i)); + if (it.peekNext() == content.get(i)) { + content.put(i - removed, content.get(i)); + } else { + removed++; + } + } + cardinality -= removed; + return this; } @Override @@ -694,11 +721,20 @@ public MappeableArrayContainer iandNot(final MappeableArrayContainer value2) { } if (BufferUtil.isBackedBySimpleArray(value2.content)) { this.cardinality = - org.roaringbitmap.Util.unsignedDifference(this.content.array(), this.getCardinality(), - value2.content.array(), value2.getCardinality(), this.content.array()); + org.roaringbitmap.Util.unsignedDifference( + this.content.array(), + this.getCardinality(), + value2.content.array(), + value2.getCardinality(), + this.content.array()); } else { - this.cardinality = BufferUtil.unsignedDifference(this.content, this.getCardinality(), - value2.content, value2.getCardinality(), this.content.array()); + this.cardinality = + BufferUtil.unsignedDifference( + this.content, + this.getCardinality(), + value2.content, + value2.getCardinality(), + this.content.array()); } return this; @@ -714,15 +750,26 @@ public MappeableArrayContainer iandNot(MappeableBitmapContainer value2) { for (int k = 0; k < cardinality; ++k) { char v = c[k]; c[pos] = v; - pos += 1 - (int)value2.bitValue(v); + pos += 1 - (int) value2.bitValue(v); } this.cardinality = pos; return this; } @Override - public MappeableContainer iandNot(final MappeableRunContainer value2) { // not inplace, revisit? - return andNot(value2); + public MappeableContainer iandNot(final MappeableRunContainer value2) { + PeekableCharIterator it = value2.getCharIterator(); + int removed = 0; + for (int i = 0; i < cardinality; i++) { + it.advanceIfNeeded(content.get(i)); + if (it.peekNext() != content.get(i)) { + content.put(i - removed, content.get(i)); + } else { + removed++; + } + } + cardinality -= removed; + return this; } private void increaseCapacity() { @@ -733,16 +780,16 @@ private void increaseCapacity() { // the illegal container does not return it. // not thread safe! private void increaseCapacity(boolean allowIllegalSize) { - int len = this.content.limit(); - int newCapacity = (len == 0) ? DEFAULT_INIT_SIZE - : len < 64 ? len * 2 : this.content.limit() < 1067 ? len * 3 / 2 : len * 5 / 4; + int newCapacity = calculateCapacity(); // do not allocate more than we will ever need if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE && !allowIllegalSize) { newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE; } // if we are within 1/16th of the max., go to max right away to avoid further reallocations - if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE - - MappeableArrayContainer.DEFAULT_MAX_SIZE / 16 && !allowIllegalSize) { + if (newCapacity + > MappeableArrayContainer.DEFAULT_MAX_SIZE + - MappeableArrayContainer.DEFAULT_MAX_SIZE / 16 + && !allowIllegalSize) { newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE; } final CharBuffer newContent = CharBuffer.allocate(newCapacity); @@ -751,18 +798,26 @@ private void increaseCapacity(boolean allowIllegalSize) { this.content = newContent; } - private int calculateCapacity(int min){ + private int calculateCapacity() { int len = this.content.limit(); - int newCapacity = (len == 0) ? DEFAULT_INIT_SIZE - : len < 64 ? len * 2 : len < 1024 ? len * 3 / 2 : len * 5 / 4; + int newCapacity = + (len == 0) + ? DEFAULT_INIT_SIZE + : len < 64 ? len * 2 : len < 1067 ? len * 3 / 2 : len * 5 / 4; + return newCapacity; + } + + private int calculateCapacity(int min) { + int newCapacity = calculateCapacity(); if (newCapacity < min) { newCapacity = min; } if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE) { newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE; } - if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE - - MappeableArrayContainer.DEFAULT_MAX_SIZE / 16) { + if (newCapacity + > MappeableArrayContainer.DEFAULT_MAX_SIZE + - MappeableArrayContainer.DEFAULT_MAX_SIZE / 16) { newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE; } return newCapacity; @@ -779,7 +834,7 @@ public MappeableContainer inot(final int firstOfRange, final int lastOfRange) { startIndex = -startIndex - 1; } int lastIndex = - BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char) (lastOfRange - 1)); + BufferUtil.unsignedBinarySearch(content, startIndex, cardinality, (char) (lastOfRange - 1)); if (lastIndex < 0) { lastIndex = -lastIndex - 1 - 1; } @@ -822,8 +877,8 @@ public MappeableContainer inot(final int firstOfRange, final int lastOfRange) { @Override public boolean intersects(MappeableArrayContainer value2) { MappeableArrayContainer value1 = this; - return BufferUtil.unsignedIntersects(value1.content, value1.getCardinality(), value2.content, - value2.getCardinality()); + return BufferUtil.unsignedIntersects( + value1.content, value1.getCardinality(), value2.content, value2.getCardinality()); } @Override @@ -839,51 +894,8 @@ public boolean intersects(MappeableRunContainer x) { @Override public MappeableContainer ior(final MappeableArrayContainer value2) { final int totalCardinality = getCardinality() + value2.getCardinality(); - if (totalCardinality > DEFAULT_MAX_SIZE) {// it could be a bitmap! - final MappeableBitmapContainer bc = new MappeableBitmapContainer(); - if (!BufferUtil.isBackedBySimpleArray(bc.bitmap)) { - throw new RuntimeException("Should not happen. Internal bug."); - } - long[] bitArray = bc.bitmap.array(); - if (BufferUtil.isBackedBySimpleArray(value2.content)) { - char[] sarray = value2.content.array(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } else { - for (int k = 0; k < value2.cardinality; ++k) { - char v2 = value2.content.get(k); - final int i = (v2) >>> 6; - bitArray[i] |= (1L << v2); - } - } - if (BufferUtil.isBackedBySimpleArray(content)) { - char[] sarray = content.array(); - for (int k = 0; k < cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } else { - for (int k = 0; k < cardinality; ++k) { - char v = content.get(k); - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } - bc.cardinality = 0; - int len = bc.bitmap.limit(); - for (int index = 0; index < len; ++index) { - bc.cardinality += Long.bitCount(bitArray[index]); - } - if (bc.cardinality <= DEFAULT_MAX_SIZE) { - return bc.toArrayContainer(); - } else if (bc.isFull()) { - return MappeableRunContainer.full(); - } - return bc; + if (totalCardinality > DEFAULT_MAX_SIZE) { + return toBitmapContainer().lazyIOR(value2).repairAfterLazy(); } if (totalCardinality >= content.limit()) { int newCapacity = calculateCapacity(totalCardinality); @@ -892,12 +904,24 @@ public MappeableContainer ior(final MappeableArrayContainer value2) { if (BufferUtil.isBackedBySimpleArray(content) && BufferUtil.isBackedBySimpleArray(value2.content)) { cardinality = - Util.unsignedUnion2by2(content.array(), 0, cardinality, value2.content.array(), 0, - value2.cardinality, destination.array()); + Util.unsignedUnion2by2( + content.array(), + 0, + cardinality, + value2.content.array(), + 0, + value2.cardinality, + destination.array()); } else { cardinality = - BufferUtil.unsignedUnion2by2(content, 0, cardinality, value2.content, 0, - value2.cardinality, destination.array()); + BufferUtil.unsignedUnion2by2( + content, + 0, + cardinality, + value2.content, + 0, + value2.cardinality, + destination.array()); } this.content = destination; } else { @@ -906,12 +930,24 @@ public MappeableContainer ior(final MappeableArrayContainer value2) { if (BufferUtil.isBackedBySimpleArray(content) && BufferUtil.isBackedBySimpleArray(value2.content)) { cardinality = - Util.unsignedUnion2by2(content.array(), value2.cardinality, cardinality, - value2.content.array(), 0, value2.cardinality, content.array()); + Util.unsignedUnion2by2( + content.array(), + value2.cardinality, + cardinality, + value2.content.array(), + 0, + value2.cardinality, + content.array()); } else { cardinality = - BufferUtil.unsignedUnion2by2(content, value2.cardinality, cardinality, value2.content, - 0, value2.cardinality, content.array()); + BufferUtil.unsignedUnion2by2( + content, + value2.cardinality, + cardinality, + value2.content, + 0, + value2.cardinality, + content.array()); } } return this; @@ -940,14 +976,19 @@ public MappeableContainer iremove(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = + BufferUtil.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { indexend++; } int rangelength = indexend - indexstart; - BufferUtil.arraycopy(content, indexstart + rangelength, content, indexstart, + BufferUtil.arraycopy( + content, + indexstart + rangelength, + content, + indexstart, cardinality - indexstart - rangelength); cardinality -= rangelength; return this; @@ -958,7 +999,6 @@ protected boolean isArrayBacked() { return BufferUtil.isBackedBySimpleArray(this.content); } - @Override public Iterator iterator() { @@ -988,7 +1028,6 @@ public MappeableContainer ixor(final MappeableArrayContainer value2) { return this.xor(value2); } - @Override public MappeableContainer ixor(MappeableBitmapContainer x) { return x.xor(this); @@ -1008,18 +1047,21 @@ public MappeableContainer limit(int maxcardinality) { } } - void loadData(final MappeableBitmapContainer bitmapContainer) { this.cardinality = bitmapContainer.cardinality; if (!BufferUtil.isBackedBySimpleArray(this.content)) { throw new RuntimeException("Should not happen. Internal bug."); } - bitmapContainer.fillArray(content.array()); + Util.fillArray(bitmapContainer.bitmap.array(), content.array()); } // for use in inot range known to be nonempty - private void negateRange(final CharBuffer buffer, final int startIndex, final int lastIndex, - final int startRange, final int lastRange) { + private void negateRange( + final CharBuffer buffer, + final int startIndex, + final int lastIndex, + final int startRange, + final int lastRange) { // compute the negation into buffer int outPos = 0; @@ -1070,7 +1112,7 @@ public MappeableContainer not(final int firstOfRange, final int lastOfRange) { startIndex = -startIndex - 1; } int lastIndex = - BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char) (lastOfRange - 1)); + BufferUtil.unsignedBinarySearch(content, startIndex, cardinality, (char) (lastOfRange - 1)); if (lastIndex < 0) { lastIndex = -lastIndex - 2; } @@ -1152,73 +1194,35 @@ int numberOfRuns() { } } - @Override public MappeableContainer or(final MappeableArrayContainer value2) { final MappeableArrayContainer value1 = this; final int totalCardinality = value1.getCardinality() + value2.getCardinality(); - if (totalCardinality > DEFAULT_MAX_SIZE) {// it could be a bitmap! - final MappeableBitmapContainer bc = new MappeableBitmapContainer(); - if (!BufferUtil.isBackedBySimpleArray(bc.bitmap)) { - throw new RuntimeException("Should not happen. Internal bug."); - } - long[] bitArray = bc.bitmap.array(); - if (BufferUtil.isBackedBySimpleArray(value2.content)) { - char[] sarray = value2.content.array(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } else { - for (int k = 0; k < value2.cardinality; ++k) { - char v2 = value2.content.get(k); - final int i = (v2) >>> 6; - bitArray[i] |= (1L << v2); - } - } - if (BufferUtil.isBackedBySimpleArray(this.content)) { - char[] sarray = this.content.array(); - for (int k = 0; k < this.cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } else { - for (int k = 0; k < this.cardinality; ++k) { - char v = this.content.get(k); - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } - bc.cardinality = 0; - int len = bc.bitmap.limit(); - for (int index = 0; index < len; ++index) { - bc.cardinality += Long.bitCount(bitArray[index]); - } - if (bc.cardinality <= DEFAULT_MAX_SIZE) { - return bc.toArrayContainer(); - } else if (bc.isFull()) { - return MappeableRunContainer.full(); - } - return bc; + if (totalCardinality > DEFAULT_MAX_SIZE) { + return toBitmapContainer().lazyIOR(value2).repairAfterLazy(); } final MappeableArrayContainer answer = new MappeableArrayContainer(totalCardinality); if (BufferUtil.isBackedBySimpleArray(value1.content) && BufferUtil.isBackedBySimpleArray(value2.content)) { answer.cardinality = Util.unsignedUnion2by2( - value1.content.array(), 0, value1.getCardinality(), - value2.content.array(), 0, value2.getCardinality(), - answer.content.array() - ); + value1.content.array(), + 0, + value1.getCardinality(), + value2.content.array(), + 0, + value2.getCardinality(), + answer.content.array()); } else { answer.cardinality = - BufferUtil.unsignedUnion2by2( - value1.content, 0, value1.getCardinality(), - value2.content, 0, value2.getCardinality(), - answer.content.array() - ); + BufferUtil.unsignedUnion2by2( + value1.content, + 0, + value1.getCardinality(), + value2.content, + 0, + value2.getCardinality(), + answer.content.array()); } return answer; } @@ -1226,64 +1230,35 @@ public MappeableContainer or(final MappeableArrayContainer value2) { protected MappeableContainer lazyor(final MappeableArrayContainer value2) { final MappeableArrayContainer value1 = this; final int totalCardinality = value1.getCardinality() + value2.getCardinality(); - if (totalCardinality > ARRAY_LAZY_LOWERBOUND) {// it could be a bitmap! - final MappeableBitmapContainer bc = new MappeableBitmapContainer(); - if (!BufferUtil.isBackedBySimpleArray(bc.bitmap)) { - throw new RuntimeException("Should not happen. Internal bug."); - } - long[] bitArray = bc.bitmap.array(); - if (BufferUtil.isBackedBySimpleArray(value2.content)) { - char[] sarray = value2.content.array(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } else { - for (int k = 0; k < value2.cardinality; ++k) { - char v2 = value2.content.get(k); - final int i = (v2) >>> 6; - bitArray[i] |= (1L << v2); - } - } - if (BufferUtil.isBackedBySimpleArray(this.content)) { - char[] sarray = this.content.array(); - for (int k = 0; k < this.cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } else { - for (int k = 0; k < this.cardinality; ++k) { - char v = this.content.get(k); - final int i = (v) >>> 6; - bitArray[i] |= (1L << v); - } - } - bc.cardinality = -1; - return bc; + if (totalCardinality > ARRAY_LAZY_LOWERBOUND) { + return toBitmapContainer().lazyIOR(value2); } final MappeableArrayContainer answer = new MappeableArrayContainer(totalCardinality); if (BufferUtil.isBackedBySimpleArray(value1.content) && BufferUtil.isBackedBySimpleArray(value2.content)) { answer.cardinality = - Util.unsignedUnion2by2( - value1.content.array(), 0, value1.getCardinality(), - value2.content.array(), 0, value2.getCardinality(), - answer.content.array() - ); + Util.unsignedUnion2by2( + value1.content.array(), + 0, + value1.getCardinality(), + value2.content.array(), + 0, + value2.getCardinality(), + answer.content.array()); } else { answer.cardinality = - BufferUtil.unsignedUnion2by2( - value1.content, 0, value1.getCardinality(), - value2.content, 0, value2.getCardinality(), - answer.content.array() - ); + BufferUtil.unsignedUnion2by2( + value1.content, + 0, + value1.getCardinality(), + value2.content, + 0, + value2.getCardinality(), + answer.content.array()); } return answer; } - @Override public MappeableContainer or(MappeableBitmapContainer x) { return x.or(this); @@ -1376,7 +1351,8 @@ public MappeableContainer remove(int begin, int end) { if (indexstart < 0) { indexstart = -indexstart - 1; } - int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char) (end - 1)); + int indexend = + BufferUtil.unsignedBinarySearch(content, indexstart, cardinality, (char) (end - 1)); if (indexend < 0) { indexend = -indexend - 1; } else { @@ -1384,7 +1360,11 @@ public MappeableContainer remove(int begin, int end) { } int rangelength = indexend - indexstart; MappeableArrayContainer answer = clone(); - BufferUtil.arraycopy(content, indexstart + rangelength, answer.content, indexstart, + BufferUtil.arraycopy( + content, + indexstart + rangelength, + answer.content, + indexstart, cardinality - indexstart - rangelength); answer.cardinality = cardinality - rangelength; return answer; @@ -1395,7 +1375,6 @@ void removeAtIndex(final int loc) { --cardinality; } - @Override public MappeableContainer remove(final char x) { if (BufferUtil.isBackedBySimpleArray(this.content)) { @@ -1414,7 +1393,6 @@ public MappeableContainer remove(final char x) { --cardinality; } return this; - } } @@ -1423,17 +1401,16 @@ public MappeableContainer repairAfterLazy() { return this; } - @Override public MappeableContainer runOptimize() { int numRuns = numberOfRuns(); int sizeAsRunContainer = MappeableRunContainer.getArraySizeInBytes(numRuns); if (getArraySizeInBytes() > sizeAsRunContainer) { return new MappeableRunContainer(this, numRuns); // this could be - // maybe faster if - // initial - // container is a - // bitmap + // maybe faster if + // initial + // container is a + // bitmap } else { return this; } @@ -1589,14 +1566,14 @@ public String toString() { if (this.cardinality == 0) { return "{}"; } - final StringBuilder sb = new StringBuilder("{}".length() + "-123456789,".length() - * cardinality); + final StringBuilder sb = + new StringBuilder("{}".length() + "-123456789,".length() * cardinality); sb.append('{'); for (int i = 0; i < this.cardinality - 1; i++) { - sb.append((int)(this.content.get(i))); + sb.append((int) (this.content.get(i))); sb.append(','); } - sb.append((int)(this.content.get(this.cardinality - 1))); + sb.append((int) (this.content.get(this.cardinality - 1))); sb.append('}'); return sb.toString(); } @@ -1666,60 +1643,27 @@ public void writeExternal(ObjectOutput out) throws IOException { public MappeableContainer xor(final MappeableArrayContainer value2) { final MappeableArrayContainer value1 = this; final int totalCardinality = value1.getCardinality() + value2.getCardinality(); - if (totalCardinality > DEFAULT_MAX_SIZE) {// it could be a bitmap! - final MappeableBitmapContainer bc = new MappeableBitmapContainer(); - if (!BufferUtil.isBackedBySimpleArray(bc.bitmap)) { - throw new RuntimeException("Should not happen. Internal bug."); - } - long[] bitArray = bc.bitmap.array(); - if (BufferUtil.isBackedBySimpleArray(value2.content)) { - char[] sarray = value2.content.array(); - for (int k = 0; k < value2.cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] ^= (1L << v); - } - } else { - for (int k = 0; k < value2.cardinality; ++k) { - char v2 = value2.content.get(k); - final int i = (v2) >>> 6; - bitArray[i] ^= (1L << v2); - } - } - if (BufferUtil.isBackedBySimpleArray(this.content)) { - char[] sarray = this.content.array(); - for (int k = 0; k < this.cardinality; ++k) { - char v = sarray[k]; - final int i = (v) >>> 6; - bitArray[i] ^= (1L << v); - } - } else { - for (int k = 0; k < this.cardinality; ++k) { - char v = this.content.get(k); - final int i = (v) >>> 6; - bitArray[i] ^= (1L << v); - } - } - - bc.cardinality = 0; - int len = bc.bitmap.limit(); - for (int index = 0; index < len; ++index) { - bc.cardinality += Long.bitCount(bitArray[index]); - } - if (bc.cardinality <= DEFAULT_MAX_SIZE) { - return bc.toArrayContainer(); - } - return bc; + if (totalCardinality > DEFAULT_MAX_SIZE) { + return toBitmapContainer().ixor(value2); } final MappeableArrayContainer answer = new MappeableArrayContainer(totalCardinality); if (BufferUtil.isBackedBySimpleArray(value1.content) && BufferUtil.isBackedBySimpleArray(value2.content)) { - answer.cardinality = org.roaringbitmap.Util.unsignedExclusiveUnion2by2(value1.content.array(), - value1.getCardinality(), value2.content.array(), value2.getCardinality(), - answer.content.array()); + answer.cardinality = + org.roaringbitmap.Util.unsignedExclusiveUnion2by2( + value1.content.array(), + value1.getCardinality(), + value2.content.array(), + value2.getCardinality(), + answer.content.array()); } else { - answer.cardinality = BufferUtil.unsignedExclusiveUnion2by2(value1.content, - value1.getCardinality(), value2.content, value2.getCardinality(), answer.content.array()); + answer.cardinality = + BufferUtil.unsignedExclusiveUnion2by2( + value1.content, + value1.getCardinality(), + value2.content, + value2.getCardinality(), + answer.content.array()); } return answer; } @@ -1734,7 +1678,6 @@ public MappeableContainer xor(final MappeableRunContainer value2) { return value2.xor(this); } - protected MappeableContainer xor(CharIterator it) { return or(it, true); } @@ -1758,11 +1701,11 @@ public void forEach(char msb, IntConsumer ic) { public int andCardinality(MappeableArrayContainer value2) { if (BufferUtil.isBackedBySimpleArray(content) && BufferUtil.isBackedBySimpleArray(value2.content)) { - return Util.unsignedLocalIntersect2by2Cardinality(content.array(), cardinality, - value2.content.array(), value2.getCardinality()); + return Util.unsignedLocalIntersect2by2Cardinality( + content.array(), cardinality, value2.content.array(), value2.getCardinality()); } - return BufferUtil.unsignedLocalIntersect2by2Cardinality(content, cardinality, - value2.content, value2.getCardinality()); + return BufferUtil.unsignedLocalIntersect2by2Cardinality( + content, cardinality, value2.content, value2.getCardinality()); } @Override @@ -1785,7 +1728,7 @@ protected boolean contains(MappeableRunContainer runContainer) { for (int i = 0; i < runContainer.numberOfRuns(); ++i) { int start = (runContainer.getValue(i)); int length = (runContainer.getLength(i)); - if (!contains(start, start + length)) { + if (!contains(start, start + length + 1)) { return false; } } @@ -1798,7 +1741,7 @@ protected boolean contains(MappeableArrayContainer arrayContainer) { return false; } int i1 = 0, i2 = 0; - while(i1 < cardinality && i2 < arrayContainer.cardinality) { + while (i1 < cardinality && i2 < arrayContainer.cardinality) { if (content.get(i1) == arrayContainer.content.get(i2)) { ++i1; ++i2; @@ -1818,10 +1761,10 @@ protected boolean contains(MappeableBitmapContainer bitmapContainer) { @Override public boolean intersects(int minimum, int supremum) { - if((minimum < 0) || (supremum < minimum) || (supremum > (1<<16))) { + if ((minimum < 0) || (supremum < minimum) || (supremum > (1 << 16))) { throw new RuntimeException("This should never happen (bug)."); } - int pos = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char)minimum); + int pos = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (char) minimum); int index = pos >= 0 ? pos : -pos - 1; return index < cardinality && (content.get(index)) < supremum; } @@ -1829,26 +1772,21 @@ public boolean intersects(int minimum, int supremum) { @Override public boolean contains(int minimum, int supremum) { int maximum = supremum - 1; - int start = BufferUtil.advanceUntil(content, -1, cardinality, (char)minimum); - int end = BufferUtil.advanceUntil(content, start - 1, cardinality, (char)maximum); + int start = BufferUtil.advanceUntil(content, -1, cardinality, (char) minimum); + int end = BufferUtil.advanceUntil(content, start - 1, cardinality, (char) maximum); return start < cardinality - && end < cardinality - && end - start == maximum - minimum - && content.get(start) == (char)minimum - && content.get(end) == (char)maximum; + && end < cardinality + && end - start == maximum - minimum + && content.get(start) == (char) minimum + && content.get(end) == (char) maximum; } - } - final class MappeableArrayContainerCharIterator implements PeekableCharIterator { int pos; private MappeableArrayContainer parent; - MappeableArrayContainerCharIterator() { - - } - + MappeableArrayContainerCharIterator() {} MappeableArrayContainerCharIterator(MappeableArrayContainer p) { wrap(p); @@ -1864,7 +1802,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -1878,7 +1816,6 @@ public char next() { return parent.content.get(pos++); } - @Override public int nextAsInt() { return (parent.content.get(pos++)); @@ -1889,7 +1826,6 @@ public char peekNext() { return parent.content.get(pos); } - @Override public void remove() { parent.removeAtIndex(pos - 1); @@ -1900,18 +1836,13 @@ void wrap(MappeableArrayContainer p) { parent = p; pos = 0; } - - - } - final class RawArrayContainerCharIterator implements PeekableCharIterator { int pos; private MappeableArrayContainer parent; char[] content; - RawArrayContainerCharIterator(MappeableArrayContainer p) { parent = p; if (!p.isArrayBacked()) { @@ -1921,7 +1852,6 @@ final class RawArrayContainerCharIterator implements PeekableCharIterator { pos = 0; } - @Override public void advanceIfNeeded(char minval) { pos = Util.advanceUntil(content, pos - 1, parent.cardinality, minval); @@ -1932,7 +1862,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -1961,16 +1891,13 @@ public void remove() { parent.removeAtIndex(pos - 1); pos--; } - } - final class RawReverseArrayContainerCharIterator implements CharIterator { int pos; private MappeableArrayContainer parent; char[] content; - RawReverseArrayContainerCharIterator(MappeableArrayContainer p) { parent = p; if (!p.isArrayBacked()) { @@ -1985,7 +1912,7 @@ public CharIterator clone() { try { return (CharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -1994,7 +1921,6 @@ public boolean hasNext() { return pos >= 0; } - @Override public char next() { return content[pos--]; @@ -2010,20 +1936,15 @@ public void remove() { parent.removeAtIndex(pos + 1); pos++; } - } - final class ReverseMappeableArrayContainerCharIterator implements CharIterator { int pos; private MappeableArrayContainer parent; - ReverseMappeableArrayContainerCharIterator() { - - } - + ReverseMappeableArrayContainerCharIterator() {} ReverseMappeableArrayContainerCharIterator(MappeableArrayContainer p) { wrap(p); @@ -2034,7 +1955,7 @@ public CharIterator clone() { try { return (CharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -2048,7 +1969,6 @@ public char next() { return parent.content.get(pos--); } - @Override public int nextAsInt() { return (parent.content.get(pos--)); @@ -2064,5 +1984,4 @@ void wrap(MappeableArrayContainer p) { parent = p; pos = parent.cardinality - 1; } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableBitmapContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableBitmapContainer.java similarity index 90% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableBitmapContainer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableBitmapContainer.java index a09c32852..cb0814752 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableBitmapContainer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableBitmapContainer.java @@ -4,7 +4,18 @@ package org.roaringbitmap.buffer; -import org.roaringbitmap.*; +import static java.lang.Long.numberOfLeadingZeros; +import static java.lang.Long.numberOfTrailingZeros; +import static java.nio.ByteOrder.LITTLE_ENDIAN; + +import org.roaringbitmap.BitSetUtil; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.CharIterator; +import org.roaringbitmap.Container; +import org.roaringbitmap.ContainerBatchIterator; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.PeekableCharIterator; +import org.roaringbitmap.Util; import java.io.DataOutput; import java.io.IOException; @@ -14,24 +25,23 @@ import java.nio.LongBuffer; import java.util.Iterator; -import static java.lang.Long.numberOfLeadingZeros; -import static java.lang.Long.numberOfTrailingZeros; -import static java.nio.ByteOrder.LITTLE_ENDIAN; - - /** * Simple bitset-like container. Unlike org.roaringbitmap.BitmapContainer, this class uses a * LongBuffer to store data. */ public final class MappeableBitmapContainer extends MappeableContainer implements Cloneable { - protected static final int MAX_CAPACITY = 1 << 16; + public static final int MAX_CAPACITY = 1 << 16; + + private static final int MAX_CAPACITY_BYTE = MAX_CAPACITY / Byte.SIZE; - - private static final long serialVersionUID = 2L; + private static final int MAX_CAPACITY_LONG = MAX_CAPACITY / Long.SIZE; + + private static final long serialVersionUID = 3L; // bail out early when the number of runs is excessive, without // an exact count (just a decent lower bound) private static final int BLOCKSIZE = 128; + // 64 words can have max 32 runs per word, max 2k runs /** @@ -40,7 +50,6 @@ public final class MappeableBitmapContainer extends MappeableContainer implement */ private static final boolean USE_BRANCHLESS = true; - // the parameter is for overloading and symmetry with ArrayContainer protected static int serializedSizeInBytes(int unusedCardinality) { return MAX_CAPACITY / 8; @@ -52,7 +61,7 @@ protected static int serializedSizeInBytes(int unusedCardinality) { // nruns value for which RunContainer.serializedSizeInBytes == // BitmapContainer.getArraySizeInBytes() - private final int MAXRUNS = (getArraySizeInBytes() - 2) / 4; + private static final int MAXRUNS = (MAX_CAPACITY_BYTE - 2) / 4; /** * Create a bitmap container with all bits set to false @@ -64,7 +73,7 @@ public MappeableBitmapContainer() { /** * Creates a new bitmap container from a non-mappeable one. This copies the data. - * + * * @param bc the original container */ public MappeableBitmapContainer(BitmapContainer bc) { @@ -76,7 +85,7 @@ public MappeableBitmapContainer(BitmapContainer bc) { * Create a bitmap container with a run of ones from firstOfRun to lastOfRun, inclusive caller * must ensure that the range isn't so small that an ArrayContainer should have been created * instead - * + * * @param firstOfRun first index * @param lastOfRun last index (range is exclusive) */ @@ -86,8 +95,6 @@ public MappeableBitmapContainer(final int firstOfRun, final int lastOfRun) { Util.setBitmapRange(bitmap.array(), firstOfRun, lastOfRun); } - - MappeableBitmapContainer(int newCardinality, LongBuffer newBitmap) { this.cardinality = newCardinality; LongBuffer tmp = newBitmap.duplicate(); // for thread safety @@ -98,14 +105,17 @@ public MappeableBitmapContainer(final int firstOfRun, final int lastOfRun) { /** * Construct a new BitmapContainer backed by the provided LongBuffer. - * + * * @param array LongBuffer where the data is stored * @param initCardinality cardinality (number of values stored) */ public MappeableBitmapContainer(final LongBuffer array, final int initCardinality) { if (array.limit() != MAX_CAPACITY / 64) { - throw new RuntimeException("Mismatch between buffer and storage requirements: " - + array.limit() + " vs. " + MAX_CAPACITY / 64); + throw new RuntimeException( + "Mismatch between buffer and storage requirements: " + + array.limit() + + " vs. " + + MAX_CAPACITY / 64); } this.cardinality = initCardinality; this.bitmap = array; @@ -127,14 +137,13 @@ public MappeableContainer add(int begin, int end) { return answer; } - @Override public MappeableContainer add(final char i) { final long previous = bitmap.get(i / 64); final long newv = previous | (1L << i); bitmap.put(i / 64, newv); if (USE_BRANCHLESS) { - cardinality += (int)((previous ^ newv) >>> i); + cardinality += (int) ((previous ^ newv) >>> i); } else if (previous != newv) { cardinality++; } @@ -160,7 +169,7 @@ public MappeableArrayContainer and(final MappeableArrayContainer value2) { for (int k = 0; k < ca; ++k) { char v = c[k]; sarray[answer.cardinality] = v; - answer.cardinality += (int)this.bitValue(v); + answer.cardinality += (int) this.bitValue(v); } } else { @@ -168,7 +177,7 @@ public MappeableArrayContainer and(final MappeableArrayContainer value2) { for (int k = 0; k < ca; ++k) { char v = value2.content.get(k); sarray[answer.cardinality] = v; - answer.cardinality += (int)this.bitValue(v); + answer.cardinality += (int) this.bitValue(v); } } return answer; @@ -217,8 +226,8 @@ public MappeableContainer and(final MappeableBitmapContainer value2) { final MappeableArrayContainer ac = new MappeableArrayContainer(newCardinality); if (BufferUtil.isBackedBySimpleArray(this.bitmap) && BufferUtil.isBackedBySimpleArray(value2.bitmap)) { - org.roaringbitmap.Util.fillArrayAND(ac.content.array(), this.bitmap.array(), - value2.bitmap.array()); + org.roaringbitmap.Util.fillArrayAND( + ac.content.array(), this.bitmap.array(), value2.bitmap.array()); } else { BufferUtil.fillArrayAND(ac.content.array(), this.bitmap, value2.bitmap); } @@ -231,8 +240,6 @@ public MappeableContainer and(final MappeableRunContainer value2) { return value2.and(this); } - - @Override public MappeableContainer andNot(final MappeableArrayContainer value2) { final MappeableBitmapContainer answer = clone(); @@ -269,8 +276,6 @@ public MappeableContainer andNot(final MappeableArrayContainer value2) { return answer; } - - @Override public MappeableContainer andNot(final MappeableBitmapContainer value2) { @@ -316,8 +321,8 @@ public MappeableContainer andNot(final MappeableBitmapContainer value2) { final MappeableArrayContainer ac = new MappeableArrayContainer(newCardinality); if (BufferUtil.isBackedBySimpleArray(this.bitmap) && BufferUtil.isBackedBySimpleArray(value2.bitmap)) { - org.roaringbitmap.Util.fillArrayANDNOT(ac.content.array(), this.bitmap.array(), - value2.bitmap.array()); + org.roaringbitmap.Util.fillArrayANDNOT( + ac.content.array(), this.bitmap.array(), value2.bitmap.array()); } else { BufferUtil.fillArrayANDNOT(ac.content.array(), this.bitmap, value2.bitmap); } @@ -331,8 +336,7 @@ public MappeableContainer andNot(final MappeableRunContainer value2) { long[] b = answer.bitmap.array(); for (int rlepos = 0; rlepos < value2.nbrruns; ++rlepos) { int start = (value2.getValue(rlepos)); - int end = (value2.getValue(rlepos)) - + (value2.getLength(rlepos)) + 1; + int end = (value2.getValue(rlepos)) + (value2.getLength(rlepos)) + 1; int prevOnesInRange = Util.cardinalityInBitmapRange(b, start, end); Util.resetBitmapRange(b, start, end); answer.updateCardinality(prevOnesInRange, 0); @@ -355,8 +359,6 @@ public void clear() { } } - - @Override public MappeableBitmapContainer clone() { return new MappeableBitmapContainer(this.cardinality, this.bitmap); @@ -403,11 +405,10 @@ public boolean contains(final char i) { long bitValue(final char i) { return (bitmap.get(i >>> 6) >>> i) & 1; } - - + /** * Checks whether the container contains the value i. - * + * * @param buf underlying buffer * @param position position of the container in the buffer * @param i index @@ -452,23 +453,14 @@ public boolean equals(Object o) { /** * Fill the array with set bits - * + * * @param array container (should be sufficiently large) */ void fillArray(final char[] array) { int pos = 0; if (BufferUtil.isBackedBySimpleArray(bitmap)) { long[] b = bitmap.array(); - int base = 0; - for (int k = 0; k < b.length; ++k) { - long bitset = b[k]; - while (bitset != 0) { - array[pos++] = (char) (base + numberOfTrailingZeros(bitset)); - bitset &= (bitset - 1); - } - base += 64; - } - + BitSetUtil.arrayContainerBufferOf(0, b.length, array, b); } else { int len = this.bitmap.limit(); int base = 0; @@ -516,8 +508,8 @@ public void fillLeastSignificant16bits(int[] x, int i, int mask) { public MappeableContainer flip(char i) { final long bef = bitmap.get(i >>> 6); final long mask = 1L << i; - if (cardinality == MappeableArrayContainer.DEFAULT_MAX_SIZE + 1) {// this - // is + if (cardinality == MappeableArrayContainer.DEFAULT_MAX_SIZE + 1) { // this + // is // the // uncommon // path @@ -529,19 +521,16 @@ public MappeableContainer flip(char i) { } long aft = bef ^ mask; // TODO: check whether a branchy version could be faster - cardinality += 1 - 2 * (int)((bef & mask) >>> i); + cardinality += 1 - 2 * (int) ((bef & mask) >>> i); bitmap.put(i >>> 6, aft); return this; } - @Override protected int getArraySizeInBytes() { - return MAX_CAPACITY / 8; + return MAX_CAPACITY_BYTE; } - - @Override public int getCardinality() { return cardinality; @@ -604,11 +593,10 @@ public MappeableContainer iand(final MappeableArrayContainer b2) { BufferUtil.intersectArrayIntoBitmap(bitmap, b2.content, b2.cardinality); return this; } else { - return b2.and(this);// no inplace possible + return b2.and(this); // no inplace possible } } - @Override public MappeableContainer iand(final MappeableBitmapContainer b2) { if (BufferUtil.isBackedBySimpleArray(this.bitmap) @@ -676,7 +664,7 @@ public MappeableContainer iand(final MappeableRunContainer x) { int runEnd = runStart + (x.getLength(rlepos)); for (int runValue = runStart; runValue <= runEnd; ++runValue) { answer.content.put(answer.cardinality, (char) runValue); - answer.cardinality += (int)this.bitValue((char) runValue); + answer.cardinality += (int) this.bitValue((char) runValue); } } return answer; @@ -717,8 +705,6 @@ public MappeableContainer iandNot(final MappeableArrayContainer b2) { return this; } - - @Override public MappeableContainer iandNot(final MappeableBitmapContainer b2) { int newCardinality = 0; @@ -743,7 +729,6 @@ public MappeableContainer iandNot(final MappeableBitmapContainer b2) { org.roaringbitmap.Util.fillArrayANDNOT(ac.content.array(), b, b2Arr); ac.cardinality = newCardinality; return ac; - } int len = this.bitmap.limit(); for (int k = 0; k < len; ++k) { @@ -792,11 +777,10 @@ public MappeableContainer iandNot(final MappeableRunContainer x) { } else { return toArrayContainer(); } - } MappeableContainer ilazyor(MappeableArrayContainer value2) { - this.cardinality = -1;// invalid + this.cardinality = -1; // invalid if (!BufferUtil.isBackedBySimpleArray(bitmap)) { throw new RuntimeException("Should not happen. Internal bug."); } @@ -823,11 +807,10 @@ MappeableContainer ilazyor(MappeableBitmapContainer x) { this.bitmap.put(k, this.bitmap.get(k) | x.bitmap.get(k)); } } - this.cardinality = -1;// invalid + this.cardinality = -1; // invalid return this; } - MappeableContainer ilazyor(MappeableRunContainer x) { for (int rlepos = 0; rlepos < x.nbrruns; ++rlepos) { int start = (x.getValue(rlepos)); @@ -849,7 +832,6 @@ public MappeableContainer inot(final int firstOfRange, final int lastOfRange) { return this; } - @Override public boolean intersects(MappeableArrayContainer value2) { if (BufferUtil.isBackedBySimpleArray(value2.content)) { @@ -901,8 +883,6 @@ public boolean intersects(MappeableRunContainer x) { return x.intersects(this); } - - @Override public MappeableBitmapContainer ior(final MappeableArrayContainer value2) { if (!BufferUtil.isBackedBySimpleArray(this.bitmap)) { @@ -918,7 +898,7 @@ public MappeableBitmapContainer ior(final MappeableArrayContainer value2) { long aft = bef | (1L << v2[k]); b[i] = aft; if (USE_BRANCHLESS) { - cardinality += (int)((bef - aft) >>> 63); + cardinality += (int) ((bef - aft) >>> 63); } else { if (aft != bef) { cardinality++; @@ -935,7 +915,7 @@ public MappeableBitmapContainer ior(final MappeableArrayContainer value2) { long aft = bef | (1L << v2); b[i] = aft; if (USE_BRANCHLESS) { - cardinality += (int)((bef - aft) >>> 63); + cardinality += (int) ((bef - aft) >>> 63); } else { if (aft != bef) { cardinality++; @@ -1089,7 +1069,7 @@ public MappeableContainer ixor(final MappeableArrayContainer value2) { final int index = (vc) >>> 6; long ba = b[index]; // TODO: check whether a branchy version could be faster - this.cardinality += 1 - 2 * (int)((ba & mask) >>> vc); + this.cardinality += 1 - 2 * (int) ((ba & mask) >>> vc); b[index] = ba ^ mask; } @@ -1101,7 +1081,7 @@ public MappeableContainer ixor(final MappeableArrayContainer value2) { final int index = (v2) >>> 6; long ba = b[index]; // TODO: check whether a branchy version could be faster - this.cardinality += 1 - 2 * (int)((ba & mask) >>> v2); + this.cardinality += 1 - 2 * (int) ((ba & mask) >>> v2); b[index] = ba ^ mask; } } @@ -1137,7 +1117,6 @@ public MappeableContainer ixor(MappeableBitmapContainer b2) { org.roaringbitmap.Util.fillArrayXOR(ac.content.array(), b, b2Arr); ac.cardinality = newCardinality; return ac; - } int newCardinality = 0; int len = this.bitmap.limit(); @@ -1187,7 +1166,7 @@ public MappeableContainer ixor(final MappeableRunContainer x) { protected MappeableContainer lazyor(MappeableArrayContainer value2) { MappeableBitmapContainer answer = clone(); - answer.cardinality = -1;// invalid + answer.cardinality = -1; // invalid if (!BufferUtil.isBackedBySimpleArray(answer.bitmap)) { throw new RuntimeException("Should not happen. Internal bug."); } @@ -1203,7 +1182,7 @@ protected MappeableContainer lazyor(MappeableArrayContainer value2) { protected MappeableContainer lazyor(MappeableBitmapContainer x) { MappeableBitmapContainer answer = new MappeableBitmapContainer(); - answer.cardinality = -1;// invalid + answer.cardinality = -1; // invalid if (!BufferUtil.isBackedBySimpleArray(answer.bitmap)) { throw new RuntimeException("Should not happen. Internal bug."); } @@ -1249,13 +1228,18 @@ public MappeableContainer limit(int maxcardinality) { } return ac; } - MappeableBitmapContainer bc = new MappeableBitmapContainer(maxcardinality, this.bitmap); + LongBuffer newBitmap = LongBuffer.allocate(MAX_CAPACITY / 64); + MappeableBitmapContainer bc = new MappeableBitmapContainer(newBitmap, maxcardinality); int s = (select(maxcardinality)); int usedwords = (s + 63) >>> 6; - int len = this.bitmap.limit(); - int todelete = len - usedwords; - for (int k = 0; k < todelete; ++k) { - bc.bitmap.put(len - 1 - k, 0); + if (this.isArrayBacked()) { + long[] source = this.bitmap.array(); + long[] dest = newBitmap.array(); + System.arraycopy(source, 0, dest, 0, usedwords); + } else { + for (int k = 0; k < usedwords; ++k) { + bc.bitmap.put(k, this.bitmap.get(k)); + } } int lastword = s % 64; if (lastword != 0) { @@ -1276,22 +1260,20 @@ void loadData(final MappeableArrayContainer arrayContainer) { char[] ac = arrayContainer.content.array(); for (int k = 0; k < arrayContainer.cardinality; ++k) { final char x = ac[k]; - bitArray[(x) >>> 6] = - b[(x) >>> 6] | (1L << x); + bitArray[(x) >>> 6] = b[(x) >>> 6] | (1L << x); } } else { for (int k = 0; k < arrayContainer.cardinality; ++k) { final char x = arrayContainer.content.get(k); - bitArray[(x) >>> 6] = - bitmap.get((x) >>> 6) | (1L << x); + bitArray[(x) >>> 6] = bitmap.get((x) >>> 6) | (1L << x); } } } /** * Find the index of the next set bit greater or equal to i, returns -1 if none found. - * + * * @param i starting index * @return index of the next set bit */ @@ -1341,7 +1323,6 @@ public MappeableContainer not(final int firstOfRange, final int lastOfRange) { return answer.inot(firstOfRange, lastOfRange); } - @Override int numberOfRuns() { if (BufferUtil.isBackedBySimpleArray(this.bitmap)) { @@ -1352,7 +1333,7 @@ int numberOfRuns() { for (int i = 0; i < src.length - 1; i++) { long word = nextWord; nextWord = src[i + 1]; - numRuns += Long.bitCount((~word) & (word << 1)) + (int)((word >>> 63) & ~nextWord); + numRuns += Long.bitCount((~word) & (word << 1)) + (int) ((word >>> 63) & ~nextWord); } long word = nextWord; @@ -1370,7 +1351,7 @@ int numberOfRuns() { for (int i = 0; i < len - 1; i++) { long word = nextWord; nextWord = bitmap.get(i + 1); - numRuns += Long.bitCount((~word) & (word << 1)) + (int)((word >>> 63) & ~nextWord); + numRuns += Long.bitCount((~word) & (word << 1)) + (int) ((word >>> 63) & ~nextWord); } long word = nextWord; @@ -1380,13 +1361,12 @@ int numberOfRuns() { } return numRuns; - } } /** * Computes the number of runs - * + * * @return the number of runs */ private int numberOfRunsAdjustment() { @@ -1398,7 +1378,7 @@ private int numberOfRunsAdjustment() { final long word = nextWord; nextWord = b[i + 1]; - ans += (int)((word >>> 63) & ~nextWord); + ans += (int) ((word >>> 63) & ~nextWord); } final long word = nextWord; @@ -1414,7 +1394,7 @@ private int numberOfRunsAdjustment() { final long word = nextWord; nextWord = bitmap.get(i + 1); - ans += (int)((word >>> 63) & ~nextWord); + ans += (int) ((word >>> 63) & ~nextWord); } final long word = nextWord; @@ -1428,7 +1408,7 @@ private int numberOfRunsAdjustment() { /** * Counts how many runs there is in the bitmap, up to a maximum - * + * * @param mustNotExceed maximum of runs beyond which counting is pointless * @return estimated number of courses */ @@ -1463,8 +1443,6 @@ private int numberOfRunsLowerBound(int mustNotExceed) { return numRuns; } - - @Override public MappeableContainer or(final MappeableArrayContainer value2) { final MappeableBitmapContainer answer = clone(); @@ -1484,7 +1462,7 @@ public MappeableContainer or(final MappeableArrayContainer value2) { long aft = w | (1L << v); bitArray[i] = aft; if (USE_BRANCHLESS) { - answer.cardinality += (int)((w - aft) >>> 63); + answer.cardinality += (int) ((w - aft) >>> 63); } else { if (w != aft) { answer.cardinality++; @@ -1500,7 +1478,7 @@ public MappeableContainer or(final MappeableArrayContainer value2) { long aft = w | (1L << v2); bitArray[i] = aft; if (USE_BRANCHLESS) { - answer.cardinality += (int)((w - aft) >>> 63); + answer.cardinality += (int) ((w - aft) >>> 63); } else { if (w != aft) { answer.cardinality++; @@ -1514,8 +1492,6 @@ public MappeableContainer or(final MappeableArrayContainer value2) { return answer; } - - @Override public MappeableContainer or(final MappeableBitmapContainer value2) { final MappeableBitmapContainer value1 = this.clone(); @@ -1527,8 +1503,6 @@ public MappeableContainer or(final MappeableRunContainer value2) { return value2.or(this); } - - /** * Find the index of the previous set bit less than or equal to i, returns -1 if none found. * @@ -1596,7 +1570,6 @@ public int rank(char lowbits) { return answer; } - @Override public void readExternal(ObjectInput in) throws IOException { // little endian @@ -1636,14 +1609,12 @@ public MappeableContainer remove(int begin, int end) { return answer; } - - @Override public MappeableContainer remove(final char i) { long X = bitmap.get(i >>> 6); long mask = 1L << i; - if (cardinality == MappeableArrayContainer.DEFAULT_MAX_SIZE + 1) {// this is + if (cardinality == MappeableArrayContainer.DEFAULT_MAX_SIZE + 1) { // this is // the // uncommon // path @@ -1659,12 +1630,11 @@ public MappeableContainer remove(final char i) { return this; } - @Override public MappeableContainer repairAfterLazy() { if (getCardinality() < 0) { computeCardinality(); - if(getCardinality() <= MappeableArrayContainer.DEFAULT_MAX_SIZE) { + if (getCardinality() <= MappeableArrayContainer.DEFAULT_MAX_SIZE) { return this.toArrayContainer(); } else if (isFull()) { return MappeableRunContainer.full(); @@ -1697,6 +1667,67 @@ public MappeableContainer runOptimize() { @Override public char select(int j) { + if (BufferUtil.isBackedBySimpleArray(this.bitmap)) { + long[] b = this.bitmap.array(); + if ( // cardinality != -1 && // omitted as (-1>>>1) > j as j < (1<<16) + cardinality >>> 1 < j && j < cardinality) { + int leftover = cardinality - j; + for (int k = b.length - 1; k >= 0; --k) { + long w = b[k]; + if (w != 0) { + int bits = Long.bitCount(w); + if (bits >= leftover) { + return (char) (k * 64 + Util.select(w, bits - leftover)); + } + leftover -= bits; + } + } + } else { + int leftover = j; + for (int k = 0; k < b.length; ++k) { + long w = b[k]; + if (w != 0) { + int bits = Long.bitCount(w); + if (bits > leftover) { + return (char) (k * 64 + Util.select(w, leftover)); + } + leftover -= bits; + } + } + } + } else { + int len = this.bitmap.limit(); + if ( // cardinality != -1 && // (-1>>>1) > j as j < (1<<16) + cardinality >>> 1 < j && j < cardinality) { + int leftover = cardinality - j; + for (int k = len - 1; k >= 0; --k) { + int w = Long.bitCount(bitmap.get(k)); + if (w >= leftover) { + return (char) (k * 64 + Util.select(bitmap.get(k), w - leftover)); + } + leftover -= w; + } + } else { + int leftover = j; + for (int k = 0; k < len; ++k) { + long X = bitmap.get(k); + int w = Long.bitCount(X); + if (w > leftover) { + return (char) (k * 64 + Util.select(X, leftover)); + } + leftover -= w; + } + } + } + throw new IllegalArgumentException("Insufficient cardinality."); + } + + /** TODO For comparison only, should be removed before merge. + * + * @param j ... + * @return ... + */ + public char selectOneSide(int j) { int leftover = j; if (BufferUtil.isBackedBySimpleArray(this.bitmap)) { long[] b = this.bitmap.array(); @@ -1729,7 +1760,7 @@ public int serializedSizeInBytes() { /** * Copies the data to an array container - * + * * @return the array container */ MappeableArrayContainer toArrayContainer() { @@ -1764,7 +1795,7 @@ public String toString() { final CharIterator i = this.getCharIterator(); sb.append('{'); while (i.hasNext()) { - sb.append((int)(i.next())); + sb.append((int) (i.next())); if (i.hasNext()) { sb.append(','); } @@ -1774,9 +1805,7 @@ public String toString() { } @Override - public void trim() { - - } + public void trim() {} @Override protected void writeArray(DataOutput out) throws IOException { @@ -1825,7 +1854,7 @@ public MappeableContainer xor(final MappeableArrayContainer value2) { final int index = (vc) >>> 6; long ba = bitArray[index]; // TODO: check whether a branchy version could be faster - answer.cardinality += 1 - 2 * (int)((ba & mask) >>> vc); + answer.cardinality += 1 - 2 * (int) ((ba & mask) >>> vc); bitArray[index] = ba ^ mask; } } else { @@ -1836,7 +1865,7 @@ public MappeableContainer xor(final MappeableArrayContainer value2) { final int index = (v2) >>> 6; long ba = bitArray[index]; // TODO: check whether a branchy version could be faster - answer.cardinality += 1 - 2 * (int)((ba & mask) >>> v2); + answer.cardinality += 1 - 2 * (int) ((ba & mask) >>> v2); bitArray[index] = ba ^ mask; } } @@ -1918,14 +1947,13 @@ public void forEach(char msb, IntConsumer ic) { } } - @Override public int andCardinality(final MappeableArrayContainer value2) { int answer = 0; int c = value2.cardinality; for (int k = 0; k < c; ++k) { char v = value2.content.get(k); - answer += (int)this.bitValue(v); + answer += (int) this.bitValue(v); } return answer; } @@ -1964,15 +1992,15 @@ public int first() { assertNonEmpty(cardinality == 0); long firstNonZeroWord; int i = 0; - if(BufferUtil.isBackedBySimpleArray(bitmap)) { + if (BufferUtil.isBackedBySimpleArray(bitmap)) { long[] array = bitmap.array(); - while(array[i] == 0) { + while (array[i] == 0) { ++i; } firstNonZeroWord = array[i]; } else { i = bitmap.position(); - while(bitmap.get(i) == 0) { + while (bitmap.get(i) == 0) { ++i; } firstNonZeroWord = bitmap.get(i); @@ -1985,14 +2013,14 @@ public int last() { assertNonEmpty(cardinality == 0); long lastNonZeroWord; int i = bitmap.limit() - 1; - if(BufferUtil.isBackedBySimpleArray(bitmap)) { + if (BufferUtil.isBackedBySimpleArray(bitmap)) { long[] array = this.bitmap.array(); - while(i > 0 && array[i] == 0) { + while (i > 0 && array[i] == 0) { --i; } lastNonZeroWord = array[i]; } else { - while(i > 0 && bitmap.get(i) == 0) { + while (i > 0 && bitmap.get(i) == 0) { --i; } lastNonZeroWord = bitmap.get(i); @@ -2022,13 +2050,13 @@ public int previousAbsentValue(char fromValue) { @Override protected boolean contains(MappeableBitmapContainer bitmapContainer) { - if((cardinality != -1) && (bitmapContainer.cardinality != -1)) { - if(cardinality < bitmapContainer.cardinality) { + if ((cardinality != -1) && (bitmapContainer.cardinality != -1)) { + if (cardinality < bitmapContainer.cardinality) { return false; } } - for(int i = 0; i < MAX_CAPACITY >>> 6; ++i ) { - if((this.bitmap.get(i) & bitmapContainer.bitmap.get(i)) != bitmapContainer.bitmap.get(i)) { + for (int i = 0; i < MAX_CAPACITY >>> 6; ++i) { + if ((this.bitmap.get(i) & bitmapContainer.bitmap.get(i)) != bitmapContainer.bitmap.get(i)) { return false; } } @@ -2037,7 +2065,7 @@ protected boolean contains(MappeableBitmapContainer bitmapContainer) { @Override public boolean intersects(int minimum, int supremum) { - if((minimum < 0) || (supremum < minimum) || (supremum > (1<<16))) { + if ((minimum < 0) || (supremum < minimum) || (supremum > (1 << 16))) { throw new RuntimeException("This should never happen (bug)."); } int start = minimum >>> 6; @@ -2113,28 +2141,23 @@ protected boolean contains(MappeableArrayContainer arrayContainer) { } } for (int i = 0; i < arrayContainer.cardinality; ++i) { - if(!contains(arrayContainer.content.get(i))) { + if (!contains(arrayContainer.content.get(i))) { return false; } } return true; } - - } - final class MappeableBitmapContainerCharIterator implements PeekableCharIterator { - private final static int len = MappeableBitmapContainer.MAX_CAPACITY >>> 6;// hard coded for speed + private static final int len = + MappeableBitmapContainer.MAX_CAPACITY >>> 6; // hard coded for speed private long w; int x; - private MappeableBitmapContainer parent; - MappeableBitmapContainerCharIterator() { - - } + MappeableBitmapContainerCharIterator() {} MappeableBitmapContainerCharIterator(MappeableBitmapContainer p) { wrap(p); @@ -2145,7 +2168,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -2190,21 +2213,23 @@ void wrap(MappeableBitmapContainer p) { @Override public void advanceIfNeeded(char minval) { - if (minval >= (x + 1) * 64) { - x = minval >>> 6; - w = parent.bitmap.get(x); + if (!hasNext()) { + return; + } + if (minval >= x * 64) { + if (minval >= (x + 1) * 64) { + x = minval / 64; + w = parent.bitmap.get(x); + } + w &= ~0L << (minval & 63); while (w == 0) { - ++x; + x++; if (x == len) { return; } w = parent.bitmap.get(x); } } - while (hasNext() && (peekNext() < minval)) { - next(); // could be optimized - } - } @Override @@ -2213,18 +2238,16 @@ public char peekNext() { } } - final class ReverseMappeableBitmapContainerCharIterator implements CharIterator { - private final static int len = MappeableBitmapContainer.MAX_CAPACITY >>> 6;// hard coded for speed + private static final int len = + MappeableBitmapContainer.MAX_CAPACITY >>> 6; // hard coded for speed private long w; int x; private MappeableBitmapContainer parent; - ReverseMappeableBitmapContainerCharIterator() { - - } + ReverseMappeableBitmapContainerCharIterator() {} ReverseMappeableBitmapContainerCharIterator(MappeableBitmapContainer p) { wrap(p); @@ -2247,7 +2270,7 @@ public boolean hasNext() { @Override public char next() { int shift = Long.numberOfLeadingZeros(w) + 1; - char answer = (char)((x + 1) * 64 - shift); + char answer = (char) ((x + 1) * 64 - shift); w &= (0xFFFFFFFFFFFFFFFEL >>> shift); while (w == 0) { --x; diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainer.java similarity index 96% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainer.java index de53dea70..eb91e6c34 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainer.java @@ -4,7 +4,12 @@ package org.roaringbitmap.buffer; -import org.roaringbitmap.*; +import org.roaringbitmap.CharIterator; +import org.roaringbitmap.Container; +import org.roaringbitmap.ContainerBatchIterator; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.PeekableCharIterator; +import org.roaringbitmap.WordStorage; import java.io.DataOutput; import java.io.Externalizable; @@ -16,11 +21,11 @@ * Base container class. This class is similar to org.roaringbitmap.Container but meant to be used * with memory mapping. */ -public abstract class MappeableContainer implements Iterable, Cloneable, Externalizable, - WordStorage { +public abstract class MappeableContainer + implements Iterable, Cloneable, Externalizable, WordStorage { /** * Create a container initialized with a range of consecutive values - * + * * @param start first index * @param last last index (range is exclusive) * @return a new container initialized with the specified values @@ -44,10 +49,9 @@ public static MappeableContainer rangeOfOnes(final int start, final int last) { */ public abstract MappeableContainer add(int begin, int end); - /** * Add a char to the container. May generate a new container. - * + * * @param x char to be added * @return the new container */ @@ -89,7 +93,7 @@ public static MappeableContainer rangeOfOnes(final int start, final int last) { /** * Computes the bitwise AND of this container with another (intersection). This container as well * as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ @@ -98,7 +102,7 @@ public static MappeableContainer rangeOfOnes(final int start, final int last) { /** * Computes the bitwise AND of this container with another (intersection). This container as well * as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ @@ -111,10 +115,8 @@ protected MappeableContainer and(MappeableContainer x) { return and((MappeableRunContainer) x); } return and((MappeableBitmapContainer) x); - } - protected abstract int andCardinality(MappeableArrayContainer x); protected abstract int andCardinality(MappeableBitmapContainer x); @@ -153,22 +155,19 @@ public int andCardinality(MappeableContainer x) { } } - /** * Computes the bitwise AND of this container with another (intersection). This container as well * as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ - public abstract MappeableContainer and(MappeableRunContainer x); - /** * Computes the bitwise ANDNOT of this container with another (difference). This container as well * as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ @@ -177,7 +176,7 @@ public int andCardinality(MappeableContainer x) { /** * Computes the bitwise ANDNOT of this container with another (difference). This container as well * as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ @@ -196,11 +195,10 @@ protected MappeableContainer andNot(MappeableContainer x) { /** * Computes the bitwise ANDNOT of this container with another (difference). This container as well * as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ - public abstract MappeableContainer andNot(MappeableRunContainer x); /** @@ -244,29 +242,28 @@ public MappeableContainer iorNot(MappeableContainer x, int endOfRange) { /** * Checks whether the contain contains the provided value - * + * * @param x value to check * @return whether the value is in the container */ public abstract boolean contains(char x); - /** + /** * Checks whether the container is a subset of this container or not * @param subset the container to be tested * @return true if the parameter is a subset of this container */ public boolean contains(MappeableContainer subset) { - if(subset instanceof MappeableRunContainer) { - return contains((MappeableRunContainer)subset); - } else if(subset instanceof MappeableArrayContainer) { + if (subset instanceof MappeableRunContainer) { + return contains((MappeableRunContainer) subset); + } else if (subset instanceof MappeableArrayContainer) { return contains((MappeableArrayContainer) subset); - } else if(subset instanceof MappeableBitmapContainer){ - return contains((MappeableBitmapContainer)subset); + } else if (subset instanceof MappeableBitmapContainer) { + return contains((MappeableBitmapContainer) subset); } return false; } - protected abstract boolean contains(MappeableRunContainer runContainer); protected abstract boolean contains(MappeableArrayContainer arrayContainer); @@ -288,13 +285,13 @@ public boolean contains(MappeableContainer subset) { * @return true if the container contains the range */ public abstract boolean contains(int minimum, int supremum); - + /** * Fill the least significant 16 bits of the integer array, starting at index index, with the * char values from this container. The caller is responsible to allocate enough room. The most * significant 16 bits of each integer are given by the most significant bits of the provided * mask. - * + * * @param x provided array * @param i starting index * @param mask indicates most significant bits @@ -310,26 +307,24 @@ public boolean contains(MappeableContainer subset) { */ public abstract MappeableContainer flip(char x); - /** * Size of the underlying array - * + * * @return size in bytes */ protected abstract int getArraySizeInBytes(); - /** * Computes the distinct number of char values in the container. Can be expected to run in * constant time. - * + * * @return the cardinality */ public abstract int getCardinality(); /** * Get the name of this container. - * + * * @return name of the container */ public String getContainerName() { @@ -341,10 +336,11 @@ public String getContainerName() { return ContainerNames[2]; } } + /** * Name of the various possible containers */ - public static String[] ContainerNames = {"mappeablebitmap","mappeablearray","mappeablerun"}; + public static String[] ContainerNames = {"mappeablebitmap", "mappeablearray", "mappeablerun"}; /** * Iterator to visit the char values in the container in descending order. @@ -353,7 +349,6 @@ public String getContainerName() { */ public abstract CharIterator getReverseCharIterator(); - /** * Iterator to visit the char values in the container in ascending order. * @@ -366,7 +361,7 @@ public String getContainerName() { * @return iterator */ public abstract ContainerBatchIterator getBatchIterator(); - + /** * Iterate through the values of this container and pass them * along to the IntConsumer, using msb as the 16 most significant bits. @@ -378,7 +373,7 @@ public String getContainerName() { /** * Computes an estimate of the memory usage of this container. The estimate is not meant to be * exact. - * + * * @return estimated memory usage in bytes */ public abstract int getSizeInBytes(); @@ -396,7 +391,7 @@ public String getContainerName() { * Computes the in-place bitwise AND of this container with another (intersection). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate * a new container. - * + * * @param x other container * @return aggregated container */ @@ -406,13 +401,12 @@ public String getContainerName() { * Computes the in-place bitwise AND of this container with another (intersection). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate * a new container. - * + * * @param x other container * @return aggregated container */ public abstract MappeableContainer iand(MappeableBitmapContainer x); - protected MappeableContainer iand(MappeableContainer x) { if (x instanceof MappeableArrayContainer) { return iand((MappeableArrayContainer) x); @@ -421,25 +415,23 @@ protected MappeableContainer iand(MappeableContainer x) { } return iand((MappeableBitmapContainer) x); - } /** * Computes the in-place bitwise AND of this container with another (intersection). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate * a new container. - * + * * @param x other container * @return aggregated container */ - public abstract MappeableContainer iand(MappeableRunContainer x); /** * Computes the in-place bitwise ANDNOT of this container with another (difference). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate * a new container. - * + * * @param x other container * @return aggregated container */ @@ -449,7 +441,7 @@ protected MappeableContainer iand(MappeableContainer x) { * Computes the in-place bitwise ANDNOT of this container with another (difference). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate * a new container. - * + * * @param x other container * @return aggregated container */ @@ -469,26 +461,22 @@ protected MappeableContainer iandNot(MappeableContainer x) { * Computes the in-place bitwise ANDNOT of this container with another (difference). The current * container is generally modified, whereas the provided container (x) is unaffected. May generate * a new container. - * + * * @param x other container * @return aggregated container */ - public abstract MappeableContainer iandNot(MappeableRunContainer x); - - /** * Computes the in-place bitwise NOT of this container (complement). Only those bits within the * range are affected. The current container is generally modified. May generate a new container. - * + * * @param rangeStart beginning of range (inclusive); 0 is beginning of this container. * @param rangeEnd ending of range (exclusive) * @return (partially) completmented container */ public abstract MappeableContainer inot(int rangeStart, int rangeEnd); - /** * Returns true if the current container intersects the other container. * @@ -532,7 +520,7 @@ public boolean intersects(MappeableContainer x) { * Computes the in-place bitwise OR of this container with another (union). The current container * is generally modified, whereas the provided container (x) is unaffected. May generate a new * container. - * + * * @param x other container * @return aggregated container */ @@ -542,7 +530,7 @@ public boolean intersects(MappeableContainer x) { * Computes the in-place bitwise OR of this container with another (union). The current container * is generally modified, whereas the provided container (x) is unaffected. May generate a new * container. - * + * * @param x other container * @return aggregated container */ @@ -562,11 +550,10 @@ protected MappeableContainer ior(MappeableContainer x) { * Computes the in-place bitwise OR of this container with another (union). The current container * is generally modified, whereas the provided container (x) is unaffected. May generate a new * container. - * + * * @param x other container * @return aggregated container */ - public abstract MappeableContainer ior(MappeableRunContainer x); /** @@ -580,12 +567,11 @@ protected MappeableContainer ior(MappeableContainer x) { protected abstract boolean isArrayBacked(); - /** * Computes the in-place bitwise XOR of this container with another (symmetric difference). The * current container is generally modified, whereas the provided container (x) is unaffected. May * generate a new container. - * + * * @param x other container * @return aggregated container */ @@ -595,7 +581,7 @@ protected MappeableContainer ior(MappeableContainer x) { * Computes the in-place bitwise XOR of this container with another (symmetric difference). The * current container is generally modified, whereas the provided container (x) is unaffected. May * generate a new container. - * + * * @param x other container * @return aggregated container */ @@ -609,23 +595,18 @@ protected MappeableContainer ixor(MappeableContainer x) { } return ixor((MappeableBitmapContainer) x); - } - /** * Computes the in-place bitwise XOR of this container with another (symmetric difference). The * current container is generally modified, whereas the provided container (x) is unaffected. May * generate a new container. - * + * * @param x other container * @return aggregated container */ - public abstract MappeableContainer ixor(MappeableRunContainer x); - - /** * Computes the in-place bitwise OR of this container with another (union). The current container * is generally modified, whereas the provided container (x) is unaffected. May generate a new @@ -666,7 +647,7 @@ public MappeableContainer lazyIOR(MappeableContainer x) { * provided container are left unaffected. The resulting container may not track its cardinality * correctly. This can be fixed as follows: if(c.getCardinality()<0) * ((MappeableBitmapContainer)c).computeCardinality(); - * + * * @param x other container * @return aggregated container */ @@ -697,7 +678,7 @@ public MappeableContainer lazyOR(MappeableContainer x) { /** * Create a new MappeableContainer containing at most maxcardinality integers. - * + * * @param maxcardinality maximal cardinality * @return a new bitmap with cardinality no more than maxcardinality */ @@ -706,7 +687,7 @@ public MappeableContainer lazyOR(MappeableContainer x) { /** * Computes the bitwise NOT of this container (complement). Only those bits within the range are * affected. The current container is left unaffected. - * + * * @param rangeStart beginning of range (inclusive); 0 is beginning of this container. * @param rangeEnd ending of range (exclusive) * @return (partially) completmented container @@ -718,23 +699,21 @@ public MappeableContainer lazyOR(MappeableContainer x) { /** * Computes the bitwise OR of this container with another (union). This container as well as the * provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ public abstract MappeableContainer or(MappeableArrayContainer x); - /** * Computes the bitwise OR of this container with another (union). This container as well as the * provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ public abstract MappeableContainer or(MappeableBitmapContainer x); - protected MappeableContainer or(MappeableContainer x) { if (x instanceof MappeableArrayContainer) { return or((MappeableArrayContainer) x); @@ -748,17 +727,16 @@ protected MappeableContainer or(MappeableContainer x) { /** * Computes the bitwise OR of this container with another (union). This container as well as the * provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ - public abstract MappeableContainer or(MappeableRunContainer x); /** * Rank returns the number of integers that are smaller or equal to x (Rank(infinity) would be * GetCardinality()). - * + * * @param lowbits upper limit * * @return the rank @@ -776,7 +754,7 @@ protected MappeableContainer or(MappeableContainer x) { /** * Remove the char from this container. May create a new container. - * + * * @param x to be removed * @return New container */ @@ -784,7 +762,7 @@ protected MappeableContainer or(MappeableContainer x) { /** * The output of a lazyOR or lazyIOR might be an invalid container, this should be called on it. - * + * * @return a new valid container */ public abstract MappeableContainer repairAfterLazy(); @@ -792,22 +770,20 @@ protected MappeableContainer or(MappeableContainer x) { /** * Convert to MappeableRunContainers, when the result is smaller. Overridden by * MappeableRunContainer to possibly switch from MappeableRunContainer to a smaller alternative. - * + * * @return the new container */ public abstract MappeableContainer runOptimize(); - /** * Return the jth value - * + * * @param j index of the value * * @return the value */ public abstract char select(int j); - /** * Report the number of bytes required to serialize this container. * @@ -815,11 +791,9 @@ protected MappeableContainer or(MappeableContainer x) { */ public abstract int serializedSizeInBytes(); - - /** * Convert to a non-mappeable container. - * + * * @return the non-mappeable container */ public abstract Container toContainer(); @@ -829,11 +803,9 @@ protected MappeableContainer or(MappeableContainer x) { */ public abstract void trim(); - - /** * Write just the underlying array. - * + * * @param out output stream * @throws IOException in case of failure */ @@ -849,7 +821,7 @@ protected MappeableContainer or(MappeableContainer x) { /** * Computes the bitwise XOR of this container with another (symmetric difference). This container * as well as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ @@ -858,7 +830,7 @@ protected MappeableContainer or(MappeableContainer x) { /** * Computes the bitwise XOR of this container with another (symmetric difference). This container * as well as the provided container are left unaffected. - * + * * @param x other container * @return aggregated container */ @@ -872,13 +844,12 @@ protected MappeableContainer xor(MappeableContainer x) { } return xor((MappeableBitmapContainer) x); - } /** * Computes the bitwise XOR of this container with another (symmetric difference). This container * as well as the provided container are left unaffected. - * + * * @param x other parameter * @return aggregated container */ @@ -889,7 +860,7 @@ protected MappeableContainer xor(MappeableContainer x) { * If the container is already a bitmap, the container is returned unchanged. * @return a bitmap container */ - public abstract MappeableBitmapContainer toBitmapContainer() ; + public abstract MappeableBitmapContainer toBitmapContainer(); /** * Get the first integer held in the container @@ -933,16 +904,14 @@ protected MappeableContainer xor(MappeableContainer x) { */ public abstract int previousAbsentValue(char fromValue); - /** * Throw if the container is empty * @param condition a boolean expression * @throws NoSuchElementException if empty */ protected void assertNonEmpty(boolean condition) { - if(condition) { + if (condition) { throw new NoSuchElementException("Empty " + getContainerName()); } } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainerPointer.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainerPointer.java similarity index 96% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainerPointer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainerPointer.java index 1d472ca7a..ae19d9674 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainerPointer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableContainerPointer.java @@ -5,9 +5,9 @@ package org.roaringbitmap.buffer; /** - * + * * This interface allows you to iterate over the containers in a roaring bitmap. - * + * */ public interface MappeableContainerPointer extends Comparable, Cloneable { @@ -18,7 +18,7 @@ public interface MappeableContainerPointer /** * Create a copy - * + * * @return return a clone of this pointer */ MappeableContainerPointer clone(); @@ -26,7 +26,7 @@ public interface MappeableContainerPointer /** * Returns the cardinality of the current container. Can be faster than loading the container * first. - * + * * @return cardinality of the current container */ int getCardinality(); @@ -34,34 +34,34 @@ public interface MappeableContainerPointer /** * This method can be used to check whether there is current a valid container as it returns null * when there is not. - * + * * @return null or the current container */ MappeableContainer getContainer(); /** * Get the size in bytes of the container. Used for sorting. - * + * * @return the size in bytes */ int getSizeInBytes(); /** - * + * * @return whether there is a container at the current position */ boolean hasContainer(); /** * Returns true if it is a bitmap container (MappeableBitmapContainer). - * + * * @return boolean indicated if it is a bitmap container */ boolean isBitmapContainer(); /** * Returns true if it is a run container (MappeableRunContainer). - * + * * @return boolean indicated if it is a run container */ boolean isRunContainer(); @@ -69,7 +69,7 @@ public interface MappeableContainerPointer /** * The key is a 16-bit integer that indicates the position of the container in the roaring bitmap. * To be interpreted as an unsigned integer. - * + * * @return the key */ char key(); @@ -78,6 +78,4 @@ public interface MappeableContainerPointer * Move to the previous container */ void previous(); - - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableRunContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableRunContainer.java similarity index 91% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableRunContainer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableRunContainer.java index 3c29a2689..1f7ff56dc 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MappeableRunContainer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MappeableRunContainer.java @@ -3,8 +3,17 @@ */ package org.roaringbitmap.buffer; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.roaringbitmap.Util.resetBitmapRange; +import static org.roaringbitmap.Util.setBitmapRange; +import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY; -import org.roaringbitmap.*; +import org.roaringbitmap.CharIterator; +import org.roaringbitmap.Container; +import org.roaringbitmap.ContainerBatchIterator; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.PeekableCharIterator; +import org.roaringbitmap.RunContainer; import java.io.DataOutput; import java.io.IOException; @@ -14,10 +23,7 @@ import java.nio.CharBuffer; import java.util.Arrays; import java.util.Iterator; - -import static java.nio.ByteOrder.LITTLE_ENDIAN; -import static org.roaringbitmap.Util.*; -import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY; +import java.util.Optional; /** * This container takes the form of runs of consecutive values (effectively, run-length encoding). @@ -31,8 +37,8 @@ public final class MappeableRunContainer extends MappeableContainer implements C private static final int DEFAULT_INIT_SIZE = 4; private static final long serialVersionUID = 1L; - private static int branchyBufferedUnsignedInterleavedBinarySearch(final CharBuffer sb, - final int begin, final int end, final char k) { + private static int branchyBufferedUnsignedInterleavedBinarySearch( + final CharBuffer sb, final int begin, final int end, final char k) { int low = begin; int high = end - 1; while (low <= high) { @@ -49,8 +55,8 @@ private static int branchyBufferedUnsignedInterleavedBinarySearch(final CharBuff return -(low + 1); } - private static int branchyBufferedUnsignedInterleavedBinarySearch(final ByteBuffer sb, - int position, final int begin, final int end, final char k) { + private static int branchyBufferedUnsignedInterleavedBinarySearch( + final ByteBuffer sb, int position, final int begin, final int end, final char k) { int low = begin; int high = end - 1; while (low <= high) { @@ -67,14 +73,13 @@ private static int branchyBufferedUnsignedInterleavedBinarySearch(final ByteBuff return -(low + 1); } - private static int bufferedUnsignedInterleavedBinarySearch(final CharBuffer sb, final int begin, - final int end, final char k) { + private static int bufferedUnsignedInterleavedBinarySearch( + final CharBuffer sb, final int begin, final int end, final char k) { return branchyBufferedUnsignedInterleavedBinarySearch(sb, begin, end, k); } - - private static int bufferedUnsignedInterleavedBinarySearch(final ByteBuffer sb, int position, - final int begin, final int end, final char k) { + private static int bufferedUnsignedInterleavedBinarySearch( + final ByteBuffer sb, int position, final int begin, final int end, final char k) { return branchyBufferedUnsignedInterleavedBinarySearch(sb, position, begin, end, k); } @@ -86,7 +91,6 @@ private static char getLength(char[] vl, int index) { return vl[2 * index + 1]; } - private static char getValue(char[] vl, int index) { return vl[2 * index]; } @@ -97,8 +101,7 @@ protected static int serializedSizeInBytes(int numberOfRuns) { protected CharBuffer valueslength; - protected int nbrruns = 0;// how many runs, this number should fit in 16 bits. - + protected int nbrruns = 0; // how many runs, this number should fit in 16 bits. /** * Create a container with default capacity @@ -116,16 +119,14 @@ public MappeableRunContainer(final int capacity) { valueslength = CharBuffer.allocate(2 * capacity); } - private MappeableRunContainer(int nbrruns, final CharBuffer valueslength) { this.nbrruns = nbrruns; - CharBuffer tmp = valueslength.duplicate();// for thread safety + CharBuffer tmp = valueslength.duplicate(); // for thread safety this.valueslength = CharBuffer.allocate(Math.max(2 * nbrruns, tmp.limit())); tmp.rewind(); this.valueslength.put(tmp); // may copy more than it needs to?? } - protected MappeableRunContainer(MappeableArrayContainer arr, int nbrRuns) { this.nbrruns = nbrRuns; valueslength = CharBuffer.allocate(2 * nbrRuns); @@ -295,7 +296,6 @@ protected MappeableRunContainer(MappeableBitmapContainer bc, int nbrRuns) { curWord = curWordWith1s & (curWordWith1s + 1); // We've lathered and rinsed, so repeat... } - } } @@ -338,10 +338,10 @@ public MappeableContainer add(char k) { // toBitmapOrArrayContainer(getCardinality()).add(k) int index = bufferedUnsignedInterleavedBinarySearch(valueslength, 0, nbrruns, k); if (index >= 0) { - return this;// already there + return this; // already there } - index = -index - 2;// points to preceding value, possibly -1 - if (index >= 0) {// possible match + index = -index - 2; // points to preceding value, possibly -1 + if (index >= 0) { // possible match int offset = (k) - (getValue(index)); int le = (getLength(index)); if (offset <= le) { @@ -352,8 +352,7 @@ public MappeableContainer add(char k) { if (index + 1 < nbrruns) { if ((getValue(index + 1)) == (k) + 1) { // indeed fusion is needed - setLength(index, - (char) (getValue(index + 1) + getLength(index + 1) - getValue(index))); + setLength(index, (char) (getValue(index + 1) + getLength(index + 1) - getValue(index))); recoverRoomAtIndex(index + 1); return this; } @@ -392,7 +391,6 @@ public boolean isEmpty() { return nbrruns == 0; } - @Override public MappeableContainer and(MappeableArrayContainer x) { MappeableArrayContainer ac = new MappeableArrayContainer(x.cardinality); @@ -406,17 +404,16 @@ public MappeableContainer and(MappeableArrayContainer x) { int rlelength = (this.getLength(rlepos)); while (arraypos < x.cardinality) { int arrayval = (x.content.get(arraypos)); - while (rleval + rlelength < arrayval) {// this will frequently be false + while (rleval + rlelength < arrayval) { // this will frequently be false ++rlepos; if (rlepos == this.nbrruns) { - return ac;// we are done + return ac; // we are done } rleval = (this.getValue(rlepos)); rlelength = (this.getLength(rlepos)); } if (rleval > arrayval) { - arraypos = - BufferUtil.advanceUntil(x.content, arraypos, x.cardinality, (char)rleval); + arraypos = BufferUtil.advanceUntil(x.content, arraypos, x.cardinality, (char) rleval); } else { ac.content.put(ac.cardinality, (char) arrayval); ac.cardinality++; @@ -466,7 +463,6 @@ public MappeableContainer and(MappeableBitmapContainer x) { } else { return answer.toArrayContainer(); } - } @Override @@ -495,10 +491,10 @@ public MappeableContainer and(MappeableRunContainer x) { xstart = (x.getValue(xrlepos)); xend = xstart + (x.getLength(xrlepos)) + 1; } - } else {// they overlap + } else { // they overlap final int lateststart = Math.max(start, xstart); int earliestend; - if (end == xend) {// improbable + if (end == xend) { // improbable earliestend = end; rlepos++; xrlepos++; @@ -518,7 +514,7 @@ public MappeableContainer and(MappeableRunContainer x) { end = start + (this.getLength(rlepos)) + 1; } - } else {// end > xend + } else { // end > xend earliestend = xend; xrlepos++; if (xrlepos < x.nbrruns) { @@ -546,8 +542,9 @@ public MappeableContainer andNot(MappeableArrayContainer x) { if (card <= MappeableArrayContainer.DEFAULT_MAX_SIZE) { // if the cardinality is small, we construct the solution in place MappeableArrayContainer ac = new MappeableArrayContainer(card); - ac.cardinality = org.roaringbitmap.Util.unsignedDifference(this.getCharIterator(), - x.getCharIterator(), ac.content.array()); + ac.cardinality = + org.roaringbitmap.Util.unsignedDifference( + this.getCharIterator(), x.getCharIterator(), ac.content.array()); return ac; } // otherwise, we generate a bitmap @@ -671,7 +668,6 @@ private void appendValueLength(int value, int index) { } } - // To check if a value length can be prepended with a given value private boolean canPrependValueLength(int value, int index) { if (index < this.nbrruns) { @@ -681,21 +677,16 @@ private boolean canPrependValueLength(int value, int index) { return false; } - - @Override public void clear() { nbrruns = 0; } - @Override public MappeableContainer clone() { return new MappeableRunContainer(nbrruns, valueslength); } - - // To set the last value of a value length private void closeValueLength(int value, int index) { int initialValue = (getValue(index)); @@ -709,7 +700,7 @@ public boolean contains(char x) { return true; } index = -index - 2; // points to preceding value, possibly -1 - if (index != -1) {// possible match + if (index != -1) { // possible match int offset = (x) - (getValue(index)); int le = (getLength(index)); return offset <= le; @@ -732,14 +723,12 @@ public static boolean contains(ByteBuffer buf, int position, char x, final int n return true; } index = -index - 2; // points to preceding value, possibly -1 - if (index != -1) {// possible match - int offset = (x) - - (buf.getChar(position + index * 2 * 2)); + if (index != -1) { // possible match + int offset = (x) - (buf.getChar(position + index * 2 * 2)); int le = (buf.getChar(position + index * 2 * 2 + 2)); return offset <= le; } return false; - } // a very cheap check... if you have more than 4096, then you should use a bitmap container. @@ -762,26 +751,37 @@ private MappeableContainer convertToLazyBitmapIfNeeded() { // Push all values length to the end of the array (resize array if needed) private void copyToOffset(int offset) { - final int minCapacity = 2 * (offset + nbrruns); - if (valueslength.capacity() < minCapacity) { + int minCapacity = 2 * (offset + nbrruns); + Optional newvalueslength = computeNewCapacity(valueslength.capacity(), minCapacity); + if (newvalueslength.isPresent()) { // expensive case where we need to reallocate - int newCapacity = valueslength.capacity(); - while (newCapacity < minCapacity) { - newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE - : newCapacity < 64 ? newCapacity * 2 - : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4; - } - CharBuffer newvalueslength = CharBuffer.allocate(newCapacity); - copyValuesLength(this.valueslength, 0, newvalueslength, offset, nbrruns); - this.valueslength = newvalueslength; + copyValuesLength(this.valueslength, 0, newvalueslength.get(), offset, nbrruns); + this.valueslength = newvalueslength.get(); } else { // efficient case where we just copy copyValuesLength(this.valueslength, 0, this.valueslength, offset, nbrruns); } } - private void copyValuesLength(CharBuffer src, int srcIndex, CharBuffer dst, int dstIndex, - int length) { + private static Optional computeNewCapacity(int oldCapacity, int minCapacity) { + if (oldCapacity < minCapacity) { + int newCapacity = oldCapacity; + while ((newCapacity = computeNewCapacity(newCapacity)) < minCapacity) {} + return Optional.of(CharBuffer.allocate(newCapacity)); + } + return Optional.empty(); + } + + private static int computeNewCapacity(int oldCapacity) { + return oldCapacity == 0 + ? DEFAULT_INIT_SIZE + : oldCapacity < 64 + ? oldCapacity * 2 + : oldCapacity < 1024 ? oldCapacity * 3 / 2 : oldCapacity * 5 / 4; + } + + private void copyValuesLength( + CharBuffer src, int srcIndex, CharBuffer dst, int dstIndex, int length) { if (BufferUtil.isBackedBySimpleArray(src) && BufferUtil.isBackedBySimpleArray(dst)) { // common case. System.arraycopy(src.array(), 2 * srcIndex, dst.array(), 2 * dstIndex, 2 * length); @@ -804,7 +804,6 @@ private void decrementLength(int index) { valueslength.put(2 * index + 1, (char) (valueslength.get(2 * index + 1) - 1)); } - private void decrementValue() { valueslength.put(0, (char) (valueslength.get(0) - 1)); } @@ -812,18 +811,11 @@ private void decrementValue() { // not thread safe! // not actually used anywhere, but potentially useful private void ensureCapacity(int minNbRuns) { - final int minCapacity = 2 * minNbRuns; - if (valueslength.capacity() < minCapacity) { - int newCapacity = valueslength.capacity(); - while (newCapacity < minCapacity) { - newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE - : newCapacity < 64 ? newCapacity * 2 - : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4; - } - final CharBuffer nv = CharBuffer.allocate(newCapacity); + Optional nv = computeNewCapacity(valueslength.capacity(), 2 * minNbRuns); + if (nv.isPresent()) { valueslength.rewind(); - nv.put(valueslength); - valueslength = nv; + nv.get().put(valueslength); + valueslength = nv.get(); } } @@ -876,7 +868,7 @@ private boolean equals(MappeableArrayContainer arrayContainer) { if (arrayContainer.select(pos) != runStart) { return false; } - if (arrayContainer.select(pos + length) != (char)((runStart) + length)) { + if (arrayContainer.select(pos + length) != (char) ((runStart) + length)) { return false; } pos += length + 1; @@ -896,7 +888,6 @@ public void fillLeastSignificant16bits(int[] x, int i, int mask) { } } - @Override public MappeableContainer flip(char x) { if (this.contains(x)) { @@ -990,7 +981,7 @@ public int hashCode() { public MappeableContainer iadd(int begin, int end) { // TODO: it might be better and simpler to do return // toBitmapOrArrayContainer(getCardinality()).iadd(begin,end) - if(end == begin) { + if (end == begin) { return this; } if ((begin > end) || (end > (1 << 16))) { @@ -1003,8 +994,9 @@ public MappeableContainer iadd(int begin, int end) { int bIndex = bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (char) begin); - int eIndex = bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, - (char) (end - 1)); + int eIndex = + bufferedUnsignedInterleavedBinarySearch( + this.valueslength, bIndex >= 0 ? bIndex : -bIndex - 1, this.nbrruns, (char) (end - 1)); if (bIndex >= 0 && eIndex >= 0) { mergeValuesLength(bIndex, eIndex); @@ -1084,8 +1076,6 @@ public MappeableContainer iadd(int begin, int end) { } } - - @Override public MappeableContainer iand(MappeableArrayContainer x) { return and(x); @@ -1096,7 +1086,6 @@ public MappeableContainer iand(MappeableBitmapContainer x) { return and(x); } - @Override public MappeableContainer iand(MappeableRunContainer x) { return and(x); @@ -1124,7 +1113,6 @@ MappeableContainer ilazyor(MappeableArrayContainer x) { return ilazyorToRun(x); } - private MappeableContainer ilazyorToRun(MappeableArrayContainer x) { if (isFull()) { return full(); @@ -1165,11 +1153,7 @@ private MappeableContainer ilazyorToRun(MappeableArrayContainer x) { // not thread safe! private void increaseCapacity() { - int newCapacity = (valueslength.capacity() == 0) ? DEFAULT_INIT_SIZE - : valueslength.capacity() < 64 ? valueslength.capacity() * 2 - : valueslength.capacity() < 1024 ? valueslength.capacity() * 3 / 2 - : valueslength.capacity() * 5 / 4; - + int newCapacity = computeNewCapacity(valueslength.capacity()); final CharBuffer nv = CharBuffer.allocate(newCapacity); valueslength.rewind(); nv.put(valueslength); @@ -1192,7 +1176,6 @@ private void initValueLength(int value, int index) { setLength(index, (char) (length - (value - initialValue))); } - @Override public MappeableContainer inot(int rangeStart, int rangeEnd) { if (rangeEnd <= rangeStart) { @@ -1267,11 +1250,11 @@ public MappeableContainer inot(int rangeStart, int rangeEnd) { // use local variables so we are always reading 1 location ahead. char bufferedValue = 0, bufferedLength = 0; // 65535 start and 65535 length would be illegal, - // could use as sentinel + // could use as sentinel char nextValue = 0, nextLength = 0; if (k < myNbrRuns) { // prime the readahead variables - bufferedValue = vl[2 * k];// getValue(k); - bufferedLength = vl[2 * k + 1];// getLength(k); + bufferedValue = vl[2 * k]; // getValue(k); + bufferedLength = vl[2 * k + 1]; // getLength(k); } ans.smartAppendExclusive(vl, (char) rangeStart, (char) (rangeEnd - rangeStart - 1)); @@ -1282,8 +1265,8 @@ public MappeableContainer inot(int rangeStart, int rangeEnd) { "internal error in inot, writer has overtaken reader!! " + k + " " + ans.nbrruns); } if (k + 1 < myNbrRuns) { - nextValue = vl[2 * (k + 1)];// getValue(k+1); // readahead for next iteration - nextLength = vl[2 * (k + 1) + 1];// getLength(k+1); + nextValue = vl[2 * (k + 1)]; // getValue(k+1); // readahead for next iteration + nextLength = vl[2 * (k + 1) + 1]; // getLength(k+1); } ans.smartAppendExclusive(vl, bufferedValue, bufferedLength); bufferedValue = nextValue; @@ -1306,7 +1289,7 @@ public boolean intersects(MappeableArrayContainer x) { int rlelength = (this.getLength(rlepos)); while (arraypos < x.cardinality) { int arrayval = (x.content.get(arraypos)); - while (rleval + rlelength < arrayval) {// this will frequently be false + while (rleval + rlelength < arrayval) { // this will frequently be false ++rlepos; if (rlepos == this.nbrruns) { return false; @@ -1359,7 +1342,7 @@ public boolean intersects(MappeableRunContainer x) { xstart = (x.getValue(xrlepos)); xend = xstart + (x.getLength(xrlepos)) + 1; } - } else {// they overlap + } else { // they overlap return true; } } @@ -1455,7 +1438,7 @@ public MappeableContainer ior(MappeableRunContainer x) { this.smartAppend(vl, x.getValue(xrlepos), x.getLength(xrlepos)); ++xrlepos; } - return this.toBitmapIfNeeded(); + return this.toEfficientContainer(); } @Override @@ -1463,7 +1446,7 @@ public MappeableContainer ior(MappeableRunContainer x) { public MappeableContainer iremove(int begin, int end) { // TODO: it might be better and simpler to do return // toBitmapOrArrayContainer(getCardinality()).iremove(begin,end) - if(end == begin) { + if (end == begin) { return this; } if ((begin > end) || (end > (1 << 16))) { @@ -1476,8 +1459,9 @@ public MappeableContainer iremove(int begin, int end) { int bIndex = bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (char) begin); - int eIndex = bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, - (char) (end - 1)); + int eIndex = + bufferedUnsignedInterleavedBinarySearch( + this.valueslength, bIndex >= 0 ? bIndex : -bIndex - 1, this.nbrruns, (char) (end - 1)); if (bIndex >= 0) { if (eIndex < 0) { @@ -1500,7 +1484,7 @@ public MappeableContainer iremove(int begin, int end) { } } // last run is one charer - if (getLength(eIndex) == 0) {// special case where we remove last run + if (getLength(eIndex) == 0) { // special case where we remove last run recoverRoomsInRange(eIndex - 1, eIndex); } else { incrementValue(eIndex); @@ -1543,9 +1527,7 @@ public MappeableContainer iremove(int begin, int end) { recoverRoomsInRange(bIndex, eIndex); } } - } - } return this; } @@ -1614,7 +1596,6 @@ public void remove() { i.remove(); } }; - } @Override @@ -1622,7 +1603,6 @@ public MappeableContainer ixor(MappeableArrayContainer x) { return xor(x); } - @Override public MappeableContainer ixor(MappeableBitmapContainer x) { return xor(x); @@ -1699,8 +1679,6 @@ private MappeableRunContainer lazyandNot(MappeableArrayContainer x) { return answer; } - - protected MappeableContainer lazyor(MappeableArrayContainer x) { return lazyorToRun(x); } @@ -1802,15 +1780,18 @@ public MappeableContainer limit(int maxcardinality) { break; } } - - CharBuffer newBuf = CharBuffer.allocate(2 * (r + 1)); - for (int i = 0; i < 2 * (r + 1); ++i) { - newBuf.put(valueslength.get(i)); // could be optimized + CharBuffer newBuf; + if (BufferUtil.isBackedBySimpleArray(valueslength)) { + char[] newArray = Arrays.copyOf(valueslength.array(), 2 * (r + 1)); + newBuf = CharBuffer.wrap(newArray); + } else { + newBuf = CharBuffer.allocate(2 * (r + 1)); + for (int i = 0; i < 2 * (r + 1); i++) { + newBuf.put(valueslength.get(i)); + } } MappeableRunContainer rc = new MappeableRunContainer(newBuf, r + 1); - - rc.setLength(r, - (char) ((rc.getLength(r)) - cardinality + maxcardinality)); + rc.setLength(r, (char) (rc.getLength(r) - cardinality + maxcardinality)); return rc; } @@ -1936,7 +1917,7 @@ public MappeableContainer or(MappeableRunContainer x) { if (answer.isFull()) { return full(); } - return answer.toBitmapIfNeeded(); + return answer.toEfficientContainer(); } // Prepend a value length with all values starting from a given value @@ -2005,10 +1986,10 @@ public MappeableContainer remove(char x) { incrementValue(index); decrementLength(index); } - return this;// already there + return this; // already there } - index = -index - 2;// points to preceding value, possibly -1 - if (index >= 0) {// possible match + index = -index - 2; // points to preceding value, possibly -1 + if (index >= 0) { // possible match int offset = (x) - (getValue(index)); int le = (getLength(index)); if (offset < le) { @@ -2037,7 +2018,6 @@ public MappeableContainer repairAfterLazy() { /** * Convert to Array or Bitmap container if the serialized form would be shorter */ - @Override public MappeableContainer runOptimize() { return toEfficientContainer(); // which had the same functionality. @@ -2062,19 +2042,14 @@ public int serializedSizeInBytes() { return serializedSizeInBytes(nbrruns); } - - private void setLength(int index, char v) { setLength(valueslength, index, v); } - - private void setLength(CharBuffer valueslength, int index, char v) { valueslength.put(2 * index + 1, v); } - private void setValue(int index, char v) { setValue(valueslength, index, v); } @@ -2083,17 +2058,16 @@ private void setValue(CharBuffer valueslength, int index, char v) { valueslength.put(2 * index, v); } - - // assume that the (maybe) inplace operations // will never actually *be* in place if they are // to return ArrayContainer or BitmapContainer private void smartAppend(char[] vl, char val) { int oldend; - if ((nbrruns == 0) || ( - (val) > (oldend = (vl[2 * (nbrruns - 1)]) - + (vl[2 * (nbrruns - 1) + 1])) + 1)) { // we add a new one + if ((nbrruns == 0) + || ((val) + > (oldend = (vl[2 * (nbrruns - 1)]) + (vl[2 * (nbrruns - 1) + 1])) + + 1)) { // we add a new one vl[2 * nbrruns] = val; vl[2 * nbrruns + 1] = 0; nbrruns++; @@ -2106,9 +2080,10 @@ private void smartAppend(char[] vl, char val) { void smartAppend(char start, char length) { int oldend; - if ((nbrruns == 0) || ((start) > (oldend = - (getValue(nbrruns - 1)) + (getLength(nbrruns - 1))) - + 1)) { // we add a new one + if ((nbrruns == 0) + || ((start) + > (oldend = (getValue(nbrruns - 1)) + (getLength(nbrruns - 1))) + + 1)) { // we add a new one ensureCapacity(nbrruns + 1); valueslength.put(2 * nbrruns, start); valueslength.put(2 * nbrruns + 1, length); @@ -2123,9 +2098,10 @@ void smartAppend(char start, char length) { private void smartAppend(char[] vl, char start, char length) { int oldend; - if ((nbrruns == 0) || ( - (start) > (oldend = (vl[2 * (nbrruns - 1)]) - + (vl[2 * (nbrruns - 1) + 1])) + 1)) { // we add a new one + if ((nbrruns == 0) + || ((start) + > (oldend = (vl[2 * (nbrruns - 1)]) + (vl[2 * (nbrruns - 1) + 1])) + + 1)) { // we add a new one vl[2 * nbrruns] = start; vl[2 * nbrruns + 1] = length; nbrruns++; @@ -2133,16 +2109,16 @@ private void smartAppend(char[] vl, char start, char length) { } int newend = (start) + (length) + 1; if (newend > oldend) { // we merge - vl[2 * (nbrruns - 1) + 1] = - (char) (newend - 1 - (vl[2 * (nbrruns - 1)])); + vl[2 * (nbrruns - 1) + 1] = (char) (newend - 1 - (vl[2 * (nbrruns - 1)])); } } private void smartAppendExclusive(char[] vl, char val) { int oldend; - if ((nbrruns == 0) || ( - (val) > (oldend = (getValue(nbrruns - 1)) - + (getLength(nbrruns - 1)) + 1))) { // we add a new one + if ((nbrruns == 0) + || ((val) + > (oldend = + (getValue(nbrruns - 1)) + (getLength(nbrruns - 1)) + 1))) { // we add a new one vl[2 * nbrruns] = val; vl[2 * nbrruns + 1] = 0; nbrruns++; @@ -2182,9 +2158,9 @@ private void smartAppendExclusive(char[] vl, char val) { private void smartAppendExclusive(char[] vl, char start, char length) { int oldend; - if ((nbrruns == 0) || ( - start > (oldend = getValue(nbrruns - 1) - + getLength(nbrruns - 1) + 1))) { // we add a new one + if ((nbrruns == 0) + || (start + > (oldend = getValue(nbrruns - 1) + getLength(nbrruns - 1) + 1))) { // we add a new one vl[2 * nbrruns] = start; vl[2 * nbrruns + 1] = length; nbrruns++; @@ -2226,17 +2202,6 @@ private void smartAppendExclusive(char[] vl, char start, char length) { } } - - // convert to bitmap *if needed* (useful if you know it can't be an array) - private MappeableContainer toBitmapIfNeeded() { - int sizeAsRunContainer = MappeableRunContainer.serializedSizeInBytes(this.nbrruns); - int sizeAsBitmapContainer = MappeableBitmapContainer.serializedSizeInBytes(0); - if (sizeAsBitmapContainer > sizeAsRunContainer) { - return this; - } - return toBitmapContainer(); - } - /** * Convert the container to either a Bitmap or an Array Container, depending on the cardinality. * @@ -2273,7 +2238,6 @@ public Container toContainer() { return new RunContainer(this); } - // convert to bitmap or array *if needed* private MappeableContainer toEfficientContainer() { int sizeAsRunContainer = MappeableRunContainer.serializedSizeInBytes(this.nbrruns); @@ -2330,10 +2294,9 @@ public String toString() { StringBuilder sb = new StringBuilder("[]".length() + "-123456789,".length() * nbrruns); for (int k = 0; k < this.nbrruns; ++k) { sb.append('['); - sb.append((int)(this.getValue(k))); + sb.append((int) (this.getValue(k))); sb.append(','); - sb.append((this.getValue(k)) - + (this.getLength(k))); + sb.append((this.getValue(k)) + (this.getLength(k))); sb.append(']'); } return sb.toString(); @@ -2380,7 +2343,7 @@ protected void writeArray(ByteBuffer buffer) { source.position(0); source.limit(nbrruns * 2); CharBuffer target = buffer.asCharBuffer(); - target.put((char)nbrruns); + target.put((char) nbrruns); target.put(source); int bytesWritten = (nbrruns * 2 + 1) * 2; buffer.position(buffer.position() + bytesWritten); @@ -2468,21 +2431,18 @@ public MappeableContainer xor(MappeableRunContainer x) { return answer.toEfficientContainer(); } - @Override public void forEach(char msb, IntConsumer ic) { - int high = ((int)msb) << 16; - for(int k = 0; k < this.nbrruns; ++k) { + int high = ((int) msb) << 16; + for (int k = 0; k < this.nbrruns; ++k) { int base = (this.getValue(k) & 0xFFFF) | high; int le = this.getLength(k) & 0xFFFF; - for(int l = base; l - le <= base; ++l) { + for (int l = base; l - le <= base; ++l) { ic.accept(l); } } } - - @Override public int andCardinality(MappeableArrayContainer x) { if (this.nbrruns == 0) { @@ -2495,17 +2455,17 @@ public int andCardinality(MappeableArrayContainer x) { int rlelength = (this.getLength(rlepos)); while (arraypos < x.cardinality) { int arrayval = (x.content.get(arraypos)); - while (rleval + rlelength < arrayval) {// this will frequently be false + while (rleval + rlelength < arrayval) { // this will frequently be false ++rlepos; if (rlepos == this.nbrruns) { - return andCardinality;// we are done + return andCardinality; // we are done } rleval = (this.getValue(rlepos)); rlelength = (this.getLength(rlepos)); } if (rleval > arrayval) { - arraypos = BufferUtil.advanceUntil(x.content, arraypos, - x.cardinality, this.getValue(rlepos)); + arraypos = + BufferUtil.advanceUntil(x.content, arraypos, x.cardinality, this.getValue(rlepos)); } else { andCardinality++; arraypos++; @@ -2514,7 +2474,6 @@ public int andCardinality(MappeableArrayContainer x) { return andCardinality; } - @Override public int andCardinality(MappeableBitmapContainer x) { // could be implemented as return toBitmapOrArrayContainer().iand(x); @@ -2550,10 +2509,10 @@ public int andCardinality(MappeableRunContainer x) { xstart = (x.getValue(xrlepos)); xend = xstart + (x.getLength(xrlepos)) + 1; } - } else {// they overlap + } else { // they overlap final int lateststart = Math.max(start, xstart); int earliestend; - if (end == xend) {// improbable + if (end == xend) { // improbable earliestend = end; rlepos++; xrlepos++; @@ -2573,7 +2532,7 @@ public int andCardinality(MappeableRunContainer x) { end = start + (this.getLength(rlepos)) + 1; } - } else {// end > xend + } else { // end > xend earliestend = xend; xrlepos++; if (xrlepos < x.nbrruns) { @@ -2588,7 +2547,6 @@ public int andCardinality(MappeableRunContainer x) { return cardinality; } - @Override public MappeableBitmapContainer toBitmapContainer() { int card = this.getCardinality(); @@ -2681,17 +2639,17 @@ public int previousAbsentValue(char fromValue) { @Override protected boolean contains(MappeableRunContainer runContainer) { int i1 = 0, i2 = 0; - while(i1 < numberOfRuns() && i2 < runContainer.numberOfRuns()) { + while (i1 < numberOfRuns() && i2 < runContainer.numberOfRuns()) { int start1 = (getValue(i1)); int stop1 = start1 + (getLength(i1)); int start2 = (runContainer.getValue(i2)); int stop2 = start2 + (runContainer.getLength(i2)); - if(start1 > start2) { + if (start1 > start2) { return false; } else { - if(stop1 > stop2) { + if (stop1 > stop2) { i2++; - } else if(stop1 == stop2) { + } else if (stop1 == stop2) { i1++; i2++; } else { @@ -2710,11 +2668,11 @@ protected boolean contains(MappeableArrayContainer arrayContainer) { return false; } int ia = 0, ir = 0; - while(ia < arrayContainer.getCardinality() && ir < runCount) { + while (ia < arrayContainer.getCardinality() && ir < runCount) { int start = (getValue(ir)); int stop = start + (getLength(ir)); int value = (arrayContainer.content.get(ia)); - if(value < start) { + if (value < start) { return false; } else if (value > stop) { ++ir; @@ -2733,30 +2691,38 @@ protected boolean contains(MappeableBitmapContainer bitmapContainer) { } final int runCount = numberOfRuns(); char ib = 0, ir = 0; - while(ib < MappeableBitmapContainer.MAX_CAPACITY / 64 && ir < runCount) { + int start = getValue(0); + int stop = start + getLength(0); + while (ib < MappeableBitmapContainer.MAX_CAPACITY / 64 && ir < runCount) { long w = bitmapContainer.bitmap.get(ib); - while (w != 0 && ir < runCount) { - int start = (getValue(ir)); - int stop = start+ (getLength(ir)); - long t = w & -w; + while (w != 0) { long r = ib * 64 + Long.numberOfTrailingZeros(w); if (r < start) { return false; - } else if(r > stop) { + } else if (r > stop) { ++ir; + if (ir == runCount) { + break; + } + start = getValue(ir); + stop = start + getLength(ir); + + } else if (ib * 64 + 64 < stop) { + ib = (char) (stop / 64); + w = bitmapContainer.bitmap.get(ib); } else { - w ^= t; + w &= w - 1; } } - if(w == 0) { + if (w == 0) { ++ib; } else { return false; } } - if(ib < MappeableBitmapContainer.MAX_CAPACITY / 64) { - for(; ib < MappeableBitmapContainer.MAX_CAPACITY / 64 ; ib++) { - if(bitmapContainer.bitmap.get(ib) != 0) { + if (ib < MappeableBitmapContainer.MAX_CAPACITY / 64) { + for (; ib < MappeableBitmapContainer.MAX_CAPACITY / 64; ib++) { + if (bitmapContainer.bitmap.get(ib) != 0) { return false; } } @@ -2766,15 +2732,14 @@ protected boolean contains(MappeableBitmapContainer bitmapContainer) { @Override public boolean intersects(int minimum, int supremum) { - if((minimum < 0) || (supremum < minimum) || (supremum > (1<<16))) { + if ((minimum < 0) || (supremum < minimum) || (supremum > (1 << 16))) { throw new RuntimeException("This should never happen (bug)."); } for (int i = 0; i < numberOfRuns(); ++i) { char runFirstValue = getValue(i); char runLastValue = (char) (runFirstValue + getLength(i)); - if ((runFirstValue) < supremum - && (runLastValue) - ((char) minimum) >= 0){ + if ((runFirstValue) < supremum && (runLastValue) - ((char) minimum) >= 0) { return true; } } @@ -2796,11 +2761,8 @@ public boolean contains(int minimum, int supremum) { } return false; } - - } - final class MappeableRunContainerCharIterator implements PeekableCharIterator { private int pos; private int le = 0; @@ -2809,9 +2771,7 @@ final class MappeableRunContainerCharIterator implements PeekableCharIterator { private MappeableRunContainer parent; - MappeableRunContainerCharIterator() { - - } + MappeableRunContainerCharIterator() {} MappeableRunContainerCharIterator(MappeableRunContainer p) { wrap(p); @@ -2822,7 +2782,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -2863,7 +2823,7 @@ public int nextAsInt() { @Override public void remove() { - throw new RuntimeException("Not implemented");// TODO + throw new RuntimeException("Not implemented"); // TODO } void wrap(MappeableRunContainer p) { @@ -2898,10 +2858,8 @@ public void advanceIfNeeded(char minval) { public char peekNext() { return (char) (base + le); } - } - final class RawMappeableRunContainerCharIterator implements PeekableCharIterator { private int pos; private int le = 0; @@ -2911,7 +2869,6 @@ final class RawMappeableRunContainerCharIterator implements PeekableCharIterator private MappeableRunContainer parent; private char[] vl; - RawMappeableRunContainerCharIterator(MappeableRunContainer p) { wrap(p); } @@ -2921,7 +2878,7 @@ public PeekableCharIterator clone() { try { return (PeekableCharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -2953,7 +2910,6 @@ public char next() { return ans; } - @Override public int nextAsInt() { int ans = base + le; @@ -2971,7 +2927,7 @@ public int nextAsInt() { @Override public void remove() { - throw new RuntimeException("Not implemented");// TODO + throw new RuntimeException("Not implemented"); // TODO } private void wrap(MappeableRunContainer p) { @@ -3010,10 +2966,8 @@ public void advanceIfNeeded(char minval) { public char peekNext() { return (char) (base + le); } - } - final class RawReverseMappeableRunContainerCharIterator implements CharIterator { private int pos; private int le; @@ -3021,8 +2975,6 @@ final class RawReverseMappeableRunContainerCharIterator implements CharIterator private int base; private char[] vl; - - RawReverseMappeableRunContainerCharIterator(MappeableRunContainer p) { wrap(p); } @@ -3032,7 +2984,7 @@ public CharIterator clone() { try { return (CharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -3081,7 +3033,7 @@ public int nextAsInt() { @Override public void remove() { - throw new RuntimeException("Not implemented");// TODO + throw new RuntimeException("Not implemented"); // TODO } private void wrap(MappeableRunContainer p) { @@ -3097,10 +3049,8 @@ private void wrap(MappeableRunContainer p) { base = getValue(pos); } } - } - final class ReverseMappeableRunContainerCharIterator implements CharIterator { private int pos; private int le; @@ -3108,10 +3058,7 @@ final class ReverseMappeableRunContainerCharIterator implements CharIterator { private int base; private MappeableRunContainer parent; - - ReverseMappeableRunContainerCharIterator() { - - } + ReverseMappeableRunContainerCharIterator() {} ReverseMappeableRunContainerCharIterator(MappeableRunContainer p) { wrap(p); @@ -3122,7 +3069,7 @@ public CharIterator clone() { try { return (CharIterator) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -3163,7 +3110,7 @@ public int nextAsInt() { @Override public void remove() { - throw new RuntimeException("Not implemented");// TODO + throw new RuntimeException("Not implemented"); // TODO } void wrap(MappeableRunContainer p) { @@ -3175,5 +3122,4 @@ void wrap(MappeableRunContainer p) { base = parent.getValue(pos); } } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringArray.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringArray.java similarity index 91% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringArray.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringArray.java index e451d1fb6..5b81c7f21 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringArray.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringArray.java @@ -4,21 +4,24 @@ package org.roaringbitmap.buffer; +import static java.nio.ByteOrder.LITTLE_ENDIAN; import org.roaringbitmap.AppendableStorage; import org.roaringbitmap.InvalidRoaringFormat; import org.roaringbitmap.Util; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.LongBuffer; import java.util.Arrays; import java.util.NoSuchElementException; -import static java.nio.ByteOrder.LITTLE_ENDIAN; - - /** * Specialized array to store the containers used by a RoaringBitmap. This class is similar to * org.roaringbitmap.RoaringArray but meant to be used with memory mapping. This is not meant to be @@ -26,7 +29,10 @@ * * Objects of this class reside in RAM. */ -public final class MutableRoaringArray implements Cloneable, Externalizable, PointableRoaringArray, +public final class MutableRoaringArray + implements Cloneable, + Externalizable, + PointableRoaringArray, AppendableStorage { protected static final int INITIAL_CAPACITY = 4; @@ -38,7 +44,6 @@ public final class MutableRoaringArray implements Cloneable, Externalizable, Poi private static final long serialVersionUID = 5L; // TODO: OFK was 4L, not sure - char[] keys = null; MappeableContainer[] values = null; @@ -58,7 +63,6 @@ public MutableRoaringArray(int initialCapacity) { this.size = size; } - @Override public int advanceUntil(char x, int pos) { int lower = pos + 1; @@ -71,8 +75,7 @@ public int advanceUntil(char x, int pos) { int spansize = 1; // could set larger // bootstrap an upper limit - while (lower + spansize < size - && (keys[lower + spansize]) < (x)) { + while (lower + spansize < size && (keys[lower + spansize]) < (x)) { spansize *= 2; // hoping for compiler will reduce to shift } int upper = (lower + spansize < size) ? lower + spansize : size - 1; @@ -83,8 +86,8 @@ public int advanceUntil(char x, int pos) { return upper; } - if ((keys[upper]) < (x)) {// means array has no - // item key >= x + if ((keys[upper]) < (x)) { // means array has no + // item key >= x return size; } @@ -109,8 +112,7 @@ public int advanceUntil(char x, int pos) { @Override public void append(char key, MappeableContainer value) { if (size > 0 && key < keys[size - 1]) { - throw new IllegalArgumentException("append only: " + (key) - + " < " + (keys[size - 1])); + throw new IllegalArgumentException("append only: " + (key) + " < " + (keys[size - 1])); } extendArray(1); this.keys[this.size] = key; @@ -119,8 +121,7 @@ public void append(char key, MappeableContainer value) { } void append(MutableRoaringArray appendage) { - assert size == 0 || appendage.size == 0 - || keys[size - 1] < appendage.keys[0]; + assert size == 0 || appendage.size == 0 || keys[size - 1] < appendage.keys[0]; if (appendage.size != 0 && size != 0) { keys = Arrays.copyOf(keys, size + appendage.size); values = Arrays.copyOf(values, size + appendage.size); @@ -263,10 +264,12 @@ public void deserialize(DataInput in) throws IOException { if ((cookie & 0xFFFF) != SERIAL_COOKIE && cookie != SERIAL_COOKIE_NO_RUNCONTAINER) { throw new InvalidRoaringFormat("I failed to find a valid cookie."); } - this.size = ((cookie & 0xFFFF) == SERIAL_COOKIE) ? (cookie >>> 16) + 1 - : Integer.reverseBytes(in.readInt()); + this.size = + ((cookie & 0xFFFF) == SERIAL_COOKIE) + ? (cookie >>> 16) + 1 + : Integer.reverseBytes(in.readInt()); // logically we cannot have more than (1<<16) containers. - if(this.size > (1<<16)) { + if (this.size > (1 << 16)) { throw new InvalidRoaringFormat("Size too large"); } if ((this.keys == null) || (this.keys.length < this.size)) { @@ -355,7 +358,7 @@ public void deserialize(ByteBuffer bbf) { boolean hasRunContainers = (cookie & 0xFFFF) == SERIAL_COOKIE; this.size = hasRunContainers ? (cookie >>> 16) + 1 : buffer.getInt(); - if(this.size > (1<<16)) { + if (this.size > (1 << 16)) { throw new InvalidRoaringFormat("Size too large"); } if ((this.keys == null) || (this.keys.length < this.size)) { @@ -363,7 +366,6 @@ public void deserialize(ByteBuffer bbf) { this.values = new MappeableContainer[this.size]; } - byte[] bitmapOfRunContainers = null; boolean hasrun = (cookie & 0xFFFF) == SERIAL_COOKIE; if (hasrun) { @@ -394,10 +396,10 @@ public void deserialize(ByteBuffer bbf) { if (isBitmap[k]) { long[] array = new long[MappeableBitmapContainer.MAX_CAPACITY / 64]; buffer.asLongBuffer().get(array); - container = new MappeableBitmapContainer(cardinalities[k], LongBuffer.wrap(array)); + container = new MappeableBitmapContainer(LongBuffer.wrap(array), cardinalities[k]); buffer.position(buffer.position() + 1024 * 8); } else if (bitmapOfRunContainers != null - && ((bitmapOfRunContainers[k / 8] & (1 << (k & 7))) != 0)) { + && ((bitmapOfRunContainers[k / 8] & (1 << (k & 7))) != 0)) { int nbrruns = (buffer.getChar()); int length = 2 * nbrruns; @@ -437,22 +439,10 @@ public int getCardinality(int i) { return getContainerAtIndex(i).getCardinality(); } - // retired method (inefficient) - // involves a binary search - /*@Override - public MappeableContainer getContainer(char x) { - final int i = this.binarySearch(0, size, x); - if (i < 0) { - return null; - } - return this.values[i]; - }*/ - @Override public int getContainerIndex(char x) { return this.binarySearch(0, size, x); - } - + } @Override public MappeableContainer getContainerAtIndex(int i) { @@ -479,7 +469,7 @@ public MappeableContainerPointer clone() { try { return (MappeableContainerPointer) super.clone(); } catch (CloneNotSupportedException e) { - return null;// will not happen + return null; // will not happen } } @@ -511,7 +501,7 @@ public int getSizeInBytes() { @Override public boolean hasContainer() { - return 0 <= k & k < MutableRoaringArray.this.size; + return 0 <= k && k < MutableRoaringArray.this.size; } @Override @@ -527,16 +517,13 @@ public boolean isRunContainer() { @Override public char key() { return MutableRoaringArray.this.keys[k]; - } - @Override public void previous() { --k; } }; - } // involves a binary search @@ -558,17 +545,17 @@ public char getKeyAtIndex(int i) { @Override public boolean equals(Object o) { if (o instanceof ImmutableRoaringArray) { - ImmutableRoaringArray srb = (ImmutableRoaringArray)o; + ImmutableRoaringArray srb = (ImmutableRoaringArray) o; if (srb.size() != this.size()) { return false; } MappeableContainerPointer cp = this.getContainerPointer(); MappeableContainerPointer cpo = srb.getContainerPointer(); - while(cp.hasContainer() && cpo.hasContainer()) { - if(cp.key() != cpo.key()) { + while (cp.hasContainer() && cpo.hasContainer()) { + if (cp.key() != cpo.key()) { return false; } - if(!cp.getContainer().equals(cpo.getContainer())) { + if (!cp.getContainer().equals(cpo.getContainer())) { return false; } } @@ -598,10 +585,10 @@ public boolean hasRunCompression() { protected int headerSize() { if (hasRunCompression()) { - if (size < NO_OFFSET_THRESHOLD) {// for small bitmaps, we omit the offsets + if (size < NO_OFFSET_THRESHOLD) { // for small bitmaps, we omit the offsets return 4 + (size + 7) / 8 + 4 * size; } - return 4 + (size + 7) / 8 + 8 * size;// - 4 because we pack the size with the cookie + return 4 + (size + 7) / 8 + 8 * size; // - 4 because we pack the size with the cookie } else { return 4 + 4 + 8 * size; } @@ -630,7 +617,6 @@ protected void removeAtIndex(int i) { size--; } - protected void removeIndexRange(int begin, int end) { if (end <= begin) { return; @@ -650,7 +636,6 @@ protected void replaceKeyAndContainerAtIndex(int i, char key, MappeableContainer this.values[i] = c; } - protected void resize(int newLength) { Arrays.fill(this.keys, newLength, this.size, (char) 0); Arrays.fill(this.values, newLength, this.size, null); @@ -701,7 +686,6 @@ public void serialize(DataOutput out) throws IOException { for (int k = 0; k < size; ++k) { values[k].writeArray(out); } - } /** @@ -726,7 +710,7 @@ public void serialize(ByteBuffer buffer) { runMarker |= (1 << j); } } - buf.put((byte)runMarker); + buf.put((byte) runMarker); } int runMarkersLength = buf.position() - offset; if (this.size < NO_OFFSET_THRESHOLD) { @@ -788,10 +772,9 @@ public void writeExternal(ObjectOutput out) throws IOException { serialize(out); } - @Override public boolean containsForContainerAtIndex(int i, char x) { - return getContainerAtIndex(i).contains(x);// no faster way + return getContainerAtIndex(i).contains(x); // no faster way } @Override @@ -810,10 +793,33 @@ public int last() { return lastKey << 16 | container.last(); } + @Override + public int firstSigned() { + assertNonEmpty(); + int index = advanceUntil((char) (1 << 15), -1); + if (index == size) { // no negatives + index = 0; + } + char key = getKeyAtIndex(index); + MappeableContainer container = getContainerAtIndex(index); + return key << 16 | container.first(); + } + + @Override + public int lastSigned() { + assertNonEmpty(); + int index = advanceUntil((char) (1 << 15), -1) - 1; + if (index == -1) { // no positives + index += size; + } + char key = getKeyAtIndex(index); + MappeableContainer container = getContainerAtIndex(index); + return key << 16 | container.last(); + } + private void assertNonEmpty() { - if(size == 0) { + if (size == 0) { throw new NoSuchElementException("Empty MutableRoaringArray"); } } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmap.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmap.java similarity index 77% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmap.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmap.java index 180f31945..923a10b95 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmap.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmap.java @@ -4,11 +4,20 @@ package org.roaringbitmap.buffer; -import org.roaringbitmap.*; - -import java.io.*; +import org.roaringbitmap.AppendableStorage; +import org.roaringbitmap.BitmapDataProvider; +import org.roaringbitmap.CharIterator; +import org.roaringbitmap.ContainerPointer; +import org.roaringbitmap.InvalidRoaringFormat; +import org.roaringbitmap.RoaringBitmap; + +import java.io.DataInput; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.Serializable; import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.util.Iterator; /** @@ -62,8 +71,12 @@ * @see org.roaringbitmap.RoaringBitmap */ public class MutableRoaringBitmap extends ImmutableRoaringBitmap - implements Cloneable, Serializable, Iterable, Externalizable, - BitmapDataProvider, AppendableStorage { + implements Cloneable, + Serializable, + Iterable, + Externalizable, + BitmapDataProvider, + AppendableStorage { private static final long serialVersionUID = 4L; // 3L; bumped by ofk for runcontainers /** @@ -73,10 +86,10 @@ public class MutableRoaringBitmap extends ImmutableRoaringBitmap * negative. Values that would fall outside * of the valid 32-bit range are discarded * so that the result can have lower cardinality. - * + * * This method can be relatively expensive when * offset is not divisible by 65536. Use sparingly. - * + * * @param x source bitmap * @param offset increment (can be negative) * @return a new bitmap @@ -84,53 +97,53 @@ public class MutableRoaringBitmap extends ImmutableRoaringBitmap public static MutableRoaringBitmap addOffset(final ImmutableRoaringBitmap x, long offset) { // we need "offset" to be a long because we want to support values // between -0xFFFFFFFF up to +-0xFFFFFFFF - long container_offset_long = offset < 0 - ? (offset - (1<<16) + 1) / (1<<16) : offset / (1 << 16); - if((container_offset_long < -(1<<16) ) || (container_offset_long >= (1<<16) )) { + long container_offset_long = + offset < 0 ? (offset - (1 << 16) + 1) / (1 << 16) : offset / (1 << 16); + if ((container_offset_long < -(1 << 16)) || (container_offset_long >= (1 << 16))) { return new MutableRoaringBitmap(); // it is necessarily going to be empty } // next cast is necessarily safe, the result is between -0xFFFF and 0xFFFF int container_offset = (int) container_offset_long; // next case is safe - int in_container_offset = (int)(offset - container_offset_long * (1L<<16)); - if(in_container_offset == 0) { + int in_container_offset = (int) (offset - container_offset_long * (1L << 16)); + if (in_container_offset == 0) { MutableRoaringBitmap answer = new MutableRoaringBitmap(); - for(int pos = 0; pos < x.highLowContainer.size(); pos++) { + for (int pos = 0; pos < x.highLowContainer.size(); pos++) { int key = (x.highLowContainer.getKeyAtIndex(pos)); key += container_offset; - answer.getMappeableRoaringArray().append((char)key, - x.highLowContainer.getContainerAtIndex(pos).clone()); + answer + .getMappeableRoaringArray() + .append((char) key, x.highLowContainer.getContainerAtIndex(pos).clone()); } return answer; } else { MutableRoaringBitmap answer = new MutableRoaringBitmap(); - for(int pos = 0; pos < x.highLowContainer.size(); pos++) { + for (int pos = 0; pos < x.highLowContainer.size(); pos++) { int key = (x.highLowContainer.getKeyAtIndex(pos)); key += container_offset; + if (key + 1 < 0 || key > 0xFFFF) { + continue; + } MappeableContainer c = x.highLowContainer.getContainerAtIndex(pos); - MappeableContainer[] offsetted = BufferUtil.addOffset(c, - (char)in_container_offset); - boolean keyok = (key >= 0) && (key <= 0xFFFF); - boolean keypok = (key + 1 >= 0) && (key + 1 <= 0xFFFF); - if( !offsetted[0].isEmpty() && keyok) { + MappeableContainer[] offsetted = BufferUtil.addOffset(c, (char) in_container_offset); + boolean keyok = key >= 0; + boolean keypok = key + 1 <= 0xFFFF; + if (!offsetted[0].isEmpty() && keyok) { int current_size = answer.highLowContainer.size(); int lastkey = 0; - if(current_size > 0) { - lastkey = (answer.highLowContainer.getKeyAtIndex( - current_size - 1)); + if (current_size > 0) { + lastkey = (answer.highLowContainer.getKeyAtIndex(current_size - 1)); } - if((current_size > 0) && (lastkey == key)) { - MappeableContainer prev = answer.highLowContainer - .getContainerAtIndex(current_size - 1); + if ((current_size > 0) && (lastkey == key)) { + MappeableContainer prev = answer.highLowContainer.getContainerAtIndex(current_size - 1); MappeableContainer orresult = prev.ior(offsetted[0]); - answer.getMappeableRoaringArray().setContainerAtIndex(current_size - 1, - orresult); + answer.getMappeableRoaringArray().setContainerAtIndex(current_size - 1, orresult); } else { - answer.getMappeableRoaringArray().append((char)key, offsetted[0]); + answer.getMappeableRoaringArray().append((char) key, offsetted[0]); } } - if( !offsetted[1].isEmpty() && keypok) { - answer.getMappeableRoaringArray().append((char)(key + 1), offsetted[1]); + if (!offsetted[1].isEmpty() && keypok) { + answer.getMappeableRoaringArray().append((char) (key + 1), offsetted[1]); } } answer.repairAfterLazy(); @@ -146,9 +159,9 @@ public static MutableRoaringBitmap addOffset(final ImmutableRoaringBitmap x, lon * @param rangeEnd exclusive ending of range * @return new bitmap */ - public static MutableRoaringBitmap add(MutableRoaringBitmap rb, final long rangeStart, - final long rangeEnd) { - rangeSanityCheck(rangeStart,rangeEnd); + public static MutableRoaringBitmap add( + MutableRoaringBitmap rb, final long rangeStart, final long rangeEnd) { + rangeSanityCheck(rangeStart, rangeEnd); if (rangeStart >= rangeEnd) { return rb.clone(); // empty range } @@ -159,27 +172,30 @@ public static MutableRoaringBitmap add(MutableRoaringBitmap rb, final long range final int lbLast = (BufferUtil.lowbits(rangeEnd - 1)); MutableRoaringBitmap answer = new MutableRoaringBitmap(); - ((MutableRoaringArray) answer.highLowContainer).appendCopiesUntil(rb.highLowContainer, - (char) hbStart); + ((MutableRoaringArray) answer.highLowContainer) + .appendCopiesUntil(rb.highLowContainer, (char) hbStart); if (hbStart == hbLast) { final int i = rb.highLowContainer.getIndex((char) hbStart); final MappeableContainer c = - i >= 0 ? rb.highLowContainer.getContainerAtIndex(i).add(lbStart, lbLast + 1) + i >= 0 + ? rb.highLowContainer.getContainerAtIndex(i).add(lbStart, lbLast + 1) : MappeableContainer.rangeOfOnes(lbStart, lbLast + 1); ((MutableRoaringArray) answer.highLowContainer).append((char) hbStart, c); - ((MutableRoaringArray) answer.highLowContainer).appendCopiesAfter(rb.highLowContainer, - (char) hbLast); + ((MutableRoaringArray) answer.highLowContainer) + .appendCopiesAfter(rb.highLowContainer, (char) hbLast); return answer; } int ifirst = rb.highLowContainer.getIndex((char) hbStart); int ilast = rb.highLowContainer.getIndex((char) hbLast); { - final MappeableContainer c = ifirst >= 0 - ? rb.highLowContainer.getContainerAtIndex(ifirst).add(lbStart, - BufferUtil.maxLowBitAsInteger() + 1) - : MappeableContainer.rangeOfOnes(lbStart, BufferUtil.maxLowBitAsInteger() + 1); + final MappeableContainer c = + ifirst >= 0 + ? rb.highLowContainer + .getContainerAtIndex(ifirst) + .add(lbStart, BufferUtil.maxLowBitAsInteger() + 1) + : MappeableContainer.rangeOfOnes(lbStart, BufferUtil.maxLowBitAsInteger() + 1); ((MutableRoaringArray) answer.highLowContainer).append((char) hbStart, c); } for (int hb = hbStart + 1; hb < hbLast; ++hb) { @@ -188,12 +204,13 @@ public static MutableRoaringBitmap add(MutableRoaringBitmap rb, final long range } { final MappeableContainer c = - ilast >= 0 ? rb.highLowContainer.getContainerAtIndex(ilast).add(0, lbLast + 1) + ilast >= 0 + ? rb.highLowContainer.getContainerAtIndex(ilast).add(0, lbLast + 1) : MappeableContainer.rangeOfOnes(0, lbLast + 1); ((MutableRoaringArray) answer.highLowContainer).append((char) hbLast, c); } - ((MutableRoaringArray) answer.highLowContainer).appendCopiesAfter(rb.highLowContainer, - (char) hbLast); + ((MutableRoaringArray) answer.highLowContainer) + .appendCopiesAfter(rb.highLowContainer, (char) hbLast); return answer; } @@ -208,8 +225,8 @@ public static MutableRoaringBitmap add(MutableRoaringBitmap rb, final long range * @deprecated use the version where longs specify the range */ @Deprecated - public static MutableRoaringBitmap add(MutableRoaringBitmap rb, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap add( + MutableRoaringBitmap rb, final int rangeStart, final int rangeEnd) { if (rangeStart >= 0) { return add(rb, (long) rangeStart, (long) rangeEnd); } @@ -218,9 +235,6 @@ public static MutableRoaringBitmap add(MutableRoaringBitmap rb, return add(rb, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - - - /** * Bitwise AND (intersection) operation. The provided bitmaps are *not* modified. This operation * is thread-safe as long as the provided bitmaps remain unchanged. @@ -229,8 +243,8 @@ public static MutableRoaringBitmap add(MutableRoaringBitmap rb, * @param x2 other bitmap * @return result of the operation */ - public static MutableRoaringBitmap and(final MutableRoaringBitmap x1, - final MutableRoaringBitmap x2) { + public static MutableRoaringBitmap and( + final MutableRoaringBitmap x1, final MutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -248,7 +262,7 @@ public static MutableRoaringBitmap and(final MutableRoaringBitmap x1, } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = x1.highLowContainer.advanceUntil(s2, pos1); } else { // s1 > s2 pos2 = x2.highLowContainer.advanceUntil(s1, pos2); @@ -265,8 +279,8 @@ public static MutableRoaringBitmap and(final MutableRoaringBitmap x1, * @param x2 other bitmap * @return result of the operation */ - public static MutableRoaringBitmap andNot(final MutableRoaringBitmap x1, - final MutableRoaringBitmap x2) { + public static MutableRoaringBitmap andNot( + final MutableRoaringBitmap x1, final MutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); @@ -283,7 +297,7 @@ public static MutableRoaringBitmap andNot(final MutableRoaringBitmap x1, } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { final int nextPos1 = x1.highLowContainer.advanceUntil(s2, pos1); answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer, pos1, nextPos1); pos1 = nextPos1; @@ -311,9 +325,9 @@ public void add(final int... dat) { /** * Set the specified values to true, within given boundaries. This can be expected to be slightly - * faster than calling "add" repeatedly on the values dat[offset], dat[offset+1],..., - * dat[offset+n-1]. - * The provided integers values don't have to be in sorted order, but it may be preferable + * faster than calling "add" repeatedly on the values dat[offset], dat[offset+1],..., + * dat[offset+n-1]. + * The provided integers values don't have to be in sorted order, but it may be preferable * to sort them from a performance point of view. * * @param dat set values @@ -322,13 +336,13 @@ public void add(final int... dat) { */ public void addN(final int[] dat, final int offset, final int n) { // let us validate the values first. - if((n < 0) || (offset < 0)) { + if ((n < 0) || (offset < 0)) { throw new IllegalArgumentException("Negative values do not make sense."); } - if(n == 0) { + if (n == 0) { return; // nothing to do } - if(offset + n > dat.length) { + if (offset + n > dat.length) { throw new IllegalArgumentException("Data source is too small."); } MutableRoaringArray mra = (MutableRoaringArray) highLowContainer; @@ -341,24 +355,24 @@ public void addN(final int[] dat, final int offset, final int n) { if (currentcontainerindex >= 0) { currentcont = highLowContainer.getContainerAtIndex(currentcontainerindex); MappeableContainer newcont = currentcont.add(BufferUtil.lowbits(val)); - if(newcont != currentcont) { + if (newcont != currentcont) { mra.setContainerAtIndex(currentcontainerindex, newcont); currentcont = newcont; } } else { - currentcontainerindex = - currentcontainerindex - 1; + currentcontainerindex = -currentcontainerindex - 1; final MappeableArrayContainer newac = new MappeableArrayContainer(); currentcont = newac.add(BufferUtil.lowbits(val)); mra.insertNewKeyValueAt(currentcontainerindex, currenthb, currentcont); } j++; - for( ; j < n; ++j) { + for (; j < n; ++j) { val = dat[j + offset]; char newhb = BufferUtil.highbits(val); - if(currenthb == newhb) {// easy case + if (currenthb == newhb) { // easy case // this could be quite frequent MappeableContainer newcont = currentcont.add(BufferUtil.lowbits(val)); - if(newcont != currentcont) { + if (newcont != currentcont) { mra.setContainerAtIndex(currentcontainerindex, newcont); currentcont = newcont; } @@ -368,12 +382,12 @@ public void addN(final int[] dat, final int offset, final int n) { if (currentcontainerindex >= 0) { currentcont = highLowContainer.getContainerAtIndex(currentcontainerindex); MappeableContainer newcont = currentcont.add(BufferUtil.lowbits(val)); - if(newcont != currentcont) { + if (newcont != currentcont) { mra.setContainerAtIndex(currentcontainerindex, newcont); currentcont = newcont; } } else { - currentcontainerindex = - currentcontainerindex - 1; + currentcontainerindex = -currentcontainerindex - 1; final MappeableArrayContainer newac = new MappeableArrayContainer(); currentcont = newac.add(BufferUtil.lowbits(val)); mra.insertNewKeyValueAt(currentcontainerindex, currenthb, currentcont); @@ -396,16 +410,46 @@ public static MutableRoaringBitmap bitmapOf(final int... dat) { return ans; } - + /** + * @see #add(long, long) + */ + public static MutableRoaringBitmap bitmapOfRange(long min, long max) { + rangeSanityCheck(min, max); + if (min >= max) { + return new MutableRoaringBitmap(); + } + final int hbStart = BufferUtil.highbits(min); + final int lbStart = BufferUtil.lowbits(min); + final int hbLast = BufferUtil.highbits(max - 1); + final int lbLast = BufferUtil.lowbits(max - 1); + + MutableRoaringArray array = new MutableRoaringArray(hbLast - hbStart + 1); + MutableRoaringBitmap bitmap = new MutableRoaringBitmap(array); + + int firstEnd = hbStart < hbLast ? 1 << 16 : lbLast + 1; + MappeableContainer firstContainer = MappeableContainer.rangeOfOnes(lbStart, firstEnd); + bitmap.append((char) hbStart, firstContainer); + if (hbStart < hbLast) { + int i = hbStart + 1; + while (i < hbLast) { + MappeableContainer runContainer = MappeableContainer.rangeOfOnes(0, 1 << 16); + bitmap.append((char) i, runContainer); + i++; + } + MappeableContainer lastContainer = MappeableContainer.rangeOfOnes(0, lbLast + 1); + bitmap.append((char) hbLast, lastContainer); + } + return bitmap; + } protected static void rangeSanityCheck(final long rangeStart, final long rangeEnd) { - if (rangeStart < 0 || rangeStart > (1L << 32)-1) { - throw new IllegalArgumentException("rangeStart="+ rangeStart - +" should be in [0, 0xffffffff]"); + if (rangeStart < 0 || rangeStart > (1L << 32) - 1) { + throw new IllegalArgumentException( + "rangeStart=" + rangeStart + " should be in [0, 0xffffffff]"); } if (rangeEnd > (1L << 32) || rangeEnd < 0) { - throw new IllegalArgumentException("rangeEnd="+ rangeEnd - +" should be in [0, 0xffffffff + 1]"); + throw new IllegalArgumentException( + "rangeEnd=" + rangeEnd + " should be in [0, 0xffffffff + 1]"); } } @@ -418,8 +462,8 @@ protected static void rangeSanityCheck(final long rangeStart, final long rangeEn * @param rangeEnd exclusive ending of range * @return a new Bitmap */ - public static MutableRoaringBitmap flip(MutableRoaringBitmap bm, final long rangeStart, - final long rangeEnd) { + public static MutableRoaringBitmap flip( + MutableRoaringBitmap bm, final long rangeStart, final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); if (rangeStart >= rangeEnd) { return bm.clone(); @@ -431,7 +475,6 @@ public static MutableRoaringBitmap flip(MutableRoaringBitmap bm, final long rang final int hbLast = (BufferUtil.highbits(rangeEnd - 1)); final int lbLast = (BufferUtil.lowbits(rangeEnd - 1)); - // copy the containers before the active area answer.getMappeableRoaringArray().appendCopiesUntil(bm.highLowContainer, (char) hbStart); @@ -452,8 +495,12 @@ public static MutableRoaringBitmap flip(MutableRoaringBitmap bm, final long rang } else { // *think* the range of ones must never be // empty. - answer.getMappeableRoaringArray().insertNewKeyValueAt(-j - 1, (char) hb, - MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); + answer + .getMappeableRoaringArray() + .insertNewKeyValueAt( + -j - 1, + (char) hb, + MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); } } // copy the containers after the active area. @@ -462,7 +509,6 @@ public static MutableRoaringBitmap flip(MutableRoaringBitmap bm, final long rang return answer; } - /** * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The * given bitmap is unchanged. @@ -474,8 +520,8 @@ public static MutableRoaringBitmap flip(MutableRoaringBitmap bm, final long rang * @deprecated use the version where longs specify the range */ @Deprecated - public static MutableRoaringBitmap flip(MutableRoaringBitmap rb, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap flip( + MutableRoaringBitmap rb, final int rangeStart, final int rangeEnd) { if (rangeStart >= 0) { return flip(rb, (long) rangeStart, (long) rangeEnd); } @@ -485,12 +531,13 @@ public static MutableRoaringBitmap flip(MutableRoaringBitmap rb, } // important: inputs should not have been computed lazily - protected static MutableRoaringBitmap lazyorfromlazyinputs(final MutableRoaringBitmap x1, - final MutableRoaringBitmap x2) { + protected static MutableRoaringBitmap lazyorfromlazyinputs( + final MutableRoaringBitmap x1, final MutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); MappeableContainerPointer i1 = x1.highLowContainer.getContainerPointer(); MappeableContainerPointer i2 = x2.highLowContainer.getContainerPointer(); - main: if (i1.hasContainer() && i2.hasContainer()) { + main: + if (i1.hasContainer() && i2.hasContainer()) { while (true) { if (i1.key() == i2.key()) { MappeableContainer c1 = i1.getContainer(); @@ -557,19 +604,25 @@ public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) { * @param x2 other bitmap * @return result of the operation */ - public static MutableRoaringBitmap or(final MutableRoaringBitmap x1, - final MutableRoaringBitmap x2) { + public static MutableRoaringBitmap or( + final MutableRoaringBitmap x1, final MutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = x1.highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - answer.getMappeableRoaringArray().append(s1, x1.highLowContainer.getContainerAtIndex(pos1) - .or(x2.highLowContainer.getContainerAtIndex(pos2))); + answer + .getMappeableRoaringArray() + .append( + s1, + x1.highLowContainer + .getContainerAtIndex(pos1) + .or(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -577,17 +630,23 @@ public static MutableRoaringBitmap or(final MutableRoaringBitmap x1, } s1 = x1.highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { - answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer.getKeyAtIndex(pos1), - x1.highLowContainer.getContainerAtIndex(pos1)); + } else if (s1 < s2) { + answer + .getMappeableRoaringArray() + .appendCopy( + x1.highLowContainer.getKeyAtIndex(pos1), + x1.highLowContainer.getContainerAtIndex(pos1)); pos1++; if (pos1 == length1) { break main; } s1 = x1.highLowContainer.getKeyAtIndex(pos1); } else { // s1 > s2 - answer.getMappeableRoaringArray().appendCopy(x2.highLowContainer.getKeyAtIndex(pos2), - x2.highLowContainer.getContainerAtIndex(pos2)); + answer + .getMappeableRoaringArray() + .appendCopy( + x2.highLowContainer.getKeyAtIndex(pos2), + x2.highLowContainer.getContainerAtIndex(pos2)); pos2++; if (pos2 == length2) { break main; @@ -612,8 +671,8 @@ public static MutableRoaringBitmap or(final MutableRoaringBitmap x1, * @param rangeEnd exclusive ending of range * @return new bitmap */ - public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, final long rangeStart, - final long rangeEnd) { + public static MutableRoaringBitmap remove( + MutableRoaringBitmap rb, final long rangeStart, final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); if (rangeStart >= rangeEnd) { return rb.clone(); // empty range @@ -623,8 +682,8 @@ public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, final long ra final int hbLast = (BufferUtil.highbits(rangeEnd - 1)); final int lbLast = (BufferUtil.lowbits(rangeEnd - 1)); MutableRoaringBitmap answer = new MutableRoaringBitmap(); - ((MutableRoaringArray) answer.highLowContainer).appendCopiesUntil(rb.highLowContainer, - (char) hbStart); + ((MutableRoaringArray) answer.highLowContainer) + .appendCopiesUntil(rb.highLowContainer, (char) hbStart); if (hbStart == hbLast) { final int i = rb.highLowContainer.getIndex((char) hbStart); @@ -635,15 +694,17 @@ public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, final long ra ((MutableRoaringArray) answer.highLowContainer).append((char) hbStart, c); } } - ((MutableRoaringArray) answer.highLowContainer).appendCopiesAfter(rb.highLowContainer, - (char) hbLast); + ((MutableRoaringArray) answer.highLowContainer) + .appendCopiesAfter(rb.highLowContainer, (char) hbLast); return answer; } int ifirst = rb.highLowContainer.getIndex((char) hbStart); int ilast = rb.highLowContainer.getIndex((char) hbLast); if ((ifirst >= 0) && (lbStart != 0)) { - final MappeableContainer c = rb.highLowContainer.getContainerAtIndex(ifirst).remove(lbStart, - BufferUtil.maxLowBitAsInteger() + 1); + final MappeableContainer c = + rb.highLowContainer + .getContainerAtIndex(ifirst) + .remove(lbStart, BufferUtil.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { ((MutableRoaringArray) answer.highLowContainer).append((char) hbStart, c); } @@ -655,8 +716,8 @@ public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, final long ra ((MutableRoaringArray) answer.highLowContainer).append((char) hbLast, c); } } - ((MutableRoaringArray) answer.highLowContainer).appendCopiesAfter(rb.highLowContainer, - (char) hbLast); + ((MutableRoaringArray) answer.highLowContainer) + .appendCopiesAfter(rb.highLowContainer, (char) hbLast); return answer; } @@ -670,8 +731,8 @@ public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, final long ra * @deprecated use the version where longs specify the range */ @Deprecated - public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, - final int rangeStart, final int rangeEnd) { + public static MutableRoaringBitmap remove( + MutableRoaringBitmap rb, final int rangeStart, final int rangeEnd) { if (rangeStart >= 0) { return remove(rb, (long) rangeStart, (long) rangeEnd); } @@ -680,7 +741,6 @@ public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, return remove(rb, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - /** * Bitwise XOR (symmetric difference) operation. The provided bitmaps are *not* modified. This * operation is thread-safe as long as the provided bitmaps remain unchanged. @@ -689,20 +749,23 @@ public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, * @param x2 other bitmap * @return result of the operation */ - public static MutableRoaringBitmap xor(final MutableRoaringBitmap x1, - final MutableRoaringBitmap x2) { + public static MutableRoaringBitmap xor( + final MutableRoaringBitmap x1, final MutableRoaringBitmap x2) { final MutableRoaringBitmap answer = new MutableRoaringBitmap(); int pos1 = 0, pos2 = 0; final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = x1.highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - final MappeableContainer c = x1.highLowContainer.getContainerAtIndex(pos1) - .xor(x2.highLowContainer.getContainerAtIndex(pos2)); + final MappeableContainer c = + x1.highLowContainer + .getContainerAtIndex(pos1) + .xor(x2.highLowContainer.getContainerAtIndex(pos2)); if (!c.isEmpty()) { answer.getMappeableRoaringArray().append(s1, c); } @@ -713,17 +776,23 @@ public static MutableRoaringBitmap xor(final MutableRoaringBitmap x1, } s1 = x1.highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { - answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer.getKeyAtIndex(pos1), - x1.highLowContainer.getContainerAtIndex(pos1)); + } else if (s1 < s2) { + answer + .getMappeableRoaringArray() + .appendCopy( + x1.highLowContainer.getKeyAtIndex(pos1), + x1.highLowContainer.getContainerAtIndex(pos1)); pos1++; if (pos1 == length1) { break main; } s1 = x1.highLowContainer.getKeyAtIndex(pos1); } else if (s1 - s2 > 0) { - answer.getMappeableRoaringArray().appendCopy(x2.highLowContainer.getKeyAtIndex(pos2), - x2.highLowContainer.getContainerAtIndex(pos2)); + answer + .getMappeableRoaringArray() + .appendCopy( + x2.highLowContainer.getKeyAtIndex(pos2), + x2.highLowContainer.getContainerAtIndex(pos2)); pos2++; if (pos2 == length2) { break main; @@ -760,8 +829,8 @@ public MutableRoaringBitmap(RoaringBitmap rb) { highLowContainer = new MutableRoaringArray(); ContainerPointer cp = rb.getContainerPointer(); while (cp.getContainer() != null) { - ((MutableRoaringArray) highLowContainer).append(cp.key(), - cp.getContainer().toMappeableContainer()); + ((MutableRoaringArray) highLowContainer) + .append(cp.key(), cp.getContainer().toMappeableContainer()); cp.advance(); } } @@ -780,8 +849,9 @@ public void add(final int x) { final char hb = BufferUtil.highbits(x); final int i = highLowContainer.getIndex(hb); if (i >= 0) { - getMappeableRoaringArray().setContainerAtIndex(i, - highLowContainer.getContainerAtIndex(i).add(BufferUtil.lowbits(x))); + getMappeableRoaringArray() + .setContainerAtIndex( + i, highLowContainer.getContainerAtIndex(i).add(BufferUtil.lowbits(x))); } else { final MappeableArrayContainer newac = new MappeableArrayContainer(); getMappeableRoaringArray().insertNewKeyValueAt(-i - 1, hb, newac.add(BufferUtil.lowbits(x))); @@ -817,13 +887,16 @@ public void add(final long rangeStart, final long rangeEnd) { highLowContainer.getContainerAtIndex(i).iadd(containerStart, containerLast + 1); ((MutableRoaringArray) highLowContainer).setContainerAtIndex(i, c); } else { - ((MutableRoaringArray) highLowContainer).insertNewKeyValueAt(-i - 1, (char) hb, - MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); + ((MutableRoaringArray) highLowContainer) + .insertNewKeyValueAt( + -i - 1, + (char) hb, + MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); } } } - /** + /** * * Add to the current bitmap all integers in [rangeStart,rangeEnd). * @@ -841,16 +914,15 @@ public void add(final int rangeStart, final int rangeEnd) { add(rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - - - /** * In-place bitwise AND (intersection) operation. The current bitmap is modified. * * @param array other bitmap */ public void and(final ImmutableRoaringBitmap array) { - if(array == this) { return; } + if (array == this) { + return; + } int pos1 = 0, pos2 = 0, intersectionSize = 0; final int length1 = highLowContainer.size(), length2 = array.highLowContainer.size(); @@ -866,7 +938,7 @@ public void and(final ImmutableRoaringBitmap array) { } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { pos1 = highLowContainer.advanceUntil(s2, pos1); } else { // s1 > s2 pos2 = array.highLowContainer.advanceUntil(s1, pos2); @@ -875,14 +947,13 @@ public void and(final ImmutableRoaringBitmap array) { getMappeableRoaringArray().resize(intersectionSize); } - /** * In-place bitwise ANDNOT (difference) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void andNot(final ImmutableRoaringBitmap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -901,7 +972,7 @@ public void andNot(final ImmutableRoaringBitmap x2) { } ++pos1; ++pos2; - } else if (s1 < s2) { + } else if (s1 < s2) { if (pos1 != intersectionSize) { final MappeableContainer c1 = highLowContainer.getContainerAtIndex(pos1); getMappeableRoaringArray().replaceKeyAndContainerAtIndex(intersectionSize, s1, c1); @@ -926,12 +997,12 @@ public void andNot(final ImmutableRoaringBitmap x2) { * @param rangeEnd end point of the range (exclusive). */ public void orNot(ImmutableRoaringBitmap other, long rangeEnd) { - if(other == this) { + if (other == this) { throw new UnsupportedOperationException("orNot between a bitmap and itself?"); } rangeSanityCheck(0, rangeEnd); - int maxKey = (int)((rangeEnd - 1) >>> 16); - int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int)(rangeEnd & 0xFFFF); + int maxKey = (int) ((rangeEnd - 1) >>> 16); + int lastRun = (rangeEnd & 0xFFFF) == 0 ? 0x10000 : (int) (rangeEnd & 0xFFFF); int size = 0; int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(), length2 = other.highLowContainer.size(); @@ -939,8 +1010,8 @@ public void orNot(ImmutableRoaringBitmap other, long rangeEnd) { int s2 = length2 > 0 ? other.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; int remainder = 0; for (int i = highLowContainer.size() - 1; - i >= 0 && highLowContainer.getKeyAtIndex(i) > maxKey; - --i) { + i >= 0 && highLowContainer.getKeyAtIndex(i) > maxKey; + --i) { ++remainder; } int correction = 0; @@ -952,8 +1023,7 @@ public void orNot(ImmutableRoaringBitmap other, long rangeEnd) { } // it's almost certain that the bitmap will grow, so make a conservative overestimate, // this avoids temporary allocation, and can trim afterwards - int maxSize = Math.min(maxKey + 1 + remainder - correction - + highLowContainer.size(), 0x10000); + int maxSize = Math.min(maxKey + 1 + remainder - correction + highLowContainer.size(), 0x10000); if (maxSize == 0) { return; } @@ -961,27 +1031,36 @@ public void orNot(ImmutableRoaringBitmap other, long rangeEnd) { MappeableContainer[] newValues = new MappeableContainer[maxSize]; for (int key = 0; key <= maxKey && size < maxSize; ++key) { if (key == s1 && key == s2) { // actually need to do an or not - newValues[size] = highLowContainer.getContainerAtIndex(pos1) - .iorNot(other.highLowContainer.getContainerAtIndex(pos2), - key == maxKey ? lastRun : 0x10000); + newValues[size] = + highLowContainer + .getContainerAtIndex(pos1) + .iorNot( + other.highLowContainer.getContainerAtIndex(pos2), + key == maxKey ? lastRun : 0x10000); ++pos1; ++pos2; s1 = pos1 < length1 ? highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; s2 = pos2 < length2 ? other.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else if (key == s1) { // or in a hole - newValues[size] = highLowContainer.getContainerAtIndex(pos1) - .ior(key == maxKey - ? MappeableRunContainer.rangeOfOnes(0, lastRun) - : MappeableRunContainer.full()); + newValues[size] = + key == maxKey + ? highLowContainer + .getContainerAtIndex(pos1) + .ior(MappeableRunContainer.rangeOfOnes(0, lastRun)) + : MappeableRunContainer.full(); ++pos1; s1 = pos1 < length1 ? highLowContainer.getKeyAtIndex(pos1) : maxKey + 1; } else if (key == s2) { // insert the complement - newValues[size] = other.highLowContainer.getContainerAtIndex(pos2) + newValues[size] = + other + .highLowContainer + .getContainerAtIndex(pos2) .not(0, key == maxKey ? lastRun : 0x10000); ++pos2; s2 = pos2 < length2 ? other.highLowContainer.getKeyAtIndex(pos2) : maxKey + 1; } else { // key missing from both - newValues[size] = key == maxKey + newValues[size] = + key == maxKey ? MappeableRunContainer.rangeOfOnes(0, lastRun) : MappeableRunContainer.full(); } @@ -989,25 +1068,30 @@ public void orNot(ImmutableRoaringBitmap other, long rangeEnd) { if (newValues[size].isEmpty()) { newValues[size] = null; } else { - newKeys[size] = (char)key; + newKeys[size] = (char) key; ++size; } } // copy over everything which will remain without being complemented if (remainder > 0) { - System.arraycopy(((MutableRoaringArray)highLowContainer).keys, - highLowContainer.size() - remainder, - newKeys, size, remainder); - System.arraycopy(((MutableRoaringArray)highLowContainer).values, - highLowContainer.size() - remainder, - newValues, size, remainder); - } - ((MutableRoaringArray)highLowContainer).keys = newKeys; - ((MutableRoaringArray)highLowContainer).values = newValues; - ((MutableRoaringArray)highLowContainer).size = size + remainder; + System.arraycopy( + ((MutableRoaringArray) highLowContainer).keys, + highLowContainer.size() - remainder, + newKeys, + size, + remainder); + System.arraycopy( + ((MutableRoaringArray) highLowContainer).values, + highLowContainer.size() - remainder, + newValues, + size, + remainder); + } + ((MutableRoaringArray) highLowContainer).keys = newKeys; + ((MutableRoaringArray) highLowContainer).values = newValues; + ((MutableRoaringArray) highLowContainer).size = size + remainder; } - /** * Add the value to the container (set the value to "true"), whether it already appears or not. * @@ -1019,15 +1103,26 @@ public boolean checkedAdd(final int x) { final int i = highLowContainer.getIndex(hb); if (i >= 0) { MappeableContainer C = highLowContainer.getContainerAtIndex(i); - int oldcard = C.getCardinality(); - C = C.add(BufferUtil.lowbits(x)); - getMappeableRoaringArray().setContainerAtIndex(i, C); - return C.getCardinality() > oldcard; + char lowX = BufferUtil.lowbits(x); + MappeableContainer newCont; + if (C instanceof MappeableRunContainer) { // do not compute cardinality + if (!C.contains(lowX)) { + newCont = C.add(lowX); + getMappeableRoaringArray().setContainerAtIndex(i, newCont); + return true; + } + } else { // it is faster to use getCardinality() than contains() for other container types + int oldCard = C.getCardinality(); + newCont = C.add(lowX); + getMappeableRoaringArray().setContainerAtIndex(i, newCont); + return newCont.getCardinality() > oldCard; + } } else { final MappeableArrayContainer newac = new MappeableArrayContainer(); getMappeableRoaringArray().insertNewKeyValueAt(-i - 1, hb, newac.add(BufferUtil.lowbits(x))); return true; } + return false; } /** @@ -1069,7 +1164,6 @@ public MutableRoaringBitmap clone() { final MutableRoaringBitmap x = (MutableRoaringBitmap) super.clone(); x.highLowContainer = highLowContainer.clone(); return x; - } /** @@ -1083,12 +1177,11 @@ public MutableRoaringBitmap clone() { public void deserialize(DataInput in) throws IOException { try { getMappeableRoaringArray().deserialize(in); - } catch(InvalidRoaringFormat cookie) { - throw cookie.toIOException();// we convert it to an IOException + } catch (InvalidRoaringFormat cookie) { + throw cookie.toIOException(); // we convert it to an IOException } } - /** * Deserialize (retrieve) this bitmap. * See format specification at https://github.com/RoaringBitmap/RoaringFormatSpec @@ -1110,8 +1203,8 @@ public void deserialize(DataInput in) throws IOException { public void deserialize(ByteBuffer buffer) throws IOException { try { getMappeableRoaringArray().deserialize(buffer); - } catch(InvalidRoaringFormat cookie) { - throw cookie.toIOException();// we convert it to an IOException + } catch (InvalidRoaringFormat cookie) { + throw cookie.toIOException(); // we convert it to an IOException } } @@ -1133,13 +1226,11 @@ public void flip(final int x) { } } else { final MappeableArrayContainer newac = new MappeableArrayContainer(); - ((MutableRoaringArray) highLowContainer).insertNewKeyValueAt(-i - 1, hb, - newac.add(BufferUtil.lowbits(x))); + ((MutableRoaringArray) highLowContainer) + .insertNewKeyValueAt(-i - 1, hb, newac.add(BufferUtil.lowbits(x))); } } - - /** * Modifies the current bitmap by complementing the bits in the given range, from rangeStart * (inclusive) rangeEnd (exclusive). @@ -1147,7 +1238,7 @@ public void flip(final int x) { * @param rangeStart inclusive beginning of range * @param rangeEnd exclusive ending of range */ - public void flip(final long rangeStart, final long rangeEnd) { + public void flip(final long rangeStart, final long rangeEnd) { rangeSanityCheck(rangeStart, rangeEnd); if (rangeStart >= rangeEnd) { return; // empty range @@ -1174,14 +1265,16 @@ public void flip(final long rangeStart, final long rangeEnd) { getMappeableRoaringArray().removeAtIndex(i); } } else { - getMappeableRoaringArray().insertNewKeyValueAt(-i - 1, (char) hb, - MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); + getMappeableRoaringArray() + .insertNewKeyValueAt( + -i - 1, + (char) hb, + MappeableContainer.rangeOfOnes(containerStart, containerLast + 1)); } } } - - /** + /** * Modifies the current bitmap by complementing the bits in the given range, from rangeStart * (inclusive) rangeEnd (exclusive). * @@ -1200,9 +1293,6 @@ public void flip(final int rangeStart, final int rangeEnd) { } } - - - /** * @return a mutable copy of this bitmap */ @@ -1233,8 +1323,8 @@ public boolean hasNext() { private Iterator init() { if (pos < MutableRoaringBitmap.this.highLowContainer.size()) { - iter = MutableRoaringBitmap.this.highLowContainer.getContainerAtIndex(pos) - .getCharIterator(); + iter = + MutableRoaringBitmap.this.highLowContainer.getContainerAtIndex(pos).getCharIterator(); hs = (MutableRoaringBitmap.this.highLowContainer.getKeyAtIndex(pos)) << 16; } return this; @@ -1252,28 +1342,34 @@ public Integer next() { @Override public void remove() { - // todo: implement + // todo: implement throw new UnsupportedOperationException(); } - }.init(); } // call repairAfterLazy on result, eventually // important: x2 should not have been computed lazily protected void lazyor(final ImmutableRoaringBitmap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - getMappeableRoaringArray().setContainerAtIndex(pos1, highLowContainer - .getContainerAtIndex(pos1).lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); + getMappeableRoaringArray() + .setContainerAtIndex( + pos1, + highLowContainer + .getContainerAtIndex(pos1) + .lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -1281,15 +1377,15 @@ protected void lazyor(final ImmutableRoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); } else { // s1 > s2 - getMappeableRoaringArray().insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + getMappeableRoaringArray() + .insertNewKeyValueAt(pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; @@ -1310,20 +1406,23 @@ protected void lazyor(final ImmutableRoaringBitmap x2) { // this method is like lazyor except that it will convert // the current container to a bitset protected void naivelazyor(final ImmutableRoaringBitmap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - MappeableBitmapContainer c1 = highLowContainer.getContainerAtIndex(pos1) - .toBitmapContainer(); - getMappeableRoaringArray().setContainerAtIndex(pos1, - c1.lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); + MappeableBitmapContainer c1 = + highLowContainer.getContainerAtIndex(pos1).toBitmapContainer(); + getMappeableRoaringArray() + .setContainerAtIndex(pos1, c1.lazyIOR(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -1331,15 +1430,15 @@ protected void naivelazyor(final ImmutableRoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); } else { // s1 > s2 - getMappeableRoaringArray().insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + getMappeableRoaringArray() + .insertNewKeyValueAt(pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; @@ -1355,27 +1454,31 @@ protected void naivelazyor(final ImmutableRoaringBitmap x2) { } } - - - /** * In-place bitwise OR (union) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void or(final ImmutableRoaringBitmap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } int pos1 = 0, pos2 = 0; int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - getMappeableRoaringArray().setContainerAtIndex(pos1, highLowContainer - .getContainerAtIndex(pos1).ior(x2.highLowContainer.getContainerAtIndex(pos2))); + getMappeableRoaringArray() + .setContainerAtIndex( + pos1, + highLowContainer + .getContainerAtIndex(pos1) + .ior(x2.highLowContainer.getContainerAtIndex(pos2))); pos1++; pos2++; if ((pos1 == length1) || (pos2 == length2)) { @@ -1383,15 +1486,15 @@ public void or(final ImmutableRoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); } else { // s1 > s2 - getMappeableRoaringArray().insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + getMappeableRoaringArray() + .insertNewKeyValueAt(pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; @@ -1407,15 +1510,11 @@ public void or(final ImmutableRoaringBitmap x2) { } } - - @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { getMappeableRoaringArray().readExternal(in); - } - /** * If present remove the specified integers (effectively, sets its bit value to false) * @@ -1428,8 +1527,9 @@ public void remove(final int x) { if (i < 0) { return; } - getMappeableRoaringArray().setContainerAtIndex(i, - highLowContainer.getContainerAtIndex(i).remove(BufferUtil.lowbits(x))); + getMappeableRoaringArray() + .setContainerAtIndex( + i, highLowContainer.getContainerAtIndex(i).remove(BufferUtil.lowbits(x))); if (highLowContainer.getContainerAtIndex(i).isEmpty()) { getMappeableRoaringArray().removeAtIndex(i); } @@ -1468,8 +1568,10 @@ public void remove(final long rangeStart, final long rangeEnd) { int ilast = highLowContainer.getIndex((char) hbLast); if (ifirst >= 0) { if (lbStart != 0) { - final MappeableContainer c = highLowContainer.getContainerAtIndex(ifirst).iremove(lbStart, - BufferUtil.maxLowBitAsInteger() + 1); + final MappeableContainer c = + highLowContainer + .getContainerAtIndex(ifirst) + .iremove(lbStart, BufferUtil.maxLowBitAsInteger() + 1); if (!c.isEmpty()) { ((MutableRoaringArray) highLowContainer).setContainerAtIndex(ifirst, c); ifirst++; @@ -1496,7 +1598,6 @@ public void remove(final long rangeStart, final long rangeEnd) { ((MutableRoaringArray) highLowContainer).removeIndexRange(ifirst, ilast); } - /** * Remove from the current bitmap all integers in [rangeStart,rangeEnd). * @@ -1514,7 +1615,6 @@ public void remove(final int rangeStart, final int rangeEnd) { remove(rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL); } - /** * Remove run-length encoding even when it is more space efficient * @@ -1542,7 +1642,6 @@ protected void repairAfterLazy() { } } - /** * Use a run-length encoding where it is estimated as more space efficient * @@ -1604,7 +1703,6 @@ public boolean runOptimize() { */ public ImmutableRoaringBitmap toImmutableRoaringBitmap() { return this; - } /** @@ -1620,15 +1718,13 @@ public void writeExternal(ObjectOutput out) throws IOException { getMappeableRoaringArray().writeExternal(out); } - - /** * In-place bitwise XOR (symmetric difference) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void xor(final ImmutableRoaringBitmap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -1636,14 +1732,17 @@ public void xor(final ImmutableRoaringBitmap x2) { int length1 = highLowContainer.size(); final int length2 = x2.highLowContainer.size(); - main: if (pos1 < length1 && pos2 < length2) { + main: + if (pos1 < length1 && pos2 < length2) { char s1 = highLowContainer.getKeyAtIndex(pos1); char s2 = x2.highLowContainer.getKeyAtIndex(pos2); while (true) { if (s1 == s2) { - final MappeableContainer c = highLowContainer.getContainerAtIndex(pos1) - .ixor(x2.highLowContainer.getContainerAtIndex(pos2)); + final MappeableContainer c = + highLowContainer + .getContainerAtIndex(pos1) + .ixor(x2.highLowContainer.getContainerAtIndex(pos2)); if (!c.isEmpty()) { this.getMappeableRoaringArray().setContainerAtIndex(pos1, c); pos1++; @@ -1657,15 +1756,15 @@ public void xor(final ImmutableRoaringBitmap x2) { } s1 = highLowContainer.getKeyAtIndex(pos1); s2 = x2.highLowContainer.getKeyAtIndex(pos2); - } else if (s1 < s2) { + } else if (s1 < s2) { pos1++; if (pos1 == length1) { break main; } s1 = highLowContainer.getKeyAtIndex(pos1); } else { // s1 > s2 - getMappeableRoaringArray().insertNewKeyValueAt(pos1, s2, - x2.highLowContainer.getContainerAtIndex(pos2).clone()); + getMappeableRoaringArray() + .insertNewKeyValueAt(pos1, s2, x2.highLowContainer.getContainerAtIndex(pos2).clone()); pos1++; length1++; pos2++; diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapPrivate.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapPrivate.java similarity index 100% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapPrivate.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapPrivate.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapSupplier.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapSupplier.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapSupplier.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapSupplier.java index 4222c24ea..c8d535ee0 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapSupplier.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/MutableRoaringBitmapSupplier.java @@ -9,7 +9,7 @@ /** * A {@link BitmapDataProviderSupplier} providing {@link MutableRoaringBitmap} as * {@link BitmapDataProvider} - * + * * @author Benoit Lacelle * */ @@ -19,5 +19,4 @@ public class MutableRoaringBitmapSupplier implements BitmapDataProviderSupplier public BitmapDataProvider newEmpty() { return new MutableRoaringBitmap(); } - } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/PointableRoaringArray.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/PointableRoaringArray.java similarity index 83% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/PointableRoaringArray.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/PointableRoaringArray.java index ce15da377..1e7164397 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/PointableRoaringArray.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/PointableRoaringArray.java @@ -10,7 +10,7 @@ /** * Generic interface for the array underlying roaring bitmap classes. - * + * */ public interface PointableRoaringArray extends Cloneable { /** @@ -26,7 +26,7 @@ public interface PointableRoaringArray extends Cloneable { /** * Create an independent copy of the underlying array - * + * * @return a copy */ PointableRoaringArray clone(); @@ -35,18 +35,17 @@ public interface PointableRoaringArray extends Cloneable { * This checks whether the container at index i has the value x. * This can be faster than calling "getContainerAtIndex" and then calling * contains. - * + * * @param i container index (assumed to be non-negative) * @param x 16-bit value to check * @return whether the container contains at index i contains x */ boolean containsForContainerAtIndex(int i, char x); - /** * Returns the cardinality of the container at the given index. This method is expected to be * fast. - * + * * @param i index * @return the cardinality */ @@ -54,14 +53,13 @@ public interface PointableRoaringArray extends Cloneable { /** * Obsolete method (retired because it forces us to create a new container). - * + * * @param x 16-bit key * @return matching container */ - //MappeableContainer getContainer(short x); + // MappeableContainer getContainer(short x); - - /** + /** * Returns either the index of the container corresponding to key x, or a negative value. * @param x 16-bit key * @return index of container (negative value if no container found) @@ -99,16 +97,16 @@ public interface PointableRoaringArray extends Cloneable { /** * Check whether this bitmap has had its runs compressed. - * + * * @return whether this bitmap has run compression */ boolean hasRunCompression(); /** * Serialize. - * + * * The current bitmap is not modified. - * + * * @param out the DataOutput stream * @throws IOException Signals that an I/O exception has occurred. */ @@ -128,21 +126,32 @@ public interface PointableRoaringArray extends Cloneable { */ int serializedSizeInBytes(); - /** * @return number of keys */ int size(); /** - * Gets the first value in the array - * @return te first value in the array + * Gets the smallest unsigned (first) integer in the array. + * @return the smallest unsigned (first) integer in the array */ int first(); /** - * Gets the last value in the array - * @return te last value in the array + * Gets the largest unsigned (last) integer in the array. + * @return the largest unsigned (last) integer in the array */ int last(); + + /** + * Gets the smallest signed integer in the array. + * @return the smallest signed integer in the array + */ + int firstSigned(); + + /** + * Gets the largest signed integer in the array. + * @return the largest signed integer in the array + */ + int lastSigned(); } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/RoaringBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/RoaringBatchIterator.java similarity index 87% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/RoaringBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/RoaringBatchIterator.java index bb03181ec..a5534c590 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/RoaringBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/RoaringBatchIterator.java @@ -20,9 +20,9 @@ public RoaringBatchIterator(MappeableContainerPointer containerPointer) { @Override public int nextBatch(int[] buffer) { int consumed = 0; - while (iterator != null && consumed == 0) { - consumed = iterator.next(key, buffer); - if (consumed == 0 || !iterator.hasNext()) { + while (iterator != null && consumed < buffer.length) { + consumed += iterator.next(key, buffer, consumed); + if (consumed < buffer.length || !iterator.hasNext()) { nextContainer(); } } @@ -50,7 +50,7 @@ public void advanceIfNeeded(int target) { @Override public BatchIterator clone() { try { - RoaringBatchIterator it = (RoaringBatchIterator)super.clone(); + RoaringBatchIterator it = (RoaringBatchIterator) super.clone(); if (null != iterator) { it.iterator = iterator.clone(); } @@ -79,11 +79,11 @@ private void nextIterator() { if (null != containerPointer && containerPointer.hasContainer()) { MappeableContainer container = containerPointer.getContainer(); if (container instanceof MappeableArrayContainer) { - nextIterator((MappeableArrayContainer)container); + nextIterator((MappeableArrayContainer) container); } else if (container instanceof MappeableBitmapContainer) { - nextIterator((MappeableBitmapContainer)container); + nextIterator((MappeableBitmapContainer) container); } else if (container instanceof MappeableRunContainer) { - nextIterator((MappeableRunContainer)container); + nextIterator((MappeableRunContainer) container); } key = containerPointer.key() << 16; } else { diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/RunBatchIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/RunBatchIterator.java similarity index 75% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/RunBatchIterator.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/RunBatchIterator.java index 1ba04f7ea..47fe31da6 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/RunBatchIterator.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/RunBatchIterator.java @@ -2,8 +2,6 @@ import org.roaringbitmap.ContainerBatchIterator; - - public final class RunBatchIterator implements ContainerBatchIterator { private MappeableRunContainer runs; @@ -15,16 +13,17 @@ public RunBatchIterator(MappeableRunContainer runs) { } @Override - public int next(int key, int[] buffer) { + public int next(int key, int[] buffer, int offset) { int consumed = 0; do { int runStart = (runs.getValue(run)); int runLength = (runs.getLength(run)); int chunkStart = runStart + cursor; - int chunkEnd = chunkStart + Math.min(runLength - cursor, buffer.length - consumed - 1); + int usableBufferLength = buffer.length - offset - consumed; + int chunkEnd = chunkStart + Math.min(runLength - cursor, usableBufferLength - 1); int chunk = chunkEnd - chunkStart + 1; for (int i = 0; i < chunk; ++i) { - buffer[consumed + i] = key + chunkStart + i; + buffer[offset + consumed + i] = key + chunkStart + i; } consumed += chunk; if (runStart + runLength == chunkEnd) { @@ -33,7 +32,7 @@ public int next(int key, int[] buffer) { } else { cursor += chunk; } - } while (consumed < buffer.length && run != runs.numberOfRuns()); + } while ((offset + consumed) < buffer.length && run != runs.numberOfRuns()); return consumed; } @@ -45,7 +44,7 @@ public boolean hasNext() { @Override public ContainerBatchIterator clone() { try { - return (ContainerBatchIterator)super.clone(); + return (ContainerBatchIterator) super.clone(); } catch (CloneNotSupportedException e) { // won't happen throw new IllegalStateException(e); @@ -62,14 +61,15 @@ public void advanceIfNeeded(char target) { do { int runStart = runs.getValue(run); int runLength = runs.getLength(run); - if (runStart <= target && runStart + runLength > target) { - cursor = target - runStart; - break; - } if (runStart > target) { cursor = 0; break; } + int offset = target - runStart; + if (offset <= runLength) { + cursor = offset; + break; + } ++run; cursor = 0; } while (run != runs.numberOfRuns()); diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/package-info.java b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/package-info.java similarity index 94% rename from RoaringBitmap/src/main/java/org/roaringbitmap/buffer/package-info.java rename to roaringbitmap/src/main/java/org/roaringbitmap/buffer/package-info.java index 0de419318..ddf38a6b1 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/buffer/package-info.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/buffer/package-info.java @@ -2,21 +2,19 @@ * (c) the authors Licensed under the Apache License, Version 2.0. */ - - /** * The org.roaringbitmap.buffer package provides - * two classes ({@link org.roaringbitmap.buffer.MutableRoaringBitmap} and + * two classes ({@link org.roaringbitmap.buffer.MutableRoaringBitmap} and * ({@link org.roaringbitmap.buffer.ImmutableRoaringBitmap}) that users * can rely upon for fast set of integers. * It differs from the org.roaringbitmap in that - * the backing stores are ByteBuffers. - * + * the backing stores are ByteBuffers. + * * Initially, one wants to construct a bitmap using * the MutableRoaringBitmap class. After serialization, * one can memory-map an ImmutableRoaringBitmap to the * serialized bytes, enabling off-heap processing. - * + * *
  * {@code
  *      import org.roaringbitmap.buffer.*;
@@ -25,7 +23,7 @@
  *
  *      MutableRoaringBitmap r1 = new MutableRoaringBitmap();
  *      for(int k = 4000; k<4255;++k) r1.add(k);
- *      
+ *
  *      MutableRoaringBitmap r2 = new MutableRoaringBitmap();
  *      for(int k = 1000; k<4255; k+=2) r2.add(k);
  *
@@ -41,4 +39,3 @@
  *
  */
 package org.roaringbitmap.buffer;
-
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/insights/BitmapAnalyser.java b/roaringbitmap/src/main/java/org/roaringbitmap/insights/BitmapAnalyser.java
similarity index 86%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/insights/BitmapAnalyser.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/insights/BitmapAnalyser.java
index 02a1a4e68..bf1366c89 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/insights/BitmapAnalyser.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/insights/BitmapAnalyser.java
@@ -40,11 +40,10 @@ public static BitmapStatistics analyse(RoaringBitmap r) {
    * @return the statistics
    */
   public static BitmapStatistics analyse(Collection bitmaps) {
-    return bitmaps
-      .stream()
-      .reduce(
-        BitmapStatistics.empty,
-        (acc, r) -> acc.merge(BitmapAnalyser.analyse(r)),
-        BitmapStatistics::merge);
+    return bitmaps.stream()
+        .reduce(
+            BitmapStatistics.empty,
+            (acc, r) -> acc.merge(BitmapAnalyser.analyse(r)),
+            BitmapStatistics::merge);
   }
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/insights/BitmapStatistics.java b/roaringbitmap/src/main/java/org/roaringbitmap/insights/BitmapStatistics.java
similarity index 75%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/insights/BitmapStatistics.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/insights/BitmapStatistics.java
index 4bb08532c..b41aec6f8 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/insights/BitmapStatistics.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/insights/BitmapStatistics.java
@@ -28,7 +28,6 @@ public class BitmapStatistics {
     this.bitmapsCount = bitmapsCount;
   }
 
-
   /**
    * Calculates what fraction of all containers is the `containerTypeCount`
    * @param containerTypeCount denominator
@@ -49,11 +48,15 @@ public ArrayContainersStats getArrayContainersStats() {
   @Override
   public String toString() {
     return "BitmapStatistics{"
-      + "bitmapsCount=" + bitmapsCount
-      + ", arrayContainersStats=" + arrayContainersStats
-      + ", bitmapContainerCount=" + bitmapContainerCount
-      + ", runContainerCount=" + runContainerCount
-      + '}';
+        + "bitmapsCount="
+        + bitmapsCount
+        + ", arrayContainersStats="
+        + arrayContainersStats
+        + ", bitmapContainerCount="
+        + bitmapContainerCount
+        + ", runContainerCount="
+        + runContainerCount
+        + '}';
   }
 
   public long containerCount() {
@@ -62,14 +65,14 @@ public long containerCount() {
 
   BitmapStatistics merge(BitmapStatistics other) {
     return new BitmapStatistics(
-      arrayContainersStats.merge(other.arrayContainersStats),
-      bitmapContainerCount + other.bitmapContainerCount,
-      runContainerCount + other.runContainerCount,
-      bitmapsCount + other.bitmapsCount);
+        arrayContainersStats.merge(other.arrayContainersStats),
+        bitmapContainerCount + other.bitmapContainerCount,
+        runContainerCount + other.runContainerCount,
+        bitmapsCount + other.bitmapsCount);
   }
 
-  public final static BitmapStatistics empty = new BitmapStatistics(
-      ArrayContainersStats.empty, 0, 0, 0);
+  public static final BitmapStatistics empty =
+      new BitmapStatistics(ArrayContainersStats.empty, 0, 0, 0);
 
   @Override
   public boolean equals(Object o) {
@@ -81,9 +84,9 @@ public boolean equals(Object o) {
     }
     BitmapStatistics that = (BitmapStatistics) o;
     return bitmapsCount == that.bitmapsCount
-      && bitmapContainerCount == that.bitmapContainerCount
-      && runContainerCount == that.runContainerCount
-      && Objects.equals(arrayContainersStats, that.arrayContainersStats);
+        && bitmapContainerCount == that.bitmapContainerCount
+        && runContainerCount == that.runContainerCount
+        && Objects.equals(arrayContainersStats, that.arrayContainersStats);
   }
 
   @Override
@@ -123,8 +126,7 @@ public long getCardinalitySum() {
 
     ArrayContainersStats merge(ArrayContainersStats other) {
       return new ArrayContainersStats(
-        containersCount + other.containersCount,
-        cardinalitySum + other.cardinalitySum);
+          containersCount + other.containersCount, cardinalitySum + other.cardinalitySum);
     }
 
     /**
@@ -139,7 +141,6 @@ public long averageCardinality() {
       }
     }
 
-
     @Override
     public boolean equals(Object o) {
       if (this == o) {
@@ -149,8 +150,7 @@ public boolean equals(Object o) {
         return false;
       }
       ArrayContainersStats that = (ArrayContainersStats) o;
-      return containersCount == that.containersCount
-        && cardinalitySum == that.cardinalitySum;
+      return containersCount == that.containersCount && cardinalitySum == that.cardinalitySum;
     }
 
     @Override
@@ -161,13 +161,13 @@ public int hashCode() {
     @Override
     public String toString() {
       return "ArrayContainersStats{"
-        + "containersCount=" + containersCount
-        + ", cardinalitySum=" + cardinalitySum
-        + '}';
+          + "containersCount="
+          + containersCount
+          + ", cardinalitySum="
+          + cardinalitySum
+          + '}';
     }
 
-    public final static ArrayContainersStats empty = new ArrayContainersStats(0, 0);
+    public static final ArrayContainersStats empty = new ArrayContainersStats(0, 0);
   }
-
-
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/insights/NaiveWriterRecommender.java b/roaringbitmap/src/main/java/org/roaringbitmap/insights/NaiveWriterRecommender.java
similarity index 73%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/insights/NaiveWriterRecommender.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/insights/NaiveWriterRecommender.java
index 5b04dc4f7..8f2829910 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/insights/NaiveWriterRecommender.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/insights/NaiveWriterRecommender.java
@@ -34,55 +34,51 @@ public static String recommend(BitmapStatistics s) {
   }
 
   private static void denseArrayWarning(StringBuilder sb) {
-    sb
-      .append("Most of your containers are array containers, ")
-      .append("but with quite significant cardinality.\n")
-      .append("It should be better to start with .constantMemory() ")
+    sb.append("Most of your containers are array containers, ")
+        .append("but with quite significant cardinality.\n")
+        .append("It should be better to start with .constantMemory() ")
         .append("that can scale down to ArrayContainer anyway.");
   }
 
   private static void runContainerRecommendations(StringBuilder sb) {
-    sb
-      .append(".optimiseForRuns(), because over ")
-      .append(RunContainersDomination)
-      .append(" containers are of type RunContainer.\n")
-      .append("Make sure to try .constantMemory()")
+    sb.append(".optimiseForRuns(), because over ")
+        .append(RunContainersDomination)
+        .append(" containers are of type RunContainer.\n")
+        .append("Make sure to try .constantMemory()")
         .append("as inserting to RunContainers might not be that efficient.");
   }
 
   private static void constantMemoryRecommendation(BitmapStatistics s, StringBuilder sb) {
     long buffersSizeBytes = s.getBitmapsCount() * Long.BYTES * 1024L;
     long bufferSizeMiB = buffersSizeBytes / (1024 * 1024);
-    sb
-      .append(".constantMemory() is sensible default for most use cases.\n")
-      .append("Be prepared to allocate on heap ")
-      .append(bufferSizeMiB)
+    sb.append(".constantMemory() is sensible default for most use cases.\n")
+        .append("Be prepared to allocate on heap ")
+        .append(bufferSizeMiB)
         .append(" [MiB] just for buffers if you have them open at the same time.");
   }
 
   private static void arrayContainerRecommendations(BitmapStatistics s, StringBuilder sb) {
     double acFraction = s.containerFraction(s.getArrayContainersStats().getContainersCount());
     sb.append(".optimiseForArrays(), because fraction of ArrayContainers ")
-      .append(acFraction)
-      .append(" is over arbitrary threshold ")
-      .append(ArrayContainersDomination)
-      .append("\n")
-      .append(".expectedContainerSize(")
-      .append(s.getArrayContainersStats().averageCardinality())
+        .append(acFraction)
+        .append(" is over arbitrary threshold ")
+        .append(ArrayContainersDomination)
+        .append("\n")
+        .append(".expectedContainerSize(")
+        .append(s.getArrayContainersStats().averageCardinality())
         .append(") to preallocate array containers for average number of elements.\n");
   }
 
   private static void containerCountRecommendations(BitmapStatistics basedOn, StringBuilder sb) {
     long averageContainersCount = basedOn.containerCount() / basedOn.getBitmapsCount();
     sb.append(".initialCapacity(")
-      .append(averageContainersCount)
-      .append("), because on average each bitmap has ")
-      .append(averageContainersCount)
+        .append(averageContainersCount)
+        .append("), because on average each bitmap has ")
+        .append(averageContainersCount)
         .append(" containers.\n");
   }
 
   private static double ArrayContainersDomination = 0.75;
   private static int WorthUsingArraysCardinalityThreshold = 4096 / 2;
   private static double RunContainersDomination = 0.8;
-
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/ContainerWithIndex.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/ContainerWithIndex.java
similarity index 100%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/ContainerWithIndex.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/ContainerWithIndex.java
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/HighLowContainer.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/HighLowContainer.java
similarity index 85%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/HighLowContainer.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/HighLowContainer.java
index ad7e0ee62..f6d2cd241 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/HighLowContainer.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/HighLowContainer.java
@@ -2,15 +2,21 @@
 
 import static java.nio.ByteOrder.LITTLE_ENDIAN;
 
+import org.roaringbitmap.Container;
+import org.roaringbitmap.art.Art;
+import org.roaringbitmap.art.ContainerIterator;
+import org.roaringbitmap.art.Containers;
+import org.roaringbitmap.art.KeyIterator;
+import org.roaringbitmap.art.LeafNode;
+import org.roaringbitmap.art.LeafNodeIterator;
+import org.roaringbitmap.art.Node;
+
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.NoSuchElementException;
 
-import org.roaringbitmap.Container;
-import org.roaringbitmap.art.*;
-
 public class HighLowContainer {
 
   private Art art;
@@ -109,7 +115,7 @@ public boolean isEmpty() {
   }
 
   private void assertNonEmpty() {
-    if(isEmpty()) {
+    if (isEmpty()) {
       throw new NoSuchElementException("Empty " + this.getClass().getSimpleName());
     }
   }
@@ -130,7 +136,6 @@ public long first() {
     return LongUtils.toLong(high, low);
   }
 
-
   /**
    * Gets the last value in the array
    * @return the last value in the array
@@ -147,16 +152,42 @@ public long last() {
     return LongUtils.toLong(high, low);
   }
 
+  /**
+   * Compares two unsigned byte arrays for order.
+   * Result is a negative integer, zero, or a positive integer
+   * as the first array is less than, equal to, or greater than the second.
+   * @return result of comparing
+   */
+  public static int compareUnsigned(byte[] a, byte[] b) {
+    if (a == null) {
+      return b == null ? 0 : 1;
+    }
+    if (b == null) {
+      return -1;
+    }
+    for (int i = 0; i < Math.min(a.length, b.length); i++) {
+      int aVal = a[i] & 0xff;
+      int bVal = b[i] & 0xff;
+      if (aVal != bVal) {
+        return Integer.compare(aVal, bVal);
+      }
+    }
+    return Integer.compare(a.length, b.length);
+  }
+
   /**
    * serialize into the ByteBuffer in little endian
    * @param buffer the ByteBuffer should be large enough to hold the data
    * @throws IOException indicate exception happened
    */
   public void serialize(ByteBuffer buffer) throws IOException {
-    ByteBuffer byteBuffer = buffer.order() == LITTLE_ENDIAN ? buffer
-        : buffer.slice().order(LITTLE_ENDIAN);
+    ByteBuffer byteBuffer =
+        buffer.order() == LITTLE_ENDIAN ? buffer : buffer.slice().order(LITTLE_ENDIAN);
     if (art.isEmpty()) {
       byteBuffer.put(EMPTY_TAG);
+      if (byteBuffer != buffer) {
+        buffer.position(buffer.position() + byteBuffer.position());
+      }
       return;
     } else {
       byteBuffer.put(NOT_EMPTY_TAG);
@@ -174,8 +205,8 @@ public void serialize(ByteBuffer buffer) throws IOException {
    * @throws IOException indicate exception happened
    */
   public void deserialize(ByteBuffer buffer) throws IOException {
-    ByteBuffer byteBuffer = buffer.order() == LITTLE_ENDIAN ? buffer
-        : buffer.slice().order(LITTLE_ENDIAN);
+    ByteBuffer byteBuffer =
+        buffer.order() == LITTLE_ENDIAN ? buffer : buffer.slice().order(LITTLE_ENDIAN);
     clear();
     byte emptyTag = byteBuffer.get();
     if (emptyTag == EMPTY_TAG) {
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/ImmutableLongBitmapDataProvider.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/ImmutableLongBitmapDataProvider.java
similarity index 91%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/ImmutableLongBitmapDataProvider.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/ImmutableLongBitmapDataProvider.java
index f6329e83d..20047d57c 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/ImmutableLongBitmapDataProvider.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/ImmutableLongBitmapDataProvider.java
@@ -37,9 +37,9 @@ public interface ImmutableLongBitmapDataProvider {
 
   /**
    * Visit all values in the bitmap and pass them to the consumer.
-   * 
+   *
    * * Usage:
-   * 
+   *
    * 
    * {@code
    *  bitmap.forEach(new LongConsumer() {
@@ -47,19 +47,19 @@ public interface ImmutableLongBitmapDataProvider {
    *    {@literal @}Override
    *    public void accept(long value) {
    *      // do something here
-   *      
+   *
    *    }});
    *   }
    * }
    * 
- * + * * @param lc the consumer */ void forEach(LongConsumer lc); /** * For better performance, consider the Use the {@link #forEach forEach} method. - * + * * @return a custom iterator over set bits, the bits are traversed in ascending sorted order */ // RoaringBitmap proposes a PeekableLongIterator @@ -75,10 +75,11 @@ public interface ImmutableLongBitmapDataProvider { * @return an Ordered, Distinct, Sorted and Sized IntStream in ascending order */ default LongStream stream() { - int characteristics = Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED - | Spliterator.SIZED; - Spliterator.OfLong x = Spliterators.spliterator(new RoaringOfLong(getLongIterator()), - getLongCardinality(), characteristics); + int characteristics = + Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.SIZED; + Spliterator.OfLong x = + Spliterators.spliterator( + new RoaringOfLong(getLongIterator()), getLongCardinality(), characteristics); return StreamSupport.longStream(x, false); } @@ -87,13 +88,15 @@ default LongStream stream() { */ default LongStream reverseStream() { int characteristics = Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SIZED; - Spliterator.OfLong x = Spliterators.spliterator(new RoaringOfLong(getLongIterator()), - getLongCardinality(), characteristics); + Spliterator.OfLong x = + Spliterators.spliterator( + new RoaringOfLong(getLongIterator()), getLongCardinality(), characteristics); return StreamSupport.longStream(x, false); } + /** * Estimate of the memory usage of this data structure. - * + * * Internally, this is computed as a 64-bit counter. * * @return estimated memory usage. @@ -125,9 +128,9 @@ default LongStream reverseStream() { /** * Rank returns the number of integers that are smaller or equal to x (Rank(infinity) would be * GetCardinality()). - * + * * The value is a full 64-bit value. - * + * * @param x upper limit * * @return the rank @@ -185,7 +188,7 @@ default LongStream reverseStream() { */ long[] toArray(); - /** + /** * An internal class to help provide streams. * Sad but true the interface of LongIterator and PrimitiveIterator.OfLong * Does not match. Otherwise it would be easier to just make LongIterator diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/IntegerUtil.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/IntegerUtil.java similarity index 100% rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/IntegerUtil.java rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/IntegerUtil.java diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongBitmapDataProvider.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongBitmapDataProvider.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongBitmapDataProvider.java rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongBitmapDataProvider.java index e22105b4b..d3a34ee0e 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongBitmapDataProvider.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongBitmapDataProvider.java @@ -23,7 +23,6 @@ public interface LongBitmapDataProvider extends ImmutableLongBitmapDataProvider */ void removeLong(long x); - /** * Recover allocated but unused memory. */ diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongConsumer.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongConsumer.java similarity index 95% rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongConsumer.java rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongConsumer.java index 4945f348a..a1b14a160 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongConsumer.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongConsumer.java @@ -6,16 +6,16 @@ /** * An LongConsumer receives the long values contained in a data structure. Each value is visited * once. - * + * * Usage: - * + * *
  * {@code
  *  bitmap.forEach(new LongConsumer() {
  *
  *    public void accept(long value) {
  *      // do something here
- *      
+ *
  *    }});
  *   }
  * }
@@ -24,7 +24,7 @@
 public interface LongConsumer {
   /**
    * Receives the long
-   * 
+   *
    * @param value the long value
    */
   void accept(long value);
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongConsumerRelativeRangeAdapter.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongConsumerRelativeRangeAdapter.java
similarity index 100%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongConsumerRelativeRangeAdapter.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongConsumerRelativeRangeAdapter.java
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongIterator.java
similarity index 98%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongIterator.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongIterator.java
index 9db3ad6cb..f7a172edd 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongIterator.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongIterator.java
@@ -11,7 +11,7 @@
 public interface LongIterator extends Cloneable {
   /**
    * Creates a copy of the iterator.
-   * 
+   *
    * @return a clone of the current iterator
    */
   LongIterator clone();
@@ -25,5 +25,4 @@ public interface LongIterator extends Cloneable {
    * @return next long value
    */
   long next();
-
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongUtils.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongUtils.java
similarity index 66%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongUtils.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongUtils.java
index 7de7234af..bdfc513fe 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/LongUtils.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/LongUtils.java
@@ -11,15 +11,14 @@ public class LongUtils {
    * @return the high 48 bit
    */
   public static byte[] highPart(long num) {
-    byte[] high48 = new byte[]{
-        (byte) ((num >>> 56) & 0xff),
-        (byte) ((num >>> 48) & 0xff),
-        (byte) ((num >>> 40) & 0xff),
-        (byte) ((num >>> 32) & 0xff),
-        (byte) ((num >>> 24) & 0xff),
-        (byte) ((num >>> 16) & 0xff)
+    return new byte[] {
+      (byte) ((num >>> 56) & 0xff),
+      (byte) ((num >>> 48) & 0xff),
+      (byte) ((num >>> 40) & 0xff),
+      (byte) ((num >>> 32) & 0xff),
+      (byte) ((num >>> 24) & 0xff),
+      (byte) ((num >>> 16) & 0xff)
     };
-    return high48;
   }
 
   /**
@@ -40,16 +39,26 @@ public static char lowPart(long num) {
    * @return the long data
    */
   public static long toLong(byte[] high, char low) {
-    byte byte6 = (byte) (low >>> 8 & 0xFFL);
-    byte byte7 = (byte) low;
-    return (high[0] & 0xFFL) << 56
-        | (high[1] & 0xFFL) << 48
-        | (high[2] & 0xFFL) << 40
-        | (high[3] & 0xFFL) << 32
-        | (high[4] & 0xFFL) << 24
-        | (high[5] & 0xFFL) << 16
-        | (byte6 & 0xFFL) << 8
-        | (byte7 & 0xFFL);
+    return toLong(high) << 16 | low;
+  }
+
+  /**
+   * Reconstruct the long data.
+   *
+   * @param high the high 48 bit
+   * @return the long data
+   */
+  public static long toLong(byte[] high) {
+    return (high[0] & 0xFFL) << 40
+        | (high[1] & 0xFFL) << 32
+        | (high[2] & 0xFFL) << 24
+        | (high[3] & 0xFFL) << 16
+        | (high[4] & 0xFFL) << 8
+        | (high[5] & 0xFFL);
+  }
+
+  public static long toLong(long high, char low) {
+    return high << 16 | low;
   }
 
   /**
@@ -88,36 +97,6 @@ public static long fromBDBytes(byte[] work) {
         | (long) (work[7] & 0xff);
   }
 
-  /**
-   * compare according to the dictionary order
-   *
-   * @param a a byte array
-   * @param b another byte array
-   * @return 1 indicates a greater than b,0 indicates equal,-1 indicates a smaller than b
-   */
-  public static int compareHigh(byte[] a, byte[] b) {
-    return compareTo(a, 0, a.length, b, 0, b.length);
-  }
-
-  private static int compareTo(byte[] buffer1, int offset1, int length1,
-      byte[] buffer2, int offset2, int length2) {
-    if (buffer1 == buffer2
-        && offset1 == offset2
-        && length1 == length2) {
-      return 0;
-    }
-    int end1 = offset1 + length1;
-    int end2 = offset2 + length2;
-    for (int i = offset1, j = offset2; i < end1 && j < end2; i++, j++) {
-      int a = (buffer1[i] & 0xff);
-      int b = (buffer2[j] & 0xff);
-      if (a != b) {
-        return a - b;
-      }
-    }
-    return length1 - length2;
-  }
-
   /**
    * initialize a long value with the given fist 32 bit
    *
@@ -171,15 +150,10 @@ public static byte[] highPartInPlace(long num, byte[] high48) {
    * checks if given high48 is the maximum possible one
    * (e.g. it is the case for -1L, which is the maximum unsigned long)
    *
-   * @param high48 the byte array
+   * @param key long
    * @return true if this the maximum high part
    */
-  public static boolean isMaxHigh(byte[] high48) {
-    return high48[0] == -1
-            && high48[1] == -1
-            && high48[2] == -1
-            && high48[3] == -1
-            && high48[4] == -1
-            && high48[5] == -1;
+  public static boolean isMaxHigh(long key) {
+    return (key & 0xFF_FF_FF_FF_FF_FFL) == 0xFF_FF_FF_FF_FF_FFL;
   }
 }
diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/PeekableLongIterator.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/PeekableLongIterator.java
similarity index 91%
rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/PeekableLongIterator.java
rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/PeekableLongIterator.java
index 076e2cefd..84293f272 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/PeekableLongIterator.java
+++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/PeekableLongIterator.java
@@ -3,9 +3,8 @@
  */
 package org.roaringbitmap.longlong;
 
-
 /**
- * Simple extension to the IntIterator interface. 
+ * Simple extension to the IntIterator interface.
  * It allows you to "skip" values using the advanceIfNeeded
  * method, and to look at the value without advancing (peekNext).
  *
@@ -14,19 +13,19 @@
  */
 public interface PeekableLongIterator extends LongIterator {
   /**
-   * If needed, 
-   * 
-   * for a forwards iterator 
+   * If needed,
+   *
+   * for a forwards iterator
    * advance as long as the next value is smaller than thresholdVal
-   * 
-   * For a reverse iterator 
+   *
+   * For a reverse iterator
    * advance as long as the next value is greater than thresholdVal
    *
    *  The advanceIfNeeded method is used for performance reasons, to skip
    *  over unnecessary repeated calls to next.
-   *  
+   *
    *  Suppose for example that you wish to compute the intersection between
-   *  an ordered list of longs (e.g., longs[] x = {1,4,5}) and a 
+   *  an ordered list of longs (e.g., longs[] x = {1,4,5}) and a
    *  PeekableIntIterator.
    *  You might do it as follows...
    *     

@@ -42,24 +41,24 @@ public interface PeekableLongIterator extends LongIterator {
    *       j.advanceIfNeeded(val);
    *     }
    *     
- * - * The benefit of calling advanceIfNeeded is that each such call + * + * The benefit of calling advanceIfNeeded is that each such call * can be much faster than repeated calls to "next". The underlying * implementation can "skip" over some data. - * - * + * + * * @param thresholdVal threshold */ public void advanceIfNeeded(long thresholdVal); /** - * + * * Look at the next value without advancing - * + * * The peek is useful when working with several iterators at once. * Suppose that you have 100 iterators, and you want to compute * their intersections without materializing the result. - * You might do it as follows... + * You might do it as follows... *

    *    PriorityQueue pq = new PriorityQueue(100,
    *      new Comparator<PeekableIntIterator>() {
@@ -68,9 +67,9 @@ public interface PeekableLongIterator extends LongIterator {
    *                 return a.peek() - b.peek();
    *             }
    *         });
-   * 
+   *
    *    //...  populate pq
-   *    
+   *
    *    while(! pq.isEmpty() ) {
    *      // get iterator with a smallest value
    *      PeekableLongIterator pi = pq.poll();
@@ -79,21 +78,19 @@ public interface PeekableLongIterator extends LongIterator {
    *      if(pi.hasNext()) pq.add(pi)
    *    }
    *    
- * + * * Notice how the peek method allows you to compare iterators in a way * that the next method could not do. - * + * * @return next value */ public long peekNext(); /** * Creates a copy of the iterator. - * + * * @return a clone of the current iterator */ @Override PeekableLongIterator clone(); } - - diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/Roaring64Bitmap.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/Roaring64Bitmap.java similarity index 73% rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/Roaring64Bitmap.java rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/Roaring64Bitmap.java index c9d1c612d..92d6fda6c 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/Roaring64Bitmap.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/Roaring64Bitmap.java @@ -1,5 +1,17 @@ package org.roaringbitmap.longlong; +import org.roaringbitmap.ArrayContainer; +import org.roaringbitmap.BitmapContainer; +import org.roaringbitmap.Container; +import org.roaringbitmap.PeekableCharIterator; +import org.roaringbitmap.RelativeRangeConsumer; +import org.roaringbitmap.RunContainer; +import org.roaringbitmap.Util; +import org.roaringbitmap.art.ContainerIterator; +import org.roaringbitmap.art.KeyIterator; +import org.roaringbitmap.art.LeafNode; +import org.roaringbitmap.art.LeafNodeIterator; + import java.io.DataInput; import java.io.DataOutput; import java.io.Externalizable; @@ -13,12 +25,6 @@ import java.util.NoSuchElementException; import java.util.Objects; -import org.roaringbitmap.*; -import org.roaringbitmap.art.ContainerIterator; -import org.roaringbitmap.art.KeyIterator; -import org.roaringbitmap.art.LeafNode; -import org.roaringbitmap.art.LeafNodeIterator; - /** * Roaring64Bitmap is a compressed 64 bit bitmap. It can contain all the numbers of long * rang[Long.MAX_VALUE, Long.MIN_VALUE]. Since java has no unsigned long,we treat the negative value @@ -208,12 +214,12 @@ public void forAllInRange(long start, int length, final RelativeRangeConsumer rr return; // nothing else to do } final long end = start + length; - final byte[] endHigh = LongUtils.highPart(end); + final long endHigh = LongUtils.rightShiftHighPart(end); long filledUntil = start; LeafNode node = leafIterator.next(); - byte[] high = node.getKeyBytes(); - while (LongUtils.compareHigh(high, endHigh) <= 0) { + long high = node.getKey(); + while (high <= endHigh) { // fill missing values until start of container long containerStart = LongUtils.toLong(high, (char) 0); if (filledUntil < containerStart) { @@ -233,17 +239,14 @@ public void forAllInRange(long start, int length, final RelativeRangeConsumer rr // Only part of the container is in range char containerRangeStart = LongUtils.lowPart(start); char containerRangeEnd = LongUtils.lowPart(end); - container.forAllInRange( - LongUtils.lowPart(start), - LongUtils.lowPart(end), - rrc); + container.forAllInRange(LongUtils.lowPart(start), LongUtils.lowPart(end), rrc); filledUntil += containerRangeEnd - containerRangeStart; - } else if (startInContainer) {// && !endInContainer + } else if (startInContainer) { // && !endInContainer // range begins within the container char containerRangeStart = LongUtils.lowPart(start); container.forAllFrom(containerRangeStart, rrc); filledUntil += BitmapContainer.MAX_CAPACITY - containerRangeStart; - } else if (endInContainer) {// && !startInContainer + } else if (endInContainer) { // && !startInContainer // range end within the container char containerRangeEnd = LongUtils.lowPart(end); container.forAllUntil(containerRangeStartOffset, containerRangeEnd, rrc); @@ -254,7 +257,7 @@ public void forAllInRange(long start, int length, final RelativeRangeConsumer rr } if (leafIterator.hasNext()) { node = leafIterator.next(); - high = node.getKeyBytes(); + high = node.getKey(); } else { break; } @@ -279,15 +282,15 @@ public void forEachInRange(long start, int length, final LongConsumer lc) { @Override public long rankLong(long id) { long result = 0; - byte[] high = LongUtils.highPart(id); + long high = LongUtils.rightShiftHighPart(id); + byte[] highBytes = LongUtils.highPart(id); char low = LongUtils.lowPart(id); - ContainerWithIndex containerWithIndex = highLowContainer.searchContainer(high); + ContainerWithIndex containerWithIndex = highLowContainer.searchContainer(highBytes); KeyIterator keyIterator = highLowContainer.highKeyIterator(); if (containerWithIndex == null) { while (keyIterator.hasNext()) { - byte[] highKey = keyIterator.next(); - int res = LongUtils.compareHigh(highKey, high); - if (res > 0) { + long highKey = keyIterator.nextKey(); + if (highKey > high) { break; } else { long containerIdx = keyIterator.currentContainerIdx(); @@ -297,10 +300,10 @@ public long rankLong(long id) { } } else { while (keyIterator.hasNext()) { - byte[] key = keyIterator.next(); + long key = keyIterator.nextKey(); long containerIdx = keyIterator.currentContainerIdx(); Container container = highLowContainer.getContainer(containerIdx); - if (LongUtils.compareHigh(key, high) == 0) { + if (key == high) { result += container.rank(low); break; } else { @@ -317,7 +320,9 @@ public long rankLong(long id) { * @param x2 other bitmap */ public void or(final Roaring64Bitmap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } KeyIterator highIte2 = x2.highLowContainer.highKeyIterator(); while (highIte2.hasNext()) { byte[] high = highIte2.next(); @@ -334,13 +339,63 @@ public void or(final Roaring64Bitmap x2) { } } + /** + * Bitwise OR (union) operation. The provided bitmaps are *not* modified. This operation is + * thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return result of the operation + */ + public static Roaring64Bitmap or(final Roaring64Bitmap x1, final Roaring64Bitmap x2) { + Roaring64Bitmap result = new Roaring64Bitmap(); + KeyIterator it1 = x1.highLowContainer.highKeyIterator(); + KeyIterator it2 = x2.highLowContainer.highKeyIterator(); + + byte[] highKey1 = null, highKey2 = null; + if (it1.hasNext()) { + highKey1 = it1.next(); + } + if (it2.hasNext()) { + highKey2 = it2.next(); + } + + while (highKey1 != null || highKey2 != null) { + int compare = HighLowContainer.compareUnsigned(highKey1, highKey2); + if (compare == 0) { + long containerIdx1 = it1.currentContainerIdx(); + long containerIdx2 = it2.currentContainerIdx(); + Container container1 = x1.highLowContainer.getContainer(containerIdx1); + Container container2 = x2.highLowContainer.getContainer(containerIdx2); + Container orResult = container1.or(container2); + result.highLowContainer.put(highKey1, orResult); + + highKey1 = it1.hasNext() ? it1.next() : null; + highKey2 = it2.hasNext() ? it2.next() : null; + } else if (compare < 0) { + long containerIdx1 = it1.currentContainerIdx(); + Container container1 = x1.highLowContainer.getContainer(containerIdx1); + result.highLowContainer.put(highKey1, container1.clone()); + + highKey1 = it1.hasNext() ? it1.next() : null; + } else { + long containerIdx2 = it2.currentContainerIdx(); + Container container2 = x2.highLowContainer.getContainer(containerIdx2); + result.highLowContainer.put(highKey2, container2.clone()); + + highKey2 = it2.hasNext() ? it2.next() : null; + } + } + return result; + } + /** * In-place bitwise XOR (symmetric difference) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void xor(final Roaring64Bitmap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -360,13 +415,65 @@ public void xor(final Roaring64Bitmap x2) { } } + /** + * Bitwise XOR (symmetric difference) operation. The provided bitmaps are *not* modified. This + * operation is thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return result of the operation + */ + public static Roaring64Bitmap xor(final Roaring64Bitmap x1, final Roaring64Bitmap x2) { + Roaring64Bitmap result = new Roaring64Bitmap(); + KeyIterator it1 = x1.highLowContainer.highKeyIterator(); + KeyIterator it2 = x2.highLowContainer.highKeyIterator(); + + byte[] highKey1 = null, highKey2 = null; + if (it1.hasNext()) { + highKey1 = it1.next(); + } + if (it2.hasNext()) { + highKey2 = it2.next(); + } + + while (highKey1 != null || highKey2 != null) { + int compare = HighLowContainer.compareUnsigned(highKey1, highKey2); + if (compare == 0) { + long containerIdx1 = it1.currentContainerIdx(); + long containerIdx2 = it2.currentContainerIdx(); + Container container1 = x1.highLowContainer.getContainer(containerIdx1); + Container container2 = x2.highLowContainer.getContainer(containerIdx2); + Container xorResult = container1.xor(container2); + result.highLowContainer.put(highKey1, xorResult); + + highKey1 = it1.hasNext() ? it1.next() : null; + highKey2 = it2.hasNext() ? it2.next() : null; + } else if (compare < 0) { + long containerIdx1 = it1.currentContainerIdx(); + Container container1 = x1.highLowContainer.getContainer(containerIdx1); + result.highLowContainer.put(highKey1, container1.clone()); + + highKey1 = it1.hasNext() ? it1.next() : null; + } else { + long containerIdx2 = it2.currentContainerIdx(); + Container container2 = x2.highLowContainer.getContainer(containerIdx2); + result.highLowContainer.put(highKey2, container2.clone()); + + highKey2 = it2.hasNext() ? it2.next() : null; + } + } + return result; + } + /** * In-place bitwise AND (intersection) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void and(final Roaring64Bitmap x2) { - if(x2 == this) { return; } + if (x2 == this) { + return; + } KeyIterator thisIterator = highLowContainer.highKeyIterator(); while (thisIterator.hasNext()) { byte[] highKey = thisIterator.next(); @@ -386,6 +493,110 @@ public void and(final Roaring64Bitmap x2) { } } + /** + * Bitwise AND (intersection) operation. The provided bitmaps are *not* modified. This operation + * is thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return result of the operation + */ + public static Roaring64Bitmap and(final Roaring64Bitmap x1, final Roaring64Bitmap x2) { + Roaring64Bitmap result = new Roaring64Bitmap(); + KeyIterator it1 = x1.highLowContainer.highKeyIterator(); + while (it1.hasNext()) { + byte[] highKey = it1.next(); + long containerIdx1 = it1.currentContainerIdx(); + ContainerWithIndex containerWithIdx2 = x2.highLowContainer.searchContainer(highKey); + if (containerWithIdx2 != null) { + Container container1 = x1.highLowContainer.getContainer(containerIdx1); + Container container2 = containerWithIdx2.getContainer(); + Container andResult = container1.and(container2); + if (!andResult.isEmpty()) { + result.highLowContainer.put(highKey, andResult); + } + } + } + + return result; + } + + /** + * Checks whether the two bitmaps intersect. This can be much faster than calling "and" and + * checking the cardinality of the result. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return true if they intersect + */ + public static boolean intersects(final Roaring64Bitmap x1, final Roaring64Bitmap x2) { + KeyIterator it1 = x1.highLowContainer.highKeyIterator(); + KeyIterator it2 = x2.highLowContainer.highKeyIterator(); + + byte[] highKey1 = it1.hasNext() ? it1.next() : null; + byte[] highKey2 = it2.hasNext() ? it2.next() : null; + + while (highKey1 != null && highKey2 != null) { + int compare = HighLowContainer.compareUnsigned(highKey1, highKey2); + if (compare == 0) { + long containerIdx1 = it1.currentContainerIdx(); + long containerIdx2 = it2.currentContainerIdx(); + Container container1 = x1.highLowContainer.getContainer(containerIdx1); + Container container2 = x2.highLowContainer.getContainer(containerIdx2); + if (container1.intersects(container2)) { + return true; + } + highKey1 = it1.hasNext() ? it1.next() : null; + highKey2 = it2.hasNext() ? it2.next() : null; + } else if (compare < 0) { + highKey1 = it1.hasNext() ? it1.next() : null; + } else { + highKey2 = it2.hasNext() ? it2.next() : null; + } + } + + return false; + } + + /** + * Cardinality of Bitwise AND (intersection) operation. The provided bitmaps are *not* modified. + * This operation is thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return as if you did and(x1,x2).getCardinality() + */ + public static long andCardinality(final Roaring64Bitmap x1, final Roaring64Bitmap x2) { + long cardinality = 0; + KeyIterator it1 = x1.highLowContainer.highKeyIterator(); + KeyIterator it2 = x2.highLowContainer.highKeyIterator(); + + byte[] highKey1 = null, highKey2 = null; + if (it1.hasNext()) { + highKey1 = it1.next(); + } + if (it2.hasNext()) { + highKey2 = it2.next(); + } + + while (highKey1 != null && highKey2 != null) { + int compare = HighLowContainer.compareUnsigned(highKey1, highKey2); + if (compare == 0) { + long containerIdx1 = it1.currentContainerIdx(); + long containerIdx2 = it2.currentContainerIdx(); + Container container1 = x1.highLowContainer.getContainer(containerIdx1); + Container container2 = x2.highLowContainer.getContainer(containerIdx2); + cardinality += container1.andCardinality(container2); + highKey1 = it1.hasNext() ? it1.next() : null; + highKey2 = it2.hasNext() ? it2.next() : null; + } else if (compare < 0) { + highKey1 = it1.hasNext() ? it1.next() : null; + } else { + highKey2 = it2.hasNext() ? it2.next() : null; + } + } + return cardinality; + } /** * In-place bitwise ANDNOT (difference) operation. The current bitmap is modified. @@ -393,7 +604,7 @@ public void and(final Roaring64Bitmap x2) { * @param x2 other bitmap */ public void andNot(final Roaring64Bitmap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -415,6 +626,35 @@ public void andNot(final Roaring64Bitmap x2) { } } + /** + * Bitwise ANDNOT (difference) operation. The provided bitmaps are *not* modified. This operation + * is thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return result of the operation + */ + public static Roaring64Bitmap andNot(final Roaring64Bitmap x1, final Roaring64Bitmap x2) { + Roaring64Bitmap result = new Roaring64Bitmap(); + KeyIterator it1 = x1.highLowContainer.highKeyIterator(); + while (it1.hasNext()) { + byte[] highKey = it1.next(); + long containerIdx = it1.currentContainerIdx(); + ContainerWithIndex containerWithIdx2 = x2.highLowContainer.searchContainer(highKey); + Container container1 = x1.highLowContainer.getContainer(containerIdx); + if (containerWithIdx2 != null) { + Container andNotResult = container1.andNot(containerWithIdx2.getContainer()); + if (!andNotResult.isEmpty()) { + result.highLowContainer.put(highKey, andNotResult); + } + } else { + result.highLowContainer.put(highKey, container1.clone()); + } + } + + return result; + } + /** * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The * given bitmap is unchanged. @@ -424,13 +664,13 @@ public void andNot(final Roaring64Bitmap x2) { */ public void flip(final long rangeStart, final long rangeEnd) { - if(rangeStart >= 0 && rangeEnd >= 0 && rangeStart >= rangeEnd){ + if (rangeEnd >= 0 && rangeStart >= rangeEnd) { // both numbers in positive range, and start is beyond end, nothing to do. return; - } else if(rangeStart < 0 && rangeEnd < 0 && rangeStart >= rangeEnd){ + } else if (rangeStart < 0 && rangeStart >= rangeEnd) { // both numbers in negative range, and start is beyond end, nothing to do. return; - } else if(rangeStart < 0 && rangeEnd > 0) { + } else if (rangeStart < 0 && rangeEnd > 0) { // start is neg which is "higher" and end is above zero thus, nothing to do. return; } @@ -449,7 +689,8 @@ public void flip(final long rangeStart, final long rangeEnd) { // last container may contain partial range final int containerLast = (hb == shEnd) ? lbLast : LongUtils.maxLowBitAsInteger(); - ContainerWithIndex cwi = highLowContainer.searchContainer( + ContainerWithIndex cwi = + highLowContainer.searchContainer( LongUtils.highPartInPlace(LongUtils.leftShiftHighPart(hb), hbStart)); if (cwi != null) { @@ -491,8 +732,8 @@ public void readExternal(ObjectInput in) throws IOException { */ @Override public String toString() { - final StringBuilder answer = new StringBuilder("{}".length() + "-1234567890123456789,".length() - * 256); + final StringBuilder answer = + new StringBuilder("{}".length() + "-1234567890123456789,".length() * 256); final LongIterator i = this.getLongIterator(); answer.append('{'); if (i.hasNext()) { @@ -511,7 +752,6 @@ public String toString() { return answer.toString(); } - /** * For better performance, consider the Use the {@link #forEach forEach} method. * @@ -557,7 +797,6 @@ public int getSizeInBytes() { return (int) getLongSizeInBytes(); } - /** * Estimate of the memory usage of this data structure. This can be expected to be within 1% of * the true memory usage in common usage scenarios. @@ -629,7 +868,6 @@ public boolean runOptimize() { return hasChanged; } - /** * Serialize this bitmap. * @@ -740,6 +978,23 @@ public static Roaring64Bitmap bitmapOf(final long... dat) { return ans; } + /** + * If present remove the specified integer (effectively, sets its bit value to false) + * + * @param x integer value representing the index in a bitmap + */ + public void remove(final long x) { + byte[] highKey = LongUtils.highPart(x); + ContainerWithIndex containerWithIdx = highLowContainer.searchContainer(highKey); + if (containerWithIdx != null) { + char low = LongUtils.lowPart(x); + containerWithIdx.getContainer().remove(low); + if (containerWithIdx.getContainer().isEmpty()) { + highLowContainer.remove(highKey); + } + } + } + /** * Set all the specified values to true. This can be expected to be slightly faster than calling * "add" repeatedly. The provided integers values don't have to be in sorted order, but it may be @@ -776,35 +1031,36 @@ public void addRange(final long rangeStart, final long rangeEnd) { throw new IllegalArgumentException("Invalid range [" + rangeStart + "," + rangeEnd + ")"); } - byte[] startHigh = LongUtils.highPart(rangeStart); + long startHigh = LongUtils.rightShiftHighPart(rangeStart); int startLow = LongUtils.lowPart(rangeStart); - byte[] endHigh = LongUtils.highPart(rangeEnd - 1); + long endHigh = LongUtils.rightShiftHighPart(rangeEnd - 1); int endLow = LongUtils.lowPart(rangeEnd - 1); + long rangeStartVal = rangeStart; - byte[] startHighKey = startHigh; - for (; LongUtils.compareHigh(startHighKey, endHigh) <= 0; ) { - final int containerStart = - (LongUtils.compareHigh(startHighKey, startHigh) == 0) ? startLow : 0; + long startHighKey = LongUtils.rightShiftHighPart(rangeStart); + byte[] startHighKeyBytes = LongUtils.highPart(rangeStart); + while (startHighKey <= endHigh) { + final int containerStart = startHighKey == startHigh ? startLow : 0; // last container may contain partial range - final int containerLast = (LongUtils.compareHigh(startHighKey, endHigh) == 0) ? endLow - : Util.maxLowBitAsInteger(); - ContainerWithIndex containerWithIndex = highLowContainer.searchContainer(startHighKey); + final int containerLast = startHighKey == endHigh ? endLow : Util.maxLowBitAsInteger(); + ContainerWithIndex containerWithIndex = highLowContainer.searchContainer(startHighKeyBytes); if (containerWithIndex != null) { long containerIdx = containerWithIndex.getContainerIdx(); - Container freshContainer = highLowContainer.getContainer(containerIdx) - .iadd(containerStart, containerLast + 1); + Container freshContainer = + highLowContainer.getContainer(containerIdx).iadd(containerStart, containerLast + 1); highLowContainer.replaceContainer(containerIdx, freshContainer); } else { Container freshContainer = Container.rangeOfOnes(containerStart, containerLast + 1); - highLowContainer.put(startHighKey, freshContainer); + highLowContainer.put(startHighKeyBytes, freshContainer); } if (LongUtils.isMaxHigh(startHighKey)) { break; } - //increase the high + // increase the high rangeStartVal = rangeStartVal + (containerLast - containerStart) + 1; - startHighKey = LongUtils.highPart(rangeStartVal); + startHighKey = LongUtils.rightShiftHighPart(rangeStartVal); + startHighKeyBytes = LongUtils.highPart(rangeStartVal); } } @@ -859,7 +1115,7 @@ public void trim() { if (container.isEmpty()) { keyIterator.remove(); } else { - //TODO + // TODO container.trim(); } } @@ -885,7 +1141,6 @@ public boolean equals(Object obj) { return Objects.equals(highLowContainer, other.highLowContainer); } - /** * Add the value if it is not already present, otherwise remove it. * @@ -903,7 +1158,7 @@ public void flip(final long x) { } } - //mainly used for benchmark + // mainly used for benchmark @Override public Roaring64Bitmap clone() { long sizeInBytesL = this.serializedSizeInBytes(); @@ -923,7 +1178,6 @@ public Roaring64Bitmap clone() { } } - private abstract class PeekableIterator implements PeekableLongIterator { private final LeafNodeIterator keyIte; private byte[] high; @@ -932,10 +1186,10 @@ private abstract class PeekableIterator implements PeekableLongIterator { PeekableIterator(final LeafNodeIterator keyIte) { this.keyIte = keyIte; } - + abstract PeekableCharIterator getIterator(Container container); + abstract boolean compare(long next, long val); - abstract boolean compareHigh(byte[] next, byte[] val); @Override public boolean hasNext() { @@ -948,7 +1202,7 @@ public boolean hasNext() { long containerIdx = leafNode.getContainerIdx(); Container container = highLowContainer.getContainer(containerIdx); charIterator = getIterator(container); - if(charIterator.hasNext()){ + if (charIterator.hasNext()) { return true; } } @@ -970,25 +1224,26 @@ public void advanceIfNeeded(long minval) { if (!hasNext()) { return; } - if(compare(this.peekNext(), minval)) { + if (compare(this.peekNext(), minval)) { return; } - //empty bitset - if(this.high == null) { + // empty bitset + if (this.high == null) { return; } - byte[] minHigh = LongUtils.highPart(minval); - if (!Arrays.equals(this.high, minHigh)) { + long minHigh = LongUtils.rightShiftHighPart(minval); + long high = LongUtils.toLong(this.high); + if (minHigh != high) { // advance outer if (keyIte.hasNext()) { LeafNode leafNode = keyIte.next(); this.high = leafNode.getKeyBytes(); - if (compareHigh(this.high, minHigh)) { + if (compare(leafNode.getKey(), minHigh)) { long containerIdx = leafNode.getContainerIdx(); Container container = highLowContainer.getContainer(containerIdx); charIterator = getIterator(container); - if(!charIterator.hasNext()){ + if (!charIterator.hasNext()) { return; } } else { @@ -999,7 +1254,7 @@ public void advanceIfNeeded(long minval) { long containerIdx = leafNode.getContainerIdx(); Container container = highLowContainer.getContainer(containerIdx); charIterator = getIterator(container); - if(!charIterator.hasNext()){ + if (!charIterator.hasNext()) { return; } } else { @@ -1012,7 +1267,8 @@ public void advanceIfNeeded(long minval) { } } - if (Arrays.equals(this.high, minHigh)) { + byte[] minHighBytes = LongUtils.highPart(minval); + if (Arrays.equals(this.high, minHighBytes)) { // advance inner char low = LongUtils.lowPart(minval); charIterator.advanceIfNeeded(low); @@ -1035,47 +1291,36 @@ public PeekableLongIterator clone() { } } - private class ForwardPeekableIterator extends PeekableIterator { public ForwardPeekableIterator(final LeafNodeIterator keyIte) { super(keyIte); } - + @Override PeekableCharIterator getIterator(Container container) { return container.getCharIterator(); } - + @Override boolean compare(long next, long val) { return Long.compareUnsigned(next, val) >= 0; } - - @Override - boolean compareHigh(byte[] next, byte[] val) { - return LongUtils.compareHigh(next, val) >= 0; - } } private class ReversePeekableIterator extends PeekableIterator { public ReversePeekableIterator(final LeafNodeIterator keyIte) { super(keyIte); } - + @Override PeekableCharIterator getIterator(Container container) { return container.getReverseCharIterator(); } - + @Override boolean compare(long next, long val) { return Long.compareUnsigned(next, val) <= 0; } - - @Override - boolean compareHigh(byte[] next, byte[] val) { - return LongUtils.compareHigh(next, val) <= 0; - } } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java similarity index 75% rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java index f8109657c..a2864ff0d 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java @@ -3,13 +3,39 @@ */ package org.roaringbitmap.longlong; -import org.roaringbitmap.*; +import org.roaringbitmap.BitmapDataProvider; +import org.roaringbitmap.BitmapDataProviderSupplier; +import org.roaringbitmap.IntConsumer; +import org.roaringbitmap.IntIterator; +import org.roaringbitmap.RoaringBitmap; +import org.roaringbitmap.RoaringBitmapPrivate; +import org.roaringbitmap.RoaringBitmapSupplier; +import org.roaringbitmap.Util; import org.roaringbitmap.buffer.MutableRoaringBitmap; import org.roaringbitmap.buffer.MutableRoaringBitmapPrivate; -import java.io.*; -import java.util.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.UnsupportedEncodingException; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Map; import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.SortedMap; +import java.util.TreeMap; /** * Roaring64NavigableMap extends RoaringBitmap to the whole range of longs (or unsigned longs). It @@ -91,9 +117,9 @@ public Roaring64NavigableMap() { } /** - * + * * By default, use RoaringBitmap as underlyings {@link BitmapDataProvider} - * + * * @param signedLongs true if longs has to be ordered as plain java longs. False to handle them as * unsigned 64bits long (as RoaringBitmap with unsigned integers) */ @@ -103,7 +129,7 @@ public Roaring64NavigableMap(boolean signedLongs) { /** * By default, use RoaringBitmap as underlyings {@link BitmapDataProvider} - * + * * @param signedLongs true if longs has to be ordered as plain java longs. False to handle them as * unsigned 64bits long (as RoaringBitmap with unsigned integers) * @param cacheCardinalities true if cardinalities have to be cached. It will prevent many @@ -115,7 +141,7 @@ public Roaring64NavigableMap(boolean signedLongs, boolean cacheCardinalities) { /** * By default, longs are managed as unsigned longs and cardinalities are cached. - * + * * @param supplier provide the logic to instantiate new {@link BitmapDataProvider}, typically * instantiated once per high. */ @@ -125,7 +151,7 @@ public Roaring64NavigableMap(BitmapDataProviderSupplier supplier) { /** * By default, we activating cardinalities caching. - * + * * @param signedLongs true if longs has to be ordered as plain java longs. False to handle them as * unsigned 64bits long (as RoaringBitmap with unsigned integers) * @param supplier provide the logic to instantiate new {@link BitmapDataProvider}, typically @@ -136,7 +162,7 @@ public Roaring64NavigableMap(boolean signedLongs, BitmapDataProviderSupplier sup } /** - * + * * @param signedLongs true if longs has to be ordered as plain java longs. False to handle them as * unsigned 64bits long (as RoaringBitmap with unsigned integers) * @param cacheCardinalities true if cardinalities have to be cached. It will prevent many @@ -144,8 +170,8 @@ public Roaring64NavigableMap(boolean signedLongs, BitmapDataProviderSupplier sup * @param supplier provide the logic to instantiate new {@link BitmapDataProvider}, typically * instantiated once per high. */ - public Roaring64NavigableMap(boolean signedLongs, boolean cacheCardinalities, - BitmapDataProviderSupplier supplier) { + public Roaring64NavigableMap( + boolean signedLongs, boolean cacheCardinalities, BitmapDataProviderSupplier supplier) { this.signedLongs = signedLongs; this.supplier = supplier; @@ -310,7 +336,6 @@ public long getLongCardinality() { return 0L; } - return sortedCumulatedCardinality[indexOk - 1]; } else { long cardinality = 0L; @@ -322,9 +347,9 @@ public long getLongCardinality() { } /** - * + * * @return the cardinality as an int - * + * * @throws UnsupportedOperationException if the cardinality does not fit in an int */ public int getIntCardinality() throws UnsupportedOperationException { @@ -459,13 +484,16 @@ public void remove() { @Override public void forEach(final LongConsumer lc) { for (final Entry highEntry : highToBitmap.entrySet()) { - highEntry.getValue().forEach(new IntConsumer() { - - @Override - public void accept(int low) { - lc.accept(RoaringIntPacking.pack(highEntry.getKey(), low)); - } - }); + highEntry + .getValue() + .forEach( + new IntConsumer() { + + @Override + public void accept(int low) { + lc.accept(RoaringIntPacking.pack(highEntry.getKey(), low)); + } + }); } } @@ -539,7 +567,7 @@ private long rankLongNoCache(int high, int low) { } /** - * + * * @param high for which high bucket should we compute the cardinality * @return the highest validatedIndex */ @@ -597,7 +625,6 @@ protected int ensureCumulatives(int high) { // We have added one valid cardinality indexOk++; } - } if (highToBitmap.isEmpty() || indexOk == highToBitmap.size()) { @@ -613,8 +640,8 @@ private int binarySearch(int[] array, int key) { if (signedLongs) { return Arrays.binarySearch(array, key); } else { - return unsignedBinarySearch(array, 0, array.length, key, - RoaringIntPacking.unsignedComparator()); + return unsignedBinarySearch( + array, 0, array.length, key, RoaringIntPacking.unsignedComparator()); } } @@ -627,8 +654,8 @@ private int binarySearch(int[] array, int from, int to, int key) { } // From Arrays.binarySearch (Comparator). Check with org.roaringbitmap.Util.unsignedBinarySearch - private static int unsignedBinarySearch(int[] a, int fromIndex, int toIndex, int key, - Comparator c) { + private static int unsignedBinarySearch( + int[] a, int fromIndex, int toIndex, int key, Comparator c) { int low = fromIndex; int high = toIndex - 1; @@ -665,14 +692,21 @@ private void ensureOne(Map.Entry e, int currentHigh } else { index = -sortedHighs.length - 1; } - assert index == binarySearch(sortedHighs, 0, indexOk, currentHigh) : "Computed " + index - + " differs from dummy binary-search index: " - + binarySearch(sortedHighs, 0, indexOk, currentHigh); + assert index == binarySearch(sortedHighs, 0, indexOk, currentHigh) + : "Computed " + + index + + " differs from dummy binary-search index: " + + binarySearch(sortedHighs, 0, indexOk, currentHigh); if (index >= 0) { // This would mean calling .ensureOne is useless: should never got here at the first time - throw new IllegalStateException("Unexpectedly found " + currentHigh + " in " - + Arrays.toString(sortedHighs) + " strictly before index" + indexOk); + throw new IllegalStateException( + "Unexpectedly found " + + currentHigh + + " in " + + Arrays.toString(sortedHighs) + + " strictly before index" + + indexOk); } else { int insertionPosition = -index - 1; @@ -715,8 +749,6 @@ private void ensureOne(Map.Entry e, int currentHigh } } - - private int highestHigh() { return RoaringIntPacking.highestHigh(signedLongs); } @@ -728,7 +760,9 @@ private int highestHigh() { * @param x2 other bitmap */ public void naivelazyor(final Roaring64NavigableMap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } for (Entry e2 : x2.highToBitmap.entrySet()) { // Keep object to prevent auto-boxing Integer high = e2.getKey(); @@ -737,7 +771,7 @@ public void naivelazyor(final Roaring64NavigableMap x2) { BitmapDataProvider lowBitmap2 = e2.getValue(); - if (lowBitmap1 == null){ + if (lowBitmap1 == null) { // Clone to prevent future modification of this modifying the input Bitmap BitmapDataProvider lowBitmap2Clone; if (lowBitmap2 instanceof RoaringBitmap) { @@ -745,23 +779,24 @@ public void naivelazyor(final Roaring64NavigableMap x2) { } else if (lowBitmap2 instanceof MutableRoaringBitmap) { lowBitmap2Clone = ((MutableRoaringBitmap) lowBitmap2).clone(); } else { - throw new UnsupportedOperationException(".naivelazyor(...) over " - + getClassName(lowBitmap2)); + throw new UnsupportedOperationException( + ".naivelazyor(...) over " + getClassName(lowBitmap2)); } pushBitmapForHigh(high, lowBitmap2Clone); - } else if (lowBitmap1 instanceof RoaringBitmap - && lowBitmap2 instanceof RoaringBitmap) { + } else if (lowBitmap1 instanceof RoaringBitmap && lowBitmap2 instanceof RoaringBitmap) { RoaringBitmapPrivate.naivelazyor((RoaringBitmap) lowBitmap1, (RoaringBitmap) lowBitmap2); } else if (lowBitmap1 instanceof MutableRoaringBitmap - && lowBitmap2 instanceof MutableRoaringBitmap) { - MutableRoaringBitmapPrivate.naivelazyor((MutableRoaringBitmap) lowBitmap1, - (MutableRoaringBitmap) lowBitmap2); + && lowBitmap2 instanceof MutableRoaringBitmap) { + MutableRoaringBitmapPrivate.naivelazyor( + (MutableRoaringBitmap) lowBitmap1, (MutableRoaringBitmap) lowBitmap2); } else { - throw new UnsupportedOperationException(".naivelazyor(...) over " - + getClassName(lowBitmap1) + " and " + getClassName(lowBitmap2)); + throw new UnsupportedOperationException( + ".naivelazyor(...) over " + + getClassName(lowBitmap1) + + " and " + + getClassName(lowBitmap2)); } - } } @@ -771,7 +806,9 @@ public void naivelazyor(final Roaring64NavigableMap x2) { * @param x2 other bitmap */ public void or(final Roaring64NavigableMap x2) { - if(this == x2) { return; } + if (this == x2) { + return; + } boolean firstBucket = true; for (Entry e2 : x2.highToBitmap.entrySet()) { @@ -802,7 +839,6 @@ public void or(final Roaring64NavigableMap x2) { // Clone to prevent future modification of this modifying the input Bitmap BitmapDataProvider lowBitmap2Clone = ((MutableRoaringBitmap) lowBitmap2).clone(); - pushBitmapForHigh(high, lowBitmap2Clone); } else { ((MutableRoaringBitmap) lowBitmap1).or((MutableRoaringBitmap) lowBitmap2); @@ -822,13 +858,106 @@ public void or(final Roaring64NavigableMap x2) { } } + /** + * Bitwise OR (union) operation. The provided bitmaps are *not* modified. This operation is + * thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return result of the operation + */ + public static Roaring64NavigableMap or( + final Roaring64NavigableMap x1, final Roaring64NavigableMap x2) { + Roaring64NavigableMap result = new Roaring64NavigableMap(); + if (x1 == x2) { + return x1; + } + if (x1 == null) { + return x2; + } + if (x2 == null) { + return x1; + } + + Iterator> x1Iterator = + x1.getHighToBitmap().entrySet().iterator(); + Iterator> x2Iterator = + x2.getHighToBitmap().entrySet().iterator(); + Entry x1Entry = x1Iterator.hasNext() ? x1Iterator.next() : null; + Entry x2Entry = x2Iterator.hasNext() ? x2Iterator.next() : null; + + while (x1Entry != null || x2Entry != null) { + if (x1Entry == null) { + pushClonedEntry(x2Entry, result); + x2Entry = x2Iterator.hasNext() ? x2Iterator.next() : null; + } else if (x2Entry == null) { + pushClonedEntry(x1Entry, result); + x1Entry = x1Iterator.hasNext() ? x1Iterator.next() : null; + } else { + // compare & merge + int compare = Integer.compareUnsigned(x1Entry.getKey(), x2Entry.getKey()); + if (compare == 0) { + if (x1Entry.getValue() instanceof RoaringBitmap + && x2Entry.getValue() instanceof RoaringBitmap) { + result.pushBitmapForHigh( + x1Entry.getKey(), + RoaringBitmap.or( + (RoaringBitmap) x1Entry.getValue(), (RoaringBitmap) x2Entry.getValue())); + } else if (x1Entry.getValue() instanceof MutableRoaringBitmap + && x2Entry.getValue() instanceof MutableRoaringBitmap) { + result.pushBitmapForHigh( + x1Entry.getKey(), + MutableRoaringBitmap.or( + (MutableRoaringBitmap) x1Entry.getValue(), + (MutableRoaringBitmap) x2Entry.getValue())); + } else { + throw new UnsupportedOperationException( + ".or(...) over " + + getClassName(x1Entry.getValue()) + + " and " + + getClassName(x2Entry.getValue())); + } + x1Entry = x1Iterator.hasNext() ? x1Iterator.next() : null; + x2Entry = x2Iterator.hasNext() ? x2Iterator.next() : null; + } else if (compare < 0) { + pushClonedEntry(x1Entry, result); + x1Entry = x1Iterator.hasNext() ? x1Iterator.next() : null; + } else { + pushClonedEntry(x2Entry, result); + x2Entry = x2Iterator.hasNext() ? x2Iterator.next() : null; + } + } + } + + result.resetPerfHelpers(); + return result; + } + + /** + * static method for push a new entry(cloned) into target Roaring64NavigableMap + * + * @param entry the original entry item of a Roaring64NavigableMap instance + * @param result the target Roaring64NavigableMap + */ + private static void pushClonedEntry( + Entry entry, Roaring64NavigableMap result) { + if (entry.getValue() instanceof RoaringBitmap) { + result.pushBitmapForHigh(entry.getKey(), ((RoaringBitmap) (entry.getValue())).clone()); + } else if (entry.getValue() instanceof MutableRoaringBitmap) { + result.pushBitmapForHigh(entry.getKey(), ((MutableRoaringBitmap) (entry.getValue())).clone()); + } else { + throw new UnsupportedOperationException( + ". Unsupported type for pushClonedEntry: " + getClassName(entry.getValue())); + } + } + /** * In-place bitwise XOR (symmetric difference) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void xor(final Roaring64NavigableMap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -881,13 +1010,64 @@ public void xor(final Roaring64NavigableMap x2) { } } + /** + * Checks whether the two bitmaps intersect. This can be much faster than calling "and" and + * checking the cardinality of the result. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return true if they intersect + */ + public static boolean intersects(final Roaring64NavigableMap x1, final Roaring64NavigableMap x2) { + if (x2 == x1) { + return true; + } + if (x1 == null || x2 == null) { + return false; + } + + // find the one with smaller entries cnt + long x1HighCnt = x1.getHighToBitmap().size(); + long x2HighCnt = x2.getHighToBitmap().size(); + Roaring64NavigableMap outer = x1HighCnt < x2HighCnt ? x1 : x2; + Roaring64NavigableMap inner = x1HighCnt < x2HighCnt ? x2 : x1; + for (Entry entry : outer.getHighToBitmap().entrySet()) { + BitmapDataProvider lowBitmap1 = entry.getValue(); + BitmapDataProvider lowBitmap2 = inner.getHighToBitmap().get(entry.getKey()); + if (lowBitmap2 == null) { + continue; + } + if (lowBitmap1 instanceof RoaringBitmap && lowBitmap2 instanceof RoaringBitmap) { + if (RoaringBitmap.intersects((RoaringBitmap) lowBitmap1, (RoaringBitmap) lowBitmap2)) { + return true; + } + } else if (lowBitmap1 instanceof MutableRoaringBitmap + && lowBitmap2 instanceof MutableRoaringBitmap) { + if (MutableRoaringBitmap.intersects( + (MutableRoaringBitmap) lowBitmap1, (MutableRoaringBitmap) lowBitmap2)) { + return true; + } + } else { + throw new UnsupportedOperationException( + ".intersects(...) over " + + getClassName(lowBitmap1) + + " and " + + getClassName(lowBitmap2)); + } + } + + return false; + } + /** * In-place bitwise AND (intersection) operation. The current bitmap is modified. * * @param x2 other bitmap */ public void and(final Roaring64NavigableMap x2) { - if(x2 == this) { return; } + if (x2 == this) { + return; + } boolean firstBucket = true; Iterator> thisIterator = highToBitmap.entrySet().iterator(); @@ -926,6 +1106,115 @@ public void and(final Roaring64NavigableMap x2) { } } + /** + * Bitwise AND (intersection) operation. The provided bitmaps are *not* modified. This operation + * is thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return result of the operation + */ + public static Roaring64NavigableMap and( + final Roaring64NavigableMap x1, final Roaring64NavigableMap x2) { + Roaring64NavigableMap result = new Roaring64NavigableMap(); + if (x2 == x1) { + return x1; + } + if (x1 == null || x2 == null) { + return result; + } + Iterator> x1Iterator = + x1.getHighToBitmap().entrySet().iterator(); + while (x1Iterator.hasNext()) { + Entry e1 = x1Iterator.next(); + // Keep object to prevent auto-boxing + Integer high = e1.getKey(); + + BitmapDataProvider lowBitmap1 = e1.getValue(); + BitmapDataProvider lowBitmap2 = x2.getHighToBitmap().get(high); + if (lowBitmap2 != null) { + if (lowBitmap2 instanceof RoaringBitmap && lowBitmap1 instanceof RoaringBitmap) { + RoaringBitmap andResult = + RoaringBitmap.and((RoaringBitmap) lowBitmap1, (RoaringBitmap) lowBitmap2); + result.pushBitmapForHigh(high, andResult); + } else if (lowBitmap2 instanceof MutableRoaringBitmap + && lowBitmap1 instanceof MutableRoaringBitmap) { + MutableRoaringBitmap andResult = + MutableRoaringBitmap.and( + (MutableRoaringBitmap) lowBitmap1, (MutableRoaringBitmap) lowBitmap2); + result.pushBitmapForHigh(high, andResult); + } else { + throw new UnsupportedOperationException( + ".and(...) over " + getClassName(lowBitmap1) + " and " + getClassName(lowBitmap2)); + } + } + } + result.resetPerfHelpers(); + return result; + } + + /** + * Cardinality of Bitwise AND (intersection) operation. The provided bitmaps are *not* modified. + * This operation is thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return as if you did and(x1,x2).getCardinality() + */ + public static long andCardinality( + final Roaring64NavigableMap x1, final Roaring64NavigableMap x2) { + long cardinality = 0; + if (x1 == null || x2 == null) { + return cardinality; + } + if (x1.getHighToBitmap().isEmpty() || x2.getHighToBitmap().isEmpty()) { + return cardinality; + } + if (x2 == x1) { + return x1.getLongCardinality(); + } + + Iterator> x1Iterator = + x1.getHighToBitmap().entrySet().iterator(); + Iterator> x2Iterator = + x2.getHighToBitmap().entrySet().iterator(); + Entry x1Entry = x1Iterator.next(); + Entry x2Entry = x2Iterator.next(); + + while (x1Entry != null && x2Entry != null) { + int highKey1 = x1Entry.getKey(); + int highKey2 = x2Entry.getKey(); + BitmapDataProvider lowBitmap1 = x1Entry.getValue(); + BitmapDataProvider lowBitmap2 = x2Entry.getValue(); + + int compare = Integer.compareUnsigned(highKey1, highKey2); + if (compare == 0) { + if (lowBitmap2 instanceof RoaringBitmap && lowBitmap1 instanceof RoaringBitmap) { + cardinality += + RoaringBitmap.andCardinality((RoaringBitmap) lowBitmap1, (RoaringBitmap) lowBitmap2); + } else if (lowBitmap2 instanceof MutableRoaringBitmap + && lowBitmap1 instanceof MutableRoaringBitmap) { + cardinality += + MutableRoaringBitmap.andCardinality( + (MutableRoaringBitmap) lowBitmap1, (MutableRoaringBitmap) lowBitmap2); + } else { + throw new UnsupportedOperationException( + ".andCardinality(...) over " + + getClassName(lowBitmap1) + + " and " + + getClassName(lowBitmap2)); + } + x1Entry = x1Iterator.hasNext() ? x1Iterator.next() : null; + x2Entry = x2Iterator.hasNext() ? x2Iterator.next() : null; + } else if (compare < 0) { + x1Entry = x1Iterator.hasNext() ? x1Iterator.next() : null; + } else { + x2Entry = x2Iterator.hasNext() ? x2Iterator.next() : null; + } + } + + return cardinality; + } /** * In-place bitwise ANDNOT (difference) operation. The current bitmap is modified. @@ -933,7 +1222,7 @@ public void and(final Roaring64NavigableMap x2) { * @param x2 other bitmap */ public void andNot(final Roaring64NavigableMap x2) { - if(x2 == this) { + if (x2 == this) { clear(); return; } @@ -972,6 +1261,56 @@ public void andNot(final Roaring64NavigableMap x2) { } } + /** + * Bitwise ANDNOT (difference) operation. The provided bitmaps are *not* modified. This operation + * is thread-safe as long as the provided bitmaps remain unchanged. + * + * @param x1 first bitmap + * @param x2 other bitmap + * @return result of the operation + */ + public static Roaring64NavigableMap andNot( + final Roaring64NavigableMap x1, final Roaring64NavigableMap x2) { + Roaring64NavigableMap result = new Roaring64NavigableMap(); + if (x1 == x2 || x1 == null || x1.getHighToBitmap() == null) { + return result; + } + if (x2 == null || x2.getHighToBitmap() == null) { + return x1; + } + + Iterator> x1Iterator = + x1.getHighToBitmap().entrySet().iterator(); + while (x1Iterator.hasNext()) { + Entry e1 = x1Iterator.next(); + + // Keep object to prevent auto-boxing + Integer high = e1.getKey(); + BitmapDataProvider lowBitmap1 = e1.getValue(); + BitmapDataProvider lowBitmap2 = x2.getHighToBitmap().get(high); + if (lowBitmap2 != null) { + if (lowBitmap2 instanceof RoaringBitmap && lowBitmap1 instanceof RoaringBitmap) { + RoaringBitmap andNotResult = + RoaringBitmap.andNot((RoaringBitmap) lowBitmap1, (RoaringBitmap) lowBitmap2); + result.pushBitmapForHigh(high, andNotResult); + } else if (lowBitmap2 instanceof MutableRoaringBitmap + && lowBitmap1 instanceof MutableRoaringBitmap) { + MutableRoaringBitmap andNotResult = + MutableRoaringBitmap.andNot( + (MutableRoaringBitmap) lowBitmap1, (MutableRoaringBitmap) lowBitmap2); + result.pushBitmapForHigh(high, andNotResult); + } else { + throw new UnsupportedOperationException( + ".andNot(...) over " + getClassName(lowBitmap1) + " and " + getClassName(lowBitmap2)); + } + } else { + result.pushBitmapForHigh(high, lowBitmap1); + } + } + result.resetPerfHelpers(); + return result; + } + /** * {@link Roaring64NavigableMap} are serializable. However, contrary to RoaringBitmap, the * serialization format is not well-defined: for now, it is strongly coupled with Java standard @@ -996,8 +1335,8 @@ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundExcept */ @Override public String toString() { - final StringBuilder answer = new StringBuilder("{}".length() + "-1234567890123456789,".length() - * 256); + final StringBuilder answer = + new StringBuilder("{}".length() + "-1234567890123456789,".length() * 256); final LongIterator i = this.getLongIterator(); answer.append('{'); if (i.hasNext()) { @@ -1019,13 +1358,11 @@ public String toString() { } else { answer.append(RoaringIntPacking.toUnsignedString(i.next())); } - } answer.append("}"); return answer.toString(); } - /** * * For better performance, consider the Use the {@link #forEach forEach} method. @@ -1039,8 +1376,8 @@ public LongIterator getLongIterator() { return toIterator(it, false); } - protected LongIterator toIterator(final Iterator> it, - final boolean reversed) { + protected LongIterator toIterator( + final Iterator> it, final boolean reversed) { return new LongIterator() { protected int currentKey; @@ -1117,7 +1454,6 @@ public boolean contains(long x) { return lowBitmap.contains(low); } - @Override public int getSizeInBytes() { return (int) getLongSizeInBytes(); @@ -1126,10 +1462,10 @@ public int getSizeInBytes() { @Override public long getLongSizeInBytes() { long size = 8; - + // Size of containers size += highToBitmap.values().stream().mapToLong(p -> p.getLongSizeInBytes()).sum(); - + // Size of Map data-structure: we consider each TreeMap entry costs 40 bytes // http://java-performance.info/memory-consumption-of-java-data-types-2/ size += 8L + 40L * highToBitmap.size(); @@ -1140,7 +1476,7 @@ public long getLongSizeInBytes() { // The cache impacts the size in heap size += 8L * sortedCumulatedCardinality.length; size += 4L * sortedHighs.length; - + return size; } @@ -1161,18 +1497,18 @@ public void repairAfterLazy() { for (BitmapDataProvider lowBitmap : highToBitmap.values()) { if (lowBitmap instanceof RoaringBitmap) { RoaringBitmapPrivate.repairAfterLazy((RoaringBitmap) lowBitmap); - } else if(lowBitmap instanceof MutableRoaringBitmap){ + } else if (lowBitmap instanceof MutableRoaringBitmap) { MutableRoaringBitmapPrivate.repairAfterLazy((MutableRoaringBitmap) lowBitmap); } else { throw new UnsupportedOperationException( - ".repairAfterLazy is not supported for " + lowBitmap.getClass()); + ".repairAfterLazy is not supported for " + lowBitmap.getClass()); } } } /** * Use a run-length encoding where it is estimated as more space efficient - * + * * @return whether a change was applied */ public boolean runOptimize() { @@ -1187,7 +1523,6 @@ public boolean runOptimize() { return hasChanged; } - /** * Serialize this bitmap. * @@ -1364,7 +1699,6 @@ public void deserializePortable(DataInput in) throws IOException { resetPerfHelpers(); } - @Override public long serializedSizeInBytes() { long nbBytes = 0L; @@ -1476,7 +1810,7 @@ public void addRange(final long rangeStart, final long rangeEnd) { int compareHigh = compare(startHigh, endHigh); if (compareHigh > 0 - || compareHigh == 0 && Util.toUnsignedLong(startLow) >= Util.toUnsignedLong(endLow)) { + || compareHigh == 0 && Util.toUnsignedLong(startLow) >= Util.toUnsignedLong(endLow)) { throw new IllegalArgumentException("Invalid range [" + rangeStart + "," + rangeEnd + ")"); } @@ -1545,7 +1879,6 @@ public void removeLong(long x) { // Invalidate only if actually modified invalidateAboveHigh(high); } - } @Override @@ -1575,7 +1908,34 @@ public boolean equals(Object obj) { return Objects.equals(highToBitmap, other.highToBitmap); } - + /** + * clone current Roaring64NavigableMap instance, the new cloned instance will have + * the same serialization mode with this one. + *

+ * *NOTE* This can only handle instances where {@link #serializedSizeInBytes} < Integer.MAX_VALUE, + * otherwise an UnsupportedOperationException will be thrown. + */ + @Override + public Roaring64NavigableMap clone() { + long sizeInBytesL = this.serializedSizeInBytes(); + if (sizeInBytesL >= Integer.MAX_VALUE) { + throw new UnsupportedOperationException(); + } + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dataOutput = new DataOutputStream(baos)) { + serialize(dataOutput); + Roaring64NavigableMap freshOne = new Roaring64NavigableMap(); + try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + DataInputStream dataInput = new DataInputStream(bais)) { + freshOne.deserialize(dataInput); + return freshOne; + } catch (Exception e) { + throw new RuntimeException("fail to deserialize", e); + } + } catch (Exception e) { + throw new RuntimeException("fail to clone through the ser/deser", e); + } + } /** * Add the value if it is not already present, otherwise remove it. @@ -1611,7 +1971,7 @@ public void flip(final long x) { } private void assertNonEmpty() { - if(isEmpty()) { + if (isEmpty()) { throw new NoSuchElementException("Empty " + this.getClass().getSimpleName()); } } diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/RoaringIntPacking.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/RoaringIntPacking.java similarity index 99% rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/RoaringIntPacking.java rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/RoaringIntPacking.java index 9828859b7..7140bb210 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/RoaringIntPacking.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/RoaringIntPacking.java @@ -10,14 +10,14 @@ * Used to hold the logic packing 2 integers in a long, and separating a long in two integers. It is * useful in {@link Roaring64NavigableMap} as the implementation split the input long in two * integers, one used as key of a NavigableMap while the other is added in a Bitmap - * + * * @author Benoit Lacelle * */ class RoaringIntPacking { /** - * + * * @param id any long, positive or negative * @return an int holding the 32 highest order bits of information of the input long */ @@ -26,7 +26,7 @@ public static int high(long id) { } /** - * + * * @param id any long, positive or negative * @return an int holding the 32 lowest order bits of information of the input long */ @@ -35,7 +35,7 @@ public static int low(long id) { } /** - * + * * @param high an integer representing the highest order bits of the output long * @param low an integer representing the lowest order bits of the output long * @return a long packing together the integers as computed by @@ -46,9 +46,8 @@ public static long pack(int high, int low) { return (((long) high) << 32) | (low & 0xffffffffL); } - /** - * + * * @param signedLongs true if long put in a {@link Roaring64NavigableMap} should be considered as * signed long. * @return the int representing the highest value which can be set as high value in a diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/package-info.java b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/package-info.java similarity index 96% rename from RoaringBitmap/src/main/java/org/roaringbitmap/longlong/package-info.java rename to roaringbitmap/src/main/java/org/roaringbitmap/longlong/package-info.java index 3da296b9f..38a5c22bb 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/package-info.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/longlong/package-info.java @@ -2,14 +2,12 @@ * (c) the authors Licensed under the Apache License, Version 2.0. */ - - /** * The org.roaringbitmap.longlong package provides * one class ({@link org.roaringbitmap.longlong.Roaring64NavigableMap}) that users * can rely upon for fast set of 64-bit integers. - * - * + * + * *

  * {@code
  *      import org.roaringbitmap.longlong.*;
@@ -18,10 +16,9 @@
  *
  *      Roaring64NavigableMap r1 = new Roaring64NavigableMap();
  *      for(long k = 4000l; k<4255l;++k) r1.addLong(k);
- *      
+ *
  * }
  * 
* */ package org.roaringbitmap.longlong; - diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/package-info.java b/roaringbitmap/src/main/java/org/roaringbitmap/package-info.java similarity index 97% rename from RoaringBitmap/src/main/java/org/roaringbitmap/package-info.java rename to roaringbitmap/src/main/java/org/roaringbitmap/package-info.java index c05ab40fc..edabd83a5 100644 --- a/RoaringBitmap/src/main/java/org/roaringbitmap/package-info.java +++ b/roaringbitmap/src/main/java/org/roaringbitmap/package-info.java @@ -2,14 +2,12 @@ * (c) the authors Licensed under the Apache License, Version 2.0. */ - - /** * The org.roaringbitmap package provides * one class ({@link org.roaringbitmap.RoaringBitmap}) that users * can rely upon for fast set of integers. - * - * + * + * *
  * {@code
  *      import org.roaringbitmap.*;
@@ -18,7 +16,7 @@
  *
  *      RoaringBitmap r1 = new RoaringBitmap();
  *      for(int k = 4000; k<4255;++k) r1.add(k);
- *      
+ *
  *      RoaringBitmap r2 = new RoaringBitmap();
  *      for(int k = 1000; k<4255; k+=2) r2.add(k);
  *
@@ -34,4 +32,3 @@
  *
  */
 package org.roaringbitmap;
-
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/CloneBatchIteratorTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/CloneBatchIteratorTest.java
similarity index 93%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/CloneBatchIteratorTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/CloneBatchIteratorTest.java
index 137bc2d08..71c7606b4 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/CloneBatchIteratorTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/CloneBatchIteratorTest.java
@@ -1,14 +1,14 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
 import com.google.common.primitives.Ints;
 import org.junit.jupiter.api.Test;
 
 import java.util.Arrays;
 
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
-
 public class CloneBatchIteratorTest {
 
   @Test
@@ -31,8 +31,8 @@ public void testIndependenceOfClones() {
 
   @Test
   public void testIndependenceOfClones2() {
-    int[] c1 = new int[]{1, 10, 20};
-    int[] c2 = new int[]{65560, 70000};
+    int[] c1 = new int[] {1, 10, 20};
+    int[] c2 = new int[] {65560, 70000};
     RoaringBitmap bitmap = new RoaringBitmap();
     for (int x : Ints.concat(c1, c2)) {
       bitmap.add(x);
@@ -41,7 +41,7 @@ public void testIndependenceOfClones2() {
     BatchIterator it1 = bitmap.getBatchIterator();
     BatchIterator it2 = it1.clone();
 
-    int[] buffer = new int[8];
+    int[] buffer = new int[3];
 
     assertEquals(3, it2.nextBatch(buffer));
     assertArrayEquals(c1, Arrays.copyOfRange(buffer, 0, 3));
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/ContainerBatchIteratorTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/ContainerBatchIteratorTest.java
new file mode 100644
index 000000000..8802ba591
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/ContainerBatchIteratorTest.java
@@ -0,0 +1,179 @@
+package org.roaringbitmap;
+
+import static java.util.Arrays.copyOfRange;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class ContainerBatchIteratorTest {
+
+  private static int[][] DATA;
+
+  @BeforeAll
+  public static void setup() {
+    DATA =
+        Stream.of(
+                IntStream.range(0, 20000).toArray(),
+                IntStream.range(0, 1 << 16).toArray(),
+                IntStream.range(0, 1 << 16)
+                    .filter(i -> i < 500 || i > 2000)
+                    .filter(i -> i < (1 << 15) || i > ((1 << 15) | (1 << 8)))
+                    .toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 12) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 11) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 10) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 9) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 8) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 7) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 6) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 5) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 4) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 3) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 2) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 1) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 3) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 5) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 7) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 9) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 271) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 1000) == 0).toArray(),
+                IntStream.empty().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray())
+            .toArray(int[][]::new);
+  }
+
+  @AfterAll
+  public static void clear() {
+    DATA = null;
+  }
+
+  public static Stream params() {
+    return Stream.of(DATA)
+        .flatMap(
+            array ->
+                IntStream.concat(
+                        IntStream.of(512, 1024, 2048, 4096, 8192, 65536),
+                        IntStream.range(0, 100)
+                            .map(i -> ThreadLocalRandom.current().nextInt(1, 65536)))
+                    .mapToObj(i -> Arguments.of(array, i)));
+  }
+
+  @ParameterizedTest(name = "{1}")
+  @MethodSource("params")
+  public void test(int[] expectedValues, int batchSize) {
+    int[] buffer = new int[batchSize];
+    Container container = createContainer(expectedValues);
+    ContainerBatchIterator it = container.getBatchIterator();
+    int cardinality = 0;
+    while (it.hasNext()) {
+      int from = cardinality;
+      cardinality += it.next(0, buffer);
+      assertArrayEquals(
+          copyOfRange(expectedValues, from, cardinality),
+          copyOfRange(buffer, 0, cardinality - from),
+          "Failure with batch size " + batchSize);
+    }
+    assertEquals(expectedValues.length, cardinality);
+  }
+
+  @ParameterizedTest(name = "{1}")
+  @MethodSource("params")
+  public void testAdvanceIfNeeded(int[] expectedValues, int batchSize) {
+    if (expectedValues.length < 2) {
+      return;
+    }
+    int[] buffer = new int[batchSize];
+    Container container = createContainer(expectedValues);
+    ContainerBatchIterator it = container.getBatchIterator();
+    int cardinality = expectedValues.length / 2;
+    int advanceUntil = expectedValues[cardinality];
+    it.advanceIfNeeded((char) advanceUntil);
+    while (it.hasNext()) {
+      int from = cardinality;
+      cardinality += it.next(0, buffer);
+      assertArrayEquals(
+          copyOfRange(expectedValues, from, cardinality),
+          copyOfRange(buffer, 0, cardinality - from),
+          "Failure with batch size "
+              + batchSize
+              + " and container type "
+              + container.getContainerName());
+    }
+    assertEquals(expectedValues.length, cardinality);
+  }
+
+  // https://github.com/RoaringBitmap/RoaringBitmap/issues/730
+  @Test
+  public void testHasNextBitmapIterator() {
+    BitmapContainer container = new BitmapContainer(); // create an empty container
+    assertFalse(container.getBatchIterator().hasNext());
+  }
+
+  private Container createContainer(int[] expectedValues) {
+    Container container = new ArrayContainer();
+    for (int value : expectedValues) {
+      container = container.add((char) value);
+    }
+    return container.runOptimize();
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/KryoTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/KryoTest.java
new file mode 100644
index 000000000..6c0c1ebde
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/KryoTest.java
@@ -0,0 +1,94 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.KryoDataInput;
+import com.esotericsoftware.kryo.io.KryoDataOutput;
+import com.esotericsoftware.kryo.io.Output;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class KryoTest {
+  public static Kryo createKryo() {
+    Kryo kryo = new Kryo();
+    kryo.setRegistrationRequired(false);
+    kryo.register(RoaringBitmap.class, new RoaringSerializer());
+    return kryo;
+  }
+
+  public static void writeRoaringToFile(
+      File f, RoaringBitmap roaring, Serializer serializer)
+      throws FileNotFoundException {
+    Kryo kryo = createKryo();
+    Output kryoOutputMap = new Output(new FileOutputStream(f));
+    kryo.writeObjectOrNull(kryoOutputMap, roaring, serializer);
+    kryoOutputMap.flush();
+    kryoOutputMap.close();
+  }
+
+  public static RoaringBitmap readRoaringFromFile(File f, Serializer serializer)
+      throws FileNotFoundException {
+    Kryo kryo = createKryo();
+    Input inputMap = new Input(new FileInputStream(f));
+    RoaringBitmap roaring = kryo.readObjectOrNull(inputMap, RoaringBitmap.class, serializer);
+    inputMap.close();
+    return roaring;
+  }
+
+  @Test
+  public void roaringTest() throws IOException {
+    RoaringSerializer serializer = new RoaringSerializer();
+    RoaringBitmap roaringDense = new RoaringBitmap();
+    for (int i = 0; i < 100_000; i++) {
+      roaringDense.add(i);
+    }
+    File tmpfiledense = File.createTempFile("roaring_dense", "bin");
+    tmpfiledense.deleteOnExit();
+    writeRoaringToFile(tmpfiledense, roaringDense, serializer);
+    RoaringBitmap denseRoaringFromFile = readRoaringFromFile(tmpfiledense, serializer);
+    assertEquals(denseRoaringFromFile, roaringDense);
+
+    RoaringBitmap roaringSparse = new RoaringBitmap();
+    for (int i = 0; i < 100_000; i++) {
+      if (i % 11 == 0) {
+        roaringSparse.add(i);
+      }
+    }
+    File tmpfilesparse = File.createTempFile("roaring_sparse", "bin");
+    writeRoaringToFile(tmpfilesparse, roaringSparse, serializer);
+    RoaringBitmap sparseRoaringFromFile = readRoaringFromFile(tmpfilesparse, serializer);
+    assertEquals(sparseRoaringFromFile, roaringSparse);
+  }
+}
+
+class RoaringSerializer extends Serializer {
+  @Override
+  public void write(Kryo kryo, Output output, RoaringBitmap bitmap) {
+    try {
+      bitmap.serialize(new KryoDataOutput(output));
+    } catch (IOException e) {
+      e.printStackTrace();
+      throw new RuntimeException();
+    }
+  }
+
+  @Override
+  public RoaringBitmap read(Kryo kryo, Input input, Class type) {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    try {
+      bitmap.deserialize(new KryoDataInput(input));
+    } catch (IOException e) {
+      e.printStackTrace();
+      throw new RuntimeException();
+    }
+    return bitmap;
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/OrNotTruncationTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/OrNotTruncationTest.java
new file mode 100644
index 000000000..46ff3e179
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/OrNotTruncationTest.java
@@ -0,0 +1,65 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class OrNotTruncationTest {
+
+  private static final Consumer NO_OP = x -> {};
+
+  public static Stream params() {
+    return Stream.of(
+        Arguments.of(new RoaringBitmap(), NO_OP),
+        Arguments.of(new RoaringBitmap(), (Consumer) x -> x.add(2)),
+        Arguments.of(new RoaringBitmap(), (Consumer) x -> x.add(2L, 5L)),
+        Arguments.of(new RoaringBitmap(), (Consumer) x -> x.add(3L, 5L)),
+        Arguments.of(
+            new RoaringBitmap(),
+            (Consumer)
+                x -> {
+                  x.add(1L, 10L);
+                  x.remove(2L, 10L);
+                }),
+        Arguments.of(
+            new RoaringBitmap(),
+            (Consumer)
+                x -> {
+                  for (int i : new int[] {0, 1, 2, 3, 4, 5, 6}) x.add(i);
+                }),
+        Arguments.of(RoaringBitmap.bitmapOf(2), NO_OP),
+        Arguments.of(RoaringBitmap.bitmapOf(2, 3, 4), NO_OP),
+        Arguments.of(testCase().withArrayAt(0).build(), NO_OP),
+        Arguments.of(testCase().withRunAt(0).build(), NO_OP),
+        Arguments.of(testCase().withBitmapAt(0).build(), NO_OP),
+        Arguments.of(testCase().withArrayAt(0).withRunAt(1).build(), NO_OP),
+        Arguments.of(testCase().withRunAt(0).withRunAt(1).build(), NO_OP),
+        Arguments.of(testCase().withBitmapAt(0).withRunAt(1).build(), NO_OP),
+        Arguments.of(testCase().withArrayAt(1).build(), NO_OP),
+        Arguments.of(testCase().withRunAt(1).build(), NO_OP),
+        Arguments.of(testCase().withBitmapAt(1).build(), NO_OP),
+        Arguments.of(testCase().withArrayAt(1).withRunAt(2).build(), NO_OP),
+        Arguments.of(testCase().withRunAt(1).withRunAt(2).build(), NO_OP),
+        Arguments.of(testCase().withBitmapAt(1).withRunAt(2).build(), NO_OP));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void testTruncation(RoaringBitmap other, Consumer init) {
+    RoaringBitmap one = new RoaringBitmap();
+    one.add(0);
+    one.add(10);
+    init.accept(other);
+    one.orNot(other, 7);
+    assertTrue(one.contains(10));
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/ParallelAggregationTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/ParallelAggregationTest.java
similarity index 53%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/ParallelAggregationTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/ParallelAggregationTest.java
index 1d5f78c9d..c800eb7ac 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/ParallelAggregationTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/ParallelAggregationTest.java
@@ -1,20 +1,21 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.roaringbitmap.buffer.BufferFastAggregation;
+import org.roaringbitmap.buffer.BufferParallelAggregation;
+import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
+
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
-import org.roaringbitmap.buffer.BufferFastAggregation;
-import org.roaringbitmap.buffer.BufferParallelAggregation;
-import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
 
 import java.util.concurrent.ForkJoinPool;
 import java.util.stream.IntStream;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class ParallelAggregationTest {
 
@@ -62,10 +63,10 @@ public void disjointOR() {
     assertEquals(FastAggregation.or(one, two, three), ParallelAggregation.or(one, two, three));
   }
 
-
   @Test
   public void wideOr() {
-    RoaringBitmap[] input = IntStream.range(0, 20)
+    RoaringBitmap[] input =
+        IntStream.range(0, 20)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
     assertEquals(FastAggregation.or(input), ParallelAggregation.or(input));
@@ -73,16 +74,17 @@ public void wideOr() {
 
   @Test
   public void hugeOr1() {
-    RoaringBitmap[] input = IntStream.range(0, 513)
+    RoaringBitmap[] input =
+        IntStream.range(0, 513)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
     assertEquals(FastAggregation.or(input), ParallelAggregation.or(input));
   }
 
-
   @Test
   public void hugeOr2() {
-    RoaringBitmap[] input = IntStream.range(0, 1999)
+    RoaringBitmap[] input =
+        IntStream.range(0, 1999)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
     assertEquals(FastAggregation.or(input), ParallelAggregation.or(input));
@@ -90,7 +92,8 @@ public void hugeOr2() {
 
   @Test
   public void hugeOr3() {
-    RoaringBitmap[] input = IntStream.range(0, 4096)
+    RoaringBitmap[] input =
+        IntStream.range(0, 4096)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
     assertEquals(FastAggregation.or(input), ParallelAggregation.or(input));
@@ -98,66 +101,75 @@ public void hugeOr3() {
 
   @Test
   public void hugeOrNoParallelismAvailable1() {
-    RoaringBitmap[] input = IntStream.range(0, 513)
+    RoaringBitmap[] input =
+        IntStream.range(0, 513)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
-    assertEquals(FastAggregation.or(input),
-            NO_PARALLELISM_AVAILABLE.submit(() -> ParallelAggregation.or(input)).join());
+    assertEquals(
+        FastAggregation.or(input),
+        NO_PARALLELISM_AVAILABLE.submit(() -> ParallelAggregation.or(input)).join());
   }
 
-
   @Test
   public void hugeOrNoParallelismAvailable2() {
-    RoaringBitmap[] input = IntStream.range(0, 2000)
+    RoaringBitmap[] input =
+        IntStream.range(0, 2000)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
-    assertEquals(FastAggregation.or(input),
-            NO_PARALLELISM_AVAILABLE.submit(() -> ParallelAggregation.or(input)).join());
+    assertEquals(
+        FastAggregation.or(input),
+        NO_PARALLELISM_AVAILABLE.submit(() -> ParallelAggregation.or(input)).join());
   }
 
   @Test
   public void hugeOrNoParallelismAvailable3() {
-    RoaringBitmap[] input = IntStream.range(0, 4096)
+    RoaringBitmap[] input =
+        IntStream.range(0, 4096)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
-    assertEquals(FastAggregation.or(input),
-            NO_PARALLELISM_AVAILABLE.submit(() -> ParallelAggregation.or(input)).join());
+    assertEquals(
+        FastAggregation.or(input),
+        NO_PARALLELISM_AVAILABLE.submit(() -> ParallelAggregation.or(input)).join());
   }
 
   @Test
   public void hugeOrInFJP1() {
-    RoaringBitmap[] input = IntStream.range(0, 513)
+    RoaringBitmap[] input =
+        IntStream.range(0, 513)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
-    assertEquals(FastAggregation.or(input),
-            POOL.submit(() -> ParallelAggregation.or(input)).join());
+    assertEquals(
+        FastAggregation.or(input), POOL.submit(() -> ParallelAggregation.or(input)).join());
   }
 
   @Test
   public void regressionTest() {
-    RoaringBitmap[] input = IntStream.range(0, 513)
+    RoaringBitmap[] input =
+        IntStream.range(0, 513)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
-    assertEquals(FastAggregation.or(input),
-            BIG_POOL.submit(() -> ParallelAggregation.or(input)).join());
+    assertEquals(
+        FastAggregation.or(input), BIG_POOL.submit(() -> ParallelAggregation.or(input)).join());
   }
 
   @Test
   public void hugeOrInFJP2() {
-    RoaringBitmap[] input = IntStream.range(0, 2000)
+    RoaringBitmap[] input =
+        IntStream.range(0, 2000)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
-    assertEquals(FastAggregation.or(input),
-            POOL.submit(() -> ParallelAggregation.or(input)).join());
+    assertEquals(
+        FastAggregation.or(input), POOL.submit(() -> ParallelAggregation.or(input)).join());
   }
 
   @Test
   public void hugeOrInFJP3() {
-    RoaringBitmap[] input = IntStream.range(0, 4096)
+    RoaringBitmap[] input =
+        IntStream.range(0, 4096)
             .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())
             .toArray(RoaringBitmap[]::new);
-    assertEquals(FastAggregation.or(input),
-            POOL.submit(() -> ParallelAggregation.or(input)).join());
+    assertEquals(
+        FastAggregation.or(input), POOL.submit(() -> ParallelAggregation.or(input)).join());
   }
 
   @Test
@@ -176,7 +188,6 @@ public void singleContainerXOR() {
     assertEquals(FastAggregation.xor(one, two, three), ParallelAggregation.xor(one, two, three));
   }
 
-
   @Test
   public void missingMiddleContainerXOR() {
     RoaringBitmap one = testCase().withRunAt(0).withBitmapAt(1).withArrayAt(2).build();
@@ -214,123 +225,216 @@ public void singleContainerOR_Buffer() {
     ImmutableRoaringBitmap one = testCase().withRunAt(0).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap two = testCase().withBitmapAt(0).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap three = testCase().withArrayAt(0).build().toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
+    assertEquals(
+        BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
   }
 
   @Test
   public void twoContainerOR_Buffer() {
-    ImmutableRoaringBitmap one = testCase().withRunAt(0).withArrayAt(1).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap one =
+        testCase().withRunAt(0).withArrayAt(1).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap two = testCase().withBitmapAt(1).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap three = testCase().withArrayAt(1).build().toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
+    assertEquals(
+        BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
   }
 
   @Test
   public void disjointOR_Buffer() {
-    ImmutableRoaringBitmap one = testCase().withRunAt(0).withArrayAt(2).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap one =
+        testCase().withRunAt(0).withArrayAt(2).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap two = testCase().withBitmapAt(1).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap three = testCase().withArrayAt(3).build().toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
+    assertEquals(
+        BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
   }
 
   @Test
   public void disjointBigKeysOR_Buffer() {
-    ImmutableRoaringBitmap one = testCase().withRunAt(0).withArrayAt(2).withBitmapAt((1 << 15) | 1).build()
-        .toMutableRoaringBitmap();
-    ImmutableRoaringBitmap two = testCase().withBitmapAt(1).withRunAt((1 << 15) | 2).build()
-        .toMutableRoaringBitmap();
-    ImmutableRoaringBitmap three = testCase().withArrayAt(3).withRunAt((1 << 15) | 3).build()
-        .toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
+    ImmutableRoaringBitmap one =
+        testCase()
+            .withRunAt(0)
+            .withArrayAt(2)
+            .withBitmapAt((1 << 15) | 1)
+            .build()
+            .toMutableRoaringBitmap();
+    ImmutableRoaringBitmap two =
+        testCase().withBitmapAt(1).withRunAt((1 << 15) | 2).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap three =
+        testCase().withArrayAt(3).withRunAt((1 << 15) | 3).build().toMutableRoaringBitmap();
+    assertEquals(
+        BufferFastAggregation.or(one, two, three), BufferParallelAggregation.or(one, two, three));
   }
 
   @Test
   public void wideOr_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 20)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 20)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
     assertEquals(BufferFastAggregation.or(input), BufferParallelAggregation.or(input));
   }
 
   @Test
   public void hugeOr1_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 513)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 513)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
     assertEquals(BufferFastAggregation.or(input), BufferParallelAggregation.or(input));
   }
 
-
   @Test
   public void hugeOr2_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 1999)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 1999)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
     assertEquals(BufferFastAggregation.or(input), BufferParallelAggregation.or(input));
   }
 
   @Test
   public void hugeOr3_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 4096)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 4096)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
     assertEquals(BufferFastAggregation.or(input), BufferParallelAggregation.or(input));
   }
 
   @Test
   public void hugeOrNoParallelismAvailable1_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 513)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
-    assertEquals(BufferFastAggregation.or(input),
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 513)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
+    assertEquals(
+        BufferFastAggregation.or(input),
         NO_PARALLELISM_AVAILABLE.submit(() -> BufferParallelAggregation.or(input)).join());
   }
 
-
   @Test
   public void hugeOrNoParallelismAvailable2_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 2000)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
-    assertEquals(BufferFastAggregation.or(input),
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 2000)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
+    assertEquals(
+        BufferFastAggregation.or(input),
         NO_PARALLELISM_AVAILABLE.submit(() -> BufferParallelAggregation.or(input)).join());
   }
 
   @Test
   public void hugeOrNoParallelismAvailable3_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 4096)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
-    assertEquals(BufferFastAggregation.or(input),
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 4096)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
+    assertEquals(
+        BufferFastAggregation.or(input),
         NO_PARALLELISM_AVAILABLE.submit(() -> BufferParallelAggregation.or(input)).join());
   }
 
-
   @Test
   public void hugeOrInFJP1_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 513)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
-    assertEquals(BufferFastAggregation.or(input),
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 513)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
+    assertEquals(
+        BufferFastAggregation.or(input),
         POOL.submit(() -> BufferParallelAggregation.or(input)).join());
   }
 
-
   @Test
   public void hugeOrInFJP2_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 2000)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
-    assertEquals(BufferFastAggregation.or(input),
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 2000)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
+    assertEquals(
+        BufferFastAggregation.or(input),
         POOL.submit(() -> BufferParallelAggregation.or(input)).join());
   }
 
   @Test
   public void hugeOrInFJP3_Buffer() {
-    ImmutableRoaringBitmap[] input = IntStream.range(0, 4096)
-        .mapToObj(i -> testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap())
-        .toArray(ImmutableRoaringBitmap[]::new);
-    assertEquals(BufferFastAggregation.or(input),
+    ImmutableRoaringBitmap[] input =
+        IntStream.range(0, 4096)
+            .mapToObj(
+                i ->
+                    testCase()
+                        .withBitmapAt(0)
+                        .withArrayAt(1)
+                        .withRunAt(2)
+                        .build()
+                        .toMutableRoaringBitmap())
+            .toArray(ImmutableRoaringBitmap[]::new);
+    assertEquals(
+        BufferFastAggregation.or(input),
         POOL.submit(() -> BufferParallelAggregation.or(input)).join());
   }
 
@@ -339,46 +443,56 @@ public void singleContainerXOR_Buffer() {
     ImmutableRoaringBitmap one = testCase().withRunAt(0).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap two = testCase().withBitmapAt(0).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap three = testCase().withArrayAt(0).build().toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
+    assertEquals(
+        BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
   }
 
-
   @Test
   public void missingMiddleContainerXOR_Buffer() {
-    ImmutableRoaringBitmap one = testCase().withRunAt(0).withBitmapAt(1).withArrayAt(2).build()
-        .toMutableRoaringBitmap();
-    ImmutableRoaringBitmap two = testCase().withBitmapAt(0).withArrayAt(2).build().toMutableRoaringBitmap();
-    ImmutableRoaringBitmap three = testCase().withArrayAt(0).withBitmapAt(1).withArrayAt(2).build()
-        .toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
+    ImmutableRoaringBitmap one =
+        testCase().withRunAt(0).withBitmapAt(1).withArrayAt(2).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap two =
+        testCase().withBitmapAt(0).withArrayAt(2).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap three =
+        testCase().withArrayAt(0).withBitmapAt(1).withArrayAt(2).build().toMutableRoaringBitmap();
+    assertEquals(
+        BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
   }
 
   @Test
   public void twoContainerXOR_Buffer() {
-    ImmutableRoaringBitmap one = testCase().withRunAt(0).withArrayAt(1).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap one =
+        testCase().withRunAt(0).withArrayAt(1).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap two = testCase().withBitmapAt(1).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap three = testCase().withArrayAt(1).build().toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
+    assertEquals(
+        BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
   }
 
   @Test
   public void disjointXOR_Buffer() {
-    ImmutableRoaringBitmap one = testCase().withRunAt(0).withArrayAt(2).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap one =
+        testCase().withRunAt(0).withArrayAt(2).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap two = testCase().withBitmapAt(1).build().toMutableRoaringBitmap();
     ImmutableRoaringBitmap three = testCase().withArrayAt(3).build().toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
+    assertEquals(
+        BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
   }
 
   @Test
   public void disjointBigKeysXOR_Buffer() {
-    ImmutableRoaringBitmap one = testCase().withRunAt(0).withArrayAt(2).withBitmapAt((1 << 15) | 1).build()
-        .toMutableRoaringBitmap();
-    ImmutableRoaringBitmap two = testCase().withBitmapAt(1).withRunAt((1 << 15) | 2).build()
-        .toMutableRoaringBitmap();
-    ImmutableRoaringBitmap three = testCase().withArrayAt(3).withRunAt((1 << 15) | 3).build()
-        .toMutableRoaringBitmap();
-    assertEquals(BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
+    ImmutableRoaringBitmap one =
+        testCase()
+            .withRunAt(0)
+            .withArrayAt(2)
+            .withBitmapAt((1 << 15) | 1)
+            .build()
+            .toMutableRoaringBitmap();
+    ImmutableRoaringBitmap two =
+        testCase().withBitmapAt(1).withRunAt((1 << 15) | 2).build().toMutableRoaringBitmap();
+    ImmutableRoaringBitmap three =
+        testCase().withArrayAt(3).withRunAt((1 << 15) | 3).build().toMutableRoaringBitmap();
+    assertEquals(
+        BufferFastAggregation.xor(one, two, three), BufferParallelAggregation.xor(one, two, three));
   }
-
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/PreviousValueTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/PreviousValueTest.java
similarity index 79%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/PreviousValueTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/PreviousValueTest.java
index 29af1a14e..41e3805d6 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/PreviousValueTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/PreviousValueTest.java
@@ -1,20 +1,25 @@
 package org.roaringbitmap;
 
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import org.roaringbitmap.buffer.MutableRoaringBitmap;
 
+import org.junit.jupiter.api.Test;
+
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.Arrays;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 public class PreviousValueTest {
   @Test
   public void regressionTest() throws IOException {
     int testValue = 1828834057;
-    String[] data = new String(Files.readAllBytes(Paths.get("src/test/resources/testdata/prevvalue-regression.txt"))).split(",");
+    String[] data =
+        new String(
+                Files.readAllBytes(
+                    Paths.get("src/test/resources/testdata/prevvalue-regression.txt")))
+            .split(",");
     RoaringBitmap bitmap = new RoaringBitmap();
     Arrays.stream(data).map(Integer::parseInt).forEach(bitmap::add);
     assertEquals(bitmap.last(), bitmap.previousValue(testValue));
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
similarity index 64%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
index bd8689ee5..62bf588e4 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
@@ -1,5 +1,15 @@
 package org.roaringbitmap;
 
+import static java.nio.ByteOrder.LITTLE_ENDIAN;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.RangeBitmapTest.Distribution.EXP;
+import static org.roaringbitmap.RangeBitmapTest.Distribution.NORMAL;
+import static org.roaringbitmap.RangeBitmapTest.Distribution.POINT;
+import static org.roaringbitmap.RangeBitmapTest.Distribution.UNIFORM;
+
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
@@ -9,7 +19,10 @@
 import org.junit.jupiter.params.provider.MethodSource;
 import org.junit.jupiter.params.provider.ValueSource;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -24,27 +37,37 @@
 import java.util.stream.LongStream;
 import java.util.stream.Stream;
 
-import static java.nio.ByteOrder.LITTLE_ENDIAN;
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.roaringbitmap.RangeBitmapTest.Distribution.EXP;
-import static org.roaringbitmap.RangeBitmapTest.Distribution.NORMAL;
-import static org.roaringbitmap.RangeBitmapTest.Distribution.POINT;
-import static org.roaringbitmap.RangeBitmapTest.Distribution.UNIFORM;
-
 /**
  * When contributing test, please be mindful of the computational requirements.
  * We can use fuzzers to hunt for difficult-to-find bugs, but we should not
  * abuse the continuous-integration infrastructure.
  */
-
 @Execution(ExecutionMode.CONCURRENT)
 public class RangeBitmapTest {
 
+  @Test
+  public void betweenRegressionTest() throws IOException {
+    String[] lines =
+        new String(
+                Files.readAllBytes(
+                    Paths.get("src/test/resources/testdata/rangebitmap_regression.txt")))
+            .split(",");
+    RangeBitmap.Appender appender = RangeBitmap.appender(2175288L);
+    for (String line : lines) {
+      appender.add(Long.parseLong(line));
+    }
+    RangeBitmap bitmap = appender.build();
+    for (int i = 0; i < 4; i++) {
+      long lowerTs = 263501 + i;
+      RoaringBitmap eqLower = bitmap.eq(lowerTs); // eq
+      RoaringBitmap eqUpper = bitmap.eq(lowerTs + 1); // eq
+      // [x,y] both inclusive, so it should be union of the two above
+      RoaringBitmap range = bitmap.between(lowerTs, lowerTs + 1);
+      assertEquals(RoaringBitmap.or(eqLower, eqUpper), range);
+    }
+  }
+
   @ParameterizedTest
-  @Disabled("expensive - run on an ad hoc basis")
   @ValueSource(ints = {0, 0xFFFF, 0x10001, 100_000, 0x110001, 1_000_000})
   public void testInsertContiguousValues(int size) {
     RangeBitmap.Appender appender = RangeBitmap.appender(size);
@@ -72,7 +95,6 @@ public void testInsertContiguousValues(int size) {
   }
 
   @ParameterizedTest
-  @Disabled("expensive - run on an ad hoc basis")
   @ValueSource(ints = {0, 0xFFFF, 0x10001, 100_000, 0x110001, 1_000_000})
   public void testInsertReversedContiguousValues(int size) {
     RangeBitmap.Appender appender = RangeBitmap.appender(size);
@@ -217,17 +239,22 @@ public void verifyBufferCleanerCalled() {
     AtomicInteger cleanerInvocations = new AtomicInteger();
     AtomicInteger supplierInvocations = new AtomicInteger();
     Consumer cleaner = buffer -> cleanerInvocations.incrementAndGet();
-    IntFunction supplier = capacity -> {
-      supplierInvocations.incrementAndGet();
-      return ByteBuffer.allocate(capacity).order(LITTLE_ENDIAN);
-    };
+    IntFunction supplier =
+        capacity -> {
+          supplierInvocations.incrementAndGet();
+          return ByteBuffer.allocate(capacity).order(LITTLE_ENDIAN);
+        };
     RangeBitmap.Appender appender = RangeBitmap.appender(1_000_000, supplier, cleaner);
     LongStream.range(0, 1_000_000).forEach(appender::add);
     ByteBuffer target = ByteBuffer.allocate(appender.serializedSizeInBytes());
     appender.serialize(target);
-    assertEquals(supplierInvocations.get() - 2, cleanerInvocations.get(),
+    assertEquals(
+        supplierInvocations.get() - 2,
+        cleanerInvocations.get(),
         "two internal buffers remain active and uncleaned at any time, the rest must be cleaned");
-    assertTrue(supplierInvocations.get() > 2, "this test requires more than 2 buffer allocations to ensure cleaning occurs");
+    assertTrue(
+        supplierInvocations.get() > 2,
+        "this test requires more than 2 buffer allocations to ensure cleaning occurs");
   }
 
   @Test
@@ -246,15 +273,17 @@ public void testSerializeBigSlices() {
     RangeBitmap.Appender appender = RangeBitmap.appender(-1L);
     IntStream.range(0, 1_000_000)
         .mapToDouble(i -> random.nextGaussian())
-        .mapToLong(value -> {
-          long bits = Double.doubleToLongBits(value);
-          if ((bits & Long.MIN_VALUE) == Long.MIN_VALUE) {
-            bits = bits == Long.MIN_VALUE ? Long.MIN_VALUE : ~bits;
-          } else {
-            bits ^= Long.MIN_VALUE;
-          }
-          return bits;
-        }).forEach(appender::add);
+        .mapToLong(
+            value -> {
+              long bits = Double.doubleToLongBits(value);
+              if ((bits & Long.MIN_VALUE) == Long.MIN_VALUE) {
+                bits = bits == Long.MIN_VALUE ? Long.MIN_VALUE : ~bits;
+              } else {
+                bits ^= Long.MIN_VALUE;
+              }
+              return bits;
+            })
+        .forEach(appender::add);
     ByteBuffer buffer = ByteBuffer.allocate(appender.serializedSizeInBytes());
     appender.serialize(buffer);
     buffer.flip();
@@ -264,11 +293,27 @@ public void testSerializeBigSlices() {
   }
 
   @ParameterizedTest
-  @ValueSource(longs = {1L, 0xFL, 0xFFL, 0xFFFL, 0xFFFFL, 
-      0xFFFFFL, 0xFFFFFFL, 0xFFFFFFL, 0xFFFFFFFL, 0xFFFFFFFFL,
-      0xFFFFFFFFFL, 0xFFFFFFFFFFL, 0xFFFFFFFFFFFL,
-      0xFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFL,  0xFFFFFFFFFFFFFFL,
-      0xFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL})
+  @ValueSource(
+      longs = {
+        1L,
+        0xFL,
+        0xFFL,
+        0xFFFL,
+        0xFFFFL,
+        0xFFFFFL,
+        0xFFFFFFL,
+        0xFFFFFFL,
+        0xFFFFFFFL,
+        0xFFFFFFFFL,
+        0xFFFFFFFFFL,
+        0xFFFFFFFFFFL,
+        0xFFFFFFFFFFFL,
+        0xFFFFFFFFFFFFL,
+        0xFFFFFFFFFFFFFL,
+        0xFFFFFFFFFFFFFFL,
+        0xFFFFFFFFFFFFFFFL,
+        0xFFFFFFFFFFFFFFFFL
+      })
   public void testSerializeEmpty(long maxValue) {
     RangeBitmap.Appender appender = RangeBitmap.appender(maxValue);
     ByteBuffer buffer = ByteBuffer.allocate(appender.serializedSizeInBytes());
@@ -281,7 +326,6 @@ public void testSerializeEmpty(long maxValue) {
 
   @ParameterizedTest
   @MethodSource("distributions")
-  @Disabled("expensive - run on an ad hoc basis")
   public void testAppenderReuseAfterClear(LongSupplier dist) {
     RangeBitmap.Appender appender = RangeBitmap.appender(10_000_000);
     long[] values = new long[100_000];
@@ -308,7 +352,6 @@ public void testAppenderReuseAfterClear(LongSupplier dist) {
 
   @ParameterizedTest
   @MethodSource("distributions")
-  @Disabled("expensive - run on an ad hoc basis")
   public void testConstructRelativeToMinValue(LongSupplier dist) {
     int[] values = IntStream.range(0, 1_000_000).map(i -> (int) dist.getAsLong()).toArray();
     int min = IntStream.of(values).min().orElse(0);
@@ -324,143 +367,189 @@ public void testConstructRelativeToMinValue(LongSupplier dist) {
 
   public static Stream distributions() {
     return Stream.of(
-        NORMAL.of(42, 1_000, 100),
-        NORMAL.of(42, 10_000, 10),
-        NORMAL.of(42, 1_000_000, 1000),
-        UNIFORM.of(42, 0, 1_000_000),
-        UNIFORM.of(42, 500_000, 10_000_000),
-        EXP.of(42, 0.0001),
-        EXP.of(42, 0.9999),
-        POINT.of(0, 0),
-        POINT.of(0, 1),
-        POINT.of(0, 2),
-        POINT.of(0, 3),
-        POINT.of(0, 4),
-        POINT.of(0, 7),
-        POINT.of(0, 8),
-        POINT.of(0, 15),
-        POINT.of(0, 31),
-        POINT.of(0, Long.MAX_VALUE)
-    ).map(Arguments::of);
+            NORMAL.of(42, 1_000, 100),
+            NORMAL.of(42, 10_000, 10),
+            NORMAL.of(42, 1_000_000, 1000),
+            UNIFORM.of(42, 0, 1_000_000),
+            UNIFORM.of(42, 500_000, 10_000_000),
+            EXP.of(42, 0.0001),
+            EXP.of(42, 0.9999),
+            POINT.of(0, 0),
+            POINT.of(0, 1),
+            POINT.of(0, 2),
+            POINT.of(0, 3),
+            POINT.of(0, 4),
+            POINT.of(0, 7),
+            POINT.of(0, 8),
+            POINT.of(0, 15),
+            POINT.of(0, 31),
+            POINT.of(0, Long.MAX_VALUE))
+        .map(Arguments::of);
   }
 
   @ParameterizedTest
   @MethodSource("distributions")
-  @Disabled("expensive - run on an ad hoc basis")
   public void testAgainstReferenceImplementation(LongSupplier dist) {
     long maxValue = 10_000_000;
     ReferenceImplementation.Builder builder = ReferenceImplementation.builder();
     RangeBitmap.Appender appender = RangeBitmap.appender(maxValue);
     LongStream.range(0, 1_000_000)
         .map(i -> Math.min(dist.getAsLong(), maxValue))
-        .forEach(v -> {
-          builder.add(v);
-          appender.add(v);
-        });
+        .forEach(
+            v -> {
+              builder.add(v);
+              appender.add(v);
+            });
     ReferenceImplementation referenceImplementation = builder.seal();
     RangeBitmap sut = appender.build();
-    assertAll(LongStream.range(0, 7)
-        .map(i -> (long) Math.pow(10, i))
-        .mapToObj(threshold -> () -> {
-          assertEquals(referenceImplementation.lessThanOrEqualTo(threshold), sut.lte(threshold));
-          assertEquals(referenceImplementation.lessThanOrEqualTo(threshold).getCardinality(), sut.lteCardinality(threshold));
-        }));
+    assertAll(
+        LongStream.range(0, 7)
+            .map(i -> (long) Math.pow(10, i))
+            .mapToObj(
+                threshold ->
+                    () -> {
+                      assertEquals(
+                          referenceImplementation.lessThanOrEqualTo(threshold), sut.lte(threshold));
+                      assertEquals(
+                          referenceImplementation.lessThanOrEqualTo(threshold).getCardinality(),
+                          sut.lteCardinality(threshold));
+                    }));
   }
 
   @ParameterizedTest
   @MethodSource("distributions")
   @SuppressWarnings("unchecked")
-  @Disabled("expensive - run on an ad hoc basis")
   public void testAgainstPrecomputed(LongSupplier dist) {
     long maxValue = 10_000_000;
     ReferenceImplementation.Builder builder = ReferenceImplementation.builder();
     RangeBitmap.Appender appender = RangeBitmap.appender(maxValue);
     RoaringBitmapWriter[] recorders =
-        LongStream.range(0, 7).map(i -> (long) Math.pow(10, i)).mapToObj(i -> RoaringBitmapWriter.writer().runCompress(true).get()).toArray(RoaringBitmapWriter[]::new);
+        LongStream.range(0, 7)
+            .map(i -> (long) Math.pow(10, i))
+            .mapToObj(i -> RoaringBitmapWriter.writer().runCompress(true).get())
+            .toArray(RoaringBitmapWriter[]::new);
     LongStream.range(0, 1_000_000)
-        .forEach(i -> {
-          long v = Math.min(dist.getAsLong(), maxValue);
-          for (int p = 0; p < 7; ++p) {
-            if (v <= (long) Math.pow(10, p)) {
-              recorders[p].add((int) i);
-            }
-          }
-          builder.add(v);
-          appender.add(v);
-        });
-    RoaringBitmap[] precomputed = Arrays.stream(recorders).map(RoaringBitmapWriter::get).toArray(RoaringBitmap[]::new);
+        .forEach(
+            i -> {
+              long v = Math.min(dist.getAsLong(), maxValue);
+              for (int p = 0; p < 7; ++p) {
+                if (v <= (long) Math.pow(10, p)) {
+                  recorders[p].add((int) i);
+                }
+              }
+              builder.add(v);
+              appender.add(v);
+            });
+    RoaringBitmap[] precomputed =
+        Arrays.stream(recorders).map(RoaringBitmapWriter::get).toArray(RoaringBitmap[]::new);
     RoaringBitmap all = RoaringBitmap.bitmapOfRange(0, 1_000_000);
     RangeBitmap sut = appender.build();
-    assertAll(IntStream.range(0, 7).mapToObj(i -> () -> {
-      assertEquals(precomputed[i], sut.lte((long) Math.pow(10, i)));
-      assertEquals(precomputed[i].getCardinality(), sut.lteCardinality((long) Math.pow(10, i)));
-    }));
-    assertAll(IntStream.range(0, 7).mapToObj(i -> () -> {
-      assertEquals(all, RoaringBitmap.or((sut.lte((long) Math.pow(10, i))), sut.gt((long) Math.pow(10, i))));
-      assertEquals(all.getCardinality(), sut.lteCardinality((long) Math.pow(10, i)) + sut.gtCardinality((long) Math.pow(10, i)));
-    }));
-    assertAll(IntStream.range(0, 7).mapToObj(i -> () -> {
-      assertEquals(all, RoaringBitmap.or((sut.lt((long) Math.pow(10, i))), sut.gte((long) Math.pow(10, i))));
-      assertEquals(all.getCardinality(), sut.ltCardinality((long) Math.pow(10, i)) + sut.gteCardinality((long) Math.pow(10, i)));
-    }));
-    assertAll(IntStream.range(0, 7).mapToObj(i -> () -> {
-      assertEquals(RoaringBitmap.andNot(all, precomputed[i]), sut.gt((long) Math.pow(10, i)));
-      assertEquals(RoaringBitmap.andNot(all, precomputed[i]).getCardinality(), sut.gtCardinality((long) Math.pow(10, i)));
-    }));
+    assertAll(
+        IntStream.range(0, 7)
+            .mapToObj(
+                i ->
+                    () -> {
+                      assertEquals(precomputed[i], sut.lte((long) Math.pow(10, i)));
+                      assertEquals(
+                          precomputed[i].getCardinality(),
+                          sut.lteCardinality((long) Math.pow(10, i)));
+                    }));
+    assertAll(
+        IntStream.range(0, 7)
+            .mapToObj(
+                i ->
+                    () -> {
+                      assertEquals(
+                          all,
+                          RoaringBitmap.or(
+                              (sut.lte((long) Math.pow(10, i))), sut.gt((long) Math.pow(10, i))));
+                      assertEquals(
+                          all.getCardinality(),
+                          sut.lteCardinality((long) Math.pow(10, i))
+                              + sut.gtCardinality((long) Math.pow(10, i)));
+                    }));
+    assertAll(
+        IntStream.range(0, 7)
+            .mapToObj(
+                i ->
+                    () -> {
+                      assertEquals(
+                          all,
+                          RoaringBitmap.or(
+                              (sut.lt((long) Math.pow(10, i))), sut.gte((long) Math.pow(10, i))));
+                      assertEquals(
+                          all.getCardinality(),
+                          sut.ltCardinality((long) Math.pow(10, i))
+                              + sut.gteCardinality((long) Math.pow(10, i)));
+                    }));
+    assertAll(
+        IntStream.range(0, 7)
+            .mapToObj(
+                i ->
+                    () -> {
+                      assertEquals(
+                          RoaringBitmap.andNot(all, precomputed[i]),
+                          sut.gt((long) Math.pow(10, i)));
+                      assertEquals(
+                          RoaringBitmap.andNot(all, precomputed[i]).getCardinality(),
+                          sut.gtCardinality((long) Math.pow(10, i)));
+                    }));
   }
 
-
   @ParameterizedTest
   @MethodSource("distributions")
-  @Disabled("expensive - run on an ad hoc basis")
   public void testContextualRangeEvaluationAgainstNonContextual(LongSupplier dist) {
     long maxValue = 10_000_000;
     RangeBitmap.Appender appender = RangeBitmap.appender(maxValue);
     LongStream.range(0, 1_000_000)
-        .forEach(i -> {
-          long v = Math.min(dist.getAsLong(), maxValue);
-          appender.add(v);
-        });
+        .forEach(
+            i -> {
+              long v = Math.min(dist.getAsLong(), maxValue);
+              appender.add(v);
+            });
     RangeBitmap sut = appender.build();
-    IntStream.range(1, 8).forEach(i -> {
-      long min = (long) Math.pow(10, i - 1);
-      long max = (long) Math.pow(10, i);
-      RoaringBitmap lte = sut.lte(max);
-      RoaringBitmap gte = sut.gte(min);
-      RoaringBitmap expected = RoaringBitmap.and(lte, gte);
-      assertEquals(expected, sut.gte(min, lte));
-      assertEquals(expected.getCardinality(), sut.gteCardinality(min, lte), "" + i);
-      assertEquals(expected, sut.lte(max, gte));
-      assertEquals(expected.getCardinality(), sut.lteCardinality(max, gte));
-      assertEquals(expected, sut.lt(max + 1, gte));
-      assertEquals(expected.getCardinality(), sut.ltCardinality(max + 1, gte));
-      assertEquals(expected, sut.gt(min - 1, lte));
-      assertEquals(expected.getCardinality(), sut.gtCardinality(min - 1, lte));
-    });
+    IntStream.range(1, 8)
+        .forEach(
+            i -> {
+              long min = (long) Math.pow(10, i - 1);
+              long max = (long) Math.pow(10, i);
+              RoaringBitmap lte = sut.lte(max);
+              RoaringBitmap gte = sut.gte(min);
+              RoaringBitmap expected = RoaringBitmap.and(lte, gte);
+              assertEquals(expected, sut.gte(min, lte));
+              assertEquals(expected.getCardinality(), sut.gteCardinality(min, lte), "" + i);
+              assertEquals(expected, sut.lte(max, gte));
+              assertEquals(expected.getCardinality(), sut.lteCardinality(max, gte));
+              assertEquals(expected, sut.lt(max + 1, gte));
+              assertEquals(expected.getCardinality(), sut.ltCardinality(max + 1, gte));
+              assertEquals(expected, sut.gt(min - 1, lte));
+              assertEquals(expected.getCardinality(), sut.gtCardinality(min - 1, lte));
+            });
   }
 
-
   @ParameterizedTest
   @MethodSource("distributions")
-  @Disabled("expensive - run on an ad hoc basis")
   public void testDoubleEndedRangeEvaluationAgainstNonContextual(LongSupplier dist) {
     long maxValue = 10_000_000;
     RangeBitmap.Appender appender = RangeBitmap.appender(maxValue);
     LongStream.range(0, 1_000_000)
-        .forEach(i -> {
-          long v = Math.min(dist.getAsLong(), maxValue);
-          appender.add(v);
-        });
+        .forEach(
+            i -> {
+              long v = Math.min(dist.getAsLong(), maxValue);
+              appender.add(v);
+            });
     RangeBitmap sut = appender.build();
-    IntStream.range(1, 8).forEach(i -> {
-      long min = (long) Math.pow(10, i - 1);
-      long max = (long) Math.pow(10, i);
-      RoaringBitmap lte = sut.lte(max);
-      RoaringBitmap gte = sut.gte(min);
-      RoaringBitmap expected = RoaringBitmap.and(lte, gte);
-      assertEquals(expected, sut.between(min, max));
-      assertEquals(expected.getCardinality(), sut.betweenCardinality(min, max));
-    });
+    IntStream.range(1, 8)
+        .forEach(
+            i -> {
+              long min = (long) Math.pow(10, i - 1);
+              long max = (long) Math.pow(10, i);
+              RoaringBitmap lte = sut.lte(max);
+              RoaringBitmap gte = sut.gte(min);
+              RoaringBitmap expected = RoaringBitmap.and(lte, gte);
+              assertEquals(expected, sut.between(min, max));
+              assertEquals(expected.getCardinality(), sut.betweenCardinality(min, max));
+            });
   }
 
   @Test
@@ -501,117 +590,292 @@ public void testBetween2() {
     assertEquals(7, sut.betweenCardinality(2, 8));
     assertEquals(RoaringBitmap.bitmapOfRange(3, 8), sut.between(3, 7));
     assertEquals(5, sut.betweenCardinality(3, 7));
-    assertEquals(RoaringBitmap.bitmapOfRange(0x10000 - 5, 0x10000 + 6), sut.between(0x10000 - 5, 0x10000 + 5));
+    assertEquals(
+        RoaringBitmap.bitmapOfRange(0x10000 - 5, 0x10000 + 6),
+        sut.between(0x10000 - 5, 0x10000 + 5));
     assertEquals(11, RoaringBitmap.bitmapOfRange(0x10000 - 5, 0x10000 + 6).getCardinality());
     assertEquals(11, sut.betweenCardinality(0x10000 - 5, 0x10000 + 5));
   }
 
   @Test
   public void testBetween3() {
-    long[] values = {-4616189618054758400L, 4601552919265804287L, -4586634745500139520L, 4571364728013586431L};
+    long[] values = {
+      -4616189618054758400L, 4601552919265804287L, -4586634745500139520L, 4571364728013586431L
+    };
     RangeBitmap.Appender appender = RangeBitmap.appender(-4586634745500139520L);
     Arrays.stream(values).forEach(appender::add);
     int numSequentialValues = 1 << 20;
     LongStream.range(0, numSequentialValues).forEach(appender::add);
     RangeBitmap sut = appender.build();
     RoaringBitmap sequentialValues = RoaringBitmap.bitmapOfRange(4, numSequentialValues + 4);
-    assertEquals(RoaringBitmap.bitmapOf(0), sut.between(-4620693217682128896L, -4616189618054758400L));
+    assertEquals(
+        RoaringBitmap.bitmapOf(0), sut.between(-4620693217682128896L, -4616189618054758400L));
     assertEquals(1, sut.betweenCardinality(-4620693217682128896L, -4616189618054758400L));
     assertEquals(RoaringBitmap.bitmapOfRange(5, 47), sut.between(1, 42));
     assertEquals(42, sut.betweenCardinality(1, 42));
-    assertEquals(RoaringBitmap.or(RoaringBitmap.bitmapOf(3), sequentialValues), sut.between(0, 4571364728013586431L));
-    assertEquals(RoaringBitmap.or(RoaringBitmap.bitmapOf(3), sequentialValues).getCardinality(), sut.betweenCardinality(0, 4571364728013586431L));
-    assertEquals(RoaringBitmap.or(RoaringBitmap.bitmapOf(1, 3), sequentialValues), sut.between(0, 4601552919265804287L));
-    assertEquals(RoaringBitmap.or(RoaringBitmap.bitmapOf(1, 3), sequentialValues).getCardinality(), sut.betweenCardinality(0, 4601552919265804287L));
+    assertEquals(
+        RoaringBitmap.or(RoaringBitmap.bitmapOf(3), sequentialValues),
+        sut.between(0, 4571364728013586431L));
+    assertEquals(
+        RoaringBitmap.or(RoaringBitmap.bitmapOf(3), sequentialValues).getCardinality(),
+        sut.betweenCardinality(0, 4571364728013586431L));
+    assertEquals(
+        RoaringBitmap.or(RoaringBitmap.bitmapOf(1, 3), sequentialValues),
+        sut.between(0, 4601552919265804287L));
+    assertEquals(
+        RoaringBitmap.or(RoaringBitmap.bitmapOf(1, 3), sequentialValues).getCardinality(),
+        sut.betweenCardinality(0, 4601552919265804287L));
     assertEquals(RoaringBitmap.bitmapOf(0), sut.between(Long.MAX_VALUE, -4616189618054758400L));
     assertEquals(1, sut.betweenCardinality(Long.MAX_VALUE, -4616189618054758400L));
     assertEquals(RoaringBitmap.bitmapOf(0, 2), sut.between(Long.MAX_VALUE, -4586634745500139520L));
     assertEquals(2, sut.betweenCardinality(Long.MAX_VALUE, -4586634745500139520L));
-    assertEquals(RoaringBitmap.bitmapOfRange(0, numSequentialValues + 4), sut.between(0, 0xFFFFFFFFFFFFFFFFL));
-    assertEquals(RoaringBitmap.bitmapOfRange(0, numSequentialValues + 4).getCardinality(), sut.betweenCardinality(0, 0xFFFFFFFFFFFFFFFFL));
-    assertEquals(RoaringBitmap.bitmapOfRange(0, 4), sut.between(4571364728013586431L, -4586634745500139520L));
+    assertEquals(
+        RoaringBitmap.bitmapOfRange(0, numSequentialValues + 4),
+        sut.between(0, 0xFFFFFFFFFFFFFFFFL));
+    assertEquals(
+        RoaringBitmap.bitmapOfRange(0, numSequentialValues + 4).getCardinality(),
+        sut.betweenCardinality(0, 0xFFFFFFFFFFFFFFFFL));
+    assertEquals(
+        RoaringBitmap.bitmapOfRange(0, 4),
+        sut.between(4571364728013586431L, -4586634745500139520L));
     assertEquals(4, sut.betweenCardinality(4571364728013586431L, -4586634745500139520L));
     assertEquals(RoaringBitmap.bitmapOf(0, 2), sut.between(Long.MAX_VALUE, 0xFFFFFFFFFFFFFFFFL));
     assertEquals(2, sut.betweenCardinality(Long.MAX_VALUE, 0xFFFFFFFFFFFFFFFFL));
-    assertEquals(RoaringBitmap.or(RoaringBitmap.bitmapOf(1, 3), sequentialValues), sut.between(0, Long.MAX_VALUE));
-    assertEquals(RoaringBitmap.orCardinality(RoaringBitmap.bitmapOf(1, 3), sequentialValues), sut.betweenCardinality(0, Long.MAX_VALUE));
+    assertEquals(
+        RoaringBitmap.or(RoaringBitmap.bitmapOf(1, 3), sequentialValues),
+        sut.between(0, Long.MAX_VALUE));
+    assertEquals(
+        RoaringBitmap.orCardinality(RoaringBitmap.bitmapOf(1, 3), sequentialValues),
+        sut.betweenCardinality(0, Long.MAX_VALUE));
     assertEquals(new RoaringBitmap(), sut.between(-42, 0xFFFFFFFFFFFFFFFFL));
     assertEquals(0, sut.betweenCardinality(-42, 0xFFFFFFFFFFFFFFFFL));
   }
 
   @Test
   public void testBetween4() {
-    long[] values = {-4616189618054758400L, 4601552919265804287L, -4586634745500139520L, 4571364728013586431L,
-        -4556648864387432448L, 4541763675970600959L, -4526534890170089472L, 4511741717132607487L,
-        -4496888740970496000L, 4481700220488384511L, -4466831549978902528L, 4452010031096791039L,
-        -4436860832214679552L, 4421918433705197567L, -4407127634823086080L, 4392016835940974591L,
-        -4377002437431492608L, 4362241638549381119L, -4347168339667269632L, 4332083628657787647L,
-        -4317352126650676160L, 4302315448862314671L, -4287162073302051438L, 4272459181524432137L,
-        -4257458266522935884L, 4242237835737300334L, -4227562883636919499L, 4212596893231971325L,
-        -4197310978827808127L, 4182663311568480478L, -4167731427214848790L, 4152444271493337051L,
-        -4137760542057730537L, 4122861964394837603L, -4107616442036749309L, 4092854650044723837L,
-        -4077988598447005469L, 4062783733670385380L, -4047945708713107023L, 4033111420850910690L,
-        -4017946260743693147L, 4003033789531285016L, -3988230520942059423L, 3973104134926055302L,
-        -3958118962292622004L, 3943345985962156897L, -3928257465269603386L, 3913201295154700195L,
-        -3898457901108180877L, 3883406358270559600L, -3868280854677658470L, 3853566349580304959L,
-        -3838550917929140944L, 3823357705861632449L, -3808671412628698674L, 3793691245808059326L,
-        -3778431912183317079L, 3763773169599230700L, -3748827441089650601L, 3733522980173203346L,
-        -3718871697978100924L, 3703959600631664618L, -3688697178669147109L, 3673967073435426414L,
-        -3659087819021747723L, 3643866450725177229L, -3629059369867805881L, 3614212188630648294L,
-        -3599030911804729185L, 3584148659439886491L, -3569332799664175299L, 3554190674665064179L,
-        -3539235012624956505L, 3524449740213939054L, -3509345849420695115L, 3494318498244586478L,
-        -3479563096306902762L, 3464496543605325988L, -3449399183507341415L, 3434672951953772672L,
-        -3419642862232339617L, 3404477134046585572L, -3389779389196254110L, 3374784907853867652L,
-        -3359552413957401235L, 3344882488153199927L, -3329922780618476166L, 3314625085832642195L,
-        -3299982327065677369L, 3285056578327499206L, -3269777092125304377L, 3255078982340978658L,
-        -3240186396490052060L, 3224948363896921682L, -3210172528595600116L, 3195312328376755120L,
-        -3180114777823726749L, 3165263038697213921L, -3150434465072198619L, 3135276447761457361L,
-        -3120350583805656195L, 3105552895526177699L, -3090433484897357453L, 3075435233412954391L,
-        -3060667706603726686L, 3045585997812719925L, -3030517055382416577L, 3015778983133980657L,
-        -3000734092543963630L, 2985596115986804532L, -2970886807957891842L, 2955877872642278850L,
-        -2940672479945612186L, 2925991261974827647L, -2911017439231874848L, 2895746210461470323L,
-        -2881092424188076561L, 2866152891066862228L, -2850856174385872187L, 2836190371749287492L,
-        -2821284324586802134L, 2806029465354223306L, -2791285180001867583L, 2776411833970953486L,
-        -2761197851152838739L, 2746376922523362867L, -2731535511191248833L, 2716361446746634160L,
-        -2701465671166845646L, 2686655446064028545L, -2671520364406035042L, 2656551496101331837L,
-        -2641771726300562525L, 2626674713770128755L, -2611634465851251049L, 2596884437556387778L,
-        -2581824601908336563L, 2566714647334991567L, -2551993663479489668L, 2536970133380640164L,
-        -2521792105902541959L, 2507099485757353896L, -2492111410296396691L, 2476866905372250427L,
-        -2462201984162915723L, 2447248532371775213L, -2431939108066722645L, 2417301236599432233L,
-        -2402381596985847092L, 2387109747189393536L, -2372397319144302929L, 2357510699235361700L,
-        -2342280124069713038L, 2327490306091863256L, -2312635931988238351L, 2297445664079235090L,
-        -2282580269995175180L, 2267757385935804494L, -2252606480582119011L, 2237667281706838269L,
-        -2222875149643809597L, 2207762684285551627L, -2192751410418844296L, 2177989309602243369L,
-        -2162914383302020084L, 2147832723701497720L, -2133099950273986391L, 2118061683210125099L,
-        -2102911287541423996L, 2088207154142320474L, -2073204687113968945L, 2057987166378687038L,
-        -2043311001757325518L, 2028343495701151489L, -2013060423143036769L, 1998411571781188921L,
-        -1983478207299406984L, 1968189201417707433L, -1953508941032453066L, 1938608917931913404L,
-        -1923361588776766700L, 1908603184529225747L, -1893735721371305496L, 1878529092144433054L,
-        -1863694375531377859L, 1848858709192421875L, -1833691825989254769L, 1818782585581752070L,
-        -1803977970823815880L, 1788849902096923513L, -1773867884546405676L, 1759093593598059126L,
-        -1744003429633153813L, 1728950340653910252L, -1714205662800866089L, 1699152515205088754L,
-        -1684030020533730232L, 1669314261719067301L, -1654297262921266511L, 1639106989253701968L,
+    long[] values = {
+      -4616189618054758400L,
+      4601552919265804287L,
+      -4586634745500139520L,
+      4571364728013586431L,
+      -4556648864387432448L,
+      4541763675970600959L,
+      -4526534890170089472L,
+      4511741717132607487L,
+      -4496888740970496000L,
+      4481700220488384511L,
+      -4466831549978902528L,
+      4452010031096791039L,
+      -4436860832214679552L,
+      4421918433705197567L,
+      -4407127634823086080L,
+      4392016835940974591L,
+      -4377002437431492608L,
+      4362241638549381119L,
+      -4347168339667269632L,
+      4332083628657787647L,
+      -4317352126650676160L,
+      4302315448862314671L,
+      -4287162073302051438L,
+      4272459181524432137L,
+      -4257458266522935884L,
+      4242237835737300334L,
+      -4227562883636919499L,
+      4212596893231971325L,
+      -4197310978827808127L,
+      4182663311568480478L,
+      -4167731427214848790L,
+      4152444271493337051L,
+      -4137760542057730537L,
+      4122861964394837603L,
+      -4107616442036749309L,
+      4092854650044723837L,
+      -4077988598447005469L,
+      4062783733670385380L,
+      -4047945708713107023L,
+      4033111420850910690L,
+      -4017946260743693147L,
+      4003033789531285016L,
+      -3988230520942059423L,
+      3973104134926055302L,
+      -3958118962292622004L,
+      3943345985962156897L,
+      -3928257465269603386L,
+      3913201295154700195L,
+      -3898457901108180877L,
+      3883406358270559600L,
+      -3868280854677658470L,
+      3853566349580304959L,
+      -3838550917929140944L,
+      3823357705861632449L,
+      -3808671412628698674L,
+      3793691245808059326L,
+      -3778431912183317079L,
+      3763773169599230700L,
+      -3748827441089650601L,
+      3733522980173203346L,
+      -3718871697978100924L,
+      3703959600631664618L,
+      -3688697178669147109L,
+      3673967073435426414L,
+      -3659087819021747723L,
+      3643866450725177229L,
+      -3629059369867805881L,
+      3614212188630648294L,
+      -3599030911804729185L,
+      3584148659439886491L,
+      -3569332799664175299L,
+      3554190674665064179L,
+      -3539235012624956505L,
+      3524449740213939054L,
+      -3509345849420695115L,
+      3494318498244586478L,
+      -3479563096306902762L,
+      3464496543605325988L,
+      -3449399183507341415L,
+      3434672951953772672L,
+      -3419642862232339617L,
+      3404477134046585572L,
+      -3389779389196254110L,
+      3374784907853867652L,
+      -3359552413957401235L,
+      3344882488153199927L,
+      -3329922780618476166L,
+      3314625085832642195L,
+      -3299982327065677369L,
+      3285056578327499206L,
+      -3269777092125304377L,
+      3255078982340978658L,
+      -3240186396490052060L,
+      3224948363896921682L,
+      -3210172528595600116L,
+      3195312328376755120L,
+      -3180114777823726749L,
+      3165263038697213921L,
+      -3150434465072198619L,
+      3135276447761457361L,
+      -3120350583805656195L,
+      3105552895526177699L,
+      -3090433484897357453L,
+      3075435233412954391L,
+      -3060667706603726686L,
+      3045585997812719925L,
+      -3030517055382416577L,
+      3015778983133980657L,
+      -3000734092543963630L,
+      2985596115986804532L,
+      -2970886807957891842L,
+      2955877872642278850L,
+      -2940672479945612186L,
+      2925991261974827647L,
+      -2911017439231874848L,
+      2895746210461470323L,
+      -2881092424188076561L,
+      2866152891066862228L,
+      -2850856174385872187L,
+      2836190371749287492L,
+      -2821284324586802134L,
+      2806029465354223306L,
+      -2791285180001867583L,
+      2776411833970953486L,
+      -2761197851152838739L,
+      2746376922523362867L,
+      -2731535511191248833L,
+      2716361446746634160L,
+      -2701465671166845646L,
+      2686655446064028545L,
+      -2671520364406035042L,
+      2656551496101331837L,
+      -2641771726300562525L,
+      2626674713770128755L,
+      -2611634465851251049L,
+      2596884437556387778L,
+      -2581824601908336563L,
+      2566714647334991567L,
+      -2551993663479489668L,
+      2536970133380640164L,
+      -2521792105902541959L,
+      2507099485757353896L,
+      -2492111410296396691L,
+      2476866905372250427L,
+      -2462201984162915723L,
+      2447248532371775213L,
+      -2431939108066722645L,
+      2417301236599432233L,
+      -2402381596985847092L,
+      2387109747189393536L,
+      -2372397319144302929L,
+      2357510699235361700L,
+      -2342280124069713038L,
+      2327490306091863256L,
+      -2312635931988238351L,
+      2297445664079235090L,
+      -2282580269995175180L,
+      2267757385935804494L,
+      -2252606480582119011L,
+      2237667281706838269L,
+      -2222875149643809597L,
+      2207762684285551627L,
+      -2192751410418844296L,
+      2177989309602243369L,
+      -2162914383302020084L,
+      2147832723701497720L,
+      -2133099950273986391L,
+      2118061683210125099L,
+      -2102911287541423996L,
+      2088207154142320474L,
+      -2073204687113968945L,
+      2057987166378687038L,
+      -2043311001757325518L,
+      2028343495701151489L,
+      -2013060423143036769L,
+      1998411571781188921L,
+      -1983478207299406984L,
+      1968189201417707433L,
+      -1953508941032453066L,
+      1938608917931913404L,
+      -1923361588776766700L,
+      1908603184529225747L,
+      -1893735721371305496L,
+      1878529092144433054L,
+      -1863694375531377859L,
+      1848858709192421875L,
+      -1833691825989254769L,
+      1818782585581752070L,
+      -1803977970823815880L,
+      1788849902096923513L,
+      -1773867884546405676L,
+      1759093593598059126L,
+      -1744003429633153813L,
+      1728950340653910252L,
+      -1714205662800866089L,
+      1699152515205088754L,
+      -1684030020533730232L,
+      1669314261719067301L,
+      -1654297262921266511L,
+      1639106989253701968L,
     };
     RangeBitmap.Appender appender = RangeBitmap.appender(0xFFFFFFFFFFFFFFFFL);
     Arrays.stream(values).forEach(appender::add);
     RangeBitmap sut = appender.build();
-    assertEquals(RoaringBitmap.bitmapOf(0), sut.between(-4620693217682128896L, -4616189618054758400L));
+    assertEquals(
+        RoaringBitmap.bitmapOf(0), sut.between(-4620693217682128896L, -4616189618054758400L));
     assertEquals(1, sut.betweenCardinality(-4620693217682128896L, -4616189618054758400L));
   }
 
   @ParameterizedTest
   @MethodSource("distributions")
-  @Disabled("expensive - run on an ad hoc basis")
   public void testContextualBetweenCardinality(LongSupplier dist) {
     long maxValue = 10_000_000;
     RangeBitmap.Appender appender = RangeBitmap.appender(maxValue);
     long[] thresholds = new long[256];
     LongStream.range(0, 1_000_000)
-        .forEach(i -> {
-          long v = Math.min(dist.getAsLong(), maxValue);
-          thresholds[(int)i & 255] = v;
-          appender.add(v);
-        });
+        .forEach(
+            i -> {
+              long v = Math.min(dist.getAsLong(), maxValue);
+              thresholds[(int) i & 255] = v;
+              appender.add(v);
+            });
     RangeBitmap sut = appender.build();
     long numRows = sut.gteCardinality(0L);
     RoaringBitmap context = new RoaringBitmap();
@@ -621,7 +885,7 @@ public void testContextualBetweenCardinality(LongSupplier dist) {
     Arrays.sort(thresholds);
     for (int i = 0; i < thresholds.length; i += 2) {
       long min = thresholds[i];
-      long max = thresholds[i+1];
+      long max = thresholds[i + 1];
       long contextualCardinality = sut.betweenCardinality(min, max, context);
       RoaringBitmap bitmap = sut.between(min, max);
       bitmap.and(context);
@@ -689,26 +953,28 @@ public void testExtremeValues() {
   }
 
   // creates very large integer values so stresses edge cases in the top slice
-  private static final DoubleToLongFunction DOUBLE_ENCODER = value -> {
-    if (value == Double.NEGATIVE_INFINITY) {
-      return 0;
-    }
-    if (value == Double.POSITIVE_INFINITY || Double.isNaN(value)) {
-      return 0xFFFFFFFFFFFFFFFFL;
-    }
-    long bits = Double.doubleToLongBits(value);
-    if ((bits & Long.MIN_VALUE) == Long.MIN_VALUE) {
-      bits = bits == Long.MIN_VALUE ? Long.MIN_VALUE : ~bits;
-    } else {
-      bits ^= Long.MIN_VALUE;
-    }
-    return bits;
-  };
+  private static final DoubleToLongFunction DOUBLE_ENCODER =
+      value -> {
+        if (value == Double.NEGATIVE_INFINITY) {
+          return 0;
+        }
+        if (value == Double.POSITIVE_INFINITY || Double.isNaN(value)) {
+          return 0xFFFFFFFFFFFFFFFFL;
+        }
+        long bits = Double.doubleToLongBits(value);
+        if ((bits & Long.MIN_VALUE) == Long.MIN_VALUE) {
+          bits = bits == Long.MIN_VALUE ? Long.MIN_VALUE : ~bits;
+        } else {
+          bits ^= Long.MIN_VALUE;
+        }
+        return bits;
+      };
 
   @Test
   public void testIndexDoubleValues() {
     RangeBitmap.Appender appender = RangeBitmap.appender(-1L);
-    double[] doubles = IntStream.range(0, 200).mapToDouble(i -> Math.pow(-1, i) * Math.pow(10, i)).toArray();
+    double[] doubles =
+        IntStream.range(0, 200).mapToDouble(i -> Math.pow(-1, i) * Math.pow(10, i)).toArray();
     Arrays.stream(doubles).mapToLong(DOUBLE_ENCODER).forEach(appender::add);
     RangeBitmap bitmap = appender.build();
     for (double value : doubles) {
@@ -728,7 +994,8 @@ public void testIndexDoubleValues() {
   @Test
   public void testBetweenDoubleValues() {
     RangeBitmap.Appender appender = RangeBitmap.appender(-1L);
-    double[] doubles = IntStream.range(0, 200).mapToDouble(i -> Math.pow(-1, i) * Math.pow(10, i)).toArray();
+    double[] doubles =
+        IntStream.range(0, 200).mapToDouble(i -> Math.pow(-1, i) * Math.pow(10, i)).toArray();
     Arrays.stream(doubles).mapToLong(DOUBLE_ENCODER).forEach(appender::add);
     RangeBitmap bitmap = appender.build();
     for (double value : doubles) {
@@ -747,7 +1014,7 @@ public void testBetweenDoubleValues() {
   }
 
   @ParameterizedTest
-  @ValueSource(longs = {1, 2, 3, 4, 7, 8, 15, 16,  31, 32, 63, 64})
+  @ValueSource(longs = {1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64})
   public void extremelySmallBitmapTest(long value) {
     RangeBitmap.Appender accumulator = RangeBitmap.appender(value);
     accumulator.add(value);
@@ -760,7 +1027,7 @@ public void extremelySmallBitmapTest(long value) {
   }
 
   @ParameterizedTest
-  @ValueSource(longs = {1, 2, 3, 4, 7, 8, 15, 16,  31, 32, 63, 64})
+  @ValueSource(longs = {1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64})
   public void testModulo65536(long value) {
     int count = 65537;
     RangeBitmap.Appender accumulator = RangeBitmap.appender(value);
@@ -774,15 +1041,17 @@ public void testModulo65536(long value) {
     assertEquals(accumulator.build().between(value, value).getCardinality(), count);
     assertEquals(accumulator.build().betweenCardinality(value, value), count);
   }
+
   @Test
   public void regressionTestIssue586() {
     // see https://github.com/RoaringBitmap/RoaringBitmap/issues/586
     assertAll(
-            () -> regresssionTestIssue586(0x0FFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFF0L, 0xFFFFFFFFFFFFFF0L),
-            () -> regresssionTestIssue586(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF0L, 0xFFFFFFFFFFFFFFF0L),
-            () -> regresssionTestIssue586(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF1L, 0xFFFFFFFFFFFFFFF0L),
-            () -> regresssionTestIssue586(0, 10_000_000_000L, 10_000_000L)
-    );
+        () -> regresssionTestIssue586(0x0FFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFF0L, 0xFFFFFFFFFFFFFF0L),
+        () ->
+            regresssionTestIssue586(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF0L, 0xFFFFFFFFFFFFFFF0L),
+        () ->
+            regresssionTestIssue586(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF1L, 0xFFFFFFFFFFFFFFF0L),
+        () -> regresssionTestIssue586(0, 10_000_000_000L, 10_000_000L));
   }
 
   @Test
@@ -794,7 +1063,7 @@ public void regressionTestIssue588() {
 
     RoaringBitmap bitmap = RoaringBitmap.bitmapOf(valueInBitmap);
     assertTrue(bitmap.intersects(minValueThatWorks, baseValue));
-    assertTrue(bitmap.intersects(minValueThatWorks-1, baseValue));
+    assertTrue(bitmap.intersects(minValueThatWorks - 1, baseValue));
   }
 
   private static void regresssionTestIssue586(long low, long high, long value) {
@@ -836,15 +1105,18 @@ public void testEqWithContext(int max) {
     RangeBitmap bitmap = appender.build();
     for (int offset = 0; offset < max; offset++) {
       assertEquals(expected[offset], bitmap.eq(offset, expected[offset]));
-      assertEquals(expected[offset].getLongCardinality(), bitmap.eqCardinality(offset, expected[offset]));
+      assertEquals(
+          expected[offset].getLongCardinality(), bitmap.eqCardinality(offset, expected[offset]));
       assertTrue(bitmap.eq(offset, expected[(offset + 1) % max]).isEmpty());
       assertEquals(0L, bitmap.eqCardinality(offset, expected[(offset + 1) % max]));
       assertTrue(bitmap.eq(offset, new RoaringBitmap()).isEmpty());
       assertEquals(0L, bitmap.eqCardinality(offset, new RoaringBitmap()));
       assertTrue(bitmap.eq(offset, RoaringBitmap.bitmapOf(maxRow + 1)).isEmpty());
       assertEquals(0L, bitmap.eqCardinality(offset, RoaringBitmap.bitmapOf(maxRow + 1)));
-      RoaringBitmap overlapOnlyWithLast = RoaringBitmap.bitmapOfRange(expected[offset].last(), 2 * maxRow);
-      assertEquals(RoaringBitmap.bitmapOf(expected[offset].last()), bitmap.eq(offset, overlapOnlyWithLast));
+      RoaringBitmap overlapOnlyWithLast =
+          RoaringBitmap.bitmapOfRange(expected[offset].last(), 2 * maxRow);
+      assertEquals(
+          RoaringBitmap.bitmapOf(expected[offset].last()), bitmap.eq(offset, overlapOnlyWithLast));
       assertEquals(1L, bitmap.eqCardinality(offset, overlapOnlyWithLast));
     }
   }
@@ -886,7 +1158,8 @@ public void testNeqWithContext(int max) {
     RangeBitmap bitmap = appender.build();
     for (int offset = 0; offset < max; offset++) {
       assertEquals(expected[offset], bitmap.neq(offset, expected[offset]));
-      assertEquals(expected[offset].getLongCardinality(), bitmap.neqCardinality(offset, expected[offset]));
+      assertEquals(
+          expected[offset].getLongCardinality(), bitmap.neqCardinality(offset, expected[offset]));
       assertTrue(bitmap.neq(offset, new RoaringBitmap()).isEmpty());
       assertEquals(0L, bitmap.neqCardinality(offset, new RoaringBitmap()));
       assertTrue(bitmap.neq(offset, RoaringBitmap.bitmapOf(maxRow + 1)).isEmpty());
@@ -1048,10 +1321,67 @@ LongSupplier of(long seed, double... params) {
     POINT {
       @Override
       LongSupplier of(long seed, double... params) {
-        return () -> (long)params[0];
+        return () -> (long) params[0];
       }
     };
 
     abstract LongSupplier of(long seed, double... params);
   }
+
+  private static long rangeMaskOriginal(long maxValue) {
+    int lz = Long.numberOfLeadingZeros(maxValue | 1);
+    return lz == 0 ? -1L : (1L << (64 - lz)) - 1;
+  }
+
+  private static long rangeMaskOptimized(long maxValue) {
+    int lz = Long.numberOfLeadingZeros(maxValue | 1);
+    return -1L >>> lz;
+  }
+
+  @Test
+  public void rangeMaskRandom() {
+    Random r = new Random(0);
+    for (int i = 0; i < 10_000; i++) {
+      long value = r.nextLong();
+      assertEquals(rangeMaskOriginal(value), rangeMaskOptimized(value));
+    }
+  }
+
+  @Test
+  public void rangeMaskExpressionSimplification() {
+    for (int lz = 0; lz < 64; lz++) {
+      long original = lz == 0 ? -1L : (1L << (64 - lz)) - 1;
+      long simplified = -1L >>> lz;
+      assertEquals(Long.toBinaryString(original), Long.toBinaryString(simplified), "lz=" + lz);
+    }
+  }
+
+  private static long rangeMaskOriginal2(long sliceCount) {
+    return sliceCount == 64 ? -1L : (1L << sliceCount) - 1;
+  }
+
+  private static long rangeMaskSimplified2(long sliceCount) {
+    return -1L >>> (64 - sliceCount);
+  }
+
+  @Test
+  public void rangeMaskRandom2() {
+    Random r = new Random(0);
+    for (int i = 0; i < 10_000; i++) {
+      long value = (r.nextLong() & 63) + 1; // 1-64 are valid only
+      assertEquals(rangeMaskOriginal2(value), rangeMaskSimplified2(value), "" + value);
+    }
+  }
+
+  @Test
+  public void rangeMaskExpressionSimplification2() {
+    for (int sliceCount = 1; sliceCount <= 64; sliceCount++) {
+      long original = sliceCount == 64 ? -1L : (1L << sliceCount) - 1;
+      long simplified = -1L >>> (64 - sliceCount);
+      assertEquals(
+          Long.toBinaryString(original),
+          Long.toBinaryString(simplified),
+          "sliceCount=" + sliceCount);
+    }
+  }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringArrayTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringArrayTest.java
similarity index 84%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/RoaringArrayTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/RoaringArrayTest.java
index 99ff1c6c8..58ca04910 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringArrayTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringArrayTest.java
@@ -1,13 +1,13 @@
 package org.roaringbitmap;
 
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
 
+import org.junit.jupiter.api.Test;
 
 public class RoaringArrayTest {
 
-
   @Test
   public void whenAppendEmpty_ShouldBeUnchanged() {
     RoaringArray array = new RoaringArray();
@@ -47,12 +47,12 @@ public void whenAppendToEmpty_ShouldEqualAppendage() {
   public void whenAppendNonEmpty_SizeShouldEqualSumOfSizes() {
     RoaringArray array = new RoaringArray();
     array.size = 2;
-    array.keys = new char[]{0, 2, 0, 0};
+    array.keys = new char[] {0, 2, 0, 0};
     array.values = new Container[4];
 
     RoaringArray appendage = new RoaringArray();
     appendage.size = 3;
-    appendage.keys = new char[]{5, 6, 7, 0};
+    appendage.keys = new char[] {5, 6, 7, 0};
     appendage.values = new Container[4];
 
     array.append(appendage);
@@ -60,17 +60,16 @@ public void whenAppendNonEmpty_SizeShouldEqualSumOfSizes() {
     assertEquals(5, array.size);
   }
 
-
   @Test
   public void whenAppendNonEmpty_ResultantKeysShouldBeMonotonic() {
     RoaringArray array = new RoaringArray();
     array.size = 2;
-    array.keys = new char[]{0, 2, 0, 0};
+    array.keys = new char[] {0, 2, 0, 0};
     array.values = new Container[4];
 
     RoaringArray appendage = new RoaringArray();
     appendage.size = 3;
-    appendage.keys = new char[]{5, 6, 7, 0};
+    appendage.keys = new char[] {5, 6, 7, 0};
     appendage.values = new Container[4];
 
     array.append(appendage);
@@ -87,5 +86,4 @@ public void resizeOnlyIfNecessary() {
     array.extendArray(1);
     assertSame(keys, array.keys, "Keys were not reallocated");
   }
-
-}
\ No newline at end of file
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitSetTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitSetTest.java
new file mode 100644
index 000000000..01332c140
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitSetTest.java
@@ -0,0 +1,851 @@
+package org.roaringbitmap;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Random;
+
+// From https://github.com/openjdk/jdk/blob/master/test/jdk/java/util/BitSet/BSMethods.java
+@SuppressWarnings("all")
+public class RoaringBitSetTest {
+  private static Random generator = new Random();
+
+  @Test
+  public void testSetGetClearFlip() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet testSet = new RoaringBitSet();
+      HashSet history = new HashSet<>();
+
+      // Set a random number of bits in random places
+      // up to a random maximum
+      int nextBitToSet = 0;
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+      for (int x = 0; x < numberOfSetBits; x++) {
+        nextBitToSet = generator.nextInt(highestPossibleSetBit);
+        history.add(Integer.valueOf(nextBitToSet));
+        testSet.set(nextBitToSet);
+      }
+
+      // Make sure each bit is set appropriately
+      for (int x = 0; x < highestPossibleSetBit; x++) {
+        if (testSet.get(x) != history.contains(Integer.valueOf(x))) failCount++;
+      }
+
+      // Clear the bits
+      Iterator setBitIterator = history.iterator();
+      while (setBitIterator.hasNext()) {
+        Integer setBit = setBitIterator.next();
+        testSet.clear(setBit.intValue());
+      }
+
+      // Verify they were cleared
+      for (int x = 0; x < highestPossibleSetBit; x++) if (testSet.get(x)) failCount++;
+      if (testSet.length() != 0) failCount++;
+
+      // Set them with set(int, boolean)
+      setBitIterator = history.iterator();
+      while (setBitIterator.hasNext()) {
+        Integer setBit = setBitIterator.next();
+        testSet.set(setBit.intValue(), true);
+      }
+
+      // Make sure each bit is set appropriately
+      for (int x = 0; x < highestPossibleSetBit; x++) {
+        if (testSet.get(x) != history.contains(Integer.valueOf(x))) failCount++;
+      }
+
+      // Clear them with set(int, boolean)
+      setBitIterator = history.iterator();
+      while (setBitIterator.hasNext()) {
+        Integer setBit = setBitIterator.next();
+        testSet.set(setBit.intValue(), false);
+      }
+
+      // Verify they were cleared
+      for (int x = 0; x < highestPossibleSetBit; x++) if (testSet.get(x)) failCount++;
+      if (testSet.length() != 0) failCount++;
+
+      // Flip them on
+      setBitIterator = history.iterator();
+      while (setBitIterator.hasNext()) {
+        Integer setBit = setBitIterator.next();
+        testSet.flip(setBit.intValue());
+      }
+
+      // Verify they were flipped
+      for (int x = 0; x < highestPossibleSetBit; x++) {
+        if (testSet.get(x) != history.contains(Integer.valueOf(x))) failCount++;
+      }
+
+      // Flip them off
+      setBitIterator = history.iterator();
+      while (setBitIterator.hasNext()) {
+        Integer setBit = setBitIterator.next();
+        testSet.flip(setBit.intValue());
+      }
+
+      // Verify they were flipped
+      for (int x = 0; x < highestPossibleSetBit; x++) if (testSet.get(x)) failCount++;
+      if (testSet.length() != 0) failCount++;
+
+      checkSanity(testSet);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testClear() {
+    int failCount = 0;
+
+    for (int i = 0; i < 1000; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+
+      // Make a fairly random bitset
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+
+      for (int x = 0; x < numberOfSetBits; x++) b1.set(generator.nextInt(highestPossibleSetBit));
+
+      RoaringBitSet b2 = (RoaringBitSet) b1.clone();
+
+      // Clear out a random range
+      int rangeStart = generator.nextInt(100);
+      int rangeEnd = rangeStart + generator.nextInt(100);
+
+      // Use the clear(int, int) call on b1
+      b1.clear(rangeStart, rangeEnd);
+
+      // Use a loop on b2
+      for (int x = rangeStart; x < rangeEnd; x++) b2.clear(x);
+
+      // Verify their equality
+      if (!b1.equals(b2)) {
+        failCount++;
+      }
+      checkEquality(b1, b2);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testFlip() {
+    int failCount = 0;
+
+    for (int i = 0; i < 1000; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+
+      // Make a fairly random bitset
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+
+      for (int x = 0; x < numberOfSetBits; x++) b1.set(generator.nextInt(highestPossibleSetBit));
+
+      RoaringBitSet b2 = (RoaringBitSet) b1.clone();
+
+      // Flip a random range
+      int rangeStart = generator.nextInt(100);
+      int rangeEnd = rangeStart + generator.nextInt(100);
+
+      // Use the flip(int, int) call on b1
+      b1.flip(rangeStart, rangeEnd);
+
+      // Use a loop on b2
+      for (int x = rangeStart; x < rangeEnd; x++) b2.flip(x);
+
+      // Verify their equality
+      if (!b1.equals(b2)) failCount++;
+      checkEquality(b1, b2);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testSet() {
+    int failCount = 0;
+
+    // Test set(int, int)
+    for (int i = 0; i < 1000; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+
+      // Make a fairly random bitset
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+
+      for (int x = 0; x < numberOfSetBits; x++) b1.set(generator.nextInt(highestPossibleSetBit));
+
+      RoaringBitSet b2 = (RoaringBitSet) b1.clone();
+
+      // Set a random range
+      int rangeStart = generator.nextInt(100);
+      int rangeEnd = rangeStart + generator.nextInt(100);
+
+      // Use the set(int, int) call on b1
+      b1.set(rangeStart, rangeEnd);
+
+      // Use a loop on b2
+      for (int x = rangeStart; x < rangeEnd; x++) b2.set(x);
+
+      // Verify their equality
+      if (!b1.equals(b2)) {
+        failCount++;
+      }
+      checkEquality(b1, b2);
+    }
+
+    // Test set(int, int, boolean)
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+
+      // Make a fairly random bitset
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+
+      for (int x = 0; x < numberOfSetBits; x++) b1.set(generator.nextInt(highestPossibleSetBit));
+
+      RoaringBitSet b2 = (RoaringBitSet) b1.clone();
+      boolean setOrClear = generator.nextBoolean();
+
+      // Set a random range
+      int rangeStart = generator.nextInt(100);
+      int rangeEnd = rangeStart + generator.nextInt(100);
+
+      // Use the set(int, int, boolean) call on b1
+      b1.set(rangeStart, rangeEnd, setOrClear);
+
+      // Use a loop on b2
+      for (int x = rangeStart; x < rangeEnd; x++) b2.set(x, setOrClear);
+
+      // Verify their equality
+      if (!b1.equals(b2)) {
+        failCount++;
+      }
+      checkEquality(b1, b2);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testGet() {
+    int failCount = 0;
+
+    for (int i = 0; i < 1000; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+
+      // Make a fairly random bitset
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+
+      for (int x = 0; x < numberOfSetBits; x++) b1.set(generator.nextInt(highestPossibleSetBit));
+
+      // Get a new set from a random range
+      int rangeStart = generator.nextInt(100);
+      int rangeEnd = rangeStart + generator.nextInt(100);
+
+      RoaringBitSet b2 = (RoaringBitSet) b1.get(rangeStart, rangeEnd);
+
+      RoaringBitSet b3 = new RoaringBitSet();
+      for (int x = rangeStart; x < rangeEnd; x++) b3.set(x - rangeStart, b1.get(x));
+
+      // Verify their equality
+      if (!b2.equals(b3)) {
+        failCount++;
+      }
+      checkEquality(b2, b3);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testAndNot() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+
+      // Set some random bits in first set and remember them
+      for (int x = 0; x < 10; x++) b1.set(generator.nextInt(255));
+
+      // Set some random bits in second set and remember them
+      for (int x = 10; x < 20; x++) b2.set(generator.nextInt(255));
+
+      // andNot the sets together
+      RoaringBitSet b3 = (RoaringBitSet) b1.clone();
+      b3.andNot(b2);
+
+      // Examine each bit of b3 for errors
+      for (int x = 0; x < 256; x++) {
+        boolean bit1 = b1.get(x);
+        boolean bit2 = b2.get(x);
+        boolean bit3 = b3.get(x);
+        if (!(bit3 == (bit1 & (!bit2)))) failCount++;
+      }
+      checkSanity(b1, b2, b3);
+    }
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testAnd() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+
+      // Set some random bits in first set and remember them
+      for (int x = 0; x < 10; x++) b1.set(generator.nextInt(255));
+
+      // Set more random bits in second set and remember them
+      for (int x = 10; x < 20; x++) b2.set(generator.nextInt(255));
+
+      // And the sets together
+      RoaringBitSet b3 = (RoaringBitSet) b1.clone();
+      b3.and(b2);
+
+      // Examine each bit of b3 for errors
+      for (int x = 0; x < 256; x++) {
+        boolean bit1 = b1.get(x);
+        boolean bit2 = b2.get(x);
+        boolean bit3 = b3.get(x);
+        if (!(bit3 == (bit1 & bit2))) failCount++;
+      }
+      checkSanity(b1, b2, b3);
+    }
+
+    // `and' that happens to clear the last word
+    RoaringBitSet b4 = makeSet(2, 127);
+    b4.and(makeSet(2, 64));
+    checkSanity(b4);
+    if (!(b4.equals(makeSet(2)))) failCount++;
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testOr() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+      int[] history = new int[20];
+
+      // Set some random bits in first set and remember them
+      int nextBitToSet = 0;
+      for (int x = 0; x < 10; x++) {
+        nextBitToSet = generator.nextInt(255);
+        history[x] = nextBitToSet;
+        b1.set(nextBitToSet);
+      }
+
+      // Set more random bits in second set and remember them
+      for (int x = 10; x < 20; x++) {
+        nextBitToSet = generator.nextInt(255);
+        history[x] = nextBitToSet;
+        b2.set(nextBitToSet);
+      }
+
+      // Or the sets together
+      RoaringBitSet b3 = (RoaringBitSet) b1.clone();
+      b3.or(b2);
+
+      // Verify the set bits of b3 from the history
+      for (int x = 0; x < 20; x++) {
+        if (!b3.get(history[x])) failCount++;
+      }
+
+      // Examine each bit of b3 for errors
+      for (int x = 0; x < 256; x++) {
+        boolean bit1 = b1.get(x);
+        boolean bit2 = b2.get(x);
+        boolean bit3 = b3.get(x);
+        if (!(bit3 == (bit1 | bit2))) failCount++;
+      }
+      checkSanity(b1, b2, b3);
+    }
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testXor() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+
+      // Set some random bits in first set and remember them
+      for (int x = 0; x < 10; x++) b1.set(generator.nextInt(255));
+
+      // Set more random bits in second set and remember them
+      for (int x = 10; x < 20; x++) b2.set(generator.nextInt(255));
+
+      // Xor the sets together
+      RoaringBitSet b3 = (RoaringBitSet) b1.clone();
+      b3.xor(b2);
+
+      // Examine each bit of b3 for errors
+      for (int x = 0; x < 256; x++) {
+        boolean bit1 = b1.get(x);
+        boolean bit2 = b2.get(x);
+        boolean bit3 = b3.get(x);
+        if (!(bit3 == (bit1 ^ bit2))) failCount++;
+      }
+      checkSanity(b1, b2, b3);
+      b3.xor(b3);
+      checkEmpty(b3);
+    }
+
+    // xor that happens to clear the last word
+    RoaringBitSet b4 = makeSet(2, 64, 127);
+    b4.xor(makeSet(64, 127));
+    checkSanity(b4);
+    if (!(b4.equals(makeSet(2)))) failCount++;
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testLength() {
+    int failCount = 0;
+
+    // Test length after set
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      int highestSetBit = 0;
+
+      for (int x = 0; x < 100; x++) {
+        int nextBitToSet = generator.nextInt(255);
+        if (nextBitToSet > highestSetBit) highestSetBit = nextBitToSet;
+        b1.set(nextBitToSet);
+        if (b1.length() != highestSetBit + 1) failCount++;
+      }
+      checkSanity(b1);
+    }
+
+    // Test length after flip
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      for (int x = 0; x < 100; x++) {
+        // Flip a random range twice
+        int rangeStart = generator.nextInt(100);
+        int rangeEnd = rangeStart + generator.nextInt(100);
+        b1.flip(rangeStart);
+        b1.flip(rangeStart);
+        if (b1.length() != 0) failCount++;
+        b1.flip(rangeStart, rangeEnd);
+        b1.flip(rangeStart, rangeEnd);
+        if (b1.length() != 0) failCount++;
+      }
+      checkSanity(b1);
+    }
+
+    // Test length after or
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+      int bit1 = generator.nextInt(100);
+      int bit2 = generator.nextInt(100);
+      int highestSetBit = (bit1 > bit2) ? bit1 : bit2;
+      b1.set(bit1);
+      b2.set(bit2);
+      b1.or(b2);
+      if (b1.length() != highestSetBit + 1) failCount++;
+      checkSanity(b1, b2);
+    }
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testEquals() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      // Create BitSets of different sizes
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+
+      // Set some random bits
+      int nextBitToSet = 0;
+      for (int x = 0; x < 10; x++) {
+        nextBitToSet += generator.nextInt(50) + 1;
+        b1.set(nextBitToSet);
+        b2.set(nextBitToSet);
+      }
+
+      // Verify their equality despite different storage sizes
+      if (!b1.equals(b2)) failCount++;
+      checkEquality(b1, b2);
+    }
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testNextSetBit() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      RoaringBitSet testSet = new RoaringBitSet();
+      int[] history = new int[numberOfSetBits];
+
+      // Set some random bits and remember them
+      int nextBitToSet = 0;
+      for (int x = 0; x < numberOfSetBits; x++) {
+        nextBitToSet += generator.nextInt(30) + 1;
+        history[x] = nextBitToSet;
+        testSet.set(nextBitToSet);
+      }
+
+      // Verify their retrieval using nextSetBit()
+      int historyIndex = 0;
+      for (int x = testSet.nextSetBit(0); x >= 0; x = testSet.nextSetBit(x + 1)) {
+        if (x != history[historyIndex++]) failCount++;
+      }
+
+      checkSanity(testSet);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testNextClearBit() {
+    int failCount = 0;
+
+    for (int i = 0; i < 1000; i++) {
+      RoaringBitSet b = new RoaringBitSet();
+      int[] history = new int[10];
+
+      // Set all the bits
+      for (int x = 0; x < 256; x++) b.set(x);
+
+      // Clear some random bits and remember them
+      int nextBitToClear = 0;
+      for (int x = 0; x < 10; x++) {
+        nextBitToClear += generator.nextInt(24) + 1;
+        history[x] = nextBitToClear;
+        b.clear(nextBitToClear);
+      }
+
+      // Verify their retrieval using nextClearBit()
+      int historyIndex = 0;
+      for (int x = b.nextClearBit(0); x < 256; x = b.nextClearBit(x + 1)) {
+        if (x != history[historyIndex++]) failCount++;
+      }
+
+      checkSanity(b);
+    }
+
+    // regression test for 4350178
+    RoaringBitSet bs = new RoaringBitSet();
+    if (bs.nextClearBit(0) != 0) failCount++;
+    for (int i = 0; i < 64; i++) {
+      bs.set(i);
+      if (bs.nextClearBit(0) != i + 1) failCount++;
+    }
+
+    checkSanity(bs);
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testIntersects() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+
+      // Set some random bits in first set
+      int nextBitToSet = 0;
+      for (int x = 0; x < 30; x++) {
+        nextBitToSet = generator.nextInt(255);
+        b1.set(nextBitToSet);
+      }
+
+      // Set more random bits in second set
+      for (int x = 0; x < 30; x++) {
+        nextBitToSet = generator.nextInt(255);
+        b2.set(nextBitToSet);
+      }
+
+      // Make sure they intersect
+      nextBitToSet = generator.nextInt(255);
+      b1.set(nextBitToSet);
+      b2.set(nextBitToSet);
+
+      if (!b1.intersects(b2)) failCount++;
+
+      // Remove the common set bits
+      b1.andNot(b2);
+
+      // Make sure they don't intersect
+      if (b1.intersects(b2)) failCount++;
+
+      checkSanity(b1, b2);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testCardinality() {
+    int failCount = 0;
+
+    for (int i = 0; i < 100; i++) {
+      RoaringBitSet b1 = new RoaringBitSet();
+
+      // Set a random number of increasing bits
+      int nextBitToSet = 0;
+      int iterations = generator.nextInt(20) + 1;
+      for (int x = 0; x < iterations; x++) {
+        nextBitToSet += generator.nextInt(20) + 1;
+        b1.set(nextBitToSet);
+      }
+
+      if (b1.cardinality() != iterations) {
+        failCount++;
+      }
+
+      checkSanity(b1);
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testEmpty() {
+    int failCount = 0;
+
+    RoaringBitSet b1 = new RoaringBitSet();
+    if (!b1.isEmpty()) failCount++;
+
+    int nextBitToSet = 0;
+    int numberOfSetBits = generator.nextInt(100) + 1;
+    int highestPossibleSetBit = generator.nextInt(1000) + 1;
+    for (int x = 0; x < numberOfSetBits; x++) {
+      nextBitToSet = generator.nextInt(highestPossibleSetBit);
+      b1.set(nextBitToSet);
+      if (b1.isEmpty()) failCount++;
+      b1.clear(nextBitToSet);
+      if (!b1.isEmpty()) failCount++;
+    }
+
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  @Test
+  public void testEmpty2() {
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.set(100);
+      t.clear(3, 600);
+      checkEmpty(t);
+    }
+    checkEmpty(new RoaringBitSet());
+
+    RoaringBitSet s = new RoaringBitSet();
+    checkEmpty(s);
+    s.clear(92);
+    checkEmpty(s);
+    s.clear(127, 127);
+    checkEmpty(s);
+    s.set(127, 127);
+    checkEmpty(s);
+    s.set(128, 128);
+    checkEmpty(s);
+    RoaringBitSet empty = new RoaringBitSet();
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.and(empty);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.or(empty);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.xor(empty);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.andNot(empty);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.and(t);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.or(t);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.xor(t);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.andNot(t);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.and(makeSet(1));
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.and(makeSet(127));
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.and(makeSet(128));
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      t.flip(7);
+      t.flip(7);
+      checkEmpty(t);
+    }
+    {
+      RoaringBitSet t = new RoaringBitSet();
+      checkEmpty((RoaringBitSet) t.get(200, 300));
+    }
+    {
+      RoaringBitSet t = makeSet(2, 5);
+      Assertions.assertEquals(makeSet(0, 3), t.get(2, 6));
+    }
+  }
+
+  @Test
+  public void testLogicalIdentities() {
+    int failCount = 0;
+
+    // Verify that (!b1)|(!b2) == !(b1&b2)
+    for (int i = 0; i < 50; i++) {
+      // Construct two fairly random bitsets
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+
+      for (int x = 0; x < numberOfSetBits; x++) {
+        b1.set(generator.nextInt(highestPossibleSetBit));
+        b2.set(generator.nextInt(highestPossibleSetBit));
+      }
+
+      RoaringBitSet b3 = (RoaringBitSet) b1.clone();
+      RoaringBitSet b4 = (RoaringBitSet) b2.clone();
+
+      for (int x = 0; x < highestPossibleSetBit; x++) {
+        b1.flip(x);
+        b2.flip(x);
+      }
+      b1.or(b2);
+      b3.and(b4);
+      for (int x = 0; x < highestPossibleSetBit; x++) b3.flip(x);
+      if (!b1.equals(b3)) failCount++;
+      checkSanity(b1, b2, b3, b4);
+    }
+
+    // Verify that (b1&(!b2)|(b2&(!b1) == b1^b2
+    for (int i = 0; i < 50; i++) {
+      // Construct two fairly random bitsets
+      RoaringBitSet b1 = new RoaringBitSet();
+      RoaringBitSet b2 = new RoaringBitSet();
+
+      int numberOfSetBits = generator.nextInt(100) + 1;
+      int highestPossibleSetBit = generator.nextInt(1000) + 1;
+
+      for (int x = 0; x < numberOfSetBits; x++) {
+        b1.set(generator.nextInt(highestPossibleSetBit));
+        b2.set(generator.nextInt(highestPossibleSetBit));
+      }
+
+      RoaringBitSet b3 = (RoaringBitSet) b1.clone();
+      RoaringBitSet b4 = (RoaringBitSet) b2.clone();
+      RoaringBitSet b5 = (RoaringBitSet) b1.clone();
+      RoaringBitSet b6 = (RoaringBitSet) b2.clone();
+
+      for (int x = 0; x < highestPossibleSetBit; x++) b2.flip(x);
+      b1.and(b2);
+      for (int x = 0; x < highestPossibleSetBit; x++) b3.flip(x);
+      b3.and(b4);
+      b1.or(b3);
+      b5.xor(b6);
+      if (!b1.equals(b5)) failCount++;
+      checkSanity(b1, b2, b3, b4, b5, b6);
+    }
+    Assertions.assertEquals(failCount, 0);
+  }
+
+  private static void checkSanity(RoaringBitSet... sets) {
+    for (RoaringBitSet s : sets) {
+      int len = s.length();
+      int cardinality1 = s.cardinality();
+      int cardinality2 = 0;
+      for (int i = s.nextSetBit(0); i >= 0; i = s.nextSetBit(i + 1)) {
+        Assertions.assertTrue(s.get(i));
+        cardinality2++;
+      }
+      Assertions.assertEquals(s.nextSetBit(len), -1);
+      Assertions.assertEquals(len, s.nextClearBit(len));
+      Assertions.assertEquals((len == 0), s.isEmpty());
+      Assertions.assertEquals(cardinality2, cardinality1);
+      Assertions.assertTrue(len <= s.size());
+      Assertions.assertTrue(len >= 0);
+      Assertions.assertTrue(cardinality1 >= 0);
+    }
+  }
+
+  private static void checkEquality(RoaringBitSet s, RoaringBitSet t) {
+    checkSanity(s, t);
+    Assertions.assertEquals(t, s);
+    Assertions.assertEquals(t.toString(), s.toString());
+    Assertions.assertEquals(s.length(), t.length());
+    Assertions.assertEquals(s.cardinality(), t.cardinality());
+  }
+
+  private static RoaringBitSet makeSet(int... elts) {
+    RoaringBitSet s = new RoaringBitSet();
+    for (int elt : elts) s.set(elt);
+    return s;
+  }
+
+  private static void checkEmpty(RoaringBitSet s) {
+    Assertions.assertTrue(s.isEmpty());
+    Assertions.assertEquals(s.length(), 0);
+    Assertions.assertEquals(s.cardinality(), 0);
+    Assertions.assertEquals(s, new RoaringBitSet());
+    Assertions.assertEquals(s.nextSetBit(0), -1);
+    Assertions.assertEquals(s.nextSetBit(127), -1);
+    Assertions.assertEquals(s.nextSetBit(128), -1);
+    Assertions.assertEquals(s.nextClearBit(0), 0);
+    Assertions.assertEquals(s.nextClearBit(127), 127);
+    Assertions.assertEquals(s.nextClearBit(128), 128);
+    Assertions.assertEquals(s.toString(), "{}");
+    Assertions.assertFalse(s.get(0));
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapBatchIteratorTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapBatchIteratorTest.java
new file mode 100644
index 000000000..00fcdcff7
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapBatchIteratorTest.java
@@ -0,0 +1,302 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.RoaringBitmapWriter.writer;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class RoaringBitmapBatchIteratorTest {
+
+  private static RoaringBitmap[] BITMAPS;
+  private static final int[] SIZES = {128, 256, 1024, 8192, 5, 127, 1023};
+
+  private static void initBitmaps() {
+    BITMAPS =
+        new RoaringBitmap[] {
+          testCase()
+              .withArrayAt(0)
+              .withArrayAt(2)
+              .withArrayAt(4)
+              .withArrayAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withRunAt(0)
+              .withRunAt(2)
+              .withRunAt(4)
+              .withRunAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withBitmapAt(0)
+              .withRunAt(2)
+              .withBitmapAt(4)
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withArrayAt(0)
+              .withBitmapAt(2)
+              .withRunAt(4)
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withRunAt(0)
+              .withArrayAt(2)
+              .withBitmapAt(4)
+              .withRunAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withBitmapAt(0)
+              .withRunAt(2)
+              .withArrayAt(4)
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withArrayAt(0)
+              .withBitmapAt(2)
+              .withRunAt(4)
+              .withArrayAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withBitmapAt(0)
+              .withArrayAt(2)
+              .withBitmapAt(4)
+              .withRunAt((1 << 15) | (1 << 14))
+              .build(),
+          testCase()
+              .withRunAt((1 << 15) | (1 << 11))
+              .withBitmapAt((1 << 15) | (1 << 12))
+              .withArrayAt((1 << 15) | (1 << 13))
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build(),
+          RoaringBitmap.bitmapOf(
+              IntStream.range(1 << 10, 1 << 26).filter(i -> (i & 1) == 0).toArray()),
+          RoaringBitmap.bitmapOf(
+              IntStream.range(1 << 10, 1 << 25).filter(i -> ((i >>> 8) & 1) == 0).toArray()),
+          RoaringBitmap.bitmapOf(IntStream.range(0, 127).toArray()),
+          RoaringBitmap.bitmapOf(IntStream.range(0, 1024).toArray()),
+          RoaringBitmap.bitmapOf(
+              IntStream.concat(IntStream.range(0, 256), IntStream.range(1 << 16, (1 << 16) | 256))
+                  .toArray()),
+          RoaringBitmap.bitmapOf(8511),
+          new RoaringBitmap()
+        };
+  }
+
+  @BeforeAll
+  public static void beforeAll() throws InterruptedException {
+    int tryIndex = 0;
+    int maxTryIndex = 3;
+    while (++tryIndex < maxTryIndex) {
+      try {
+        initBitmaps();
+      } catch (OutOfMemoryError e) {
+        if (tryIndex == maxTryIndex) {
+          throw e;
+        }
+        e.printStackTrace();
+        System.out.println(
+            "RoaringBitmapBatchIteratorTest.beforeAll Issue on try #"
+                + tryIndex
+                + ". Sleeping 5s for other tests to complete");
+        TimeUnit.SECONDS.sleep(5);
+      }
+    }
+  }
+
+  @AfterAll
+  public static void clear() {
+    BITMAPS = null;
+  }
+
+  public static Stream params() {
+    return Stream.of(BITMAPS)
+        .flatMap(bitmap -> IntStream.of(SIZES).mapToObj(i -> Arguments.of(bitmap, i)));
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAsIntIterator(RoaringBitmap bitmap, int size) {
+    IntIterator it = bitmap.getBatchIterator().asIntIterator(new int[size]);
+    RoaringBitmapWriter w =
+        writer().constantMemory().initialCapacity(bitmap.highLowContainer.size).get();
+    while (it.hasNext()) {
+      w.add(it.next());
+    }
+    RoaringBitmap copy = w.get();
+    assertEquals(bitmap, copy);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void test(RoaringBitmap bitmap, int batchSize) {
+    int[] buffer = new int[batchSize];
+    RoaringBitmap result = new RoaringBitmap();
+    RoaringBatchIterator it = bitmap.getBatchIterator();
+    int cardinality = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      cardinality += batch;
+    }
+    assertEquals(bitmap, result);
+    assertEquals(bitmap.getCardinality(), cardinality);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAdvancedIfNeeded(RoaringBitmap bitmap, int batchSize) {
+    final int cardinality = bitmap.getCardinality();
+    if (cardinality < 2) {
+      return;
+    }
+    int midpoint = bitmap.select(cardinality / 2);
+    int[] buffer = new int[batchSize];
+    RoaringBitmap result = new RoaringBitmap();
+    RoaringBatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded(midpoint);
+    int consumed = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      consumed += batch;
+    }
+    RoaringBitmap expected = bitmap.clone();
+    expected.remove(0, midpoint & 0xFFFFFFFFL);
+    assertEquals(expected, result);
+    assertEquals(expected.getCardinality(), consumed);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAdvancedIfNeededToAbsentValue(RoaringBitmap bitmap, int batchSize) {
+    long firstAbsent = bitmap.nextAbsentValue(0);
+    int[] buffer = new int[batchSize];
+    RoaringBitmap result = new RoaringBitmap();
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded((int) firstAbsent);
+    int consumed = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      consumed += batch;
+    }
+    RoaringBitmap expected = bitmap.clone();
+    expected.remove(0, firstAbsent & 0xFFFFFFFFL);
+    assertEquals(expected, result);
+    assertEquals(expected.getCardinality(), consumed);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAdvancedIfNeededBeyondLastValue(
+      RoaringBitmap bitmap, int batchSize) {
+    long advanceTo = bitmap.isEmpty() ? 0 : bitmap.last() + 1;
+    int[] buffer = new int[batchSize];
+    RoaringBitmap result = new RoaringBitmap();
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded((int) advanceTo);
+    int consumed = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      consumed += batch;
+    }
+    assertEquals(0, consumed);
+    assertTrue(result.isEmpty());
+  }
+
+  @Test
+  public void testTimelyTermination() {
+    RoaringBitmap bm = RoaringBitmap.bitmapOf(8511);
+    BatchIterator bi = bm.getBatchIterator();
+    int[] batch = new int[10];
+    assertTrue(bi.hasNext());
+    int n = bi.nextBatch(batch);
+    assertEquals(n, 1);
+    assertEquals(batch[0], 8511);
+    assertFalse(bi.hasNext());
+  }
+
+  @Test
+  public void testTimelyTerminationAfterAdvanceIfNeeded() {
+    RoaringBitmap bm = RoaringBitmap.bitmapOf(8511);
+    BatchIterator bi = bm.getBatchIterator();
+    assertTrue(bi.hasNext());
+    bi.advanceIfNeeded(8512);
+    assertFalse(bi.hasNext());
+  }
+
+  @Test
+  public void testBatchIteratorWithAdvanceIfNeeded() {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(3 << 16, (3 << 16) + 5, (3 << 16) + 10);
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded(6);
+    assertTrue(it.hasNext());
+    int[] batch = new int[10];
+    int n = it.nextBatch(batch);
+    assertEquals(n, 3);
+    assertEquals(batch[0], 3 << 16);
+    assertEquals(batch[1], (3 << 16) + 5);
+    assertEquals(batch[2], (3 << 16) + 10);
+  }
+
+  @ParameterizedTest
+  @ValueSource(ints = {10, 11, 12, 13, 14, 15, 18, 20, 21, 23, 24})
+  public void testBatchIteratorWithAdvancedIfNeededWithZeroLengthRun(int number) {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(10, 11, 12, 13, 14, 15, 18, 20, 21, 22, 23, 24);
+    bitmap.runOptimize();
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded(number);
+    assertTrue(it.hasNext());
+    int[] batch = new int[10];
+    int n = it.nextBatch(batch);
+    int i = Arrays.binarySearch(batch, 0, n, number);
+    assertTrue(i >= 0, "key " + number + " not found");
+    assertEquals(batch[i], number);
+  }
+
+  @Test
+  public void testBatchIteratorFillsBufferAcrossContainers() {
+    RoaringBitmap bitmap =
+        RoaringBitmap.bitmapOf(3 << 4, 3 << 8, 3 << 12, 3 << 16, 3 << 20, 3 << 24, 3 << 28);
+    assertEquals(5, bitmap.highLowContainer.size());
+    BatchIterator it = bitmap.getBatchIterator();
+    int[] batch = new int[3];
+    int n = it.nextBatch(batch);
+    assertEquals(3, n);
+    assertArrayEquals(new int[] {3 << 4, 3 << 8, 3 << 12}, batch);
+    n = it.nextBatch(batch);
+    assertEquals(3, n);
+    assertArrayEquals(new int[] {3 << 16, 3 << 20, 3 << 24}, batch);
+    n = it.nextBatch(batch);
+    assertEquals(1, n);
+    assertArrayEquals(new int[] {3 << 28}, Arrays.copyOfRange(batch, 0, 1));
+    n = it.nextBatch(batch);
+    assertEquals(0, n);
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapIntervalIntersectionTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapIntervalIntersectionTest.java
similarity index 50%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapIntervalIntersectionTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapIntervalIntersectionTest.java
index ff90b2edd..d8f5939e4 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/RoaringBitmapIntervalIntersectionTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapIntervalIntersectionTest.java
@@ -1,5 +1,8 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
 
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
@@ -9,35 +12,55 @@
 
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
-
 public class RoaringBitmapIntervalIntersectionTest {
 
   private static Arguments[] ARGS;
 
   @BeforeAll
   public static void setup() {
-    ARGS = new Arguments[] {
-        Arguments.of(RoaringBitmap.bitmapOf(1, 2, 3), 0, 1 << 16, RoaringBitmap.bitmapOf(1, 2, 3), 1, 1),
-        Arguments.of(RoaringBitmap.bitmapOf(1 << 31 | 1 << 30), 0, 1 << 16),
-        Arguments.of(RoaringBitmap.bitmapOf(1 << 31 | 1 << 30), 0, 256),
-        Arguments.of(RoaringBitmap.bitmapOf(1, 1 << 31 | 1 << 30), 0, 256),
-        Arguments.of(RoaringBitmap.bitmapOf(1, 1 << 16, 1 << 31 | 1 << 30), 0, 1L << 32),
-        Arguments.of(testCase().withArrayAt(10).withBitmapAt(20).withRunAt(30)
-            .withRange(70000L, 150000L).build(), 70000L, 150000L),
-        Arguments.of(testCase().withArrayAt(10).withBitmapAt(20).withRunAt(30)
-            .withRange(70000L, 150000L).build(), 71000L, 140000L),
-        Arguments.of(testCase().withArrayAt(0).withBitmapAt(1).withRunAt(20).build(), 67000, 150000),
-        Arguments.of(testCase().withBitmapAt(0).withArrayAt(1).withRunAt(20).build(), 67000, 150000),
-        Arguments.of(testCase().withBitmapAt(0).withRunAt(1).withArrayAt(20).build(), 67000, 150000),
-        Arguments.of(testCase().withArrayAt(0)
-            .withArrayAt(1)
-            .withArrayAt(2)
-            .withBitmapAt(200)
-            .withRunAt(205).build(), 199 * (1 << 16), 200 * (1 << 16) + (1 << 14))
-    };
+    ARGS =
+        new Arguments[] {
+          Arguments.of(
+              RoaringBitmap.bitmapOf(1, 2, 3), 0, 1 << 16, RoaringBitmap.bitmapOf(1, 2, 3), 1, 1),
+          Arguments.of(RoaringBitmap.bitmapOf(1 << 31 | 1 << 30), 0, 1 << 16),
+          Arguments.of(RoaringBitmap.bitmapOf(1 << 31 | 1 << 30), 0, 256),
+          Arguments.of(RoaringBitmap.bitmapOf(1, 1 << 31 | 1 << 30), 0, 256),
+          Arguments.of(RoaringBitmap.bitmapOf(1, 1 << 16, 1 << 31 | 1 << 30), 0, 1L << 32),
+          Arguments.of(
+              testCase()
+                  .withArrayAt(10)
+                  .withBitmapAt(20)
+                  .withRunAt(30)
+                  .withRange(70000L, 150000L)
+                  .build(),
+              70000L,
+              150000L),
+          Arguments.of(
+              testCase()
+                  .withArrayAt(10)
+                  .withBitmapAt(20)
+                  .withRunAt(30)
+                  .withRange(70000L, 150000L)
+                  .build(),
+              71000L,
+              140000L),
+          Arguments.of(
+              testCase().withArrayAt(0).withBitmapAt(1).withRunAt(20).build(), 67000, 150000),
+          Arguments.of(
+              testCase().withBitmapAt(0).withArrayAt(1).withRunAt(20).build(), 67000, 150000),
+          Arguments.of(
+              testCase().withBitmapAt(0).withRunAt(1).withArrayAt(20).build(), 67000, 150000),
+          Arguments.of(
+              testCase()
+                  .withArrayAt(0)
+                  .withArrayAt(1)
+                  .withArrayAt(2)
+                  .withBitmapAt(200)
+                  .withRunAt(205)
+                  .build(),
+              199 * (1 << 16),
+              200 * (1 << 16) + (1 << 14))
+        };
   }
 
   @AfterAll
@@ -49,7 +72,6 @@ public static Stream params() {
     return Stream.of(ARGS);
   }
 
-
   @ParameterizedTest
   @MethodSource("params")
   public void testIntersects(RoaringBitmap bitmap, long minimum, long supremum) {
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapSubsetTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapSubsetTest.java
new file mode 100644
index 000000000..5922a7e2c
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapSubsetTest.java
@@ -0,0 +1,140 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.google.common.collect.ContiguousSet;
+import com.google.common.collect.DiscreteDomain;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Range;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+public class RoaringBitmapSubsetTest {
+
+  private static final Predicate DIVISIBLE_BY_4 = i -> i % 4 == 0;
+
+  private static final Predicate DIVISIBLE_BY_3 = i -> i % 3 == 0;
+
+  public static Stream params() {
+    return Stream.of(
+        Arguments.of( // array vs array
+            ImmutableSet.of(1, 2, 3, 4), ImmutableSet.of(2, 3)),
+        Arguments.of( // array vs empty
+            ImmutableSet.of(1, 2, 3, 4), ImmutableSet.of()),
+        Arguments.of( // identical arrays
+            ImmutableSet.of(1, 2, 3, 4), ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // disjoint arrays
+            ImmutableSet.of(10, 12, 14, 15), ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // disjoint arrays, cardinality mismatch
+            ImmutableSet.of(10, 12, 14), ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // run vs array, subset
+            ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // run vs array, subset
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // run vs empty
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of()),
+        Arguments.of( // identical runs, 1 container
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers())),
+        Arguments.of( // identical runs, 2 containers
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()),
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers())),
+        Arguments.of( // disjoint array vs run, either side of container boundary
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of((1 << 16) + 1, (1 << 16) + 2, (1 << 16) + 3, (1 << 16) + 4)),
+        Arguments.of( // disjoint array vs run
+            ContiguousSet.create(Range.closed(3, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 2)),
+        Arguments.of( // run vs run, overlap with shift
+            ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()),
+            ContiguousSet.create(Range.closed(1 << 4, 1 << 12), DiscreteDomain.integers())),
+        Arguments.of( // run vs run, subset
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 1 << 8)),
+        Arguments.of( // run vs run, overlap with shift, 2 containers
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()),
+            ImmutableSet.of(1 << 6, 1 << 26)),
+        Arguments.of( // run vs 2 container run, overlap
+            ImmutableSet.of(1, 1 << 16),
+            ContiguousSet.create(Range.closed(0, 1 << 20), DiscreteDomain.integers())),
+        Arguments.of( // bitmap vs intersecting array
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.of(4, 8)),
+        Arguments.of( // bitmap vs bitmap, cardinality mismatch
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // bitmap vs empty
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.of()),
+        Arguments.of( // identical bitmaps
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // bitmap vs overlapping but disjoint array
+            ImmutableSet.of(3, 7),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // bitmap vs overlapping but disjoint bitmap
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_3::test)),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // disjoint, large (signed-negative) keys
+            ImmutableSet.of(0xbf09001d, 0xbf090169), ImmutableSet.of(0x8088000e, 0x80880029)));
+  }
+
+  @ParameterizedTest(name = "assert that {1} is subset of {0}")
+  @MethodSource("params")
+  public void testProperSubset(Set superSet, Set subSet) {
+    RoaringBitmap superSetRB = create(superSet);
+    RoaringBitmap subSetRB = create(subSet);
+    assertEquals(superSet.containsAll(subSet), superSetRB.contains(subSetRB));
+    // reverse the test
+    assertEquals(subSet.containsAll(superSet), subSetRB.contains(superSetRB));
+  }
+
+  private RoaringBitmap create(Set set) {
+    RoaringBitmap rb = new RoaringBitmap();
+    if (set instanceof ContiguousSet) {
+      ContiguousSet contiguousSet = (ContiguousSet) set;
+      rb.add(contiguousSet.first().longValue(), contiguousSet.last().longValue());
+    } else {
+      for (Integer i : set) {
+        rb.add(i);
+      }
+    }
+    return rb;
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapWriterRandomisedTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapWriterRandomisedTest.java
new file mode 100644
index 000000000..e5c838c79
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/RoaringBitmapWriterRandomisedTest.java
@@ -0,0 +1,159 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.roaringbitmap.RoaringBitmapWriter.writer;
+import static org.roaringbitmap.Util.toUnsignedLong;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class RoaringBitmapWriterRandomisedTest {
+
+  private static int[][] ARRAYS;
+
+  @BeforeAll
+  public static void init() {
+    ARRAYS =
+        new int[][] {
+          new int[] {0, 1, 2, 3},
+          randomArray(0),
+          randomArray(10),
+          randomArray(100),
+          randomArray(1000),
+          randomArray(10_000),
+          randomArray(100_000),
+          randomArray(1000_000),
+          randomArray(10_000_000)
+        };
+  }
+
+  @AfterAll
+  public static void clear() {
+    ARRAYS = null;
+  }
+
+  public static Stream tests() {
+    return Stream.of(ARRAYS).map(Arguments::of);
+  }
+
+  @ParameterizedTest(name = "-")
+  @MethodSource("tests")
+  public void shouldBuildSameBitmapAsBitmapOf(int[] values) {
+    RoaringBitmapWriter writer =
+        writer().expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))).get();
+    for (int i : values) {
+      writer.add(i);
+    }
+    writer.flush();
+    verify(writer.getUnderlying(), values);
+  }
+
+  @ParameterizedTest(name = "-")
+  @MethodSource("tests")
+  public void shouldBuildSameBitmapAsBitmapOfWithAddMany(int[] values) {
+    RoaringBitmapWriter writer =
+        writer().expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))).get();
+    writer.addMany(values);
+    writer.flush();
+    verify(writer.getUnderlying(), values);
+  }
+
+  @ParameterizedTest(name = "-")
+  @MethodSource("tests")
+  public void getShouldFlushToTheUnderlyingBitmap(int[] values) {
+    RoaringBitmapWriter writer =
+        writer().expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values))).get();
+    writer.addMany(values);
+    verify(writer.get(), values);
+  }
+
+  @ParameterizedTest(name = "-")
+  @MethodSource("tests")
+  public void getShouldFlushToTheUnderlyingBitmap_ConstantMemory(int[] values) {
+    RoaringBitmapWriter writer = writer().constantMemory().get();
+    writer.addMany(values);
+    verify(writer.get(), values);
+  }
+
+  @ParameterizedTest(name = "-")
+  @MethodSource("tests")
+  public void shouldBuildSameBitmapAsBitmapOf_ConstantMemory(int[] values) {
+    RoaringBitmapWriter writer =
+        writer()
+            .constantMemory()
+            .expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values)))
+            .get();
+    for (int i : values) {
+      writer.add(i);
+    }
+    writer.flush();
+    verify(writer.getUnderlying(), values);
+  }
+
+  @ParameterizedTest(name = "-")
+  @MethodSource("tests")
+  public void shouldBuildSameBitmapAsBitmapOfWithAddMany_ConstantMemory(int[] values) {
+    RoaringBitmapWriter writer =
+        writer()
+            .constantMemory()
+            .expectedRange(toUnsignedLong(min()), toUnsignedLong(max(values)))
+            .get();
+    writer.addMany(values);
+    writer.flush();
+    verify(writer.getUnderlying(), values);
+  }
+
+  private void verify(RoaringBitmap rb, int[] values) {
+    RoaringBitmap baseline = RoaringBitmap.bitmapOf(values);
+    RoaringArray baselineHLC = baseline.highLowContainer;
+    RoaringArray rbHLC = rb.highLowContainer;
+    assertEquals(baselineHLC.size, rbHLC.size);
+    for (int i = 0; i < baselineHLC.size; ++i) {
+      Container baselineContainer = baselineHLC.getContainerAtIndex(i);
+      Container rbContainer = rbHLC.getContainerAtIndex(i);
+      assertEquals(baselineContainer, rbContainer);
+    }
+    assertEquals(baseline, rb);
+  }
+
+  private static int[] randomArray(int size) {
+    Random random = new Random(1234);
+    int[] data = new int[size];
+    int last = 0;
+    int i = 0;
+    while (i < size) {
+      if (random.nextGaussian() > 0.1) {
+        int runLength = random.nextInt(Math.min(size - i, 1 << 16));
+        for (int j = 1; j < runLength; ++j) {
+          data[i + j] = last + 1;
+          last = data[i + j];
+        }
+        i += runLength;
+      } else {
+        data[i] = last + 1 + random.nextInt(999);
+        last = data[i];
+        ++i;
+      }
+    }
+    Arrays.sort(data);
+    return data;
+  }
+
+  private int max(int[] values) {
+    return values.length == 0 ? 0 : values[values.length - 1];
+  }
+
+  private int min() {
+    return 0;
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/SeededTestData.java b/roaringbitmap/src/test/java/org/roaringbitmap/SeededTestData.java
similarity index 81%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/SeededTestData.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/SeededTestData.java
index 13a0317ac..9ba36234f 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/SeededTestData.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/SeededTestData.java
@@ -1,16 +1,17 @@
 package org.roaringbitmap;
 
+import static org.roaringbitmap.RoaringBitmapWriter.writer;
+
 import java.util.Arrays;
 import java.util.SplittableRandom;
 import java.util.stream.IntStream;
 
-import static org.roaringbitmap.RoaringBitmapWriter.writer;
-
 public class SeededTestData {
 
   private static final ThreadLocal bits = ThreadLocal.withInitial(() -> new long[1 << 10]);
 
-  private static final ThreadLocal RNG = ThreadLocal.withInitial(() -> new SplittableRandom(0xfeef1f0));
+  private static final ThreadLocal RNG =
+      ThreadLocal.withInitial(() -> new SplittableRandom(0xfeef1f0));
 
   public static RoaringBitmap randomBitmap(int maxKeys, double rleLimit, double denseLimit) {
     try {
@@ -31,7 +32,8 @@ public static RoaringBitmap randomBitmap(int maxKeys) {
     }
   }
 
-  public static  T randomBitmap(int maxKeys, RoaringBitmapWriter writer) {
+  public static  T randomBitmap(
+      int maxKeys, RoaringBitmapWriter writer) {
     try {
       SplittableRandom random = RNG.get();
       double rleLimit = random.nextDouble();
@@ -42,18 +44,26 @@ public static  T randomBitmap(int maxKeys, Roaring
     }
   }
 
-  private static RoaringBitmap randomBitmap(int maxKeys, double rleLimit, double denseLimit, SplittableRandom random) {
-    return randomBitmap(maxKeys, rleLimit, denseLimit, random, writer().initialCapacity(maxKeys).optimiseForArrays().get());
+  private static RoaringBitmap randomBitmap(
+      int maxKeys, double rleLimit, double denseLimit, SplittableRandom random) {
+    return randomBitmap(
+        maxKeys,
+        rleLimit,
+        denseLimit,
+        random,
+        writer().initialCapacity(maxKeys).optimiseForArrays().get());
   }
 
-  private static  T randomBitmap(int maxKeys,
-                                                       double rleLimit,
-                                                       double denseLimit,
-                                                       SplittableRandom random,
-                                                       RoaringBitmapWriter writer) {
+  private static  T randomBitmap(
+      int maxKeys,
+      double rleLimit,
+      double denseLimit,
+      SplittableRandom random,
+      RoaringBitmapWriter writer) {
     int[] keys = createSorted16BitInts(random.nextInt(1, maxKeys), random);
     IntStream.of(keys)
-            .forEach(key -> {
+        .forEach(
+            key -> {
               double choice = random.nextDouble();
               final IntStream stream;
               if (choice < rleLimit) {
@@ -96,9 +106,9 @@ private static IntStream rleRegion(SplittableRandom random) {
     int numRuns = random.nextInt(1, 2048);
     int[] runs = createSorted16BitInts(numRuns * 2, random);
     return IntStream.range(0, numRuns)
-            .map(i -> i * 2)
-            .mapToObj(i -> IntStream.range(runs[i], runs[i + 1]))
-            .flatMapToInt(i -> i);
+        .map(i -> i * 2)
+        .mapToObj(i -> IntStream.range(runs[i], runs[i + 1]))
+        .flatMapToInt(i -> i);
   }
 
   private static IntStream sparseRegion(SplittableRandom random) {
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestAdversarialInputs.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestAdversarialInputs.java
new file mode 100644
index 000000000..6b854688b
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestAdversarialInputs.java
@@ -0,0 +1,63 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public class TestAdversarialInputs {
+
+  public static Stream badFiles() {
+    return IntStream.rangeClosed(1, 7)
+        .mapToObj(i -> Arguments.of("/testdata/crashproneinput" + i + ".bin"));
+  }
+
+  // open a stream without copying files
+  public static InputStream openInputstream(String resourceName) throws IOException {
+    InputStream resourceAsStream = TestAdversarialInputs.class.getResourceAsStream(resourceName);
+    if (resourceAsStream == null) {
+      throw new IOException("Cannot get resource \"" + resourceName + "\".");
+    }
+    return resourceAsStream;
+  }
+
+  @Test
+  public void testInputGoodFile1() throws IOException {
+    InputStream inputStream = openInputstream("/testdata/bitmapwithruns.bin");
+    RoaringBitmap rb = new RoaringBitmap();
+    // should not throw an exception
+    rb.deserialize(new DataInputStream(inputStream));
+    assertEquals(rb.getCardinality(), 200100);
+  }
+
+  @Test
+  public void testInputGoodFile2() throws IOException {
+    InputStream inputStream = openInputstream("/testdata/bitmapwithoutruns.bin");
+    RoaringBitmap rb = new RoaringBitmap();
+    // should not throw an exception
+    rb.deserialize(new DataInputStream(inputStream));
+    assertEquals(rb.getCardinality(), 200100);
+  }
+
+  @ParameterizedTest
+  @MethodSource("badFiles")
+  public void testInputBadFile8(String fileName) {
+    assertThrows(IOException.class, () -> deserialize(fileName));
+  }
+
+  private void deserialize(String fileName) throws IOException {
+    InputStream inputStream = openInputstream(fileName);
+    RoaringBitmap rb = new RoaringBitmap();
+    // should not work
+    rb.deserialize(new DataInputStream(inputStream));
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java
new file mode 100644
index 000000000..7bbf5aa7e
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestArrayContainer.java
@@ -0,0 +1,979 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
+
+import com.google.common.primitives.Ints;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestArrayContainer {
+
+  @Test
+  public void testConst() {
+    ArrayContainer ac1 = new ArrayContainer(5, 15);
+    char[] data = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+    ArrayContainer ac2 = new ArrayContainer(data);
+    assertEquals(ac1, ac2);
+  }
+
+  @Test
+  public void testRemove() {
+    ArrayContainer ac1 = new ArrayContainer(5, 15);
+    ac1.remove((char) 14);
+    ArrayContainer ac2 = new ArrayContainer(5, 14);
+    assertEquals(ac1, ac2);
+  }
+
+  @Test
+  public void arrayContainersNeverFull() {
+    assertFalse(new ArrayContainer(5, 15).isFull());
+  }
+
+  @Test
+  public void testToString() {
+    ArrayContainer ac1 = new ArrayContainer(5, 15);
+    ac1.add((char) -3);
+    ac1.add((char) -17);
+    assertEquals("{5,6,7,8,9,10,11,12,13,14,65519,65533}", ac1.toString());
+  }
+
+  @Test
+  public void testIandNot() {
+    ArrayContainer ac1 = new ArrayContainer(5, 15);
+    ArrayContainer ac2 = new ArrayContainer(10, 15);
+    BitmapContainer bc = new BitmapContainer(5, 10);
+    ArrayContainer ac3 = ac1.iandNot(bc);
+    assertEquals(ac2, ac3);
+  }
+
+  @Test
+  public void testReverseArrayContainerShortIterator() {
+    // Test Clone
+    ArrayContainer ac1 = new ArrayContainer(5, 15);
+    ReverseArrayContainerCharIterator rac1 = new ReverseArrayContainerCharIterator(ac1);
+    CharIterator rac2 = rac1.clone();
+    assertNotNull(rac2);
+    assertEquals(asList(rac1), asList(rac2));
+  }
+
+  private static List asList(CharIterator ints) {
+    int[] values = new int[10];
+    int size = 0;
+    while (ints.hasNext()) {
+      if (!(size < values.length)) {
+        values = Arrays.copyOf(values, values.length * 2);
+      }
+      values[size++] = ints.next();
+    }
+    return Ints.asList(Arrays.copyOf(values, size));
+  }
+
+  @Test
+  public void roundtrip() throws Exception {
+    Container ac = new ArrayContainer();
+    ac = ac.add(1, 5);
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    try (ObjectOutputStream oo = new ObjectOutputStream(bos)) {
+      ac.writeExternal(oo);
+    }
+    Container ac2 = new ArrayContainer();
+    final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+    ac2.readExternal(new ObjectInputStream(bis));
+
+    assertEquals(4, ac2.getCardinality());
+    for (int i = 1; i < 5; i++) {
+      assertTrue(ac2.contains((char) i));
+    }
+  }
+
+  @Test
+  public void intersectsArray() {
+    Container ac = new ArrayContainer();
+    ac = ac.add(1, 10);
+    Container ac2 = new ArrayContainer();
+    ac2 = ac2.add(5, 25);
+    assertTrue(ac.intersects(ac2));
+  }
+
+  @Test
+  public void orFullToRunContainer() {
+    ArrayContainer ac = new ArrayContainer(0, 1 << 12);
+    BitmapContainer half = new BitmapContainer(1 << 12, 1 << 16);
+    Container result = ac.or(half);
+    assertEquals(1 << 16, result.getCardinality());
+    assertTrue(result instanceof RunContainer);
+  }
+
+  @Test
+  public void orFullToRunContainer2() {
+    ArrayContainer ac = new ArrayContainer(0, 1 << 15);
+    ArrayContainer half = new ArrayContainer(1 << 15, 1 << 16);
+    Container result = ac.or(half);
+    assertEquals(1 << 16, result.getCardinality());
+    assertTrue(result instanceof RunContainer);
+  }
+
+  @Test
+  public void iandBitmap() {
+    Container ac = new ArrayContainer();
+    ac = ac.add(1, 10);
+    Container bc = new BitmapContainer();
+    bc = bc.add(5, 25);
+    ac.iand(bc);
+    assertEquals(5, ac.getCardinality());
+    for (int i = 5; i < 10; i++) {
+      assertTrue(ac.contains((char) i));
+    }
+  }
+
+  @Test
+  public void iandRun() {
+    Container ac = new ArrayContainer();
+    ac = ac.add(1, 10);
+    Container rc = new RunContainer();
+    rc = rc.add(5, 25);
+    ac = ac.iand(rc);
+    assertEquals(5, ac.getCardinality());
+    for (int i = 5; i < 10; i++) {
+      assertTrue(ac.contains((char) i));
+    }
+  }
+
+  @Test
+  public void addEmptyRange() {
+    Container ac = new ArrayContainer();
+    ac = ac.add(1, 1);
+    assertEquals(0, ac.getCardinality());
+  }
+
+  @Test
+  public void addInvalidRange() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container ac = new ArrayContainer();
+          ac.add(13, 1);
+        });
+  }
+
+  @Test
+  public void iaddEmptyRange() {
+    Container ac = new ArrayContainer();
+    ac = ac.iadd(1, 1);
+    assertEquals(0, ac.getCardinality());
+  }
+
+  @Test
+  public void iaddInvalidRange() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container ac = new ArrayContainer();
+          ac.iadd(13, 1);
+        });
+  }
+
+  @Test
+  public void iaddSanityTest() {
+    Container ac = new ArrayContainer();
+    ac = ac.iadd(10, 20);
+    // insert disjoint at end
+    ac = ac.iadd(30, 70);
+    // insert disjoint between
+    ac = ac.iadd(25, 26);
+    // insert disjoint at start
+    ac = ac.iadd(1, 2);
+    // insert overlap at end
+    ac = ac.iadd(60, 80);
+    // insert overlap between
+    ac = ac.iadd(10, 30);
+    // insert overlap at start
+    ac = ac.iadd(1, 20);
+    assertEquals(79, ac.getCardinality());
+  }
+
+  @Test
+  public void clear() {
+    Container ac = new ArrayContainer();
+    ac = ac.add(1, 10);
+    ac.clear();
+    assertEquals(0, ac.getCardinality());
+  }
+
+  @Test
+  public void testLazyORFull() {
+    ArrayContainer ac = new ArrayContainer(0, 1 << 15);
+    ArrayContainer ac2 = new ArrayContainer(1 << 15, 1 << 16);
+    Container rbc = ac.lazyor(ac2);
+    assertEquals(-1, rbc.getCardinality());
+    Container repaired = rbc.repairAfterLazy();
+    assertEquals(1 << 16, repaired.getCardinality());
+    assertTrue(repaired instanceof RunContainer);
+  }
+
+  @Test
+  public void testFirst_Empty() {
+    assertThrows(NoSuchElementException.class, () -> new ArrayContainer().first());
+  }
+
+  @Test
+  public void testLast_Empty() {
+    assertThrows(NoSuchElementException.class, () -> new ArrayContainer().last());
+  }
+
+  @Test
+  public void testFirstLast() {
+    Container rc = new ArrayContainer();
+    final int firstInclusive = 1;
+    int lastExclusive = firstInclusive;
+    for (int i = 0; i < 1 << 16 - 10; ++i) {
+      int newLastExclusive = lastExclusive + 10;
+      rc = rc.add(lastExclusive, newLastExclusive);
+      assertEquals(firstInclusive, rc.first());
+      assertEquals(newLastExclusive - 1, rc.last());
+      lastExclusive = newLastExclusive;
+    }
+  }
+
+  @Test
+  public void testContainsBitmapContainer_ExcludeShiftedSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(2, 12);
+    assertFalse(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsBitmapContainer_AlwaysFalse() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(0, 10);
+    assertFalse(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsBitmapContainer_ExcludeSuperSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container superset = new BitmapContainer().add(0, 20);
+    assertFalse(ac.contains(superset));
+  }
+
+  @Test
+  public void testContainsBitmapContainer_ExcludeDisJointSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container disjoint = new BitmapContainer().add(20, 40);
+    assertFalse(ac.contains(disjoint));
+    assertFalse(disjoint.contains(ac));
+  }
+
+  @Test
+  public void testContainsRunContainer_EmptyContainsEmpty() {
+    Container ac = new ArrayContainer();
+    Container subset = new RunContainer();
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsRunContainer_IncludeProperSubset() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new RunContainer().add(0, 9);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsRunContainer_IncludeSelf() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new RunContainer().add(0, 10);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsRunContainer_ExcludeSuperSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container superset = new RunContainer().add(0, 20);
+    assertFalse(ac.contains(superset));
+  }
+
+  @Test
+  public void testContainsRunContainer_IncludeProperSubsetDifferentStart() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new RunContainer().add(1, 9);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsRunContainer_ExcludeShiftedSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new RunContainer().add(2, 12);
+    assertFalse(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsRunContainer_ExcludeDisJointSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container disjoint = new RunContainer().add(20, 40);
+    assertFalse(ac.contains(disjoint));
+    assertFalse(disjoint.contains(ac));
+  }
+
+  @Test
+  public void testContainsRunContainer_Issue723Case1() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new RunContainer().add(5, 6);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsRunContainer_Issue723Case2() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container rc = new RunContainer().add(5, 11);
+    assertFalse(ac.contains(rc));
+  }
+
+  @Test
+  public void testContainsArrayContainer_EmptyContainsEmpty() {
+    Container ac = new ArrayContainer();
+    Container subset = new ArrayContainer();
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsArrayContainer_IncludeProperSubset() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(0, 9);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsArrayContainer_IncludeProperSubsetDifferentStart() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(2, 9);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsArrayContainer_ExcludeShiftedSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container shifted = new ArrayContainer().add(2, 12);
+    assertFalse(ac.contains(shifted));
+  }
+
+  @Test
+  public void testContainsArrayContainer_IncludeSelf() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(0, 10);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsArrayContainer_ExcludeSuperSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container superset = new ArrayContainer().add(0, 20);
+    assertFalse(ac.contains(superset));
+  }
+
+  @Test
+  public void testContainsArrayContainer_ExcludeDisJointSet() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container disjoint = new ArrayContainer().add(20, 40);
+    assertFalse(ac.contains(disjoint));
+    assertFalse(disjoint.contains(ac));
+  }
+
+  @Test
+  public void iorNotIncreaseCapacity() {
+    Container ac1 = new ArrayContainer();
+    Container ac2 = new ArrayContainer();
+    ac1.add((char) 128);
+    ac1.add((char) 256);
+    ac2.add((char) 1024);
+
+    ac1.ior(ac2);
+    assertTrue(ac1.contains((char) 128));
+    assertTrue(ac1.contains((char) 256));
+    assertTrue(ac1.contains((char) 1024));
+  }
+
+  @Test
+  public void iorIncreaseCapacity() {
+    Container ac1 = new ArrayContainer();
+    Container ac2 = new ArrayContainer();
+    ac1.add((char) 128);
+    ac1.add((char) 256);
+    ac1.add((char) 512);
+    ac1.add((char) 513);
+    ac2.add((char) 1024);
+
+    ac1.ior(ac2);
+    assertTrue(ac1.contains((char) 128));
+    assertTrue(ac1.contains((char) 256));
+    assertTrue(ac1.contains((char) 512));
+    assertTrue(ac1.contains((char) 513));
+    assertTrue(ac1.contains((char) 1024));
+  }
+
+  @Test
+  public void iorSanityCheck() {
+    Container ac = new ArrayContainer().add(0, 10);
+    Container disjoint = new ArrayContainer().add(20, 40);
+    ac.ior(disjoint);
+    assertTrue(ac.contains(disjoint));
+  }
+
+  @Test
+  public void iorNot() {
+    Container rc1 = new ArrayContainer();
+    Container rc2 = new ArrayContainer();
+
+    rc1.iadd(257, 258);
+    rc2.iadd(128, 256);
+    rc1 = rc1.iorNot(rc2, 258);
+    assertEquals(130, rc1.getCardinality());
+
+    PeekableCharIterator iterator = rc1.getCharIterator();
+    for (int i = 0; i < 128; i++) {
+      assertTrue(iterator.hasNext());
+      assertEquals(i, iterator.next());
+    }
+    assertTrue(iterator.hasNext());
+    assertEquals(256, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(257, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void iorNot2() {
+    Container rc1 = new ArrayContainer();
+    Container rc2 = new ArrayContainer();
+    rc2.iadd(128, 256).iadd(257, 260);
+    rc1 = rc1.iorNot(rc2, 261);
+    assertEquals(130, rc1.getCardinality());
+
+    PeekableCharIterator iterator = rc1.getCharIterator();
+    for (int i = 0; i < 128; i++) {
+      assertTrue(iterator.hasNext());
+      assertEquals(i, iterator.next());
+    }
+    assertTrue(iterator.hasNext());
+    assertEquals(256, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(260, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void iorNot3() {
+    Container rc1 = new ArrayContainer();
+    Container rc2 = new BitmapContainer();
+
+    rc1.iadd(257, 258);
+    rc2.iadd(128, 256);
+    rc1 = rc1.iorNot(rc2, 258);
+    assertEquals(130, rc1.getCardinality());
+
+    PeekableCharIterator iterator = rc1.getCharIterator();
+    for (int i = 0; i < 128; i++) {
+      assertTrue(iterator.hasNext());
+      assertEquals(i, iterator.next());
+    }
+    assertTrue(iterator.hasNext());
+    assertEquals(256, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(257, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void iorNot4() {
+    Container rc1 = new ArrayContainer();
+    Container rc2 = new RunContainer();
+
+    rc1.iadd(257, 258);
+    rc2.iadd(128, 256);
+    rc1 = rc1.iorNot(rc2, 258);
+    assertEquals(130, rc1.getCardinality());
+
+    PeekableCharIterator iterator = rc1.getCharIterator();
+    for (int i = 0; i < 128; i++) {
+      assertTrue(iterator.hasNext());
+      assertEquals(i, iterator.next());
+    }
+    assertTrue(iterator.hasNext());
+    assertEquals(256, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(257, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot() {
+    final Container rc1 = new ArrayContainer();
+
+    {
+      Container rc2 = new ArrayContainer();
+      rc2.iadd(128, 256);
+      Container res = rc1.orNot(rc2, 257);
+      assertEquals(129, res.getCardinality());
+
+      PeekableCharIterator iterator = res.getCharIterator();
+      for (int i = 0; i < 128; i++) {
+        assertTrue(iterator.hasNext());
+        assertEquals(i, iterator.next());
+      }
+      assertTrue(iterator.hasNext());
+      assertEquals(256, iterator.next());
+
+      assertFalse(iterator.hasNext());
+    }
+
+    {
+      Container rc2 = new BitmapContainer();
+      rc2.iadd(128, 256);
+      Container res = rc1.orNot(rc2, 257);
+      assertEquals(129, res.getCardinality());
+
+      PeekableCharIterator iterator = res.getCharIterator();
+      for (int i = 0; i < 128; i++) {
+        assertTrue(iterator.hasNext());
+        assertEquals(i, iterator.next());
+      }
+      assertTrue(iterator.hasNext());
+      assertEquals(256, iterator.next());
+
+      assertFalse(iterator.hasNext());
+    }
+
+    {
+      Container rc2 = new RunContainer();
+      rc2.iadd(128, 256);
+      Container res = rc1.orNot(rc2, 257);
+      assertEquals(129, res.getCardinality());
+
+      PeekableCharIterator iterator = res.getCharIterator();
+      for (int i = 0; i < 128; i++) {
+        assertTrue(iterator.hasNext());
+        assertEquals(i, iterator.next());
+      }
+      assertTrue(iterator.hasNext());
+      assertEquals(256, iterator.next());
+
+      assertFalse(iterator.hasNext());
+    }
+  }
+
+  @Test
+  public void orNot2() {
+    Container rc1 = new ArrayContainer();
+    Container rc2 = new ArrayContainer();
+    rc2.iadd(128, 256).iadd(257, 260);
+    rc1 = rc1.orNot(rc2, 261);
+    assertEquals(130, rc1.getCardinality());
+
+    PeekableCharIterator iterator = rc1.getCharIterator();
+    for (int i = 0; i < 128; i++) {
+      assertTrue(iterator.hasNext());
+      assertEquals(i, iterator.next());
+    }
+    assertTrue(iterator.hasNext());
+    assertEquals(256, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(260, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void testIntersectsWithRange() {
+    Container container = new ArrayContainer().add(0, 10);
+    assertTrue(container.intersects(0, 1));
+    assertTrue(container.intersects(0, 101));
+    assertTrue(container.intersects(0, lower16Bits(-1)));
+    assertFalse(container.intersects(11, lower16Bits(-1)));
+  }
+
+  @Test
+  public void testIntersectsWithRange2() {
+    Container container = new ArrayContainer().add(lower16Bits(-50), lower16Bits(-10));
+    assertFalse(container.intersects(0, 1));
+    assertTrue(container.intersects(0, lower16Bits(-40)));
+    assertFalse(container.intersects(lower16Bits(-100), lower16Bits(-55)));
+    assertFalse(container.intersects(lower16Bits(-9), lower16Bits(-1)));
+    assertTrue(container.intersects(11, 1 << 16));
+  }
+
+  @Test
+  public void testIntersectsWithRange3() {
+    Container container = new ArrayContainer().add((char) 1).add((char) 300).add((char) 1024);
+    assertTrue(container.intersects(0, 300));
+    assertTrue(container.intersects(1, 300));
+    assertFalse(container.intersects(2, 300));
+    assertFalse(container.intersects(2, 299));
+    assertTrue(container.intersects(0, lower16Bits(-1)));
+    assertFalse(container.intersects(1025, 1 << 16));
+  }
+
+  @Test
+  public void testContainsRange() {
+    Container ac = new ArrayContainer().add(20, 100);
+    assertFalse(ac.contains(1, 21));
+    assertFalse(ac.contains(1, 19));
+    assertTrue(ac.contains(20, 100));
+    assertTrue(ac.contains(20, 99));
+    assertTrue(ac.contains(21, 100));
+    assertFalse(ac.contains(21, 101));
+    assertFalse(ac.contains(19, 99));
+    assertFalse(ac.contains(190, 9999));
+  }
+
+  @Test
+  public void testContainsRange2() {
+    Container ac = new ArrayContainer().add((char) 1).add((char) 10).add(20, 100);
+    assertFalse(ac.contains(1, 21));
+    assertFalse(ac.contains(1, 20));
+    assertTrue(ac.contains(1, 2));
+  }
+
+  @Test
+  public void testContainsRangeUnsigned() {
+    Container ac = new ArrayContainer().add(1 << 15, 1 << 8 | 1 << 15);
+    assertTrue(ac.contains(1 << 15, 1 << 8 | 1 << 15));
+    assertTrue(ac.contains(1 + (1 << 15), (1 << 8 | 1 << 15) - 1));
+    assertFalse(ac.contains(1 + (1 << 15), (1 << 8 | 1 << 15) + 1));
+    assertFalse(ac.contains((1 << 15) - 1, (1 << 8 | 1 << 15) - 1));
+    assertFalse(ac.contains(0, 1 << 15));
+    assertFalse(ac.contains(1 << 8 | 1 << 15 | 1, 1 << 16));
+  }
+
+  @Test
+  public void testNextValueBeforeStart() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(10, container.nextValue((char) 5));
+  }
+
+  @Test
+  public void testNextValue() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(10, container.nextValue((char) 10));
+    assertEquals(20, container.nextValue((char) 11));
+    assertEquals(30, container.nextValue((char) 30));
+  }
+
+  @Test
+  public void testNextValueAfterEnd() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(-1, container.nextValue((char) 31));
+  }
+
+  @Test
+  public void testNextValue2() {
+    Container container = new ArrayContainer().iadd(64, 129);
+    assertTrue(container instanceof ArrayContainer);
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(-1, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 5000));
+  }
+
+  @Test
+  public void testNextValueBetweenRuns() {
+    Container container = new ArrayContainer().iadd(64, 129).iadd(256, 321);
+    assertTrue(container instanceof ArrayContainer);
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(256, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 512));
+  }
+
+  @Test
+  public void testNextValue3() {
+    Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertTrue(container instanceof ArrayContainer);
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 63));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(200, container.nextValue((char) 129));
+    assertEquals(200, container.nextValue((char) 199));
+    assertEquals(200, container.nextValue((char) 200));
+    assertEquals(250, container.nextValue((char) 250));
+    assertEquals(5000, container.nextValue((char) 2500));
+    assertEquals(5000, container.nextValue((char) 5000));
+    assertEquals(5200, container.nextValue((char) 5200));
+    assertEquals(-1, container.nextValue((char) 5201));
+  }
+
+  @Test
+  public void testPreviousValue1() {
+    Container container = new ArrayContainer().iadd(64, 129);
+    assertTrue(container instanceof ArrayContainer);
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
+  }
+
+  @Test
+  public void testPreviousValue2() {
+    Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertTrue(container instanceof ArrayContainer);
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
+    assertEquals(128, container.previousValue((char) 199));
+    assertEquals(200, container.previousValue((char) 200));
+    assertEquals(250, container.previousValue((char) 250));
+    assertEquals(500, container.previousValue((char) 2500));
+    assertEquals(5000, container.previousValue((char) 5000));
+    assertEquals(5200, container.previousValue((char) 5200));
+  }
+
+  @Test
+  public void testPreviousValueBeforeStart() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(-1, container.previousValue((char) 5));
+  }
+
+  @Test
+  public void testPreviousValueSparse() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(-1, container.previousValue((char) 9));
+    assertEquals(10, container.previousValue((char) 10));
+    assertEquals(10, container.previousValue((char) 11));
+    assertEquals(20, container.previousValue((char) 21));
+    assertEquals(30, container.previousValue((char) 30));
+  }
+
+  @Test
+  public void testPreviousValueUnsigned() {
+    ArrayContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)});
+    assertEquals(-1, container.previousValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 8)));
+  }
+
+  @Test
+  public void testNextValueUnsigned() {
+    ArrayContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)});
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 7)));
+    assertEquals(-1, container.nextValue((char) ((1 << 15) | 8)));
+  }
+
+  @Test
+  public void testPreviousValueAfterEnd() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(30, container.previousValue((char) 31));
+  }
+
+  @Test
+  public void testPreviousAbsentValue1() {
+    Container container = new ArrayContainer().iadd(64, 129);
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
+  }
+
+  @Test
+  public void testPreviousAbsentValue2() {
+    Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
+    assertEquals(199, container.previousAbsentValue((char) 199));
+    assertEquals(199, container.previousAbsentValue((char) 200));
+    assertEquals(199, container.previousAbsentValue((char) 250));
+    assertEquals(2500, container.previousAbsentValue((char) 2500));
+    assertEquals(4999, container.previousAbsentValue((char) 5000));
+    assertEquals(4999, container.previousAbsentValue((char) 5200));
+  }
+
+  @Test
+  public void testPreviousAbsentValueEmpty() {
+    ArrayContainer container = new ArrayContainer();
+    for (int i = 0; i < 1000; i++) {
+      assertEquals(i, container.previousAbsentValue((char) i));
+    }
+  }
+
+  @Test
+  public void testPreviousAbsentValueSparse() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(9, container.previousAbsentValue((char) 9));
+    assertEquals(9, container.previousAbsentValue((char) 10));
+    assertEquals(11, container.previousAbsentValue((char) 11));
+    assertEquals(21, container.previousAbsentValue((char) 21));
+    assertEquals(29, container.previousAbsentValue((char) 30));
+  }
+
+  @Test
+  public void testPreviousAbsentValueUnsigned() {
+    ArrayContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)});
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char) ((1 << 15) | 8)));
+  }
+
+  @Test
+  public void testNextAbsentValue1() {
+    Container container = new ArrayContainer().iadd(64, 129);
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
+  }
+
+  @Test
+  public void testNextAbsentValue2() {
+    Container container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
+    assertEquals(199, container.nextAbsentValue((char) 199));
+    assertEquals(501, container.nextAbsentValue((char) 200));
+    assertEquals(501, container.nextAbsentValue((char) 250));
+    assertEquals(2500, container.nextAbsentValue((char) 2500));
+    assertEquals(5201, container.nextAbsentValue((char) 5000));
+    assertEquals(5201, container.nextAbsentValue((char) 5200));
+  }
+
+  @Test
+  public void testNextAbsentValueEmpty() {
+    ArrayContainer container = new ArrayContainer();
+    for (int i = 0; i < 1000; i++) {
+      assertEquals(i, container.nextAbsentValue((char) i));
+    }
+  }
+
+  @Test
+  public void testNextAbsentValueSparse() {
+    ArrayContainer container = new ArrayContainer(new char[] {10, 20, 30});
+    assertEquals(9, container.nextAbsentValue((char) 9));
+    assertEquals(11, container.nextAbsentValue((char) 10));
+    assertEquals(11, container.nextAbsentValue((char) 11));
+    assertEquals(21, container.nextAbsentValue((char) 21));
+    assertEquals(31, container.nextAbsentValue((char) 30));
+  }
+
+  @Test
+  public void testNextAbsentValueUnsigned() {
+    ArrayContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)});
+    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 8)));
+  }
+
+  @Test
+  public void testRangeConsumer() {
+    char[] entries = new char[] {3, 4, 7, 8, 10, 65530, 65534, 65535};
+    ArrayContainer container = new ArrayContainer(entries);
+
+    ValidationRangeConsumer consumer =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {
+              ABSENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT,
+              PRESENT
+            });
+    container.forAllUntil(0, (char) 11, consumer);
+    assertEquals(11, consumer.getNumberOfValuesConsumed());
+
+    ValidationRangeConsumer consumer2 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {PRESENT, ABSENT, ABSENT, PRESENT, PRESENT});
+    container.forAllInRange((char) 4, (char) 9, consumer2);
+    assertEquals(5, consumer2.getNumberOfValuesConsumed());
+
+    ValidationRangeConsumer consumer3 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {
+              PRESENT, ABSENT, ABSENT, ABSENT, PRESENT, PRESENT
+            });
+    container.forAllFrom((char) 65530, consumer3);
+    assertEquals(6, consumer3.getNumberOfValuesConsumed());
+
+    ValidationRangeConsumer consumer4 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    container.forAll(0, consumer4);
+    consumer4.assertAllAbsentExcept(entries, 0);
+
+    ValidationRangeConsumer consumer5 =
+        ValidationRangeConsumer.ofSize(2 * BitmapContainer.MAX_CAPACITY);
+    consumer5.acceptAllAbsent(0, BitmapContainer.MAX_CAPACITY);
+    container.forAll(BitmapContainer.MAX_CAPACITY, consumer5);
+    consumer5.assertAllAbsentExcept(entries, BitmapContainer.MAX_CAPACITY);
+
+    container = new ArrayContainer();
+    ValidationRangeConsumer consumer6 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    container.forAll(0, consumer6);
+    consumer6.assertAllAbsent();
+
+    container = new ArrayContainer();
+    Container c = container.iadd(0, ArrayContainer.DEFAULT_MAX_SIZE);
+    assertTrue(container == c, "Container type changed!");
+    ValidationRangeConsumer consumer7 =
+        ValidationRangeConsumer.ofSize(ArrayContainer.DEFAULT_MAX_SIZE);
+    container.forAllUntil(0, (char) ArrayContainer.DEFAULT_MAX_SIZE, consumer7);
+    consumer7.assertAllPresent();
+  }
+
+  private static int lower16Bits(int x) {
+    return ((char) x) & 0xFFFF;
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestBitSetUtil.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestBitSetUtil.java
similarity index 84%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestBitSetUtil.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestBitSetUtil.java
index 1f945b586..a4db0f37a 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestBitSetUtil.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestBitSetUtil.java
@@ -1,5 +1,9 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -7,12 +11,9 @@
 import java.util.BitSet;
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-
 public class TestBitSetUtil {
-  private static BitSet appendRandomBitset(final Random random, final int offset,
-      final BitSet bitset, final int nbits) {
+  private static BitSet appendRandomBitset(
+      final Random random, final int offset, final BitSet bitset, final int nbits) {
     for (int i = 0; i < nbits; i++) {
       final boolean b = random.nextBoolean();
       bitset.set(offset + i, b);
@@ -25,9 +26,18 @@ private static BitSet randomBitset(final Random random, final int offset, final
     return appendRandomBitset(random, offset, bitset, length);
   }
 
-
   private void assertEqualBitsets(final BitSet bitset, final RoaringBitmap bitmap) {
-    assertTrue(BitSetUtil.equals(bitset, bitmap));
+    assertTrue(BitSetUtil.equals(bitset, bitmap), "bitset and bitmap do not match");
+    assertEquals(bitset, BitSetUtil.bitsetOf(bitmap), "bitsetOf doesn't match");
+    assertEquals(
+        bitset, BitSetUtil.bitsetOfWithoutCopy(bitmap), "bitsetOfWithoutCopy doesn't match");
+    assertEquals(
+        bitset, BitSet.valueOf(BitSetUtil.toByteArray(bitmap)), "toByteArray doesn't match");
+
+    RoaringBitmap runBitmap = bitmap.clone();
+    runBitmap.runOptimize();
+    assertEquals(
+        bitset, BitSetUtil.bitsetOf(runBitmap), "bitsetOf doesn't match for run optimized bitmap");
   }
 
   @Test
@@ -138,8 +148,8 @@ public void testSmallBitSet10000000() {
   }
 
   /*
-    The ByteBuffer->RoaringBitmap just replicate similar tests written for BitSet/long[]->RoaringBitmap
-   */
+   The ByteBuffer->RoaringBitmap just replicate similar tests written for BitSet/long[]->RoaringBitmap
+  */
 
   @Test
   public void testEmptyByteBuffer() {
@@ -204,7 +214,7 @@ public void testRandomByteBuffer() {
     final Random random = new Random(8934);
     final int runs = 100;
     final int maxNbits = 500000;
-    for (int i = 0;i < runs; ++i) {
+    for (int i = 0; i < runs; ++i) {
       final int offset = random.nextInt(maxNbits) & Integer.MAX_VALUE;
       final BitSet bitset = randomBitset(random, offset, random.nextInt(maxNbits));
       final RoaringBitmap bitmap = BitSetUtil.bitmapOf(toByteBuffer(bitset), false);
@@ -236,6 +246,19 @@ public void testByteArrayWithFastRank() {
     Assertions.assertTrue(bitmap instanceof FastRankRoaringBitmap);
   }
 
+  @Test
+  public void testBitmapOfNegative() {
+    final RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(-1);
+    IllegalArgumentException exception =
+        assertThrows(
+            IllegalArgumentException.class,
+            () -> {
+              BitSetUtil.bitsetOf(bitmap);
+            });
+    assertEquals("bitmap has negative bits set", exception.getMessage());
+  }
+
   private static ByteBuffer toByteBuffer(BitSet bitset) {
     return ByteBuffer.wrap(bitset.toByteArray());
   }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestBitmapContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestBitmapContainer.java
similarity index 63%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestBitmapContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestBitmapContainer.java
index f4ab4b4ef..b3dfbb179 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestBitmapContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestBitmapContainer.java
@@ -4,6 +4,13 @@
 
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
+
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -21,10 +28,6 @@
 import java.util.Random;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.*;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestBitmapContainer {
   private static BitmapContainer emptyContainer() {
@@ -47,14 +50,14 @@ public void testToString() {
     assertEquals("{5,6,7,8,9,10,11,12,13,14,65517,65533}", bc2.toString());
   }
 
-  @Test  
+  @Test
   public void testXOR() {
-    BitmapContainer bc = new BitmapContainer(100,10000);
+    BitmapContainer bc = new BitmapContainer(100, 10000);
     BitmapContainer bc2 = new BitmapContainer();
     BitmapContainer bc3 = new BitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -63,22 +66,22 @@ public void testXOR() {
     bc = (BitmapContainer) bc.ixor(bc2);
     assertEquals(0, bc.ixor(bc3).getCardinality());
   }
-  
-  @Test  
+
+  @Test
   public void testANDNOT() {
-    BitmapContainer bc = new BitmapContainer(100,10000);
+    BitmapContainer bc = new BitmapContainer(100, 10000);
     BitmapContainer bc2 = new BitmapContainer();
     BitmapContainer bc3 = new BitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
       }
     }
     RunContainer rc = new RunContainer();
-    rc.iadd(0, 1<<16);
+    rc.iadd(0, 1 << 16);
     bc = (BitmapContainer) bc.iand(rc);
     bc = (BitmapContainer) bc.iandNot(bc2);
     assertEquals(bc, bc3);
@@ -87,16 +90,15 @@ public void testANDNOT() {
     bc3.clear();
     assertEquals(0, bc3.getCardinality());
   }
-  
 
-  @Test  
+  @Test
   public void testAND() {
-    BitmapContainer bc = new BitmapContainer(100,10000);
+    BitmapContainer bc = new BitmapContainer(100, 10000);
     BitmapContainer bc2 = new BitmapContainer();
     BitmapContainer bc3 = new BitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -107,16 +109,14 @@ public void testAND() {
     assertEquals(0, bc.iand(bc3).getCardinality());
   }
 
-  
-
-  @Test  
+  @Test
   public void testOR() {
-    BitmapContainer bc = new BitmapContainer(100,10000);
+    BitmapContainer bc = new BitmapContainer(100, 10000);
     BitmapContainer bc2 = new BitmapContainer();
     BitmapContainer bc3 = new BitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -127,7 +127,7 @@ public void testOR() {
     bc2 = (BitmapContainer) bc2.ior(bc);
     assertEquals(bc, bc2);
     RunContainer rc = new RunContainer();
-    rc.iadd(0, 1<<16);
+    rc.iadd(0, 1 << 16);
     assertEquals(0, bc.iandNot(rc).getCardinality());
   }
 
@@ -182,93 +182,93 @@ public void testLazyORFull3() {
   @Test
   public void runConstructorForBitmap() {
     System.out.println("runConstructorForBitmap");
-    for(int start = 0; start <= (1<<16); start += 4096 ) {
-      for(int end = start; end <= (1<<16); end += 4096 ) {
-        BitmapContainer bc = new BitmapContainer(start,end);
+    for (int start = 0; start <= (1 << 16); start += 4096) {
+      for (int end = start; end <= (1 << 16); end += 4096) {
+        BitmapContainer bc = new BitmapContainer(start, end);
         BitmapContainer bc2 = new BitmapContainer();
-        BitmapContainer bc3 = (BitmapContainer) bc2.add(start,end);
+        BitmapContainer bc3 = (BitmapContainer) bc2.add(start, end);
         bc2.iadd(start, end);
-        assertEquals(bc.getCardinality(), end-start);
-        assertEquals(bc2.getCardinality(), end-start);
+        assertEquals(bc.getCardinality(), end - start);
+        assertEquals(bc2.getCardinality(), end - start);
         assertEquals(bc, bc2);
         assertEquals(bc, bc3);
-        assertEquals(0,bc2.remove(start, end).getCardinality());
-        assertEquals(bc2.getCardinality(), end-start);
-        assertEquals(0,bc2.not(start, end).getCardinality());
-      }  
+        assertEquals(0, bc2.remove(start, end).getCardinality());
+        assertEquals(bc2.getCardinality(), end - start);
+        assertEquals(0, bc2.not(start, end).getCardinality());
+      }
     }
   }
 
   @Test
   public void runConstructorForBitmap2() {
     System.out.println("runConstructorForBitmap2");
-    for(int start = 0; start <= (1<<16); start += 63 ) {
-      for(int end = start; end <= (1<<16); end += 63 ) {
-        BitmapContainer bc = new BitmapContainer(start,end);
+    for (int start = 0; start <= (1 << 16); start += 63) {
+      for (int end = start; end <= (1 << 16); end += 63) {
+        BitmapContainer bc = new BitmapContainer(start, end);
         BitmapContainer bc2 = new BitmapContainer();
-        BitmapContainer bc3 = (BitmapContainer) bc2.add(start,end);
+        BitmapContainer bc3 = (BitmapContainer) bc2.add(start, end);
         bc2.iadd(start, end);
-        assertEquals(bc.getCardinality(), end-start);
-        assertEquals(bc2.getCardinality(), end-start);
+        assertEquals(bc.getCardinality(), end - start);
+        assertEquals(bc2.getCardinality(), end - start);
         assertEquals(bc, bc2);
         assertEquals(bc, bc3);
-        assertEquals(0,bc2.remove(start, end).getCardinality());
-        assertEquals(bc2.getCardinality(), end-start);
-        assertEquals(0,bc2.not(start, end).getCardinality());
-      }  
+        assertEquals(0, bc2.remove(start, end).getCardinality());
+        assertEquals(bc2.getCardinality(), end - start);
+        assertEquals(0, bc2.not(start, end).getCardinality());
+      }
     }
   }
 
   @Test
   public void testRangeCardinality() {
-    BitmapContainer bc = generateContainer((char)100, (char)10000, 5);
+    BitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
     bc = (BitmapContainer) bc.add(200, 2000);
     assertEquals(8280, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality2() {
-    BitmapContainer bc = generateContainer((char)100, (char)10000, 5);
+    BitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
     bc.iadd(200, 2000);
     assertEquals(8280, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality3() {
-    BitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    BitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc.ior(rc);
     assertEquals(8677, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality4() {
-    BitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    BitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc = (BitmapContainer) bc.andNot(rc);
     assertEquals(5274, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality5() {
-    BitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    BitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc.iandNot(rc);
     assertEquals(5274, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality6() {
-    BitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 5200}, 3);
+    BitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 5200}, 3);
     bc = (BitmapContainer) bc.iand(rc);
     assertEquals(5046, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality7() {
-    BitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    BitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc.ixor(rc);
     assertEquals(6031, bc.cardinality);
   }
@@ -299,65 +299,65 @@ public void numberOfRunsLowerBound1() {
       // a big parameter like 100000 ensures that the full lower bound
       // is taken
 
-
       assertTrue(bc.numberOfRunsLowerBound(100000) <= bc.numberOfRuns());
-      assertEquals(bc.numberOfRuns(),
-          bc.numberOfRunsLowerBound(100000) + bc.numberOfRunsAdjustment());
+      assertEquals(
+          bc.numberOfRuns(), bc.numberOfRunsLowerBound(100000) + bc.numberOfRunsAdjustment());
 
       /*
        * the unrolled guys are commented out, did not help performance and slated for removal
        * soon...
-       * 
+       *
        * assertTrue(bc.numberOfRunsLowerBoundUnrolled2(1) > 1);
        * assertTrue(bc.numberOfRunsLowerBoundUnrolled2(100) <= bc.numberOfRuns());
-       * 
+       *
        * assertEquals(bc.numberOfRunsLowerBound(100000),
        * bc.numberOfRunsLowerBoundUnrolled2(100000));
        */
     }
-
   }
 
   @Test
   public void testNextTooLarge() {
-    assertThrows(ArrayIndexOutOfBoundsException.class,
-            () -> emptyContainer().nextSetBit(Short.MAX_VALUE + 1));
+    assertThrows(
+        ArrayIndexOutOfBoundsException.class,
+        () -> emptyContainer().nextSetBit(Short.MAX_VALUE + 1));
   }
 
   @Test
   public void testNextTooSmall() {
-    assertThrows(ArrayIndexOutOfBoundsException.class,
-            () -> emptyContainer().nextSetBit(-1));
+    assertThrows(ArrayIndexOutOfBoundsException.class, () -> emptyContainer().nextSetBit(-1));
   }
 
   @Test
   public void testPreviousTooLarge() {
-    assertThrows(ArrayIndexOutOfBoundsException.class,
-            () -> emptyContainer().prevSetBit(Short.MAX_VALUE + 1));
+    assertThrows(
+        ArrayIndexOutOfBoundsException.class,
+        () -> emptyContainer().prevSetBit(Short.MAX_VALUE + 1));
   }
 
-
   @Test
   public void testPreviousTooSmall() {
-    assertThrows(ArrayIndexOutOfBoundsException.class,
-            () -> emptyContainer().prevSetBit(-1));
+    assertThrows(ArrayIndexOutOfBoundsException.class, () -> emptyContainer().prevSetBit(-1));
   }
 
-
   @Test
   public void addInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container bc = new BitmapContainer();
-      bc.add(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container bc = new BitmapContainer();
+          bc.add(13, 1);
+        });
   }
 
   @Test
   public void iaddInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container bc = new BitmapContainer();
-      bc.iadd(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container bc = new BitmapContainer();
+          bc.iadd(13, 1);
+        });
   }
 
   @Test
@@ -526,7 +526,6 @@ public void orNot() {
 
       assertFalse(iterator.hasNext());
     }
-
   }
 
   @Test
@@ -606,23 +605,25 @@ public void orFullToRunContainer4() {
   @Test
   public void iremoveEmptyRange() {
     Container bc = new BitmapContainer();
-    bc = bc.iremove(1,1);
+    bc = bc.iremove(1, 1);
     assertEquals(0, bc.getCardinality());
   }
 
   @Test
   public void iremoveInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container ac = new BitmapContainer();
-      ac.iremove(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container ac = new BitmapContainer();
+          ac.iremove(13, 1);
+        });
   }
 
   @Test
   public void iremove() {
     Container bc = new BitmapContainer();
-    bc = bc.add(1,10);
-    bc = bc.iremove(5,10);
+    bc = bc.add(1, 10);
+    bc = bc.iremove(5, 10);
     assertEquals(4, bc.getCardinality());
     for (int i = 1; i < 5; i++) {
       assertTrue(bc.contains((char) i));
@@ -632,8 +633,8 @@ public void iremove() {
   @Test
   public void iremove2() {
     Container bc = new BitmapContainer();
-    bc = bc.add(1,8092);
-    bc = bc.iremove(1,10);
+    bc = bc.add(1, 8092);
+    bc = bc.iremove(1, 10);
     assertEquals(8082, bc.getCardinality());
     for (int i = 10; i < 8092; i++) {
       assertTrue(bc.contains((char) i));
@@ -643,7 +644,7 @@ public void iremove2() {
   @Test
   public void ixorRun() {
     Container bc = new BitmapContainer();
-    bc = bc.add(1,10);
+    bc = bc.add(1, 10);
     Container rc = new RunContainer();
     rc = rc.add(5, 15);
     bc = bc.ixor(rc);
@@ -659,7 +660,7 @@ public void ixorRun() {
   @Test
   public void ixorRun2() {
     Container bc = new BitmapContainer();
-    bc = bc.add(1,8092);
+    bc = bc.add(1, 8092);
     Container rc = new RunContainer();
     rc = rc.add(1, 10);
     bc = bc.ixor(rc);
@@ -671,26 +672,30 @@ public void ixorRun2() {
 
   @Test
   public void selectInvalidPosition() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container bc = new BitmapContainer();
-      bc = bc.add(1, 13);
-      bc.select(100);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container bc = new BitmapContainer();
+          bc = bc.add(1, 13);
+          bc.select(100);
+        });
   }
 
   @Test
   public void removeInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container ac = new BitmapContainer();
-      ac.remove(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container ac = new BitmapContainer();
+          ac.remove(13, 1);
+        });
   }
 
   @Test
   public void remove() {
     Container bc = new BitmapContainer();
-    bc = bc.add(1,8092);
-    bc = bc.remove(1,10);
+    bc = bc.add(1, 8092);
+    bc = bc.remove(1, 10);
     assertEquals(8082, bc.getCardinality());
     for (int i = 10; i < 8092; i++) {
       assertTrue(bc.contains((char) i));
@@ -700,7 +705,7 @@ public void remove() {
   @Test
   public void iandRun() {
     Container bc = new BitmapContainer();
-    bc = bc.add(0,8092);
+    bc = bc.add(0, 8092);
     Container rc = new RunContainer();
     rc = rc.add(1, 10);
     bc = bc.iand(rc);
@@ -743,42 +748,42 @@ public void testContainsBitmapContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsBitmapContainer_IncludeProperSubset() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new BitmapContainer().add(0,9);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(0, 9);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsBitmapContainer_IncludeSelf() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new BitmapContainer().add(0,10);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(0, 10);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsBitmapContainer_ExcludeSuperSet() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container superset = new BitmapContainer().add(0,20);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container superset = new BitmapContainer().add(0, 20);
     assertFalse(bc.contains(superset));
   }
 
   @Test
   public void testContainsBitmapContainer_IncludeProperSubsetDifferentStart() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new RunContainer().add(2,9);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new RunContainer().add(2, 9);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsBitmapContainer_ExcludeShiftedSet() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container shifted = new BitmapContainer().add(2,12);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container shifted = new BitmapContainer().add(2, 12);
     assertFalse(bc.contains(shifted));
   }
 
   @Test
   public void testContainsBitmapContainer_ExcludeDisJointSet() {
-    Container bc = new BitmapContainer().add(0,10);
+    Container bc = new BitmapContainer().add(0, 10);
     Container disjoint = new BitmapContainer().add(20, 40);
     assertFalse(bc.contains(disjoint));
     assertFalse(disjoint.contains(bc));
@@ -793,42 +798,42 @@ public void testContainsRunContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsRunContainer_IncludeProperSubset() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new RunContainer().add(0,9);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new RunContainer().add(0, 9);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsRunContainer_IncludeSelf() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new RunContainer().add(0,10);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new RunContainer().add(0, 10);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsRunContainer_ExcludeSuperSet() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container superset = new RunContainer().add(0,20);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container superset = new RunContainer().add(0, 20);
     assertFalse(bc.contains(superset));
   }
 
   @Test
   public void testContainsRunContainer_IncludeProperSubsetDifferentStart() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new RunContainer().add(2,9);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new RunContainer().add(2, 9);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsRunContainer_ExcludeShiftedSet() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container shifted = new RunContainer().add(2,12);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container shifted = new RunContainer().add(2, 12);
     assertFalse(bc.contains(shifted));
   }
 
   @Test
   public void testContainsRunContainer_ExcludeDisJointSet() {
-    Container bc = new BitmapContainer().add(0,10);
+    Container bc = new BitmapContainer().add(0, 10);
     Container disjoint = new RunContainer().add(20, 40);
     assertFalse(bc.contains(disjoint));
     assertFalse(disjoint.contains(bc));
@@ -843,36 +848,36 @@ public void testContainsArrayContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsArrayContainer_IncludeProperSubset() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new ArrayContainer().add(0,9);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(0, 9);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsArrayContainer_IncludeSelf() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new ArrayContainer().add(0,10);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(0, 10);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsArrayContainer_ExcludeSuperSet() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container superset = new ArrayContainer().add(0,20);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container superset = new ArrayContainer().add(0, 20);
     assertFalse(bc.contains(superset));
   }
 
   @Test
   public void testContainsArrayContainer_IncludeProperSubsetDifferentStart() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container subset = new ArrayContainer().add(2,9);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(2, 9);
     assertTrue(bc.contains(subset));
   }
 
   @Test
   public void testContainsArrayContainer_ExcludeShiftedSet() {
-    Container bc = new BitmapContainer().add(0,10);
-    Container shifted = new ArrayContainer().add(2,12);
+    Container bc = new BitmapContainer().add(0, 10);
+    Container shifted = new ArrayContainer().add(2, 12);
     assertFalse(bc.contains(shifted));
   }
 
@@ -895,24 +900,24 @@ public void testIntersectsWithRange() {
 
   public static Stream bitmapsForRangeIntersection() {
     return Stream.of(
-            Arguments.of(new BitmapContainer().add((char)60), 0, 61, true),
-            Arguments.of(new BitmapContainer().add((char)60), 0, 60, false),
-            Arguments.of(new BitmapContainer().add((char)1000), 0, 1001, true),
-            Arguments.of(new BitmapContainer().add((char)1000), 0, 1000, false),
-            Arguments.of(new BitmapContainer().add((char)1000), 0, 10000, true)
-    );
+        Arguments.of(new BitmapContainer().add((char) 60), 0, 61, true),
+        Arguments.of(new BitmapContainer().add((char) 60), 0, 60, false),
+        Arguments.of(new BitmapContainer().add((char) 1000), 0, 1001, true),
+        Arguments.of(new BitmapContainer().add((char) 1000), 0, 1000, false),
+        Arguments.of(new BitmapContainer().add((char) 1000), 0, 10000, true));
   }
 
   @ParameterizedTest
   @MethodSource("bitmapsForRangeIntersection")
-  public void testIntersectsWithRangeUpperBoundaries(Container container, int min, int sup, boolean intersects) {
+  public void testIntersectsWithRangeUpperBoundaries(
+      Container container, int min, int sup, boolean intersects) {
     assertEquals(intersects, container.intersects(min, sup));
   }
 
   @Test
   public void testIntersectsWithRangeHitScan() {
-    Container container = new BitmapContainer().add(0, 10)
-            .add(500, 512).add(lower16Bits(-50), lower16Bits(-10));
+    Container container =
+        new BitmapContainer().add(0, 10).add(500, 512).add(lower16Bits(-50), lower16Bits(-10));
     assertTrue(container.intersects(0, 1));
     assertTrue(container.intersects(0, 101));
     assertTrue(container.intersects(0, 1 << 16));
@@ -920,7 +925,6 @@ public void testIntersectsWithRangeHitScan() {
     assertTrue(container.intersects(501, 511));
   }
 
-
   @Test
   public void testIntersectsWithRangeUnsigned() {
     Container container = new BitmapContainer().add(lower16Bits(-50), lower16Bits(-10));
@@ -928,7 +932,7 @@ public void testIntersectsWithRangeUnsigned() {
     assertTrue(container.intersects(0, lower16Bits(-40)));
     assertFalse(container.intersects(lower16Bits(-100), lower16Bits(-55)));
     assertFalse(container.intersects(lower16Bits(-9), lower16Bits(-1)));
-    //assertTrue(container.intersects(11, (char)-1)); // forbidden
+    // assertTrue(container.intersects(11, (char)-1)); // forbidden
   }
 
   @Test
@@ -940,7 +944,6 @@ public void testIntersectsAtEndWord() {
     assertFalse(container.intersects(lower16Bits(-10), lower16Bits(-1)));
   }
 
-
   @Test
   public void testIntersectsAtEndWord2() {
     Container container = new BitmapContainer().add(lower16Bits(500), lower16Bits(-500));
@@ -978,7 +981,6 @@ public void testContainsRangeMultiWord() {
     assertFalse(container.contains(64 * 10, 2 + 64 * 13));
   }
 
-
   @Test
   public void testContainsRangeSubWord() {
     long[] bitmap = evenBits();
@@ -1020,267 +1022,278 @@ public void testNextSetBitBeforeStart() {
 
   @Test
   public void testNextValue() {
-    BitmapContainer container = new ArrayContainer(new char[] { 10, 20, 30}).toBitmapContainer();
-    assertEquals(10, container.nextValue((char)10));
-    assertEquals(20, container.nextValue((char)11));
-    assertEquals(30, container.nextValue((char)30));
+    BitmapContainer container = new ArrayContainer(new char[] {10, 20, 30}).toBitmapContainer();
+    assertEquals(10, container.nextValue((char) 10));
+    assertEquals(20, container.nextValue((char) 11));
+    assertEquals(30, container.nextValue((char) 30));
   }
 
   @Test
   public void testNextValueAfterEnd() {
-    BitmapContainer container = new ArrayContainer(new char[] { 10, 20, 30}).toBitmapContainer();
-    assertEquals(-1, container.nextValue((char)31));
+    BitmapContainer container = new ArrayContainer(new char[] {10, 20, 30}).toBitmapContainer();
+    assertEquals(-1, container.nextValue((char) 31));
   }
 
   @Test
   public void testNextValue2() {
     BitmapContainer container = new BitmapContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(-1, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)5000));
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(-1, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 5000));
   }
 
   @Test
   public void testNextValueBetweenRuns() {
-    BitmapContainer container = new BitmapContainer().iadd(64, 129).iadd(256, 321).toBitmapContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(256, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)512));
+    BitmapContainer container =
+        new BitmapContainer().iadd(64, 129).iadd(256, 321).toBitmapContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(256, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 512));
   }
 
   @Test
   public void testNextValue3() {
-    BitmapContainer container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)63));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(200, container.nextValue((char)129));
-    assertEquals(200, container.nextValue((char)199));
-    assertEquals(200, container.nextValue((char)200));
-    assertEquals(250, container.nextValue((char)250));
-    assertEquals(5000, container.nextValue((char)2500));
-    assertEquals(5000, container.nextValue((char)5000));
-    assertEquals(5200, container.nextValue((char)5200));
-    assertEquals(-1, container.nextValue((char)5201));
+    BitmapContainer container =
+        new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 63));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(200, container.nextValue((char) 129));
+    assertEquals(200, container.nextValue((char) 199));
+    assertEquals(200, container.nextValue((char) 200));
+    assertEquals(250, container.nextValue((char) 250));
+    assertEquals(5000, container.nextValue((char) 2500));
+    assertEquals(5000, container.nextValue((char) 5000));
+    assertEquals(5200, container.nextValue((char) 5200));
+    assertEquals(-1, container.nextValue((char) 5201));
   }
 
   @Test
   public void testNextValueUnsigned() {
-    BitmapContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}).toBitmapContainer();
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 7)));
-    assertEquals(-1, container.nextValue((char)((1 << 15) | 8)));
+    BitmapContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)})
+            .toBitmapContainer();
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 7)));
+    assertEquals(-1, container.nextValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testPreviousValue1() {
     BitmapContainer container = new ArrayContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
   }
 
   @Test
   public void testPreviousValue2() {
-    BitmapContainer container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
-    assertEquals(128, container.previousValue((char)199));
-    assertEquals(200, container.previousValue((char)200));
-    assertEquals(250, container.previousValue((char)250));
-    assertEquals(500, container.previousValue((char)2500));
-    assertEquals(5000, container.previousValue((char)5000));
-    assertEquals(5200, container.previousValue((char)5200));
+    BitmapContainer container =
+        new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
+    assertEquals(128, container.previousValue((char) 199));
+    assertEquals(200, container.previousValue((char) 200));
+    assertEquals(250, container.previousValue((char) 250));
+    assertEquals(500, container.previousValue((char) 2500));
+    assertEquals(5000, container.previousValue((char) 5000));
+    assertEquals(5200, container.previousValue((char) 5200));
   }
 
   @Test
   public void testPreviousValueBeforeStart() {
-    BitmapContainer container = new ArrayContainer(new char[] { 10, 20, 30}).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)5));
+    BitmapContainer container = new ArrayContainer(new char[] {10, 20, 30}).toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) 5));
   }
 
   @Test
   public void testPreviousValueSparse() {
-    BitmapContainer container = new ArrayContainer(new char[] { 10, 20, 30}).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)9));
-    assertEquals(10, container.previousValue((char)10));
-    assertEquals(10, container.previousValue((char)11));
-    assertEquals(20, container.previousValue((char)21));
-    assertEquals(30, container.previousValue((char)30));
+    BitmapContainer container = new ArrayContainer(new char[] {10, 20, 30}).toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) 9));
+    assertEquals(10, container.previousValue((char) 10));
+    assertEquals(10, container.previousValue((char) 11));
+    assertEquals(20, container.previousValue((char) 21));
+    assertEquals(30, container.previousValue((char) 30));
   }
 
   @Test
   public void testPreviousValueAfterEnd() {
-    BitmapContainer container = new ArrayContainer(new char[] { 10, 20, 30}).toBitmapContainer();
-    assertEquals(30, container.previousValue((char)31));
+    BitmapContainer container = new ArrayContainer(new char[] {10, 20, 30}).toBitmapContainer();
+    assertEquals(30, container.previousValue((char) 31));
   }
 
   @Test
   public void testPreviousEvenBits() {
     BitmapContainer container = new BitmapContainer(evenBits(), 1 << 15);
-    assertEquals(0, container.previousValue((char)0));
-    assertEquals(0, container.previousValue((char)1));
-    assertEquals(2, container.previousValue((char)2));
-    assertEquals(2, container.previousValue((char)3));
+    assertEquals(0, container.previousValue((char) 0));
+    assertEquals(0, container.previousValue((char) 1));
+    assertEquals(2, container.previousValue((char) 2));
+    assertEquals(2, container.previousValue((char) 3));
   }
 
   @Test
   public void testPreviousValueUnsigned() {
-    BitmapContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 8)));
+    BitmapContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)})
+            .toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testPreviousAbsentValue1() {
     BitmapContainer container = new ArrayContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
   }
 
   @Test
   public void testPreviousAbsentValue2() {
-    BitmapContainer container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
-    assertEquals(199, container.previousAbsentValue((char)199));
-    assertEquals(199, container.previousAbsentValue((char)200));
-    assertEquals(199, container.previousAbsentValue((char)250));
-    assertEquals(2500, container.previousAbsentValue((char)2500));
-    assertEquals(4999, container.previousAbsentValue((char)5000));
-    assertEquals(4999, container.previousAbsentValue((char)5200));
+    BitmapContainer container =
+        new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
+    assertEquals(199, container.previousAbsentValue((char) 199));
+    assertEquals(199, container.previousAbsentValue((char) 200));
+    assertEquals(199, container.previousAbsentValue((char) 250));
+    assertEquals(2500, container.previousAbsentValue((char) 2500));
+    assertEquals(4999, container.previousAbsentValue((char) 5000));
+    assertEquals(4999, container.previousAbsentValue((char) 5200));
   }
 
   @Test
   public void testPreviousAbsentValueEmpty() {
     BitmapContainer container = new ArrayContainer().toBitmapContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.previousAbsentValue((char)i));
+      assertEquals(i, container.previousAbsentValue((char) i));
     }
   }
 
   @Test
   public void testPreviousAbsentValueSparse() {
-    BitmapContainer container = new ArrayContainer(new char[] { 10, 20, 30}).toBitmapContainer();
-    assertEquals(9, container.previousAbsentValue((char)9));
-    assertEquals(9, container.previousAbsentValue((char)10));
-    assertEquals(11, container.previousAbsentValue((char)11));
-    assertEquals(21, container.previousAbsentValue((char)21));
-    assertEquals(29, container.previousAbsentValue((char)30));
+    BitmapContainer container = new ArrayContainer(new char[] {10, 20, 30}).toBitmapContainer();
+    assertEquals(9, container.previousAbsentValue((char) 9));
+    assertEquals(9, container.previousAbsentValue((char) 10));
+    assertEquals(11, container.previousAbsentValue((char) 11));
+    assertEquals(21, container.previousAbsentValue((char) 21));
+    assertEquals(29, container.previousAbsentValue((char) 30));
   }
 
   @Test
   public void testPreviousAbsentEvenBits() {
     BitmapContainer container = new BitmapContainer(evenBits(), 1 << 15);
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i - 1, container.previousAbsentValue((char)i));
-      assertEquals(i + 1, container.previousAbsentValue((char)(i+1)));
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i - 1, container.previousAbsentValue((char) i));
+      assertEquals(i + 1, container.previousAbsentValue((char) (i + 1)));
     }
   }
 
   @Test
   public void testPreviousAbsentValueUnsigned() {
-    BitmapContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}).toBitmapContainer();
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char)((1 << 15) | 8)));
+    BitmapContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)})
+            .toBitmapContainer();
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testNextAbsentValue1() {
     BitmapContainer container = new ArrayContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
   }
 
   @Test
   public void testNextAbsentValue2() {
-    BitmapContainer container = new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
-    assertEquals(199, container.nextAbsentValue((char)199));
-    assertEquals(501, container.nextAbsentValue((char)200));
-    assertEquals(501, container.nextAbsentValue((char)250));
-    assertEquals(2500, container.nextAbsentValue((char)2500));
-    assertEquals(5201, container.nextAbsentValue((char)5000));
-    assertEquals(5201, container.nextAbsentValue((char)5200));
+    BitmapContainer container =
+        new ArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
+    assertEquals(199, container.nextAbsentValue((char) 199));
+    assertEquals(501, container.nextAbsentValue((char) 200));
+    assertEquals(501, container.nextAbsentValue((char) 250));
+    assertEquals(2500, container.nextAbsentValue((char) 2500));
+    assertEquals(5201, container.nextAbsentValue((char) 5000));
+    assertEquals(5201, container.nextAbsentValue((char) 5200));
   }
 
   @Test
   public void testNextAbsentValueEmpty() {
     BitmapContainer container = new ArrayContainer().toBitmapContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.nextAbsentValue((char)i));
+      assertEquals(i, container.nextAbsentValue((char) i));
     }
   }
 
   @Test
   public void testNextAbsentValueSparse() {
-    BitmapContainer container = new ArrayContainer(new char[] { 10, 20, 30}).toBitmapContainer();
-    assertEquals(9, container.nextAbsentValue((char)9));
-    assertEquals(11, container.nextAbsentValue((char)10));
-    assertEquals(11, container.nextAbsentValue((char)11));
-    assertEquals(21, container.nextAbsentValue((char)21));
-    assertEquals(31, container.nextAbsentValue((char)30));
+    BitmapContainer container = new ArrayContainer(new char[] {10, 20, 30}).toBitmapContainer();
+    assertEquals(9, container.nextAbsentValue((char) 9));
+    assertEquals(11, container.nextAbsentValue((char) 10));
+    assertEquals(11, container.nextAbsentValue((char) 11));
+    assertEquals(21, container.nextAbsentValue((char) 21));
+    assertEquals(31, container.nextAbsentValue((char) 30));
   }
 
   @Test
   public void testNextAbsentEvenBits() {
     BitmapContainer container = new BitmapContainer(evenBits(), 1 << 15);
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i + 1, container.nextAbsentValue((char)i));
-      assertEquals(i + 1, container.nextAbsentValue((char)(i+1)));
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i + 1, container.nextAbsentValue((char) i));
+      assertEquals(i + 1, container.nextAbsentValue((char) (i + 1)));
     }
   }
 
   @Test
   public void testNextAbsentValueUnsigned() {
-    BitmapContainer container = new ArrayContainer(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}).toBitmapContainer();
-    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 8)));
+    BitmapContainer container =
+        new ArrayContainer(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)})
+            .toBitmapContainer();
+    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 8)));
   }
 
   @Test
@@ -1288,43 +1301,52 @@ public void testRangeConsumer() {
     char[] entries = new char[] {3, 4, 7, 8, 10, 65530, 65534, 65535};
     BitmapContainer container = new ArrayContainer(entries).toBitmapContainer();
 
-    ValidationRangeConsumer consumer = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] {
-        ABSENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, PRESENT
-    });
+    ValidationRangeConsumer consumer =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {
+              ABSENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT,
+              PRESENT
+            });
     container.forAllUntil(0, (char) 11, consumer);
     assertEquals(11, consumer.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer2 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] {
-        PRESENT, ABSENT, ABSENT, PRESENT, PRESENT
-    });
+    ValidationRangeConsumer consumer2 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {PRESENT, ABSENT, ABSENT, PRESENT, PRESENT});
     container.forAllInRange((char) 4, (char) 9, consumer2);
     assertEquals(5, consumer2.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer3 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] {
-        PRESENT, ABSENT, ABSENT, ABSENT, PRESENT, PRESENT
-    });
+    ValidationRangeConsumer consumer3 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {
+              PRESENT, ABSENT, ABSENT, ABSENT, PRESENT, PRESENT
+            });
     container.forAllFrom((char) 65530, consumer3);
     assertEquals(6, consumer3.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer4 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer4 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
     container.forAll(0, consumer4);
     consumer4.assertAllAbsentExcept(entries, 0);
 
-    ValidationRangeConsumer consumer5 = ValidationRangeConsumer.ofSize(2 * BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer5 =
+        ValidationRangeConsumer.ofSize(2 * BitmapContainer.MAX_CAPACITY);
     consumer5.acceptAllAbsent(0, BitmapContainer.MAX_CAPACITY);
     container.forAll(BitmapContainer.MAX_CAPACITY, consumer5);
     consumer5.assertAllAbsentExcept(entries, BitmapContainer.MAX_CAPACITY);
 
     // Completely Empty
     container = new BitmapContainer();
-    ValidationRangeConsumer consumer6 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer6 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
     container.forAll(0, consumer6);
     consumer6.assertAllAbsent();
 
     // Completely Full
     container = new BitmapContainer();
     container.iadd(0, BitmapContainer.MAX_CAPACITY);
-    ValidationRangeConsumer consumer7 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer7 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
     container.forAll(0, consumer7);
     consumer7.assertAllPresent();
 
@@ -1350,6 +1372,6 @@ private static long[] evenBits() {
   }
 
   private static int lower16Bits(int x) {
-    return (char)x;
+    return (char) x;
   }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestConcatenation.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestConcatenation.java
similarity index 55%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestConcatenation.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestConcatenation.java
index 8cba22bde..fbd6d5ede 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestConcatenation.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestConcatenation.java
@@ -1,5 +1,11 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.roaringbitmap.buffer.MutableRoaringBitmap;
+
 import com.google.common.io.ByteArrayDataOutput;
 import com.google.common.io.ByteStreams;
 import com.google.common.io.Files;
@@ -10,7 +16,6 @@
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.roaringbitmap.buffer.MutableRoaringBitmap;
 
 import java.io.File;
 import java.io.IOException;
@@ -18,10 +23,6 @@
 import java.util.Arrays;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestConcatenation {
 
@@ -29,37 +30,38 @@ public class TestConcatenation {
 
   @BeforeAll
   public static void setup() {
-    DATA = new Arguments[]{
-        // the data set reported in issue #260
-        Arguments.of(read("src/test/resources/testdata/testIssue260.txt"), 5950),
-        Arguments.of(read("src/test/resources/testdata/offset_failure_case_1.txt"), 20),
-        Arguments.of(read("src/test/resources/testdata/offset_failure_case_2.txt"), 20),
-        Arguments.of(read("src/test/resources/testdata/offset_failure_case_3.txt"), 20),
-        // a range of test cases with offsets being divisors of 65536
-        Arguments.of(testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(), 1 << 16),
-        Arguments.of(testCase().withRunAt(0).withBitmapAt(1).withBitmapAt(2).build(), 1 << 16),
-        Arguments.of(testCase().withBitmapAt(0).withBitmapAt(1).withRunAt(2).build(), 1 << 16),
-        Arguments.of(testCase().withBitmapAt(0).withRunAt(2).withArrayAt(4).build(), 1 << 16),
-        Arguments.of(testCase().withRunAt(0).withBitmapAt(2).withBitmapAt(4).build(), 1 << 16),
-        Arguments.of(testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).build(), 1 << 16),
-        // awkward offsets
-        Arguments.of(testCase().withBitmapAt(0).build(), 20),
-        Arguments.of(testCase().withRunAt(0).build(), 20),
-        Arguments.of(testCase().withArrayAt(0).build(), 20),
-        Arguments.of(testCase().withBitmapAt(0).withRunAt(1).build(), 20),
-        Arguments.of(testCase().withRunAt(0).withBitmapAt(1).build(), 20),
-        Arguments.of(testCase().withArrayAt(0).withBitmapAt(1).build(), 20),
-        Arguments.of(testCase().withBitmapAt(0).withRunAt(2).build(), 20),
-        Arguments.of(testCase().withRunAt(0).withBitmapAt(2).build(), 20),
-        Arguments.of(testCase().withArrayAt(0).withBitmapAt(2).build(), 20),
-        Arguments.of(testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(), 20),
-        Arguments.of(testCase().withRunAt(0).withBitmapAt(1).withBitmapAt(2).build(), 20),
-        Arguments.of(testCase().withArrayAt(0).withBitmapAt(1).withRunAt(2).build(), 20),
-        Arguments.of(testCase().withBitmapAt(0).withRunAt(2).withArrayAt(4).build(), 20),
-        Arguments.of(testCase().withRunAt(0).withBitmapAt(2).withBitmapAt(4).build(), 20),
-        Arguments.of(testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).build(), 20),
-        Arguments.of(testCase().withRange(0, 1 << 16).build(), 20)
-    };
+    DATA =
+        new Arguments[] {
+          // the data set reported in issue #260
+          Arguments.of(read("src/test/resources/testdata/testIssue260.txt"), 5950),
+          Arguments.of(read("src/test/resources/testdata/offset_failure_case_1.txt"), 20),
+          Arguments.of(read("src/test/resources/testdata/offset_failure_case_2.txt"), 20),
+          Arguments.of(read("src/test/resources/testdata/offset_failure_case_3.txt"), 20),
+          // a range of test cases with offsets being divisors of 65536
+          Arguments.of(testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(), 1 << 16),
+          Arguments.of(testCase().withRunAt(0).withBitmapAt(1).withBitmapAt(2).build(), 1 << 16),
+          Arguments.of(testCase().withBitmapAt(0).withBitmapAt(1).withRunAt(2).build(), 1 << 16),
+          Arguments.of(testCase().withBitmapAt(0).withRunAt(2).withArrayAt(4).build(), 1 << 16),
+          Arguments.of(testCase().withRunAt(0).withBitmapAt(2).withBitmapAt(4).build(), 1 << 16),
+          Arguments.of(testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).build(), 1 << 16),
+          // awkward offsets
+          Arguments.of(testCase().withBitmapAt(0).build(), 20),
+          Arguments.of(testCase().withRunAt(0).build(), 20),
+          Arguments.of(testCase().withArrayAt(0).build(), 20),
+          Arguments.of(testCase().withBitmapAt(0).withRunAt(1).build(), 20),
+          Arguments.of(testCase().withRunAt(0).withBitmapAt(1).build(), 20),
+          Arguments.of(testCase().withArrayAt(0).withBitmapAt(1).build(), 20),
+          Arguments.of(testCase().withBitmapAt(0).withRunAt(2).build(), 20),
+          Arguments.of(testCase().withRunAt(0).withBitmapAt(2).build(), 20),
+          Arguments.of(testCase().withArrayAt(0).withBitmapAt(2).build(), 20),
+          Arguments.of(testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(), 20),
+          Arguments.of(testCase().withRunAt(0).withBitmapAt(1).withBitmapAt(2).build(), 20),
+          Arguments.of(testCase().withArrayAt(0).withBitmapAt(1).withRunAt(2).build(), 20),
+          Arguments.of(testCase().withBitmapAt(0).withRunAt(2).withArrayAt(4).build(), 20),
+          Arguments.of(testCase().withRunAt(0).withBitmapAt(2).withBitmapAt(4).build(), 20),
+          Arguments.of(testCase().withArrayAt(0).withBitmapAt(2).withRunAt(4).build(), 20),
+          Arguments.of(testCase().withRange(0, 1 << 16).build(), 20)
+        };
   }
 
   @AfterAll
@@ -67,7 +69,6 @@ public static void clear() {
     DATA = null;
   }
 
-
   public static Stream params() {
     return Stream.of(DATA);
   }
@@ -90,7 +91,8 @@ public void testElementwiseOffsetAppliedCorrectlyBuffer(RoaringBitmap bitmap, in
     for (int i = 0; i < array1.length; ++i) {
       array1[i] += offset;
     }
-    MutableRoaringBitmap shifted = MutableRoaringBitmap.addOffset(bitmap.toMutableRoaringBitmap(), offset);
+    MutableRoaringBitmap shifted =
+        MutableRoaringBitmap.addOffset(bitmap.toMutableRoaringBitmap(), offset);
     assertArrayEquals(array1, shifted.toArray(), failureMessage(bitmap));
   }
 
@@ -104,7 +106,8 @@ public void testCardinalityPreserved(RoaringBitmap bitmap, int offset) {
   @ParameterizedTest(name = "{1}")
   @MethodSource("params")
   public void testCardinalityPreservedBuffer(RoaringBitmap bitmap, int offset) {
-    MutableRoaringBitmap shifted = MutableRoaringBitmap.addOffset(bitmap.toMutableRoaringBitmap(), offset);
+    MutableRoaringBitmap shifted =
+        MutableRoaringBitmap.addOffset(bitmap.toMutableRoaringBitmap(), offset);
     assertEquals(bitmap.getCardinality(), shifted.getCardinality(), failureMessage(bitmap));
   }
 
@@ -121,8 +124,10 @@ public void canSerializeAndDeserialize(RoaringBitmap bitmap, int offset) throws
 
   @ParameterizedTest(name = "{1}")
   @MethodSource("params")
-  public void canSerializeAndDeserializeBuffer(RoaringBitmap bitmap, int offset) throws IOException {
-    MutableRoaringBitmap shifted = MutableRoaringBitmap.addOffset(bitmap.toMutableRoaringBitmap(), offset);
+  public void canSerializeAndDeserializeBuffer(RoaringBitmap bitmap, int offset)
+      throws IOException {
+    MutableRoaringBitmap shifted =
+        MutableRoaringBitmap.addOffset(bitmap.toMutableRoaringBitmap(), offset);
     ByteArrayDataOutput out = ByteStreams.newDataOutput();
     shifted.serialize(out);
     MutableRoaringBitmap deserialized = new MutableRoaringBitmap();
@@ -132,10 +137,12 @@ public void canSerializeAndDeserializeBuffer(RoaringBitmap bitmap, int offset) t
 
   private static RoaringBitmap read(String classPathResource) {
     try {
-      RoaringBitmapWriter writer = RoaringBitmapWriter.writer().constantMemory().get();
-      Arrays.stream(Files.readFirstLine(new File(classPathResource), StandardCharsets.UTF_8).split(","))
-              .mapToInt(Integer::parseInt)
-              .forEach(writer::add);
+      RoaringBitmapWriter writer =
+          RoaringBitmapWriter.writer().constantMemory().get();
+      Arrays.stream(
+              Files.readFirstLine(new File(classPathResource), StandardCharsets.UTF_8).split(","))
+          .mapToInt(Integer::parseInt)
+          .forEach(writer::add);
       writer.flush();
       return writer.getUnderlying();
     } catch (IOException e) {
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestContainer.java
similarity index 85%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestContainer.java
index 5558267e2..9332513bb 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestContainer.java
@@ -3,23 +3,30 @@
  */
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import org.junit.jupiter.api.Test;
-
-import java.util.*;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import static org.junit.jupiter.api.Assertions.*;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.junit.jupiter.params.provider.ValueSource;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
 
 /**
  * Various tests on Container and its subclasses, ArrayContainer and BitmapContainer
@@ -27,7 +34,7 @@
 @SuppressWarnings({"static-method"})
 public class TestContainer {
 
-  private final static Class[] CONTAINER_TYPES =
+  private static final Class[] CONTAINER_TYPES =
       new Class[] {ArrayContainer.class, BitmapContainer.class, RunContainer.class};
 
   @Test
@@ -36,7 +43,7 @@ public void testNames() {
     assertEquals(new ArrayContainer().getContainerName(), Container.ContainerNames[1]);
     assertEquals(new RunContainer().getContainerName(), Container.ContainerNames[2]);
   }
-  
+
   public static boolean checkContent(Container c, char[] s) {
     CharIterator si = c.getCharIterator();
     int ctr = 0;
@@ -254,10 +261,25 @@ public void inotTest10() {
     final Container c1 = c.inot(65190, 65201);
     assertTrue(c1 instanceof ArrayContainer);
     assertEquals(14, c1.getCardinality());
-    assertTrue(checkContent(c1,
-        new char[] {0, 2, 4, (char) 65190, (char) 65191, (char) 65192, (char) 65193,
-            (char) 65194, (char) 65195, (char) 65196, (char) 65197, (char) 65198,
-            (char) 65199, (char) 65200}));
+    assertTrue(
+        checkContent(
+            c1,
+            new char[] {
+              0,
+              2,
+              4,
+              (char) 65190,
+              (char) 65191,
+              (char) 65192,
+              (char) 65193,
+              (char) 65194,
+              (char) 65195,
+              (char) 65196,
+              (char) 65197,
+              (char) 65198,
+              (char) 65199,
+              (char) 65200
+            }));
   }
 
   @Test
@@ -320,7 +342,6 @@ public void inotTest5() {
     c = c.inot(4, 1000); // back, as a bitmap
     assertTrue(c instanceof BitmapContainer);
     assertTrue(checkContent(c, content));
-
   }
 
   @Test
@@ -628,8 +649,6 @@ public void notTest9() {
     assertTrue(checkContent(c2, content));
   }
 
-
-
   @Test
   public void numberOfRuns() {
     char[] positions = {3, 4, 5, 10, 11, 13, 15, 62, 63, 64, 65};
@@ -645,8 +664,6 @@ public void numberOfRuns() {
     assertEquals(rc.numberOfRuns(), bc.numberOfRuns());
   }
 
-
-
   @Test
   public void numberOfRuns1() {
     System.out.println("numberOfRuns1");
@@ -673,8 +690,8 @@ public void numberOfRuns1() {
       assertEquals(rc.numberOfRuns(), ac.numberOfRuns());
       assertEquals(rc.numberOfRuns(), bc.numberOfRuns());
       // a limit of 50k assures that the no early bail-out can be taken
-      assertEquals(bc.numberOfRuns(),
-          bc.numberOfRunsLowerBound(50000) + bc.numberOfRunsAdjustment());
+      assertEquals(
+          bc.numberOfRuns(), bc.numberOfRunsLowerBound(50000) + bc.numberOfRunsAdjustment());
       // inferior approaches to be removed in a future cleanup, now commented...
       // assertEquals(bc.numberOfRunsLowerBound(), bc.numberOfRunsLowerBoundUnrolled());
       // assertEquals(bc.numberOfRunsLowerBound(), bc.numberOfRunsLowerBoundUnrolled2());
@@ -682,8 +699,6 @@ public void numberOfRuns1() {
     }
   }
 
-
-
   @Test
   public void or1() {
     System.out.println("or1");
@@ -699,7 +714,6 @@ public void or1() {
     assertTrue(checkContent(result, new char[] {1, 3, 5, (char) 50000, (char) 50001}));
   }
 
-
   @Test
   public void or2() {
     System.out.println("or2");
@@ -716,8 +730,9 @@ public void or2() {
     ac1.add((char) 50004);
 
     Container result = ac.or(ac1.getCharIterator());
-    assertTrue(checkContent(result,
-        new char[] {1, 4, 5, (char) 50000, (char) 50002, (char) 50003, (char) 50004}));
+    assertTrue(
+        checkContent(
+            result, new char[] {1, 4, 5, (char) 50000, (char) 50002, (char) 50003, (char) 50004}));
   }
 
   @Test
@@ -742,12 +757,14 @@ public void or3() {
     ac1.add((char) 50004);
 
     Container result = ac.or(ac1.getCharIterator());
-    assertTrue(checkContent(result, new char[] {1, 3, 4, 5, (char) 50000, (char) 50001,
-        (char) 50002, (char) 50003, (char) 50004}));
+    assertTrue(
+        checkContent(
+            result,
+            new char[] {
+              1, 3, 4, 5, (char) 50000, (char) 50001, (char) 50002, (char) 50003, (char) 50004
+            }));
   }
 
-
-
   @Test
   public void or4() {
     System.out.println("or4");
@@ -770,14 +787,24 @@ public void or4() {
     ac1.add((char) 50003);
     ac1.add((char) 50004);
 
-
     Container result = ac.or(ac1.getCharIterator());
-    assertTrue(checkContent(result, new char[] {1, 3, 4, 5, (char) 50000, (char) 50001,
-        (char) 50002, (char) 50003, (char) 50004, (char) 50011}));
+    assertTrue(
+        checkContent(
+            result,
+            new char[] {
+              1,
+              3,
+              4,
+              5,
+              (char) 50000,
+              (char) 50001,
+              (char) 50002,
+              (char) 50003,
+              (char) 50004,
+              (char) 50011
+            }));
   }
 
-
-
   @Test
   public void or5() {
     System.out.println("or5");
@@ -801,31 +828,54 @@ public void or5() {
     assertTrue(checkContent(result, new char[] {1, 3, 4, 5, (char) 50000, (char) 50001}));
   }
 
+  @Test
+  public void or6() {
+    System.out.println("or6");
+    RunContainer rc1 = new RunContainer();
+    for (int i = 0; i < 6144; i += 6) {
+      rc1.iadd(i, i + 1);
+    }
+
+    RunContainer rc2 = new RunContainer();
+
+    for (int i = 3; i < 6144; i += 6) {
+      rc2.iadd(i, i + 1);
+    }
+
+    Container result = rc1.or(rc2);
+    assertTrue(result.getCardinality() < ArrayContainer.DEFAULT_MAX_SIZE);
+    assertTrue(result instanceof ArrayContainer);
+  }
+
   @Test
   public void testXorContainer() throws Exception {
     Container rc1 = new RunContainer(new char[] {10, 12, 90, 10}, 2);
-    Container rc2 = new RunContainer(new char[]{1, 10, 40, 400, 900, 10}, 3);
+    Container rc2 = new RunContainer(new char[] {1, 10, 40, 400, 900, 10}, 3);
     Container bc1 = new BitmapContainer().add(10, 20);
     Container bc2 = new BitmapContainer().add(21, 30);
     Container ac1 = new ArrayContainer(4, new char[] {10, 12, 90, 104});
-    Container ac2 = new ArrayContainer(2, new char[]{1, 10, 40, 400, 900, 1910});
-    for(Set test : Sets.powerSet(ImmutableSet.of(rc1, rc2, bc1, bc2, ac1, ac2))) {
+    Container ac2 = new ArrayContainer(2, new char[] {1, 10, 40, 400, 900, 1910});
+    for (Set test : Sets.powerSet(ImmutableSet.of(rc1, rc2, bc1, bc2, ac1, ac2))) {
       Iterator it = test.iterator();
-      if(test.size() == 1) { // compare with self
+      if (test.size() == 1) { // compare with self
         Container x = it.next();
-        assertEquals(x.xor(x).getCardinality(), x.xorCardinality(x), x.getContainerName() + ": " + x);
-      } else if(test.size() == 2) {
+        assertEquals(
+            x.xor(x).getCardinality(), x.xorCardinality(x), x.getContainerName() + ": " + x);
+      } else if (test.size() == 2) {
         Container x = it.next();
         Container y = it.next();
         assertEquals(
-                x.xor(y).getCardinality(), x.xorCardinality(y), x.getContainerName() + " " + x + " " + y.getContainerName() + " " + y);
-        assertEquals(y.xor(x).getCardinality(), y.xorCardinality(x), y.getContainerName() + " " + y + " " + x.getContainerName() + " " + x);
+            x.xor(y).getCardinality(),
+            x.xorCardinality(y),
+            x.getContainerName() + " " + x + " " + y.getContainerName() + " " + y);
+        assertEquals(
+            y.xor(x).getCardinality(),
+            y.xorCardinality(x),
+            y.getContainerName() + " " + y + " " + x.getContainerName() + " " + x);
       }
     }
   }
 
-
-
   @Test
   public void rangeOfOnesTest1() {
     final Container c = Container.rangeOfOnes(4, 11); // sparse
@@ -834,8 +884,6 @@ public void rangeOfOnesTest1() {
     assertTrue(checkContent(c, new char[] {4, 5, 6, 7, 8, 9, 10}));
   }
 
-
-
   @Test
   public void rangeOfOnesTest2() {
     final Container c = Container.rangeOfOnes(1000, 35001); // dense
@@ -843,7 +891,6 @@ public void rangeOfOnesTest2() {
     assertEquals(35000 - 1000 + 1, c.getCardinality());
   }
 
-
   @Test
   public void rangeOfOnesTest2A() {
     final Container c = Container.rangeOfOnes(1000, 35001); // dense
@@ -854,7 +901,6 @@ public void rangeOfOnesTest2A() {
     assertTrue(checkContent(c, s));
   }
 
-
   @Test
   public void rangeOfOnesTest3() {
     // bdry cases
@@ -866,8 +912,6 @@ public void rangeOfOnesTest4() {
     Container.rangeOfOnes(1, ArrayContainer.DEFAULT_MAX_SIZE + 2);
   }
 
-
-
   @Test
   public void testRunOptimize1() {
     ArrayContainer ac = new ArrayContainer();
@@ -879,8 +923,6 @@ public void testRunOptimize1() {
     assertEquals(ac, c);
   }
 
-
-
   public void testRunOptimize1A() {
     ArrayContainer ac = new ArrayContainer();
     for (char s : new char[] {1, 2, 3, 4, 6, 8, 9, (char) 50000, (char) 50003}) {
@@ -891,7 +933,6 @@ public void testRunOptimize1A() {
     assertSame(ac, c);
   }
 
-
   @Test
   public void testRunOptimize2() {
     BitmapContainer bc = new BitmapContainer();
@@ -903,8 +944,6 @@ public void testRunOptimize2() {
     assertEquals(bc, c);
   }
 
-
-
   @Test
   public void testRunOptimize2A() {
     BitmapContainer bc = new BitmapContainer();
@@ -919,7 +958,7 @@ public void testRunOptimize2A() {
   @Test
   public void testRunOptimize3() {
     RunContainer rc = new RunContainer();
-    for (char s : new char[] {1, 2,3, 4, 5, 6, 7, 8, 9, (char) 50000, (char) 50001}) {
+    for (char s : new char[] {1, 2, 3, 4, 5, 6, 7, 8, 9, (char) 50000, (char) 50001}) {
       rc.add(s);
     }
     Container c = rc.runOptimize();
@@ -938,7 +977,6 @@ public void testRunOptimize3A() {
     assertEquals(c, rc);
   }
 
-
   @Test
   public void testRunOptimize3B() {
     RunContainer rc = new RunContainer();
@@ -1002,12 +1040,11 @@ public void xor2() {
     ac1.add((char) 50004);
 
     Container result = ac.xor(ac1.getCharIterator());
-    assertTrue(checkContent(result,
-        new char[] {1, 4, 5, (char) 50000, (char) 50002, (char) 50003, (char) 50004}));
+    assertTrue(
+        checkContent(
+            result, new char[] {1, 4, 5, (char) 50000, (char) 50002, (char) 50003, (char) 50004}));
   }
 
-
-
   @Test
   public void xor3() {
     System.out.println("xor3");
@@ -1030,8 +1067,9 @@ public void xor3() {
     ac1.add((char) 50004);
 
     Container result = ac.xor(ac1.getCharIterator());
-    assertTrue(checkContent(result,
-        new char[] {3, 4, (char) 50001, (char) 50002, (char) 50003, (char) 50004}));
+    assertTrue(
+        checkContent(
+            result, new char[] {3, 4, (char) 50001, (char) 50002, (char) 50003, (char) 50004}));
   }
 
   @Test
@@ -1039,7 +1077,7 @@ public void testConsistentToString() {
     ArrayContainer ac = new ArrayContainer();
     BitmapContainer bc = new BitmapContainer();
     RunContainer rc = new RunContainer();
-    for (char i : new char[]{0, 2, 17, Short.MAX_VALUE, (char)-3, (char)-1}) {
+    for (char i : new char[] {0, 2, 17, Short.MAX_VALUE, (char) -3, (char) -1}) {
       ac.add(i);
       bc.add(i);
       rc.add(i);
@@ -1048,10 +1086,8 @@ public void testConsistentToString() {
 
     assertEquals(expected, ac.toString());
     assertEquals(expected, bc.toString());
-    String normalizedRCstr = rc.toString()
-        .replaceAll("\\d+\\]\\[", "")
-        .replace('[', '{')
-        .replaceFirst(",\\d+\\]", "}");
+    String normalizedRCstr =
+        rc.toString().replaceAll("\\d+\\]\\[", "").replace('[', '{').replaceFirst(",\\d+\\]", "}");
     assertEquals(expected, normalizedRCstr);
   }
 
@@ -1077,14 +1113,15 @@ public void xor4() {
     ac1.add((char) 50003);
     ac1.add((char) 50004);
 
-
     Container result = ac.xor(ac1.getCharIterator());
-    assertTrue(checkContent(result, new char[] {3, 4, (char) 50001, (char) 50002, (char) 50003,
-        (char) 50004, (char) 50011}));
+    assertTrue(
+        checkContent(
+            result,
+            new char[] {
+              3, 4, (char) 50001, (char) 50002, (char) 50003, (char) 50004, (char) 50011
+            }));
   }
 
-
-
   @Test
   public void xor5() {
     System.out.println("xor5");
@@ -1120,7 +1157,8 @@ private Container getContainerInstance(Class ct) {
   private void testForAllMaterialization(char[] data) {
     for (Class ct1 : CONTAINER_TYPES) {
       Container container = getContainerInstance(ct1);
-      ValidationRangeConsumer.Value[] expected = new ValidationRangeConsumer.Value[Character.MAX_VALUE + 1];
+      ValidationRangeConsumer.Value[] expected =
+          new ValidationRangeConsumer.Value[Character.MAX_VALUE + 1];
       Arrays.fill(expected, ABSENT);
       for (char c : data) {
         container = container.add(c);
@@ -1142,14 +1180,14 @@ private char[] allValues() {
   @Test
   public void forAll() {
     testForAllMaterialization(new char[0]);
-    testForAllMaterialization(new char[]{0});
-    testForAllMaterialization(new char[]{1});
-    testForAllMaterialization(new char[]{Character.MAX_VALUE});
-    testForAllMaterialization(new char[]{0, 2, 5, 7});
-    testForAllMaterialization(new char[]{49, 63, 65, 32768, 3280});
-    testForAllMaterialization(new char[]{0, Character.MAX_VALUE});
-    testForAllMaterialization(new char[]{Character.MAX_VALUE - 1, Character.MAX_VALUE});
-    testForAllMaterialization(new char[]{Character.MAX_VALUE - 1});
+    testForAllMaterialization(new char[] {0});
+    testForAllMaterialization(new char[] {1});
+    testForAllMaterialization(new char[] {Character.MAX_VALUE});
+    testForAllMaterialization(new char[] {0, 2, 5, 7});
+    testForAllMaterialization(new char[] {49, 63, 65, 32768, 3280});
+    testForAllMaterialization(new char[] {0, Character.MAX_VALUE});
+    testForAllMaterialization(new char[] {Character.MAX_VALUE - 1, Character.MAX_VALUE});
+    testForAllMaterialization(new char[] {Character.MAX_VALUE - 1});
     testForAllMaterialization(allValues());
   }
 
@@ -1157,7 +1195,8 @@ public void forAll() {
   private void testForAllFromMaterialization(char start, char[] data) {
     for (Class ct1 : CONTAINER_TYPES) {
       Container container = getContainerInstance(ct1);
-      ValidationRangeConsumer.Value[] expected = new ValidationRangeConsumer.Value[Character.MAX_VALUE + 1 - start];
+      ValidationRangeConsumer.Value[] expected =
+          new ValidationRangeConsumer.Value[Character.MAX_VALUE + 1 - start];
       Arrays.fill(expected, ABSENT);
       for (char c : data) {
         container = container.add(c);
@@ -1177,13 +1216,14 @@ private void testForAllFromMaterialization(char start, char[] data) {
   @ValueSource(ints = {0, 1, 50, 63, 64, 65, 32768, 3280, 65534, 65535})
   public void forAllFrom(int start) {
     testForAllFromMaterialization((char) start, new char[0]);
-    testForAllFromMaterialization((char) start, new char[]{0});
-    testForAllFromMaterialization((char) start, new char[]{1});
-    testForAllFromMaterialization((char) start, new char[]{0, 2, 5, 7});
-    testForAllFromMaterialization((char) start, new char[]{49, 63, 65, 32768, 3280});
-    testForAllFromMaterialization((char) start, new char[]{0, Character.MAX_VALUE});
-    testForAllFromMaterialization((char) start, new char[]{Character.MAX_VALUE - 1, Character.MAX_VALUE});
-    testForAllFromMaterialization((char) start, new char[]{Character.MAX_VALUE - 1});
+    testForAllFromMaterialization((char) start, new char[] {0});
+    testForAllFromMaterialization((char) start, new char[] {1});
+    testForAllFromMaterialization((char) start, new char[] {0, 2, 5, 7});
+    testForAllFromMaterialization((char) start, new char[] {49, 63, 65, 32768, 3280});
+    testForAllFromMaterialization((char) start, new char[] {0, Character.MAX_VALUE});
+    testForAllFromMaterialization(
+        (char) start, new char[] {Character.MAX_VALUE - 1, Character.MAX_VALUE});
+    testForAllFromMaterialization((char) start, new char[] {Character.MAX_VALUE - 1});
     testForAllFromMaterialization((char) start, allValues());
   }
 
@@ -1211,13 +1251,14 @@ private void testForAllUntilMaterialization(char end, char[] data) {
   @ValueSource(ints = {0, 1, 50, 63, 64, 65, 32768, 3280, 65534, 65535})
   public void forAllUntil(int end) {
     testForAllUntilMaterialization((char) end, new char[0]);
-    testForAllUntilMaterialization((char) end, new char[]{0});
-    testForAllUntilMaterialization((char) end, new char[]{1});
-    testForAllUntilMaterialization((char) end, new char[]{0, 2, 5, 7});
-    testForAllUntilMaterialization((char) end, new char[]{49, 63, 65, 32768, 3280});
-    testForAllUntilMaterialization((char) end, new char[]{0, Character.MAX_VALUE});
-    testForAllUntilMaterialization((char) end, new char[]{Character.MAX_VALUE - 1, Character.MAX_VALUE});
-    testForAllUntilMaterialization((char) end, new char[]{Character.MAX_VALUE - 1});
+    testForAllUntilMaterialization((char) end, new char[] {0});
+    testForAllUntilMaterialization((char) end, new char[] {1});
+    testForAllUntilMaterialization((char) end, new char[] {0, 2, 5, 7});
+    testForAllUntilMaterialization((char) end, new char[] {49, 63, 65, 32768, 3280});
+    testForAllUntilMaterialization((char) end, new char[] {0, Character.MAX_VALUE});
+    testForAllUntilMaterialization(
+        (char) end, new char[] {Character.MAX_VALUE - 1, Character.MAX_VALUE});
+    testForAllUntilMaterialization((char) end, new char[] {Character.MAX_VALUE - 1});
     testForAllUntilMaterialization((char) end, allValues());
   }
 
@@ -1242,7 +1283,8 @@ private void testForAllInRangeMaterialization(char start, char end, char[] data)
       } else {
         final Container container = getContainerInstance(ct1);
         final ValidationRangeConsumer consumer = ValidationRangeConsumer.ofSize(0);
-        assertThrows(IllegalArgumentException.class, () -> container.forAllInRange(start, end, consumer));
+        assertThrows(
+            IllegalArgumentException.class, () -> container.forAllInRange(start, end, consumer));
       }
     }
   }
@@ -1259,17 +1301,21 @@ private static Stream provideArgsForAllInRange() {
     }
     return cartesianProduct.stream();
   }
+
   @ParameterizedTest
   @MethodSource("provideArgsForAllInRange")
   public void forAllInRange(int start, int end) {
     testForAllInRangeMaterialization((char) start, (char) end, new char[0]);
-    testForAllInRangeMaterialization((char) start, (char) end, new char[]{0});
-    testForAllInRangeMaterialization((char) start, (char) end, new char[]{1});
-    testForAllInRangeMaterialization((char) start, (char) end, new char[]{0, 2, 5, 7});
-    testForAllInRangeMaterialization((char) start, (char) end, new char[]{49, 63, 65, 32768, 3280});
-    testForAllInRangeMaterialization((char) start, (char) end, new char[]{0, Character.MAX_VALUE});
-    testForAllInRangeMaterialization((char) start, (char) end, new char[]{Character.MAX_VALUE - 1, Character.MAX_VALUE});
-    testForAllInRangeMaterialization((char) start, (char) end, new char[]{Character.MAX_VALUE - 1});
+    testForAllInRangeMaterialization((char) start, (char) end, new char[] {0});
+    testForAllInRangeMaterialization((char) start, (char) end, new char[] {1});
+    testForAllInRangeMaterialization((char) start, (char) end, new char[] {0, 2, 5, 7});
+    testForAllInRangeMaterialization(
+        (char) start, (char) end, new char[] {49, 63, 65, 32768, 3280});
+    testForAllInRangeMaterialization((char) start, (char) end, new char[] {0, Character.MAX_VALUE});
+    testForAllInRangeMaterialization(
+        (char) start, (char) end, new char[] {Character.MAX_VALUE - 1, Character.MAX_VALUE});
+    testForAllInRangeMaterialization(
+        (char) start, (char) end, new char[] {Character.MAX_VALUE - 1});
     testForAllInRangeMaterialization((char) start, (char) end, allValues());
   }
 
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestEmptyRoaringBatchIterator.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestEmptyRoaringBatchIterator.java
new file mode 100644
index 000000000..f48da513e
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestEmptyRoaringBatchIterator.java
@@ -0,0 +1,54 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
+import org.roaringbitmap.buffer.MutableRoaringBitmap;
+
+import org.junit.jupiter.api.Test;
+
+public class TestEmptyRoaringBatchIterator {
+
+  @Test
+  public void testEmptyMutableRoaringBitmap() {
+    MutableRoaringBitmap mutableRoaringBitmap = new MutableRoaringBitmap();
+    BatchIterator iterator = mutableRoaringBitmap.getBatchIterator();
+    int[] ints = new int[1024];
+    int cnt = iterator.nextBatch(ints);
+    assertEquals(0, cnt);
+
+    mutableRoaringBitmap.add(1);
+    iterator = mutableRoaringBitmap.getBatchIterator();
+    cnt = iterator.nextBatch(ints);
+    assertEquals(1, cnt);
+  }
+
+  @Test
+  public void testEmptyImmutableRoaringBitmap() {
+    MutableRoaringBitmap mutableRoaringBitmap = new MutableRoaringBitmap();
+    ImmutableRoaringBitmap immutableRoaringBitmap = mutableRoaringBitmap.toImmutableRoaringBitmap();
+    BatchIterator iterator = immutableRoaringBitmap.getBatchIterator();
+    int[] ints = new int[1024];
+    int cnt = iterator.nextBatch(ints);
+    assertEquals(0, cnt);
+
+    mutableRoaringBitmap.add(1);
+    iterator = mutableRoaringBitmap.toImmutableRoaringBitmap().getBatchIterator();
+    cnt = iterator.nextBatch(ints);
+    assertEquals(1, cnt);
+  }
+
+  @Test
+  public void testEmptyRoaringBitmap() {
+    RoaringBitmap roaringBitmap = new RoaringBitmap();
+    BatchIterator iterator = roaringBitmap.getBatchIterator();
+    int[] ints = new int[1024];
+    int cnt = iterator.nextBatch(ints);
+    assertEquals(0, cnt);
+
+    roaringBitmap.add(1);
+    iterator = roaringBitmap.getBatchIterator();
+    cnt = iterator.nextBatch(ints);
+    assertEquals(1, cnt);
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestFastAggregation.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestFastAggregation.java
new file mode 100644
index 000000000..64476ccf6
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestFastAggregation.java
@@ -0,0 +1,281 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestFastAggregation {
+
+  @Test
+  public void horizontal_or() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6);
+    RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1 << 16, 2 << 16);
+    RoaringBitmap result = FastAggregation.horizontal_or(Arrays.asList(rb1, rb2, rb3));
+    RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1 << 16, 2 << 16);
+    assertEquals(expected, result);
+  }
+
+  @Test
+  public void or() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6);
+    RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1 << 16, 2 << 16);
+    RoaringBitmap result = FastAggregation.or(rb1, rb2, rb3);
+    RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1 << 16, 2 << 16);
+    assertEquals(expected, result);
+  }
+
+  @Test
+  public void horizontal_or2() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6);
+    RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1 << 16, 2 << 16);
+    RoaringBitmap result = FastAggregation.horizontal_or(rb1, rb2, rb3);
+    RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1 << 16, 2 << 16);
+    assertEquals(expected, result);
+  }
+
+  @Test
+  public void priorityqueue_or() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6);
+    RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1 << 16, 2 << 16);
+    RoaringBitmap result =
+        FastAggregation.priorityqueue_or(Arrays.asList(rb1, rb2, rb3).iterator());
+    RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1 << 16, 2 << 16);
+    assertEquals(expected, result);
+  }
+
+  @Test
+  public void priorityqueue_or2() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(0, 1, 2);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(0, 5, 6);
+    RoaringBitmap rb3 = RoaringBitmap.bitmapOf(1 << 16, 2 << 16);
+    RoaringBitmap result = FastAggregation.priorityqueue_or(rb1, rb2, rb3);
+    RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 2, 5, 6, 1 << 16, 2 << 16);
+    assertEquals(expected, result);
+  }
+
+  private static class ExtendedRoaringBitmap extends RoaringBitmap {}
+
+  @Test
+  public void testWorkShyAnd() {
+    final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2, 0x10001, 0x20001, 0x30001);
+    final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3, 0x20002, 0x30001);
+    final RoaringBitmap bResult = FastAggregation.workShyAnd(new long[1024], b1, b2);
+    assertFalse(bResult.contains(1));
+    assertTrue(bResult.contains(2));
+    assertFalse(bResult.contains(3));
+  }
+
+  @Test
+  public void testAndWithIterator() {
+    final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2);
+    final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3);
+    final RoaringBitmap bResult = FastAggregation.and(Arrays.asList(b1, b2).iterator());
+    assertFalse(bResult.contains(1));
+    assertTrue(bResult.contains(2));
+    assertFalse(bResult.contains(3));
+
+    final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap();
+    eb1.add(1);
+    eb1.add(2);
+    final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap();
+    eb2.add(2);
+    eb2.add(3);
+    final RoaringBitmap ebResult = FastAggregation.and(Arrays.asList(b1, b2).iterator());
+    assertFalse(ebResult.contains(1));
+    assertTrue(ebResult.contains(2));
+    assertFalse(ebResult.contains(3));
+  }
+
+  @Test
+  public void testNaiveAndWithIterator() {
+    final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2);
+    final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3);
+    final RoaringBitmap bResult = FastAggregation.naive_and(Arrays.asList(b1, b2).iterator());
+    assertFalse(bResult.contains(1));
+    assertTrue(bResult.contains(2));
+    assertFalse(bResult.contains(3));
+
+    final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap();
+    eb1.add(1);
+    eb1.add(2);
+    final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap();
+    eb2.add(2);
+    eb2.add(3);
+    final RoaringBitmap ebResult = FastAggregation.naive_and(Arrays.asList(b1, b2).iterator());
+    assertFalse(ebResult.contains(1));
+    assertTrue(ebResult.contains(2));
+    assertFalse(ebResult.contains(3));
+  }
+
+  @Test
+  public void testOrWithIterator() {
+    final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2);
+    final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3);
+    final RoaringBitmap bItResult = FastAggregation.or(Arrays.asList(b1, b2).iterator());
+    assertTrue(bItResult.contains(1));
+    assertTrue(bItResult.contains(2));
+    assertTrue(bItResult.contains(3));
+
+    final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap();
+    eb1.add(1);
+    eb1.add(2);
+    final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap();
+    eb2.add(2);
+    eb2.add(3);
+    final RoaringBitmap ebItResult = FastAggregation.or(Arrays.asList(b1, b2).iterator());
+    assertTrue(ebItResult.contains(1));
+    assertTrue(ebItResult.contains(2));
+    assertTrue(ebItResult.contains(3));
+  }
+
+  @Test
+  public void testNaiveOrWithIterator() {
+    final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2);
+    final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3);
+    final RoaringBitmap bResult = FastAggregation.naive_or(Arrays.asList(b1, b2).iterator());
+    assertTrue(bResult.contains(1));
+    assertTrue(bResult.contains(2));
+    assertTrue(bResult.contains(3));
+
+    final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap();
+    eb1.add(1);
+    eb1.add(2);
+    final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap();
+    eb2.add(2);
+    eb2.add(3);
+    final RoaringBitmap ebResult = FastAggregation.naive_or(Arrays.asList(b1, b2).iterator());
+    assertTrue(ebResult.contains(1));
+    assertTrue(ebResult.contains(2));
+    assertTrue(ebResult.contains(3));
+  }
+
+  @Test
+  public void testNaiveXorWithIterator() {
+    final RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2);
+    final RoaringBitmap b2 = RoaringBitmap.bitmapOf(2, 3);
+    final RoaringBitmap bResult = FastAggregation.naive_xor(Arrays.asList(b1, b2).iterator());
+    assertTrue(bResult.contains(1));
+    assertFalse(bResult.contains(2));
+    assertTrue(bResult.contains(3));
+
+    final ExtendedRoaringBitmap eb1 = new ExtendedRoaringBitmap();
+    eb1.add(1);
+    eb1.add(2);
+    final ExtendedRoaringBitmap eb2 = new ExtendedRoaringBitmap();
+    eb2.add(2);
+    eb2.add(3);
+    final RoaringBitmap ebResult = FastAggregation.naive_xor(Arrays.asList(b1, b2).iterator());
+    assertTrue(ebResult.contains(1));
+    assertFalse(ebResult.contains(2));
+    assertTrue(ebResult.contains(3));
+  }
+
+  public static Stream bitmaps() {
+    return Stream.of(
+        Arguments.of(
+            Arrays.asList(
+                testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(),
+                testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(),
+                testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(),
+                testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build(),
+                testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build(),
+                testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build(),
+                testCase().withArrayAt(0).withRunAt(1).withBitmapAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(),
+                testCase().withBitmapAt(0).withArrayAt(3).withRunAt(4).build(),
+                testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withArrayAt(0).withBitmapAt(1).withRunAt(2).build(),
+                testCase().withRunAt(0).withArrayAt(1).withBitmapAt(2).build(),
+                testCase().withBitmapAt(0).withRunAt(1).withArrayAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build(),
+                testCase().withBitmapAt(0).withArrayAt(2).withRunAt(4).build(),
+                testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withArrayAt(0).withArrayAt(1).withArrayAt(2).build(),
+                testCase().withBitmapAt(0).withBitmapAt(2).withBitmapAt(4).build(),
+                testCase().withRunAt(0).withRunAt(1).withRunAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withArrayAt(0).withArrayAt(1).withArrayAt(2).build(),
+                testCase().withBitmapAt(0).withBitmapAt(2).withArrayAt(4).build(),
+                testCase().withRunAt(0).withRunAt(1).withArrayAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withArrayAt(0).withArrayAt(1).withBitmapAt(2).build(),
+                testCase().withBitmapAt(0).withBitmapAt(2).withBitmapAt(4).build(),
+                testCase().withRunAt(0).withRunAt(1).withBitmapAt(2).build())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withArrayAt(20).build(),
+                testCase().withBitmapAt(0).withBitmapAt(1).withBitmapAt(4).build(),
+                testCase().withRunAt(0).withRunAt(1).withBitmapAt(3).build())));
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testWorkShyAnd")
+  public void testWorkShyAnd(List list) {
+    RoaringBitmap[] bitmaps = list.toArray(new RoaringBitmap[0]);
+    long[] buffer = new long[1024];
+    RoaringBitmap result = FastAggregation.and(buffer, bitmaps);
+    RoaringBitmap expected = FastAggregation.naive_and(bitmaps);
+    assertEquals(expected, result);
+    result = FastAggregation.and(bitmaps);
+    assertEquals(expected, result);
+    result = FastAggregation.workAndMemoryShyAnd(buffer, bitmaps);
+    assertEquals(expected, result);
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testAndCardinality")
+  public void testAndCardinality(List list) {
+    RoaringBitmap[] bitmaps = list.toArray(new RoaringBitmap[0]);
+    for (int length = 0; length <= bitmaps.length; length++) {
+      RoaringBitmap[] subset = Arrays.copyOf(bitmaps, length);
+      RoaringBitmap and = FastAggregation.and(subset);
+      int andCardinality = FastAggregation.andCardinality(subset);
+      assertEquals(and.getCardinality(), andCardinality);
+    }
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testOrCardinality")
+  public void testOrCardinality(List list) {
+    RoaringBitmap[] bitmaps = list.toArray(new RoaringBitmap[0]);
+    for (int length = 0; length <= bitmaps.length; length++) {
+      RoaringBitmap[] subset = Arrays.copyOf(bitmaps, length);
+      RoaringBitmap or = FastAggregation.or(subset);
+      int orCardinality = FastAggregation.orCardinality(subset);
+      assertEquals(or.getCardinality(), orCardinality);
+    }
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestForAllInRange.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestForAllInRange.java
similarity index 87%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestForAllInRange.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestForAllInRange.java
index 282e37654..ab3efe9e4 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestForAllInRange.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestForAllInRange.java
@@ -1,18 +1,18 @@
 package org.roaringbitmap;
 
-import java.util.Arrays;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
+
+import org.roaringbitmap.ValidationRangeConsumer.Value;
 
 import com.google.common.primitives.UnsignedInteger;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
-import org.roaringbitmap.ValidationRangeConsumer.Value;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
 
+import java.util.Arrays;
 
 public class TestForAllInRange {
 
@@ -40,16 +40,14 @@ public void testContinuous(int offset) {
     bitmap.forAllInRange(uAdd(offset, 10001), 1000, consumer2);
     assertEquals(1000, consumer2.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer3 = ValidationRangeConsumer.validate(new Value[]{
-        ABSENT, ABSENT, PRESENT, PRESENT, PRESENT
-    });
-    bitmap.forAllInRange(uAdd(offset,98), 5, consumer3);
+    ValidationRangeConsumer consumer3 =
+        ValidationRangeConsumer.validate(new Value[] {ABSENT, ABSENT, PRESENT, PRESENT, PRESENT});
+    bitmap.forAllInRange(uAdd(offset, 98), 5, consumer3);
     assertEquals(5, consumer3.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer4 = ValidationRangeConsumer.validate(new Value[]{
-        PRESENT, PRESENT, ABSENT, ABSENT, ABSENT
-    });
-    bitmap.forAllInRange(uAdd(offset,9998), 5, consumer4);
+    ValidationRangeConsumer consumer4 =
+        ValidationRangeConsumer.validate(new Value[] {PRESENT, PRESENT, ABSENT, ABSENT, ABSENT});
+    bitmap.forAllInRange(uAdd(offset, 9998), 5, consumer4);
     assertEquals(5, consumer4.getNumberOfValuesConsumed());
 
     bitmap = new RoaringBitmap();
@@ -63,7 +61,7 @@ public void testContinuous(int offset) {
     consumer6.assertAllPresent();
 
     bitmap = new RoaringBitmap();
-    bitmap.add(uAddL(offset, 100), uAddL(offset,  10000));
+    bitmap.add(uAddL(offset, 100), uAddL(offset, 10000));
     ValidationRangeConsumer consumer7 = ValidationRangeConsumer.ofSize(1000000);
     bitmap.forAllInRange(uAdd(offset, 10000), 1000000, consumer7);
     consumer7.assertAllAbsent();
@@ -84,19 +82,20 @@ public void testDense(int offset) {
     bitmap.forAllInRange(uAdd(offset, 0), 100000, consumer);
     assertEquals(100000, consumer.getNumberOfValuesConsumed());
 
-    Value[] expectedSubRange = Arrays.copyOfRange(expected,2500, 6000);
+    Value[] expectedSubRange = Arrays.copyOfRange(expected, 2500, 6000);
     ValidationRangeConsumer consumer2 = ValidationRangeConsumer.validate(expectedSubRange);
     bitmap.forAllInRange(uAdd(offset, 2500), 3500, consumer2);
     assertEquals(3500, consumer2.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer3 = ValidationRangeConsumer.validate(new Value[]{
-        expected[99997], expected[99998], expected[99999], ABSENT, ABSENT, ABSENT
-    });
+    ValidationRangeConsumer consumer3 =
+        ValidationRangeConsumer.validate(
+            new Value[] {
+              expected[99997], expected[99998], expected[99999], ABSENT, ABSENT, ABSENT
+            });
     bitmap.forAllInRange(uAdd(offset, 99997), 6, consumer3);
     assertEquals(6, consumer3.getNumberOfValuesConsumed());
   }
 
-
   @ParameterizedTest
   @ValueSource(ints = {0, 1, 65531, 65536, 2147483642, 2147483647, -2147483648, -2146958415})
   public void testSparse(int offset) {
@@ -112,7 +111,7 @@ public void testSparse(int offset) {
     bitmap.forAllInRange(uAdd(offset, 0), 100000, consumer);
     assertEquals(100000, consumer.getNumberOfValuesConsumed());
 
-    Value[] expectedSubRange = Arrays.copyOfRange(expected,2500, 6001);
+    Value[] expectedSubRange = Arrays.copyOfRange(expected, 2500, 6001);
     ValidationRangeConsumer consumer2 = ValidationRangeConsumer.validate(expectedSubRange);
     bitmap.forAllInRange(uAdd(offset, 2500), 3500, consumer2);
     assertEquals(3500, consumer2.getNumberOfValuesConsumed());
@@ -147,15 +146,18 @@ public void readToEnd() {
     emptyLastContainerBitmap.forAllInRange(0xFFFFFFFE, 2, consumer3);
     assertEquals(2, consumer3.getNumberOfValuesConsumed());
   }
+
   @Test
   public void readPastEnd() {
     final RoaringBitmap bitmap = new RoaringBitmap();
     bitmap.add(0xFFFFFFFE);
     bitmap.add(0xFFFFFFFF);
 
-    assertThrows(IllegalArgumentException.class, () -> {
-        bitmap.forAllInRange(0xFFFFFFFE, 3, ValidationRangeConsumer.ofSize(3));
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          bitmap.forAllInRange(0xFFFFFFFE, 3, ValidationRangeConsumer.ofSize(3));
+        });
   }
 
   @Test
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestForEach.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestForEach.java
new file mode 100644
index 000000000..5b68e1dfc
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestForEach.java
@@ -0,0 +1,71 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class TestForEach {
+
+  @Test
+  public void testContinuous() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(100L, 10000L);
+
+    final MutableInteger cardinality = new MutableInteger();
+    bitmap.forEach(
+        new IntConsumer() {
+          int expected = 100;
+
+          @Override
+          public void accept(int value) {
+            cardinality.value++;
+            assertEquals(value, expected++);
+          }
+        });
+    assertEquals(cardinality.value, bitmap.getCardinality());
+  }
+
+  @Test
+  public void testDense() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    for (int k = 0; k < 100000; k += 3) bitmap.add(k);
+
+    final MutableInteger cardinality = new MutableInteger();
+    bitmap.forEach(
+        new IntConsumer() {
+          int expected = 0;
+
+          @Override
+          public void accept(int value) {
+            cardinality.value++;
+            assertEquals(value, expected);
+            expected += 3;
+          }
+        });
+    assertEquals(cardinality.value, bitmap.getCardinality());
+  }
+
+  @Test
+  public void testSparse() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    for (int k = 0; k < 100000; k += 3000) bitmap.add(k);
+
+    final MutableInteger cardinality = new MutableInteger();
+    bitmap.forEach(
+        new IntConsumer() {
+          int expected = 0;
+
+          @Override
+          public void accept(int value) {
+            cardinality.value++;
+            assertEquals(value, expected);
+            expected += 3000;
+          }
+        });
+    assertEquals(cardinality.value, bitmap.getCardinality());
+  }
+}
+
+class MutableInteger {
+  public int value = 0;
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestImmutableRoaringBitmap.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestImmutableRoaringBitmap.java
new file mode 100644
index 000000000..29e6a0526
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestImmutableRoaringBitmap.java
@@ -0,0 +1,68 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
+
+import org.junit.jupiter.api.Test;
+
+public class TestImmutableRoaringBitmap {
+
+  @Test
+  public void xor() {
+    ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 73647, 83469);
+    ImmutableRoaringBitmap b = ImmutableRoaringBitmap.bitmapOf(1, 5, 10 << 16);
+    ImmutableRoaringBitmap xor = ImmutableRoaringBitmap.xor(a, b);
+    ImmutableRoaringBitmap expected = ImmutableRoaringBitmap.bitmapOf(5, 73647, 83469, 10 << 16);
+    assertEquals(expected, xor);
+  }
+
+  @Test
+  public void or() {
+    ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 73647, 83469);
+    ImmutableRoaringBitmap b = ImmutableRoaringBitmap.bitmapOf(1, 5, 10 << 16);
+    ImmutableRoaringBitmap expected = ImmutableRoaringBitmap.bitmapOf(1, 5, 73647, 83469, 10 << 16);
+    assertEquals(expected, ImmutableRoaringBitmap.or(a, b));
+    assertEquals(expected, ImmutableRoaringBitmap.or(b, a));
+  }
+
+  @Test
+  public void andNot() {
+    ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1 << 16, 2 << 16);
+    ImmutableRoaringBitmap b = ImmutableRoaringBitmap.bitmapOf(11, 12, 13, 2 << 16);
+    ImmutableRoaringBitmap andNot = ImmutableRoaringBitmap.andNot(a, b);
+    ImmutableRoaringBitmap expected = ImmutableRoaringBitmap.bitmapOf(1 << 16);
+    assertEquals(expected, andNot);
+  }
+
+  @Test
+  public void flipInvalidRange() {
+    assertThrows(
+        RuntimeException.class,
+        () -> {
+          ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 5, 7, 13);
+          ImmutableRoaringBitmap.flip(a, 7L, 5L);
+        });
+  }
+
+  @Test
+  public void flipInvalidRange2() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 5, 7, 13);
+          ImmutableRoaringBitmap.flip(a, 1L << 32, 1L << 33);
+        });
+  }
+
+  @Test
+  public void flipInvalidRange3() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          ImmutableRoaringBitmap a = ImmutableRoaringBitmap.bitmapOf(1, 5, 7, 13);
+          ImmutableRoaringBitmap.flip(a, 1L, 1L << 33);
+        });
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestIntIteratorFlyweight.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestIntIteratorFlyweight.java
similarity index 89%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestIntIteratorFlyweight.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestIntIteratorFlyweight.java
index a64eacba7..b87d1612a 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestIntIteratorFlyweight.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestIntIteratorFlyweight.java
@@ -2,9 +2,11 @@
  * (c) the authors Licensed under the Apache License, Version 2.0.
  */
 
-
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.primitives.Ints;
@@ -17,9 +19,6 @@
 import java.util.List;
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestIntIteratorFlyweight {
   private static List asList(IntIterator ints) {
@@ -43,7 +42,7 @@ private static int[] takeSortedAndDistinct(Random source, int count) {
       } while (!ints.add(next));
     }
     // we add a range of continuous values
-    for(int k = 1000; k < 10000; ++k) {
+    for (int k = 1000; k < 10000; ++k) {
       ints.add(k);
     }
     int[] unboxed = Ints.toArray(ints);
@@ -64,8 +63,6 @@ public void testEmptyIteration() {
     assertFalse(reverseIter.hasNext());
   }
 
-
-
   @Test
   public void testIteration() {
     final Random source = new Random(0xcb000a2b9b5bdfb6L);
@@ -81,19 +78,19 @@ public void testIteration() {
 
     IntIteratorFlyweight iter = new IntIteratorFlyweight();
     iter.wrap(bitmap);
-    
+
     IntIteratorFlyweight iter2 = new IntIteratorFlyweight(bitmap);
     PeekableIntIterator j = bitmap.getIntIterator();
-    for(int k = 0; k < data.length; k+=3) {
+    for (int k = 0; k < data.length; k += 3) {
       iter2.advanceIfNeeded(data[k]);
       iter2.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
-      assertEquals(j.peekNext(),data[k]);            
-      assertEquals(iter2.peekNext(),data[k]);
+      assertEquals(j.peekNext(), data[k]);
+      assertEquals(iter2.peekNext(), data[k]);
     }
     new IntIteratorFlyweight(bitmap).advanceIfNeeded(-1);
-    bitmap.getIntIterator().advanceIfNeeded(-1);// should not crash
+    bitmap.getIntIterator().advanceIfNeeded(-1); // should not crash
 
     ReverseIntIteratorFlyweight reverseIter = new ReverseIntIteratorFlyweight();
     reverseIter.wrap(bitmap);
@@ -101,7 +98,6 @@ public void testIteration() {
     final List intIteratorCopy = asList(iter);
     final List reverseIntIteratorCopy = asList(reverseIter);
 
-
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
     assertEquals(bitmap.getCardinality(), reverseIntIteratorCopy.size());
 
@@ -123,26 +119,25 @@ public void testIterationFromBitmap() {
     bitmap.runOptimize();
 
     IntIteratorFlyweight iter = new IntIteratorFlyweight(bitmap);
-    assertEquals(iter.peekNext(),data[0]);
-    assertEquals(iter.peekNext(),data[0]);
-    
+    assertEquals(iter.peekNext(), data[0]);
+    assertEquals(iter.peekNext(), data[0]);
+
     IntIteratorFlyweight iter2 = new IntIteratorFlyweight(bitmap);
     PeekableIntIterator j = bitmap.getIntIterator();
-    for(int k = 0; k < data.length; k+=3) {
+    for (int k = 0; k < data.length; k += 3) {
       iter2.advanceIfNeeded(data[k]);
       iter2.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
-      assertEquals(j.peekNext(),data[k]);
-      assertEquals(iter2.peekNext(),data[k]);
+      assertEquals(j.peekNext(), data[k]);
+      assertEquals(iter2.peekNext(), data[k]);
     }
-    
+
     ReverseIntIteratorFlyweight reverseIter = new ReverseIntIteratorFlyweight(bitmap);
 
     final List intIteratorCopy = asList(iter);
     final List reverseIntIteratorCopy = asList(reverseIter);
 
-
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
     assertEquals(bitmap.getCardinality(), reverseIntIteratorCopy.size());
 
@@ -165,23 +160,27 @@ public void testIterationFromBitmapClone() {
 
     IntIteratorFlyweight iter = (IntIteratorFlyweight) new IntIteratorFlyweight(bitmap).clone();
 
-    ReverseIntIteratorFlyweight reverseIter = (ReverseIntIteratorFlyweight) new ReverseIntIteratorFlyweight(bitmap).clone();
+    ReverseIntIteratorFlyweight reverseIter =
+        (ReverseIntIteratorFlyweight) new ReverseIntIteratorFlyweight(bitmap).clone();
 
     final List intIteratorCopy = asList(iter);
     final List reverseIntIteratorCopy = asList(reverseIter);
 
-
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
     assertEquals(bitmap.getCardinality(), reverseIntIteratorCopy.size());
 
     assertEquals(Ints.asList(data), intIteratorCopy);
     assertEquals(Lists.reverse(Ints.asList(data)), reverseIntIteratorCopy);
-  }  
+  }
+
   @Test
   public void testIterationSmall() {
 
-    final int[] data = new int[] {1, 2, 3, 4, 5, 6, 100, 101, 102, 103, 104, 105, 50000, 50001,
-        50002, 1000000, 1000005, 1000007}; // runcontainer then arraycontainer
+    final int[] data =
+        new int[] {
+          1, 2, 3, 4, 5, 6, 100, 101, 102, 103, 104, 105, 50000, 50001, 50002, 1000000, 1000005,
+          1000007
+        }; // runcontainer then arraycontainer
     RoaringBitmap bitmap = RoaringBitmap.bitmapOf(data);
     bitmap.runOptimize();
 
@@ -194,7 +193,6 @@ public void testIterationSmall() {
     final List intIteratorCopy = asList(iter);
     final List reverseIntIteratorCopy = asList(reverseIter);
 
-
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
     assertEquals(bitmap.getCardinality(), reverseIntIteratorCopy.size());
 
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestIteratorMemory.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestIteratorMemory.java
similarity index 79%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestIteratorMemory.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestIteratorMemory.java
index 670cd1b4c..4538783ea 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestIteratorMemory.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestIteratorMemory.java
@@ -1,5 +1,7 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Disabled;
@@ -14,9 +16,6 @@
 import java.util.Random;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
-
 @Disabled("makes no meaningful assertions")
 public class TestIteratorMemory {
   final IntIteratorFlyweight flyweightIterator = new IntIteratorFlyweight();
@@ -27,19 +26,16 @@ public class TestIteratorMemory {
   final RoaringBitmap bitmap_a;
   final RoaringBitmap bitmap_b;
   final RoaringBitmap bitmap_c;
-  {
 
+  {
     final int[] data = takeSortedAndDistinct(new Random(0xcb000a2b9b5bdfb6L), 100000);
     bitmap_a = RoaringBitmap.bitmapOf(data);
 
     bitmap_b = new RoaringBitmap();
-    for (int k = 0; k < (1 << 30); k += 32)
-      bitmap_b.add(k);
+    for (int k = 0; k < (1 << 30); k += 32) bitmap_b.add(k);
 
     bitmap_c = new RoaringBitmap();
-    for (int k = 0; k < (1 << 30); k += 3)
-      bitmap_c.add(k);
-
+    for (int k = 0; k < (1 << 30); k += 3) bitmap_c.add(k);
   }
 
   private int[] takeSortedAndDistinct(Random source, int count) {
@@ -70,13 +66,20 @@ private int[] toArray(LinkedHashSet integers) {
   protected static final ThreadMXBean THREAD_MBEAN = ManagementFactory.getThreadMXBean();
 
   public static boolean isThreadAllocatedMemorySupported(ThreadMXBean threadMbean) {
-    if (threadMbean != null && Stream.of(threadMbean.getClass().getInterfaces())
-        .anyMatch(c -> c.getName().equals("com.sun.management.ThreadMXBean"))) {
+    if (threadMbean != null
+        && Stream.of(threadMbean.getClass().getInterfaces())
+            .anyMatch(c -> c.getName().equals("com.sun.management.ThreadMXBean"))) {
       try {
-        return (Boolean) Class.forName("com.sun.management.ThreadMXBean")
-            .getMethod("isThreadAllocatedMemorySupported").invoke(threadMbean);
-      } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
-          | NoSuchMethodException | SecurityException | ClassNotFoundException e) {
+        return (Boolean)
+            Class.forName("com.sun.management.ThreadMXBean")
+                .getMethod("isThreadAllocatedMemorySupported")
+                .invoke(threadMbean);
+      } catch (IllegalAccessException
+          | IllegalArgumentException
+          | InvocationTargetException
+          | NoSuchMethodException
+          | SecurityException
+          | ClassNotFoundException e) {
         return false;
       }
     } else {
@@ -87,10 +90,16 @@ public static boolean isThreadAllocatedMemorySupported(ThreadMXBean threadMbean)
   public static long getThreadAllocatedBytes(ThreadMXBean threadMbean, long l) {
     if (isThreadAllocatedMemorySupported(threadMbean)) {
       try {
-        return (Long) Class.forName("com.sun.management.ThreadMXBean")
-            .getMethod("getThreadAllocatedBytes", long.class).invoke(threadMbean, l);
-      } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
-          | NoSuchMethodException | SecurityException | ClassNotFoundException e) {
+        return (Long)
+            Class.forName("com.sun.management.ThreadMXBean")
+                .getMethod("getThreadAllocatedBytes", long.class)
+                .invoke(threadMbean, l);
+      } catch (IllegalAccessException
+          | IllegalArgumentException
+          | InvocationTargetException
+          | NoSuchMethodException
+          | SecurityException
+          | ClassNotFoundException e) {
         return -1L;
       }
     } else {
@@ -112,7 +121,6 @@ public void measureBoxedIterationAllocation() {
       long result = 0;
       while (intIterator.hasNext()) {
         result += intIterator.next();
-
       }
       // A small check for iterator consistency
       assertEquals(407, result % 1024);
@@ -131,7 +139,6 @@ public void measureStandardIterationAllocation() {
       long result = 0;
       while (intIterator.hasNext()) {
         result += intIterator.next();
-
       }
       // A small check for iterator consistency
       assertEquals(407, result % 1024);
@@ -152,7 +159,6 @@ public void measureFlyWeightIterationAllocation() {
       long result = 0;
       while (intIterator.hasNext()) {
         result += intIterator.next();
-
       }
       // A small check for iterator consistency
       assertEquals(407, result % 1024);
@@ -161,5 +167,4 @@ public void measureFlyWeightIterationAllocation() {
       System.out.println("FlyWeight Iteration allocated: " + (after - before));
     }
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestIterators.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestIterators.java
similarity index 62%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestIterators.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestIterators.java
index 81b6fa611..3fada8540 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestIterators.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestIterators.java
@@ -2,23 +2,24 @@
  * (c) the authors Licensed under the Apache License, Version 2.0.
  */
 
-
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.primitives.Ints;
 import org.junit.jupiter.api.Test;
 
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.LinkedHashSet;
+import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Random;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.stream.Collectors;
 
 public class TestIterators {
   private static List asList(IntIterator ints) {
@@ -34,35 +35,37 @@ private static List asList(IntIterator ints) {
   }
 
   private static List asList(final CharIterator shorts) {
-    return asList(new IntIterator() {
-      @Override
-      public IntIterator clone() {
-        throw new UnsupportedOperationException();
-      }
-
-      @Override
-      public boolean hasNext() {
-        return shorts.hasNext();
-      }
-
-      @Override
-      public int next() {
-        return shorts.next();
-      }
-    });
+    return asList(
+        new IntIterator() {
+          @Override
+          public IntIterator clone() {
+            throw new UnsupportedOperationException();
+          }
+
+          @Override
+          public boolean hasNext() {
+            return shorts.hasNext();
+          }
+
+          @Override
+          public int next() {
+            return shorts.next();
+          }
+        });
   }
 
-  private static int[] takeSortedAndDistinct(Random source, int count) {
-    LinkedHashSet ints = new LinkedHashSet(count);
+  private static int[] takeSortedAndDistinct(
+      Random source, int count, Comparator comparator) {
+    HashSet ints = new HashSet(count);
     for (int size = 0; size < count; size++) {
       int next;
       do {
-        next = Math.abs(source.nextInt());
+        next = source.nextInt();
       } while (!ints.add(next));
     }
-    int[] unboxed = Ints.toArray(ints);
-    Arrays.sort(unboxed);
-    return unboxed;
+    ArrayList list = new ArrayList(ints);
+    list.sort(comparator);
+    return Ints.toArray(list);
   }
 
   @Test
@@ -77,72 +80,108 @@ public void testBitmapIteration() {
   public void testEmptyIteration() {
     assertFalse(RoaringBitmap.bitmapOf().iterator().hasNext());
     assertFalse(RoaringBitmap.bitmapOf().getIntIterator().hasNext());
+    assertFalse(RoaringBitmap.bitmapOf().getSignedIntIterator().hasNext());
     assertFalse(RoaringBitmap.bitmapOf().getReverseIntIterator().hasNext());
   }
 
   @Test
   public void testIteration() {
     final Random source = new Random(0xcb000a2b9b5bdfb6l);
-    final int[] data = takeSortedAndDistinct(source, 450000);
+    final int[] data = takeSortedAndDistinct(source, 450000, Integer::compareUnsigned);
     RoaringBitmap bitmap = RoaringBitmap.bitmapOf(data);
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
     final List intIteratorCopy = asList(bitmap.getIntIterator());
+    final List signedIntIteratorCopy = asList(bitmap.getSignedIntIterator());
     final List reverseIntIteratorCopy = asList(bitmap.getReverseIntIterator());
 
     assertEquals(bitmap.getCardinality(), iteratorCopy.size());
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
+    assertEquals(bitmap.getCardinality(), signedIntIteratorCopy.size());
     assertEquals(bitmap.getCardinality(), reverseIntIteratorCopy.size());
     assertEquals(Ints.asList(data), iteratorCopy);
     assertEquals(Ints.asList(data), intIteratorCopy);
+    assertEquals(
+        Ints.asList(data).stream().sorted().collect(Collectors.toList()), signedIntIteratorCopy);
     assertEquals(Lists.reverse(Ints.asList(data)), reverseIntIteratorCopy);
   }
 
   @Test
   public void testSmallIteration() {
-    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(1, 2, 3);
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(0, 1, 2, 3, -1, 2147483647, -2147483648);
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
     final List intIteratorCopy = asList(bitmap.getIntIterator());
+    final List signedIntIteratorCopy = asList(bitmap.getSignedIntIterator());
     final List reverseIntIteratorCopy = asList(bitmap.getReverseIntIterator());
 
-    assertEquals(ImmutableList.of(1, 2, 3), iteratorCopy);
-    assertEquals(ImmutableList.of(1, 2, 3), intIteratorCopy);
-    assertEquals(ImmutableList.of(3, 2, 1), reverseIntIteratorCopy);
+    assertEquals(ImmutableList.of(0, 1, 2, 3, 2147483647, -2147483648, -1), iteratorCopy);
+    assertEquals(ImmutableList.of(0, 1, 2, 3, 2147483647, -2147483648, -1), intIteratorCopy);
+    assertEquals(ImmutableList.of(-2147483648, -1, 0, 1, 2, 3, 2147483647), signedIntIteratorCopy);
+    assertEquals(ImmutableList.of(-1, -2147483648, 2147483647, 3, 2, 1, 0), reverseIntIteratorCopy);
   }
-  
+
   @Test
   public void testSkips() {
-    final Random source = new Random(0xcb000a2b9b5bdfb6l);
-    final int[] data = takeSortedAndDistinct(source, 45000);
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
+    final int[] data = takeSortedAndDistinct(source, 45000, Integer::compareUnsigned);
     RoaringBitmap bitmap = RoaringBitmap.bitmapOf(data);
     PeekableIntIterator pii = bitmap.getIntIterator();
-    for(int i = 0; i < data.length; ++i) {
+    for (int i = 0; i < data.length; ++i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.peekNext());
     }
     pii = bitmap.getIntIterator();
-    for(int i = 0; i < data.length; ++i) {
+    for (int i = 0; i < data.length; ++i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.next());
     }
     pii = bitmap.getIntIterator();
-    for(int i = 1; i < data.length; ++i) {
-      pii.advanceIfNeeded(data[i-1]);
+    for (int i = 1; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i - 1]);
+      pii.next();
+      assertEquals(data[i], pii.peekNext());
+    }
+    bitmap.getIntIterator().advanceIfNeeded(-1); // should not crash
+  }
+
+  @Test
+  public void testSkipsSignedIterator() {
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
+    int[] data = takeSortedAndDistinct(source, 45000, Integer::compare);
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(data);
+
+    PeekableIntIterator pii = bitmap.getSignedIntIterator();
+    for (int i = 0; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i]);
+      assertEquals(data[i], pii.peekNext());
+    }
+    pii = bitmap.getSignedIntIterator();
+    for (int i = data.length - 1; i >= 0; --i) { // no backward advancing
+      pii.advanceIfNeeded(data[i]);
+      assertEquals(data[data.length - 1], pii.peekNext());
+    }
+    pii = bitmap.getSignedIntIterator();
+    for (int i = 0; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i]);
+      assertEquals(data[i], pii.next());
+    }
+    pii = bitmap.getSignedIntIterator();
+    for (int i = 1; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i - 1]);
       pii.next();
-      assertEquals(data[i],pii.peekNext() );
+      assertEquals(data[i], pii.peekNext());
     }
-    bitmap.getIntIterator().advanceIfNeeded(-1);// should not crash
   }
-  
+
   @Test
   public void testSkipsDense() {
     RoaringBitmap bitmap = new RoaringBitmap();
     int N = 100000;
-    for(int i = 0; i < N; ++i) {
+    for (int i = 0; i < N; ++i) {
       bitmap.add(2 * i);
     }
-    for(int i = 0; i < N; ++i) {
+    for (int i = 0; i < N; ++i) {
       PeekableIntIterator pii = bitmap.getIntIterator();
       pii.advanceIfNeeded(2 * i);
       assertEquals(pii.peekNext(), 2 * i);
@@ -159,18 +198,22 @@ public void testCorruptionInfiniteLoop() {
     bitmap.add(Integer.MAX_VALUE - 2);
     // Adding this one leads to the issue
     bitmap.add(Integer.MAX_VALUE - 3);
-    bitmap.forEach((org.roaringbitmap.IntConsumer) e -> {
-      if (!bitmap.contains(e)) {
-        throw new IllegalStateException("Not expecting to find: " + e);
-      }
-    });
+    bitmap.forEach(
+        (org.roaringbitmap.IntConsumer)
+            e -> {
+              if (!bitmap.contains(e)) {
+                throw new IllegalStateException("Not expecting to find: " + e);
+              }
+            });
 
     bitmap.runOptimize(); // This is the line causing the issue
-    bitmap.forEach((org.roaringbitmap.IntConsumer) e -> {
-      if (!bitmap.contains(e)) {
-        throw new IllegalStateException("Not expecting to find: " + e);
-      }
-    });
+    bitmap.forEach(
+        (org.roaringbitmap.IntConsumer)
+            e -> {
+              if (!bitmap.contains(e)) {
+                throw new IllegalStateException("Not expecting to find: " + e);
+              }
+            });
   }
 
   @Test
@@ -178,25 +221,25 @@ public void testSkipsRun() {
     RoaringBitmap bitmap = new RoaringBitmap();
     bitmap.add(4L, 100000L);
     bitmap.runOptimize();
-    for(int i = 4; i < 100000; ++i) {
+    for (int i = 4; i < 100000; ++i) {
       PeekableIntIterator pii = bitmap.getIntIterator();
       pii.advanceIfNeeded(i);
       assertEquals(pii.peekNext(), i);
       assertEquals(pii.next(), i);
     }
   }
-  
+
   @Test
   public void testIndexIterator4() throws Exception {
-      RoaringBitmap b = new RoaringBitmap();
-      for (int i = 0; i < 4096; i++) {
-          b.add(i);
-      }
-      PeekableIntIterator it = b.getIntIterator();
-      it.advanceIfNeeded(4096);
-      while (it.hasNext()) {
-          it.next();
-      }
+    RoaringBitmap b = new RoaringBitmap();
+    for (int i = 0; i < 4096; i++) {
+      b.add(i);
+    }
+    PeekableIntIterator it = b.getIntIterator();
+    it.advanceIfNeeded(4096);
+    while (it.hasNext()) {
+      it.next();
+    }
   }
 
   @Test
@@ -256,7 +299,7 @@ public void testSkipIntoFarAwayGaps() {
     // advancing to a value not in any range but beyond second range
     // should go to the first value of third range
     assertFalse(bitset.contains(4325376 - 5)); // same container
-    bitIt.advanceIfNeeded( 4325376 - 5);
+    bitIt.advanceIfNeeded(4325376 - 5);
 
     assertEquals(6000000, bitIt.peekNext());
 
@@ -278,7 +321,7 @@ public void testSkipIntoFarAwayGaps() {
     // advancing to a value not in any range but beyond second range
     // should go to the first value of third range
     assertFalse(bitset.contains(4325376 + 5)); // next container
-    bitIt.advanceIfNeeded( 4325376 + 5);
+    bitIt.advanceIfNeeded(4325376 + 5);
 
     assertEquals(6000000, bitIt.peekNext());
 
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestMemory.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestMemory.java
similarity index 79%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestMemory.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestMemory.java
index 6123e8ab6..b6b1089cc 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestMemory.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestMemory.java
@@ -1,19 +1,22 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
 
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 public class TestMemory {
   @Test
   public void testGCStability() {
     final int N = 10000;
     final int M = 5000000;
-    System.out.println("[testGCStability] testing GC stability with " + N + " bitmaps containing ~"
-        + M / N + " values each on average");
+    System.out.println(
+        "[testGCStability] testing GC stability with "
+            + N
+            + " bitmaps containing ~"
+            + M / N
+            + " values each on average");
     System.out.println("Universe size = " + M);
     final RoaringBitmap[] bitmaps = new RoaringBitmap[N];
     for (int i = 0; i < N; i++) {
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRange.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRange.java
similarity index 77%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestRange.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestRange.java
index 850559ac1..5fd8588be 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRange.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRange.java
@@ -1,5 +1,9 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import org.junit.jupiter.api.Test;
 
 import java.util.ArrayList;
@@ -7,9 +11,6 @@
 import java.util.List;
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.*;
-
-
 public class TestRange {
   @Test
   public void flip64() {
@@ -22,8 +23,8 @@ public void flip64() {
     assertFalse(i.hasNext());
   }
 
-  private static int fillWithRandomBits(final RoaringBitmap bitmap, final BitSet bitset,
-      final int bits) {
+  private static int fillWithRandomBits(
+      final RoaringBitmap bitmap, final BitSet bitset, final int bits) {
     int added = 0;
     Random r = new Random(1011);
     for (int j = 0; j < bits; j++) {
@@ -36,7 +37,6 @@ private static int fillWithRandomBits(final RoaringBitmap bitmap, final BitSet b
     return added;
   }
 
-
   @Test
   public void doubleadd() {
     RoaringBitmap rb = new RoaringBitmap();
@@ -49,7 +49,6 @@ public void doubleadd() {
     assertEquals(0, rb.getCardinality());
   }
 
-
   @Test
   public void rangeAddRemoveBig() {
     final int numCases = 5000;
@@ -68,7 +67,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.add(start, end);
       rbstatic = RoaringBitmap.add(rbstatic, start, end);
-      bs.set((int)start, (int)end);
+      bs.set((int) start, (int) end);
 
       //
       start = r.nextInt(65536 * 20);
@@ -80,7 +79,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.remove(start, end);
       rbstatic = RoaringBitmap.remove(rbstatic, start, end);
-      bs.clear((int)start, (int)end);
+      bs.clear((int) start, (int) end);
 
       //
       start = r.nextInt(20) * 65536;
@@ -92,7 +91,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.add(start, end);
       rbstatic = RoaringBitmap.add(rbstatic, start, end);
-      bs.set((int)start, (int)end);
+      bs.set((int) start, (int) end);
 
       //
       start = r.nextInt(65536 * 20);
@@ -104,7 +103,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.add(start, end);
       rbstatic = RoaringBitmap.add(rbstatic, start, end);
-      bs.set((int)start, (int)end);
+      bs.set((int) start, (int) end);
       //
       start = r.nextInt(20) * 65536;
       end = r.nextInt(65536 * 20);
@@ -115,7 +114,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.remove(start, end);
       rbstatic = RoaringBitmap.remove(rbstatic, start, end);
-      bs.clear((int)start, (int)end);
+      bs.clear((int) start, (int) end);
 
       //
       start = r.nextInt(65536 * 20);
@@ -127,7 +126,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.remove(start, end);
       rbstatic = RoaringBitmap.remove(rbstatic, start, end);
-      bs.clear((int)start, (int)end);
+      bs.clear((int) start, (int) end);
     }
     assertTrue(TestRoaringBitmap.equals(bs, rbstatic));
     assertTrue(TestRoaringBitmap.equals(bs, rbinplace));
@@ -188,7 +187,6 @@ public void setTest1A() {
     assertTrue(TestRoaringBitmap.equals(bs, rb1));
   }
 
-
   @Test
   public void setTest2() {
     final RoaringBitmap rb = new RoaringBitmap();
@@ -216,7 +214,6 @@ public void setTest2A() {
     assertTrue(TestRoaringBitmap.equals(bs, rb));
   }
 
-
   @Test
   public void setTest3() {
     final RoaringBitmap rb = new RoaringBitmap();
@@ -234,7 +231,6 @@ public void setTest3() {
     assertTrue(TestRoaringBitmap.equals(bs, rb));
   }
 
-
   @Test
   public void setTest3A() {
     final RoaringBitmap rb = new RoaringBitmap();
@@ -254,7 +250,6 @@ public void setTest3A() {
     assertTrue(TestRoaringBitmap.equals(bs, rb2));
   }
 
-
   @Test
   public void setTest4() {
     final RoaringBitmap rb = new RoaringBitmap();
@@ -429,7 +424,6 @@ public void setTest7A() {
     assertEquals(rb2, rb3);
     assertTrue(TestRoaringBitmap.equals(bs, rb3));
 
-
     rb3 = RoaringBitmap.add(rb3, 65536L * 3 + 195, 65536L * 3 + 245);
     bs.set(65536 * 3 + 195, 65536 * 3 + 245);
     rb2.add(65536L * 3 + 195, 65536L * 3 + 245);
@@ -442,7 +436,6 @@ public void setTest7A() {
 
     // now removing
 
-
     rb3 = RoaringBitmap.remove(rb3, 65536L * 3 + 195, 65536L * 3 + 245);
     bs.clear(65536 * 3 + 195, 65536 * 3 + 245);
     rb2.remove(65536L * 3 + 195, 65536L * 3 + 245);
@@ -464,14 +457,11 @@ public void setTest7A() {
     assertEquals(rb2, rb3);
     assertTrue(TestRoaringBitmap.equals(bs, rb3));
 
-
     rb2 = RoaringBitmap.remove(rb1, 130L, 185L);
     bs.clear(130, 185);
     rb.remove(130L, 185L);
     assertEquals(rb2, rb);
     assertTrue(TestRoaringBitmap.equals(bs, rb2));
-
-
   }
 
   @Test
@@ -569,7 +559,7 @@ public void setTestSinglePonitsA() {
   public void testClearRanges() {
     long N = 16;
     for (long end = 1; end < N; ++end) {
-        for (long start = 0; start < end; ++start) {
+      for (long start = 0; start < end; ++start) {
         RoaringBitmap bs1 = new RoaringBitmap();
         bs1.add(0L, N);
         for (int k = (int) start; k < end; ++k) {
@@ -708,7 +698,7 @@ public void testSetRanges() {
     for (long end = 1; end < N; ++end) {
       for (long start = 0; start < end; ++start) {
         RoaringBitmap bs1 = new RoaringBitmap();
-        for (int k = (int)start; k < end; ++k) {
+        for (int k = (int) start; k < end; ++k) {
           bs1.add(k);
         }
         RoaringBitmap bs2 = new RoaringBitmap();
@@ -736,7 +726,6 @@ public void testStaticClearRanges() {
     }
   }
 
-
   @Test
   public void testStaticSetRanges() {
     int N = 256;
@@ -753,219 +742,204 @@ public void testStaticSetRanges() {
     }
   }
 
-    /* nb on 20 April 2016, all unit tests above [then] were switched from
-     * the original int-range functions to the wrapper int-range functions
-     * without test errors.  Then all code above switched use longs for 
-     * range endpoints, again without test errors.
-     *
-     * Below, check the deprecated versions for undocumented behaviours that
-     * hopefully don't rely on...but might have
-     */
-
+  /* nb on 20 April 2016, all unit tests above [then] were switched from
+   * the original int-range functions to the wrapper int-range functions
+   * without test errors.  Then all code above switched use longs for
+   * range endpoints, again without test errors.
+   *
+   * Below, check the deprecated versions for undocumented behaviours that
+   * hopefully don't rely on...but might have
+   */
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedStaticAdd() {
     RoaringBitmap rb1 = RoaringBitmap.add(new RoaringBitmap(), 300000, 500000);
     RoaringBitmap rb2 = RoaringBitmap.add(new RoaringBitmap(), 300000L, 500000L);
     assertEquals(rb1, rb2);
-    rb1 = RoaringBitmap.add( rb1, Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-    rb2 = RoaringBitmap.add( rb2, Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1 = RoaringBitmap.add(rb1, Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2 = RoaringBitmap.add(rb2, Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedStaticFlip() {
     RoaringBitmap rb1 = RoaringBitmap.flip(new RoaringBitmap(), 300000, 500000);
     RoaringBitmap rb2 = RoaringBitmap.flip(new RoaringBitmap(), 300000L, 500000L);
     assertEquals(rb1, rb2);
-    rb1 = RoaringBitmap.flip(rb1, Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-    rb2 = RoaringBitmap.flip(rb2, Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1 = RoaringBitmap.flip(rb1, Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2 = RoaringBitmap.flip(rb2, Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedMemberFlip() {
     RoaringBitmap rb1 = new RoaringBitmap();
     rb1.flip(300000, 500000);
     RoaringBitmap rb2 = new RoaringBitmap();
     rb2.flip(300000L, 500000L);
     assertEquals(rb1, rb2);
-    rb1.flip(Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-    rb2.flip(Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1.flip(Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2.flip(Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedStaticRemove() {
-      RoaringBitmap rb1 = RoaringBitmap.add(new RoaringBitmap(), 200000L, 400000L);
-      rb1 = RoaringBitmap.remove(rb1, 300000, 500000);
-      RoaringBitmap rb2 = RoaringBitmap.add(new RoaringBitmap(), 200000L, 400000L);
-      rb2 = RoaringBitmap.remove(rb2,300000L, 500000L);
+    RoaringBitmap rb1 = RoaringBitmap.add(new RoaringBitmap(), 200000L, 400000L);
+    rb1 = RoaringBitmap.remove(rb1, 300000, 500000);
+    RoaringBitmap rb2 = RoaringBitmap.add(new RoaringBitmap(), 200000L, 400000L);
+    rb2 = RoaringBitmap.remove(rb2, 300000L, 500000L);
     assertEquals(rb1, rb2);
 
-      rb1 = RoaringBitmap.add(rb1, Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      rb2 = RoaringBitmap.add(rb2, Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      rb1 = RoaringBitmap.remove(rb1, Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      rb2 = RoaringBitmap.remove(rb2, Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1 = RoaringBitmap.add(rb1, Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    rb2 = RoaringBitmap.add(rb2, Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    rb1 = RoaringBitmap.remove(rb1, Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2 = RoaringBitmap.remove(rb2, Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedAdd() {
-      RoaringBitmap rb1 = new RoaringBitmap();
-      rb1.add(300000, 500000);
-      RoaringBitmap rb2 = new RoaringBitmap();
-      rb2.add(300000L, 500000L);
+    RoaringBitmap rb1 = new RoaringBitmap();
+    rb1.add(300000, 500000);
+    RoaringBitmap rb2 = new RoaringBitmap();
+    rb2.add(300000L, 500000L);
     assertEquals(rb1, rb2);
-      rb1.add( Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      rb2.add( Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1.add(Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2.add(Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedRemove() {
-      RoaringBitmap rb1 = new RoaringBitmap();
-      rb1.add(200000L, 400000L);
-      rb1.remove(300000, 500000);
-      RoaringBitmap rb2 = new RoaringBitmap();
-      rb2.add(200000L, 400000L);
-      rb2.remove(300000L, 500000L);
+    RoaringBitmap rb1 = new RoaringBitmap();
+    rb1.add(200000L, 400000L);
+    rb1.remove(300000, 500000);
+    RoaringBitmap rb2 = new RoaringBitmap();
+    rb2.add(200000L, 400000L);
+    rb2.remove(300000L, 500000L);
     assertEquals(rb1, rb2);
 
-      rb1.add(Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      rb2.add(Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      rb1.remove(Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      rb2.remove(Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1.add(Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    rb2.add(Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    rb1.remove(Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2.remove(Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
-
-
-    // the other tests for ranged AND are in TestRoaringBitmap; the
-    // range-with-longs is assumed to be okay and only lightly checked here
+  // the other tests for ranged AND are in TestRoaringBitmap; the
+  // range-with-longs is assumed to be okay and only lightly checked here
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorAnd() {
 
-      RoaringBitmap rb1 = new RoaringBitmap();
-      RoaringBitmap rb2 = new RoaringBitmap();
+    RoaringBitmap rb1 = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
 
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full overlap is on 300000 to 399999
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full overlap is on 300000 to 399999
 
-      RoaringBitmap result = RoaringBitmap.and(list.iterator(), 350000L,  450000L); 
-      RoaringBitmap resultInt = RoaringBitmap.and(list.iterator(), 350000,  450000);
+    RoaringBitmap result = RoaringBitmap.and(list.iterator(), 350000L, 450000L);
+    RoaringBitmap resultInt = RoaringBitmap.and(list.iterator(), 350000, 450000);
 
     assertEquals(result, resultInt);
-      assertEquals(50000, result.getCardinality());
+    assertEquals(50000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = RoaringBitmap.and(list.iterator(), 300000, 200000);
-      result = RoaringBitmap.and(list.iterator(), 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = RoaringBitmap.and(list.iterator(), 300000, 200000);
+    result = RoaringBitmap.and(list.iterator(), 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorOr() {
 
-      RoaringBitmap rb1 = new RoaringBitmap();
-      RoaringBitmap rb2 = new RoaringBitmap();
+    RoaringBitmap rb1 = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
 
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full union is 200000 to 499999
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full union is 200000 to 499999
 
-      RoaringBitmap result = RoaringBitmap.or(list.iterator(), 250000L,  550000L); 
-      RoaringBitmap resultInt = RoaringBitmap.or(list.iterator(), 250000,  550000);
+    RoaringBitmap result = RoaringBitmap.or(list.iterator(), 250000L, 550000L);
+    RoaringBitmap resultInt = RoaringBitmap.or(list.iterator(), 250000, 550000);
 
     assertEquals(result, resultInt);
-      assertEquals(250000, result.getCardinality());
+    assertEquals(250000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = RoaringBitmap.or(list.iterator(), 300000, 200000);
-      result = RoaringBitmap.or(list.iterator(), 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = RoaringBitmap.or(list.iterator(), 300000, 200000);
+    result = RoaringBitmap.or(list.iterator(), 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorAndNot() {
 
-      RoaringBitmap rb1 = new RoaringBitmap();
-      RoaringBitmap rb2 = new RoaringBitmap();
+    RoaringBitmap rb1 = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
 
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full andNOToverlap is on 200000 to 299999
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full andNOToverlap is on 200000 to 299999
 
-      RoaringBitmap result = RoaringBitmap.andNot(rb1, rb2, 250000L,  450000L); 
-      RoaringBitmap resultInt = RoaringBitmap.andNot(rb1, rb2, 250000,  450000);
+    RoaringBitmap result = RoaringBitmap.andNot(rb1, rb2, 250000L, 450000L);
+    RoaringBitmap resultInt = RoaringBitmap.andNot(rb1, rb2, 250000, 450000);
 
     assertEquals(result, resultInt);
-      assertEquals(50000, result.getCardinality());
+    assertEquals(50000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = RoaringBitmap.andNot(rb1, rb2, 300000, 200000);
-      result = RoaringBitmap.andNot(rb1, rb2, 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = RoaringBitmap.andNot(rb1, rb2, 300000, 200000);
+    result = RoaringBitmap.andNot(rb1, rb2, 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorXor() {
 
-      RoaringBitmap rb1 = new RoaringBitmap();
-      RoaringBitmap rb2 = new RoaringBitmap();
+    RoaringBitmap rb1 = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
 
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full XOR is 200000 to 299999, 400000-4999999
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full XOR is 200000 to 299999, 400000-4999999
 
-      RoaringBitmap result = RoaringBitmap.xor(list.iterator(), 250000L,  450000L); 
-      RoaringBitmap resultInt = RoaringBitmap.xor(list.iterator(), 250000,  450000);
+    RoaringBitmap result = RoaringBitmap.xor(list.iterator(), 250000L, 450000L);
+    RoaringBitmap resultInt = RoaringBitmap.xor(list.iterator(), 250000, 450000);
 
     assertEquals(result, resultInt);
-      assertEquals(100000, result.getCardinality());
+    assertEquals(100000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = RoaringBitmap.xor(list.iterator(), 300000, 200000);
-      result = RoaringBitmap.xor(list.iterator(), 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = RoaringBitmap.xor(list.iterator(), 300000, 200000);
+    result = RoaringBitmap.xor(list.iterator(), 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
-
-
-
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestRangeCardinality.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRangeCardinality.java
new file mode 100644
index 000000000..c9dcb6ada
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRangeCardinality.java
@@ -0,0 +1,35 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+public class TestRangeCardinality {
+
+  public static Stream data() {
+    return Stream.of(
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 3, 8, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 2, 8, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 3, 7, 2),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 0, 7, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 0, 6, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9, Short.MAX_VALUE}, 0, Short.MAX_VALUE + 1, 6),
+        Arguments.of(new int[] {1, 10000, 25000, Short.MAX_VALUE - 1}, 0, Short.MAX_VALUE, 4),
+        Arguments.of(
+            new int[] {1 << 3, 1 << 8, 511, 512, 513, 1 << 12, 1 << 14}, 0, Short.MAX_VALUE, 7));
+  }
+
+  @ParameterizedTest
+  @MethodSource("data")
+  public void testCardinalityInBitmapWordRange(int[] elements, int begin, int end, int expected) {
+    BitmapContainer bc = new BitmapContainer();
+    for (int e : elements) {
+      bc.add((char) e);
+    }
+    assertEquals(expected, Util.cardinalityInBitmapRange(bc.bitmap, begin, end));
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRankIterator.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRankIterator.java
similarity index 88%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestRankIterator.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestRankIterator.java
index 3ed4b7990..ab036051a 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRankIterator.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRankIterator.java
@@ -1,5 +1,10 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.RoaringBitmapWriter.writer;
+import static org.roaringbitmap.SeededTestData.randomBitmap;
+
 import com.google.common.collect.Lists;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -14,11 +19,6 @@
 import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.roaringbitmap.RoaringBitmapWriter.writer;
-import static org.roaringbitmap.SeededTestData.randomBitmap;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestRankIterator {
 
@@ -29,8 +29,8 @@ public static Stream parameters() throws CloneNotSupportedException {
     withFull.add(0L, 262144L);
 
     assertTrue(fast.isCacheDismissed());
-    return Lists.cartesianProduct(Arrays.asList(fast, withFull), computeAdvances())
-            .stream().map(list -> Arguments.of(list.get(0), list.get(1)));
+    return Lists.cartesianProduct(Arrays.asList(fast, withFull), computeAdvances()).stream()
+        .map(list -> Arguments.of(list.get(0), list.get(1)));
   }
 
   @ParameterizedTest(name = "{1}")
@@ -78,15 +78,15 @@ private void testBitmapRanksOnAdvance(FastRankRoaringBitmap bm, int advance) {
 
   private static List computeAdvances() {
     return IntStream.of(0, 1, 3, 5, 7, 11)
-            .flatMap(i -> IntStream.range(0, 18).map(j -> i * (1 << j)))
-            .boxed()
-            .distinct()
-            .collect(Collectors.toList());
+        .flatMap(i -> IntStream.range(0, 18).map(j -> i * (1 << j)))
+        .boxed()
+        .distinct()
+        .collect(Collectors.toList());
   }
 
   private static FastRankRoaringBitmap getBitmap() {
-    FastRankRoaringBitmap bitmap = randomBitmap(50,
-            writer().fastRank().initialCapacity(50).constantMemory().get());
+    FastRankRoaringBitmap bitmap =
+        randomBitmap(50, writer().fastRank().initialCapacity(50).constantMemory().get());
     assertTrue(bitmap.isCacheDismissed());
     return bitmap;
   }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRankIteratorsOfContainers.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRankIteratorsOfContainers.java
similarity index 98%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestRankIteratorsOfContainers.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestRankIteratorsOfContainers.java
index 293217364..4212bf52a 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRankIteratorsOfContainers.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRankIteratorsOfContainers.java
@@ -1,13 +1,12 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
 
 import org.junit.jupiter.api.Test;
 
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertSame;
-
 public class TestRankIteratorsOfContainers {
   private void testContainerRanksOnNext(Container c) {
     PeekableCharRankIterator iterator = c.getCharRankIterator();
@@ -82,7 +81,7 @@ private void fillRandom(Container container, Random rnd) {
       container.add((char) (16384 + rnd.nextInt(1 << 10)));
     }
 
-    assertSame(empty, container,"bad test -- container was changed");
+    assertSame(empty, container, "bad test -- container was changed");
   }
 
   private void fillRange(Container container, int begin, int end) {
@@ -120,7 +119,6 @@ public void testBitmapContainer3() {
     testContainerIterators(container);
   }
 
-
   @Test
   public void testBitmapContainer4() {
     BitmapContainer container = new BitmapContainer();
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestReverseIteratorsOfContainers.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestReverseIteratorsOfContainers.java
similarity index 95%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestReverseIteratorsOfContainers.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestReverseIteratorsOfContainers.java
index fc1c97c54..a80a48af3 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestReverseIteratorsOfContainers.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestReverseIteratorsOfContainers.java
@@ -1,21 +1,20 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.google.common.primitives.Chars;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.ArgumentsProvider;
 import org.junit.jupiter.params.provider.ArgumentsSource;
 
-import com.google.common.primitives.Chars;
-
 import java.util.Arrays;
 import java.util.LinkedHashSet;
 import java.util.Random;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 public class TestReverseIteratorsOfContainers {
 
   @ParameterizedTest
@@ -43,7 +42,7 @@ public void testSkips(Converter converter) {
       pii.next();
       assertEquals(data[i], pii.peekNext());
     }
-    container.getCharIterator().advanceIfNeeded((char) -1);// should not crash
+    container.getCharIterator().advanceIfNeeded((char) -1); // should not crash
   }
 
   @ParameterizedTest
@@ -115,7 +114,7 @@ public void testSkipsReverse(Converter converter) {
       pii.next();
       assertEquals(data[i], pii.peekNext());
     }
-    container.getReverseCharIterator().advanceIfNeeded((char) -1);// should not crash
+    container.getReverseCharIterator().advanceIfNeeded((char) -1); // should not crash
   }
 
   @ParameterizedTest
@@ -134,8 +133,8 @@ public void testSkipsDenseReverse(Converter converter) {
       PeekableCharIterator pii = container.getReverseCharIterator();
       char c = (char) (2 * i);
       pii.advanceIfNeeded(c);
-      assertEquals(pii.peekNext(), 2 * i);
-      assertEquals(pii.next(), 2 * i);
+      assertEquals(2 * i, pii.peekNext());
+      assertEquals(2 * i, pii.next());
     }
   }
 
@@ -153,7 +152,6 @@ public void testSkipsRunReverse(Converter converter) {
       assertEquals(pii.peekNext(), i);
       assertEquals(pii.next(), i);
     }
-
   }
 
   @ParameterizedTest
@@ -178,9 +176,7 @@ private static char[] takeSortedAndDistinct(Random source, int count) {
     return unboxed;
   }
 
-  static interface Converter extends Function {
-
-  }
+  static interface Converter extends Function {}
 
   static class ArrayContainerConverter implements Converter {
 
@@ -201,7 +197,6 @@ public Container apply(Container container) {
     public String toString() {
       return "ArrayContainer";
     }
-
   }
 
   static class BitmapContainerConverter implements Converter {
@@ -219,7 +214,6 @@ public Container apply(Container container) {
     public String toString() {
       return "BitmapContainer";
     }
-
   }
 
   static class RunContainerConverter implements Converter {
@@ -241,17 +235,19 @@ public Container apply(Container container) {
     public String toString() {
       return "RunContainer";
     }
-
   }
 
   static class ContainerProvider implements ArgumentsProvider {
 
-    Stream streams = Stream.of(new ArrayContainerConverter(), new BitmapContainerConverter(), new RunContainerConverter());
+    Stream streams =
+        Stream.of(
+            new ArrayContainerConverter(),
+            new BitmapContainerConverter(),
+            new RunContainerConverter());
 
     @Override
     public Stream provideArguments(ExtensionContext context) {
       return streams.map(f -> Arguments.of(f));
     }
   }
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap.java
new file mode 100644
index 000000000..04f1c544f
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap.java
@@ -0,0 +1,5883 @@
+/*
+ * (c) the authors Licensed under the Apache License, Version 2.0.
+ */
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.RoaringBitmapWriter.writer;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ContiguousSet;
+import com.google.common.collect.DiscreteDomain;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Range;
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.stream.IntStream;
+
+/**
+ * Generic testing of the roaring bitmaps
+ */
+@SuppressWarnings({"static-method"})
+@Execution(ExecutionMode.CONCURRENT)
+public class TestRoaringBitmap {
+  @Test
+  public void intersectBitmapWithRangeHighBits() {
+    Container[] values = new Container[1];
+    RoaringArray ra = new RoaringArray(new char[1], values, 1);
+    long[] bitmap = new long[1024];
+    Arrays.fill(bitmap, 0, 512, 0xAAAAAAAAAAAAAAAAL);
+    values[0] = new BitmapContainer(bitmap, 512 * Long.bitCount(0xAAAAAAAAAAAAAAAAL));
+    RoaringBitmap rr1 = new RoaringBitmap(ra);
+    assertFalse(rr1.intersects((1 << 15), 0xFFFF));
+  }
+
+  @Test
+  public void testRangeCardinality() {
+    RoaringBitmap r = new RoaringBitmap();
+    long Min = 0L;
+    long Max = 1000000L;
+    r.add(Min, Max);
+    for (long s = Min; s <= Max; s += 100) {
+      for (long e = s; e <= Max; e += 100) {
+        assertEquals(e - s, r.rangeCardinality(s, e));
+      }
+    }
+  }
+
+  @Test
+  public void testRangeCardinality2() {
+    RoaringBitmap r = new RoaringBitmap();
+    long Min = 1L << 16;
+    long Max = 1L << 18;
+    r.add(Min, Max);
+    for (long s = Min; s <= Max; s += 1024) {
+      for (long e = s; e <= Max; e += 1024) {
+        assertEquals(e - s, r.rangeCardinality(s, e));
+      }
+    }
+  }
+
+  @Test
+  public void testMultipleAdd() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(1);
+    bitmap.add(1, 2, 3);
+    bitmap.add(0xFFFFFFFF);
+    bitmap.add(0xFFFFFFFEL, 0xFFFFFFFFL);
+    assertEquals("{1,2,3,4294967294,4294967295}", bitmap.toString());
+  }
+
+  @Test
+  public void testAddN() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.addN(new int[] {1, 2, 3, 4, 5}, 1, 3);
+    assertEquals("{2,3,4}", bitmap.toString());
+  }
+
+  @Test
+  public void testStringer() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(1);
+    bitmap.add(2);
+    bitmap.add(3);
+    bitmap.add(0xFFFFFFFF);
+    assertEquals("{1,2,3,4294967295}", bitmap.toString());
+  }
+
+  @Test
+  public void report128() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(59798854);
+    bitmap.add(91274955);
+    bitmap.add(97569495);
+    bitmap.add(101993170);
+    PeekableIntIterator it = bitmap.getIntIterator();
+    it.advanceIfNeeded(100620278);
+    assertTrue(it.hasNext());
+    assertEquals(101993170, it.next());
+    assertFalse(it.hasNext());
+  }
+
+  @Test
+  public void report128_fly() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(59798854);
+    bitmap.add(91274955);
+    bitmap.add(97569495);
+    bitmap.add(101993170);
+    IntIteratorFlyweight it = new IntIteratorFlyweight();
+    it.wrap(bitmap);
+    it.advanceIfNeeded(100620278);
+    assertTrue(it.hasNext());
+    assertEquals(101993170, it.next());
+    assertFalse(it.hasNext());
+  }
+
+  @Test
+  public void limitBug2() {
+    class MyConsumer implements IntConsumer {
+      public int count = 0;
+
+      @Override
+      public void accept(int value) {
+        count++;
+      }
+    }
+
+    RoaringBitmap r = new RoaringBitmap();
+    int count = 0;
+    for (int i = 0; i < 500; i++) {
+      for (int j = 0; j < 9943; j++) {
+        if (i % 2 == 0) r.add(count);
+        count++;
+      }
+    }
+    RoaringBitmap limited = r.limit(1000000);
+    assertEquals(1000000, limited.getCardinality());
+    MyConsumer c = new MyConsumer();
+    limited.forEach(c);
+    assertEquals(1000000, c.count);
+    assertEquals(1000000, limited.toArray().length);
+  }
+
+  @Test
+  public void limitTest() {
+    RoaringBitmap r = new RoaringBitmap();
+    r.add(0l, 10000000l);
+    assertEquals(1, r.limit(1).getCardinality());
+    assertEquals(10, r.limit(10).getCardinality());
+    assertEquals(100, r.limit(100).getCardinality());
+    assertEquals(1000, r.limit(1000).getCardinality());
+    assertEquals(10000, r.limit(10000).getCardinality());
+    assertEquals(100000, r.limit(100000).getCardinality());
+    assertEquals(1000000, r.limit(1000000).getCardinality());
+  }
+
+  @Test
+  public void pointerContainerTest() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int i = 0; i < (1 << 16); i += 2) {
+      rb.add(i);
+    }
+    for (int i = (1 << 16); i < 2 * ((1 << 16)); i += 512) {
+      rb.add(i);
+    }
+    for (int i = 2 * (1 << 16); i < 3 * ((1 << 16)); i++) {
+      rb.add(i);
+    }
+    rb.runOptimize();
+    ContainerPointer cp = rb.getContainerPointer();
+    ContainerPointer cpo = (ContainerPointer) cp.clone();
+    assertNotEquals(cp.getContainer(), null);
+    assertNotEquals(cpo.getContainer(), null);
+
+    assertEquals(cp.compareTo(cpo), 0);
+
+    assertEquals(cp.getCardinality(), (1 << 16) / 2);
+    assertTrue(cp.isBitmapContainer());
+    assertFalse(cp.isRunContainer());
+
+    cp.advance();
+    assertTrue(cp.compareTo(cpo) > 0);
+    assertNotEquals(cp.getContainer(), null);
+    assertEquals(cp.getCardinality(), (1 << 16) / 512);
+    assertFalse(cp.isBitmapContainer());
+    assertFalse(cp.isRunContainer());
+
+    cp.advance();
+    assertTrue(cp.compareTo(cpo) > 0);
+    assertNotEquals(cp.getContainer(), null);
+    assertEquals(cp.getCardinality(), (1 << 16));
+    assertFalse(cp.isBitmapContainer());
+    assertTrue(cp.isRunContainer());
+
+    cpo.advance();
+    assertTrue(cp.compareTo(cpo) > 0);
+    cpo.advance();
+    assertEquals(0, cp.compareTo(cpo));
+
+    cp.advance();
+
+    assertNull(cp.getContainer());
+  }
+
+  public static int[][] randomlists = {
+    {
+      127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
+      146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+      165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
+      184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+      203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+      222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
+      241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259,
+      260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
+      279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297,
+      298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316,
+      317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335,
+      336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+      355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373,
+      374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
+      393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411,
+      412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
+      431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449,
+      450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468,
+      469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487,
+      488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506,
+      507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525,
+      526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544,
+      545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
+      564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582,
+      583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601,
+      602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620,
+      621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639,
+      640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658,
+      659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677,
+      678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696,
+      697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715,
+      716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734,
+      735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753,
+      754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772,
+      773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791,
+      792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810,
+      811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829,
+      830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848,
+      849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867,
+      868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886,
+      887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905,
+      906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924,
+      925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943,
+      944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962,
+      963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981,
+      982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999,
+      1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014,
+      1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029,
+      1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044,
+      1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059,
+      1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074,
+      1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089,
+      1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104,
+      1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119,
+      1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134,
+      1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149,
+      1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164,
+      1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179,
+      1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194,
+      1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209,
+      1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224,
+      1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239,
+      1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254,
+      1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269,
+      1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284,
+      1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299,
+      1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314,
+      1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329,
+      1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344,
+      1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359,
+      1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374,
+      1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389,
+      1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404,
+      1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419,
+      1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434,
+      1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449,
+      1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464,
+      1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479,
+      1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494,
+      1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509,
+      1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524,
+      1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539,
+      1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554,
+      1555, 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569,
+      1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584,
+      1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1598, 1599,
+      1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614,
+      1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629,
+      1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644,
+      1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659,
+      1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674,
+      1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689,
+      1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, 1704,
+      1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719,
+      1720, 1721, 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734,
+      1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749,
+      1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764,
+      1765, 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779,
+      1780, 1781, 1782, 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794,
+      1795, 1796, 1797, 1798, 1799, 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809,
+      1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824,
+      1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839,
+      1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, 1854,
+      1855, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869,
+      1870, 1871, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884,
+      1885, 1886, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899,
+      1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914,
+      1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929,
+      1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944,
+      1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959,
+      1960, 1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974,
+      1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989,
+      1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+      2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
+      2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034,
+      2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049,
+      2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064,
+      2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079,
+      2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094,
+      2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109,
+      2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124,
+      2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139,
+      2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, 2153, 2154,
+      2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169,
+      2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184,
+      2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199,
+      2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214,
+      2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225, 2226, 2227, 2228, 2229,
+      2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244,
+      2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259,
+      2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274,
+      2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289,
+      2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, 2300, 2301, 2302, 2303, 2304,
+      2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319,
+      2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, 2330, 2331, 2332, 2333, 2334,
+      2335, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345, 2346, 2347, 2348, 2349,
+      2350, 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, 2359, 2360, 2361, 2362, 2363, 2364,
+      2365, 2366, 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379,
+      2380, 2381, 2382, 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, 2394,
+      2395, 2396, 2397, 2398, 2399, 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409,
+      2410, 2411, 2412, 2413, 2414, 2415, 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2423, 2424,
+      2425, 2426, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439,
+      2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2454,
+      2455, 2456, 2457, 2458, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469,
+      2470, 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, 2481, 2482, 2483, 2484,
+      2485, 2486, 2487, 2488, 2489, 2490, 2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499,
+      2500, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, 2514,
+      2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, 2524, 2525, 2526, 2527, 2528, 2529,
+      2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, 2542, 2543, 2544,
+      2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559,
+      2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, 2573, 2574,
+      2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 2583, 2584, 2585, 2586, 2587, 2588, 2589,
+      2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, 2604,
+      2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619,
+      2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634,
+      2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649,
+      2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664,
+      2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2677, 2678, 2679,
+      2680, 2681, 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694,
+      2695, 2696, 2697, 2698, 2699, 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709,
+      2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, 2718, 2719, 2720, 2721, 2722, 2723, 2724,
+      2725, 2726, 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2734, 2735, 2736, 2737, 2738, 2739,
+      2740, 2741, 2742, 2743, 2744, 2745, 2746, 2747, 2748, 2749, 2750, 2751, 2752, 2753, 2754,
+      2755, 2756, 2757, 2758, 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769,
+      2770, 2771, 2772, 2773, 2774, 2775, 2776, 2777, 2778, 2779, 2780, 2781, 2782, 2783, 2784,
+      2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798, 2799,
+      2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814,
+      2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, 2826, 2827, 2828, 2829,
+      2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, 2842, 2843, 2844,
+      2845, 2846, 2847, 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, 2859,
+      2860, 2861, 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874,
+      2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889,
+      2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2900, 2901, 2902, 2903, 2904,
+      2905, 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919,
+      2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 2934,
+      2935, 2936, 2937, 2938, 2939, 2940, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949,
+      2950, 2951, 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2964,
+      2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979,
+      2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 2992, 2993, 2994,
+      2995, 2996, 2997, 2998, 2999, 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009,
+      3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024,
+      3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039,
+      3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, 3053, 3054,
+      3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3068, 3069,
+      3070, 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3084,
+      3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, 3098, 3099,
+      3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3114,
+      3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129,
+      3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3144,
+      3145, 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159,
+      3160, 3161, 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174,
+      3175, 3176, 3177, 3178, 3179, 3180, 3181, 3182, 3183, 3184, 3185, 3186, 3187, 3188, 3189,
+      3190, 3191, 3192, 3193, 3194, 3195, 3196, 3197, 3198, 3199, 3200, 3201, 3202, 3203, 3204,
+      3205, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213, 3214, 3215, 3216, 3217, 3218, 3219,
+      3220, 3221, 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, 3230, 3231, 3232, 3233, 3234,
+      3235, 3236, 3237, 3238, 3239, 3240, 3241, 3242, 3243, 3244, 3245, 3246, 3247, 3248, 3249,
+      3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, 3258, 3259, 3260, 3261, 3262, 3263, 3264,
+      3265, 3266, 3267, 3268, 3269, 3270, 3271, 3272, 3273, 3274, 3275, 3276, 3277, 3278, 3279,
+      3280, 3281, 3282, 3283, 3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293, 3294,
+      3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 3306, 3307, 3308, 3309,
+      3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3320, 3321, 3322, 3323, 3324,
+      3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, 3335, 3336, 3337, 3338, 3339,
+      3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, 3354,
+      3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369,
+      3370, 3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384,
+      3385, 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399,
+      3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414,
+      3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429,
+      3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3444,
+      3445, 3446, 3447, 3448, 3449, 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459,
+      3460, 3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473, 3474,
+      3475, 3476, 3477, 3478, 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489,
+      3490, 3491, 3492, 3493, 3494, 3495, 3496, 3497, 3498, 3499, 3500, 3501, 3502, 3503, 3504,
+      3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3518, 3519,
+      3520, 3521, 3522, 3523, 3524, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 3533, 3534,
+      3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549,
+      3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, 3558, 3559, 3560, 3561, 3562, 3563, 3564,
+      3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574, 3575, 3576, 3577, 3578, 3579,
+      3580, 3581, 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594,
+      3595, 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3604, 3605, 3606, 3607, 3608, 3609,
+      3610, 3611, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, 3620, 3621, 3622, 3623, 3624,
+      3625, 3626, 3627, 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639,
+      3640, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3653, 3654,
+      3655, 3656, 3657, 3658, 3659, 3660, 3661, 3662, 3663, 3664, 3665, 3666, 3667, 3668, 3669,
+      3670, 3671, 3672, 3673, 3674, 3675, 3676, 3677, 3678, 3679, 3680, 3681, 3682, 3683, 3684,
+      3685, 3686, 3687, 3688, 3689, 3690, 3691, 3692, 3693, 3694, 3695, 3696, 3697, 3698, 3699,
+      3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 3712, 3713, 3714,
+      3715, 3716, 3717, 3718, 3719, 3720, 3721, 3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729,
+      3730, 3731, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3744,
+      3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759,
+      3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 3770, 3771, 3772, 3773, 3774,
+      3775, 3776, 3777, 3778, 3779, 3780, 3781, 3782, 3783, 3784, 3785, 3786, 3787, 3788, 3789,
+      3790, 3791, 3792, 3793, 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804,
+      3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 3814, 3815, 3816, 3817, 3818, 3819,
+      3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, 3828, 3829, 3830, 3831, 3832, 3833, 3834,
+      3835, 3836, 3837, 3838, 3839, 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, 3848, 3849,
+      3850, 3851, 3852, 3853, 3854, 3855, 3856, 3857, 3858, 3859, 3860, 3861, 3862, 3863, 3864,
+      3865, 3866, 3867, 3868, 3869, 3870, 3871, 3872, 3873, 3874, 3875, 3876, 3877, 3878, 3879,
+      3880, 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3888, 3889, 3890, 3891, 3892, 3893, 3894,
+      3895, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3904, 3905, 3906, 3907, 3908, 3909,
+      3910, 3911, 3912, 3913, 3914, 3915, 3916, 3917, 3918, 3919, 3920, 3921, 3922, 3923, 3924,
+      3925, 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939,
+      3940, 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948, 3949, 3950, 3951, 3952, 3953, 3954,
+      3955, 3956, 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3964, 3965, 3966, 3967, 3968, 3969,
+      3970, 3971, 3972, 3973, 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, 3982, 3983, 3984,
+      3985, 3986, 3987, 3988, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999,
+      4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014,
+      4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029,
+      4030, 4031, 4032, 4033, 4034, 4035, 4036, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044,
+      4045, 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059,
+      4060, 4061, 4062, 4063, 4064, 4065, 4066, 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074,
+      4075, 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088, 4089,
+      4090, 4091, 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, 4100, 4101, 4102, 4103, 4104,
+      4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 4118, 4119,
+      4120, 4121, 4122, 4123, 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, 4132, 4133, 4134,
+      4135, 4136, 4137, 4138, 4139, 4140, 4141, 4142, 4143, 4144, 4145, 4146, 4147, 4148, 4149,
+      4150, 4151, 4152, 4153, 4154, 4155, 4156, 4157, 4158, 4159, 4160, 4161, 4162, 4163, 4164,
+      4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4175, 4176, 4177, 4178, 4179,
+      4180, 4181, 4182, 4183, 4184, 4185, 4186, 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194,
+      4195, 4196, 4197, 4198, 4199, 4200, 4201, 4202, 4203, 4204, 4205, 4206, 4207, 4208, 4209,
+      4210, 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4218, 4219, 4220, 4221, 4222, 4223, 4224,
+      4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234, 4235, 4236, 4237, 4238, 4239,
+      4240, 4241, 4242, 4243, 4244, 4245, 4246, 4247, 4248, 4249, 4250, 4251, 4252, 4253, 4254,
+      4255, 4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269,
+      4270, 4271, 4272, 4273, 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284,
+      4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, 4299,
+      4300, 4301, 4302, 4303, 4304, 4305, 4306, 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314,
+      4315, 4316, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325, 4326, 4327, 4328, 4329,
+      4330, 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, 4339, 4340, 4341, 4342, 4343, 4344,
+      4345, 4346, 4347, 4348, 4349, 4350, 4351, 4352, 4353, 4354, 4355, 4356, 4357, 4358, 4359,
+      4360, 4361, 4362, 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, 4371, 4372, 4373, 4374,
+      4375, 4376, 4377, 4378, 4379, 4380, 4381, 4382, 4383, 4384, 4385, 4386, 4387, 4388, 4389,
+      4390, 4391, 4392, 4393, 4394, 4395, 4396, 4397, 4398, 4399, 4400, 4401, 4402, 4403, 4404,
+      4405, 4406, 4407, 4408, 4409, 4410, 4411, 4412, 4413, 4414, 4415, 4416, 4417, 4418, 4419,
+      4420, 4421, 4422, 4423, 4424, 4425, 4426, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434,
+      4435, 4436, 4437, 4438, 4439, 4440, 4441, 4442, 4443, 4444, 4445, 4446, 4447, 4448, 4449,
+      4450, 4451, 4452, 4453, 4454, 4455, 4456, 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464,
+      4465, 4466, 4467, 4468, 4469, 4470, 4471, 4472, 4473, 4474, 4475, 4476, 4477, 4478, 4479,
+      4480, 4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, 4489, 4490, 4491, 4492, 4493, 4494,
+      4495, 4496, 4497, 4498, 4499, 4500, 4501, 4502, 4503, 4504, 4505, 4506, 4507, 4508, 4509,
+      4510, 4511, 4512, 4513, 4514, 4515, 4516, 4517, 4518, 4519, 4520, 4521, 4522, 4523, 4524,
+      4525, 4526, 4527, 4528, 4529, 4530, 4531, 4532, 4533, 4534, 4535, 4536, 4537, 4538, 4539,
+      4540, 4541, 4542, 4543, 4544, 4545, 4546, 4547, 4548, 4549, 4550, 4551, 4552, 4553, 4554,
+      4555, 4556, 4557, 4558, 4559, 4560, 4561, 4562, 4563, 4564, 4565, 4566, 4567, 4568, 4569,
+      4570, 4571, 4572, 4573, 4574, 4575, 4576, 4577, 4578, 4579, 4580, 4581, 4582, 4583, 4584,
+      4585, 4586, 4587, 4588, 4589, 4590, 4591, 4592, 4593, 4594, 4595, 4596, 4597, 4598, 4599,
+      4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4609, 4610, 4611, 4612, 4613, 4614,
+      4615, 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, 4624, 4625, 4626, 4627, 4628, 4629,
+      4630, 4631, 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, 4640, 4641, 4642, 4643, 4644,
+      4645, 4646, 4647, 4648, 4649, 4650, 4651, 4652, 4653, 4654, 4655, 4656, 4657, 4658, 4659,
+      4660, 4661, 4662, 4663, 4664, 4665, 4666, 4667, 4668, 4669, 4670, 4671, 4672, 4673, 4674,
+      4675, 4676, 4677, 4678, 4679, 4680, 4681, 4682, 4683, 4684, 4685, 4686, 4687, 4688, 4689,
+      4690, 4691, 4692, 4693, 4694, 4695, 4696, 4697, 4698, 4699, 4700, 4701, 4702, 4703, 4704,
+      4705, 4706, 4707, 4708, 4709, 4710, 4711, 4712, 4713, 4714, 4715, 4716, 4717, 4718, 4719,
+      4720, 4721, 4722, 4723, 4724, 4725, 4726, 4727, 4728, 4729, 4730, 4731, 4732, 4733, 4734,
+      4735, 4736, 4737, 4738, 4739, 4740, 4741, 4742, 4743, 4744, 4745, 4746, 4747, 4748, 4749,
+      4750, 4751, 4752, 4753, 4754, 4755, 4756, 4757, 4758, 4759, 4760, 4761, 4762, 4763, 4764,
+      4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773, 4774, 4775, 4776, 4777, 4778, 4779,
+      4780, 4781, 4782, 4783, 4784, 4785, 4786, 4787, 4788, 4789, 4790, 4791, 4792, 4793, 4794,
+      4795, 4796, 4797, 4798, 4799, 4800, 4801, 4802, 4803, 4804, 4805, 4806, 4807, 4808, 4809,
+      4810, 4811, 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, 4820, 4821, 4822, 4823, 4824,
+      4825, 4826, 4827, 4828, 4829, 4830, 4831, 4832, 4833, 4834, 4835, 4836, 4837, 4838, 4839,
+      4840, 4841, 4842, 4843, 4844, 4845, 4846, 4847, 4848, 4849, 4850, 4851, 4852, 4853, 4854,
+      4855, 4856, 4857, 4858, 4859, 4860, 4861, 4862, 4863, 4864, 4865, 4866, 4867, 4868, 4869,
+      4870, 4871, 4872, 4873, 4874, 4875, 4876, 4877, 4878, 4879, 4880, 4881, 4882, 4883, 4884,
+      4885, 4886, 4887, 4888, 4889, 4890, 4891, 4892, 4893, 4894, 4895, 4896, 4897, 4898, 4899,
+      4900, 4901, 4902, 4903, 4904, 4905, 4906, 4907, 4908, 4909, 4910, 4911, 4912, 4913, 4914,
+      4915, 4916, 4917, 4918, 4919, 4920, 4921, 4922, 4923, 4924, 4925, 4926, 4927, 4928, 4929,
+      4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4938, 4939, 4940, 4941, 4942, 4943, 4944,
+      4945, 4946, 4947, 4948, 4949, 4950, 4951, 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959,
+      4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, 4968, 4969, 4970, 4971, 4972, 4973, 4974,
+      4975, 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, 4984, 4985, 4986, 4987, 4988, 4989,
+      4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, 5000, 5001, 5002, 5003, 5004,
+      5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019,
+      5020, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029, 5030, 5031, 5032, 5033, 5034,
+      5035, 5036, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044, 5045, 5046, 5047, 5048, 5049,
+      5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064,
+      5065, 5066, 5067, 5068, 5069, 5070, 5071, 5072, 5073, 5074, 5075, 5076, 5077, 5078, 5079,
+      5080, 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, 5089, 5090, 5091, 5092, 5093, 5094,
+      5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, 5109,
+      5110, 5111, 5112, 5113, 5114, 5115, 5116, 5117, 5118, 5119, 5120, 5121, 5122, 5123, 5124,
+      5125, 5126, 5127, 5128, 5129, 5130, 5131, 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139,
+      5140, 5141, 5142, 5143, 5144, 5145, 5146, 5147, 5148, 5149, 5150, 5151, 5152, 5153, 5154,
+      5155, 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5163, 5164, 5165, 5166, 5167, 5168, 5169,
+      5170, 5171, 5172, 5173, 5174, 5175, 5176, 5177, 5178, 5179, 5180, 5181, 5182, 5183, 5184,
+      5185, 5186, 5187, 5188, 5189, 5190, 5191, 5192, 5193, 5194, 5195, 5196, 5197, 5198, 5199,
+      5200, 5201, 5202, 5203, 5204, 5205, 5206, 5207, 5208, 5209, 5210, 5211, 5212, 5213, 5214,
+      5215, 5216, 5217, 5218, 5219, 5220, 5221, 5222, 5223, 5224, 5225, 5226, 5227, 5228, 5229,
+      5230, 5231, 5232, 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242, 5243, 5244,
+      5245, 5246, 5247, 5248, 5249, 5250, 5251, 5252, 5253, 5254, 5255, 5256, 5257, 5258, 5259,
+      5260, 5261, 5262, 5263, 5264, 5265, 5266, 5267, 5268, 5269, 5270, 5271, 5272, 5273, 5274,
+      5275, 5276, 5277, 5278, 5279, 5280, 5281, 5282, 5283, 5284, 5285, 5286, 5287, 5288, 5289,
+      5290, 5291, 5292, 5293, 5294, 5295, 5296, 5297, 5298, 5299, 5300, 5301, 5302, 5303, 5304,
+      5305, 5306, 5307, 5308, 5309, 5310, 5311, 5312, 5313, 5314, 5315, 5316, 5317, 5318, 5319,
+      5320, 5321, 5322, 5323, 5324, 5325, 5326, 5327, 5328, 5329, 5330, 5331, 5332, 5333, 5334,
+      5335, 5336, 5337, 5338, 5339, 5340, 5341, 5342, 5343, 5344, 5345, 5346, 5347, 5348, 5349,
+      5350, 5351, 5352, 5353, 5354, 5355, 5356, 5357, 5358, 5359, 5360, 5361, 5362, 5363, 5364,
+      5365, 5366, 5367, 5368, 5369, 5370, 5371, 5372, 5373, 5374, 5375, 5376, 5377, 5378, 5379,
+      5380, 5381, 5382, 5383, 5384, 5385, 5386, 5387, 5388, 5389, 5390, 5391, 5392, 5393, 5394,
+      5395, 5396, 5397, 5398, 5399, 5400, 5401, 5402, 5403, 5404, 5405, 5406, 5407, 5408, 5409,
+      5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5421, 5422, 5423, 5424,
+      5425, 5426, 5427, 5428, 5429, 5430, 5431, 5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439,
+      5440, 5441, 5442, 5443, 5444, 5445, 5446, 5447, 5448, 5449, 5450, 5451, 5452, 5453, 5454,
+      5455, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5469,
+      5470, 5471, 5472, 5473, 5474, 5475, 5476, 5477, 5478, 5479, 5480, 5481, 5482, 5483, 5484,
+      5485, 5486, 5487, 5488, 5489, 5490, 5491, 5492, 5493, 5494, 5495, 5496, 5497, 5498, 5499,
+      5500, 5501, 5502, 5503, 5504, 5505, 5506, 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514,
+      5515, 5516, 5517, 5518, 5519, 5520, 5521, 5522, 5523, 5524, 5525, 5526, 5527, 5528, 5529,
+      5530, 5531, 5532, 5533, 5534, 5535, 5536, 5537, 5538, 5539, 5540, 5541, 5542, 5543, 5544,
+      5545, 5546, 5547, 5548, 5549, 5550, 5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, 5559,
+      5560, 5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5570, 5571, 5572, 5573, 5574,
+      5575, 5576, 5577, 5578, 5579, 5580, 5581, 5582, 5583, 5584, 5585, 5586, 5587, 5588, 5589,
+      5590, 5591, 5592, 5593, 5594, 5595, 5596, 5597, 5598, 5599, 5600, 5601, 5602, 5603, 5604,
+      5605, 5606, 5607, 5608, 5609, 5610, 5611, 5612, 5613, 5614, 5615, 5616, 5617, 5618, 5619,
+      5620, 5621, 5622, 5623, 5624, 5625, 5626, 5627, 5628, 5629, 5630, 5631, 5632, 5633, 5634,
+      5635, 5636, 5637, 5638, 5639, 5640, 5641, 5642, 5643, 5644, 5645, 5646, 5647, 5648, 5649,
+      5650, 5651, 5652, 5653, 5654, 5655, 5656, 5657, 5658, 5659, 5660, 5661, 5662, 5663, 5664,
+      5665, 5666, 5667, 5668, 5669, 5670, 5671, 5672, 5673, 5674, 5675, 5676, 5677, 5678, 5679,
+      5680, 5681, 5682, 5683, 5684, 5685, 5686, 5687, 5688, 5689, 5690, 5691, 5692, 5693, 5694,
+      5695, 5696, 5697, 5698, 5699, 5700, 5701, 5702, 5703, 5704, 5705, 5706, 5707, 5708, 5709,
+      5710, 5711, 5712, 5713, 5714, 5715, 5716, 5717, 5718, 5719, 5720, 5721, 5722, 5723, 5724,
+      5725, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734, 5735, 5736, 5737, 5738, 5739,
+      5740, 5741, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, 5750, 5751, 5752, 5753, 5754,
+      5755, 5756, 5757, 5758, 5759, 5760, 5761, 5762, 5763, 5764, 5765, 5766, 5767, 5768, 5769,
+      5770, 5771, 5772, 5773, 5774, 5775, 5776, 5777, 5778, 5779, 5780, 5781, 5782, 5783, 5784,
+      5785, 5786, 5787, 5788, 5789, 5790, 5791, 5792, 5793, 5794, 5795, 5796, 5797, 5798, 5799,
+      5800, 5801, 5802, 5803, 5804, 5805, 5806, 5807, 5808, 5809, 5810, 5811, 5812, 5813, 5814,
+      5815, 5816, 5817, 5818, 5819, 5820, 5821, 5822, 5823, 5824, 5825, 5826, 5827, 5828, 5829,
+      5830, 5831, 5832, 5833, 5834, 5835, 5836, 5837, 5838, 5839, 5840, 5841, 5842, 5843, 5844,
+      5845, 5846, 5847, 5848, 5849, 5850, 5851, 5852, 5853, 5854, 5855, 5856, 5857, 5858, 5859,
+      5860, 5861, 5862, 5863, 5864, 5865, 5866, 5867, 5868, 5869, 5870, 5871, 5872, 5873, 5874,
+      5875, 5876, 5877, 5878, 5879, 5880, 5881, 5882, 5883, 5884, 5885, 5886, 5887, 5888, 5889,
+      5890, 5891, 5892, 5893, 5894, 5895, 5896, 5897, 5898, 5899, 5900, 5901, 5902, 5903, 5904,
+      5905, 5906, 5907, 5908, 5909, 5910, 5911, 5912, 5913, 5914, 5915, 5916, 5917, 5918, 5919,
+      5920, 5921, 5922, 5923, 5924, 5925, 5926, 5927, 5928, 5929, 5930, 5931, 5932, 5933, 5934,
+      5935, 5936, 5937, 5938, 5939, 5940, 5941, 5942, 5943, 5944, 5945, 5946, 5947, 5948, 5949,
+      5950, 5951, 5952, 5953, 5954, 5955, 5956, 5957, 5958, 5959, 5960, 5961, 5962, 5963, 5964,
+      5965, 5966, 5967, 5968, 5969, 5970, 5971, 5972, 5973, 5974, 5975, 5976, 5977, 5978, 5979,
+      5980, 5981, 5982, 5983, 5984, 5985, 5986, 5987, 5988, 5989, 5990, 5991, 5992, 5993, 5994,
+      5995, 5996, 5997, 5998, 5999, 6000, 6001, 6002, 6003, 6004, 6005, 6006, 6007, 6008, 6009,
+      6010, 6011, 6012, 6013, 6014, 6015, 6016, 6017, 6018, 6019, 6020, 6021, 6022, 6023, 6024,
+      6025, 6026, 6027, 6028, 6029, 6030, 6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, 6039,
+      6040, 6041, 6042, 6043, 6044, 6045, 6046, 6047, 6048, 6049, 6050, 6051, 6052, 6053, 6054,
+      6055, 6056, 6057, 6058, 6059, 6060, 6061, 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069,
+      6070, 6071, 6072, 6073, 6074, 6075, 6076, 6077, 6078, 6079, 6080, 6081, 6082, 6083, 6084,
+      6085, 6086, 6087, 6088, 6089, 6090, 6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099,
+      6100, 6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109, 6110, 6111, 6112, 6113, 6114,
+      6115, 6116, 6117, 6118, 6119, 6120, 6121, 6122, 6123, 6124, 6125, 6126, 6127, 6128, 6129,
+      6130, 6131, 6132, 6133, 6134, 6135, 6136, 6137, 6138, 6139, 6140, 6141, 6142, 6143, 6144,
+      6145, 6146, 6147, 6148, 6149, 6150, 6151, 6152, 6153, 6154, 6155, 6156, 6157, 6158, 6159,
+      6160, 6161, 6162, 6163, 6164, 6165, 6166, 6167, 6168, 6169, 6170, 6171, 6172, 6173, 6174,
+      6175, 6176, 6177, 6178, 6179, 6180, 6181, 6182, 6183, 6184, 6185, 6186, 6187, 6188, 6189,
+      6190, 6191, 6192, 6193, 6194, 6195, 6196, 6197, 6198, 6199, 6200, 6201, 6202, 6203, 6204,
+      6205, 6206, 6207, 6208, 6209, 6210, 6211, 6212, 6213, 6214, 6215, 6216, 6217, 6218, 6219,
+      6220, 6221, 6222, 6223, 6224, 6225, 6226, 6227, 6228, 6229, 6230, 6231, 6232, 6233, 6234,
+      6235, 6236, 6237, 6238, 6239, 6240, 6241, 6242, 6243, 6244, 6245, 6246, 6247, 6248, 6249,
+      6250, 6251, 6252, 6253, 6254, 6255, 6256, 6257, 6258, 6259, 6260, 6261, 6262, 6263, 6264,
+      6265, 6266, 6267, 6268, 6269, 6270, 6271, 6272, 6273, 6274, 6275, 6276, 6277, 6278, 6279,
+      6280, 6281, 6282, 6283, 6284, 6285, 6286, 6287, 6288, 6289, 6290, 6291, 6292, 6293, 6294,
+      6295, 6296, 6297, 6298, 6299, 6300, 6301, 6302, 6303, 6304, 6305, 6306, 6307, 6308, 6309,
+      6310, 6311, 6312, 6313, 6314, 6315, 6316, 6317, 6318, 6319, 6320, 6321, 6322, 6323, 6324,
+      6325, 6326, 6327, 6328, 6329, 6330, 6331, 6332, 6333, 6334, 6335, 6336, 6337, 6338, 6339,
+      6340, 6341, 6342, 6343, 6344, 6345, 6346, 6347, 6348, 6349, 6350, 6351, 6352, 6353, 6354,
+      6355, 6356, 6357, 6358, 6359, 6360, 6361, 6362, 6363, 6364, 6365, 6366, 6367, 6368, 6369,
+      6370, 6371, 6372, 6373, 6374, 6375, 6376, 6377, 6378, 6379, 6380, 6381, 6382, 6383, 6384,
+      6385, 6386, 6387, 6388, 6389, 6390, 6391, 6392, 6393, 6394, 6395, 6396, 6397, 6398, 6399,
+      6400, 6401, 6402, 6403, 6404, 6405, 6406, 6407, 6408, 6409, 6410, 6411, 6412, 6413, 6414,
+      6415, 6416, 6417, 6418, 6419, 6420, 6421, 6422, 6423, 6424, 6425, 6426, 6427, 6428, 6429,
+      6430, 6431, 6432, 6433, 6434, 6435, 6436, 6437, 6438, 6439, 6440, 6441, 6442, 6443, 6444,
+      6445, 6446, 6447, 6448, 6449, 6450, 6451, 6452, 6453, 6454, 6455, 6456, 6457, 6458, 6459,
+      6460, 6461, 6462, 6463, 6464, 6465, 6466, 6467, 6468, 6469, 6470, 6471, 6472, 6473, 6474,
+      6475, 6476, 6477, 6478, 6479, 6480, 6481, 6482, 6483, 6484, 6485, 6486, 6487, 6488, 6489,
+      6490, 6491, 6492, 6493, 6494, 6495, 6496, 6497, 6498, 6499, 6500, 6501, 6502, 6503, 6504,
+      6505, 6506, 6507, 6508, 6509, 6510, 6511, 6512, 6513, 6514, 6515, 6516, 6517, 6518, 6519,
+      6520, 6521, 6522, 6523, 6524, 6525, 6526, 6527, 6528, 6529, 6530, 6531, 6532, 6533, 6534,
+      6535, 6536, 6537, 6538, 6539, 6540, 6541, 6542, 6543, 6544, 6545, 6546, 6547, 6548, 6549,
+      6550, 6551, 6552, 6553, 6554, 6555, 6556, 6557, 6558, 6559, 6560, 6561, 6562, 6563, 6564,
+      6565, 6566, 6567, 6568, 6569, 6570, 6571, 6572, 6573, 6574, 6575, 6576, 6577, 6578, 6579,
+      6580, 6581, 6582, 6583, 6584, 6585, 6586, 6587, 6588, 6589, 6590, 6591, 6592, 6593, 6594,
+      6595, 6596, 6597, 6598, 6599, 6600, 6601, 6602, 6603, 6604, 6605, 6606, 6607, 6608, 6609,
+      6610, 6611, 6612, 6613, 6614, 6615, 6616, 6617, 6618, 6619, 6620, 6621, 6622, 6623, 6624,
+      6625, 6626, 6627, 6628, 6629, 6630, 6631, 6632, 6633, 6634, 6635, 6636, 6637, 6638, 6639,
+      6640, 6641, 6642, 6643, 6644, 6645, 6646, 6647, 6648, 6649, 6650, 6651, 6652, 6653, 6654,
+      6655, 6656, 6657, 6658, 6659, 6660, 6661, 6662, 6663, 6664, 6665, 6666, 6667, 6668, 6669,
+      6670, 6671, 6672, 6673, 6674, 6675, 6676, 6677, 6678, 6679, 6680, 6681, 6682, 6683, 6684,
+      6685, 6686, 6687, 6688, 6689, 6690, 6691, 6692, 6693, 6694, 6695, 6696, 6697, 6698, 6699,
+      6700, 6701, 6702, 6703, 6704, 6705, 6706, 6707, 6708, 6709, 6710, 6711, 6712, 6713, 6714,
+      6715, 6716, 6717, 6718, 6719, 6720, 6721, 6722, 6723, 6724, 6725, 6726, 6727, 6728, 6729,
+      6730, 6731, 6732, 6733, 6734, 6735, 6736, 6737, 6738, 6739, 6740, 6741, 6742, 6743, 6744,
+      6745, 6746, 6747, 6748, 6749, 6750, 6751, 6752, 6753, 6754, 6755, 6756, 6757, 6758, 6759,
+      6760, 6761, 6762, 6763, 6764, 6765, 6766, 6767, 6768, 6769, 6770, 6771, 6772, 6773, 6774,
+      6775, 6776, 6777, 6778, 6779, 6780, 6781, 6782, 6783, 6784, 6785, 6786, 6787, 6788, 6789,
+      6790, 6791, 6792, 6793, 6794, 6795, 6796, 6797, 6798, 6799, 6800, 6801, 6802, 6803, 6804,
+      6805, 6806, 6807, 6808, 6809, 6810, 6811, 6812, 6813, 6814, 6815, 6816, 6817, 6818, 6819,
+      6820, 6821, 6822, 6823, 6824, 6825, 6826, 6827, 6828, 6829, 6830, 6831, 6832, 6833, 6834,
+      6835, 6836, 6837, 6838, 6839, 6840, 6841, 6842, 6843, 6844, 6845, 6846, 6847, 6848, 6849,
+      6850, 6851, 6852, 6853, 6854, 6855, 6856, 6857, 6858, 6859, 6860, 6861, 6862, 6863, 6864,
+      6865, 6866, 6867, 6868, 6869, 6870, 6871, 6872, 6873, 6874, 6875, 6876, 6877, 6878, 6879,
+      6880, 6881, 6882, 6883, 6884, 6885, 6886, 6887, 6888, 6889, 6890, 6891, 6892, 6893, 6894,
+      6895, 6896, 6897, 6898, 6899, 6900, 6901, 6902, 6903, 6904, 6905, 6906, 6907, 6908, 6909,
+      6910, 6911, 6912, 6913, 6914, 6915, 6916, 6917, 6918, 6919, 6920, 6921, 6922, 6923, 6924,
+      6925, 6926, 6927, 6928, 6929, 6930, 6931, 6932, 6933, 6934, 6935, 6936, 6937, 6938, 6939,
+      6940, 6941, 6942, 6943, 6944, 6945, 6946, 6947, 6948, 6949, 6950, 6951, 6952, 6953, 6954,
+      6955, 6956, 6957, 6958, 6959, 6960, 6961, 6962, 6963, 6964, 6965, 6966, 6967, 6968, 6969,
+      6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978, 6979, 6980, 6981, 6982, 6983, 6984,
+      6985, 6986, 6987, 6988, 6989, 6990, 6991, 6992, 6993, 6994, 6995, 6996, 6997, 6998, 6999,
+      7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014,
+      7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, 7029,
+      7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, 7041, 7042, 7043, 7044,
+      7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059,
+      7060, 7061, 7062, 7063, 7064, 7065, 7066, 7067, 7068, 7069, 7070, 7071, 7072, 7073, 7074,
+      7075, 7076, 7077, 7078, 7079, 7080, 7081, 7082, 7083, 7084, 7085, 7086, 7087, 7088, 7089,
+      7090, 7091, 7092, 7093, 7094, 7095, 7096, 7097, 7098, 7099, 7100, 7101, 7102, 7103, 7104,
+      7105, 7106, 7107, 7108, 7109, 7110, 7111, 7112, 7113, 7114, 7115, 7116, 7117, 7118, 7119,
+      7120, 7121, 7122, 7123, 7124, 7125, 7126, 7127, 7128, 7129, 7130, 7131, 7132, 7133, 7134,
+      7135, 7136, 7137, 7138, 7139, 7140, 7141, 7142, 7143, 7144, 7145, 7146, 7147, 7148, 7149,
+      7150, 7151, 7152, 7153, 7154, 7155, 7156, 7157, 7158, 7159, 7160, 7161, 7162, 7163, 7164,
+      7165, 7166, 7167, 7168, 7169, 7170, 7171, 7172, 7173, 7174, 7175, 7176, 7177, 7178, 7179,
+      7180, 7181, 7182, 7183, 7184, 7185, 7186, 7187, 7188, 7189, 7190, 7191, 7192, 7193, 7194,
+      7195, 7196, 7197, 7198, 7199, 7200, 7201, 7202, 7203, 7204, 7205, 7206, 7207, 7208, 7209,
+      7210, 7211, 7212, 7213, 7214, 7215, 7216, 7217, 7218, 7219, 7220, 7221, 7222, 7223, 7224,
+      7225, 7226, 7227, 7228, 7229, 7230, 7231, 7232, 7233, 7234, 7235, 7236, 7237, 7238, 7239,
+      7240, 7241, 7242, 7243, 7244, 7245, 7246, 7247, 7248, 7249, 7250, 7251, 7252, 7253, 7254,
+      7255, 7256, 7257, 7258, 7259, 7260, 7261, 7262, 7263, 7264, 7265, 7266, 7267, 7268, 7269,
+      7270, 7271, 7272, 7273, 7274, 7275, 7276, 7277, 7278, 7279, 7280, 7281, 7282, 7283, 7284,
+      7285, 7286, 7287, 7288, 7289, 7290, 7291, 7292, 7293, 7294, 7295, 7296, 7297, 7298, 7299,
+      7300, 7301, 7302, 7303, 7304, 7305, 7306, 7307, 7308, 7309, 7310, 7311, 7312, 7313, 7314,
+      7315, 7316, 7317, 7318, 7319, 7320, 7321, 7322, 7323, 7324, 7325, 7326, 7327, 7328, 7329,
+      7330, 7331, 7332, 7333, 7334, 7335, 7336, 7337, 7338, 7339, 7340, 7341, 7342, 7343, 7344,
+      7345, 7346, 7347, 7348, 7349, 7350, 7351, 7352, 7353, 7354, 7355, 7356, 7357, 7358, 7359,
+      7360, 7361, 7362, 7363, 7364, 7365, 7366, 7367, 7368, 7369, 7370, 7371, 7372, 7373, 7374,
+      7375, 7376, 7377, 7378, 7379, 7380, 7381, 7382, 7383, 7384, 7385, 7386, 7387, 7388, 7389,
+      7390, 7391, 7392, 7393, 7394, 7395, 7396, 7397, 7398, 7399, 7400, 7401, 7402, 7403, 7404,
+      7405, 7406, 7407, 7408, 7409, 7410, 7411, 7412, 7413, 7414, 7415, 7416, 7417, 7418, 7419,
+      7420, 7421, 7422, 7423, 7424, 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432, 7433, 7434,
+      7435, 7436, 7437, 7438, 7439, 7440, 7441, 7442, 7443, 7444, 7445, 7446, 7447, 7448, 7449,
+      7450, 7451, 7452, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, 7463, 7464,
+      7465, 7466, 7467, 7468, 7469, 7470, 7471, 7472, 7473, 7474, 7475, 7476, 7477, 7478, 7479,
+      7480, 7481, 7482, 7483, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494,
+      7495, 7496, 7497, 7498, 7499, 7500, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509,
+      7510, 7511, 7512, 7513, 7514, 7515, 7516, 7517, 7518, 7519, 7520, 7521, 7522, 7523, 7524,
+      7525, 7526, 7527, 7528, 7529, 7530, 7531, 7532, 7533, 7534, 7535, 7536, 7537, 7538, 7539,
+      7540, 7541, 7542, 7543, 7544, 7545, 7546, 7547, 7548, 7549, 7550, 7551, 7552, 7553, 7554,
+      7555, 7556, 7557, 7558, 7559, 7560, 7561, 7562, 7563, 7564, 7565, 7566, 7567, 7568, 7569,
+      7570, 7571, 7572, 7573, 7574, 7575, 7576, 7577, 7578, 7579, 7580, 7581, 7582, 7583, 7584,
+      7585, 7586, 7587, 7588, 7589, 7590, 7591, 7592, 7593, 7594, 7595, 7596, 7597, 7598, 7599,
+      7600, 7601, 7602, 7603, 7604, 7605, 7606, 7607, 7608, 7609, 7610, 7611, 7612, 7613, 7614,
+      7615, 7616, 7617, 7618, 7619, 7620, 7621, 7622, 7623, 7624, 7625, 7626, 7627, 7628, 7629,
+      7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, 7641, 7642, 7643, 7644,
+      7645, 7646, 7647, 7648, 7649, 7650, 7651, 7652, 7653, 7654, 7655, 7656, 7657, 7658, 7659,
+      7660, 7661, 7662, 7663, 7664, 7665, 7666, 7667, 7668, 7669, 7670, 7671, 7672, 7673, 7674,
+      7675, 7676, 7677, 7678, 7679, 7680, 7681, 7682, 7683, 7684, 7685, 7686, 7687, 7688, 7689,
+      7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, 7700, 7701, 7702, 7703, 7704,
+      7705, 7706, 7707, 7708, 7709, 7710, 7711, 7712, 7713, 7714, 7715, 7716, 7717, 7718, 7719,
+      7720, 7721, 7722, 7723, 7724, 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, 7733, 7734,
+      7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742, 7743, 7744, 7745, 7746, 7747, 7748, 7749,
+      7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, 7761, 7762, 7763, 7764,
+      7765, 7766, 7767, 7768, 7769, 7770, 7771, 7772, 7773, 7774, 7775, 7776, 7777, 7778, 7779,
+      7780, 7781, 7782, 7783, 7784, 7785, 7786, 7787, 7788, 7789, 7790, 7791, 7792, 7793, 7794,
+      7795, 7796, 7797, 7798, 7799, 7800, 7801, 7802, 7803, 7804, 7805, 7806, 7807, 7808, 7809,
+      7810, 7811, 7812, 7813, 7814, 7815, 7816, 7817, 7818, 7819, 7820, 7821, 7822, 7823, 7824,
+      7825, 7826, 7827, 7828, 7829, 7830, 7831, 7832, 7833, 7834, 7835, 7836, 7837, 7838, 7839,
+      7840, 7841, 7842, 7843, 7844, 7845, 7846, 7847, 7848, 7849, 7850, 7851, 7852, 7853, 7854,
+      7855, 7856, 7857, 7858, 7859, 7860, 7861, 7862, 7863, 7864, 7865, 7866, 7867, 7868, 7869,
+      7870, 7871, 7872, 7873, 7874, 7875, 7876, 7877, 7878, 7879, 7880, 7881, 7882, 7883, 7884,
+      7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, 7893, 7894, 7895, 7896, 7897, 7898, 7899,
+      7900, 7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, 7910, 7911, 7912, 7913, 7914,
+      7915, 7916, 7917, 7918, 7919, 7920, 7921, 7922, 7923, 7924, 7925, 7926, 7927, 7928, 7929,
+      7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7944,
+      7945, 7946, 7947, 7948, 7949, 7950, 7951, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7959,
+      7960, 7961, 7962, 7963, 7964, 7965, 7966, 7967, 7968, 7969, 7970, 7971, 7972, 7973, 7974,
+      7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7984, 7985, 7986, 7987, 7988, 7989,
+      7990, 7991, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999
+    },
+    {
+      95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+      115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126
+    }
+  };
+
+  public static boolean equals(BitSet bs, RoaringBitmap rr) {
+    final int[] a = new int[bs.cardinality()];
+    int pos = 0;
+    for (int x = bs.nextSetBit(0); x >= 0; x = bs.nextSetBit(x + 1)) {
+      a[pos++] = x;
+    }
+    return Arrays.equals(rr.toArray(), a);
+  }
+
+  private static  Iterator toIterator(final T[] x) {
+    return new Iterator() {
+      int pos = 0;
+
+      @Override
+      public boolean hasNext() {
+        return pos < x.length;
+      }
+
+      @Override
+      public T next() {
+        return x[pos++];
+      }
+
+      @Override
+      public void remove() {}
+    };
+  }
+
+  @Test
+  public void andBigIntsTest() {
+    RoaringBitmap rb = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
+    HashSet hs = new HashSet();
+
+    for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 3) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 4) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) {
+      rb.add(i);
+    }
+
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) {
+      hs.add(i);
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 4) {
+      hs.add(i);
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) {
+      hs.add(i);
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 7) {
+      rb2.add(i);
+    }
+
+    RoaringBitmap rband = RoaringBitmap.and(rb, rb2);
+
+    Object[] correct = hs.toArray();
+    Arrays.sort(correct);
+    Integer[] resand = ArrayUtils.toObject(rband.toArray());
+    assertArrayEquals(correct, resand);
+  }
+
+  @Test
+  public void andcounttest() {
+    // This is based on andtest
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+    }
+    rr.add(100000);
+    rr.add(110000);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    rr2.add(13);
+    final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2);
+    assertEquals(rrand.getCardinality(), RoaringBitmap.andCardinality(rr, rr2));
+    assertEquals(rrand.getCardinality(), RoaringBitmap.andCardinality(rr2, rr));
+    rr.and(rr2);
+    assertEquals(rrand.getCardinality(), RoaringBitmap.andCardinality(rr2, rr));
+  }
+
+  @Test
+  public void andCounttest3() {
+    // This is based on andtest3
+    final int[] arrayand = new int[11256];
+    int pos = 0;
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536; k < 3 * 65536 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536 + 7000; k < 3 * 65536 + 9000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4 * 65536; k < 4 * 65536 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 6 * 65536; k < 6 * 65536 + 10000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 8 * 65536; k < 8 * 65536 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 9 * 65536; k < 9 * 65536 + 30000; ++k) {
+      rr.add(k);
+    }
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 6 * 65536; k < 6 * 65536 + 1000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 7 * 65536; k < 7 * 65536 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 10 * 65536; k < 10 * 65536 + 5000; ++k) {
+      rr2.add(k);
+    }
+
+    final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2);
+    final int rrandCount = RoaringBitmap.andCardinality(rr, rr2);
+
+    assertEquals(rrand.getCardinality(), rrandCount);
+  }
+
+  @Test
+  public void andNot() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    rb.add(1);
+    rb.add(1 << 16);
+    rb2.add(1 << 16);
+    rb.add(2 << 16);
+    rb.add(3 << 16);
+    rb2.add(3 << 16);
+    rb.andNot(rb2);
+
+    final IntIterator i = rb.getIntIterator();
+    assertTrue(i.hasNext());
+    assertEquals(1, i.next());
+    assertTrue(i.hasNext());
+    assertEquals(2 << 16, i.next());
+    assertFalse(i.hasNext());
+  }
+
+  @Test
+  public void andNotBigIntsTest() {
+    RoaringBitmap rb = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
+    HashSet hs = new HashSet();
+
+    for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) {
+      rb.add(i);
+      hs.add(i);
+    }
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 6 * 65536; i += 3) {
+      hs.add(i);
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) {
+      rb.add(i);
+    }
+
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) {
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 4) {
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 5) {
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 7) {
+      rb2.add(i);
+    }
+
+    RoaringBitmap rbandnot = RoaringBitmap.andNot(rb, rb2);
+
+    Object[] correct = hs.toArray();
+    Arrays.sort(correct);
+    Integer[] resandNot = ArrayUtils.toObject(rbandnot.toArray());
+    assertArrayEquals(correct, resandNot);
+  }
+
+  @Test
+  public void ANDNOTtest() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) {
+      rr.add(k);
+    }
+
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) {
+      rr2.add(k);
+    }
+    final RoaringBitmap correct = RoaringBitmap.andNot(rr, rr2);
+    rr.andNot(rr2);
+    assertEquals(correct, rr);
+  }
+
+  @Test
+  public void andnottest4() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    for (int i = 0; i < 200000; i += 4) {
+      rb2.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 14) {
+      rb2.add(i);
+    }
+    rb2.getCardinality();
+
+    // check or against an empty bitmap
+    final RoaringBitmap andNotresult = RoaringBitmap.andNot(rb, rb2);
+    final RoaringBitmap off = RoaringBitmap.andNot(rb2, rb);
+
+    assertEquals(rb, andNotresult);
+    assertEquals(rb2, off);
+    rb2.andNot(rb);
+    assertEquals(rb2, off);
+  }
+
+  @Test
+  public void andtest() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+    }
+    rr.add(100000);
+    rr.add(110000);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    rr2.add(13);
+    final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2);
+    int[] array = rrand.toArray();
+
+    assertEquals(array.length, 1);
+    assertEquals(array[0], 13);
+    rr.and(rr2);
+    array = rr.toArray();
+    assertEquals(array.length, 1);
+    assertEquals(array[0], 13);
+  }
+
+  @Test
+  public void ANDtest() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) {
+      rr.add(k);
+    }
+
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) {
+      rr2.add(k);
+    }
+    final RoaringBitmap correct = RoaringBitmap.and(rr, rr2);
+    rr.and(rr2);
+    assertEquals(correct, rr);
+  }
+
+  @Test
+  public void andtest2() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+    }
+    rr.add(100000);
+    rr.add(110000);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    rr2.add(13);
+    final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2);
+
+    final int[] array = rrand.toArray();
+    assertEquals(array.length, 1);
+    assertEquals(array[0], 13);
+  }
+
+  @Test
+  public void andtest3() {
+    final int[] arrayand = new int[11256];
+    int pos = 0;
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536; k < 3 * 65536 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536 + 7000; k < 3 * 65536 + 9000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4 * 65536; k < 4 * 65536 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 6 * 65536; k < 6 * 65536 + 10000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 8 * 65536; k < 8 * 65536 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 9 * 65536; k < 9 * 65536 + 30000; ++k) {
+      rr.add(k);
+    }
+
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 6 * 65536; k < 6 * 65536 + 1000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 7 * 65536; k < 7 * 65536 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 10 * 65536; k < 10 * 65536 + 5000; ++k) {
+      rr2.add(k);
+    }
+
+    final RoaringBitmap rrand = RoaringBitmap.and(rr, rr2);
+
+    final int[] arrayres = rrand.toArray();
+
+    assertArrayEquals(arrayand, arrayres);
+  }
+
+  @Test
+  public void andtest4() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    for (int i = 0; i < 200000; i += 4) {
+      rb2.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 14) {
+      rb2.add(i);
+    }
+
+    // check or against an empty bitmap
+    final RoaringBitmap andresult = RoaringBitmap.and(rb, rb2);
+    final RoaringBitmap off = RoaringBitmap.and(rb2, rb);
+    assertEquals(andresult, off);
+
+    assertEquals(0, andresult.getCardinality());
+
+    for (int i = 500000; i < 600000; i += 14) {
+      rb.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 3) {
+      rb2.add(i);
+    }
+    // check or against an empty bitmap
+    final RoaringBitmap andresult2 = RoaringBitmap.and(rb, rb2);
+    assertEquals(0, andresult.getCardinality());
+
+    assertEquals(0, andresult2.getCardinality());
+    for (int i = 0; i < 200000; i += 4) {
+      rb.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 14) {
+      rb.add(i);
+    }
+    assertEquals(0, andresult.getCardinality());
+    final RoaringBitmap rc = RoaringBitmap.and(rb, rb2);
+    rb.and(rb2);
+    assertEquals(rc.getCardinality(), rb.getCardinality());
+  }
+
+  @Test
+  public void ArrayContainerCardinalityTest() {
+    final ArrayContainer ac = new ArrayContainer();
+    for (char k = 0; k < 100; ++k) {
+      ac.add(k);
+      assertEquals(ac.getCardinality(), k + 1);
+    }
+    for (char k = 0; k < 100; ++k) {
+      ac.add(k);
+      assertEquals(ac.getCardinality(), 100);
+    }
+  }
+
+  @Test
+  public void arraytest() {
+    final ArrayContainer rr = new ArrayContainer();
+    rr.add((char) 110);
+    rr.add((char) 114);
+    rr.add((char) 115);
+    final char[] array = new char[3];
+    int pos = 0;
+    for (final char i : rr) {
+      array[pos++] = i;
+    }
+    assertEquals(array[0], (char) 110);
+    assertEquals(array[1], (char) 114);
+    assertEquals(array[2], (char) 115);
+  }
+
+  @Test
+  public void basictest() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    final int[] a = new int[4002];
+    int pos = 0;
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+      a[pos++] = k;
+    }
+    rr.add(100000);
+    a[pos++] = 100000;
+    rr.add(110000);
+    a[pos++] = 110000;
+    final int[] array = rr.toArray();
+
+    assertArrayEquals(array, a);
+  }
+
+  @Test
+  public void BitmapContainerCardinalityTest() {
+    final BitmapContainer ac = new BitmapContainer();
+    for (char k = 0; k < 100; ++k) {
+      ac.add(k);
+      assertEquals(ac.getCardinality(), k + 1);
+    }
+    for (char k = 0; k < 100; ++k) {
+      ac.add(k);
+      assertEquals(ac.getCardinality(), 100);
+    }
+  }
+
+  @Test
+  public void bitmapOfTest() {
+    int[] cuiRelsArray = new int[1024];
+    for (int k = 0; k < cuiRelsArray.length; ++k) {
+      cuiRelsArray[k] = k;
+    }
+    RoaringBitmap rr1 = RoaringBitmap.bitmapOf(cuiRelsArray);
+    int[] back = rr1.toArray();
+    assertArrayEquals(cuiRelsArray, back);
+  }
+
+  @Test
+  public void bitmaptest() {
+    final BitmapContainer rr = new BitmapContainer();
+    rr.add((char) 110);
+    rr.add((char) 114);
+    rr.add((char) 115);
+    final char[] array = new char[3];
+    int pos = 0;
+    for (final char i : rr) {
+      array[pos++] = i;
+    }
+    assertEquals(array[0], (char) 110);
+    assertEquals(array[1], (char) 114);
+    assertEquals(array[2], (char) 115);
+  }
+
+  @Test
+  public void cardinalityTest() {
+    final int N = 1024;
+    for (int gap = 7; gap < 100000; gap *= 10) {
+      for (int offset = 2; offset <= 1024; offset *= 2) {
+        final RoaringBitmap rb = new RoaringBitmap();
+        // check the add of new values
+        for (int k = 0; k < N; k++) {
+          rb.add(k * gap);
+          assertEquals(rb.getCardinality(), k + 1);
+        }
+        assertEquals(rb.getCardinality(), N);
+        // check the add of existing values
+        for (int k = 0; k < N; k++) {
+          rb.add(k * gap);
+          assertEquals(rb.getCardinality(), N);
+        }
+
+        final RoaringBitmap rb2 = new RoaringBitmap();
+
+        for (int k = 0; k < N; k++) {
+          rb2.add(k * gap * offset);
+          assertEquals(rb2.getCardinality(), k + 1);
+        }
+
+        assertEquals(rb2.getCardinality(), N);
+
+        for (int k = 0; k < N; k++) {
+          rb2.add(k * gap * offset);
+          assertEquals(rb2.getCardinality(), N);
+        }
+        assertEquals(RoaringBitmap.and(rb, rb2).getCardinality(), N / offset);
+        assertEquals(RoaringBitmap.or(rb, rb2).getCardinality(), 2 * N - N / offset);
+        assertEquals(RoaringBitmap.xor(rb, rb2).getCardinality(), 2 * N - 2 * N / offset);
+      }
+    }
+  }
+
+  @Test
+  public void clearTest() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    for (int i = 0; i < 200000; i += 7) {
+      // dense
+      rb.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 177) {
+      // sparse
+      rb.add(i);
+    }
+
+    final RoaringBitmap rb2 = new RoaringBitmap();
+    final RoaringBitmap rb3 = new RoaringBitmap();
+    for (int i = 0; i < 200000; i += 4) {
+      rb2.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 14) {
+      rb2.add(i);
+    }
+
+    rb.clear();
+    assertEquals(0, rb.getCardinality());
+    assertTrue(0 != rb2.getCardinality());
+
+    rb.add(4);
+    rb3.add(4);
+    final RoaringBitmap andresult = RoaringBitmap.and(rb, rb2);
+    final RoaringBitmap orresult = RoaringBitmap.or(rb, rb2);
+
+    assertEquals(1, andresult.getCardinality());
+    assertEquals(rb2.getCardinality(), orresult.getCardinality());
+
+    for (int i = 0; i < 200000; i += 4) {
+      rb.add(i);
+      rb3.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 114) {
+      rb.add(i);
+      rb3.add(i);
+    }
+
+    final int[] arrayrr = rb.toArray();
+    final int[] arrayrr3 = rb3.toArray();
+
+    assertArrayEquals(arrayrr, arrayrr3);
+  }
+
+  @Test
+  public void ContainerFactory() {
+    BitmapContainer bc1, bc2, bc3;
+    ArrayContainer ac1, ac2, ac3;
+
+    bc1 = new BitmapContainer();
+    bc2 = new BitmapContainer();
+    bc3 = new BitmapContainer();
+    ac1 = new ArrayContainer();
+    ac2 = new ArrayContainer();
+    ac3 = new ArrayContainer();
+
+    for (char i = 0; i < 5000; i++) {
+      bc1.add((char) (i * 70));
+    }
+    for (char i = 0; i < 5000; i++) {
+      bc2.add((char) (i * 70));
+    }
+    for (char i = 0; i < 5000; i++) {
+      bc3.add((char) (i * 70));
+    }
+
+    for (char i = 0; i < 4000; i++) {
+      ac1.add((char) (i * 50));
+    }
+    for (char i = 0; i < 4000; i++) {
+      ac2.add((char) (i * 50));
+    }
+    for (char i = 0; i < 4000; i++) {
+      ac3.add((char) (i * 50));
+    }
+
+    BitmapContainer rbc;
+
+    rbc = ac1.clone().toBitmapContainer();
+    assertTrue(validate(rbc, ac1));
+    rbc = ac2.clone().toBitmapContainer();
+    assertTrue(validate(rbc, ac2));
+    rbc = ac3.clone().toBitmapContainer();
+    assertTrue(validate(rbc, ac3));
+  }
+
+  @Test
+  public void containerSharingWithXor() {
+    RoaringBitmap r1 = new RoaringBitmap();
+    r1.flip(131000L, 131001L);
+    RoaringBitmap r2 = new RoaringBitmap();
+    r2.add(220000);
+    RoaringBitmap r3 = new RoaringBitmap();
+    int killingPosition = 66000;
+    r3.add(killingPosition);
+    assertFalse(r1.contains(killingPosition));
+    r2.xor(r1);
+    assertTrue(r2.contains(131000));
+    assertFalse(r1.contains(killingPosition));
+    r2.or(r3);
+    assertTrue(r2.contains(131000));
+    assertTrue(r2.contains(killingPosition));
+    assertFalse(r1.contains(killingPosition));
+  }
+
+  // From a bug report contributed by Kevin Karpenske
+  // this had created an array out of bounds error
+  @Test
+  public void fliptest_Karpenske() {
+    long[] array =
+        new long[] {
+          343798, 343799, 343800, 343801, 343803, 343804, 343805, 343807, 343809, 343811, 343812,
+          343815, 343816, 343817, 343818, 343819, 343821, 343825, 343827, 343828, 343830, 343831,
+          343832, 343833, 343835, 343836, 343837, 343838, 343839, 343840, 343841, 343842, 343843,
+          343844, 343845, 343847, 343848, 343849, 343850, 343851, 343853, 343854, 343855, 343856,
+          343858, 343859, 343860, 343861, 343862, 343863, 343864, 343865, 343866, 343868, 343869,
+          343874, 343875, 343877, 343879, 343880, 343881, 343882, 343883, 343887, 343889, 343890,
+          343891, 343894, 343895, 343898, 343899, 343900, 343901, 343902, 343904, 343906, 343907,
+          343908, 343909, 343910, 343911, 343912, 343913, 343914, 343915, 343916, 343917, 343918,
+          343919, 343921, 343922, 343923, 343924, 343927, 343928, 343929, 343930, 343931, 343932,
+          343933, 343934, 343935, 343938, 343939, 343941, 343942, 343943, 343944, 343945, 343946,
+          343949, 343951, 343953, 343954, 343955, 343956, 343958, 343959, 343961, 343962, 343964,
+          343965, 343966, 343967, 343968, 343969, 343971, 343972, 343973, 343974, 343976, 343978,
+          343979, 343981, 343982, 343983, 343985, 343987, 343988, 343989, 343992, 343993, 343994,
+          343995, 343996, 343997, 343998, 344000, 344001, 344002, 344003, 344004, 344006, 344008,
+          344009, 344011, 344012, 344013, 344015, 344017, 344019, 344020, 344021, 344023, 344025,
+          344026, 344027, 344028, 344029, 344030, 344031, 344034, 344035, 344036, 344037, 344038,
+          344039, 344040, 344042, 344043, 344046, 344047
+        };
+    RoaringBitmap bitmap = new RoaringBitmap();
+    long[] indexes = array;
+    int rangeStart = 0;
+    for (int rangeEnd = 1; rangeEnd < indexes.length; rangeEnd++) {
+      if (indexes[rangeEnd - 1] + 1 != indexes[rangeEnd]) {
+        if (rangeStart == rangeEnd - 1) {
+          bitmap.add((int) indexes[rangeStart]);
+        } else {
+          bitmap.flip(indexes[rangeStart], indexes[rangeEnd - 1] + 1);
+        }
+        rangeStart = rangeEnd;
+      }
+    }
+    if (rangeStart == indexes.length - 1) {
+      bitmap.add((int) indexes[rangeStart]);
+    } else {
+      bitmap.flip(indexes[rangeStart], indexes[indexes.length - 1] + 1);
+    }
+    assertEquals(182, bitmap.getCardinality());
+  }
+
+  @Test
+  public void flipTest1() {
+    final RoaringBitmap rb = new RoaringBitmap();
+
+    rb.flip(100000L, 200000L); // in-place on empty bitmap
+    final int rbcard = rb.getCardinality();
+    assertEquals(100000, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 100000; i < 200000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest1A() {
+    final RoaringBitmap rb = new RoaringBitmap();
+
+    final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 200000L);
+    final int rbcard = rb1.getCardinality();
+    assertEquals(100000, rbcard);
+    assertEquals(0, rb.getCardinality());
+
+    final BitSet bs = new BitSet();
+    assertTrue(equals(bs, rb)); // still empty?
+    for (int i = 100000; i < 200000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb1));
+  }
+
+  @Test
+  public void flipTest2() {
+    final RoaringBitmap rb = new RoaringBitmap();
+
+    rb.flip(100000L, 100000L);
+    final int rbcard = rb.getCardinality();
+    assertEquals(0, rbcard);
+
+    final BitSet bs = new BitSet();
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest2A() {
+    final RoaringBitmap rb = new RoaringBitmap();
+
+    final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 100000L);
+    rb.add(1); // will not affect rb1 (no shared container)
+    final int rbcard = rb1.getCardinality();
+    assertEquals(0, rbcard);
+    assertEquals(1, rb.getCardinality());
+
+    final BitSet bs = new BitSet();
+    assertTrue(equals(bs, rb1));
+    bs.set(1);
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest3() {
+    final RoaringBitmap rb = new RoaringBitmap();
+
+    rb.flip(100000L, 200000L); // got 100k-199999
+    rb.flip(100000L, 199991L); // give back 100k-199990
+    final int rbcard = rb.getCardinality();
+
+    assertEquals(9, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 199991; i < 200000; ++i) {
+      bs.set(i);
+    }
+
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest3A() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 200000L);
+    final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 100000L, 199991L);
+    final int rbcard = rb2.getCardinality();
+
+    assertEquals(9, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 199991; i < 200000; ++i) {
+      bs.set(i);
+    }
+
+    assertTrue(equals(bs, rb2));
+  }
+
+  @Test
+  public void flipTest4() { // fits evenly on both ends
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.flip(100000L, 200000L); // got 100k-199999
+    rb.flip(65536L, 4 * 65536L);
+    final int rbcard = rb.getCardinality();
+
+    // 65536 to 99999 are 1s
+    // 200000 to 262143 are 1s: total card
+
+    assertEquals(96608, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 65536; i < 100000; ++i) {
+      bs.set(i);
+    }
+    for (int i = 200000; i < 262144; ++i) {
+      bs.set(i);
+    }
+
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest4A() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 200000L);
+    final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 65536L, 4 * 65536L);
+    final int rbcard = rb2.getCardinality();
+
+    assertEquals(96608, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 65536; i < 100000; ++i) {
+      bs.set(i);
+    }
+    for (int i = 200000; i < 262144; ++i) {
+      bs.set(i);
+    }
+
+    assertTrue(equals(bs, rb2));
+  }
+
+  @Test
+  public void flipTest5() { // fits evenly on small end, multiple
+    // containers
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.flip(100000L, 132000L);
+    rb.flip(65536L, 120000L);
+    final int rbcard = rb.getCardinality();
+
+    // 65536 to 99999 are 1s
+    // 120000 to 131999
+
+    assertEquals(46464, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 65536; i < 100000; ++i) {
+      bs.set(i);
+    }
+    for (int i = 120000; i < 132000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest5A() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 132000L);
+    final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 65536L, 120000L);
+    final int rbcard = rb2.getCardinality();
+
+    assertEquals(46464, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 65536; i < 100000; ++i) {
+      bs.set(i);
+    }
+    for (int i = 120000; i < 132000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb2));
+  }
+
+  @Test
+  public void flipTest6() { // fits evenly on big end, multiple containers
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.flip(100000L, 132000L);
+    rb.flip(99000L, 2 * 65536L);
+    final int rbcard = rb.getCardinality();
+
+    // 99000 to 99999 are 1000 1s
+    // 131072 to 131999 are 928 1s
+
+    assertEquals(1928, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 99000; i < 100000; ++i) {
+      bs.set(i);
+    }
+    for (int i = 2 * 65536; i < 132000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest6A() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 100000L, 132000L);
+    final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 99000L, 2 * 65536L);
+    final int rbcard = rb2.getCardinality();
+
+    assertEquals(1928, rbcard);
+
+    final BitSet bs = new BitSet();
+    for (int i = 99000; i < 100000; ++i) {
+      bs.set(i);
+    }
+    for (int i = 2 * 65536; i < 132000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb2));
+  }
+
+  @Test
+  public void flipTest7() { // within 1 word, first container
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.flip(650L, 132000L);
+    rb.flip(648L, 651L);
+    final int rbcard = rb.getCardinality();
+
+    // 648, 649, 651-131999
+
+    assertEquals(132000 - 651 + 2, rbcard);
+
+    final BitSet bs = new BitSet();
+    bs.set(648);
+    bs.set(649);
+    for (int i = 651; i < 132000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb));
+  }
+
+  @Test
+  public void flipTest7A() { // within 1 word, first container
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb1 = RoaringBitmap.flip(rb, 650L, 132000L);
+    final RoaringBitmap rb2 = RoaringBitmap.flip(rb1, 648L, 651L);
+    final int rbcard = rb2.getCardinality();
+
+    // 648, 649, 651-131999
+
+    assertEquals(132000 - 651 + 2, rbcard);
+
+    final BitSet bs = new BitSet();
+    bs.set(648);
+    bs.set(649);
+    for (int i = 651; i < 132000; ++i) {
+      bs.set(i);
+    }
+    assertTrue(equals(bs, rb2));
+  }
+
+  @Test
+  public void flipTest8() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.add(0);
+    rb.add(2);
+    final RoaringBitmap rb2 = RoaringBitmap.flip(rb, 0L, 3L);
+
+    final BitSet bs = new BitSet();
+    bs.set(1);
+    assertTrue(equals(bs, rb2));
+  }
+
+  @Test
+  public void flipTestBigInt() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.add(Integer.MAX_VALUE + 100000);
+    rb.add(Integer.MAX_VALUE + 100002);
+    final RoaringBitmap rb2 =
+        RoaringBitmap.flip(rb, Integer.MAX_VALUE + 100001L, Integer.MAX_VALUE + 200000L);
+    assertEquals(99999, rb2.getCardinality());
+    assertTrue(rb2.contains(Integer.MAX_VALUE + 100000));
+    assertFalse(rb2.contains(Integer.MAX_VALUE + 100002));
+    assertTrue(rb2.contains(Integer.MAX_VALUE + 199999));
+  }
+
+  @Test
+  public void flipTestBig() {
+    final int numCases = 1000;
+    final RoaringBitmap rb = new RoaringBitmap();
+    final BitSet bs = new BitSet();
+    final Random r = new Random(3333);
+    int checkTime = 2;
+
+    for (int i = 0; i < numCases; ++i) {
+      final long start = r.nextInt(65536 * 20);
+      long end = r.nextInt(65536 * 20);
+      if (r.nextDouble() < 0.1) {
+        end = start + r.nextInt(100);
+      }
+      rb.flip(start, end);
+      if (start < end) {
+        bs.flip((int) start, (int) end); // throws exception
+      }
+      // otherwise
+      // insert some more ANDs to keep things sparser
+      if (r.nextDouble() < 0.2) {
+        final RoaringBitmap mask = new RoaringBitmap();
+        final BitSet mask1 = new BitSet();
+        final long startM = r.nextInt(65536 * 20);
+        final long endM = startM + 100000;
+        mask.flip(startM, endM);
+        mask1.flip((int) startM, (int) endM);
+        mask.flip(0L, 65536L * 20 + 100000);
+        mask1.flip(0, 65536 * 20 + 100000);
+        rb.and(mask);
+        bs.and(mask1);
+      }
+      // see if we can detect incorrectly shared containers
+      if (r.nextDouble() < 0.1) {
+        final RoaringBitmap irrelevant = RoaringBitmap.flip(rb, 10L, 100000L);
+        irrelevant.flip(5L, 200000L);
+        irrelevant.flip(190000L, 260000L);
+      }
+      if (i > checkTime) {
+        assertTrue(equals(bs, rb));
+        checkTime *= 1.5;
+      }
+    }
+  }
+
+  @Test
+  public void flipTestBigA() {
+    final int numCases = 1000;
+    final BitSet bs = new BitSet();
+    final Random r = new Random(3333);
+    int checkTime = 2;
+    RoaringBitmap rb1 = new RoaringBitmap(), rb2 = null; // alternate
+    // between
+    // them
+    for (int i = 0; i < numCases; ++i) {
+      final int start = r.nextInt(65536 * 20);
+      int end = r.nextInt(65536 * 20);
+      if (r.nextDouble() < 0.1) {
+        end = start + r.nextInt(100);
+      }
+
+      if ((i & 1) == 0) {
+        rb2 = RoaringBitmap.flip(rb1, (long) start, (long) end);
+        // tweak the other, catch bad sharing
+        long r1 = r.nextInt(65536 * 20);
+        long r2 = r.nextInt(65536 * 20);
+        rb1.flip(r1, r2);
+      } else {
+        rb1 = RoaringBitmap.flip(rb2, (long) start, (long) end);
+        long r1 = r.nextInt(65536 * 20);
+        long r2 = r.nextInt(65536 * 20);
+        rb2.flip(r1, r2);
+      }
+
+      if (start < end) {
+        bs.flip(start, end); // throws exception
+        // otherwise
+      }
+      // insert some more ANDs to keep things sparser
+      if (r.nextDouble() < 0.2 && (i & 1) == 0) {
+        final RoaringBitmap mask = new RoaringBitmap();
+        final BitSet mask1 = new BitSet();
+        final int startM = r.nextInt(65536 * 20);
+        final int endM = startM + 100000;
+        mask.flip((long) startM, (long) endM);
+        mask1.flip(startM, endM);
+        mask.flip(0L, 65536L * 20 + 100000);
+        mask1.flip(0, 65536 * 20 + 100000);
+        rb2.and(mask);
+        bs.and(mask1);
+      }
+      if (i > checkTime) {
+        final RoaringBitmap rb = (i & 1) == 0 ? rb2 : rb1;
+        final boolean status = equals(bs, rb);
+        assertTrue(status);
+        checkTime *= 1.5;
+      }
+    }
+  }
+
+  @Test
+  public void intersecttest() {
+    final RoaringBitmap rr1 = new RoaringBitmap();
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 0; k < 40000; ++k) {
+      rr1.add(2 * k);
+      rr2.add(2 * k + 1);
+    }
+    assertFalse(RoaringBitmap.intersects(rr1, rr2));
+    rr1.add(2 * 500 + 1);
+    assertTrue(RoaringBitmap.intersects(rr1, rr2));
+    final RoaringBitmap rr3 = new RoaringBitmap();
+    rr3.add(2 * 501 + 1);
+    assertTrue(RoaringBitmap.intersects(rr3, rr2));
+    assertFalse(RoaringBitmap.intersects(rr3, rr1));
+    for (int k = 0; k < 40000; ++k) {
+      rr1.add(2 * k + 1);
+    }
+    rr1.runOptimize();
+    assertTrue(RoaringBitmap.intersects(rr1, rr2));
+  }
+
+  @Test
+  public void intersecttestWithRange() {
+    RoaringBitmap rr1 = new RoaringBitmap();
+    RoaringBitmap rr2 = new RoaringBitmap();
+    RoaringBitmap rr3 = new RoaringBitmap();
+
+    // This bitmap containers will be Run Containers
+    rr1.add(1L, 4L);
+    rr1.add(6L, 10L);
+
+    // This one will be Array Containers
+    rr2.add(0);
+    rr2.add(2);
+
+    rr2.add(6);
+    rr2.add(7);
+    rr2.add(9);
+
+    assertFalse(rr1.intersects(0, 1));
+    assertTrue(rr1.intersects(0, 3));
+    assertTrue(rr1.intersects(0, 11));
+    assertFalse(rr1.intersects(12, 14));
+    assertFalse(rr1.intersects(4, 5));
+    assertTrue(rr1.intersects(2, 3));
+    assertTrue(rr1.intersects(4, 8));
+    assertTrue(rr1.intersects(8, 12));
+
+    assertTrue(rr2.intersects(0, 11));
+    assertFalse(rr2.intersects(12, 14));
+    assertFalse(rr2.intersects(4, 5));
+    assertTrue(rr2.intersects(2, 3));
+    assertTrue(rr2.intersects(4, 8));
+    assertTrue(rr2.intersects(8, 12));
+
+    rr3.add(5L, 10L);
+    assertTrue(rr3.intersects(5, 10));
+  }
+
+  @Test
+  public void shouldNotIntersectWithDisjointRangeBelowBitmapFirst() {
+    char[] keys = new char[1];
+    Container[] values = new Container[1];
+    RoaringBitmap bitmap = new RoaringBitmap(new RoaringArray(keys, values, 1));
+    keys[0] = (char) (1 << 15);
+    long[] bits = new long[1024];
+    long word = 1789303257167203747L;
+    Arrays.fill(bits, word);
+    values[0] = new BitmapContainer(bits, 1024 * Long.bitCount(word));
+    assertFalse(bitmap.intersects(0, bitmap.first() & 0xFFFFFFFFL));
+  }
+
+  @Test
+  public void shouldIntersectWithFirstWhenBitmapAtStart() {
+    char[] keys = new char[1];
+    Container[] values = new Container[1];
+    RoaringBitmap bitmap = new RoaringBitmap(new RoaringArray(keys, values, 1));
+    keys[0] = (char) (1 << 15);
+    long[] bits = new long[1024];
+    long word = 2697219678014362575L;
+    Arrays.fill(bits, word);
+    values[0] = new BitmapContainer(bits, 1024 * Long.bitCount(word));
+    long first = (bitmap.first() & 0xFFFFFFFFL);
+    assertTrue(bitmap.intersects(first - 1, first + 1));
+    assertTrue(bitmap.intersects(first, first + 1));
+    assertFalse(bitmap.intersects(first - 1, first));
+  }
+
+  @Test
+  public void orBigIntsTest() {
+    RoaringBitmap rb = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
+    HashSet hs = new HashSet();
+
+    for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) {
+      rb.add(i);
+      hs.add(i);
+    }
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) {
+      hs.add(i);
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 5) {
+      hs.add(i);
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 3) {
+      hs.add(i);
+      rb.add(i);
+    }
+
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 5) {
+      hs.add(i);
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 6 * 65536; i < (1 << 31) + 7 * 65536; i += 3) {
+      hs.add(i);
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 11 * 65536; i += 5) {
+      hs.add(i);
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 7) {
+      hs.add(i);
+      rb2.add(i);
+    }
+
+    RoaringBitmap rbor = RoaringBitmap.or(rb, rb2);
+
+    Object[] correct = hs.toArray();
+    Arrays.sort(correct);
+    Integer[] resor = ArrayUtils.toObject(rbor.toArray());
+    assertArrayEquals(correct, resor);
+  }
+
+  @Test
+  public void orcount() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+    }
+    rr.add(100000);
+    rr.add(110000);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr2.add(k);
+    }
+
+    final RoaringBitmap rror = RoaringBitmap.or(rr, rr2);
+    assertEquals(rror.getCardinality(), RoaringBitmap.orCardinality(rr, rr2));
+  }
+
+  @Test
+  public void testXorCardinality() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rb.add(k);
+    }
+    rb.add(100000);
+    rb.add(110000);
+    rb.add(1L << 20, 1L << 21);
+    rb.flip((1 << 20) | (1 << 19));
+    final RoaringBitmap rb2 = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rb2.add(k);
+    }
+    RoaringBitmap xor = RoaringBitmap.xor(rb, rb2);
+    assertEquals(xor.getCardinality(), RoaringBitmap.xorCardinality(rb, rb2));
+  }
+
+  @Test
+  public void testAndNotCardinality() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rb.add(k);
+    }
+    rb.add(100000);
+    rb.add(110000);
+    rb.add(1L << 20, 1L << 21);
+    rb.flip((1 << 20) | (1 << 19));
+    final RoaringBitmap rb2 = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rb2.add(k);
+    }
+    RoaringBitmap andNot = RoaringBitmap.andNot(rb, rb2);
+    assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(rb, rb2));
+  }
+
+  @Test
+  public void testAndNotCardinalityBigVsSmall() {
+    RoaringBitmap small = RoaringBitmap.bitmapOf(1, 2, 3);
+    RoaringBitmap big = new RoaringBitmap();
+    for (int i = 0; i < 4000; ++i) {
+      big.add(1 + i * 0x1000);
+    }
+    RoaringBitmap andNot = RoaringBitmap.andNot(big, small);
+    assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(big, small));
+  }
+
+  @Test
+  public void testAndNotCardinalitySmallVsBig() {
+    RoaringBitmap small = RoaringBitmap.bitmapOf(1, 2, 3);
+    RoaringBitmap big = new RoaringBitmap();
+    for (int i = 0; i < 4000; ++i) {
+      big.add(1 + i * 0x1000);
+    }
+    RoaringBitmap andNot = RoaringBitmap.andNot(small, big);
+    assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(small, big));
+  }
+
+  @Test
+  public void testAndNotCardinality_646() {
+    RoaringBitmap rb = RoaringBitmap.bitmapOf(-587409880, 605467000);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(-587409880, 347844183);
+
+    RoaringBitmap andNot = RoaringBitmap.andNot(rb, rb2);
+    assertEquals(andNot.getCardinality(), RoaringBitmap.andNotCardinality(rb, rb2));
+  }
+
+  @Test
+  public void testAndNotCardinality_648() {
+    RoaringBitmap s1 =
+        RoaringBitmap.bitmapOf(
+            -1388308580,
+            236217409,
+            -805382570,
+            612285977,
+            1389629939,
+            851442526,
+            375756307,
+            61533603,
+            1908301308,
+            2097309572,
+            204769050,
+            703198559,
+            -545810986,
+            2090296816,
+            -87319453,
+            158018332,
+            -685188145,
+            -566739002,
+            -1446363859,
+            -372441875,
+            -957637004,
+            -1144076256,
+            -1248859542,
+            -160225853,
+            14707613,
+            866274329,
+            1550526350,
+            877999004,
+            -1784269953,
+            1274953255,
+            1490490469,
+            -1340013077,
+            2067958239,
+            51232349,
+            2060711699,
+            -1802459974,
+            2039829040,
+            -2079650027,
+            -278950425,
+            1145674649,
+            298101576,
+            1687655442,
+            1209489632,
+            -762136131,
+            399832491,
+            1077638711,
+            -635674559,
+            -1643781464,
+            -1067907341,
+            144525399,
+            651571848,
+            1893053071,
+            -2058528151,
+            1592871441,
+            84583235,
+            374119809,
+            -867104416,
+            -1941224259,
+            787356209,
+            1972857336,
+            -720703901,
+            -1310021857,
+            -1831922816,
+            181898740,
+            600942551,
+            -1745822849,
+            -856908487,
+            2060184086,
+            -1217485514,
+            -1680395029,
+            1539735915,
+            2042390564,
+            -1539856946,
+            1824974207,
+            1695025297,
+            1908431629,
+            -395090370,
+            -1688185468,
+            570601902,
+            -701368853,
+            -1211735380,
+            -825285093,
+            788089714,
+            -857723909,
+            1400502194,
+            285106906,
+            -1450842998,
+            -2125215206,
+            1451519492,
+            -1559357910,
+            1157633452,
+            -387704829,
+            2036134025,
+            1051239778,
+            -1542956455,
+            357879569,
+            1962230155,
+            -1994777800,
+            672516512,
+            174507423,
+            -299175291,
+            821891018,
+            1062886766,
+            -1313955904,
+            1732661804,
+            -767116537,
+            1352149580,
+            2001322279,
+            1698147357,
+            40451458,
+            996819026,
+            1904959950,
+            2058544757,
+            1514282221,
+            234242255,
+            -1364505429,
+            1498471146,
+            1134429786,
+            -918860049,
+            1430732385,
+            644983298,
+            793600316,
+            -1726956640,
+            -538511147,
+            -1945670935,
+            291567421,
+            1033590420,
+            -1831809482,
+            985031287,
+            -773476240,
+            1724734191,
+            -1364525376,
+            1208307142,
+            -2126741265,
+            -1851759120,
+            1083333467,
+            185208087,
+            -375950074,
+            48210573,
+            -843304856,
+            -295266615,
+            -843941360,
+            -524390895,
+            -102924717,
+            836117637,
+            683196001,
+            -1824825594,
+            -1470017798,
+            -1554712054,
+            291236023,
+            -907874606,
+            2068945326,
+            -899352179,
+            -1488751007,
+            -449279886,
+            -1085935420,
+            -2094131785,
+            -474243782,
+            1306756671,
+            1353254318,
+            86944198,
+            1148225154,
+            487252515,
+            -229770314,
+            -1484325603,
+            109043190,
+            -252122045,
+            1431750974,
+            1667547537,
+            -1775516477,
+            -512978266,
+            -216545450,
+            -486550865,
+            -1193721685,
+            -1108677522,
+            -628326149,
+            -1568065979,
+            -675571394);
+    RoaringBitmap s2 =
+        RoaringBitmap.bitmapOf(
+            2060184086,
+            704452713,
+            1236293943,
+            -178539376,
+            2037977331,
+            -78910667,
+            -587409880,
+            204769050,
+            -854426111,
+            90628341,
+            -1411939301,
+            -927754519,
+            -211274987,
+            998450197,
+            -1515133464,
+            -1652963250,
+            499001553,
+            383696025,
+            -2019580769,
+            1583380373,
+            -79264832,
+            1065614902,
+            1243463658,
+            424214238,
+            1124141647,
+            271662535,
+            1415634429,
+            1893053071,
+            -1624960757,
+            -1933550809,
+            -1170233109,
+            -542340662,
+            -1681838238,
+            292656484,
+            1587781520,
+            -1463647396,
+            -124042559,
+            -162307067,
+            1411905814,
+            -1524651941,
+            1935844108,
+            1992426746,
+            422443777,
+            679395872,
+            -764857187,
+            -401706366,
+            -2007177999,
+            1044794027,
+            -1561188953,
+            1627034126,
+            -401273669,
+            -123973748,
+            -694963705,
+            838892817,
+            -1640102435,
+            852253834,
+            -23120023,
+            -2072644924,
+            1140820264,
+            -550227319,
+            -1692730465,
+            1491150291,
+            1607642920,
+            -1015774573,
+            -1801713682,
+            -752796152,
+            -439281693,
+            -792361100,
+            -188208805,
+            808883165,
+            -1364525376,
+            896915854,
+            -1672522244,
+            -1718572341);
+    RoaringBitmap s3 =
+        RoaringBitmap.bitmapOf(
+            -30718004,
+            -1652963250,
+            -762136131,
+            -1552606582,
+            -1933550809,
+            -1230616126,
+            736584428,
+            -2136360654,
+            1097548480,
+            192408815,
+            -295266615);
+    RoaringBitmap s1AndS2 = RoaringBitmap.and(s1, s2);
+    assertEquals(
+        RoaringBitmap.andNot(s1AndS2, s3).getCardinality(),
+        RoaringBitmap.andNotCardinality(s1AndS2, s3));
+  }
+
+  @Test
+  public void ortest() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+    }
+    rr.add(100000);
+    rr.add(110000);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr2.add(k);
+    }
+
+    final RoaringBitmap rror = RoaringBitmap.or(rr, rr2);
+
+    final int[] array = rror.toArray();
+    final int[] arrayrr = rr.toArray();
+
+    assertArrayEquals(array, arrayrr);
+
+    rr.or(rr2);
+    final int[] arrayirr = rr.toArray();
+    assertArrayEquals(array, arrayirr);
+  }
+
+  @Test
+  public void ORtest() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) {
+      rr.add(k);
+    }
+
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) {
+      rr2.add(k);
+    }
+    final RoaringBitmap correct = RoaringBitmap.or(rr, rr2);
+    rr.or(rr2);
+    assertEquals(correct, rr);
+  }
+
+  @Test
+  public void ortest2() {
+    final int[] arrayrr = new int[4000 + 4000 + 2];
+    int pos = 0;
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+      arrayrr[pos++] = k;
+    }
+    rr.add(100000);
+    rr.add(110000);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 4000; k < 8000; ++k) {
+      rr2.add(k);
+      arrayrr[pos++] = k;
+    }
+
+    arrayrr[pos++] = 100000;
+    arrayrr[pos++] = 110000;
+
+    final RoaringBitmap rror = RoaringBitmap.or(rr, rr2);
+
+    final int[] arrayor = rror.toArray();
+
+    assertArrayEquals(arrayor, arrayrr);
+  }
+
+  @Test
+  public void ortest3() {
+    final HashSet V1 = new HashSet();
+    final HashSet V2 = new HashSet();
+
+    final RoaringBitmap rr = new RoaringBitmap();
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    // For the first 65536: rr2 has a bitmap container, and rr has
+    // an array container.
+    // We will check the union between a BitmapCintainer and an
+    // arrayContainer
+    for (int k = 0; k < 4000; ++k) {
+      rr2.add(k);
+      V1.add(k);
+    }
+    for (int k = 3500; k < 4500; ++k) {
+      rr.add(k);
+      V1.add(k);
+    }
+    for (int k = 4000; k < 65000; ++k) {
+      rr2.add(k);
+      V1.add(k);
+    }
+
+    // In the second node of each roaring bitmap, we have two bitmap
+    // containers.
+    // So, we will check the union between two BitmapContainers
+    for (int k = 65536; k < 65536 + 10000; ++k) {
+      rr.add(k);
+      V1.add(k);
+    }
+
+    for (int k = 65536; k < 65536 + 14000; ++k) {
+      rr2.add(k);
+      V1.add(k);
+    }
+
+    // In the 3rd node of each Roaring Bitmap, we have an
+    // ArrayContainer, so, we will try the union between two
+    // ArrayContainers.
+    for (int k = 4 * 65535; k < 4 * 65535 + 1000; ++k) {
+      rr.add(k);
+      V1.add(k);
+    }
+
+    for (int k = 4 * 65535; k < 4 * 65535 + 800; ++k) {
+      rr2.add(k);
+      V1.add(k);
+    }
+
+    // For the rest, we will check if the union will take them in
+    // the result
+    for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) {
+      rr.add(k);
+      V1.add(k);
+    }
+
+    for (int k = 7 * 65535; k < 7 * 65535 + 2000; ++k) {
+      rr2.add(k);
+      V1.add(k);
+    }
+
+    final RoaringBitmap rror = RoaringBitmap.or(rr, rr2);
+    boolean valide = true;
+
+    // Si tous les elements de rror sont dans V1 et que tous les
+    // elements de
+    // V1 sont dans rror(V2)
+    // alors V1 == rror
+
+    final Object[] tab = V1.toArray();
+    final Vector vector = new Vector();
+    for (Object aTab : tab) {
+      vector.add((Integer) aTab);
+    }
+
+    for (final int i : rror.toArray()) {
+      if (!vector.contains(i)) {
+        valide = false;
+      }
+      V2.add(i);
+    }
+    for (int i = 0; i < V1.size(); i++) {
+      if (!V2.contains(vector.elementAt(i))) {
+        valide = false;
+      }
+    }
+
+    assertTrue(valide);
+  }
+
+  @Test
+  public void ortest4() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    for (int i = 0; i < 200000; i += 4) {
+      rb2.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 14) {
+      rb2.add(i);
+    }
+    final int rb2card = rb2.getCardinality();
+
+    // check or against an empty bitmap
+    final RoaringBitmap orresult = RoaringBitmap.or(rb, rb2);
+    final RoaringBitmap off = RoaringBitmap.or(rb2, rb);
+    assertEquals(orresult, off);
+
+    assertEquals(rb2card, orresult.getCardinality());
+
+    for (int i = 500000; i < 600000; i += 14) {
+      rb.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 3) {
+      rb2.add(i);
+    }
+    // check or against an empty bitmap
+    final RoaringBitmap orresult2 = RoaringBitmap.or(rb, rb2);
+    assertEquals(rb2card, orresult.getCardinality());
+
+    assertEquals(rb2.getCardinality() + rb.getCardinality(), orresult2.getCardinality());
+    rb.or(rb2);
+    assertEquals(rb, orresult2);
+  }
+
+  @Test
+  public void orNot() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    rb.add(2);
+    rb.add(1);
+    rb.add(1 << 16); // 65536
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
+
+    rb2.add(1 << 16); // 65536
+    rb2.add(3 << 16); // 196608
+
+    rb.orNot(rb2, (4 << 16) - 1);
+
+    assertEquals((4 << 16) - 1, rb.getCardinality());
+
+    final IntIterator iterator = rb.getIntIterator();
+
+    for (int i = 0; i < (4 << 16) - 1; ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next());
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNotRegressionTest() {
+    long len = 3L;
+    long orLen = 3L;
+
+    RoaringBitmap one = new RoaringBitmap();
+    RoaringBitmap other = new RoaringBitmap();
+    other.add(0L, len);
+
+    one.orNot(other, orLen);
+  }
+
+  @Test
+  public void orNotZeroRangeEndPreservesBitmap() {
+    RoaringBitmap one = new RoaringBitmap();
+    one.add(32);
+
+    RoaringBitmap other = new RoaringBitmap();
+    other.add(0L, 100);
+
+    one.orNot(other, 0);
+    assertEquals(one, RoaringBitmap.bitmapOf(32));
+  }
+
+  @Test
+  public void orNotLimitLowerThanFirstPreservesBitmap() {
+    RoaringBitmap one = new RoaringBitmap();
+    one.add(32);
+
+    RoaringBitmap other = new RoaringBitmap();
+    other.add(0L, 100);
+
+    one.orNot(other, 10);
+    assertEquals(one, RoaringBitmap.bitmapOf(32));
+  }
+
+  @Test
+  public void orNotLimitHigherThanFirstBitPreservesBitmap() {
+    RoaringBitmap one = new RoaringBitmap();
+    one.add(32);
+
+    RoaringBitmap other = new RoaringBitmap();
+    other.add(0L, 100);
+
+    one.orNot(other, 35);
+    assertEquals(one, RoaringBitmap.bitmapOf(32));
+  }
+
+  @Test
+  public void orNotWithSparseBitmaps() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    rb.add(0);
+    rb.add(1 << 16); // 65536
+    rb.add(3 << 16); // 196608
+
+    rb2.add((4 << 16) - 1); // 262143
+
+    rb.orNot(rb2, 4 << 16);
+
+    assertEquals((4 << 16) - 1, rb.getCardinality());
+
+    final IntIterator iterator = rb.getIntIterator();
+
+    for (int i = 0; i < (4 << 16) - 1; ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next());
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNotWithOtherBiggerThanOriginal() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.add(1);
+
+    final RoaringBitmap rb2 = new RoaringBitmap();
+    rb2.add(1 << 14); // 16384
+    rb2.add(3 << 16); // 196608
+
+    rb.orNot(rb2, (5 << 16));
+    assertEquals((5 << 16) - 2, rb.getCardinality());
+
+    final IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (5 << 16); ++i) {
+      if ((i != (1 << 14)) && (i != (3 << 16))) {
+        assertTrue(iterator.hasNext(), "Error on iteration " + i);
+        assertEquals(i, iterator.next(), "Error on iteration " + i);
+      }
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNotWithOtherBiggerThanOriginalAndEndRange() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.add(1);
+
+    final RoaringBitmap rb2 = new RoaringBitmap();
+    rb2.add(3 << 16); // 196608
+
+    rb.orNot(rb2, (2 << 16) + (2 << 14)); // 131072 + 32768 = 163840
+    assertEquals((2 << 16) + (2 << 14), rb.getCardinality());
+
+    final IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (2 << 16) + (2 << 14); ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next(), "Error on iteration " + i);
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNotWithOriginalBiggerThanOther() {
+    final RoaringBitmap rb = new RoaringBitmap();
+
+    rb.add(1);
+    rb.add(1 << 16); // 65536
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
+
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    rb.orNot(rb2, (5 << 16));
+    assertEquals((5 << 16), rb.getCardinality());
+
+    final IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (5 << 16); ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next(), "Error on iteration " + i);
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNotWithOriginalBiggerThanOther2() {
+    final RoaringBitmap rb = new RoaringBitmap();
+
+    rb.add(1);
+    rb.add((1 << 16) - 1); // 65535
+    rb.add(1 << 16); // 65536
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
+
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    rb.orNot(rb2, (1 << 14));
+
+    // {[0, 2^14], 65535, 65536, 131072, 196608}
+    assertEquals((1 << 14) + 4, rb.getCardinality());
+
+    final IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (1 << 14); ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next(), "Error on iteration " + i);
+    }
+
+    assertTrue(iterator.hasNext());
+    assertEquals((1 << 16) - 1, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(1 << 16, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(2 << 16, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(3 << 16, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void randomTest() {
+    rTest(15);
+    rTest(1024);
+    rTest(4096);
+    rTest(65536);
+    rTest(65536 * 16);
+  }
+
+  public void rTest(final int N) {
+    for (int gap = 1; gap <= 65536; gap *= 2) {
+      final BitSet bs1 = new BitSet();
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      for (int x = 0; x <= N; x += gap) {
+        bs1.set(x);
+        rb1.add(x);
+      }
+      if (bs1.cardinality() != rb1.getCardinality()) {
+        throw new RuntimeException("different card");
+      }
+      if (!equals(bs1, rb1)) {
+        throw new RuntimeException("basic  bug");
+      }
+      for (int offset = 1; offset <= gap; offset *= 2) {
+        final BitSet bs2 = new BitSet();
+        final RoaringBitmap rb2 = new RoaringBitmap();
+        for (int x = 0; x <= N; x += gap) {
+          bs2.set(x + offset);
+          rb2.add(x + offset);
+        }
+        if (bs2.cardinality() != rb2.getCardinality()) {
+          throw new RuntimeException("different card");
+        }
+        if (!equals(bs2, rb2)) {
+          throw new RuntimeException("basic  bug");
+        }
+
+        BitSet clonebs1;
+        // testing AND
+        clonebs1 = (BitSet) bs1.clone();
+        clonebs1.and(bs2);
+        if (!equals(clonebs1, RoaringBitmap.and(rb1, rb2))) {
+          throw new RuntimeException("bug and");
+        }
+        {
+          final RoaringBitmap t = rb1.clone();
+          t.and(rb2);
+          if (!equals(clonebs1, t)) {
+            throw new RuntimeException("bug inplace and");
+          }
+          if (!t.equals(RoaringBitmap.and(rb1, rb2))) {
+            System.out.println(
+                t.highLowContainer.getContainerAtIndex(0).getClass().getCanonicalName());
+            System.out.println(
+                RoaringBitmap.and(rb1, rb2)
+                    .highLowContainer
+                    .getContainerAtIndex(0)
+                    .getClass()
+                    .getCanonicalName());
+
+            throw new RuntimeException("bug inplace and");
+          }
+        }
+
+        // testing OR
+        clonebs1 = (BitSet) bs1.clone();
+        clonebs1.or(bs2);
+
+        if (!equals(clonebs1, RoaringBitmap.or(rb1, rb2))) {
+          throw new RuntimeException("bug or");
+        }
+        {
+          final RoaringBitmap t = rb1.clone();
+          t.or(rb2);
+          if (!equals(clonebs1, t)) {
+            throw new RuntimeException("bug or");
+          }
+          if (!t.equals(RoaringBitmap.or(rb1, rb2))) {
+            throw new RuntimeException("bug or");
+          }
+          if (!t.toString().equals(RoaringBitmap.or(rb1, rb2).toString())) {
+            throw new RuntimeException("bug or");
+          }
+        }
+        // testing XOR
+        clonebs1 = (BitSet) bs1.clone();
+        clonebs1.xor(bs2);
+        if (!equals(clonebs1, RoaringBitmap.xor(rb1, rb2))) {
+          throw new RuntimeException("bug xor");
+        }
+        {
+          final RoaringBitmap t = rb1.clone();
+          t.xor(rb2);
+          if (!equals(clonebs1, t)) {
+            throw new RuntimeException("bug xor");
+          }
+          if (!t.equals(RoaringBitmap.xor(rb1, rb2))) {
+            throw new RuntimeException("bug xor");
+          }
+        }
+        // testing NOTAND
+        clonebs1 = (BitSet) bs1.clone();
+        clonebs1.andNot(bs2);
+        if (!equals(clonebs1, RoaringBitmap.andNot(rb1, rb2))) {
+          throw new RuntimeException("bug andnot");
+        }
+        clonebs1 = (BitSet) bs2.clone();
+        clonebs1.andNot(bs1);
+        if (!equals(clonebs1, RoaringBitmap.andNot(rb2, rb1))) {
+          throw new RuntimeException("bug andnot");
+        }
+        {
+          final RoaringBitmap t = rb2.clone();
+          t.andNot(rb1);
+          if (!equals(clonebs1, t)) {
+            throw new RuntimeException("bug inplace andnot");
+          }
+          final RoaringBitmap g = RoaringBitmap.andNot(rb2, rb1);
+          if (!equals(clonebs1, g)) {
+            throw new RuntimeException("bug andnot");
+          }
+          if (!t.equals(g)) {
+            throw new RuntimeException("bug");
+          }
+        }
+        clonebs1 = (BitSet) bs1.clone();
+        clonebs1.andNot(bs2);
+        if (!equals(clonebs1, RoaringBitmap.andNot(rb1, rb2))) {
+          throw new RuntimeException("bug andnot");
+        }
+        {
+          final RoaringBitmap t = rb1.clone();
+          t.andNot(rb2);
+          if (!equals(clonebs1, t)) {
+            throw new RuntimeException("bug andnot");
+          }
+          final RoaringBitmap g = RoaringBitmap.andNot(rb1, rb2);
+          if (!equals(clonebs1, g)) {
+            throw new RuntimeException("bug andnot");
+          }
+          if (!t.equals(g)) {
+            throw new RuntimeException("bug");
+          }
+        }
+      }
+    }
+  }
+
+  @Test
+  public void sillytestHighBits() {
+    RoaringBitmap rb = RoaringBitmap.bitmapOf(-1, 0);
+    int[] array = rb.toArray();
+    assertEquals(0, array[0]);
+    assertEquals(array[1], -1);
+  }
+
+  @Test
+  public void simplecardinalityTest() {
+    final int N = 512;
+    final int gap = 70;
+
+    final RoaringBitmap rb = new RoaringBitmap();
+    for (int k = 0; k < N; k++) {
+      rb.add(k * gap);
+      assertEquals(rb.getCardinality(), k + 1);
+    }
+    assertEquals(rb.getCardinality(), N);
+    for (int k = 0; k < N; k++) {
+      rb.add(k * gap);
+      assertEquals(rb.getCardinality(), N);
+    }
+  }
+
+  @Test
+  public void sparseAnd() {
+    final RoaringBitmap rr1 = new RoaringBitmap();
+    rr1.add(1);
+    rr1.add(1 << 31);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    rr2.add(1 << 31);
+    RoaringBitmap and = RoaringBitmap.and(rr1, rr2);
+    assertEquals(1, and.getCardinality());
+    assertTrue(and.contains(1 << 31));
+    rr1.and(rr2);
+    assertEquals(1, rr1.getCardinality());
+    assertTrue(and.contains(1 << 31));
+  }
+
+  @Test
+  public void sparseAndNot() {
+    final RoaringBitmap rr1 = new RoaringBitmap();
+    rr1.add(1);
+    rr1.add(1 << 31);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    rr2.add(1 << 31);
+    RoaringBitmap andNot = RoaringBitmap.andNot(rr1, rr2);
+    assertEquals(1, andNot.getCardinality());
+    assertTrue(andNot.contains(1));
+    rr1.andNot(rr2);
+    assertEquals(1, rr1.getCardinality());
+    assertTrue(andNot.contains(1));
+  }
+
+  @Test
+  public void sparseOr() {
+    final RoaringBitmap rr1 = new RoaringBitmap();
+    rr1.add(1);
+    rr1.add(1 << 31);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    rr2.add(1 << 31);
+    RoaringBitmap or = RoaringBitmap.or(rr1, rr2);
+    assertEquals(2, or.getCardinality());
+    assertTrue(or.contains(1));
+    assertTrue(or.contains(1 << 31));
+    rr1.or(rr2);
+    assertEquals(2, rr1.getCardinality());
+    assertTrue(or.contains(1));
+    assertTrue(or.contains(1 << 31));
+  }
+
+  @Test
+  public void sparseXor() {
+    final RoaringBitmap rr1 = new RoaringBitmap();
+    rr1.add(1);
+    rr1.add(1 << 31);
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    rr2.add(1 << 31);
+    RoaringBitmap xor = RoaringBitmap.xor(rr1, rr2);
+    assertEquals(1, xor.getCardinality());
+    assertTrue(xor.contains(1));
+    rr1.xor(rr2);
+    assertEquals(1, rr1.getCardinality());
+    assertTrue(xor.contains(1));
+  }
+
+  @Test
+  public void testAndNot() {
+    int[] array1 = {
+      39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183, 39184, 39185,
+      39186, 39187, 39188
+    };
+    int[] array2 = {14205};
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(array1);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(array2);
+    RoaringBitmap answer = RoaringBitmap.andNot(rb1, rb2);
+    assertEquals(answer.getCardinality(), array1.length);
+  }
+
+  @Test
+  public void testAstesana() {
+    RoaringBitmap r1 = new RoaringBitmap();
+    // Strange thing: Replace this line by r1.add(131000) and the bug vanishes!
+    r1.flip(131000L, 131001L);
+    RoaringBitmap r2 = new RoaringBitmap();
+    r2.add(220000);
+    RoaringBitmap r3 = new RoaringBitmap();
+    int killingPosition = 66000;
+    r3.add(killingPosition);
+    assertFalse(r1.contains(killingPosition)); // ok
+    r2.or(r1);
+    assertFalse(r1.contains(killingPosition)); // ok
+    r2.or(r3);
+    assertFalse(r1.contains(killingPosition)); // ko
+  }
+
+  @Test
+  public void testCheckedAdd() {
+    RoaringBitmap rb = new RoaringBitmap();
+    // checking if the true value is well returned
+    // when adding new ints
+    for (int i = 0; i < 2 * (1 << 16); i += 2) {
+      assertTrue(rb.checkedAdd(i));
+    }
+    for (int i = 1; i < 2 * (1 << 16); i += 2) {
+      assertTrue(rb.checkedAdd(i));
+    }
+    // Checking if the false value is well returned
+    // when adding already existing ints
+    for (int i = 0; i < 2 * (1 << 16); i += 2) {
+      assertFalse(rb.checkedAdd(i));
+    }
+    for (int i = 1; i < 2 * (1 << 16) + 1; i += 2) {
+      assertFalse(rb.checkedAdd(i));
+    }
+  }
+
+  @Test
+  public void testCheckedRemove() {
+    RoaringBitmap rb = new RoaringBitmap();
+    // checking if the true value is well returned
+    // when adding new ints
+    for (int i = 0; i < 2 * (1 << 16); i++) {
+      rb.add(i);
+    }
+    for (int i = 0; i < 2 * (1 << 16); i += 2) {
+      assertTrue(rb.checkedRemove(i));
+    }
+    for (int i = 0; i < 2 * (1 << 16); i += 2) {
+      assertFalse(rb.checkedRemove(i));
+    }
+    for (int i = 1; i < 2 * (1 << 16); i += 2) {
+      assertTrue(rb.checkedRemove(i));
+    }
+    for (int i = 1; i < 2 * (1 << 16) + 1; i += 2) {
+      assertFalse(rb.checkedRemove(i));
+    }
+  }
+
+  @Test
+  public void testContains() throws IOException {
+    RoaringBitmap rbm1 = new RoaringBitmap();
+    for (int k = 0; k < 1000; ++k) {
+      rbm1.add(17 * k);
+    }
+    for (int k = 0; k < 17 * 1000; ++k) {
+      assertEquals(rbm1.contains(k), (k / 17 * 17 == k));
+    }
+  }
+
+  @Test
+  public void testEqual() {
+    RoaringBitmap rr1 = RoaringBitmap.bitmapOf(1, 2, 100000);
+    RoaringBitmap rr2 = RoaringBitmap.bitmapOf(3, 4, 100001);
+    RoaringBitmap rr3 = RoaringBitmap.bitmapOf(1, 2, 100000);
+    assertEquals(rr1, rr3);
+    assertNotEquals(rr1, rr2);
+    assertNotEquals(rr3, rr2);
+  }
+
+  // tests for how range falls on container boundaries
+
+  @Test
+  public void testFlip() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int i = 0; i < 1 << 20; ++i) {
+      rb.flip(i);
+      assertEquals(rb.getCardinality(), i + 1);
+    }
+    for (int i = (1 << 20) - 1; i >= 0; --i) {
+      rb.flip(i);
+      assertEquals(rb.getCardinality(), i);
+    }
+  }
+
+  @Test
+  public void testFlipBigInts() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int i = 0; i < 1 << 20; ++i) {
+      rb.flip((1 << 31) + i);
+      assertEquals(rb.getCardinality(), i + 1);
+    }
+    for (int i = (1 << 20) - 1; i >= 0; --i) {
+      rb.flip((1 << 31) + i);
+      assertEquals(rb.getCardinality(), i);
+    }
+  }
+
+  @Test
+  public void testFlipOnEmpty() {
+    RoaringBitmap r1 = new RoaringBitmap();
+    r1.flip(0L, 10L);
+    assertEquals(10, r1.getCardinality());
+  }
+
+  @Test
+  public void testHash() {
+    RoaringBitmap rbm1 = new RoaringBitmap();
+    rbm1.add(17);
+    RoaringBitmap rbm2 = new RoaringBitmap();
+    rbm2.add(17);
+    assertEquals(rbm1.hashCode(), rbm2.hashCode());
+    rbm2 = rbm1.clone();
+    assertEquals(rbm1.hashCode(), rbm2.hashCode());
+  }
+
+  @Test
+  public void testHighBits() {
+    for (int offset = 1 << 14; offset < 1 << 18; offset *= 2) {
+      RoaringBitmap rb = new RoaringBitmap();
+      for (long k = Integer.MIN_VALUE; k < Integer.MAX_VALUE; k += offset) {
+        rb.add((int) k);
+      }
+      int cardinality = 0;
+      for (long k = Integer.MIN_VALUE; k < Integer.MAX_VALUE; k += offset) {
+        assertTrue(rb.contains((int) k));
+        ++cardinality;
+      }
+      int[] array = rb.toArray();
+      assertEquals(array.length, cardinality);
+      for (int k = 0; k < array.length - 1; ++k) {
+        assertTrue((0xFFFFFFFFL & array[k]) <= (0xFFFFFFFFL & array[k + 1]));
+      }
+    }
+  }
+
+  @Test
+  public void testHorizontalOrCardinality() {
+    int[] vals = {65535, 131071, 196607, 262143, 327679, 393215, 458751, 524287};
+    final RoaringBitmap[] b = new RoaringBitmap[2];
+    b[0] = RoaringBitmap.bitmapOf(vals);
+    b[1] = RoaringBitmap.bitmapOf(vals);
+    RoaringBitmap a =
+        FastAggregation.or(
+            new Iterator() {
+              int k = 0;
+
+              @Override
+              public boolean hasNext() {
+                return k < b.length;
+              }
+
+              @Override
+              public RoaringBitmap next() {
+                return b[k++];
+              }
+
+              @Override
+              public void remove() {}
+            });
+    assertEquals(8, a.getCardinality());
+  }
+
+  @Test
+  public void testHorizontalOrCardinalityBigInts() {
+    int[] vals = {
+      (1 << 31) + 65535,
+      (1 << 31) + 131071,
+      (1 << 31) + 196607,
+      (1 << 31) + 262143,
+      (1 << 31) + 327679,
+      (1 << 31) + 393215,
+      (1 << 31) + 458751,
+      (1 << 31) + 524287
+    };
+    final RoaringBitmap[] b = new RoaringBitmap[2];
+    b[0] = RoaringBitmap.bitmapOf(vals);
+    b[1] = RoaringBitmap.bitmapOf(vals);
+    RoaringBitmap a =
+        FastAggregation.or(
+            new Iterator() {
+              int k = 0;
+
+              @Override
+              public boolean hasNext() {
+                return k < b.length;
+              }
+
+              @Override
+              public RoaringBitmap next() {
+                return b[k++];
+              }
+
+              @Override
+              public void remove() {}
+            });
+    assertEquals(8, a.getCardinality());
+  }
+
+  @Test
+  public void testIterator() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rb.add(k);
+    }
+    for (int k = 0; k < 1000; ++k) {
+      rb.add(k * 100);
+    }
+    RoaringBitmap copy1 = new RoaringBitmap();
+    for (int x : rb) {
+      copy1.add(x);
+    }
+    assertEquals(copy1, rb);
+    RoaringBitmap copy2 = new RoaringBitmap();
+    IntIterator i = rb.getIntIterator();
+    while (i.hasNext()) {
+      copy2.add(i.next());
+    }
+    assertEquals(copy2, rb);
+  }
+
+  @Test
+  public void testIteratorBigInts() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rb.add((1 << 31) + k);
+    }
+    for (int k = 0; k < 1000; ++k) {
+      rb.add((1 << 31) + k * 100);
+    }
+    RoaringBitmap copy1 = new RoaringBitmap();
+    for (int x : rb) {
+      copy1.add(x);
+    }
+    assertEquals(copy1, rb);
+    RoaringBitmap copy2 = new RoaringBitmap();
+    IntIterator i = rb.getIntIterator();
+    while (i.hasNext()) {
+      copy2.add(i.next());
+    }
+    assertEquals(copy2, rb);
+  }
+
+  @Test
+  public void testLimit() {
+    for (int gap = 1; gap <= 1024; gap *= 2) {
+      RoaringBitmap rb = new RoaringBitmap();
+      for (int k = 0; k < 100000; k += gap) {
+        rb.add(k);
+      }
+      int thiscard = rb.getCardinality();
+      for (int k = 0; k < thiscard; k += 100) {
+        RoaringBitmap limited = rb.limit(k);
+        assertEquals(limited.getCardinality(), k);
+      }
+      assertEquals(rb.limit(thiscard).getCardinality(), thiscard);
+      assertEquals(rb.limit(thiscard + 1).getCardinality(), thiscard);
+    }
+  }
+
+  @Test
+  public void testLimitBigInts() {
+    for (int gap = 1; gap <= 1024; gap *= 2) {
+      RoaringBitmap rb = new RoaringBitmap();
+      for (int k = 0; k < 100000; k += gap) {
+        rb.add((1 << 31) + k);
+      }
+      int thiscard = rb.getCardinality();
+      for (int k = 0; k < thiscard; k += 100) {
+        RoaringBitmap limited = rb.limit(k);
+        assertEquals(limited.getCardinality(), k);
+      }
+      assertEquals(rb.limit(thiscard).getCardinality(), thiscard);
+      assertEquals(rb.limit(thiscard + 1).getCardinality(), thiscard);
+    }
+  }
+
+  /**
+   * Test massive and.
+   */
+  @Test
+  public void testMassiveAnd() {
+    RoaringBitmap[] ewah = new RoaringBitmap[1024];
+    for (int k = 0; k < ewah.length; ++k) {
+      ewah[k] = new RoaringBitmap();
+    }
+    int howmany = 1000000;
+    for (int k = 0; k < howmany; ++k) {
+      ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k);
+    }
+    for (int k = 3; k < ewah.length; k += 3) {
+      ewah[k].flip(13L, (long) howmany / 2);
+    }
+    for (int N = 2; N < ewah.length; ++N) {
+      RoaringBitmap answer = ewah[0];
+      for (int k = 1; k < N; ++k) {
+        RoaringBitmap oldAnswer = answer;
+        answer = RoaringBitmap.and(oldAnswer, ewah[k]);
+        assertEquals(answer.getCardinality(), RoaringBitmap.andCardinality(oldAnswer, ewah[k]));
+      }
+      RoaringBitmap answer2 = FastAggregation.and(Arrays.copyOf(ewah, N));
+      assertEquals(answer, answer2);
+      RoaringBitmap answer2b = FastAggregation.and(toIterator(Arrays.copyOf(ewah, N)));
+      assertEquals(answer, answer2b);
+    }
+  }
+
+  @Test
+  public void testMassiveAndBigInts() {
+    RoaringBitmap[] ewah = new RoaringBitmap[1024];
+    for (int k = 0; k < ewah.length; ++k) {
+      ewah[k] = new RoaringBitmap();
+    }
+    int howmany = 1000000;
+    for (int k = 0; k < howmany; ++k) {
+      ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k);
+    }
+    for (int k = 3; k < ewah.length; k += 3) {
+      ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2);
+    }
+    for (int N = 2; N < ewah.length; ++N) {
+      RoaringBitmap answer = ewah[0];
+      for (int k = 1; k < N; ++k) {
+        RoaringBitmap oldAnswer = answer;
+        answer = RoaringBitmap.and(oldAnswer, ewah[k]);
+        assertEquals(answer.getCardinality(), RoaringBitmap.andCardinality(oldAnswer, ewah[k]));
+      }
+      RoaringBitmap answer2 = FastAggregation.and(Arrays.copyOf(ewah, N));
+      assertEquals(answer, answer2);
+      RoaringBitmap answer2b = FastAggregation.and(toIterator(Arrays.copyOf(ewah, N)));
+      assertEquals(answer, answer2b);
+    }
+  }
+
+  private static class ExtendedRoaringBitmap extends RoaringBitmap {}
+
+  /**
+   * Tests that the static #or operation works correctly with an iterator of
+   * RoaringBitmap extended classes.
+   */
+  @Test
+  public void testOrWithIterator() {
+    final RoaringBitmap b1 = new RoaringBitmap();
+    b1.add(13);
+    final RoaringBitmap b2 = new RoaringBitmap();
+    b2.add(42);
+
+    final RoaringBitmap result = RoaringBitmap.or(Arrays.asList(b1, b2).iterator());
+    assertTrue(result.contains(13));
+    assertTrue(result.contains(42));
+  }
+
+  /**
+   * Tests that the static #or operation works correctly with an iterator of
+   * RoaringBitmap extended classes.
+   */
+  @Test
+  public void testOrWithIteratorOfExtendedRoaringBitmaps() {
+    final ExtendedRoaringBitmap b1 = new ExtendedRoaringBitmap();
+    b1.add(1);
+    final ExtendedRoaringBitmap b2 = new ExtendedRoaringBitmap();
+    b2.add(2);
+
+    final RoaringBitmap result =
+        RoaringBitmap.or(Arrays.asList(b1, b2).iterator());
+    assertTrue(result.contains(1));
+    assertTrue(result.contains(2));
+  }
+
+  /**
+   * Test massive or.
+   */
+  @Test
+  public void testMassiveOr() {
+    final int N = 128;
+    for (int howmany = 512; howmany <= 1000000; howmany *= 2) {
+      RoaringBitmap[] ewah = new RoaringBitmap[N];
+      for (int k = 0; k < ewah.length; ++k) {
+        ewah[k] = new RoaringBitmap();
+      }
+      for (int k = 0; k < howmany; ++k) {
+        ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k);
+      }
+      for (int k = 3; k < ewah.length; k += 3) {
+        ewah[k].flip(13L, (long) howmany / 2);
+      }
+      RoaringBitmap answer = ewah[0];
+      for (int k = 1; k < ewah.length; ++k) {
+        answer = RoaringBitmap.or(answer, ewah[k]);
+      }
+      RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]);
+      RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]);
+      List rbl = new ArrayList<>();
+      rbl.add(rb1);
+      rbl.add(rb2);
+
+      ArrayList arrayList = new ArrayList<>();
+      arrayList.add(rb1);
+      arrayList.add(rb2);
+      Iterator rbi = arrayList.iterator();
+
+      RoaringBitmap rbor = RoaringBitmap.or(rb1, rb2);
+      RoaringBitmap answer2 = FastAggregation.or(ewah);
+      RoaringBitmap answer3 = FastAggregation.horizontal_or(ewah);
+      RoaringBitmap answer3b = FastAggregation.or(toIterator(ewah));
+      assertEquals(answer, answer2);
+      assertEquals(answer, answer3);
+      assertEquals(answer, answer3b);
+      assertEquals(rbor, FastAggregation.horizontal_or(rbl));
+      assertEquals(rbor, FastAggregation.priorityqueue_or(rb1, rb2));
+      assertEquals(rbor, FastAggregation.priorityqueue_or(rbi));
+    }
+  }
+
+  @Test
+  public void testMassiveOrBigInts() {
+    final int N = 128;
+    for (int howmany = 512; howmany <= 1000000; howmany *= 2) {
+      RoaringBitmap[] ewah = new RoaringBitmap[N];
+      for (int k = 0; k < ewah.length; ++k) {
+        ewah[k] = new RoaringBitmap();
+      }
+      for (int k = 0; k < howmany; ++k) {
+        ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k);
+      }
+      for (int k = 3; k < ewah.length; k += 3) {
+        ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2);
+      }
+      RoaringBitmap answer = ewah[0];
+      for (int k = 1; k < ewah.length; ++k) {
+        answer = RoaringBitmap.or(answer, ewah[k]);
+      }
+      RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]);
+      RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]);
+      List rbl = new ArrayList<>();
+      rbl.add(rb1);
+      rbl.add(rb2);
+
+      ArrayList arrayList = new ArrayList<>();
+      arrayList.add(rb1);
+      arrayList.add(rb2);
+      Iterator rbi = arrayList.iterator();
+
+      RoaringBitmap rbor = RoaringBitmap.or(rb1, rb2);
+      RoaringBitmap answer2 = FastAggregation.or(ewah);
+      RoaringBitmap answer3 = FastAggregation.horizontal_or(ewah);
+      RoaringBitmap answer3b = FastAggregation.or(toIterator(ewah));
+      assertEquals(answer, answer2);
+      assertEquals(answer, answer3);
+      assertEquals(answer, answer3b);
+      assertEquals(rbor, FastAggregation.horizontal_or(rbl));
+      assertEquals(rbor, FastAggregation.priorityqueue_or(rb1, rb2));
+      assertEquals(rbor, FastAggregation.priorityqueue_or(rbi));
+    }
+  }
+
+  /**
+   * Test massive xor.
+   */
+  @Test
+  public void testMassiveXOr() {
+    final int N = 128;
+    for (int howmany = 512; howmany <= 1000000; howmany *= 2) {
+      RoaringBitmap[] ewah = new RoaringBitmap[N];
+      for (int k = 0; k < ewah.length; ++k) {
+        ewah[k] = new RoaringBitmap();
+      }
+      for (int k = 0; k < howmany; ++k) {
+        ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k);
+      }
+      for (int k = 3; k < ewah.length; k += 3) {
+        ewah[k].flip(13L, (long) howmany / 2);
+      }
+
+      RoaringBitmap answer = ewah[0];
+      for (int k = 1; k < ewah.length; ++k) {
+        answer = RoaringBitmap.xor(answer, ewah[k]);
+      }
+      RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]);
+      RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]);
+      RoaringBitmap rxor = FastAggregation.xor(rb1, rb2);
+      RoaringBitmap answer2 = FastAggregation.xor(ewah);
+      RoaringBitmap answer3 = FastAggregation.horizontal_xor(ewah);
+      assertEquals(answer, answer2);
+      assertEquals(answer, answer3);
+      assertEquals(rxor, FastAggregation.priorityqueue_xor(rb1, rb2));
+    }
+  }
+
+  @Test
+  public void testMassiveXOrBigInts() {
+    final int N = 128;
+    for (int howmany = 512; howmany <= 1000000; howmany *= 2) {
+      RoaringBitmap[] ewah = new RoaringBitmap[N];
+      for (int k = 0; k < ewah.length; ++k) {
+        ewah[k] = new RoaringBitmap();
+      }
+      for (int k = 0; k < howmany; ++k) {
+        ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k);
+      }
+      for (int k = 3; k < ewah.length; k += 3) {
+        ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2);
+      }
+
+      RoaringBitmap answer = ewah[0];
+      for (int k = 1; k < ewah.length; ++k) {
+        answer = RoaringBitmap.xor(answer, ewah[k]);
+      }
+      RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]);
+      RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]);
+      RoaringBitmap rxor = FastAggregation.xor(rb1, rb2);
+      RoaringBitmap answer2 = FastAggregation.xor(ewah);
+      RoaringBitmap answer3 = FastAggregation.horizontal_xor(ewah);
+      assertEquals(answer, answer2);
+      assertEquals(answer, answer3);
+      assertEquals(rxor, FastAggregation.priorityqueue_xor(rb1, rb2));
+    }
+  }
+
+  @Test
+  public void testOr001() {
+    int[] array1 = {
+      22871, 22873, 22876, 22880, 22886, 22889, 22893, 22897, 22901, 22905, 22910, 22915, 22919,
+      22927, 22934, 22940, 24750, 38579, 48470, 50533, 53256, 53717, 53752, 53802, 53938, 54727,
+      54865, 55202, 55815, 55822, 55940, 56711, 56977, 57122, 59933, 60037, 60402, 60520, 60853,
+      61163, 61340, 61549, 61632, 62097, 62373, 62961, 62993, 63031, 63075, 64209, 64644, 64762,
+      64893, 64927, 64997, 65117, 65128, 65173, 65201, 65472, 65536, 65622, 66092, 66162, 66302,
+      66381, 66551, 103979, 104644, 106866, 117285, 123372, 127548, 132167, 132168, 136283, 136433,
+      137661, 138019, 138239, 138380, 138816, 138916, 138933, 139414, 140342, 140914, 142751,
+      142994, 143895, 145081, 147331, 147686, 148021, 148375, 148587, 149114, 149734, 152696,
+      153608, 154741, 154932, 155263, 157121, 158947, 159444, 161102, 161383, 162735, 164298,
+      168043, 169398, 169536, 170419, 170846, 171153, 177016, 177471, 178305, 178673, 183731,
+      183936, 184083, 184106, 185663, 188371, 189495, 189531, 196189, 198419, 198758, 198796,
+      200645, 201137, 216865, 216936, 217770, 217810, 217836, 217909, 218569, 218700, 218931,
+      219363, 220009, 225925, 234706, 241183, 241561, 242140, 242281, 245018, 245056, 249935,
+      250442, 250615, 251696, 252825, 254178, 256788, 256906, 257289, 258833, 260432, 260563,
+      260930, 262684, 262834, 263128, 265919, 268662, 269542, 270217, 271673, 273776, 274560,
+      275649, 305458, 306241, 306550, 307580, 310891, 312701, 313514, 318134, 319185, 320757,
+      321280, 322046, 322743, 323211, 324667, 325382, 326450, 327159, 328836, 329075, 331179,
+      332836, 332997, 333071, 333205, 333488, 333595, 335045, 335803, 336417, 336610, 338487,
+      339827, 339992, 346123, 348858, 351257, 351957, 353896, 354559, 357142, 358253, 366662,
+      378768, 391984, 392282, 415077, 429446, 429449, 429452, 429453, 429476, 429480, 429486,
+      429492, 429497, 429501, 429504, 429505, 429510, 429515, 429519, 429524, 429530, 429533,
+      429541, 429546, 429553, 429554, 429564, 429572, 429577, 429579, 429586, 429589, 429596,
+      429604, 429606, 429612, 429615, 429616, 429624, 429632, 429639, 429642, 429646, 429651,
+      429656, 429664, 429670, 429674, 429678, 429681, 429686, 429695, 429701, 429706, 429717,
+      429721, 429725, 429733, 429736, 429739, 429743, 429748, 429754, 429761, 429767, 429772,
+      429780, 429791, 429792, 429793, 429794, 429795, 429817, 429822, 429823, 429831, 429836,
+      429842, 429849, 429855, 429859, 429863, 429866, 429873, 429876, 429882, 429885, 429900,
+      429903, 429913, 429921, 429923, 429927, 429932, 429939, 429947, 429950, 429955, 429964,
+      429968, 429974, 429982, 429987, 429993, 429999, 430003, 430011, 430015, 430023, 430028,
+      430033, 430039, 430044, 430048, 430053, 430057, 430059, 430063, 430068, 430073, 430077,
+      430082, 430086, 430093, 430098, 430101, 430114, 430120, 430126, 430131, 430135, 430139,
+      430144, 430149, 430155, 430157, 430167, 430175, 430181, 430186, 430194, 430195, 430196,
+      430214, 430223, 430228, 430236, 430253, 430258, 430263, 430269, 430277, 430284, 430288,
+      430293, 430297, 430303, 430309, 430316, 430321, 430332, 430338, 430343, 430346, 430348,
+      430355, 430358, 430369, 430375, 430384, 430391, 430397, 430410, 430415, 430420, 430424,
+      430430, 430435, 430437, 430445, 430449, 430461, 430467, 430473, 430482, 430486, 430490,
+      430496, 430500, 430506, 430511, 430515, 430535, 430539, 430550, 430568, 430575, 430581,
+      430588, 430591, 430596, 430605, 430612, 430617, 430625, 430629, 430633, 430638, 430643,
+      430649, 430656, 430663, 430666, 430672, 430679, 430684, 430692, 430696, 430700, 430707,
+      430716, 430723, 430728, 430733, 430745, 430751, 430755, 430759, 430767, 430770, 430782,
+      430787, 430791, 430804, 430810, 430814, 430821, 430825, 430829, 430833, 430838, 430844,
+      430849, 430852, 430859, 430864, 430867, 430870, 430877, 430881, 430887, 430891, 430896,
+      430901, 430907, 430912, 430917, 430923, 430927, 430932, 430936, 430944, 430947, 430953,
+      430959, 430967, 430971, 430979, 430985, 430989, 430993, 430997, 431003, 431006, 431015,
+      431021, 431022, 431033, 431039, 431046, 431050, 431054, 431059, 431065, 431069, 431074,
+      431081, 431085, 431092, 431097, 431104, 431110, 431120, 431125, 431133, 431138, 431142,
+      431147, 431157, 431164, 431171, 431175, 431180, 431186, 431190, 431195, 431207, 431213,
+      431218, 431220, 431224, 431228, 431233, 431235, 431240, 431245, 431251, 431259, 431264,
+      431271, 431272, 431280, 431287, 431294, 431299, 431307, 431315, 431319, 431324, 431330,
+      431334, 431339, 431345, 431352, 431356, 431363, 431375, 431379, 431383, 431388, 431393,
+      431398, 431405, 431409, 431416, 431422, 431426, 431433, 431438, 431444, 431451, 431455,
+      431464, 431469, 431472, 431477, 431483, 431490, 431496, 431506, 431513, 431516, 431521,
+      431526, 431534, 431536, 431545, 431550, 431559, 431564, 431571, 431573, 431579, 431584,
+      431587, 431592, 431604, 431614, 431624, 431629, 431634, 431638, 431645, 431651, 431659,
+      431663, 431674, 431678, 431684, 431692, 431696, 431700, 431706, 431712, 431719, 431723,
+      431729, 431736, 431741, 431747, 431755, 431758, 431762, 431767, 431777, 431782, 431787,
+      431791, 431796, 431799, 431805, 431809, 431814, 431819, 431823, 431828, 431832, 431838,
+      431842, 431849, 431853, 431858, 431862, 431866, 431869, 431874, 431881, 431887, 431894,
+      431900, 431906, 431912, 431917, 431925, 431931, 431936, 431943, 431948, 431956, 431958,
+      431964, 431971, 431976, 431981, 431988, 431994, 431998, 432008, 432012, 432024, 432029,
+      432033, 432038, 432045, 432048, 432058, 432062, 432066, 432070, 432076, 432077, 432087,
+      432093, 432098, 432104, 432114, 432123, 432128, 432133, 432139, 432145, 432151, 432161,
+      432168, 432177, 432181, 432188, 432189, 432203, 432209, 432216, 432222, 432227, 432232,
+      432242, 432247, 432256, 432259, 432264, 432269, 432271, 432277, 432286, 432294, 432297,
+      432302, 432308, 432313, 432319, 432326, 432331, 432337, 432345, 432349, 432353, 432356,
+      432361, 432366, 432370, 432378, 432384, 432390, 432391, 432397, 432400, 432403, 432408,
+      432413, 432419, 432422, 432427, 432433, 432440, 432443, 432450, 432455, 432460, 432466,
+      432467, 432481, 432489, 432493, 432498, 432504, 432511, 432513, 432517, 432525, 432531,
+      432537, 432544, 432546, 432555, 432561, 432565, 432569, 432574, 432579, 432586, 432590,
+      432597, 432605, 432611, 432619, 432626, 432630, 432637, 432644, 432646, 432653, 432654,
+      432664, 432670, 432674, 432679, 432682, 432687, 432694, 432706, 432711, 432714, 432721,
+      432726, 432732, 432741, 432747, 432753, 432755, 432761, 432764, 432768, 432774, 432779,
+      432784, 432792, 432798, 432801, 432808, 432815, 432823, 432825, 432833, 432838, 432842,
+      432847, 432853, 432861, 432866, 432873, 432879, 432889, 432895, 432901, 432906, 432913,
+      432917, 432920, 432926, 432935, 432940, 432949, 432953, 432958, 432960, 432966, 432967,
+      432968, 432969, 432970, 432971, 432972, 432996, 432999, 433004, 433010, 433020, 433026,
+      433029, 433033, 433042, 433045, 433050, 433054, 433058, 433062, 433065, 433070, 433076,
+      433086, 433095, 433101, 433102, 433116, 433122, 433129, 433132, 433140, 433146, 433151,
+      433157, 433163, 433169, 433176, 433181, 433188, 433198, 433204, 433219, 433229, 433236,
+      433240, 433246, 433250, 433259, 433263, 433274, 433277, 433282, 433286, 433291, 433295,
+      433299, 433306, 433316, 433318, 433322, 433327, 433335, 433342, 433348, 433351, 433359,
+      433362, 433367, 433371, 433377, 433384, 433393, 433398, 433403, 433407, 433411, 433425,
+      433430, 433437, 433441, 433445, 433452, 433453, 433458, 433462, 433469, 433473, 433478,
+      433484, 433490, 433495, 433501, 433506, 433514, 433517, 433521, 433527, 433534, 433544,
+      433549, 433552, 433561, 433565, 433569, 433576, 433585, 433589, 433594, 433597, 433600,
+      433603, 433606, 433613, 433619, 433623, 433627, 433639, 433643, 433648, 433654, 433658,
+      433665, 433673, 433678, 433681, 433689, 433696, 433704, 433709, 433716, 433721, 433725,
+      433729, 433734, 433738, 433744, 433749, 433755, 433760, 433766, 433771, 433776, 433781,
+      433785, 433790, 433798, 433803, 433810, 433814, 433817, 433822, 433828, 433833, 433837,
+      433843, 433849, 433852, 433858, 433863, 433871, 433875, 433881, 433883, 433884, 433897,
+      433903, 433909, 433913, 433921, 433926, 433932, 433936, 433942, 433946, 433951, 433959,
+      433965, 433976, 433981, 433989, 433996, 434004, 434011, 434013, 434019, 434023, 434029,
+      434036, 434041, 434048, 434050, 434056, 434060, 434068, 434074, 434079, 434085, 434091,
+      434096, 434100, 434105, 434110, 434119, 434123, 434129, 434133, 434139, 434146, 434150,
+      434156, 434161, 434168, 434173, 434183, 434188, 434193, 434200, 434208, 434213, 434219,
+      434223, 434229, 434235, 434241, 434247, 434258, 434262, 434269, 434275, 434282, 434287,
+      434291, 434296, 434303, 434308, 434313, 434316, 434323, 434327, 434335, 434342, 434349,
+      434353, 434360, 434366, 434372, 434373, 434381, 434387, 434392, 434397, 434401, 434403,
+      434409, 434414, 434420, 434427, 434433, 434440, 434445, 434449, 434454, 434460, 434467,
+      434473, 434479, 434481, 434490, 434494, 434501, 434505, 434510, 434517, 434526, 434537,
+      434542, 434548, 434553, 434558, 434563, 434569, 434574, 434580, 434586, 434588, 434595,
+      434603, 434606, 434617, 434620, 434626, 434630, 434638, 434644, 434647, 434651, 434658,
+      434666, 434671, 434679, 434681, 434685, 434692, 434699, 434703, 434708, 434713, 434720,
+      434723, 434729, 434734, 434738, 434742, 434746, 434753, 434762, 434766, 434773, 434781,
+      434790, 434799, 434805, 434810, 434814, 434823, 434831, 434839, 434845, 434850, 434856,
+      434859, 434863, 434869, 434870, 434882, 434890, 434896, 434899, 434906, 434912, 434917,
+      434921, 434930, 434935, 434940, 434945, 434949, 434956, 434961, 434967, 434977, 434982,
+      434987, 434992, 434995, 435002, 435005, 435009, 435016, 435021, 435025, 435028, 435034,
+      435041, 435050, 435055, 435065, 435069, 435075, 435078, 435083, 435091, 435097, 435102,
+      435105, 435107, 435113, 435118, 435124, 435131, 435141, 435144, 435150, 435154, 435159,
+      435167, 435171, 435177, 435181, 435187, 435192, 435198, 435204, 435211, 435212, 435221,
+      435228, 435231, 435237, 435244, 435246, 435254, 435258, 435264, 435275, 435283, 435289,
+      435301, 435304, 435312, 435318, 435323, 435329, 435334, 435340, 435343, 435347, 435351,
+      435358, 435363, 435368, 435375, 435382, 435388, 435391, 435396, 435399, 435405, 435412,
+      435416, 435422, 435425, 435429, 435437, 435444, 435447, 435453, 435458, 435470, 435477,
+      435486, 435491, 435497, 435500, 435511, 435516, 435520, 435526, 435533, 435539, 435545,
+      435551, 435559, 435564, 435569, 435575, 435579, 435585, 435590, 435597, 435599, 435600,
+      435610, 435616, 435618, 435623, 435628, 435636, 435643, 435649, 435654, 435659, 435663,
+      435671, 435675, 435678, 435683, 435689, 435702, 435705, 435712, 435718, 435749, 435755,
+      435759, 435764, 435771, 435775, 435780, 435785, 435791, 435794, 435802, 435811, 435816,
+      435822, 435828, 435833, 435838, 435844, 435851, 435859, 435861, 435866, 435869, 435876,
+      435882, 435890, 435897, 435900, 435908, 435913, 435923, 435929, 435934, 435937, 435942,
+      435945, 435951, 435953, 435959, 435965, 435969, 435975, 435982, 435987, 435992, 436000,
+      436008, 436013, 436017, 436022, 436027, 436033, 436038, 436043, 436048, 436052, 436062,
+      436065, 436069, 436073, 436079, 436088, 436092, 436100, 436106, 436116, 436123, 436127,
+      436133, 436139, 436147, 436153, 436159, 436165, 436172, 436179, 436184, 436190, 436194,
+      436199, 436206, 436210, 436211, 436217, 436223, 436229, 436234, 436240, 436245, 436253,
+      436258, 436262, 436268, 436273, 436282, 436287, 436294, 436303, 436306, 436313, 436316,
+      436321, 436329, 436337, 436341, 436349, 436353, 436358, 436365, 436368, 436373, 436378,
+      436387, 436391, 436396, 436401, 436408, 436412, 436420, 436423, 436428, 436435, 436441,
+      436447, 436451, 436461, 436463, 436467, 436471, 436477, 436479, 436485, 436489, 436494,
+      436502, 436509, 436512, 436518, 436529, 436538, 436543, 436552, 436553, 436560, 436564,
+      436569, 436575, 436580, 436585, 436591, 436597, 436603, 436605, 436610, 436616, 436619,
+      436628, 436633, 436637, 436640, 436644, 436649, 436653, 436659, 436666, 436674, 436681,
+      436687, 436694, 436700, 436703, 436710, 436720, 436723, 436730, 436735, 436742, 436748,
+      436756, 436761, 436766, 436772, 436778, 436783, 436787, 436792, 436799, 436808, 436810,
+      436812, 436817, 436823, 436832, 436838, 436845, 436849, 436853, 436859, 436865, 436872,
+      436878, 436882, 436885, 436891, 436898, 436903, 436910, 436911, 436922, 436928, 436932,
+      436939, 436942, 436948, 436950, 436956, 436963, 436968, 436975, 436984, 436988, 436994,
+      437003, 437009, 437013, 437020, 437023, 437028, 437033, 437043, 437053, 437058, 437063,
+      437073, 437076, 437079, 437089, 437093, 437095, 437101, 437111, 437119, 437121, 437127,
+      437135, 437140, 437147, 437151, 437155, 437160, 437165, 437171, 437173, 437180, 437186,
+      437194, 437199, 437205, 437213, 437217, 437223, 437227, 437231, 437243, 437250, 437256,
+      437261, 437267, 437271, 437277, 437284, 437289, 437295, 437300, 437304, 437312, 437322,
+      437326, 437333, 437338, 437354, 437357, 437362, 437366, 437370, 437374, 437380, 437386,
+      437391, 437395, 437399, 437404, 437412, 437416, 437419, 437427, 437432, 437433, 437451,
+      437456, 437461, 437467, 437468, 437477, 437485, 437492, 437495, 437501, 437502, 437506,
+      437513, 437524, 437526, 437539, 437544, 437552, 437558, 437562, 437568, 437573, 437578,
+      437587, 437592, 437596, 437600, 437605, 437610, 437619, 437625, 437630, 437631, 437639,
+      437647, 437648, 437655, 437661, 437667, 437672, 437676, 437680, 437687, 437689, 437693,
+      437697, 437704, 437707, 437716, 437723, 437730, 437737, 437740, 437741, 437757, 437763,
+      437771, 437778, 437784, 437789, 437793, 437800, 437804, 437811, 437812, 437819, 437823,
+      437827, 437833, 437841, 437844, 437853, 437857, 437861, 437866, 437874, 437881, 437886,
+      437892, 437901, 437902, 437909, 437914, 437922, 437928, 437934, 437939, 437948, 437951,
+      437957, 437963, 437965, 437971, 437980, 437985, 437990, 437996, 438002, 438008, 438013,
+      438017, 438025, 438030, 438036, 438041, 438052, 438060, 438065, 438072, 438073, 438079,
+      438084, 438091, 438097, 438099, 438107, 438111, 438119, 438125, 438136, 438144, 438148,
+      438153, 438158, 438164, 438166, 438173, 438176, 438183, 438184, 438192, 438198, 438204,
+      438209, 438216, 438228, 438231, 438237, 438243, 438248, 438257, 438267, 438269, 438274,
+      438282, 438287, 438295, 438301, 438306, 438313, 438318, 438323, 438328, 438335, 438339,
+      438346, 438352, 438357, 438363, 438370, 438374, 438380, 438384, 438388, 438394, 438399,
+      438404, 438409, 438413, 438422, 438428, 438436, 438439, 438444, 438453, 438461, 438471,
+      438477, 438483, 438491, 438503, 438505, 438511, 438518, 438527, 438531, 438541, 438546,
+      438552, 438556, 438562, 438566, 438570, 438580, 438585, 438593, 438595, 438603, 438605,
+      438607, 438614, 438619, 438626, 438631, 438634, 438641, 438646, 438652, 438657, 438663,
+      438664, 438665, 438673, 438677, 438682, 438692, 438700, 438706, 438708, 438715, 438723,
+      438727, 438737, 438742, 438753, 438760, 438764, 438771, 438775, 438780, 438783, 438789,
+      438797, 438806, 438810, 438815, 438832, 438837, 438841, 438845, 438852, 438860, 438865,
+      438873, 438883, 438884, 438896, 438908, 438912, 438920, 438924, 438927, 438934, 438936,
+      438940, 438946, 438953, 438961, 438968, 438976, 438980, 438985, 438994, 439006, 439011,
+      439017, 439021, 439027, 439032, 439036, 439043, 439047, 439055, 439059, 439065, 439070,
+      439075, 439083, 439087, 439093, 439099, 439104, 439109, 439114, 439120, 439123, 439128,
+      439130, 439134, 439139, 439147, 439157, 439162, 439167, 439172, 439178, 439183, 439187,
+      439194, 439201, 439205, 439210, 439216, 439222, 439225, 439231, 439235, 439245, 439251,
+      439255, 439261, 439277, 439282, 439288, 439295, 439302, 439308, 439309, 439314, 439320,
+      439328, 439332, 439339, 439345, 439350, 439354, 439359, 439365, 439372, 439377, 439379,
+      439386, 439391, 439404, 439410, 439416, 439419, 439425, 439430, 439434, 439438, 439455,
+      439461, 439465, 439472, 439476, 439482, 439488, 439493, 439496, 439506, 439510, 439516,
+      439521, 439527, 439536, 439543, 439551, 439554, 439557, 439564, 439569, 439574, 439577,
+      439584, 439588, 439593, 439597, 439602, 439607, 439613, 439618, 439624, 439625, 439633,
+      439638, 439641, 439645, 439650, 439655, 439659, 439669, 439670, 439671, 439682, 439692,
+      439696, 439701, 439709, 439718, 439725, 439730, 439733, 439739, 439745, 439757, 439764,
+      439768, 439771, 439778, 439783, 439788, 439796, 439805, 439811, 439815, 439820, 439827,
+      439830, 439840, 439846, 439850, 439854, 439865, 439873, 439879, 439886, 439891, 439898,
+      439903, 439909, 439917, 439925, 439928, 439933, 439938, 439944, 439948, 439955, 439959,
+      439965, 439969, 439974, 439988, 439989, 440005, 440008, 440011, 440015, 440020, 440026,
+      440030, 440035, 440043, 440044, 440055, 440060, 440078, 440091, 440096, 440101, 440106,
+      440111, 440116, 440120, 440134, 440139, 440143, 440149, 440157, 440163, 440167, 440171,
+      440179, 440187, 440191, 440196, 440201, 440207, 440213, 440218, 440223, 440228, 440233,
+      440239, 440244, 440249, 440256, 440262, 440268, 440274, 440277, 440282, 440289, 440295,
+      440307, 440311, 440315, 440321, 440327, 440331, 440336, 440341, 440346, 440355, 440361,
+      440368, 440375, 440379, 440388, 440394, 440399, 440402, 440410, 440413, 440421, 440427,
+      440431, 440435, 440440, 440446, 440454, 440461, 440467, 440476, 440481, 440486, 440490,
+      440495, 440500, 440506, 440512, 440523, 440529, 440533, 440539, 440546, 440552, 440560,
+      440568, 440578, 440584, 440590, 440594, 440598, 440606, 440612, 440620, 440623, 440629,
+      440634, 440641, 440647, 440651, 440655, 440663, 440669, 440674, 440682, 440689, 440694,
+      440698, 440702, 440706, 440713, 440719, 440727, 440733, 440737, 440743, 440747, 440753,
+      440760, 440767, 440772, 440779, 440783, 440789, 440792, 440798, 440806, 440808, 440812,
+      440819, 440823, 440826, 440830, 440835, 440840, 440845, 440853, 440856, 440861, 440867,
+      440872, 440876, 440882, 440888, 440893, 440903, 440910, 440915, 440921, 440927, 440933,
+      440938, 440945, 440950, 440958, 440966, 440969, 440973, 440977, 440983, 440987, 440992,
+      440996, 441005, 441008, 441013, 441028, 441035, 441042, 441047, 441052, 441056, 441061,
+      441068, 441075, 441080, 441087, 441094, 441097, 441106, 441111, 441115, 441121, 441125,
+      441132, 441136, 441143, 441150, 441157, 441161, 441167, 441171, 441175, 441179, 441185,
+      441193, 441196, 441200, 441204, 441210, 441216, 441223, 441226, 441234, 441238, 441243,
+      441253, 441260, 441268, 441276, 441287, 441294, 441297, 441306, 441313, 441315, 441323,
+      441332, 441339, 441346, 441353, 441358, 441362, 441368, 441373, 441378, 441382, 441390,
+      441394, 441399, 441404, 441411, 441416, 441420, 441427, 441432, 441440, 441445, 441448,
+      441453, 441456, 441461, 441467, 441473, 441479, 441484, 441491, 441497, 441506, 441509,
+      441515, 441521, 441526, 441531, 441535, 441542, 441547, 441551, 441555, 441559, 441565,
+      441569, 441574, 441579, 441596, 441599, 441605, 441610, 441617, 441619, 441623, 441628,
+      441630, 441636, 441637, 441651, 441652, 441662, 441664, 441667, 441671, 441681, 441684,
+      441689, 441693, 441701, 441705, 441710, 441718, 441720, 441726, 441740, 441746, 441757,
+      441759, 441766, 441773, 441775, 441780, 441793, 441794, 441799, 441807, 441817, 441822,
+      441828, 441831, 441834, 441838, 441845, 441853, 441857, 441863, 441866, 441872, 441880,
+      441883, 441886, 441891, 441895, 441900, 441910, 441915, 441921, 441928, 441934, 441939,
+      441945, 441947, 441952, 441957, 441964, 441971, 441974, 441980, 441985, 441990, 441994,
+      441998, 442002, 442007, 442010, 442017, 442019, 442027, 442043, 442046, 442054, 442060,
+      442067, 442074, 442076, 442081, 442086, 442093, 442099, 442103, 442108, 442112, 442120,
+      442131, 442135, 442139, 442144, 442148, 442156, 442161, 442165, 442170, 442181, 442186,
+      442192, 442197, 442203, 442220, 442226, 442233, 442239, 442245, 442249, 442254, 442259,
+      442267, 442275, 442281, 442284, 442287, 442292, 442299, 442308, 442314, 442318, 442325,
+      442332, 442333, 442334, 442346, 442351, 442354, 442358, 442364, 442370, 442372, 442377,
+      442381, 442389, 442397, 442402, 442409, 442415, 442419, 442424, 442430, 442438, 442443,
+      442451, 442459, 442470, 442473, 442482, 442490, 442496, 442501, 442506, 442514, 442520,
+      442524, 442530, 442534, 442541, 442546, 442549, 442554, 442558, 442563, 442573, 442586,
+      442591, 442595, 442600, 442607, 442613, 442618, 442624, 442628, 442632, 442640, 442647,
+      442651, 442657, 442666, 442674, 442679, 442682, 442686, 442692, 442699, 442705, 442714,
+      442718, 442722, 442729, 442734, 442739, 442748, 442751, 442754, 442757, 442765, 442770,
+      442778, 442783, 442792, 442798, 442802, 442813, 442820, 442829, 442833, 442841, 442845,
+      442851, 442857, 442860, 442865, 442871, 442877, 442882, 442886, 442892, 442898, 442904,
+      442906, 442911, 442915, 442922, 442929, 442934, 442940, 442944, 442946, 442952, 442956,
+      442963, 442971, 442973, 442979, 442985, 442997, 443001, 443006, 443017, 443019, 443024,
+      443027, 443036, 443046, 443050, 443057, 443066, 443069, 443078, 443083, 443089, 443093,
+      443100, 443104, 443109, 443118, 443126, 443134, 443141, 443146, 443151, 443158, 443164,
+      443169, 443174, 443179, 443182, 443189, 443195, 443198, 443206, 443211, 443213, 443214,
+      443222, 443224, 443228, 443235, 443240, 443246, 443255, 443259, 443269, 443270, 443277,
+      443285, 443291, 443299, 443303, 443311, 443313, 443319, 443322, 443328, 443338, 443342,
+      443350, 443351, 443356, 443362, 443365, 443368, 443371, 443375, 443378, 443384, 443388,
+      443391, 443397, 443404, 443412, 443416, 443421, 443424, 443428, 443433, 443438, 443442,
+      443449, 443462, 443463, 443470, 443474, 443482, 443490, 443495, 443499, 443506, 443519,
+      443523, 443527, 443533, 443540, 443548, 443550, 443556, 443559, 443564, 443568, 443574,
+      443582, 443589, 443594, 443596, 443602, 443610, 443612, 443616, 443620, 443625, 443631,
+      443638, 443643, 443649, 443656, 443660, 443669, 443672, 443680, 443691, 443695, 443699,
+      443706, 443710, 443714, 443718, 443721, 443726, 443734, 443739, 443745, 443752, 443758,
+      443765, 443771, 443774, 443781, 443786, 443789, 443793, 443797, 443802, 443811, 443812,
+      443820, 443829, 443832, 443838, 443847, 443851, 443856, 443857, 443864, 443871, 443877,
+      443886, 443892, 443896, 443903, 443909, 443913, 443920, 443925, 443930, 443935, 443942,
+      443946, 443954, 443963, 443966, 443969, 443975, 443979, 443982, 443988, 443996, 443999,
+      444003, 444007, 444012, 444019, 444026, 444030, 444040, 444049, 444056, 444060, 444064,
+      444069, 444073, 444075, 444078, 444083, 444091, 444098, 444103, 444111, 444121, 444124,
+      444130, 444136, 444140, 444145, 444150, 444156, 444162, 444168, 444172, 444179, 444182,
+      444186, 444189, 444193, 444198, 444203, 444208, 444212, 444218, 444225, 444231, 444234,
+      444240, 444246, 444258, 444265, 444273, 444277, 444281, 444288, 444292, 444298, 444301,
+      444309, 444314, 444319, 444327, 444332, 444338, 444349, 444354, 444359, 444364, 444374,
+      444377, 444381, 444386, 444388, 444394, 444401, 444406, 444417, 444422, 444429, 444438,
+      444439, 444448, 444449, 444456, 444461, 444467, 444473, 444480, 444486, 444490, 444495,
+      444500, 444503, 444508, 444514, 444518, 444525, 444528, 444535, 444540, 444544, 444550,
+      444556, 444563, 444570, 444576, 444580, 444583, 444587, 444591, 444599, 444605, 444608,
+      444612, 444619, 444629, 444635, 444643, 444646, 444652, 444660, 444671, 444676, 444681,
+      444686, 444690, 444696, 444703, 444710, 444711, 444720, 444723, 444734, 444742, 444752,
+      444758, 444763, 444767, 444770, 444774, 444786, 444789, 444794, 444800, 444809, 444818,
+      444822, 444830, 444836, 444841, 444846, 444853, 444859, 444866, 444873, 444878, 444885,
+      444890, 444896, 444904, 444907, 444914, 444922, 444924, 444931, 446357, 488475, 495304,
+      496119, 497438, 498593, 498603, 498917, 499048, 499713, 500776, 501348, 503424, 508844,
+      518359, 519305, 519446, 523627, 523776, 523878, 523902, 524135, 524329, 524515, 524611,
+      524686, 524798, 524852, 525209, 525700, 525913, 525954, 526158, 526332, 526356, 536810,
+      537279, 563933, 578719, 579248, 579791, 584191, 591485, 592871, 613176, 615012, 616428,
+      619153, 636103, 640708, 643141, 645080, 646349, 647043, 649345, 651085, 652849, 653092,
+      653169, 653227, 653586, 655241, 656093, 658355, 658564, 659381, 659518, 690513, 693218,
+      693746, 694340, 694842, 695155, 695563, 695776, 696380, 697608, 697797, 698222, 698835,
+      699307, 700154, 700203, 700235, 700404, 700806, 700900, 701796, 702155, 702956, 702998,
+      705105, 705377, 705631, 708650, 709265, 709787, 725122, 735376, 737115, 737174, 738005,
+      741377, 741986, 746045, 746404, 746590, 748212, 753574, 754379, 764728, 765776, 766863,
+      769126, 782626, 782723, 783529, 786875, 787544, 807281, 811132, 821933, 822194, 829768,
+      830997, 831095, 832481, 834082, 844664, 845574, 845764, 846820, 849481, 855607, 857775,
+      872350, 876126, 902029, 903509, 904449, 904469, 905915, 910463, 911856, 924365, 928664,
+      929314, 929606, 929983, 930478, 933195, 933819, 935628, 935911, 935922, 936002, 937668,
+      941895, 942677, 943721, 944661, 944980, 945121, 945268, 945360, 950756, 951007, 959993,
+      960787, 961048, 961084, 961238, 961589, 962000, 962797, 962827, 962910, 963788, 964272,
+      964343, 964431, 964573, 964949, 965017, 965036, 965041, 965598, 965674, 965957, 966014,
+      966032, 966092, 966144, 966226, 966234, 966265, 966291, 978103, 980858, 987212, 987458,
+      987498, 988368, 988513, 988939, 990571, 993183, 1005493, 1007972, 1008230, 1009675, 1010075,
+      1010685, 1011441, 1011828, 1012269, 1012310, 1013612, 1013907, 1014379, 1018659, 1018923,
+      1022035, 1024567, 1024568, 1025024, 1026699, 1027212, 1027840, 1029108, 1031846, 1032670,
+      1032970, 1034016, 1039255, 1040626, 1040796, 1043457, 1043632, 1051053, 1052581, 1091611,
+      1092316, 1092564, 1092634, 1096386, 1096820, 1098606, 1104201, 1107101, 1110019, 1111384,
+      1111707, 1128990, 1129111, 1129147, 1129160, 1129367, 1129408, 1129508, 1129577, 1129699,
+      1129750, 1129840, 1129951, 1129988, 1130041, 1130139, 1130177, 1130241, 1130248, 1130268,
+      1130276, 1130367, 1130540, 1130562, 1130636, 1130637, 1130662, 1130716, 1131139, 1131218,
+      1131250, 1131454, 1131541, 1131775, 1132208, 1132280, 1132901, 1133264, 1133474, 1133475,
+      1133764, 1133841, 1133988, 1134290, 1134533, 1134553, 1134614, 1134667, 1134710, 1134861,
+      1134896, 1135008, 1135178, 1135544, 1135551, 1135573, 1136260, 1136385, 1136458, 1136782,
+      1136960, 1137342, 1137713, 1137824, 1138160, 1138291, 1138340, 1138457, 1138468, 1138516,
+      1138526, 1138610, 1138648, 1138700, 1138801, 1138869, 1138999, 1139010, 1139102, 1139114,
+      1139145, 1139302, 1139322, 1139417, 1139496, 1139581, 1139668, 1139852, 1139930, 1139958,
+      1140325, 1140616, 1140811, 1140861, 1141056, 1141197, 1141311, 1141346, 1141551, 1141666,
+      1141735, 1141786, 1141895, 1142017, 1142228, 1142242, 1142415, 1142484, 1142579, 1142599,
+      1142867, 1142929, 1143057, 1143132, 1143191, 1143203, 1143293, 1143476, 1143860, 1143997,
+      1144044, 1144321, 1144338, 1144459, 1144548, 1144564, 1144588, 1144592, 1144606, 1144623,
+      1144718, 1144792, 1144906, 1144997, 1145007, 1145082, 1145274, 1145380, 1145430, 1145584,
+      1145731, 1145778, 1145869, 1145914, 1145925, 1146025, 1146158, 1146212, 1146223, 1146448,
+      1146594, 1146663, 1146761, 1146803, 1146826, 1146833, 1146898, 1147078, 1147099, 1147330,
+      1147382, 1147424, 1147431, 1147472, 1147545, 1147592, 1147627, 1147657, 1147742, 1148005,
+      1148699, 1155013, 1155166, 1155915, 1178902, 1179255, 1180871, 1184802, 1187587, 1190670,
+      1198632, 1198646, 1198832, 1199211, 1199259, 1199330, 1200318, 1200824, 1200959, 1201200,
+      1202513, 1210077, 1210208, 1210296, 1211774, 1211775, 1211776, 1211777, 1212528, 1212529,
+      1212843, 1216377, 1219904, 1220650, 1232492, 1235492, 1243381, 1243807, 1267467, 1267561,
+      1267615, 1267691, 1267708, 1267731, 1267797, 1273165, 1278015, 1278076, 1278615, 1279032,
+      1279185, 1279756, 1281009, 1281074, 1282368, 1284002, 1284572, 1285041, 1285278, 1285788,
+      1285969, 1286573, 1286679, 1287001, 1287466, 1287714, 1287819, 1288542, 1288897, 1289486,
+      1290086, 1290286, 1291047, 1291363, 1291498, 1291749, 1291853, 1292129, 1292571, 1292828,
+      1292855, 1292859, 1292892, 1292893, 1292909, 1292910, 1292956, 1292957, 1292985, 1293133,
+      1293185, 1293926, 1294446, 1294490, 1294571, 1294966, 1295003, 1295395, 1295491, 1296604,
+      1298327, 1298527, 1298685, 1300235, 1300501, 1301193, 1301345, 1301536, 1301908, 1301969,
+      1301988, 1302146, 1302158, 1302810, 1303060, 1303244, 1303275, 1303487, 1303721, 1303831,
+      1303943, 1304875, 1305210, 1305677, 1305687, 1306397, 1306865, 1307044, 1307745, 1307926,
+      1308080, 1308680, 1309204, 1309475, 1310596, 1312574, 1313313, 1313764, 1313792, 1313963,
+      1314093, 1314284, 1314743, 1315154, 1315292, 1315503, 1315994, 1316517, 1316872, 1316909,
+      1317089, 1317327, 1318223, 1319657, 1321070, 1321083, 1321495, 1321517, 1322195, 1322221,
+      1322293, 1322330, 1322471, 1322496, 1322569, 1322634, 1322716, 1322859, 1323066, 1323356,
+      1323530, 1323539, 1323614, 1323868, 1323925, 1328650, 1329210, 1332937, 1333431, 1335482,
+      1338092, 1342268, 1345890, 1346245, 1346532, 1346613, 1346783, 1347371, 1347858, 1348077,
+      1348468, 1349166, 1349298, 1349335, 1350775, 1350809, 1351329, 1352877
+    };
+    int[] array2 = {
+      14402, 14403, 14404, 14405, 14406, 14407, 23246, 23247, 23248, 23249, 23250, 23936, 23937,
+      23938, 23939, 23940, 23941, 23942, 29721, 29722, 29723, 29724, 29725, 30226, 30227, 30228,
+      30229, 30230, 32141, 32142, 32143, 47737, 47738, 47739, 47740, 47741, 47742, 47743, 47744,
+      47745, 47746, 47747, 47748, 47749, 47750, 47751, 47752, 68770, 68771, 68772, 68773, 68774,
+      68775, 68776, 68777, 68778, 68779, 68780, 72301, 72302, 83071, 83072, 83073, 83074, 85302,
+      85303, 85304, 85305, 85306, 85307, 85308, 85309, 85310, 85311, 85312, 85313, 85314, 85315,
+      85316, 97108, 97109, 97110, 97111, 103442, 103443, 103444, 103445, 103446, 103447, 103448,
+      103449, 103450, 103451, 103452, 103453, 103454, 103455, 103456, 103457, 103458, 103459,
+      103460, 103461, 103462, 103463, 103464, 103465, 103466, 103467, 103468, 103469, 128488,
+      128489, 128490, 128491, 128492, 128493, 135003, 135004, 135005, 135006, 135007, 135008,
+      135009, 135010, 135011, 135012, 135013, 135014, 140363, 140364, 140365, 140366, 140367,
+      140368, 140369, 140370, 140371, 140372, 149844, 149845, 149846, 149847, 149848, 149849,
+      149850, 149851, 149852, 149853, 149854, 149855, 149856, 149857, 149858, 149859, 149860,
+      149861, 149862, 149863, 149864, 172805, 172806, 172807, 172808, 172809, 172810, 172811,
+      172812, 172813, 172814, 172815, 172816, 172817, 172818, 172819, 172820, 172821, 172822,
+      172823, 172824, 172825, 172826, 172827, 172828, 172829, 172830, 172831, 172832, 172833,
+      172834, 172835, 172836, 172837, 172838, 172839, 172840, 172841, 172842, 172843, 172844,
+      172845, 172846, 172847, 172848, 172849, 172850, 172851, 172852, 172853, 172854, 172855,
+      172856, 172857, 172858, 172859, 172860, 172861, 172862, 172863, 172864, 172865, 172866,
+      172867, 172868, 172869, 172870, 172871, 202530, 202531, 202532, 209488, 209489, 209490,
+      209491, 209492, 209493, 209494, 209495, 209496, 209497, 209498, 209499, 209500, 209501,
+      209502, 209503, 209504, 209505, 209506, 225554, 225555, 225556, 225557, 225558, 225559,
+      225560, 225561, 225562, 225563, 225564, 225565, 225566, 225567, 225568, 225569, 225570,
+      225571, 225572, 225573, 225574, 225575, 225576, 225577, 225578, 225579, 225580, 225581,
+      227917, 227918, 227919, 227920, 227921, 227922, 227923, 227924, 227925, 227926, 227927,
+      227928, 227929, 227930, 227931, 227932, 227933, 227934, 227935, 227936, 227937, 227938,
+      227939, 252773, 252774, 252775, 252776, 252777, 252778, 252779, 252780, 252781, 252782,
+      252783, 252784, 252785, 252786, 252787, 252788, 252789, 252790, 252791, 252792, 252793,
+      252794, 278695, 278696, 278697, 278698, 278699, 301237, 301238, 301239, 301240, 301241,
+      301242, 301243, 301244, 301245, 301246, 301247, 301248, 301249, 301250, 301251, 301252,
+      301253, 301254, 301255, 301256, 301257, 301258, 301259, 301260, 301261, 301262, 301263,
+      301264, 301265, 320515, 320516, 320517, 320518, 320519, 320520, 320521, 320522, 320523,
+      320524, 320525, 320526, 320527, 320528, 320529, 320530, 320531, 320532, 320533, 320534,
+      320535, 320536, 320537, 320538, 320539, 320540, 320541, 320542, 320543, 320544, 320545,
+      320546, 320547, 320548, 329641, 329642, 329643, 329644, 329645, 329646, 329647, 329648,
+      329649, 329650, 329651, 329652, 329653, 329654, 329655, 329656, 329657, 329658, 329659,
+      342703, 342704, 342705, 342706, 349520, 349521, 349522, 349523, 349524, 349525, 349526,
+      349527, 349528, 349529, 349530, 362716, 362717, 362718, 362719, 362720, 362721, 362722,
+      362723, 362724, 362725, 362726, 362727, 378643, 378644, 378645, 378646, 390154, 390155,
+      390156, 390157, 390158, 390159, 390160, 390161, 390162, 390163, 390164, 390165, 390166,
+      390167, 390168, 390169, 395108, 395109, 395110, 395111, 395112, 395113, 395114, 395115,
+      403260, 403261, 403262, 403263, 403264, 403265, 403266, 403267, 403268, 403269, 403270,
+      403271, 417315, 417316, 417317, 417318, 417319, 417320, 432653, 432654, 432655, 432656,
+      432657, 432658, 432659, 432660, 432661, 432662, 432663, 432664, 432665, 432666, 432667,
+      432668, 432669, 432670, 432671, 432672, 432673, 432674, 432675, 432676, 432677, 432678,
+      449394, 449395, 449396, 449397, 449398, 459961, 459962, 459963, 459964, 474537, 474538,
+      474539, 474540, 474541, 474542, 474543, 474544, 474545, 474546, 474547, 474548, 474549,
+      474550, 474551, 474552, 474553, 474554, 474555, 474556, 474557, 474558, 474559, 474560,
+      474561, 474562, 474563, 474564, 474565, 474566, 474567, 474568, 474569, 474570, 474571,
+      474572, 474573, 474574, 474575, 474576, 474577, 474578, 474579, 474580, 474581, 474582,
+      474583, 474584, 474585, 474586, 474587, 474588, 474589, 474590, 474591, 474592, 474593,
+      474594, 474595, 474596, 474597, 483571, 483572, 483573, 483574, 483575, 483576, 489641,
+      489642, 489643, 489644, 489645, 489646, 489647, 489648, 489649, 489650, 489651, 491296,
+      491297, 491298, 495868, 495869, 495870, 502769, 502770, 502771, 502772, 502773, 502774,
+      502775, 502776, 502777, 502778, 502779, 502780, 502781, 502782, 502783, 513810, 513811,
+      513812, 513813, 513814, 513815, 513816, 513817, 513818, 513819, 513820, 513821, 513822,
+      513823, 513824, 513825, 513826, 513827, 513828, 513829, 513830, 513831, 513832, 517220,
+      517221, 517222, 517223, 517224, 517225, 517226, 517227, 519778, 519779, 519780, 519781,
+      519782, 519783, 519784, 519785, 524240, 524241, 524242, 524243, 524244, 524245, 524246,
+      524247, 524248, 524249, 527255, 527256, 527257, 527258, 527259, 533697, 533698, 533699,
+      533700, 533701, 533702, 533703, 533704, 533705, 533706, 533707, 533708, 533709, 539237,
+      539238, 539239, 539240, 539241, 539242, 539243, 562203, 562204, 562205, 562206, 569773,
+      569774, 569775, 569776, 569777, 569778, 569779, 569780, 569781, 569782, 569783, 569784,
+      569785, 569786, 569787, 569788, 569789, 569790, 569791, 569792, 569793, 569794, 569795,
+      569796, 569797, 569798, 569799, 569800, 569801, 569802, 569803, 569804, 569805, 569806,
+      569807, 569808, 569809, 569810, 569811, 569812, 569813, 569814, 569815, 569816, 569817,
+      569818, 569819, 569820, 569821, 580161, 580162, 580163, 580164, 580165, 580166, 580167,
+      580168, 580169, 580170, 580171, 580172, 580173, 580174, 580175, 580176, 588299, 588300,
+      588301, 588302, 588303, 588304, 588305, 588306, 588307, 588308, 588309, 588310, 588311,
+      588312, 588313, 588314, 588315, 588316, 588317, 588318, 588319, 588320, 588321, 588322,
+      588323, 588324, 588325, 588326, 588327, 588328, 588329, 588330, 588331, 588332, 588333,
+      588334, 588335, 608580, 608581, 608582, 608583, 608584, 608585, 608586, 608587, 608588,
+      608589, 608590, 608591, 608592, 608593, 608594, 608595, 608596, 608597, 608598, 608599,
+      608600, 608601, 608602, 608603, 608604, 608605, 618326, 618327, 618328, 618329, 618330,
+      618331, 618332, 618333, 618334, 618335, 618336, 618337, 618338, 618339, 618340, 618341,
+      618342, 618343, 618344, 618345, 618346, 618347, 618348, 618349, 626895, 626896, 626897,
+      626898, 626899, 626900, 635313, 635314, 635315, 635316, 635317, 635318, 635319, 635320,
+      635321, 635322, 635323, 635324, 635325, 635326, 635327, 635328, 635329, 635330, 635331,
+      635332, 635333, 635334, 635335, 635336, 635337, 635338, 635339, 635340, 635341, 635342,
+      635343, 635344, 635345, 635346, 635347, 635348, 635349, 635350, 635351, 635352, 635353,
+      635354, 635355, 648087, 648088, 648089, 648090, 648091, 648092, 648093, 648094, 648095,
+      648096, 648097, 648098, 648099, 648100, 648101, 648102, 648103, 648104, 648105, 648106,
+      648107, 648108, 648109, 648110, 661574, 661575, 661576, 661577, 674566, 674567, 674568,
+      674569, 674570, 674571, 674572, 674573, 674574, 674575, 674576, 674577, 674578, 674579,
+      674580, 674581, 674582, 674583, 674584, 674585, 689328, 689329, 689330, 689331, 689332,
+      689333, 689334, 689335, 689336, 689337, 697978, 697979, 697980, 697981, 697982, 697983,
+      697984, 697985, 697986, 697987, 697988, 697989, 697990, 697991, 697992, 697993, 697994,
+      726676, 726677, 726678, 726679, 726680, 726681, 782220, 782221, 782222, 782223, 782224,
+      782225, 782226, 782227, 782228, 782229, 782230, 782231, 782232, 782233, 782234, 782235,
+      782236, 782237, 782238, 782239, 797574, 797575, 797576, 797577, 797578, 797579, 797580,
+      797581, 797582, 804283, 804284, 804285, 822332, 822333, 822334, 822335, 822336, 831020,
+      831021, 831022, 831023, 831024, 831025, 831026, 831027, 831028, 831029, 831030, 831031,
+      831032, 831033, 831034, 831035, 831036, 831037, 831038, 831039, 831040, 847227, 847228,
+      847229, 847230, 847231, 847232, 847233, 847234, 847235, 847236, 847237, 847238, 847239,
+      847240, 847241, 847242, 847243, 847244, 847245, 857616, 857617, 857618, 857619, 857620,
+      857621, 857622, 857623, 857624, 857625, 867324, 867325, 867326, 867327, 867328, 867329,
+      867330, 867331, 867332, 867333, 867334, 867335, 867336, 867337, 867338, 867339, 877587,
+      877588, 877589, 877590, 877591, 877592, 877593, 877594, 877595, 877596, 877597, 877598,
+      877599, 877600, 877601, 877602, 877603, 877604, 877605, 877606, 877607, 877608, 877609,
+      877610, 877611, 877612, 877613, 877614, 877615, 896235, 896236, 896237, 896238, 896239,
+      896240, 916629, 916630, 916631, 916632, 929361, 929362, 929363, 929364, 929365, 929366,
+      929367, 929368, 929369, 929370, 929371, 948695, 948696, 948697, 948698, 948699, 948700,
+      948701, 948702, 949573, 949574, 957768, 957769, 957770, 957771, 957772, 957773, 957774,
+      957775, 961032, 961033, 961034, 961035, 987440, 987441, 987442, 987443, 1001434, 1001435,
+      1001436, 1001437, 1001438, 1001439, 1001440, 1001441, 1001442, 1001443, 1001444, 1001445,
+      1001446, 1001447, 1001448, 1001449, 1001450, 1001451, 1001452, 1001453, 1001454, 1001455,
+      1001456, 1001457, 1001458, 1001459, 1001460, 1009985, 1009986, 1009987, 1009988, 1009989,
+      1037191, 1037192, 1037193, 1037194, 1037195, 1037196, 1037197, 1037198, 1037199, 1037200,
+      1037201, 1037202, 1037203, 1037204, 1053198, 1053199, 1053200, 1053201, 1053202, 1053203,
+      1053204, 1053205, 1053206, 1053207, 1053208, 1053209, 1053210, 1053211, 1053212, 1053213,
+      1053214, 1053215, 1053216, 1053217, 1053218, 1053219, 1053220, 1053221, 1053222, 1053223,
+      1053224, 1084019, 1084020, 1084021, 1084022, 1084023, 1084024, 1084025, 1088361, 1088362,
+      1088363, 1088364, 1088365, 1088366, 1089312, 1089313, 1089314, 1089315, 1089316, 1089317,
+      1089318, 1092235, 1092236, 1092237, 1092238, 1092239, 1092240, 1092241, 1092242, 1092243,
+      1092244, 1102836, 1102837, 1102838, 1102839, 1102840, 1102841, 1102842, 1102843, 1102844,
+      1102845, 1102846, 1102847, 1108575, 1108576, 1108577, 1108578, 1108579, 1108580, 1108581,
+      1108582, 1108583, 1108584, 1108585, 1108586, 1108587, 1108588, 1108589, 1108590, 1108591,
+      1108592, 1108593, 1108594, 1108595, 1108596, 1108597, 1108598, 1134091, 1134092, 1134093,
+      1134094, 1134095, 1134096, 1134097, 1134098, 1134099, 1134100, 1134101, 1134102, 1134103,
+      1134104, 1134105, 1134106, 1134107, 1134108, 1134109, 1134110, 1134111, 1134112, 1134113,
+      1134114, 1134115, 1134116, 1134117, 1134118, 1134119, 1134120, 1134121, 1134122, 1134123,
+      1134124, 1134125, 1134126, 1134127, 1134128, 1134129, 1151732, 1151733, 1151734, 1151735,
+      1151736, 1151737, 1151738, 1151739, 1151740, 1151741, 1151742, 1151743, 1151744, 1151745,
+      1151746, 1151747, 1199223, 1199224, 1199225, 1199226, 1203252, 1203253, 1203254, 1203255,
+      1203256, 1203257, 1203258, 1203259, 1203260, 1217223, 1217224, 1217225, 1217226, 1226505,
+      1226506, 1226507, 1226508, 1226509, 1226510, 1226511, 1226512, 1231411, 1231412, 1231413,
+      1231414, 1231415, 1231416, 1231417, 1231418, 1231419, 1231420, 1231421, 1231422, 1231423,
+      1243464, 1243465, 1243466, 1243467, 1243468, 1243469, 1243470, 1247919, 1247920, 1247921,
+      1255972, 1255973, 1255974, 1255975, 1255976, 1255977, 1255978, 1255979, 1255980, 1263675,
+      1263676, 1263677, 1263678, 1263679, 1277693, 1277694, 1277695, 1277696, 1277697, 1277698,
+      1277699, 1277700, 1283492, 1283493, 1283494, 1283495, 1283496, 1283497, 1283498, 1283499,
+      1283500, 1283501, 1283502, 1283503, 1283504, 1283505, 1283506, 1283507, 1283508, 1283509,
+      1283510, 1283511, 1283512, 1283513, 1283514, 1325789, 1325790, 1325791, 1325792, 1325793,
+      1325794, 1325795, 1325796, 1325797, 1325798, 1325799
+    };
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(array1);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(array2);
+    RoaringBitmap rrb1 = rb1.clone();
+    RoaringBitmap rrb2 = rb2.clone();
+    rrb1.runOptimize();
+    rrb2.runOptimize();
+    assertEquals(RoaringBitmap.or(rb1, rb2), RoaringBitmap.or(rrb1, rrb2));
+  }
+
+  @Test
+  public void testRandomLists() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(randomlists[0]);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(randomlists[1]);
+    RoaringBitmap rbor = RoaringBitmap.or(rb1, rb2);
+    assertEquals(rbor, FastAggregation.horizontal_or(rb1, rb2));
+  }
+
+  @Test
+  public void testRank() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int k = 0; k < 100000; k += 7) {
+      rb.add(k);
+    }
+    for (int k = 100000; k < 200000; k += 1000) {
+      rb.add(k);
+    }
+    for (int k = 0; k < 100000; ++k) {
+      assertEquals(1 + k / 7, rb.rank(k));
+    }
+    for (int k = 100000; k < 200000; ++k) {
+      assertEquals(1 + 100000 / 7 + 1 + (k - 100000) / 1000, rb.rank(k));
+    }
+  }
+
+  @Test
+  public void testRankBigInts() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int k = 0; k < 100000; k += 7) {
+      rb.add((1 << 31) + k);
+    }
+    for (int k = 100000; k < 200000; k += 1000) {
+      rb.add((1 << 31) + k);
+    }
+    for (int k = 0; k < 100000; ++k) {
+      assertEquals(1 + k / 7, rb.rank((1 << 31) + k));
+    }
+    for (int k = 100000; k < 200000; ++k) {
+      assertEquals(1 + 100000 / 7 + 1 + (k - 100000) / 1000, rb.rank((1 << 31) + k));
+    }
+  }
+
+  @Test
+  public void testSelect() {
+    long w = ~0l;
+    for (int k = 0; k < 64; ++k) {
+      assertEquals(k, Util.select(w, k));
+    }
+    for (int k = 0; k < 64; ++k) {
+      assertEquals(k, Util.select(1l << k, 0));
+    }
+    for (int k = 1; k < 64; ++k) {
+      assertEquals(k, Util.select((1l << k) + 1, 1));
+    }
+    assertEquals(0, Util.select(1, 0));
+    assertEquals(0, Util.select(5, 0));
+    assertEquals(2, Util.select(5, 1));
+    for (int gap = 1; gap <= 1024; gap *= 2) {
+      RoaringBitmap rb = new RoaringBitmap();
+      for (int k = 0; k < 100000; k += gap) {
+        rb.add(k);
+      }
+      for (int k = 0; k < 100000 / gap; ++k) {
+        assertEquals(k * gap, rb.select(k));
+      }
+    }
+  }
+
+  @Test
+  public void testSelectBigInts() {
+    for (int gap = 1; gap <= 1024; gap *= 2) {
+      RoaringBitmap rb = new RoaringBitmap();
+      for (int k = 0; k < 100000; k += gap) {
+        rb.add((1 << 31) + k);
+      }
+      for (int k = 0; k < 100000 / gap; ++k) {
+        assertEquals((1 << 31) + k * gap, rb.select(k));
+      }
+    }
+  }
+
+  @Test
+  public void testSerialization() throws IOException, ClassNotFoundException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    final ObjectOutputStream oo = new ObjectOutputStream(bos);
+    rr.writeExternal(oo);
+    oo.close();
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+    rrback.readExternal(new ObjectInputStream(bis));
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationBigInts() throws IOException, ClassNotFoundException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add((1 << 31) + k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    final ObjectOutputStream oo = new ObjectOutputStream(bos);
+    rr.writeExternal(oo);
+    oo.close();
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+    rrback.readExternal(new ObjectInputStream(bis));
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerialization2() throws IOException, ClassNotFoundException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 200; k < 400; ++k) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    final ObjectOutputStream oo = new ObjectOutputStream(bos);
+    rr.writeExternal(oo);
+    oo.close();
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+    rrback.readExternal(new ObjectInputStream(bis));
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerialization3() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add(k);
+    }
+    rr.add(1444000);
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())));
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+    // Deserialize DataInput with a buffer
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerialization4() throws IOException, ClassNotFoundException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 1; k <= 10000000; k += 10) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())));
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+    // Deserialize DataInput with a buffer
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationDataInputWithBuffer() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationDataInputWithBufferBigInts() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add((1 << 31) + k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationDataInputWithBuffer2() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 200; k < 400; ++k) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationDataInputWithBuffer3() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add(k);
+    }
+    rr.add(1444000);
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationDataInputWithBuffer4() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 1; k <= 10000000; k += 10) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    rrback.deserialize(new DataInputStream(new ByteArrayInputStream(bos.toByteArray())), null);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationByteBuffer() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray());
+    rrback.deserialize(buf);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationByteBufferBigInts() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add((1 << 31) + k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray());
+    rrback.deserialize(buf);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationByteBuffer2() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 200; k < 400; ++k) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray());
+    rrback.deserialize(buf);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationByteBuffer3() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 65000; k < 2 * 65000; ++k) {
+      rr.add(k);
+    }
+    rr.add(1444000);
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray());
+    rrback.deserialize(buf);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSerializationByteBuffer4() throws IOException {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 1; k <= 10000000; k += 10) {
+      rr.add(k);
+    }
+    final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    // Note: you could use a file output steam instead of
+    // ByteArrayOutputStream
+    int howmuch = rr.serializedSizeInBytes();
+    final DataOutputStream oo = new DataOutputStream(bos);
+    rr.serialize(oo);
+    oo.close();
+    assertEquals(howmuch, bos.toByteArray().length);
+    final RoaringBitmap rrback = new RoaringBitmap();
+    final ByteBuffer buf = ByteBuffer.wrap(bos.toByteArray());
+    rrback.deserialize(buf);
+    assertEquals(rr.getCardinality(), rrback.getCardinality());
+    assertEquals(rr, rrback);
+  }
+
+  @Test
+  public void testSetUtilIntersection() {
+    char[] data1 = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18};
+    char[] data2 = {0, 3, 6, 9, 12, 15, 18};
+    char[] result = new char[data1.length + data2.length];
+    char[] expectedresult = {0, 6, 12, 18};
+    int nl = Util.unsignedLocalIntersect2by2(data1, data1.length, data2, data2.length, result);
+    result = Arrays.copyOf(result, nl);
+    assertArrayEquals(expectedresult, result);
+  }
+
+  @Test
+  public void testXORSimple() {
+    RoaringBitmap a = RoaringBitmap.bitmapOf(73647, 83469);
+    RoaringBitmap b =
+        RoaringBitmap.bitmapOf(
+            1, 2, 3, 5, 6, 8, 9, 10, 11, 13, 14, 16, 17, 18, 19, 20, 21, 25, 26, 27, 28, 29, 30, 32,
+            33, 34, 35, 36, 37, 39, 40, 41, 50, 51, 69, 79, 80, 81, 88, 89, 172);
+    RoaringBitmap rxor = RoaringBitmap.xor(a, b);
+    RoaringBitmap ror = RoaringBitmap.or(a, b);
+    assertEquals(rxor, ror);
+  }
+
+  @Test
+  public void trimArrayContainerCardinalityTest() {
+    final ArrayContainer ac = new ArrayContainer();
+    ac.trim();
+    for (char k = 0; k < 100; ++k) {
+      ac.add(k);
+      ac.trim();
+      assertEquals(ac.getCardinality(), k + 1);
+    }
+    for (char k = 0; k < 100; ++k) {
+      ac.add(k);
+      ac.trim();
+      assertEquals(ac.getCardinality(), 100);
+    }
+  }
+
+  boolean validate(BitmapContainer bc, ArrayContainer ac) {
+    // Checking the cardinalities of each container
+
+    if (bc.getCardinality() != ac.getCardinality()) {
+      System.out.println("cardinality differs");
+      return false;
+    }
+    // Checking that the two containers contain the same values
+    int counter = 0;
+
+    int i = bc.nextSetBit(0);
+    while (i >= 0) {
+      ++counter;
+      if (!ac.contains((char) i)) {
+        System.out.println("content differs");
+        System.out.println(bc);
+        System.out.println(ac);
+        return false;
+      }
+      i = bc.nextSetBit(i + 1);
+    }
+
+    // checking the cardinality of the BitmapContainer
+    return counter == bc.getCardinality();
+  }
+
+  @Test
+  public void trimTest() {
+    // with bitmap containing 4k containers
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int i = 0; i < 4000; i++) {
+      rb.add((1 << 16) * i);
+    }
+
+    rb.trim();
+
+    int wastedBytes = 0;
+    final int javaReferenceSize = 4; // or 8 depending on factors
+    RoaringArray ra = rb.highLowContainer;
+    wastedBytes += Short.BYTES * (ra.keys.length - ra.size);
+    wastedBytes += javaReferenceSize * (ra.values.length - ra.size);
+    ContainerPointer cp = ra.getContainerPointer();
+    while (cp.getContainer() != null) {
+      if (cp.isBitmapContainer()) {
+        ; // nothing wasted
+      } else if (cp.isRunContainer()) {
+        ; // not able to access information about wasted bytes
+      } else {
+        ArrayContainer ac = (ArrayContainer) cp.getContainer();
+        wastedBytes += Short.BYTES * (ac.content.length - ac.cardinality);
+      }
+      cp.advance();
+    }
+    assertEquals(0, wastedBytes);
+  }
+
+  @Test
+  public void xorBigIntsTest() {
+    RoaringBitmap rb = new RoaringBitmap();
+    RoaringBitmap rb2 = new RoaringBitmap();
+    HashSet hs = new HashSet();
+
+    for (int i = 1 << 31; i < (1 << 31) + 65536; i += 2) {
+      hs.add(i);
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 5) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 7) {
+      rb.add(i);
+    }
+    for (int i = (1 << 31) + 11 * 65536; i < (1 << 31) + 12 * 65536; i += 6) {
+      hs.add(i);
+      rb.add(i);
+    }
+
+    for (int i = (1 << 31) + 3 * 65536; i < (1 << 31) + 4 * 65536; i += 3) {
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 5 * 65536; i < (1 << 31) + 7 * 65536; i += 5) {
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 9 * 65536; i < (1 << 31) + 10 * 65536; i += 7) {
+      rb2.add(i);
+    }
+    for (int i = (1 << 31) + 13 * 65536; i < (1 << 31) + 14 * 65536; i += 2) {
+      hs.add(i);
+      rb2.add(i);
+    }
+
+    RoaringBitmap rbxor = RoaringBitmap.xor(rb, rb2);
+
+    Object[] correct = hs.toArray();
+    Arrays.sort(correct);
+    Integer[] resxor = ArrayUtils.toObject(rbxor.toArray());
+    assertArrayEquals(correct, resxor);
+  }
+
+  @Test
+  public void XORtest() {
+    final RoaringBitmap rr = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536; k < 3 * 65536 + 9000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4 * 65535; k < 4 * 65535 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 10000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 8 * 65535; k < 8 * 65535 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 9 * 65535; k < 9 * 65535 + 30000; ++k) {
+      rr.add(k);
+    }
+
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 3 * 65536 + 2000; k < 3 * 65536 + 6000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 7 * 65535; k < 7 * 65535 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 10 * 65535; k < 10 * 65535 + 5000; ++k) {
+      rr2.add(k);
+    }
+    final RoaringBitmap correct = RoaringBitmap.xor(rr, rr2);
+    rr.xor(rr2);
+    assertEquals(correct, rr);
+  }
+
+  @Test
+  public void xortest1() {
+    final HashSet V1 = new HashSet();
+    final HashSet V2 = new HashSet();
+
+    final RoaringBitmap rr = new RoaringBitmap();
+    final RoaringBitmap rr2 = new RoaringBitmap();
+    // For the first 65536: rr2 has a bitmap container, and rr has
+    // an array container.
+    // We will check the union between a BitmapCintainer and an
+    // arrayContainer
+    for (int k = 0; k < 4000; ++k) {
+      rr2.add(k);
+      if (k < 3500) {
+        V1.add(k);
+      }
+    }
+    for (int k = 3500; k < 4500; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4000; k < 65000; ++k) {
+      rr2.add(k);
+      if (k >= 4500) {
+        V1.add(k);
+      }
+    }
+
+    // In the second node of each roaring bitmap, we have two bitmap
+    // containers.
+    // So, we will check the union between two BitmapContainers
+    for (int k = 65536; k < 65536 + 30000; ++k) {
+      rr.add(k);
+    }
+
+    for (int k = 65536; k < 65536 + 50000; ++k) {
+      rr2.add(k);
+      if (k >= 65536 + 30000) {
+        V1.add(k);
+      }
+    }
+
+    // In the 3rd node of each Roaring Bitmap, we have an
+    // ArrayContainer. So, we will try the union between two
+    // ArrayContainers.
+    for (int k = 4 * 65535; k < 4 * 65535 + 1000; ++k) {
+      rr.add(k);
+      if (k >= 4 * 65535 + 800) {
+        V1.add(k);
+      }
+    }
+
+    for (int k = 4 * 65535; k < 4 * 65535 + 800; ++k) {
+      rr2.add(k);
+    }
+
+    // For the rest, we will check if the union will take them in
+    // the result
+    for (int k = 6 * 65535; k < 6 * 65535 + 1000; ++k) {
+      rr.add(k);
+      V1.add(k);
+    }
+
+    for (int k = 7 * 65535; k < 7 * 65535 + 2000; ++k) {
+      rr2.add(k);
+      V1.add(k);
+    }
+
+    final RoaringBitmap rrxor = RoaringBitmap.xor(rr, rr2);
+    boolean valide = true;
+
+    // Si tous les elements de rror sont dans V1 et que tous les
+    // elements de
+    // V1 sont dans rror(V2)
+    // alors V1 == rror
+    final Object[] tab = V1.toArray();
+    final Vector vector = new Vector();
+    for (Object aTab : tab) {
+      vector.add((Integer) aTab);
+    }
+
+    for (final int i : rrxor.toArray()) {
+      if (!vector.contains(i)) {
+        valide = false;
+      }
+      V2.add(i);
+    }
+    for (int i = 0; i < V1.size(); i++) {
+      if (!V2.contains(vector.elementAt(i))) {
+        valide = false;
+      }
+    }
+
+    assertTrue(valide);
+  }
+
+  @Test
+  public void xortest4() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    final RoaringBitmap rb2 = new RoaringBitmap();
+
+    for (int i = 0; i < 200000; i += 4) {
+      rb2.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 14) {
+      rb2.add(i);
+    }
+    final int rb2card = rb2.getCardinality();
+
+    // check or against an empty bitmap
+    final RoaringBitmap xorresult = RoaringBitmap.xor(rb, rb2);
+    final RoaringBitmap off = RoaringBitmap.or(rb2, rb);
+    assertEquals(xorresult, off);
+
+    assertEquals(rb2card, xorresult.getCardinality());
+
+    for (int i = 500000; i < 600000; i += 14) {
+      rb.add(i);
+    }
+    for (int i = 200000; i < 400000; i += 3) {
+      rb2.add(i);
+    }
+    // check or against an empty bitmap
+    final RoaringBitmap xorresult2 = RoaringBitmap.xor(rb, rb2);
+    assertEquals(rb2card, xorresult.getCardinality());
+
+    assertEquals(rb2.getCardinality() + rb.getCardinality(), xorresult2.getCardinality());
+    rb.xor(rb2);
+    assertEquals(xorresult2, rb);
+  }
+
+  // is this better in testRange?
+  @Test
+  public void testRangedOr() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add(val1);
+        set1.add(val1);
+
+        rb2.add(val2);
+        set2.add(val2);
+      }
+      Set unionSet = new TreeSet<>();
+      unionSet.addAll(set1);
+      unionSet.addAll(set2);
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        int rangeStart = random.nextInt(length - 1);
+        // +1 to ensure rangeEnd >rangeStart, may
+        int rangeLength = random.nextInt(length - rangeStart) + 1;
+        int rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = rangeStart; i < rangeEnd; i++) {
+          if (unionSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        List list = new ArrayList<>();
+        list.add(rb1);
+        list.add(rb2);
+        RoaringBitmap result =
+            RoaringBitmap.or(list.iterator(), (long) rangeStart, (long) rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testRangedOrBigInts() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add((1 << 31) + val1);
+        set1.add((1 << 31) + val1);
+
+        rb2.add((1 << 31) + val2);
+        set2.add((1 << 31) + val2);
+      }
+      Set unionSet = new TreeSet<>();
+      unionSet.addAll(set1);
+      unionSet.addAll(set2);
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        long rangeStart1 = random.nextInt(length - 1);
+        long rangeStart = (1L << 31) + rangeStart1;
+        long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1;
+        long rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = (int) rangeStart; i < (int) rangeEnd; i++) {
+          if (unionSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        List list = new ArrayList<>();
+        list.add(rb1);
+        list.add(rb2);
+        RoaringBitmap result = RoaringBitmap.or(list.iterator(), rangeStart, rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testRangedAnd() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add(val1);
+        set1.add(val1);
+
+        rb2.add(val2);
+        set2.add(val2);
+      }
+      Set intersectionSet = new TreeSet<>(set1);
+      intersectionSet.retainAll(set2);
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        int rangeStart = random.nextInt(length - 1);
+        // +1 to ensure rangeEnd >rangeStart, may
+        int rangeLength = random.nextInt(length - rangeStart) + 1;
+        int rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = rangeStart; i < rangeEnd; i++) {
+          if (intersectionSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        List list = new ArrayList<>();
+        list.add(rb1);
+        list.add(rb2);
+        RoaringBitmap result =
+            RoaringBitmap.and(list.iterator(), (long) rangeStart, (long) rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testRangedAndBigInts() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add((1 << 31) + val1);
+        set1.add((1 << 31) + val1);
+
+        rb2.add((1 << 31) + val2);
+        set2.add((1 << 31) + val2);
+      }
+      Set intersectionSet = new TreeSet<>(set1);
+      intersectionSet.retainAll(set2);
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        long rangeStart1 = random.nextInt(length - 1);
+        long rangeStart = (1L << 31) + rangeStart1;
+        long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1;
+        long rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = (int) rangeStart; i < (int) rangeEnd; i++) {
+          if (intersectionSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        List list = new ArrayList<>();
+        list.add(rb1);
+        list.add(rb2);
+        RoaringBitmap result = RoaringBitmap.and(list.iterator(), rangeStart, rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testRangedXor() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add(val1);
+        set1.add(val1);
+
+        rb2.add(val2);
+        set2.add(val2);
+      }
+      Set xorSet = new TreeSet<>();
+      xorSet.addAll(set1);
+      xorSet.addAll(set2);
+      Set andSet = new TreeSet<>(set1);
+      andSet.retainAll(set2);
+
+      xorSet.removeAll(andSet);
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        int rangeStart = random.nextInt(length - 1);
+        // +1 to ensure rangeEnd >rangeStart, may
+        int rangeLength = random.nextInt(length - rangeStart) + 1;
+        int rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = rangeStart; i < rangeEnd; i++) {
+          if (xorSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        List list = new ArrayList<>();
+        list.add(rb1);
+        list.add(rb2);
+        RoaringBitmap result =
+            RoaringBitmap.xor(list.iterator(), (long) rangeStart, (long) rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testRangedXorBigInts() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add((1 << 31) + val1);
+        set1.add((1 << 31) + val1);
+
+        rb2.add((1 << 31) + val2);
+        set2.add((1 << 31) + val2);
+      }
+      Set xorSet = new TreeSet<>();
+      xorSet.addAll(set1);
+      xorSet.addAll(set2);
+      Set andSet = new TreeSet<>(set1);
+      andSet.retainAll(set2);
+
+      xorSet.removeAll(andSet);
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        long rangeStart1 = random.nextInt(length - 1);
+        long rangeStart = (1L << 31) + rangeStart1;
+        long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1;
+        long rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = (int) rangeStart; i < (int) rangeEnd; i++) {
+          if (xorSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        List list = new ArrayList<>();
+        list.add(rb1);
+        list.add(rb2);
+        RoaringBitmap result = RoaringBitmap.xor(list.iterator(), rangeStart, rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testRangedAndNot() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add(val1);
+        set1.add(val1);
+
+        rb2.add(val2);
+        set2.add(val2);
+      }
+      Set andNotSet = new TreeSet<>();
+      for (int i : set1) {
+        if (!set2.contains(i)) {
+          andNotSet.add(i);
+        }
+      }
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        int rangeStart = random.nextInt(length - 1);
+        // +1 to ensure rangeEnd >rangeStart, may
+        int rangeLength = random.nextInt(length - rangeStart) + 1;
+        int rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = rangeStart; i < rangeEnd; i++) {
+          if (andNotSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        RoaringBitmap result = RoaringBitmap.andNot(rb1, rb2, (long) rangeStart, (long) rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testRangedAndNotBigInts() {
+    int length = 1000;
+    int NUM_ITER = 10;
+    Random random = new Random(1234); // please use deterministic tests
+    for (int test = 0; test < 50; ++test) {
+      final RoaringBitmap rb1 = new RoaringBitmap();
+      final RoaringBitmap rb2 = new RoaringBitmap();
+      Set set1 = new HashSet<>();
+      Set set2 = new HashSet<>();
+      int numBitsToSet = length / 2;
+      for (int i = 0; i < numBitsToSet; i++) {
+        int val1 = random.nextInt(length);
+        int val2 = random.nextInt(length);
+
+        rb1.add((1 << 31) + val1);
+        set1.add((1 << 31) + val1);
+
+        rb2.add((1 << 31) + val2);
+        set2.add((1 << 31) + val2);
+      }
+      Set andNotSet = new TreeSet<>();
+      for (int i : set1) {
+        if (!set2.contains(i)) {
+          andNotSet.add(i);
+        }
+      }
+      for (int iter = 0; iter < NUM_ITER; iter++) {
+        long rangeStart1 = random.nextInt(length - 1);
+        long rangeStart = (1L << 31) + rangeStart1;
+        long rangeLength = random.nextInt((int) (length - rangeStart1)) + 1;
+        long rangeEnd = rangeStart + rangeLength;
+        Set expectedResultSet = new TreeSet<>();
+        for (int i = (int) rangeStart; i < (int) rangeEnd; i++) {
+          if (andNotSet.contains(i)) {
+            expectedResultSet.add(i);
+          }
+        }
+        RoaringBitmap result = RoaringBitmap.andNot(rb1, rb2, rangeStart, rangeEnd);
+        Set actualResultSet = new TreeSet<>();
+        IntIterator intIterator = result.getIntIterator();
+        while (intIterator.hasNext()) {
+          actualResultSet.add(intIterator.next());
+        }
+        assertEquals(expectedResultSet, actualResultSet);
+      }
+    }
+  }
+
+  @Test
+  public void testOr() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5);
+    RoaringBitmap rb2 = RoaringBitmap.bitmapOf(4, 7, 8, 9);
+    RoaringBitmap rb3 = RoaringBitmap.bitmapOf(12, 13, 15, 19, 21);
+    RoaringBitmap rb4 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 7, 8, 9);
+    RoaringBitmap rb5 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 15, 19, 21);
+    assertEquals(rb4, RoaringBitmap.lazyorfromlazyinputs(rb1, rb2));
+    assertEquals(rb5, RoaringBitmap.or(rb1, rb2, rb3));
+  }
+
+  @Test
+  public void testLazyOr() {
+    RoaringBitmap rb1 = RoaringBitmap.bitmapOf(1 << 16, 1 << 18, 1 << 19);
+    rb1.lazyor(RoaringBitmap.bitmapOf(4, 7, 8, 9));
+    rb1.lazyor(RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 1 << 16, 1 << 17, 1 << 20));
+    RoaringBitmap rb2 =
+        RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 7, 8, 9, 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20);
+    assertEquals(rb2, rb1);
+  }
+
+  @Test
+  public void testFirstLast_CreateSparseContainers() {
+    RoaringBitmap rb = new RoaringBitmap();
+    for (int i = 0; i < 20; ++i) {
+      int x = 1 << i;
+      rb.add(x);
+      assertEquals(1, rb.first());
+      assertEquals(x, rb.last());
+    }
+  }
+
+  @Test
+  public void testFirstLast_CreateSparseContainersAfterRun() {
+    RoaringBitmap rb = new RoaringBitmap();
+    rb.add(1L, 1 << 14);
+    for (int i = 18; i < 31; ++i) {
+      int x = 1 << i;
+      rb.add(x);
+      assertEquals(1, rb.first());
+      assertEquals(x, rb.last());
+    }
+  }
+
+  @Test
+  public void testFirstLast_AfterLazyMutation1() {
+    RoaringBitmap rb = new RoaringBitmap();
+    rb.add(1, 3, 5, 7);
+    assertEquals(1, rb.first());
+    assertEquals(7, rb.last());
+    RoaringBitmap mutator = new RoaringBitmap();
+    mutator.add(0, 2, 4, 6, 8);
+    rb.lazyor(mutator);
+    assertEquals(0, rb.first());
+    assertEquals(8, rb.last());
+  }
+
+  @Test
+  public void testFirstLast_AfterLazyMutation2() {
+    RoaringBitmap rb = new RoaringBitmap();
+    Iterable willForceUseOfBitmapContainer =
+        Iterables.filter(
+            ContiguousSet.create(Range.openClosed(0, 1 << 16), DiscreteDomain.integers()),
+            new Predicate() {
+              @Override
+              public boolean apply(Integer input) {
+                return input % 3 == 0;
+              }
+            });
+    int max = 0;
+    for (Integer i : willForceUseOfBitmapContainer) {
+      rb.add(i);
+      max = i;
+    }
+    assertEquals(3, rb.first());
+    assertEquals(max, rb.last());
+    RoaringBitmap mutator = new RoaringBitmap();
+    mutator.add(0, 2, 4, 6, 8);
+    rb.lazyor(mutator);
+    assertEquals(0, rb.first());
+    assertEquals(max, rb.last());
+  }
+
+  @Test
+  public void testEmptyFirst() {
+    assertThrows(NoSuchElementException.class, () -> new RoaringBitmap().first());
+  }
+
+  @Test
+  public void testEmptyLast() {
+    assertThrows(NoSuchElementException.class, () -> new RoaringBitmap().last());
+  }
+
+  @Test
+  public void testFirstLast() {
+    RoaringBitmap rb = new RoaringBitmap();
+
+    rb.add(2);
+    rb.add(4);
+    rb.add(8);
+    assertEquals(2, rb.first());
+    assertEquals(8, rb.last());
+
+    rb.add(1L << 5, 1L << 14);
+    assertEquals(2, rb.first());
+    assertEquals((1 << 14) - 1, rb.last());
+
+    rb.add(1L << 15, 1L << 30);
+    assertEquals(2, rb.first());
+    assertEquals((1L << 30) - 1, rb.last());
+  }
+
+  @Test
+  public void testIsHammingSimilar_AtStart() {
+    // similar bitmaps in the first container
+    RoaringBitmap baseline = RoaringBitmap.bitmapOf(2, 4, 8, 1 << 17, 1 << 22);
+    assertTrue(baseline.isHammingSimilar(baseline, 0));
+    RoaringBitmap other = baseline.clone();
+    other.flip(0L, 9);
+    for (int i = 0; i < 9; ++i) {
+      assertFalse(baseline.isHammingSimilar(other, i));
+    }
+    assertTrue(baseline.isHammingSimilar(other, 9));
+    other.add(0L, 9L);
+    for (int i = 0; i < 6; ++i) {
+      assertFalse(baseline.isHammingSimilar(other, i));
+    }
+    assertTrue(baseline.isHammingSimilar(other, 6));
+  }
+
+  @Test
+  public void testHammingSimilarity_BigVsSmall() {
+    RoaringBitmap big = new RoaringBitmap();
+    big.add(1, 2, 3, 4);
+    big.add(1L << 17, 1L << 30);
+    big.flip((1 << 17) | (1 << 16));
+    for (int i = 1 << 18; i < 1 << 19; ++i) {
+      if (i % 3 == 0) {
+        big.flip(i);
+      }
+    }
+    RoaringBitmap small = RoaringBitmap.bitmapOf(1, 2, 3, 4);
+    assertFalse(small.isHammingSimilar(big, 1));
+    assertFalse(big.isHammingSimilar(small, 1));
+  }
+
+  @Test
+  public void testHammingSimilarity_Shifted() {
+    RoaringBitmap baseline = RoaringBitmap.bitmapOf(1, 2, 3, 4);
+    RoaringBitmap shifted =
+        RoaringBitmap.bitmapOf((1 << 17) + 1, (1 << 17) + 2, (1 << 17) + 3, (1 << 17) + 4);
+    assertFalse(baseline.isHammingSimilar(shifted, 0));
+  }
+
+  @Test
+  public void testIsHammingSimilar_AtEnd() {
+    // reject bitmaps that are identical for many chunks but differ at the end
+    RoaringBitmap baseline = new RoaringBitmap();
+    for (int i = 0; i < 1 << 15; ++i) {
+      if (i % 3 == 0) {
+        baseline.add(i);
+      }
+    }
+    baseline.add((1L << 16) + 1, 1L << 18);
+    baseline.add((1L << 19) + 1, 1L << 20);
+    baseline.add((1 << 21) + 1);
+    baseline.add((1 << 21) + 3);
+    baseline.add((1 << 21) + 5);
+    assertEquals(baseline.getCardinality(), RoaringBitmap.andCardinality(baseline, baseline));
+    assertTrue(baseline.isHammingSimilar(baseline, 0));
+    RoaringBitmap other = baseline.clone();
+    other.flip((1 << 21) + 1);
+    assertTrue(baseline.isHammingSimilar(other, 1));
+    assertFalse(baseline.isHammingSimilar(other, 0));
+    other.add((1 << 21) + 2);
+    assertTrue(baseline.isHammingSimilar(other, 2));
+    assertFalse(baseline.isHammingSimilar(other, 1));
+    other.flip((1 << 21) + 3);
+    assertTrue(baseline.isHammingSimilar(other, 3));
+    assertFalse(baseline.isHammingSimilar(other, 2));
+  }
+
+  @Test
+  public void testAndCardinality() {
+    RoaringBitmap baseline = new RoaringBitmap();
+    baseline.add((1L << 16) + 1, 1L << 18);
+    baseline.add((1L << 19) + 1, 1L << 20);
+    baseline.add((1 << 21) + 1);
+    baseline.add((1 << 21) + 3);
+    baseline.add((1 << 21) + 5);
+    assertEquals(baseline, RoaringBitmap.and(baseline, baseline));
+    assertEquals(baseline.getCardinality(), RoaringBitmap.andCardinality(baseline, baseline));
+  }
+
+  @Test
+  public void testRankOverflow() {
+    assertEquals(0, RoaringBitmap.bitmapOf(65537).rank(1));
+    assertEquals(1, RoaringBitmap.bitmapOf(65537).rank(65537));
+    assertEquals(1, RoaringBitmap.bitmapOf(65537).rank(65538));
+  }
+
+  @Test
+  public void testNegativeAdd() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(-7);
+
+    assertEquals("{4294967289}", bitmap.toString());
+  }
+
+  @Test
+  public void testNegative_last() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(-7);
+    bitmap.add(777);
+
+    assertEquals(-7, bitmap.last());
+  }
+
+  @Test
+  public void testFirstLastSigned() {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(1_111_111, 3_333_333);
+    assertEquals(1_111_111, bitmap.firstSigned());
+    assertEquals(3_333_333, bitmap.lastSigned());
+
+    bitmap = RoaringBitmap.bitmapOf(-3_333_333, 3_333_333);
+    assertEquals(-3_333_333, bitmap.firstSigned());
+    assertEquals(3_333_333, bitmap.lastSigned());
+
+    bitmap = RoaringBitmap.bitmapOf(-3_333_333, -1_111_111);
+    assertEquals(-3_333_333, bitmap.firstSigned());
+    assertEquals(-1_111_111, bitmap.lastSigned());
+
+    bitmap = RoaringBitmap.bitmapOfRange(0, 1L << 32);
+    assertEquals(Integer.MIN_VALUE, bitmap.firstSigned());
+    assertEquals(Integer.MAX_VALUE, bitmap.lastSigned());
+  }
+
+  @ParameterizedTest
+  @ValueSource(ints = {Integer.MIN_VALUE, -65_536, 0, 65_536, Integer.MAX_VALUE})
+  public void testFirstLastSigned_SingleValueBitmap(int value) {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(value);
+    assertEquals(value, bitmap.firstSigned());
+    assertEquals(value, bitmap.lastSigned());
+  }
+
+  @Test
+  public void testContainsRange_ContiguousBitmap() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(0L, 1_000_000L);
+    assertTrue(bitmap.contains(1L, 999_999L));
+    assertFalse(bitmap.contains(1L, 1_000_001L));
+    bitmap.flip(500_000);
+    assertFalse(bitmap.contains(1L, 999_999L));
+    bitmap.flip(500_000);
+    bitmap.flip(500_000L, 600_000L);
+    assertFalse(bitmap.contains(1L, 999_999L));
+    assertTrue(bitmap.contains(0L, 500_000L));
+    assertFalse(bitmap.contains(2_000_001L, 10_000_000L));
+  }
+
+  @Test
+  public void testContainsRange_SmallBitmap() {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6);
+    assertTrue(bitmap.contains(1, 6));
+    assertTrue(bitmap.contains(1, 5));
+    assertTrue(bitmap.contains(2, 6));
+    assertTrue(bitmap.contains(2, 7));
+    assertFalse(bitmap.contains(2, 8));
+    assertFalse(bitmap.contains(0, 6));
+    assertFalse(bitmap.contains(0, 1));
+    assertFalse(bitmap.contains(6, 10));
+    assertFalse(bitmap.contains(7, 1 << 16));
+    assertFalse(bitmap.contains(1 << 17, 1 << 19));
+  }
+
+  @Test
+  public void testContainsRange_DirtyBitmap() {
+    RoaringBitmapWriter writer = writer().constantMemory().get();
+    IntStream.range(0, 1_000_000).map(i -> i * 2).forEach(writer::add);
+    writer.flush();
+    RoaringBitmap bitmap = writer.getUnderlying();
+    assertFalse(bitmap.contains(0L, 2_000_000L));
+    assertFalse(bitmap.contains(0L, 2L));
+    assertTrue(bitmap.contains(0L, 1L));
+    assertTrue(bitmap.contains(1L << 10, 1 | (1L << 10)));
+    assertFalse(bitmap.contains(1L << 31, 1L << 32));
+  }
+
+  @Test
+  public void addoffset() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.add(10);
+    rb.add(0xFFFF);
+    rb.add(0x010101);
+    for (int i = 100000; i < 200000; i += 4) {
+      rb.add(i);
+    }
+    rb.add(400000L, 1400000L);
+    for (int offset = 3; offset < 1000000; offset *= 3) {
+      RoaringBitmap rboff = RoaringBitmap.addOffset(rb, offset);
+      IntIterator i = rb.getIntIterator();
+      IntIterator j = rboff.getIntIterator();
+      while (i.hasNext() && j.hasNext()) {
+        int val1 = i.next() + offset;
+        int val2 = j.next();
+        assertEquals(val1, val2);
+      }
+      assertEquals(i.hasNext(), j.hasNext());
+    }
+    for (int offset = 1024; offset < 1000000; offset *= 2) {
+      RoaringBitmap rboff = RoaringBitmap.addOffset(rb, offset);
+      IntIterator i = rb.getIntIterator();
+      IntIterator j = rboff.getIntIterator();
+      while (i.hasNext() && j.hasNext()) {
+        assertEquals(i.next() + offset, j.next());
+      }
+      assertEquals(i.hasNext(), j.hasNext());
+    }
+  }
+
+  @Test
+  public void issue418() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.add(0);
+    assertEquals(rb.contains(0), true);
+    assertEquals(rb.getCardinality(), 1);
+    long vals[] = {100, 0xFFFF0000L, 0xFFFF0001L};
+    for (long s : vals) {
+      RoaringBitmap shifted = RoaringBitmap.addOffset(rb, s);
+      System.out.println("moved " + shifted);
+      assertEquals(shifted.contains((int) s), true);
+      assertEquals(shifted.getCardinality(), 1);
+      System.out.println("moving back by " + (-s));
+
+      shifted = RoaringBitmap.addOffset(shifted, -s);
+      System.out.println("back " + shifted);
+
+      assertEquals(shifted.contains(0), true);
+      assertEquals(shifted.getCardinality(), 1);
+    }
+  }
+
+  @Test
+  public void addNegativeOffset() {
+    final RoaringBitmap rb = new RoaringBitmap();
+    rb.add(10);
+    rb.add(0xFFFF);
+    rb.add(0x010101);
+    for (int i = 100000; i < 200000; i += 4) {
+      rb.add(i);
+    }
+    rb.add(400000L, 1400000L);
+    for (int offset = 3; offset < 1000000; offset *= 3) {
+      RoaringBitmap rboffpos = RoaringBitmap.addOffset(rb, offset);
+      RoaringBitmap rboff = RoaringBitmap.addOffset(rboffpos, -offset);
+
+      IntIterator i = rb.getIntIterator();
+      IntIterator j = rboff.getIntIterator();
+      while (i.hasNext() && j.hasNext()) {
+        int val1 = i.next();
+        int val2 = j.next();
+        if (val1 != val2) assertEquals(val1, val2);
+      }
+      assertEquals(i.hasNext(), j.hasNext());
+    }
+    for (int offset = 1024; offset < 1000000; offset *= 2) {
+      RoaringBitmap rboffpos = RoaringBitmap.addOffset(rb, offset);
+      RoaringBitmap rboff = RoaringBitmap.addOffset(rboffpos, -offset);
+      IntIterator i = rb.getIntIterator();
+      IntIterator j = rboff.getIntIterator();
+      while (i.hasNext() && j.hasNext()) {
+        assertEquals(i.next(), j.next());
+      }
+      assertEquals(i.hasNext(), j.hasNext());
+    }
+  }
+
+  @Test
+  public void testNextValue() {
+    RoaringBitmap bitmap =
+        SeededTestData.TestDataSet.testCase()
+            .withRunAt(0)
+            .withBitmapAt(1)
+            .withArrayAt(2)
+            .withRunAt(3)
+            .withBitmapAt(4)
+            .withArrayAt(5)
+            .build();
+
+    BitSet bitset = new BitSet();
+    bitmap.forEach((IntConsumer) bitset::set);
+    long b1 = 0;
+    int b2 = 0;
+    while (b1 >= 0 && b2 >= 0) {
+      b1 = bitmap.nextValue((int) b1 + 1);
+      b2 = bitset.nextSetBit(b2 + 1);
+      assertEquals(b1, b2);
+    }
+  }
+
+  @Test
+  public void testPreviousValueLimit() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(1);
+    assertEquals(-1l, bitmap.previousValue(0));
+  }
+
+  @Test
+  public void testPreviousAbsentValueLimit() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(0);
+    assertEquals(-1L, bitmap.previousAbsentValue(0));
+  }
+
+  @Test
+  public void testNextValueLimit() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(0xffffffff - 1);
+    assertEquals(-1L, bitmap.nextValue(0xffffffff));
+  }
+
+  @Test
+  public void testNextAbsentValueLimit() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    bitmap.add(-1);
+    assertEquals(-1L, bitmap.nextAbsentValue(-1));
+  }
+
+  @Test
+  public void testPreviousValue() {
+    RoaringBitmap bitmap =
+        SeededTestData.TestDataSet.testCase()
+            .withRunAt(0)
+            .withBitmapAt(1)
+            .withArrayAt(2)
+            .withRunAt(3)
+            .withBitmapAt(4)
+            .withArrayAt(5)
+            .build();
+
+    BitSet bitset = new BitSet();
+    bitmap.forEach((IntConsumer) bitset::set);
+    long b1 = Util.toUnsignedLong(bitmap.last());
+    int b2 = bitset.previousSetBit(Integer.MAX_VALUE);
+    int i = bitmap.getCardinality();
+    while (b1 > 0 && b2 > 0) {
+      assertEquals(b1, b2);
+      b1 = bitmap.previousValue((int) (b1 - 1));
+      b2 = bitset.previousSetBit(b2 - 1);
+      assertEquals(b1, b2, "mismatch at " + i + "(bitset=" + b2 + ", rb=" + b1 + ")");
+      --i;
+    }
+  }
+
+  @Test
+  public void testPreviousValueRegression() {
+    // see https://github.com/RoaringBitmap/RoaringBitmap/issues/564
+    assertEquals(-1, RoaringBitmap.bitmapOf(27399807).previousValue(403042));
+    assertEquals(-1, RoaringBitmap.bitmapOf().previousValue(403042));
+  }
+
+  @Test
+  public void testPreviousValue_AbsentTargetContainer() {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(-1, 2, 3, 131072);
+    assertEquals(3, bitmap.previousValue(65536));
+    assertEquals(131072, bitmap.previousValue(Integer.MAX_VALUE));
+    assertEquals(131072, bitmap.previousValue(-131072));
+
+    bitmap = RoaringBitmap.bitmapOf(131072);
+    assertEquals(-1, bitmap.previousValue(65536));
+  }
+
+  @Test
+  public void testPreviousValue_LastReturnedAsUnsignedLong() {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOf(-650002, -650001, -650000);
+    assertEquals(Util.toUnsignedLong(-650000), bitmap.previousValue(-1));
+  }
+
+  @Test
+  public void testRangeCardinalityAtBoundary() {
+    // See https://github.com/RoaringBitmap/RoaringBitmap/issues/285
+    RoaringBitmap r = new RoaringBitmap();
+    r.add(66236);
+    assertEquals(1, r.rangeCardinality(60000, 70000));
+  }
+
+  @Test
+  public void testNextValueArray() {
+    RoaringBitmap r = new RoaringBitmap();
+    r.add(0, 1, 2, 4, 6);
+    assertEquals(-1, r.nextValue(7));
+  }
+
+  @Test
+  public void regressionTestEquals370() {
+    // see https://github.com/RoaringBitmap/RoaringBitmap/issues/370
+    int[] a = {
+      239, 240, 241, 242, 243, 244, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 273,
+      274, 275, 276, 277, 278, 398, 399, 400, 401, 402, 403, 404, 405, 406, 408, 409, 410, 411, 412,
+      413, 420, 421, 422, 509, 510, 511, 512, 513, 514, 539, 540, 541, 542, 543, 544, 547, 548, 549,
+      550, 551, 552, 553, 554, 555, 556, 557, 558, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587,
+      588, 589, 590, 591, 592, 593, 594, 595, 624, 625, 634, 635, 636, 649, 650, 651, 652, 653, 654,
+      714, 715, 716, 718, 719, 720, 721, 722, 723, 724, 725, 726, 728, 729, 730, 731, 732, 733, 734,
+      735, 736, 739, 740, 741, 742, 743, 744, 771, 772, 773
+    };
+    int[] b = {
+      239, 240, 241, 242, 243, 244, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 273,
+      274, 275, 276, 277, 278, 398, 399, 400, 401, 402, 403, 404, 405, 406, 408, 409, 410, 411, 412,
+      413, 420, 421, 422, 509, 510, 511, 512, 513, 514, 539, 540, 541, 542, 543, 544, 547, 548, 549,
+      550, 551, 552, 553, 554, 555, 556, 557, 558, 578, 579, 580, 581, 582, 583, 584, 585, 586, 607,
+      608, 634, 635, 636, 649, 650, 651, 652, 653, 654, 714, 715, 716, 718, 719, 720, 721, 722, 723,
+      724, 725, 726, 728, 729, 730, 731, 732, 733, 734, 735, 736, 739, 740, 741, 742, 743, 744, 771,
+      772, 773
+    };
+
+    RoaringBitmap rbA = RoaringBitmap.bitmapOf(a);
+    RoaringBitmap rbB = RoaringBitmap.bitmapOf(b);
+
+    assertNotEquals(rbB, rbA);
+    rbA.runOptimize();
+    assertNotEquals(rbB, rbA);
+    rbB.runOptimize();
+    assertNotEquals(rbB, rbA);
+  }
+
+  @Test
+  public void regressionTestRemove377() {
+    // https://github.com/RoaringBitmap/RoaringBitmap/issues/377
+    RoaringBitmap map = new RoaringBitmap();
+    map.add(0L, 64L);
+    for (int i = 0; i < 64; i++) {
+      if (i != 30 && i != 32) {
+        map.remove(i);
+      }
+    }
+    map.remove(0L, 31L);
+    assertFalse(map.contains(30));
+    assertTrue(map.contains(32));
+  }
+
+  @Test
+  public void invalidCookieBuffer() {
+    assertThrows(
+        IOException.class,
+        () -> {
+          RoaringBitmap bitmap = new RoaringBitmap();
+          bitmap.deserialize(ByteBuffer.allocate(4));
+        });
+  }
+
+  @Test
+  public void invalidCookieDataInput() {
+    assertThrows(
+        IOException.class,
+        () -> {
+          RoaringBitmap bitmap = new RoaringBitmap();
+          bitmap.deserialize(new DataInputStream(new ByteArrayInputStream(new byte[4])));
+        });
+  }
+
+  @Test
+  public void invalidCookieDataInputWithBuffer() {
+    assertThrows(
+        IOException.class,
+        () -> {
+          RoaringBitmap bitmap = new RoaringBitmap();
+          bitmap.deserialize(
+              new DataInputStream(new ByteArrayInputStream(new byte[4])), new byte[8]);
+        });
+  }
+
+  @Test
+  public void testCardinalityExceeds() {
+    RoaringBitmap bitmap = new RoaringBitmap();
+    long runLength = 20_000L;
+    bitmap.add(0L, runLength);
+    for (int i = (1 << 16) + 1; i < 1 << 17; i += 2) {
+      bitmap.add(i);
+    }
+    long bitmapCount = 1 << 15;
+    bitmap.add((1 << 17) | 1);
+    bitmap.add((1 << 17) | 2);
+    bitmap.add((1 << 17) | 3);
+    long arrayCount = 3;
+    bitmap.runOptimize();
+    assertFalse(bitmap.cardinalityExceeds(Integer.MAX_VALUE));
+    assertFalse(bitmap.cardinalityExceeds(runLength + bitmapCount + arrayCount));
+    assertTrue(bitmap.cardinalityExceeds(runLength + bitmapCount + 1));
+    assertTrue(bitmap.cardinalityExceeds(runLength + bitmapCount - 1));
+    assertTrue(bitmap.cardinalityExceeds(runLength - 1));
+  }
+
+  @Test
+  public void testWithYourself() {
+    RoaringBitmap b1 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+    b1.runOptimize();
+    b1.or(b1);
+    assertTrue(b1.equals(RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
+    b1.xor(b1);
+    assertTrue(b1.isEmpty());
+    b1 = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+    b1.and(b1);
+    assertTrue(b1.equals(RoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
+    b1.andNot(b1);
+    assertTrue(b1.isEmpty());
+  }
+
+  @Test
+  public void testIssue566() {
+    RoaringBitmap roaringBitMap = new RoaringBitmap();
+    BitSet bitSet = new BitSet(5000);
+    double prob = 0.001;
+    Random random = new Random();
+    for (int i = 0; i < 5000; i++) {
+      if (random.nextDouble() < prob) {
+        bitSet.set(i);
+        roaringBitMap.add(i);
+      }
+    }
+    long roaringbits = roaringBitMap.getSizeInBytes() * 8;
+    long bitsetbits = bitSet.size();
+    System.out.println("[issue566] cardinality: " + roaringBitMap.getCardinality());
+    System.out.println("[issue566] bitset bits: " + bitsetbits);
+    System.out.println(
+        "[issue566] bitset bits per entry: " + bitsetbits * 1.0 / bitSet.cardinality());
+    System.out.println("[issue566] RoaringBitmap bits: " + roaringbits);
+    System.out.println(
+        "[issue566] RoaringBitmap bits per entry: "
+            + roaringbits * 1.0 / roaringBitMap.getCardinality());
+    assertTrue(roaringbits < bitsetbits);
+  }
+
+  @Test
+  public void issue623() {
+    RoaringBitmap r = new RoaringBitmap();
+    r.add(65535);
+    r.add(65535 + 1);
+    assertTrue(r.contains(65535));
+    assertTrue(r.contains(65535 + 1));
+    assertTrue(r.contains(65535L, 65535L + 1));
+    for (long i = 1; i <= 10_000_000; i++) {
+      r.add(i, i + 1);
+    }
+    for (long i = 1; i <= 10_000_000; i++) {
+      assertTrue(r.contains(i, i + 1));
+    }
+  }
+
+  @Test
+  public void test1235() {
+    RoaringBitmap r = RoaringBitmap.bitmapOf(1, 2, 3, 5);
+    r.flip(4);
+    assertEquals(r, RoaringBitmap.bitmapOf(1, 2, 3, 4, 5));
+  }
+
+  @Test
+  public void test2345() {
+    RoaringBitmap r = RoaringBitmap.bitmapOf(1, 2, 3, 4, 5);
+    r.flip(1);
+    assertEquals(r, RoaringBitmap.bitmapOf(2, 3, 4, 5));
+  }
+
+  @Test
+  public void testSelectRange() {
+    RoaringBitmap r = RoaringBitmap.bitmapOfRange(1, 1000000);
+    for (int i = 1; i <= 1000000; i += 1000) {
+      for (int j = i; j <= 1000000; j += 1000) {
+        RoaringBitmap rr = r.selectRange(i, j);
+        assertEquals(rr, RoaringBitmap.bitmapOfRange(i, j));
+      }
+    }
+  }
+
+  @Test
+  public void testContainerSizeRoaringBitmapMultiple() {
+    RoaringBitmap r = RoaringBitmap.bitmapOfRange(1, 1000000);
+    assertEquals(16, r.getContainerCount());
+  }
+
+  @Test
+  public void testContainerSizeRoaringBitmapSingle() {
+    RoaringBitmap r = RoaringBitmap.bitmapOfRange(1, 100);
+    assertEquals(1, r.getContainerCount());
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapOrNot.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapOrNot.java
similarity index 88%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapOrNot.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapOrNot.java
index 0d40306d2..8d70239d9 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapOrNot.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapOrNot.java
@@ -3,6 +3,11 @@
  */
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.Util.toUnsignedLong;
+
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
@@ -16,9 +21,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.jupiter.api.Assertions.*;
-import static org.roaringbitmap.Util.toUnsignedLong;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestRoaringBitmapOrNot {
 
@@ -30,11 +32,11 @@ public void orNot1() {
     rb.add(2);
     rb.add(1);
     rb.add(1 << 16); // 65536
-    rb.add(2 << 16); //131072
-    rb.add(3 << 16); //196608
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
 
-    rb2.add(1 << 16);// 65536
-    rb2.add(3 << 16);//196608
+    rb2.add(1 << 16); // 65536
+    rb2.add(3 << 16); // 196608
 
     rb.orNot(rb2, (4 << 16) - 1);
 
@@ -56,9 +58,9 @@ public void orNot2() {
 
     rb.add(0);
     rb.add(1 << 16); // 65536
-    rb.add(3 << 16); //196608
+    rb.add(3 << 16); // 196608
 
-    rb2.add((4 << 16) - 1); //262143
+    rb2.add((4 << 16) - 1); // 262143
 
     rb.orNot(rb2, 4 << 16);
 
@@ -79,8 +81,8 @@ public void orNot3() {
     rb.add(2 << 16);
 
     final RoaringBitmap rb2 = new RoaringBitmap();
-    rb2.add(1 << 14); //16384
-    rb2.add(3 << 16); //196608
+    rb2.add(1 << 14); // 16384
+    rb2.add(3 << 16); // 196608
 
     rb.orNot(rb2, (5 << 16));
     assertEquals((5 << 16) - 2, rb.getCardinality());
@@ -101,9 +103,9 @@ public void orNot4() {
     rb.add(1);
 
     final RoaringBitmap rb2 = new RoaringBitmap();
-    rb2.add(3 << 16); //196608
+    rb2.add(3 << 16); // 196608
 
-    rb.orNot(rb2, (2 << 16) + (2 << 14)); //131072 + 32768 = 163840
+    rb.orNot(rb2, (2 << 16) + (2 << 14)); // 131072 + 32768 = 163840
     assertEquals((2 << 16) + (2 << 14), rb.getCardinality());
 
     final IntIterator iterator = rb.getIntIterator();
@@ -120,8 +122,8 @@ public void orNot5() {
 
     rb.add(1);
     rb.add(1 << 16); // 65536
-    rb.add(2 << 16); //131072
-    rb.add(3 << 16); //196608
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
 
     final RoaringBitmap rb2 = new RoaringBitmap();
 
@@ -143,8 +145,8 @@ public void orNot6() {
     rb.add(1);
     rb.add((1 << 16) - 1); // 65535
     rb.add(1 << 16); // 65536
-    rb.add(2 << 16); //131072
-    rb.add(3 << 16); //196608
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
 
     final RoaringBitmap rb2 = new RoaringBitmap();
 
@@ -179,8 +181,8 @@ public void orNot7() {
     final RoaringBitmap rb = new RoaringBitmap();
 
     rb.add(1 << 16); // 65536
-    rb.add(2 << 16); //131072
-    rb.add(3 << 16); //196608
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
 
     final RoaringBitmap rb2 = new RoaringBitmap();
 
@@ -195,7 +197,6 @@ public void orNot7() {
       assertEquals(i, iterator.next(), "Error on iteration " + i);
     }
 
-
     assertTrue(iterator.hasNext());
     assertEquals(1 << 16, iterator.next());
 
@@ -208,16 +209,13 @@ public void orNot7() {
     assertFalse(iterator.hasNext());
   }
 
-
-
   @Test
   public void orNot9() {
     final RoaringBitmap rb1 = new RoaringBitmap();
 
     rb1.add(1 << 16); // 65536
-    rb1.add(2 << 16); //131072
-    rb1.add(3 << 16); //196608
-
+    rb1.add(2 << 16); // 131072
+    rb1.add(3 << 16); // 196608
 
     {
       final RoaringBitmap rb2 = new RoaringBitmap();
@@ -251,7 +249,6 @@ public void orNot9() {
       assertEquals(196608, iterator.next());
     }
 
-
     {
       final RoaringBitmap rb2 = new RoaringBitmap();
       rb2.add((1 << 16) + (1 << 13));
@@ -264,7 +261,9 @@ public void orNot9() {
 
       final IntIterator iterator = answer.getIntIterator();
       for (int i = 0; i < (2 << 16) + 1; ++i) {
-        if ((i != (1 << 16) + (1 << 13)) && (i != (1 << 16) + (1 << 14)) && (i != (1 << 16) + (1 << 15))) {
+        if ((i != (1 << 16) + (1 << 13))
+            && (i != (1 << 16) + (1 << 14))
+            && (i != (1 << 16) + (1 << 15))) {
           assertTrue(iterator.hasNext(), "Error on iteration " + i);
           assertEquals(i, iterator.next(), "Error on iteration " + i);
         }
@@ -338,7 +337,7 @@ public void orNot11() {
 
     RoaringBitmap rb3 = RoaringBitmap.orNot(rb, rb2, 65535L * 65536L + 65524);
 
-    assertEquals((int)(65535L * 65536L + 65523), rb3.last());
+    assertEquals((int) (65535L * 65536L + 65523), rb3.last());
   }
 
   @Test
@@ -354,7 +353,7 @@ public void orNotAgainstFullBitmap() {
   public void orNotNonEmptyAgainstFullBitmap() {
     RoaringBitmap rb = RoaringBitmap.bitmapOf(1, 0x10001, 0x20001);
     RoaringBitmap full = new RoaringBitmap();
-    full.add((long)0, (long)0x40000);
+    full.add((long) 0, (long) 0x40000);
     rb.orNot(full, 0x30000);
     assertEquals(RoaringBitmap.bitmapOf(1, 0x10001, 0x20001), rb);
   }
@@ -373,15 +372,17 @@ public void orNotNonEmptyAgainstFullBitmapStatic() {
     RoaringBitmap rb = RoaringBitmap.bitmapOf(1, 0x10001, 0x20001);
     RoaringBitmap full = new RoaringBitmap();
     full.add(0, 0x40000L);
-    assertEquals(RoaringBitmap.bitmapOf(1, 0x10001, 0x20001), RoaringBitmap.orNot(rb, full, 0x30000L));
+    assertEquals(
+        RoaringBitmap.bitmapOf(1, 0x10001, 0x20001), RoaringBitmap.orNot(rb, full, 0x30000L));
   }
 
   @Test
   @SuppressWarnings("unchecked")
   public void testBigOrNot() throws IOException {
-    byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json"));
+    byte[] bytes =
+        Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json"));
     Map info = new ObjectMapper().readerFor(Map.class).readValue(bytes);
-    List base64Bitmaps = (List)info.get("bitmaps");
+    List base64Bitmaps = (List) info.get("bitmaps");
     ByteBuffer lBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(0)));
     ByteBuffer rBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(1)));
     RoaringBitmap l = new RoaringBitmap();
@@ -400,13 +401,13 @@ public void testBigOrNot() throws IOException {
     assertEquals(expected, actual);
   }
 
-
   @Test
   @SuppressWarnings("unchecked")
   public void testBigOrNotStatic() throws IOException {
-    byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json"));
+    byte[] bytes =
+        Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json"));
     Map info = new ObjectMapper().readerFor(Map.class).readValue(bytes);
-    List base64Bitmaps = (List)info.get("bitmaps");
+    List base64Bitmaps = (List) info.get("bitmaps");
     ByteBuffer lBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(0)));
     ByteBuffer rBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(1)));
     RoaringBitmap l = new RoaringBitmap();
@@ -423,5 +424,4 @@ public void testBigOrNotStatic() throws IOException {
     RoaringBitmap actual = RoaringBitmap.orNot(l, r, limit);
     assertEquals(expected, actual);
   }
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriter.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriter.java
new file mode 100644
index 000000000..205947168
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriter.java
@@ -0,0 +1,323 @@
+package org.roaringbitmap;
+
+import static java.lang.Integer.MAX_VALUE;
+import static java.lang.Integer.MIN_VALUE;
+import static java.lang.Integer.toUnsignedLong;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.RoaringBitmapWriter.bufferWriter;
+import static org.roaringbitmap.RoaringBitmapWriter.writer;
+
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestRoaringBitmapWriter {
+
+  public static Stream params() {
+    return Stream.of(
+        Arguments.of(writer().optimiseForArrays()),
+        Arguments.of(writer().optimiseForRuns()),
+        Arguments.of(writer().constantMemory()),
+        Arguments.of(writer().optimiseForArrays().fastRank()),
+        Arguments.of(writer().optimiseForRuns().fastRank()),
+        Arguments.of(writer().constantMemory().fastRank()),
+        Arguments.of(writer().expectedDensity(0.001)),
+        Arguments.of(writer().expectedDensity(0.01)),
+        Arguments.of(writer().expectedDensity(0.1)),
+        Arguments.of(writer().expectedDensity(0.6)),
+        Arguments.of(writer().expectedDensity(0.001).fastRank()),
+        Arguments.of(writer().expectedDensity(0.01).fastRank()),
+        Arguments.of(writer().expectedDensity(0.1).fastRank()),
+        Arguments.of(writer().expectedDensity(0.6).fastRank()),
+        Arguments.of(writer().initialCapacity(1)),
+        Arguments.of(writer().initialCapacity(8)),
+        Arguments.of(writer().initialCapacity(8192)),
+        Arguments.of(writer().initialCapacity(1).fastRank()),
+        Arguments.of(writer().initialCapacity(8).fastRank()),
+        Arguments.of(writer().initialCapacity(8192).fastRank()),
+        Arguments.of(writer().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE))),
+        Arguments.of(writer().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE))),
+        Arguments.of(writer().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE))),
+        Arguments.of(
+            writer().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank()),
+        Arguments.of(
+            writer().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank()),
+        Arguments.of(
+            writer().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE)).fastRank()),
+        Arguments.of(
+            writer()
+                .optimiseForArrays()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))),
+        Arguments.of(
+            writer()
+                .optimiseForRuns()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))),
+        Arguments.of(
+            writer()
+                .constantMemory()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))),
+        Arguments.of(
+            writer()
+                .optimiseForArrays()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .fastRank()),
+        Arguments.of(
+            writer()
+                .optimiseForRuns()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .fastRank()),
+        Arguments.of(
+            writer()
+                .constantMemory()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .fastRank()),
+        Arguments.of(bufferWriter().optimiseForArrays()),
+        Arguments.of(bufferWriter().optimiseForRuns()),
+        Arguments.of(bufferWriter().constantMemory()),
+        Arguments.of(bufferWriter().expectedDensity(0.001)),
+        Arguments.of(bufferWriter().expectedDensity(0.01)),
+        Arguments.of(bufferWriter().expectedDensity(0.1)),
+        Arguments.of(bufferWriter().expectedDensity(0.6)),
+        Arguments.of(bufferWriter().initialCapacity(1)),
+        Arguments.of(bufferWriter().initialCapacity(8)),
+        Arguments.of(bufferWriter().initialCapacity(8192)),
+        Arguments.of(
+            bufferWriter().optimiseForArrays().expectedRange(0, toUnsignedLong(MIN_VALUE))),
+        Arguments.of(bufferWriter().optimiseForRuns().expectedRange(0, toUnsignedLong(MIN_VALUE))),
+        Arguments.of(bufferWriter().constantMemory().expectedRange(0, toUnsignedLong(MIN_VALUE))),
+        Arguments.of(
+            bufferWriter()
+                .optimiseForArrays()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))),
+        Arguments.of(
+            bufferWriter()
+                .optimiseForRuns()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))),
+        Arguments.of(
+            bufferWriter()
+                .constantMemory()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))),
+        Arguments.of(writer().optimiseForArrays().runCompress(false)),
+        Arguments.of(writer().optimiseForRuns().runCompress(false)),
+        Arguments.of(writer().constantMemory().runCompress(false)),
+        Arguments.of(writer().optimiseForArrays().fastRank().runCompress(false)),
+        Arguments.of(writer().optimiseForRuns().fastRank().runCompress(false)),
+        Arguments.of(writer().constantMemory().fastRank().runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.001).runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.01).runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.1).runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.6).runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.001).fastRank().runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.01).fastRank().runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.1).fastRank().runCompress(false)),
+        Arguments.of(writer().expectedDensity(0.6).fastRank().runCompress(false)),
+        Arguments.of(writer().initialCapacity(1).runCompress(false)),
+        Arguments.of(writer().initialCapacity(8).runCompress(false)),
+        Arguments.of(writer().initialCapacity(8192).runCompress(false)),
+        Arguments.of(writer().initialCapacity(1).fastRank().runCompress(false)),
+        Arguments.of(writer().initialCapacity(8).fastRank().runCompress(false)),
+        Arguments.of(writer().initialCapacity(8192).fastRank().runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForArrays()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForRuns()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .constantMemory()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForArrays()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .fastRank()
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForRuns()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .fastRank()
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .constantMemory()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .fastRank()
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForArrays()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForRuns()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .constantMemory()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForArrays()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .fastRank()
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .optimiseForRuns()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .fastRank()
+                .runCompress(false)),
+        Arguments.of(
+            writer()
+                .constantMemory()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .fastRank()
+                .runCompress(false)),
+        Arguments.of(bufferWriter().optimiseForArrays().runCompress(false)),
+        Arguments.of(bufferWriter().optimiseForRuns().runCompress(false)),
+        Arguments.of(bufferWriter().constantMemory().runCompress(false)),
+        Arguments.of(bufferWriter().expectedDensity(0.001).runCompress(false)),
+        Arguments.of(bufferWriter().expectedDensity(0.01).runCompress(false)),
+        Arguments.of(bufferWriter().expectedDensity(0.1).runCompress(false)),
+        Arguments.of(bufferWriter().expectedDensity(0.6).runCompress(false)),
+        Arguments.of(bufferWriter().initialCapacity(1).runCompress(false)),
+        Arguments.of(bufferWriter().initialCapacity(8).runCompress(false)),
+        Arguments.of(bufferWriter().initialCapacity(8192).runCompress(false)),
+        Arguments.of(
+            bufferWriter()
+                .optimiseForArrays()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            bufferWriter()
+                .optimiseForRuns()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            bufferWriter()
+                .constantMemory()
+                .expectedRange(0, toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            bufferWriter()
+                .optimiseForArrays()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            bufferWriter()
+                .optimiseForRuns()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .runCompress(false)),
+        Arguments.of(
+            bufferWriter()
+                .constantMemory()
+                .expectedRange(toUnsignedLong(MAX_VALUE), toUnsignedLong(MIN_VALUE))
+                .runCompress(false)));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void addInReverseOrder(
+      Supplier> supplier) {
+    RoaringBitmapWriter writer = supplier.get();
+    writer.add(1 << 17);
+    writer.add(0);
+    writer.flush();
+    assertArrayEquals(
+        RoaringBitmap.bitmapOf(0, 1 << 17).toArray(), writer.getUnderlying().toArray());
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void bitmapShouldContainAllValuesAfterFlush(
+      Supplier> supplier) {
+    RoaringBitmapWriter writer = supplier.get();
+    writer.add(0);
+    writer.add(1 << 17);
+    writer.flush();
+    assertTrue(writer.getUnderlying().contains(0));
+    assertTrue(writer.getUnderlying().contains(1 << 17));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void newKeyShouldTriggerFlush(
+      Supplier> supplier) {
+    RoaringBitmapWriter writer = supplier.get();
+    writer.add(0);
+    writer.add(1 << 17);
+    assertTrue(writer.getUnderlying().contains(0));
+    writer.add(1 << 18);
+    assertTrue(writer.getUnderlying().contains(1 << 17));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void writeSameKeyAfterManualFlush(
+      Supplier> supplier) {
+    RoaringBitmapWriter writer = supplier.get();
+    writer.add(0);
+    writer.flush();
+    writer.add(1);
+    writer.flush();
+    assertArrayEquals(RoaringBitmap.bitmapOf(0, 1).toArray(), writer.getUnderlying().toArray());
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void writeRange(Supplier> supplier) {
+    RoaringBitmapWriter writer = supplier.get();
+    writer.add(0);
+    writer.add(65500L, 65600L);
+    writer.add(1);
+    writer.add(65610);
+    writer.flush();
+    RoaringBitmap expected = RoaringBitmap.bitmapOf(0, 1, 65610);
+    expected.add(65500L, 65600L);
+    assertArrayEquals(expected.toArray(), writer.getUnderlying().toArray());
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void testWriteToMaxKeyAfterFlush(
+      Supplier> supplier) {
+    RoaringBitmapWriter writer = supplier.get();
+    writer.add(0);
+    writer.add(-2);
+    writer.flush();
+    assertArrayEquals(RoaringBitmap.bitmapOf(0, -2).toArray(), writer.get().toArray());
+    writer.add(-1);
+    assertArrayEquals(RoaringBitmap.bitmapOf(0, -2, -1).toArray(), writer.get().toArray());
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void testWriteBitmapAfterReset(
+      Supplier> supplier) {
+    RoaringBitmapWriter writer = supplier.get();
+    writer.add(0);
+    writer.add(-2);
+    assertArrayEquals(new int[] {0, -2}, writer.get().toArray());
+    writer.reset();
+    writer.add(100);
+    writer.addMany(4, 5, 6);
+    assertArrayEquals(new int[] {4, 5, 6, 100}, writer.get().toArray());
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriterWizard.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriterWizard.java
similarity index 60%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriterWizard.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriterWizard.java
index 6110d471c..e31a4f342 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriterWizard.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmapWriterWizard.java
@@ -1,11 +1,14 @@
 package org.roaringbitmap;
 
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.roaringbitmap.RoaringBitmapWriter.bufferWriter;
 import static org.roaringbitmap.RoaringBitmapWriter.writer;
 
+import org.junit.jupiter.api.Test;
+
 public class TestRoaringBitmapWriterWizard {
 
   @Test
@@ -20,13 +23,13 @@ public void whenFastRankIsSelectedWizardCreatesFastRankRoaringBitmap() {
 
   @Test
   public void whenFastRankIsSelectedBufferWizardThrows() {
-    assertThrows(IllegalStateException.class,
-            () -> bufferWriter().fastRank().get().getUnderlying());
+    assertThrows(
+        IllegalStateException.class, () -> bufferWriter().fastRank().get().getUnderlying());
   }
 
   @Test
   public void shouldRespectProvidedStorageSizeHint() {
-    assertEquals(20, writer().initialCapacity(20).get().getUnderlying().highLowContainer.keys.length);
+    assertEquals(
+        20, writer().initialCapacity(20).get().getUnderlying().highLowContainer.keys.length);
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap_FastRank.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap_FastRank.java
similarity index 92%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap_FastRank.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap_FastRank.java
index 3dd0b8652..95138d6b8 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap_FastRank.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRoaringBitmap_FastRank.java
@@ -3,6 +3,10 @@
  */
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
@@ -10,9 +14,6 @@
 
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.*;
-
-
 /**
  * Check FastRankRoaringBitmap dismiss the caches cardinalities when necessary
  */
@@ -131,7 +132,6 @@ public void addSmallAddNegativeRemoveSmall() {
     assertEquals(1, b.rank(-234 + 1));
   }
 
-
   @Test
   public void addSmallAddNegativeRemoveNegative() {
     FastRankRoaringBitmap b = new FastRankRoaringBitmap();
@@ -185,7 +185,6 @@ public void addManyRandomlyThenRemoveAllRandomly() {
     for (int i = 0; i < nbReallyAdded; i++) {
       int selected = b.select(r.nextInt(nbReallyAdded - i));
       b.remove(selected);
-
     }
     assertEquals(0, b.getLongCardinality());
   }
@@ -236,10 +235,12 @@ public void rankOnEmpty() {
 
   @Test
   public void selectOnEmpty() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      FastRankRoaringBitmap b = new FastRankRoaringBitmap();
-      b.select(0);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          FastRankRoaringBitmap b = new FastRankRoaringBitmap();
+          b.select(0);
+        });
   }
 
   @Test
@@ -265,8 +266,8 @@ public void performanceTest_MixedAddRemove_LargeInts() {
     long timeNormal = System.currentTimeMillis() - startNormal;
 
     // Mixed workload: "fast" is expected slower as it recomputer cardinality regularly
-    System.out
-        .println("AddSelectRemoveAreMixed LargeInts FastRankRoaringBitmap=" + timeFast + "ms");
+    System.out.println(
+        "AddSelectRemoveAreMixed LargeInts FastRankRoaringBitmap=" + timeFast + "ms");
     System.out.println("AddSelectRemoveAreMixed LargeInts RoaringBitmap=" + timeNormal + "ms");
   }
 
@@ -293,8 +294,8 @@ public void performanceTest_MixedAddRemove_SmallInts() {
     long timeNormal = System.currentTimeMillis() - startNormal;
 
     // Mixed workload: "fast" is expected slower as it recomputes cardinality regularly
-    System.out
-        .println("AddSelectRemoveAreMixed SmallInts FastRankRoaringBitmap=" + timeFast + "ms");
+    System.out.println(
+        "AddSelectRemoveAreMixed SmallInts FastRankRoaringBitmap=" + timeFast + "ms");
     System.out.println("AddSelectRemoveAreMixed SmallInts RoaringBitmap=" + timeNormal + "ms");
   }
 
@@ -341,8 +342,6 @@ public void performanceTest_AddManyThenSelectMany() {
     System.out.println("AddOnlyThenSelectOnly RoaringBitmap=" + timeNormal + "ms");
   }
 
-
-
   private FastRankRoaringBitmap prepareFastWithComputedCache() {
     FastRankRoaringBitmap fast = new FastRankRoaringBitmap();
 
@@ -496,16 +495,16 @@ public void testLongSizeInBytes() {
 
     // Check when empty
     assertEquals(16, fast.getLongSizeInBytes());
-    
+
     fast.add(0);
     fast.add(1024);
     fast.add(Integer.MAX_VALUE);
 
     assertEquals(34, fast.getLongSizeInBytes());
-    
+
     // Compute a rank: the cache is allocated
     fast.rank(1024);
-    
+
     // Check the size is bigger once the cache is allocated
     assertEquals(42, fast.getLongSizeInBytes());
   }
@@ -529,15 +528,22 @@ public void testSelectExceptionOutOfBounds() {
     roaringBitmap.add(3);
     roaringBitmap.add(5);
     assertEquals(5, roaringBitmap.select(roaringBitmap.getCardinality() - 1));
-    assertThrows(IllegalArgumentException.class, () -> roaringBitmap.select(roaringBitmap.getCardinality()));
-    assertThrows(IllegalArgumentException.class, () -> roaringBitmap.select(roaringBitmap.getCardinality() + 1));
+    assertThrows(
+        IllegalArgumentException.class, () -> roaringBitmap.select(roaringBitmap.getCardinality()));
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> roaringBitmap.select(roaringBitmap.getCardinality() + 1));
 
     // FastRankRoaringBitmap behavior has to be identical
     FastRankRoaringBitmap rankRoaringBitmap = new FastRankRoaringBitmap();
     rankRoaringBitmap.add(3);
     rankRoaringBitmap.add(5);
     assertEquals(5, rankRoaringBitmap.select(rankRoaringBitmap.getCardinality() - 1));
-    assertThrows(IllegalArgumentException.class, () -> rankRoaringBitmap.select(rankRoaringBitmap.getCardinality()));
-    assertThrows(IllegalArgumentException.class, () -> rankRoaringBitmap.select(rankRoaringBitmap.getCardinality() + 1));
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> rankRoaringBitmap.select(rankRoaringBitmap.getCardinality()));
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> rankRoaringBitmap.select(rankRoaringBitmap.getCardinality() + 1));
   }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestRunContainer.java
similarity index 86%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestRunContainer.java
index 3b376f5d3..ab346c43d 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestRunContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestRunContainer.java
@@ -1,6 +1,16 @@
 package org.roaringbitmap;
 
-import org.assertj.core.api.Assertions;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.ArrayContainer.DEFAULT_MAX_SIZE;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
+
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -9,30 +19,32 @@
 import java.io.ByteArrayOutputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.roaringbitmap.ArrayContainer.DEFAULT_MAX_SIZE;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
 
 @Execution(ExecutionMode.CONCURRENT)
 public class TestRunContainer {
   @Test
   public void testRunOpti() {
     RoaringBitmap mrb = new RoaringBitmap();
-    for(int r = 0; r< 100000; r+=3 ) {
+    for (int r = 0; r < 100000; r += 3) {
       mrb.add(r);
     }
     mrb.add(1000000);
-    for(int r = 2000000; r < 3000000; ++r) {
+    for (int r = 2000000; r < 3000000; ++r) {
       mrb.add(r);
     }
     RoaringBitmap m2 = mrb.clone();
     m2.runOptimize();
     IntIterator x = m2.getReverseIntIterator();
     int count = 0;
-    while(x.hasNext()) {
+    while (x.hasNext()) {
       x.next();
       count++;
     }
@@ -79,8 +91,8 @@ static int[] generateUniformHash(Random rand, int N, int Max) {
     return ans;
   }
 
-  private static void getSetOfRunContainers(ArrayList set,
-      ArrayList setb) {
+  private static void getSetOfRunContainers(
+      ArrayList set, ArrayList setb) {
     RunContainer r1 = new RunContainer();
     r1 = (RunContainer) r1.iadd(0, (1 << 16));
     Container b1 = new ArrayContainer();
@@ -140,7 +152,6 @@ private static void getSetOfRunContainers(ArrayList set,
     set.add(r6);
     setb.add(b6);
 
-
     RunContainer r7 = new RunContainer();
     Container b7 = new ArrayContainer();
     for (int k = 0; k + 1 < 65536; k += 11) {
@@ -150,7 +161,6 @@ private static void getSetOfRunContainers(ArrayList set,
     assertEquals(r7, b7);
     set.add(r7);
     setb.add(b7);
-
   }
 
   /**
@@ -579,7 +589,6 @@ public void equalTest2() {
     assertEquals(ac, ar);
   }
 
-
   @Test
   public void fillLeastSignificantBits() {
     Container rc = new RunContainer();
@@ -594,8 +603,6 @@ public void fillLeastSignificantBits() {
     assertEquals(12, array[3]);
   }
 
-
-
   @Test
   public void flip() {
     RunContainer rc = new RunContainer();
@@ -605,23 +612,24 @@ public void flip() {
     assertFalse(rc.contains((char) 1));
   }
 
-
   @Test
   public void iaddInvalidRange1() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container rc = new RunContainer();
-      rc.iadd(10, 9);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container rc = new RunContainer();
+          rc.iadd(10, 9);
+        });
   }
 
-
-
   @Test
   public void iaddInvalidRange2() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container rc = new RunContainer();
-      rc.iadd(0, 1 << 20);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container rc = new RunContainer();
+          rc.iadd(0, 1 << 20);
+        });
   }
 
   @Test
@@ -879,7 +887,6 @@ public void iaddRange7() {
     assertEquals(16, rc.getSizeInBytes());
   }
 
-
   @Test
   public void iaddRange8() {
     Container rc = new RunContainer();
@@ -903,8 +910,6 @@ public void iaddRange8() {
     assertEquals(12, rc.getSizeInBytes());
   }
 
-
-
   @Test
   public void iaddRangeAndFuseWithPreviousValueLength() {
     RunContainer container = new RunContainer();
@@ -919,7 +924,6 @@ public void iaddRangeAndFuseWithPreviousValueLength() {
     assertEquals(8, container.getSizeInBytes());
   }
 
-
   @Test
   public void iaddRangeOnNonEmptyContainerAndFuse() {
     RunContainer container = new RunContainer();
@@ -936,7 +940,6 @@ public void iaddRangeOnNonEmptyContainerAndFuse() {
     }
   }
 
-
   @Test
   public void iaddRangeWithinSetBounds() {
     RunContainer container = new RunContainer();
@@ -1043,8 +1046,6 @@ public void inot12A() {
     }
   }
 
-
-
   @Test
   public void inot13() {
     RunContainer container = new RunContainer();
@@ -1100,7 +1101,6 @@ private void inot14once(int num, int rangeSize) {
     for (int i = 0; i < 65536; ++i) {
       assertFalse(result.contains((char) i) ^ checker.get(i));
     }
-
   }
 
   @Test
@@ -1147,8 +1147,6 @@ public void inot3() {
     }
   }
 
-
-
   @Test
   public void inot4() {
     RunContainer container = new RunContainer();
@@ -1166,7 +1164,6 @@ public void inot4() {
     }
   }
 
-
   @Test
   public void inot5() {
     RunContainer container = new RunContainer();
@@ -1200,7 +1197,6 @@ public void inot6() {
     }
   }
 
-
   @Test
   public void inot7() {
     RunContainer container = new RunContainer();
@@ -1211,7 +1207,6 @@ public void inot7() {
     container.add((char) 504);
     container.add((char) 505);
 
-
     // one run, spans the range
     Container result = container.inot(502, 504);
 
@@ -1335,6 +1330,7 @@ public void ior2() {
     rc.ior(ac);
     assertEquals(512, rc.getCardinality());
   }
+
   @Test
   public void iorNot() {
     Container rc1 = new RunContainer();
@@ -1483,7 +1479,6 @@ public void orNot() {
 
       assertFalse(iterator.hasNext());
     }
-
   }
 
   @Test
@@ -1751,18 +1746,22 @@ public void iremove9() {
 
   @Test
   public void iremoveInvalidRange1() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container rc = new RunContainer();
-      rc.iremove(10, 9);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container rc = new RunContainer();
+          rc.iremove(10, 9);
+        });
   }
 
   @Test
   public void iremoveInvalidRange2() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Container rc = new RunContainer();
-      rc.remove(0, 1 << 20);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Container rc = new RunContainer();
+          rc.remove(0, 1 << 20);
+        });
   }
 
   @Test
@@ -1803,7 +1802,7 @@ public void iremoveRange() {
   public void iremoveEmptyRange() {
     RunContainer container = new RunContainer();
     assertEquals(0, container.getCardinality());
-    container.iremove(0,0);
+    container.iremove(0, 0);
     assertEquals(0, container.getCardinality());
   }
 
@@ -1942,7 +1941,6 @@ public void not11() {
     }
   }
 
-
   @Test
   public void not12() {
     RunContainer container = new RunContainer();
@@ -1966,7 +1964,6 @@ public void not12() {
     }
   }
 
-
   @Test
   public void not12A() {
     RunContainer container = new RunContainer();
@@ -2000,7 +1997,6 @@ public void not13() {
     }
   }
 
-
   @Test
   public void not14() {
     not14once(10, 1);
@@ -2015,7 +2011,6 @@ public void not14() {
     }
   }
 
-
   private void not14once(int num, int rangeSize) {
     RunContainer container = new RunContainer();
     BitSet checker = new BitSet();
@@ -2038,10 +2033,8 @@ private void not14once(int num, int rangeSize) {
     for (int i = 0; i < 65536; ++i) {
       assertFalse(result.contains((char) i) ^ checker.get(i));
     }
-
   }
 
-
   @Test
   public void not15() {
     RunContainer container = new RunContainer();
@@ -2059,7 +2052,6 @@ public void not15() {
     assertTrue(result instanceof RunContainer);
   }
 
-
   @Test
   public void not2() {
     RunContainer container = new RunContainer();
@@ -2076,7 +2068,6 @@ public void not2() {
     }
   }
 
-
   @Test
   public void not3() {
     RunContainer container = new RunContainer();
@@ -2105,7 +2096,6 @@ public void not4() {
     }
   }
 
-
   @Test
   public void not5() {
     RunContainer container = new RunContainer();
@@ -2123,8 +2113,6 @@ public void not5() {
     }
   }
 
-
-
   @Test
   public void not6() {
     RunContainer container = new RunContainer();
@@ -2151,7 +2139,6 @@ public void not7() {
     container.add((char) 504);
     container.add((char) 505);
 
-
     // one run, spans the range
     Container result = container.not(502, 504);
 
@@ -2161,8 +2148,6 @@ public void not7() {
     }
   }
 
-
-
   @Test
   public void not8() {
     RunContainer container = new RunContainer();
@@ -2183,8 +2168,6 @@ public void not8() {
     }
   }
 
-
-
   @Test
   public void not9() {
     RunContainer container = new RunContainer();
@@ -2204,8 +2187,6 @@ public void not9() {
     }
   }
 
-
-
   @Test
   public void randomFun() {
     final int bitsetperword1 = 32;
@@ -2218,7 +2199,6 @@ public void randomFun() {
     int[] values1 = generateUniformHash(rand, bitsetperword1 * howmanywords, max);
     int[] values2 = generateUniformHash(rand, bitsetperword2 * howmanywords, max);
 
-
     rc1 = new RunContainer();
     rc1 = fillMeUp(rc1, values1);
 
@@ -2254,7 +2234,6 @@ public void randomFun() {
     if (!rc1.xor(rc2).equals(ac1.xor(ac2))) {
       throw new RuntimeException("xors do not match");
     }
-
   }
 
   @Test
@@ -2281,7 +2260,6 @@ public void charRangeRank() {
     assertEquals(16, container.rank((char) 32));
   }
 
-
   @Test
   public void remove() {
     Container rc = new RunContainer();
@@ -2290,8 +2268,6 @@ public void remove() {
     assertEquals(0, newContainer.getCardinality());
   }
 
-
-
   @Test
   public void RunContainerArg_ArrayAND() {
     boolean atLeastOneArray = false;
@@ -2316,8 +2292,6 @@ public void RunContainerArg_ArrayAND() {
     assertTrue(atLeastOneArray);
   }
 
-
-
   @Test
   public void RunContainerArg_ArrayANDNOT() {
     boolean atLeastOneArray = false;
@@ -2346,22 +2320,24 @@ public void RunContainerArg_ArrayANDNOT() {
 
   @Test
   public void RunContainerArg_ArrayANDNOT2() {
-    ArrayContainer ac = new ArrayContainer(12, new char[]{0, 2, 4, 8, 10, 15, 16, 48, 50, 61, 80, (char)-2});
-    RunContainer rc = new RunContainer(new char[]{7, 3, 17, 2, 20, 3, 30, 3, 36, 6, 60, 5, (char)-3, 2}, 7);
-    assertEquals(new ArrayContainer(8, new char[]{0, 2, 4, 15, 16, 48, 50, 80}), ac.andNot(rc));
+    ArrayContainer ac =
+        new ArrayContainer(12, new char[] {0, 2, 4, 8, 10, 15, 16, 48, 50, 61, 80, (char) -2});
+    RunContainer rc =
+        new RunContainer(new char[] {7, 3, 17, 2, 20, 3, 30, 3, 36, 6, 60, 5, (char) -3, 2}, 7);
+    assertEquals(new ArrayContainer(8, new char[] {0, 2, 4, 15, 16, 48, 50, 80}), ac.andNot(rc));
   }
 
   @Test
   public void FullRunContainerArg_ArrayANDNOT2() {
-    ArrayContainer ac = new ArrayContainer(1, new char[]{3});
+    ArrayContainer ac = new ArrayContainer(1, new char[] {3});
     Container rc = RunContainer.full();
     assertEquals(new ArrayContainer(), ac.andNot(rc));
   }
 
   @Test
   public void RunContainerArg_ArrayANDNOT3() {
-    ArrayContainer ac = new ArrayContainer(1, new char[]{5});
-    Container rc = new RunContainer(new char[]{3, 10}, 1);
+    ArrayContainer ac = new ArrayContainer(1, new char[] {5});
+    Container rc = new RunContainer(new char[] {3, 10}, 1);
     assertEquals(new ArrayContainer(), ac.andNot(rc));
   }
 
@@ -2416,7 +2392,6 @@ public void RunContainerArg_ArrayXOR() {
     assertTrue(atLeastOneArray);
   }
 
-
   @Test
   public void RunContainerFromBitmap() {
     Container rc = new RunContainer();
@@ -2446,13 +2421,11 @@ public void RunContainerFromBitmap() {
     assertEquals(rc, rc2);
   }
 
-
   @Test
   public void RunContainerFromBitmap1() {
     Container rc = new RunContainer();
     Container bc = new BitmapContainer();
 
-
     rc = rc.add((char) 2);
     bc = bc.add((char) 2);
     rc = rc.add((char) 3);
@@ -2479,7 +2452,6 @@ public void RunContainerFromBitmap1() {
     assertEquals(rc, rc2);
   }
 
-
   @Test
   public void RunContainerFromBitmap2() {
     Container rc = new RunContainer();
@@ -2509,12 +2481,10 @@ public void RunContainerFromBitmap2() {
     rc = rc.add((char) 65535);
     bc = bc.add((char) 65535);
 
-
     RunContainer rc2 = new RunContainer((BitmapContainer) bc, ((RunContainer) rc).nbrruns);
     assertEquals(rc, rc2);
   }
 
-
   @Test
   public void RunContainerFromBitmap3() {
     Container rc = new RunContainer();
@@ -2564,7 +2534,6 @@ public void RunContainerVSRunContainerAND() {
     }
   }
 
-
   @Test
   public void RunContainerVSRunContainerANDNOT() {
     ArrayList set = new ArrayList();
@@ -2581,8 +2550,6 @@ public void RunContainerVSRunContainerANDNOT() {
     }
   }
 
-
-
   @Test
   public void RunContainerVSRunContainerOR() {
     ArrayList set = new ArrayList();
@@ -2615,8 +2582,6 @@ public void RunContainerVSRunContainerXOR() {
     }
   }
 
-
-
   @Test
   public void safeor() {
     Container rc1 = new RunContainer();
@@ -2682,8 +2647,6 @@ public void safeSerialization() throws Exception {
     assertEquals(container.serializedSizeInBytes(), newContainer.serializedSizeInBytes());
   }
 
-
-
   @Test
   public void select() {
     RunContainer container = new RunContainer();
@@ -2701,13 +2664,15 @@ public void select() {
 
   @Test
   public void select2() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      RunContainer container = new RunContainer();
-      container.add((char) 0);
-      container.add((char) 3);
-      container.add((char) 118);
-      container.select(666);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          RunContainer container = new RunContainer();
+          container.add((char) 0);
+          container.add((char) 3);
+          container.add((char) 118);
+          container.select(666);
+        });
   }
 
   @Test
@@ -2724,11 +2689,12 @@ public void simpleIterator() {
     assertFalse(i.hasNext());
   }
 
-
   @Test
   public void testAndNot() {
-    int[] array1 = {39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183,
-        39184, 39185, 39186, 39187, 39188};
+    int[] array1 = {
+      39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183, 39184, 39185,
+      39186, 39187, 39188
+    };
     int[] array2 = {14205};
     RoaringBitmap rb1 = RoaringBitmap.bitmapOf(array1);
     rb1.runOptimize();
@@ -2737,8 +2703,6 @@ public void testAndNot() {
     assertEquals(answer.getCardinality(), array1.length);
   }
 
-
-
   @Test
   public void testRoaringWithOptimize() {
     // create the same bitmap over and over again, with optimizing it
@@ -2756,7 +2720,6 @@ public void testRoaringWithOptimize() {
     assertEquals(1, setWithOptimize.size());
   }
 
-
   @Test
   public void testRoaringWithoutOptimize() {
     // create the same bitmap over and over again, without optimizing it
@@ -2810,7 +2773,6 @@ public void union() {
     assertEquals(100, rc.getCardinality());
   }
 
-
   @Test
   public void union2() {
     System.out.println("union2");
@@ -2830,7 +2792,6 @@ public void union2() {
     assertEquals(100, rc.getCardinality());
   }
 
-
   @Test
   public void xor() {
     Container bc = new BitmapContainer();
@@ -2851,7 +2812,6 @@ public void xor() {
     assertEquals(4 * DEFAULT_MAX_SIZE, rc.getCardinality());
   }
 
-
   @Test
   public void xor_array() {
     Container bc = new ArrayContainer();
@@ -2872,8 +2832,6 @@ public void xor_array() {
     assertEquals(4 * DEFAULT_MAX_SIZE, rc.getCardinality());
   }
 
-
-
   @Test
   public void xor_array_largecase_runcontainer_best() {
     Container bc = new ArrayContainer();
@@ -2914,7 +2872,6 @@ public void xor_array_largecase_runcontainer_best() {
     }
   }
 
-
   @Test
   public void xor_array_mediumcase() {
     Container bc = new ArrayContainer();
@@ -2962,7 +2919,6 @@ public void xor_array_mediumcase() {
     }
   }
 
-
   @Test
   public void xor_array_smallcase() {
     Container bc = new ArrayContainer();
@@ -2983,7 +2939,6 @@ public void xor_array_smallcase() {
     int rcSize = rc.getCardinality();
     int bcSize = bc.getCardinality();
 
-
     Container result = rc.xor(bc);
 
     // input containers should not change (just check card)
@@ -2994,7 +2949,6 @@ public void xor_array_smallcase() {
     assertTrue(result.contains((char) 5));
     assertTrue(result.contains((char) 0));
 
-
     for (int k = 1; k < DEFAULT_MAX_SIZE / 3; ++k) {
       for (int i = 0; i < 5; ++i) {
         assertTrue(result.contains((char) (k * 10 + i)));
@@ -3022,7 +2976,6 @@ public void xor1a() {
     assertTrue(result.contains((char) 1));
   }
 
-
   @Test
   public void xor2() {
     Container bc = new BitmapContainer();
@@ -3033,7 +2986,6 @@ public void xor2() {
     assertTrue(result.contains((char) 1));
   }
 
-
   @Test
   public void xor2a() {
     Container bc = new ArrayContainer();
@@ -3044,7 +2996,6 @@ public void xor2a() {
     assertTrue(result.contains((char) 1));
   }
 
-
   @Test
   public void xor3() {
     Container bc = new BitmapContainer();
@@ -3055,8 +3006,6 @@ public void xor3() {
     assertEquals(0, result.getCardinality());
   }
 
-
-
   @Test
   public void xor3a() {
     Container bc = new ArrayContainer();
@@ -3067,8 +3016,6 @@ public void xor3a() {
     assertEquals(0, result.getCardinality());
   }
 
-
-
   @Test
   public void xor4() {
     Container bc = new ArrayContainer();
@@ -3112,12 +3059,12 @@ public void intersects1() {
     assertFalse(ac.intersects(rc));
 
     rc = rc.remove((char) 1000);
-    rc = rc.add(100,200);
-    rc = rc.add(300,500);
+    rc = rc.add(100, 200);
+    rc = rc.add(300, 500);
     assertFalse(rc.intersects(ac));
     assertFalse(ac.intersects(rc));
 
-    rc = rc.add(500,1000);
+    rc = rc.add(500, 1000);
     assertTrue(rc.intersects(ac));
     assertTrue(ac.intersects(rc));
   }
@@ -3156,7 +3103,7 @@ public void intersects3() {
 
   @Test
   public void constructor1() {
-    assertThrows(RuntimeException.class, () -> new RunContainer(new char[]{1, 2, 10, 3}, 5));
+    assertThrows(RuntimeException.class, () -> new RunContainer(new char[] {1, 2, 10, 3}, 5));
   }
 
   @Test
@@ -3165,14 +3112,14 @@ public void ensureCapacity() {
     rc.add((char) 13);
     assertTrue(rc.contains((char) 13));
 
-    rc.ensureCapacity(10);
+    rc.ensureCapacity(0, 10);
     assertTrue(rc.contains((char) 13));
   }
 
   @Test
   public void testToString() {
     Container rc = new RunContainer(32200, 35000);
-    rc.add((char)-1);
+    rc.add((char) -1);
     assertEquals("[32200,34999][65535,65535]", rc.toString());
   }
 
@@ -3191,9 +3138,9 @@ public void lazyIOR() {
     assertEquals(13, rc.getCardinality());
 
     rc = new RunContainer();
-    rc = rc.add(0, 1<<16);
+    rc = rc.add(0, 1 << 16);
     rc = rc.lazyIOR(ac);
-    assertEquals(1<<16, rc.getCardinality());
+    assertEquals(1 << 16, rc.getCardinality());
   }
 
   @Test
@@ -3211,9 +3158,9 @@ public void lazyOR() {
     assertEquals(13, rc.getCardinality());
 
     rc = new RunContainer();
-    rc = rc.add(0, 1<<16);
+    rc = rc.add(0, 1 << 16);
     rc = rc.lazyOR(ac);
-    assertEquals(1<<16, rc.getCardinality());
+    assertEquals(1 << 16, rc.getCardinality());
   }
 
   @Test
@@ -3251,7 +3198,7 @@ public void testLazyORFull3() {
   @Test
   public void testRangeCardinality() {
     BitmapContainer bc = TestBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     Container result = rc.or(bc);
     assertEquals(8677, result.getCardinality());
   }
@@ -3259,9 +3206,9 @@ public void testRangeCardinality() {
   @Test
   public void testRangeCardinality2() {
     BitmapContainer bc = TestBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    bc.add((char)22345); //important case to have greater element than run container
-    bc.add((char)Short.MAX_VALUE);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 18000}, 3);
+    bc.add((char) 22345); // important case to have greater element than run container
+    bc.add((char) Short.MAX_VALUE);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 18000}, 3);
     assertTrue(rc.getCardinality() > ArrayContainer.DEFAULT_MAX_SIZE);
     Container result = rc.andNot(bc);
     assertEquals(11437, result.getCardinality());
@@ -3270,7 +3217,7 @@ public void testRangeCardinality2() {
   @Test
   public void testRangeCardinality3() {
     BitmapContainer bc = TestBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 5200}, 3);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 5200}, 3);
     BitmapContainer result = (BitmapContainer) rc.and(bc);
     assertEquals(5046, result.getCardinality());
   }
@@ -3278,7 +3225,7 @@ public void testRangeCardinality3() {
   @Test
   public void testRangeCardinality4() {
     BitmapContainer bc = TestBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    RunContainer rc = new RunContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    RunContainer rc = new RunContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     BitmapContainer result = (BitmapContainer) rc.xor(bc);
     assertEquals(6031, result.getCardinality());
   }
@@ -3323,48 +3270,75 @@ public void testContainsBitmapContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsBitmapContainer_IncludeProperSubset() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new BitmapContainer().add(0,9);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(0, 9);
     assertTrue(rc.contains(subset));
   }
 
-
   @Test
   public void testContainsBitmapContainer_IncludeProperSubsetDifferentStart() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new BitmapContainer().add(1,9);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(1, 9);
+    assertTrue(rc.contains(subset));
+  }
+
+  @Test
+  public void testContainsBitmapContainer_IncludeProperSubsetMultiWordRun() {
+    Container rc = new RunContainer().add(0, 80);
+    Container subset = new BitmapContainer().add(0, 79);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsBitmapContainer_ExcludeShiftedSet() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new BitmapContainer().add(2,12);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(2, 12);
     assertFalse(rc.contains(subset));
   }
 
   @Test
   public void testContainsBitmapContainer_IncludeSelf() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new BitmapContainer().add(0,10);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new BitmapContainer().add(0, 10);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsBitmapContainer_ExcludeSuperSet() {
-    Container rc = new RunContainer().add(0,10);
-    Container superset = new BitmapContainer().add(0,20);
+    Container rc = new RunContainer().add(0, 10);
+    Container superset = new BitmapContainer().add(0, 20);
     assertFalse(rc.contains(superset));
   }
 
   @Test
   public void testContainsBitmapContainer_ExcludeDisJointSet() {
-    Container rc = new RunContainer().add(0,10);
+    Container rc = new RunContainer().add(0, 10);
     Container disjoint = new BitmapContainer().add(20, 40);
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
   }
 
+  @Test
+  public void testContainsBitmapContainer_Issue721Case1() {
+    Container rc = new RunContainer().add(0, 60).add(63, 64).add(66, 67);
+    Container subset = new BitmapContainer().add(63, 64);
+    assertTrue(rc.contains(subset));
+  }
+
+  @Test
+  public void testContainsBitmapContainer_Issue721Case2() {
+    Container rc = new RunContainer().add(0, 10).add(12, 13);
+    Container disjoint = new BitmapContainer().add(11, 12);
+    assertFalse(rc.contains(disjoint));
+  }
+
+  @Test
+  public void testContainsBitmapContainer_SkipEmptyWords() {
+    Container rc = new RunContainer().add(128, 512);
+    Container subset = new BitmapContainer().add(256, 320);
+    assertTrue(rc.contains(subset));
+  }
+
   @Test
   public void testContainsRunContainer_EmptyContainsEmpty() {
     Container rc = new RunContainer();
@@ -3374,42 +3348,42 @@ public void testContainsRunContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsRunContainer_IncludeProperSubset() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new RunContainer().add(0,9);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new RunContainer().add(0, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsRunContainer_IncludeSelf() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new RunContainer().add(0,10);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new RunContainer().add(0, 10);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsRunContainer_ExcludeSuperSet() {
-    Container rc = new RunContainer().add(0,10);
-    Container superset = new RunContainer().add(0,20);
+    Container rc = new RunContainer().add(0, 10);
+    Container superset = new RunContainer().add(0, 20);
     assertFalse(rc.contains(superset));
   }
 
   @Test
   public void testContainsRunContainer_IncludeProperSubsetDifferentStart() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new RunContainer().add(1,9);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new RunContainer().add(1, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsRunContainer_ExcludeShiftedSet() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new RunContainer().add(2,12);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new RunContainer().add(2, 12);
     assertFalse(rc.contains(subset));
   }
 
   @Test
   public void testContainsRunContainer_ExcludeDisJointSet() {
-    Container rc = new RunContainer().add(0,10);
+    Container rc = new RunContainer().add(0, 10);
     Container disjoint = new RunContainer().add(20, 40);
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
@@ -3424,36 +3398,36 @@ public void testContainsArrayContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsArrayContainer_IncludeProperSubset() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new ArrayContainer().add(0,9);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(0, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsArrayContainer_IncludeProperSubsetDifferentStart() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new ArrayContainer().add(2,9);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(2, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsArrayContainer_ExcludeShiftedSet() {
-    Container rc = new RunContainer().add(0,10);
-    Container shifted = new ArrayContainer().add(2,12);
+    Container rc = new RunContainer().add(0, 10);
+    Container shifted = new ArrayContainer().add(2, 12);
     assertFalse(rc.contains(shifted));
   }
 
   @Test
   public void testContainsArrayContainer_IncludeSelf() {
-    Container rc = new RunContainer().add(0,10);
-    Container subset = new ArrayContainer().add(0,10);
+    Container rc = new RunContainer().add(0, 10);
+    Container subset = new ArrayContainer().add(0, 10);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsArrayContainer_ExcludeSuperSet() {
-    Container rc = new RunContainer().add(0,10);
-    Container superset = new ArrayContainer().add(0,20);
+    Container rc = new RunContainer().add(0, 10);
+    Container superset = new ArrayContainer().add(0, 20);
     assertFalse(rc.contains(superset));
   }
 
@@ -3464,20 +3438,17 @@ public void testContainsArrayContainer_ExcludeDisJointSet() {
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
 
-    disjoint = new ArrayContainer().add((char)512);
+    disjoint = new ArrayContainer().add((char) 512);
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
 
-    rc = rc.add(12,14).add(16,18).add(20,22);
+    rc = rc.add(12, 14).add(16, 18).add(20, 22);
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
 
     rc.trim();
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
-
-
-
   }
 
   @Test
@@ -3516,7 +3487,7 @@ public void testEqualsArrayContainer_NotEqual_ArrayShifted() {
   public void testEqualsArrayContainer_NotEqual_ArrayDiscontiguous() {
     Container rc = new RunContainer().add(0, 10);
     Container ac = new ArrayContainer().add(0, 11);
-    ac.flip((char)9);
+    ac.flip((char) 9);
     assertNotEquals(rc, ac);
     assertNotEquals(ac, rc);
   }
@@ -3576,18 +3547,16 @@ public void testIntersectsWithRange() {
     assertFalse(container.intersects(11, 1 << 16));
   }
 
-
   @Test
   public void testIntersectsWithRangeUnsigned() {
     Container container = new RunContainer().add(lower16Bits(-50), lower16Bits(-10));
     assertFalse(container.intersects(0, 1));
     assertTrue(container.intersects(0, lower16Bits(-40)));
     assertFalse(container.intersects(lower16Bits(-100), lower16Bits(-55)));
-    //assertFalse(container.intersects(-9, 1 << 16)); // forbidden
+    // assertFalse(container.intersects(-9, 1 << 16)); // forbidden
     assertTrue(container.intersects(11, 1 << 16));
   }
 
-
   @Test
   public void testIntersectsWithRangeManyRuns() {
     Container container = new RunContainer().add(0, 10).add(lower16Bits(-50), lower16Bits(-10));
@@ -3604,7 +3573,7 @@ public void testIntersectsWithRangeManyRuns() {
   @Test
   public void testContainsFull() {
     assertTrue(RunContainer.full().contains(0, 1 << 16));
-    assertFalse(RunContainer.full().flip((char)(1 << 15)).contains(0, 1 << 16));
+    assertFalse(RunContainer.full().flip((char) (1 << 15)).contains(0, 1 << 16));
   }
 
   @Test
@@ -3627,11 +3596,8 @@ public void testContainsRange() {
 
   @Test
   public void testContainsRange3() {
-    Container rc = new RunContainer().add(1, 100)
-            .add(300, 300)
-            .add(400, 500)
-            .add(502, 600)
-            .add(700, 10000);
+    Container rc =
+        new RunContainer().add(1, 100).add(300, 300).add(400, 500).add(502, 600).add(700, 10000);
     assertFalse(rc.contains(0, 100));
     assertFalse(rc.contains(500, 600));
     assertFalse(rc.contains(501, 600));
@@ -3643,135 +3609,139 @@ public void testContainsRange3() {
 
   @Test
   public void testNextValue() {
-    RunContainer container = new RunContainer(new char[] { 64, 64 }, 1);
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(-1, container.nextValue((char)129));
+    RunContainer container = new RunContainer(new char[] {64, 64}, 1);
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(-1, container.nextValue((char) 129));
   }
 
   @Test
   public void testNextValueBetweenRuns() {
-    RunContainer container = new RunContainer(new char[] { 64, 64, 256, 64 }, 2);
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(256, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)512));
+    RunContainer container = new RunContainer(new char[] {64, 64, 256, 64}, 2);
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(256, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 512));
   }
 
   @Test
   public void testNextValue2() {
-    RunContainer container = new RunContainer(new char[] { 64, 64, 200, 300, 5000, 200 }, 3);
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)63));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(200, container.nextValue((char)129));
-    assertEquals(200, container.nextValue((char)199));
-    assertEquals(200, container.nextValue((char)200));
-    assertEquals(250, container.nextValue((char)250));
-    assertEquals(5000, container.nextValue((char)2500));
-    assertEquals(5000, container.nextValue((char)5000));
-    assertEquals(5200, container.nextValue((char)5200));
-    assertEquals(-1, container.nextValue((char)5201));
+    RunContainer container = new RunContainer(new char[] {64, 64, 200, 300, 5000, 200}, 3);
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 63));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(200, container.nextValue((char) 129));
+    assertEquals(200, container.nextValue((char) 199));
+    assertEquals(200, container.nextValue((char) 200));
+    assertEquals(250, container.nextValue((char) 250));
+    assertEquals(5000, container.nextValue((char) 2500));
+    assertEquals(5000, container.nextValue((char) 5000));
+    assertEquals(5200, container.nextValue((char) 5200));
+    assertEquals(-1, container.nextValue((char) 5201));
   }
 
   @Test
   public void testPreviousValue1() {
-    RunContainer container = new RunContainer(new char[] { 64, 64 }, 1);
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
+    RunContainer container = new RunContainer(new char[] {64, 64}, 1);
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
   }
 
   @Test
   public void testPreviousValue2() {
-    RunContainer container = new RunContainer(new char[] { 64, 64, 200, 300, 5000, 200 }, 3);
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
-    assertEquals(128, container.previousValue((char)199));
-    assertEquals(200, container.previousValue((char)200));
-    assertEquals(250, container.previousValue((char)250));
-    assertEquals(500, container.previousValue((char)2500));
-    assertEquals(5000, container.previousValue((char)5000));
-    assertEquals(5200, container.previousValue((char)5200));
+    RunContainer container = new RunContainer(new char[] {64, 64, 200, 300, 5000, 200}, 3);
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
+    assertEquals(128, container.previousValue((char) 199));
+    assertEquals(200, container.previousValue((char) 200));
+    assertEquals(250, container.previousValue((char) 250));
+    assertEquals(500, container.previousValue((char) 2500));
+    assertEquals(5000, container.previousValue((char) 5000));
+    assertEquals(5200, container.previousValue((char) 5200));
   }
 
   @Test
   public void testPreviousValueUnsigned() {
-    RunContainer container = new RunContainer(new char[] { (char)((1 << 15) | 5), (char)0, (char)((1 << 15) | 7), (char)0}, 2);
-    assertEquals(-1, container.previousValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 8)));
+    RunContainer container =
+        new RunContainer(
+            new char[] {(char) ((1 << 15) | 5), (char) 0, (char) ((1 << 15) | 7), (char) 0}, 2);
+    assertEquals(-1, container.previousValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testNextValueUnsigned() {
-    RunContainer container = new RunContainer(new char[] { (char)((1 << 15) | 5), (char)0, (char)((1 << 15) | 7), (char)0}, 2);
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 7)));
-    assertEquals(-1, container.nextValue((char)((1 << 15) | 8)));
+    RunContainer container =
+        new RunContainer(
+            new char[] {(char) ((1 << 15) | 5), (char) 0, (char) ((1 << 15) | 7), (char) 0}, 2);
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 7)));
+    assertEquals(-1, container.nextValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testPreviousAbsentValue1() {
     Container container = new RunContainer().iadd(64, 129);
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
   }
 
   @Test
   public void testPreviousAbsentValue2() {
     Container container = new RunContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
-    assertEquals(199, container.previousAbsentValue((char)199));
-    assertEquals(199, container.previousAbsentValue((char)200));
-    assertEquals(199, container.previousAbsentValue((char)250));
-    assertEquals(2500, container.previousAbsentValue((char)2500));
-    assertEquals(4999, container.previousAbsentValue((char)5000));
-    assertEquals(4999, container.previousAbsentValue((char)5200));
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
+    assertEquals(199, container.previousAbsentValue((char) 199));
+    assertEquals(199, container.previousAbsentValue((char) 200));
+    assertEquals(199, container.previousAbsentValue((char) 250));
+    assertEquals(2500, container.previousAbsentValue((char) 2500));
+    assertEquals(4999, container.previousAbsentValue((char) 5000));
+    assertEquals(4999, container.previousAbsentValue((char) 5200));
   }
 
   @Test
   public void testPreviousAbsentValueEmpty() {
     RunContainer container = new RunContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.previousAbsentValue((char)i));
+      assertEquals(i, container.previousAbsentValue((char) i));
     }
   }
 
   @Test
   public void testPreviousAbsentValueSparse() {
-    RunContainer container = new RunContainer(new char[] { 10, 0, 20, 0, 30, 0}, 3);
-    assertEquals(9, container.previousAbsentValue((char)9));
-    assertEquals(9, container.previousAbsentValue((char)10));
-    assertEquals(11, container.previousAbsentValue((char)11));
-    assertEquals(21, container.previousAbsentValue((char)21));
-    assertEquals(29, container.previousAbsentValue((char)30));
+    RunContainer container = new RunContainer(new char[] {10, 0, 20, 0, 30, 0}, 3);
+    assertEquals(9, container.previousAbsentValue((char) 9));
+    assertEquals(9, container.previousAbsentValue((char) 10));
+    assertEquals(11, container.previousAbsentValue((char) 11));
+    assertEquals(21, container.previousAbsentValue((char) 21));
+    assertEquals(29, container.previousAbsentValue((char) 30));
   }
 
   @Test
@@ -3783,67 +3753,67 @@ public void testPreviousAbsentEvenBits() {
     }
 
     RunContainer container = new RunContainer(evenBits, 1 << 14);
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i - 1, container.previousAbsentValue((char)i));
-      assertEquals(i + 1, container.previousAbsentValue((char)(i+1)));
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i - 1, container.previousAbsentValue((char) i));
+      assertEquals(i + 1, container.previousAbsentValue((char) (i + 1)));
     }
   }
 
   @Test
   public void testPreviousAbsentValueUnsigned() {
-    RunContainer container = new RunContainer(new char[] { (char)((1 << 15) | 5), 0, (char)((1 << 15) | 7), 0}, 2);
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char)((1 << 15) | 8)));
+    RunContainer container =
+        new RunContainer(new char[] {(char) ((1 << 15) | 5), 0, (char) ((1 << 15) | 7), 0}, 2);
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testNextAbsentValue1() {
     Container container = new RunContainer().iadd(64, 129);
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
   }
 
   @Test
   public void testNextAbsentValue2() {
     Container container = new RunContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
-    assertEquals(199, container.nextAbsentValue((char)199));
-    assertEquals(501, container.nextAbsentValue((char)200));
-    assertEquals(501, container.nextAbsentValue((char)250));
-    assertEquals(2500, container.nextAbsentValue((char)2500));
-    assertEquals(5201, container.nextAbsentValue((char)5000));
-    assertEquals(5201, container.nextAbsentValue((char)5200));
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
+    assertEquals(199, container.nextAbsentValue((char) 199));
+    assertEquals(501, container.nextAbsentValue((char) 200));
+    assertEquals(501, container.nextAbsentValue((char) 250));
+    assertEquals(2500, container.nextAbsentValue((char) 2500));
+    assertEquals(5201, container.nextAbsentValue((char) 5000));
+    assertEquals(5201, container.nextAbsentValue((char) 5200));
   }
 
   @Test
   public void testNextAbsentValueEmpty() {
     RunContainer container = new RunContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.nextAbsentValue((char)i));
+      assertEquals(i, container.nextAbsentValue((char) i));
     }
   }
 
   @Test
   public void testNextAbsentValueSparse() {
-    Container container = new RunContainer(new char[] { 10, 0, 20, 0, 30, 0}, 3);
-    assertEquals(9, container.nextAbsentValue((char)9));
-    assertEquals(11, container.nextAbsentValue((char)10));
-    assertEquals(11, container.nextAbsentValue((char)11));
-    assertEquals(21, container.nextAbsentValue((char)21));
-    assertEquals(31, container.nextAbsentValue((char)30));
+    Container container = new RunContainer(new char[] {10, 0, 20, 0, 30, 0}, 3);
+    assertEquals(9, container.nextAbsentValue((char) 9));
+    assertEquals(11, container.nextAbsentValue((char) 10));
+    assertEquals(11, container.nextAbsentValue((char) 11));
+    assertEquals(21, container.nextAbsentValue((char) 21));
+    assertEquals(31, container.nextAbsentValue((char) 30));
   }
 
   @Test
@@ -3855,31 +3825,38 @@ public void testNextAbsentEvenBits() {
     }
 
     RunContainer container = new RunContainer(evenBits, 1 << 14);
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i + 1, container.nextAbsentValue((char)i));
-      assertEquals(i + 1, container.nextAbsentValue((char)(i+1)));
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i + 1, container.nextAbsentValue((char) i));
+      assertEquals(i + 1, container.nextAbsentValue((char) (i + 1)));
     }
   }
 
   @Test
   public void testNextAbsentValueUnsigned() {
-    RunContainer container = new RunContainer(new char[] { (char)((1 << 15) | 5), 0, (char)((1 << 15) | 7), 0}, 2);
-    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 8)));
+    RunContainer container =
+        new RunContainer(new char[] {(char) ((1 << 15) | 5), 0, (char) ((1 << 15) | 7), 0}, 2);
+    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testContains() {
-    RunContainer rc = new RunContainer(new char[]{23, 24}, 1);
+    RunContainer rc = new RunContainer(new char[] {23, 24}, 1);
     assertFalse(rc.contains(48, 49));
   }
 
   @Test
   public void testIntersects() {
-    RunContainer rc = new RunContainer(new char[]{41, 15, 215, 0, 217, 2790, 3065, 170, 3269, 422, 3733, 43, 3833, 16, 3852, 7, 3662, 3, 3901, 2}, 10);
+    RunContainer rc =
+        new RunContainer(
+            new char[] {
+              41, 15, 215, 0, 217, 2790, 3065, 170, 3269, 422, 3733, 43, 3833, 16, 3852, 7, 3662, 3,
+              3901, 2
+            },
+            10);
     assertFalse(rc.intersects(57, 215));
   }
 
@@ -3893,43 +3870,52 @@ public void testRangeConsumer() {
     container.add((char) 65530);
     container.iadd(65534, 65536);
 
-    ValidationRangeConsumer consumer = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] {
-        ABSENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, PRESENT
-    });
+    ValidationRangeConsumer consumer =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {
+              ABSENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT, ABSENT, PRESENT, PRESENT, ABSENT,
+              PRESENT
+            });
     container.forAllUntil(0, (char) 11, consumer);
     assertEquals(11, consumer.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer2 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] {
-        PRESENT, ABSENT, ABSENT, PRESENT, PRESENT
-    });
+    ValidationRangeConsumer consumer2 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {PRESENT, ABSENT, ABSENT, PRESENT, PRESENT});
     container.forAllInRange((char) 4, (char) 9, consumer2);
     assertEquals(5, consumer2.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer3 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[] {
-        PRESENT, ABSENT, ABSENT, ABSENT, PRESENT, PRESENT
-    });
+    ValidationRangeConsumer consumer3 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {
+              PRESENT, ABSENT, ABSENT, ABSENT, PRESENT, PRESENT
+            });
     container.forAllFrom((char) 65530, consumer3);
     assertEquals(6, consumer3.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer4 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer4 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
     container.forAll(0, consumer4);
     consumer4.assertAllAbsentExcept(entries, 0);
 
-    ValidationRangeConsumer consumer5 = ValidationRangeConsumer.ofSize(2 * BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer5 =
+        ValidationRangeConsumer.ofSize(2 * BitmapContainer.MAX_CAPACITY);
     consumer5.acceptAllAbsent(0, BitmapContainer.MAX_CAPACITY);
     container.forAll(BitmapContainer.MAX_CAPACITY, consumer5);
     consumer5.assertAllAbsentExcept(entries, BitmapContainer.MAX_CAPACITY);
 
     // Completely Empty
     container = new RunContainer();
-    ValidationRangeConsumer consumer6 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer6 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
     container.forAll(0, consumer6);
     consumer6.assertAllAbsent();
 
     // Completely Full
     container = new RunContainer();
     container.iadd(0, BitmapContainer.MAX_CAPACITY);
-    ValidationRangeConsumer consumer7 = ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
+    ValidationRangeConsumer consumer7 =
+        ValidationRangeConsumer.ofSize(BitmapContainer.MAX_CAPACITY);
     container.forAll(0, consumer7);
     consumer7.assertAllPresent();
 
@@ -3948,7 +3934,26 @@ public void testRangeConsumer() {
     consumer10.assertAllPresent();
   }
 
+  @Test
+  public void iorWithFullContainer() {
+    Container container = new ArrayContainer(new char[] {1, 3, 4, (char) -1});
+    container = container.ior(RunContainer.full());
+    assertEquals(RunContainer.full(), container);
+  }
+
+  @Test
+  public void toBitmapContainer() {
+    Container rc = new RunContainer().add((char) 1).add(5, 7).add(10, 21);
+    BitmapContainer bitmapContainer = rc.toBitmapContainer();
+
+    assertTrue(bitmapContainer.contains((char) 1));
+    assertTrue(bitmapContainer.contains(5, 7));
+    assertTrue(bitmapContainer.contains(10, 21));
+
+    assertEquals(rc.getCardinality(), bitmapContainer.getCardinality());
+  }
+
   private static int lower16Bits(int x) {
-    return ((char)x) & 0xFFFF;
+    return ((char) x) & 0xFFFF;
   }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestSerialization.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestSerialization.java
similarity index 95%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestSerialization.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestSerialization.java
index 1cdd714b3..0eea3deaa 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestSerialization.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestSerialization.java
@@ -1,20 +1,26 @@
 package org.roaringbitmap;
 
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
 import org.roaringbitmap.buffer.MutableRoaringBitmap;
 
-import java.io.*;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.Random;
-import java.util.Base64;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 
 class ByteBufferBackedInputStream extends InputStream {
 
@@ -64,8 +70,6 @@ public long skip(long n) {
   }
 }
 
-
-
 class ByteBufferBackedOutputStream extends OutputStream {
   ByteBuffer buf;
 
@@ -87,10 +91,8 @@ public synchronized void write(byte[] bytes, int off, int len) throws IOExceptio
   public synchronized void write(int b) throws IOException {
     buf.put((byte) b);
   }
-
 }
 
-
 public class TestSerialization {
   static RoaringBitmap bitmap_a;
 
@@ -109,7 +111,7 @@ public class TestSerialization {
   static ByteBuffer outbb;
 
   static ByteBuffer presoutbb;
-  
+
   // Very small buffer to higher to chance to encounter edge-case
   byte[] buffer = new byte[16];
 
@@ -142,17 +144,18 @@ public static void init() throws IOException {
      */
     // do not runoptimize bitmap_a1
 
-    outbb = ByteBuffer
-        .allocate(bitmap_a.serializedSizeInBytes() + bitmap_empty.serializedSizeInBytes());
-    presoutbb = ByteBuffer
-        .allocate(bitmap_a.serializedSizeInBytes() + bitmap_empty.serializedSizeInBytes());
+    outbb =
+        ByteBuffer.allocate(
+            bitmap_a.serializedSizeInBytes() + bitmap_empty.serializedSizeInBytes());
+    presoutbb =
+        ByteBuffer.allocate(
+            bitmap_a.serializedSizeInBytes() + bitmap_empty.serializedSizeInBytes());
     ByteBufferBackedOutputStream out = new ByteBufferBackedOutputStream(presoutbb);
 
     DataOutputStream dos = new DataOutputStream(out);
     bitmap_empty.serialize(dos);
     bitmap_a.serialize(dos);
     presoutbb.flip();
-
   }
 
   private static int[] takeSortedAndDistinct(Random source, int count) {
@@ -171,7 +174,6 @@ private static int[] takeSortedAndDistinct(Random source, int count) {
     return unboxed;
   }
 
-
   private static int[] toArray(LinkedHashSet integers) {
     int[] ints = new int[integers.size()];
     int i = 0;
@@ -181,7 +183,6 @@ private static int[] toArray(LinkedHashSet integers) {
     return ints;
   }
 
-
   @Test
   public void testDeserialize() throws IOException {
     presoutbb.rewind();
@@ -201,8 +202,6 @@ public void testDeserialize_buffer() throws IOException {
     assertEquals(bitmap_a, bitmap_b);
   }
 
-
-
   @Test
   public void testImmutableBuildingBySerialization() {
     presoutbb.rewind();
@@ -231,8 +230,8 @@ public void testImmutableBuildingBySerialization() {
       int val1 = it1.next(), val2 = it2.next();
       if (val1 != val2) {
         if (++blabcount < 10) {
-          System.out
-              .println("disagree on " + valcount + " nonmatching values are " + val1 + " " + val2);
+          System.out.println(
+              "disagree on " + valcount + " nonmatching values are " + val1 + " " + val2);
         }
       }
     }
@@ -245,7 +244,6 @@ public void testImmutableBuildingBySerialization() {
     assertEquals(cksum1, cksum2);
   }
 
-
   @Test
   public void testImmutableBuildingBySerializationSimple() {
     System.out.println("testImmutableBuildingBySerializationSimple ");
@@ -295,7 +293,6 @@ public void testMutableBuilding() {
     assertEquals(cksum1, cksum2);
   }
 
-
   @Test
   public void testMutableBuildingBySerialization() throws IOException {
     presoutbb.rewind();
@@ -316,8 +313,6 @@ public void testMutableBuildingBySerialization() throws IOException {
     assertEquals(cksum1, cksum2);
   }
 
-
-
   @Test
   public void testMutableDeserializeMutable() throws IOException {
     presoutbb.rewind();
@@ -347,7 +342,7 @@ public void testMutableRunSerializationBasicDeserialization() throws java.io.IOE
       bitmap_a.add(k); // bitmap density and too many little runs
       bitmap_ar.add(k);
       bitmap_am.add(k);
-      bitmap_amr.add(k);    
+      bitmap_amr.add(k);
     }
 
     bitmap_ar.runOptimize();
@@ -357,7 +352,9 @@ public void testMutableRunSerializationBasicDeserialization() throws java.io.IOE
     assertEquals(bitmap_am.serializedSizeInBytes(), bitmap_a.serializedSizeInBytes());
     assertEquals(bitmap_amr.serializedSizeInBytes(), bitmap_ar.serializedSizeInBytes());
 
-    ByteBuffer outbuf = ByteBuffer.allocate(2*(bitmap_a.serializedSizeInBytes() + bitmap_ar.serializedSizeInBytes()));
+    ByteBuffer outbuf =
+        ByteBuffer.allocate(
+            2 * (bitmap_a.serializedSizeInBytes() + bitmap_ar.serializedSizeInBytes()));
     DataOutputStream out = new DataOutputStream(new ByteBufferBackedOutputStream(outbuf));
     try {
       bitmap_a.serialize(out);
@@ -388,7 +385,6 @@ public void testMutableRunSerializationBasicDeserialization() throws java.io.IOE
     assertEquals(bitmap_ar, bitmap_c2);
     assertEquals(bitmap_ar, bitmap_c3);
     assertEquals(bitmap_ar, bitmap_c4);
-
   }
 
   @Test
@@ -402,7 +398,6 @@ public void testMutableSerialize() throws IOException {
     bitmap_ar.serialize(dos);
   }
 
-
   @Test
   public void testRunSerializationDeserialization() throws java.io.IOException {
     final int[] data = takeSortedAndDistinct(new Random(07734), 100000);
@@ -438,8 +433,6 @@ public void testRunSerializationDeserialization() throws java.io.IOException {
     assertEquals(bitmap_a, bitmap_c);
   }
 
-
-
   @Test
   public void testSerialize() throws IOException {
     outbb.rewind();
@@ -508,4 +501,3 @@ public void testDeserializeSmallDataMutable() throws IOException {
     assertEquals(actual, expected);
   }
 }
-
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestSerializationViaByteBuffer.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestSerializationViaByteBuffer.java
similarity index 58%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestSerializationViaByteBuffer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestSerializationViaByteBuffer.java
index 046155812..7d1546139 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestSerializationViaByteBuffer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestSerializationViaByteBuffer.java
@@ -1,5 +1,9 @@
 package org.roaringbitmap;
 
+import static java.nio.channels.FileChannel.MapMode.READ_WRITE;
+import static java.nio.file.Files.delete;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -10,7 +14,12 @@
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.file.Files;
@@ -18,10 +27,6 @@
 import java.util.UUID;
 import java.util.stream.Stream;
 
-import static java.nio.channels.FileChannel.MapMode.READ_WRITE;
-import static java.nio.file.Files.delete;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestSerializationViaByteBuffer {
 
@@ -32,63 +37,62 @@ public static void cleanup() {
 
   public static Stream params() {
     return Stream.of(
-            Arguments.of(2, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(2, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(3, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(3, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(4, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(4, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(5, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(5, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(6, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(6, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(7, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(7, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(8, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(8, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(9, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(9, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(10, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(10, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(11, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(11, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(12, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(12, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(13, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(13, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(14, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(14, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(15, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(15, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(2, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(2, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(3, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(3, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(4, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(4, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(5, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(5, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(6, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(6, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(7, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(7, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(8, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(8, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(9, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(9, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(10, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(10, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(11, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(11, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(12, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(12, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(13, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(13, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(14, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(14, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(15, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(15, ByteOrder.LITTLE_ENDIAN, false)
-    );
+        Arguments.of(2, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(2, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(3, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(3, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(4, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(4, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(5, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(5, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(6, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(6, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(7, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(7, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(8, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(8, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(9, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(9, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(10, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(10, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(11, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(11, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(12, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(12, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(13, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(13, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(14, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(14, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(15, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(15, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(2, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(2, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(3, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(3, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(4, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(4, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(5, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(5, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(6, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(6, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(7, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(7, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(8, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(8, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(9, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(9, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(10, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(10, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(11, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(11, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(12, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(12, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(13, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(13, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(14, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(14, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(15, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(15, ByteOrder.LITTLE_ENDIAN, false));
   }
 
   private Path file;
@@ -110,10 +114,10 @@ public void after() throws IOException {
     }
   }
 
-
   @ParameterizedTest(name = "{1}/{0} keys/runOptimise={2}")
   @MethodSource("params")
-  public void testDeserializeFromMappedFile(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromMappedFile(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     RoaringBitmap input = SeededTestData.randomBitmap(keys);
     byte[] serialised = serialise(input, runOptimise);
     try (RandomAccessFile raf = new RandomAccessFile(file.toFile(), "rw")) {
@@ -129,7 +133,8 @@ public void testDeserializeFromMappedFile(int keys, ByteOrder order, boolean run
 
   @ParameterizedTest(name = "{1}/{0} keys/runOptimise={2}")
   @MethodSource("params")
-  public void testDeserializeFromHeap(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromHeap(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     RoaringBitmap input = SeededTestData.randomBitmap(keys);
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.wrap(serialised).order(order);
@@ -140,7 +145,8 @@ public void testDeserializeFromHeap(int keys, ByteOrder order, boolean runOptimi
 
   @ParameterizedTest(name = "{1}/{0} keys/runOptimise={2}")
   @MethodSource("params")
-  public void testDeserializeFromDirect(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromDirect(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     RoaringBitmap input = SeededTestData.randomBitmap(keys);
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocateDirect(serialised.length).order(order);
@@ -153,7 +159,8 @@ public void testDeserializeFromDirect(int keys, ByteOrder order, boolean runOpti
 
   @ParameterizedTest(name = "{1}/{0} keys/runOptimise={2}")
   @MethodSource("params")
-  public void testDeserializeFromDirectWithOffset(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromDirectWithOffset(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     RoaringBitmap input = SeededTestData.randomBitmap(keys);
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocateDirect(10 + serialised.length).order(order);
@@ -167,7 +174,8 @@ public void testDeserializeFromDirectWithOffset(int keys, ByteOrder order, boole
 
   @ParameterizedTest(name = "{1}/{0} keys/runOptimise={2}")
   @MethodSource("params")
-  public void testSerializeCorrectOffset(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testSerializeCorrectOffset(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     RoaringBitmap input = SeededTestData.randomBitmap(keys);
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocateDirect(10 + serialised.length).order(order);
@@ -179,7 +187,8 @@ public void testSerializeCorrectOffset(int keys, ByteOrder order, boolean runOpt
 
   @ParameterizedTest(name = "{1}/{0} keys/runOptimise={2}")
   @MethodSource("params")
-  public void testSerializeToByteBufferDeserializeViaStream(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testSerializeToByteBufferDeserializeViaStream(
+      int keys, ByteOrder order, boolean runOptimise) throws IOException {
     RoaringBitmap input = SeededTestData.randomBitmap(keys);
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocate(serialised.length).order(order);
@@ -194,7 +203,8 @@ public void testSerializeToByteBufferDeserializeViaStream(int keys, ByteOrder or
 
   @ParameterizedTest(name = "{1}/{0} keys/runOptimise={2}")
   @MethodSource("params")
-  public void testSerializeToByteBufferDeserializeByteBuffer(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testSerializeToByteBufferDeserializeByteBuffer(
+      int keys, ByteOrder order, boolean runOptimise) throws IOException {
     RoaringBitmap input = SeededTestData.randomBitmap(keys);
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocate(serialised.length).order(order);
@@ -211,7 +221,7 @@ private static byte[] serialise(RoaringBitmap input, boolean runOptimise) throws
       input.runOptimize();
     }
     try (ByteArrayOutputStream bos = new ByteArrayOutputStream(input.serializedSizeInBytes());
-         DataOutputStream dos = new DataOutputStream(bos)) {
+        DataOutputStream dos = new DataOutputStream(bos)) {
       input.serialize(dos);
       return bos.toByteArray();
     }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestSerializedSize.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestSerializedSize.java
similarity index 81%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestSerializedSize.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestSerializedSize.java
index 0d942861d..d4c0dc92e 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestSerializedSize.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestSerializedSize.java
@@ -1,22 +1,21 @@
 package org.roaringbitmap;
 
-import org.junit.jupiter.api.Test;
-
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.junit.jupiter.api.Test;
+
 public class TestSerializedSize {
-  
+
   @Test
   public void testLucaSize() {
     System.out.println("testLucaSize");
     RoaringBitmap rb =
-        RoaringBitmap.bitmapOf( 2946000, 2997491, 10478289, 10490227, 10502444, 19866827);
+        RoaringBitmap.bitmapOf(2946000, 2997491, 10478289, 10490227, 10502444, 19866827);
     System.out.println("cardinality = " + rb.getCardinality());
     System.out.println("total size in bytes = " + rb.getSizeInBytes());
     assertTrue(rb.getSizeInBytes() <= 50);
   }
 
-
   @Test
   public void testEmpty() {
     RoaringBitmap rb = new RoaringBitmap();
@@ -28,8 +27,6 @@ public void testEmpty() {
     assertTrue(rac <= c);
   }
 
-
-
   @Test
   public void testOne() {
     for (int k = 0; k < 100000; k += 100) {
@@ -44,7 +41,6 @@ public void testOne() {
     }
   }
 
-
   @Test
   public void testRange() {
     for (int k = 0; k < 100000; k += 100) {
@@ -59,7 +55,6 @@ public void testRange() {
     }
   }
 
-
   @Test
   public void testLarge() {
     for (long scale = 15; scale < 2048; scale *= 15) {
@@ -68,8 +63,7 @@ public void testLarge() {
       int universe_size = 0;
       for (int k = 0; k < N; ++k) {
         int val = (int) (scale * k);
-        if (val > universe_size)
-          universe_size = val;
+        if (val > universe_size) universe_size = val;
         rb.add((int) (scale * k));
       }
       universe_size++;
@@ -88,14 +82,13 @@ public void testManyRanges() {
       for (long step = 1; step < 500; ++step) {
         RoaringBitmap rb = new RoaringBitmap();
         int universe_size = 0;
-        
+
         for (int i = 0; i < step; ++i) {
           final int maxv = i * (1 << 16) + stepsize;
           rb.add(i * (1L << 16), i * (1L << 16) + stepsize);
-          if (maxv > universe_size)
-            universe_size = maxv;
+          if (maxv > universe_size) universe_size = maxv;
         }
-        long c = RoaringBitmap.maximumSerializedSize(rb.getCardinality(),universe_size);
+        long c = RoaringBitmap.maximumSerializedSize(rb.getCardinality(), universe_size);
         long ac = rb.serializedSizeInBytes();
         assertTrue(ac <= c);
         rb.runOptimize();
@@ -107,9 +100,9 @@ public void testManyRanges() {
   private static int[] firstPrimes(int n) {
     int status = 1, num = 3;
     int[] answer = new int[n];
-    for (int count = 0; count < n;) {
+    for (int count = 0; count < n; ) {
       double s = Math.sqrt(num);
-      for (int j = 2; j <= s ; j++) {
+      for (int j = 2; j <= s; j++) {
         if (num % j == 0) {
           status = 0;
           break;
@@ -124,23 +117,31 @@ private static int[] firstPrimes(int n) {
     }
     return answer;
   }
-  
+
   @Test
   public void testPrimeSerializedSize() {
     System.out.println("[testPrimeSerializedSize]");
     for (int j = 1000; j < 1000 * 1000; j *= 10) {
       int[] primes = firstPrimes(j);
       RoaringBitmap rb = RoaringBitmap.bitmapOf(primes);
-      long vagueupperbound = RoaringBitmap.maximumSerializedSize(rb.getCardinality(), Integer.MAX_VALUE);
-      long upperbound = RoaringBitmap.maximumSerializedSize(rb.getCardinality(), primes[primes.length-1]+1);
+      long vagueupperbound =
+          RoaringBitmap.maximumSerializedSize(rb.getCardinality(), Integer.MAX_VALUE);
+      long upperbound =
+          RoaringBitmap.maximumSerializedSize(rb.getCardinality(), primes[primes.length - 1] + 1);
 
       long actual = rb.serializedSizeInBytes();
-      System.out.println("cardinality = " + rb.getCardinality() + " serialized size = " + actual
-          + " silly upper bound = " + vagueupperbound + " better upper bound = "+upperbound);
+      System.out.println(
+          "cardinality = "
+              + rb.getCardinality()
+              + " serialized size = "
+              + actual
+              + " silly upper bound = "
+              + vagueupperbound
+              + " better upper bound = "
+              + upperbound);
       assertTrue(actual <= vagueupperbound);
       assertTrue(upperbound <= vagueupperbound);
       assertTrue(actual <= upperbound);
     }
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestStreams.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestStreams.java
similarity index 75%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestStreams.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestStreams.java
index dc31353ef..42b162cb1 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestStreams.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestStreams.java
@@ -2,9 +2,10 @@
  * (c) the authors Licensed under the Apache License, Version 2.0.
  */
 
-
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -17,9 +18,6 @@
 import java.util.Random;
 import java.util.stream.Collectors;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-
 public class TestStreams {
   private static List asList(IntIterator ints) {
     int[] values = new int[10];
@@ -34,22 +32,23 @@ private static List asList(IntIterator ints) {
   }
 
   private static List asList(final CharIterator shorts) {
-    return asList(new IntIterator() {
-      @Override
-      public IntIterator clone() {
-        throw new UnsupportedOperationException();
-      }
-
-      @Override
-      public boolean hasNext() {
-        return shorts.hasNext();
-      }
-
-      @Override
-      public int next() {
-        return shorts.next();
-      }
-    });
+    return asList(
+        new IntIterator() {
+          @Override
+          public IntIterator clone() {
+            throw new UnsupportedOperationException();
+          }
+
+          @Override
+          public boolean hasNext() {
+            return shorts.hasNext();
+          }
+
+          @Override
+          public int next() {
+            return shorts.next();
+          }
+        });
   }
 
   private static int[] takeSortedAndDistinct(Random source, int count) {
@@ -78,8 +77,10 @@ public void testViaIteration() {
     RoaringBitmap bitmap = RoaringBitmap.bitmapOf(data);
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
-    final List intIteratorCopy = bitmap.stream().mapToObj(Integer::valueOf).collect(Collectors.toList());
-    final List reverseIntIteratorCopy = bitmap.reverseStream().mapToObj(Integer::valueOf).collect(Collectors.toList());
+    final List intIteratorCopy =
+        bitmap.stream().mapToObj(Integer::valueOf).collect(Collectors.toList());
+    final List reverseIntIteratorCopy =
+        bitmap.reverseStream().mapToObj(Integer::valueOf).collect(Collectors.toList());
 
     assertEquals(bitmap.getCardinality(), iteratorCopy.size());
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
@@ -94,8 +95,10 @@ public void testSmallIteration() {
     RoaringBitmap bitmap = RoaringBitmap.bitmapOf(1, 2, 3);
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
-    final List intIteratorCopy = bitmap.stream().mapToObj(Integer::valueOf).collect(Collectors.toList());
-    final List reverseIntIteratorCopy = bitmap.reverseStream().mapToObj(Integer::valueOf).collect(Collectors.toList());
+    final List intIteratorCopy =
+        bitmap.stream().mapToObj(Integer::valueOf).collect(Collectors.toList());
+    final List reverseIntIteratorCopy =
+        bitmap.reverseStream().mapToObj(Integer::valueOf).collect(Collectors.toList());
 
     assertEquals(ImmutableList.of(1, 2, 3), iteratorCopy);
     assertEquals(ImmutableList.of(1, 2, 3), intIteratorCopy);
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/TestUtil.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestUtil.java
new file mode 100644
index 000000000..83d7d6634
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestUtil.java
@@ -0,0 +1,229 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.SeededTestData.denseRegion;
+import static org.roaringbitmap.SeededTestData.rleRegion;
+import static org.roaringbitmap.SeededTestData.sparseRegion;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestUtil {
+
+  @Test
+  public void testUtilUnsignedIntersection() {
+    char[] data1 = fromShorts(new short[] {-19, -17, -15, -13, -11, -9, -7, -5, -3, -1});
+    char[] data2 = fromShorts(new short[] {-18, -16, -14, -12, -10, -8, -1});
+    assertTrue(Util.unsignedIntersects(data1, data1.length, data2, data2.length));
+    char[] data3 = fromShorts(new short[] {-19, -17, -15, -13, -11, -9, -7});
+    char[] data4 = fromShorts(new short[] {-18, -16, -14, -12, -10, -8, -6, -4, -2, 0});
+    assertFalse(Util.unsignedIntersects(data3, data3.length, data4, data4.length));
+    char[] data5 = {};
+    char[] data6 = {};
+    assertFalse(Util.unsignedIntersects(data5, data5.length, data6, data6.length));
+  }
+
+  @Test
+  public void testBranchyUnsignedBinarySearch() {
+    char[] data1 = fromShorts(new short[] {-19, -17, -15, -13, -11, -9, -7, -5, -3});
+    assertEquals(8, Util.branchyUnsignedBinarySearch(data1, 0, data1.length, data1[8]));
+    assertEquals(0, Util.branchyUnsignedBinarySearch(data1, 0, data1.length, data1[0]));
+    assertEquals(
+        data1.length - 1,
+        Util.branchyUnsignedBinarySearch(
+            data1, data1.length - 1, data1.length, data1[data1.length - 1]));
+    assertEquals(-1, Util.branchyUnsignedBinarySearch(data1, 0, 0, (char) 0));
+    assertEquals(-10, Util.branchyUnsignedBinarySearch(data1, 0, data1.length, (char) -1));
+  }
+
+  @Test
+  public void testPartialRadixSortEmpty() {
+    int[] data = new int[] {};
+    int[] test = Arrays.copyOf(data, data.length);
+    Util.partialRadixSort(test);
+    assertArrayEquals(data, test);
+  }
+
+  @Test
+  public void testPartialRadixSortIsStableInSameKey() {
+    int[] data = new int[] {25, 1, 0, 10};
+    for (int key : new int[] {0, 1 << 16, 1 << 17, 1 << 24, 1 << 25}) {
+      // clear the old key and prepend the new key
+      for (int i = 0; i < data.length; ++i) {
+        data[i] &= 0xFFFF;
+        data[i] |= key;
+      }
+      int[] test = Arrays.copyOf(data, data.length);
+      Util.partialRadixSort(test);
+      assertArrayEquals(data, test);
+    }
+  }
+
+  @Test
+  public void testPartialRadixSortSortsKeysCorrectly() {
+    int[] keys = {
+      // the test expects the first key to be less than the second key,
+      // neither should have any of the lower 16 bits set
+      1 << 16, 1 << 25,
+      1 << 16, 1 << 17,
+      1 << 17, 1 << 18,
+      1 << 25, 1 << 26,
+      1 << 23, 1 << 25,
+      1 << 24, 1 << 25,
+      1 << 25, 1 << 27,
+      1 << 29, 1 << 30,
+    };
+    for (int i = 0; i < keys.length; i += 2) {
+      int key1 = keys[i];
+      int key2 = keys[i + 1];
+      int[] data = new int[] {key2 | 25, key1 | 1, 0, key2 | 10, 25, key1 | 10, key1, 10};
+      // sort by keys, leave values stable
+      int[] expected = new int[] {0, 25, 10, key1 | 1, key1 | 10, key1, key2 | 25, key2 | 10};
+      int[] test = Arrays.copyOf(data, data.length);
+      Util.partialRadixSort(test);
+      assertArrayEquals(expected, test);
+    }
+  }
+
+  @Test
+  public void testPartialRadixSortSortsKeysCorrectlyWithDuplicates() {
+    int[] keys = {
+      // the test expects the first key to be less than the second key,
+      // neither should have any of the lower 16 bits set
+      1 << 16, 1 << 25,
+      1 << 16, 1 << 17,
+      1 << 17, 1 << 18,
+      1 << 25, 1 << 26,
+      1 << 23, 1 << 25,
+      1 << 24, 1 << 25,
+      1 << 25, 1 << 27,
+      1 << 29, 1 << 30,
+    };
+    for (int i = 0; i < keys.length; i += 2) {
+      int key1 = keys[i];
+      int key2 = keys[i + 1];
+      int[] data =
+          new int[] {
+            key2 | 25, key1 | 1, 0, key2 | 10, 25, key1 | 10, key1, 10, key2 | 25, key1 | 1, 0,
+            key2 | 10, 25, key1 | 10, key1, 10
+          };
+      // sort by keys, leave values stable
+      int[] expected =
+          new int[] {
+            0, 25, 10, 0, 25, 10, key1 | 1, key1 | 10, key1, key1 | 1, key1 | 10, key1, key2 | 25,
+            key2 | 10, key2 | 25, key2 | 10
+          };
+      int[] test = Arrays.copyOf(data, data.length);
+      Util.partialRadixSort(test);
+      assertArrayEquals(expected, test);
+    }
+  }
+
+  @Test
+  public void testAdvanceUntil() {
+    char[] data = fromShorts(new short[] {0, 3, 16, 18, 21, 29, 30, -342});
+    assertEquals(1, Util.advanceUntil(data, -1, data.length, (char) 3));
+    assertEquals(5, Util.advanceUntil(data, -1, data.length, (char) 28));
+    assertEquals(5, Util.advanceUntil(data, -1, data.length, (char) 29));
+    assertEquals(7, Util.advanceUntil(data, -1, data.length, (char) -342));
+  }
+
+  @Test
+  public void testReverseUntil() {
+    char[] data = fromShorts(new short[] {1, 3, 16, 18, 21, 29, 30, -342});
+    assertEquals(0, Util.reverseUntil(data, data.length, data.length, (char) 0));
+    assertEquals(1, Util.reverseUntil(data, data.length, data.length, (char) 3));
+    assertEquals(4, Util.reverseUntil(data, data.length, data.length, (char) 28));
+    assertEquals(5, Util.reverseUntil(data, data.length, data.length, (char) 29));
+    assertEquals(6, Util.reverseUntil(data, data.length, data.length, (char) 30));
+    assertEquals(6, Util.reverseUntil(data, data.length, data.length, (char) 31));
+    assertEquals(7, Util.reverseUntil(data, data.length, data.length, (char) -342));
+  }
+
+  @Test
+  public void testIterateUntil() {
+    char[] data = fromShorts(new short[] {0, 3, 16, 18, 21, 29, 30, -342});
+    assertEquals(1, Util.iterateUntil(data, 0, data.length, ((char) 3)));
+    assertEquals(5, Util.iterateUntil(data, 0, data.length, ((char) 28)));
+    assertEquals(5, Util.iterateUntil(data, 0, data.length, ((char) 29)));
+    assertEquals(7, Util.iterateUntil(data, 0, data.length, ((char) -342)));
+  }
+
+  static char[] fromShorts(short[] array) {
+    char[] result = new char[array.length];
+    for (int i = 0; i < array.length; ++i) {
+      result[i] = (char) (array[i] & 0xFFFF);
+    }
+    return result;
+  }
+
+  public static Stream sets() {
+    return Stream.of(
+        Arguments.of(rleRegion().toArray(), rleRegion().toArray()),
+        Arguments.of(denseRegion().toArray(), rleRegion().toArray()),
+        Arguments.of(sparseRegion().toArray(), rleRegion().toArray()),
+        Arguments.of(rleRegion().toArray(), denseRegion().toArray()),
+        Arguments.of(denseRegion().toArray(), denseRegion().toArray()),
+        Arguments.of(sparseRegion().toArray(), denseRegion().toArray()),
+        Arguments.of(rleRegion().toArray(), sparseRegion().toArray()),
+        Arguments.of(denseRegion().toArray(), sparseRegion().toArray()),
+        Arguments.of(sparseRegion().toArray(), sparseRegion().toArray()));
+  }
+
+  @MethodSource("sets")
+  @ParameterizedTest
+  public void testIntersectBitmapWithArray(int[] set1, int[] set2) {
+    long[] bitmap = new long[1024];
+    for (int i : set1) {
+      bitmap[i >>> 6] |= 1L << i;
+    }
+    long[] referenceBitmap = new long[1024];
+    char[] array = new char[set2.length];
+    int pos = 0;
+    for (int i : set2) {
+      referenceBitmap[i >>> 6] |= 1L << i;
+      array[pos++] = (char) i;
+    }
+    int expectedCardinality = 0;
+    for (int i = 0; i < 1024; ++i) {
+      referenceBitmap[i] &= bitmap[i];
+      expectedCardinality += Long.bitCount(referenceBitmap[i]);
+    }
+    int cardinality = Util.intersectArrayIntoBitmap(bitmap, array, array.length);
+    assertEquals(expectedCardinality, cardinality);
+    assertArrayEquals(referenceBitmap, bitmap);
+  }
+
+  @Test
+  public void bitmapOfRange() {
+    assertBitmapRange(0, 10); // begin of first container
+    assertBitmapRange(0, 1 << 16 - 1); // early full container
+    assertBitmapRange(0, 1 << 16); // full first container
+    assertBitmapRange(0, 1 << 16 + 1); // full first container + one value the second
+    assertBitmapRange(10, 1 << 16); // without first several integers
+    assertBitmapRange(1 << 16, (1 << 16) * 2); // full second container
+    assertBitmapRange(10, 100); // some integers inside interval
+    assertBitmapRange((1 << 16) - 5, (1 << 16) + 7); // first to second container
+    assertBitmapRange(0, 100_000); // more than one container
+    assertBitmapRange(100_000, 200_000); // second to third container
+    assertBitmapRange(200_000, 400_000); // more containers inside
+  }
+
+  private static void assertBitmapRange(int start, int end) {
+    RoaringBitmap bitmap = RoaringBitmap.bitmapOfRange(start, end);
+    assertEquals(end - start, bitmap.getCardinality());
+    assertEquals(start, bitmap.first());
+    assertEquals(end - 1, bitmap.last());
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/TestVeryLargeBitmap.java b/roaringbitmap/src/test/java/org/roaringbitmap/TestVeryLargeBitmap.java
similarity index 99%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/TestVeryLargeBitmap.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/TestVeryLargeBitmap.java
index 29a47975f..03c936fce 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/TestVeryLargeBitmap.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/TestVeryLargeBitmap.java
@@ -1,10 +1,9 @@
 package org.roaringbitmap;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 public class TestVeryLargeBitmap {
   @Test
   public void testSelect() {
@@ -13,7 +12,7 @@ public void testSelect() {
     assertEquals(-2, map.select(-2));
     assertEquals(-1, map.select(-1));
   }
-  
+
   @Test // this should run fine given enough memory
   public void stupidlyLarge() {
     try {
@@ -33,5 +32,4 @@ public void stupidlyLarge() {
       ome.printStackTrace();
     }
   }
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/UnorderedRoaringBitmapWriterRandomisedTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/UnorderedRoaringBitmapWriterRandomisedTest.java
new file mode 100644
index 000000000..64ab7550e
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/UnorderedRoaringBitmapWriterRandomisedTest.java
@@ -0,0 +1,70 @@
+package org.roaringbitmap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class UnorderedRoaringBitmapWriterRandomisedTest {
+
+  public static Stream tests() {
+    return Stream.of(
+        Arguments.of(generateUnorderedArray(0)),
+        Arguments.of(generateUnorderedArray(10)),
+        Arguments.of(generateUnorderedArray(100)),
+        Arguments.of(generateUnorderedArray(1000)),
+        Arguments.of(generateUnorderedArray(10000)),
+        Arguments.of(generateUnorderedArray(100000)),
+        Arguments.of(generateUnorderedArray(1000000)));
+  }
+
+  @ParameterizedTest
+  @MethodSource("tests")
+  public void bitmapOfUnorderedShouldBuildSameBitmapAsBitmapOf(int[] data) {
+    RoaringBitmap baseline = RoaringBitmap.bitmapOf(data);
+    RoaringBitmap test = RoaringBitmap.bitmapOfUnordered(data);
+    RoaringArray baselineHLC = baseline.highLowContainer;
+    RoaringArray testHLC = test.highLowContainer;
+    assertEquals(baselineHLC.size, testHLC.size);
+    for (int i = 0; i < baselineHLC.size; ++i) {
+      Container baselineContainer = baselineHLC.getContainerAtIndex(i);
+      Container rbContainer = testHLC.getContainerAtIndex(i);
+      assertEquals(baselineContainer, rbContainer);
+    }
+    assertEquals(baseline, test);
+  }
+
+  private static int[] generateUnorderedArray(int size) {
+    if (size == 0) {
+      return new int[0];
+    }
+    Random random = new Random();
+    List ints = new ArrayList<>(size);
+    int last = 0;
+    for (int i = 0; i < size; ++i) {
+      if (random.nextGaussian() > 0.1) {
+        last = last + 1;
+      } else {
+        last = last + 1 + random.nextInt(99);
+      }
+      ints.add(last);
+    }
+    Collections.shuffle(ints);
+    int[] data = new int[size];
+    int i = 0;
+    for (Integer value : ints) {
+      data[i++] = value;
+    }
+    return data;
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/ValidationRangeConsumer.java b/roaringbitmap/src/test/java/org/roaringbitmap/ValidationRangeConsumer.java
similarity index 95%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/ValidationRangeConsumer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/ValidationRangeConsumer.java
index e41ea73fe..fdbf70236 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/ValidationRangeConsumer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/ValidationRangeConsumer.java
@@ -1,8 +1,10 @@
 package org.roaringbitmap;
 
-import java.util.Arrays;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import static org.junit.jupiter.api.Assertions.*;
+import java.util.Arrays;
 
 public class ValidationRangeConsumer implements RelativeRangeConsumer {
 
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/art/Node16Test.java b/roaringbitmap/src/test/java/org/roaringbitmap/art/Node16Test.java
similarity index 97%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/art/Node16Test.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/art/Node16Test.java
index 30984a991..86f24c7fa 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/art/Node16Test.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/art/Node16Test.java
@@ -8,19 +8,19 @@ public class Node16Test {
   @Test
   public void test() {
     Node4 node4 = new Node4(0);
-    //insert 4 nodes
+    // insert 4 nodes
     for (int i = 0; i < 4; i++) {
       LeafNode leafNode = new LeafNode(i, i);
       node4 = (Node4) Node4.insert(node4, leafNode, (byte) i);
     }
-    //insert the fifth node
+    // insert the fifth node
     LeafNode leafNode4 = new LeafNode(4, 4);
     Node16 node16 = (Node16) Node4.insert(node4, leafNode4, (byte) 4);
-    //remove two nodes to shrink to node4
+    // remove two nodes to shrink to node4
     node16 = (Node16) node16.remove(4);
     Node degenerativeNode = node16.remove(3);
     Assertions.assertTrue(degenerativeNode instanceof Node4);
-    //recover to node16 by re-insert two nodes
+    // recover to node16 by re-insert two nodes
     Node4 degenerativeNode4 = (Node4) degenerativeNode;
     Node node = Node4.insert(degenerativeNode4, leafNode4, (byte) 4);
     LeafNode leafNode3 = new LeafNode(3, 3);
@@ -173,7 +173,7 @@ public void testSparseNonZeroBasedKeysSearch() {
 
       // search in the "gaps" before the key
       {
-        byte bKey = (byte)(key - 1);
+        byte bKey = (byte) (key - 1);
         sr = nodes.getNearestChildPos(bKey);
         Assertions.assertEquals(SearchResult.Outcome.NOT_FOUND, sr.outcome);
         Assertions.assertFalse(sr.hasKeyPos());
@@ -184,10 +184,10 @@ public void testSparseNonZeroBasedKeysSearch() {
         } else {
           int expect = Byte.toUnsignedInt(key) - step;
           int result = Byte.toUnsignedInt(nodes.getChildKey(sr.getNextSmallerPos()));
-          Assertions.assertEquals(  expect, result);
+          Assertions.assertEquals(expect, result);
         }
         // the NextLarger of the "key-1" should be the key
-        Assertions.assertEquals(keyPos ,sr.getNextLargerPos());
+        Assertions.assertEquals(keyPos, sr.getNextLargerPos());
         Assertions.assertEquals(key, nodes.getChildKey(sr.getNextLargerPos()));
       }
 
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/art/Node256Test.java b/roaringbitmap/src/test/java/org/roaringbitmap/art/Node256Test.java
similarity index 100%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/art/Node256Test.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/art/Node256Test.java
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/art/Node48Test.java b/roaringbitmap/src/test/java/org/roaringbitmap/art/Node48Test.java
similarity index 96%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/art/Node48Test.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/art/Node48Test.java
index fc04387c1..9699bc2de 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/art/Node48Test.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/art/Node48Test.java
@@ -1,12 +1,13 @@
 package org.roaringbitmap.art;
 
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
 
 public class Node48Test {
 
@@ -46,8 +47,8 @@ public void test() throws IOException {
     DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
     node48.serialize(dataOutputStream);
     Assertions.assertEquals(sizeInBytes, byteArrayOutputStream.toByteArray().length);
-    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
-        byteArrayOutputStream.toByteArray());
+    ByteArrayInputStream byteArrayInputStream =
+        new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
     DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
     Node48 deserNode48 = (Node48) Node.deserialize(dataInputStream);
     currentPos = maxPos;
@@ -116,7 +117,7 @@ public void testWithOffsetAndGapsBytes() {
 
     // setup data
     for (int i = 0; i < insertCount; i++) {
-      nodes = Node48.insert(nodes, leafNode, (byte) (offset + (i*step)));
+      nodes = Node48.insert(nodes, leafNode, (byte) (offset + (i * step)));
     }
     // check we are testing the correct data structure
     Assertions.assertTrue(nodes instanceof Node48);
@@ -355,9 +356,9 @@ public void testSparseNonZeroBasedKeysSearch() {
   @Test
   public void testGetNextSmallerPosEdgeCase() {
     Node nodes = new Node48(0);
-    LeafNode leafNode = new LeafNode(0,0);
+    LeafNode leafNode = new LeafNode(0, 0);
 
-    nodes = Node48.insert(nodes, leafNode, (byte)67);
+    nodes = Node48.insert(nodes, leafNode, (byte) 67);
     // check we are testing the correct thing
     Assertions.assertTrue(nodes instanceof Node48);
 
@@ -383,22 +384,22 @@ public void testGetNextPosShouldNotThrowOnLegalInputs() {
   public void testSetOneByte() {
     long[] longs = new long[Node48.LONGS_USED];
 
-    Node48.setOneByte(0,  (byte)0x67, longs);
+    Node48.setOneByte(0, (byte) 0x67, longs);
     Assertions.assertEquals(0x6700_0000_0000_0000L, longs[0]);
-    Node48.setOneByte(1,  (byte)0x23, longs);
+    Node48.setOneByte(1, (byte) 0x23, longs);
     Assertions.assertEquals(0x6723_0000_0000_0000L, longs[0]);
-    Node48.setOneByte(2,  (byte)0x14, longs);
+    Node48.setOneByte(2, (byte) 0x14, longs);
     Assertions.assertEquals(0x6723_1400_0000_0000L, longs[0]);
-    Node48.setOneByte(3,  (byte)0x98, longs);
+    Node48.setOneByte(3, (byte) 0x98, longs);
     Assertions.assertEquals(0x6723_1498_0000_0000L, longs[0]);
 
-    Node48.setOneByte(249,  (byte)0x67, longs);
+    Node48.setOneByte(249, (byte) 0x67, longs);
     Assertions.assertEquals(0x0067_0000_0000_0000L, longs[31]);
-    Node48.setOneByte(250,  (byte)0x23, longs);
+    Node48.setOneByte(250, (byte) 0x23, longs);
     Assertions.assertEquals(0x0067_2300_0000_0000L, longs[31]);
-    Node48.setOneByte(251,  (byte)0x14, longs);
+    Node48.setOneByte(251, (byte) 0x14, longs);
     Assertions.assertEquals(0x0067_2314_0000_0000L, longs[31]);
-    Node48.setOneByte(252,  (byte)0x98, longs);
+    Node48.setOneByte(252, (byte) 0x98, longs);
     Assertions.assertEquals(0x0067_2314_9800_0000L, longs[31]);
   }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/art/Node4Test.java b/roaringbitmap/src/test/java/org/roaringbitmap/art/Node4Test.java
similarity index 99%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/art/Node4Test.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/art/Node4Test.java
index 6b0405986..c9299c33a 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/art/Node4Test.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/art/Node4Test.java
@@ -1,12 +1,13 @@
 package org.roaringbitmap.art;
 
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
 
 public class Node4Test {
 
@@ -44,8 +45,8 @@ public void testTheBasics() throws IOException {
     DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
     node4.serialize(dataOutputStream);
     Assertions.assertEquals(bytesSize, byteArrayOutputStream.toByteArray().length);
-    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
-        byteArrayOutputStream.toByteArray());
+    ByteArrayInputStream byteArrayInputStream =
+        new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
     DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
     Node4 deserializedNode4 = (Node4) Node.deserialize(dataInputStream);
     Assertions.assertEquals(0, deserializedNode4.getChildPos(key2));
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/BufferContainerBatchIteratorTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/BufferContainerBatchIteratorTest.java
new file mode 100644
index 000000000..41252542b
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/BufferContainerBatchIteratorTest.java
@@ -0,0 +1,173 @@
+package org.roaringbitmap.buffer;
+
+import static java.util.Arrays.copyOfRange;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.roaringbitmap.ContainerBatchIterator;
+import org.roaringbitmap.SeededTestData;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class BufferContainerBatchIteratorTest {
+
+  private static int[][] DATA;
+
+  @BeforeAll
+  public static void setup() {
+    DATA =
+        Stream.of(
+                IntStream.range(0, 20000).toArray(),
+                IntStream.range(0, 1 << 16).toArray(),
+                IntStream.range(0, 1 << 16)
+                    .filter(i -> i < 500 || i > 2000)
+                    .filter(i -> i < (1 << 15) || i > ((1 << 15) | (1 << 8)))
+                    .toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 12) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 11) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 10) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 9) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 8) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 7) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 6) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 5) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 4) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 3) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 2) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> ((i >>> 1) & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i & 1) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 3) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 5) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 7) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 9) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 271) == 0).toArray(),
+                IntStream.range(0, 1 << 16).filter(i -> (i % 1000) == 0).toArray(),
+                IntStream.empty().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.sparseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.denseRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray(),
+                SeededTestData.rleRegion().toArray())
+            .toArray(int[][]::new);
+  }
+
+  @AfterAll
+  public static void clear() {
+    DATA = null;
+  }
+
+  public static Stream params() {
+    return Stream.of(DATA)
+        .flatMap(
+            array ->
+                IntStream.concat(
+                        IntStream.of(512, 1024, 2048, 4096, 8192, 65536),
+                        IntStream.range(0, 100)
+                            .map(i -> ThreadLocalRandom.current().nextInt(1, 65536)))
+                    .mapToObj(i -> Arguments.of(array, i)));
+  }
+
+  @ParameterizedTest(name = "{1}")
+  @MethodSource("params")
+  public void test(int[] expectedValues, int batchSize) {
+    int[] buffer = new int[batchSize];
+    MappeableContainer container = createContainer(expectedValues);
+    ContainerBatchIterator it = container.getBatchIterator();
+    int cardinality = 0;
+    while (it.hasNext()) {
+      int from = cardinality;
+      cardinality += it.next(0, buffer);
+      assertArrayEquals(
+          copyOfRange(expectedValues, from, cardinality),
+          copyOfRange(buffer, 0, cardinality - from),
+          "Failure with batch size " + batchSize);
+    }
+    assertEquals(expectedValues.length, cardinality);
+  }
+
+  @ParameterizedTest(name = "{1}")
+  @MethodSource("params")
+  public void testAdvanceIfNeeded(int[] expectedValues, int batchSize) {
+    if (expectedValues.length < 2) {
+      return;
+    }
+    int[] buffer = new int[batchSize];
+    MappeableContainer container = createContainer(expectedValues);
+    ContainerBatchIterator it = container.getBatchIterator();
+    int cardinality = expectedValues.length / 2;
+    int advanceUntil = expectedValues[cardinality];
+    it.advanceIfNeeded((char) advanceUntil);
+    while (it.hasNext()) {
+      int from = cardinality;
+      cardinality += it.next(0, buffer);
+      assertArrayEquals(
+          copyOfRange(expectedValues, from, cardinality),
+          copyOfRange(buffer, 0, cardinality - from),
+          "Failure with batch size "
+              + batchSize
+              + " and container type "
+              + container.getContainerName());
+    }
+    assertEquals(expectedValues.length, cardinality);
+  }
+
+  private MappeableContainer createContainer(int[] expectedValues) {
+    MappeableContainer container = new MappeableArrayContainer();
+    for (int value : expectedValues) {
+      container = container.add((char) value);
+    }
+    return container.runOptimize();
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/CloneBatchIteratorTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/CloneBatchIteratorTest.java
similarity index 87%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/CloneBatchIteratorTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/CloneBatchIteratorTest.java
index d0e987075..deb46a988 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/CloneBatchIteratorTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/CloneBatchIteratorTest.java
@@ -1,20 +1,22 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.roaringbitmap.BatchIterator;
+
 import com.google.common.primitives.Ints;
 import org.junit.jupiter.api.Test;
-import org.roaringbitmap.BatchIterator;
 
 import java.util.Arrays;
 
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
-
 public class CloneBatchIteratorTest {
 
   @Test
   public void testIndependenceOfClones() {
-    MutableRoaringBitmap bitmap = testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap();
+    MutableRoaringBitmap bitmap =
+        testCase().withBitmapAt(0).withArrayAt(1).withRunAt(2).build().toMutableRoaringBitmap();
     BatchIterator it1 = bitmap.getBatchIterator();
     while (it1.hasNext()) {
       BatchIterator it2 = it1.clone();
@@ -32,8 +34,8 @@ public void testIndependenceOfClones() {
 
   @Test
   public void testIndependenceOfClones2() {
-    int[] c1 = new int[]{1, 10, 20};
-    int[] c2 = new int[]{65560, 70000};
+    int[] c1 = new int[] {1, 10, 20};
+    int[] c2 = new int[] {65560, 70000};
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     for (int x : Ints.concat(c1, c2)) {
       bitmap.add(x);
@@ -42,7 +44,7 @@ public void testIndependenceOfClones2() {
     BatchIterator it1 = bitmap.getBatchIterator();
     BatchIterator it2 = it1.clone();
 
-    int[] buffer = new int[8];
+    int[] buffer = new int[3];
 
     assertEquals(3, it2.nextBatch(buffer));
     assertArrayEquals(c1, Arrays.copyOfRange(buffer, 0, 3));
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/ImmutableRoaringBitmapBatchIteratorTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/ImmutableRoaringBitmapBatchIteratorTest.java
new file mode 100644
index 000000000..44a49230c
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/ImmutableRoaringBitmapBatchIteratorTest.java
@@ -0,0 +1,298 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.RoaringBitmapWriter.bufferWriter;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.roaringbitmap.BatchIterator;
+import org.roaringbitmap.IntIterator;
+import org.roaringbitmap.RoaringBitmapWriter;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.Arrays;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class ImmutableRoaringBitmapBatchIteratorTest {
+
+  private static ImmutableRoaringBitmap[] BITMAPS;
+
+  private static final int[] SIZES = {128, 256, 1024, 8192, 5, 127, 1023};
+
+  @BeforeAll
+  public static void beforeAll() {
+    BITMAPS =
+        new ImmutableRoaringBitmap[] {
+          testCase()
+              .withArrayAt(0)
+              .withArrayAt(2)
+              .withArrayAt(4)
+              .withArrayAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withRunAt(0)
+              .withRunAt(2)
+              .withRunAt(4)
+              .withRunAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withBitmapAt(0)
+              .withRunAt(2)
+              .withBitmapAt(4)
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withArrayAt(0)
+              .withBitmapAt(2)
+              .withRunAt(4)
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withRunAt(0)
+              .withArrayAt(2)
+              .withBitmapAt(4)
+              .withRunAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withBitmapAt(0)
+              .withRunAt(2)
+              .withArrayAt(4)
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withArrayAt(0)
+              .withBitmapAt(2)
+              .withRunAt(4)
+              .withArrayAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withBitmapAt(0)
+              .withArrayAt(2)
+              .withBitmapAt(4)
+              .withRunAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          testCase()
+              .withRunAt((1 << 15) | (1 << 11))
+              .withBitmapAt((1 << 15) | (1 << 12))
+              .withArrayAt((1 << 15) | (1 << 13))
+              .withBitmapAt((1 << 15) | (1 << 14))
+              .build()
+              .toMutableRoaringBitmap(),
+          MutableRoaringBitmap.bitmapOf(
+              IntStream.range(1 << 10, 1 << 26).filter(i -> (i & 1) == 0).toArray()),
+          MutableRoaringBitmap.bitmapOf(
+              IntStream.range(1 << 10, 1 << 25).filter(i -> ((i >>> 8) & 1) == 0).toArray()),
+          MutableRoaringBitmap.bitmapOf(IntStream.range(0, 127).toArray()),
+          MutableRoaringBitmap.bitmapOf(IntStream.range(0, 1024).toArray()),
+          MutableRoaringBitmap.bitmapOf(
+              IntStream.concat(IntStream.range(0, 256), IntStream.range(1 << 16, (1 << 16) | 256))
+                  .toArray()),
+          ImmutableRoaringBitmap.bitmapOf(8511),
+          new MutableRoaringBitmap()
+        };
+  }
+
+  @AfterAll
+  public static void clear() {
+    BITMAPS = null;
+  }
+
+  public static Stream params() {
+    return Stream.of(BITMAPS)
+        .flatMap(bitmap -> IntStream.of(SIZES).mapToObj(i -> Arguments.of(bitmap, i)));
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAsIntIterator(MutableRoaringBitmap bitmap, int batchSize) {
+    IntIterator it = bitmap.getBatchIterator().asIntIterator(new int[batchSize]);
+    RoaringBitmapWriter w =
+        bufferWriter().constantMemory().initialCapacity(bitmap.highLowContainer.size()).get();
+    while (it.hasNext()) {
+      w.add(it.next());
+    }
+    MutableRoaringBitmap copy = w.get();
+    assertEquals(bitmap, copy);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void test(MutableRoaringBitmap bitmap, int batchSize) {
+    int[] buffer = new int[batchSize];
+    MutableRoaringBitmap result = new MutableRoaringBitmap();
+    BatchIterator it = bitmap.getBatchIterator();
+    int cardinality = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      cardinality += batch;
+    }
+    assertEquals(bitmap, result);
+    assertEquals(bitmap.getCardinality(), cardinality);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAdvancedIfNeeded(MutableRoaringBitmap bitmap, int batchSize) {
+    final int cardinality = bitmap.getCardinality();
+    if (cardinality < 2) {
+      return;
+    }
+    int midpoint = bitmap.select(cardinality / 2);
+    int[] buffer = new int[batchSize];
+    MutableRoaringBitmap result = new MutableRoaringBitmap();
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded(midpoint);
+    int consumed = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      consumed += batch;
+    }
+    MutableRoaringBitmap expected = bitmap.clone();
+    expected.remove(0, midpoint & 0xFFFFFFFFL);
+    assertEquals(expected, result);
+    assertEquals(expected.getCardinality(), consumed);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAdvancedIfNeededToAbsentValue(
+      MutableRoaringBitmap bitmap, int batchSize) {
+    long firstAbsent = bitmap.nextAbsentValue(0);
+    int[] buffer = new int[batchSize];
+    MutableRoaringBitmap result = new MutableRoaringBitmap();
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded((int) firstAbsent);
+    int consumed = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      consumed += batch;
+    }
+    MutableRoaringBitmap expected = bitmap.clone();
+    expected.remove(0, firstAbsent & 0xFFFFFFFFL);
+    assertEquals(expected, result);
+    assertEquals(expected.getCardinality(), consumed);
+  }
+
+  @ParameterizedTest(name = "offset={1}")
+  @MethodSource("params")
+  public void testBatchIteratorAdvancedIfNeededBeyondLastValue(
+      MutableRoaringBitmap bitmap, int batchSize) {
+    long advanceTo = bitmap.isEmpty() ? 0 : bitmap.last() + 1;
+    int[] buffer = new int[batchSize];
+    MutableRoaringBitmap result = new MutableRoaringBitmap();
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded((int) advanceTo);
+    int consumed = 0;
+    while (it.hasNext()) {
+      int batch = it.nextBatch(buffer);
+      for (int i = 0; i < batch; ++i) {
+        result.add(buffer[i]);
+      }
+      consumed += batch;
+    }
+    assertEquals(0, consumed);
+    assertTrue(result.isEmpty());
+  }
+
+  @Test
+  public void testTimelyTermination() {
+    ImmutableRoaringBitmap bm = ImmutableRoaringBitmap.bitmapOf(8511);
+    BatchIterator bi = bm.getBatchIterator();
+    int[] batch = new int[10];
+    assertTrue(bi.hasNext());
+    int n = bi.nextBatch(batch);
+    assertEquals(n, 1);
+    assertEquals(batch[0], 8511);
+    assertFalse(bi.hasNext());
+  }
+
+  @Test
+  public void testTimelyTerminationAfterAdvanceIfNeeded() {
+    ImmutableRoaringBitmap bm = ImmutableRoaringBitmap.bitmapOf(8511);
+    BatchIterator bi = bm.getBatchIterator();
+    assertTrue(bi.hasNext());
+    bi.advanceIfNeeded(8512);
+    assertFalse(bi.hasNext());
+  }
+
+  @Test
+  public void testBatchIteratorWithAdvanceIfNeeded() {
+    MutableRoaringBitmap bitmap =
+        MutableRoaringBitmap.bitmapOf(3 << 16, (3 << 16) + 5, (3 << 16) + 10);
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded(6);
+    assertTrue(it.hasNext());
+    int[] batch = new int[10];
+    int n = it.nextBatch(batch);
+    assertEquals(n, 3);
+    assertEquals(batch[0], 3 << 16);
+    assertEquals(batch[1], (3 << 16) + 5);
+    assertEquals(batch[2], (3 << 16) + 10);
+  }
+
+  @ParameterizedTest
+  @ValueSource(ints = {10, 11, 12, 13, 14, 15, 18, 20, 21, 23, 24})
+  public void testBatchIteratorWithAdvancedIfNeededWithZeroLengthRun(int number) {
+    MutableRoaringBitmap bitmap =
+        MutableRoaringBitmap.bitmapOf(10, 11, 12, 13, 14, 15, 18, 20, 21, 22, 23, 24);
+    bitmap.runOptimize();
+    BatchIterator it = bitmap.getBatchIterator();
+    it.advanceIfNeeded(number);
+    assertTrue(it.hasNext());
+    int[] batch = new int[10];
+    int n = it.nextBatch(batch);
+    int i = Arrays.binarySearch(batch, 0, n, number);
+    assertTrue(i >= 0, "key " + number + " not found");
+    assertEquals(batch[i], number);
+  }
+
+  @Test
+  public void testBatchIteratorFillsBufferAcrossContainers() {
+    MutableRoaringBitmap bitmap =
+        MutableRoaringBitmap.bitmapOf(3 << 4, 3 << 8, 3 << 12, 3 << 16, 3 << 20, 3 << 24, 3 << 28);
+    assertEquals(5, bitmap.highLowContainer.size());
+    BatchIterator it = bitmap.getBatchIterator();
+    int[] batch = new int[3];
+    int n = it.nextBatch(batch);
+    assertEquals(3, n);
+    assertArrayEquals(new int[] {3 << 4, 3 << 8, 3 << 12}, batch);
+    n = it.nextBatch(batch);
+    assertEquals(3, n);
+    assertArrayEquals(new int[] {3 << 16, 3 << 20, 3 << 24}, batch);
+    n = it.nextBatch(batch);
+    assertEquals(1, n);
+    assertArrayEquals(new int[] {3 << 28}, Arrays.copyOfRange(batch, 0, 1));
+    n = it.nextBatch(batch);
+    assertEquals(0, n);
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringArrayTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringArrayTest.java
similarity index 99%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringArrayTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringArrayTest.java
index d6f4b578a..01ba3d83c 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringArrayTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringArrayTest.java
@@ -1,13 +1,11 @@
 package org.roaringbitmap.buffer;
 
-import org.junit.jupiter.api.Test;
-
 import static org.junit.jupiter.api.Assertions.assertSame;
 
+import org.junit.jupiter.api.Test;
 
 public class MutableRoaringArrayTest {
 
-
   @Test
   public void resizeOnlyIfNecessary() {
     char[] keys = new char[1];
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringBitmapSubsetTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringBitmapSubsetTest.java
new file mode 100644
index 000000000..d8736697c
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/MutableRoaringBitmapSubsetTest.java
@@ -0,0 +1,140 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.google.common.collect.ContiguousSet;
+import com.google.common.collect.DiscreteDomain;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Range;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+public class MutableRoaringBitmapSubsetTest {
+
+  private static final Predicate DIVISIBLE_BY_4 = i -> i % 4 == 0;
+
+  private static final Predicate DIVISIBLE_BY_3 = i -> i % 3 == 0;
+
+  public static Stream params() {
+    return Stream.of(
+        Arguments.of( // array vs array
+            ImmutableSet.of(1, 2, 3, 4), ImmutableSet.of(2, 3)),
+        Arguments.of( // array vs empty
+            ImmutableSet.of(1, 2, 3, 4), ImmutableSet.of()),
+        Arguments.of( // identical arrays
+            ImmutableSet.of(1, 2, 3, 4), ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // disjoint arrays
+            ImmutableSet.of(10, 12, 14, 15), ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // disjoint arrays, cardinality mismatch
+            ImmutableSet.of(10, 12, 14), ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // run vs array, subset
+            ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // run vs array, subset
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 2, 3, 4)),
+        Arguments.of( // run vs empty
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of()),
+        Arguments.of( // identical runs, 1 container
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers())),
+        Arguments.of( // identical runs, 2 containers
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()),
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers())),
+        Arguments.of( // disjoint array vs run, either side of container boundary
+            ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of((1 << 16) + 1, (1 << 16) + 2, (1 << 16) + 3, (1 << 16) + 4)),
+        Arguments.of( // disjoint array vs run
+            ContiguousSet.create(Range.closed(3, 1 << 16), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 2)),
+        Arguments.of( // run vs run, overlap with shift
+            ContiguousSet.create(Range.closed(1, 1 << 8), DiscreteDomain.integers()),
+            ContiguousSet.create(Range.closed(1 << 4, 1 << 12), DiscreteDomain.integers())),
+        Arguments.of( // run vs run, subset
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()),
+            ImmutableSet.of(1, 1 << 8)),
+        Arguments.of( // run vs run, overlap with shift, 2 containers
+            ContiguousSet.create(Range.closed(1, 1 << 20), DiscreteDomain.integers()),
+            ImmutableSet.of(1 << 6, 1 << 26)),
+        Arguments.of( // run vs 2 container run, overlap
+            ImmutableSet.of(1, 1 << 16),
+            ContiguousSet.create(Range.closed(0, 1 << 20), DiscreteDomain.integers())),
+        Arguments.of( // bitmap vs intersecting array
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.of(4, 8)),
+        Arguments.of( // bitmap vs bitmap, cardinality mismatch
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 16), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // bitmap vs empty
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.of()),
+        Arguments.of( // identical bitmaps
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test)),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // bitmap vs overlapping but disjoint array
+            ImmutableSet.of(3, 7),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // bitmap vs overlapping but disjoint bitmap
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_3::test)),
+            ImmutableSet.copyOf(
+                Iterables.filter(
+                    ContiguousSet.create(Range.closed(1, 1 << 15), DiscreteDomain.integers()),
+                    DIVISIBLE_BY_4::test))),
+        Arguments.of( // disjoint, large (signed-negative) keys
+            ImmutableSet.of(0xbf09001d, 0xbf090169), ImmutableSet.of(0x8088000e, 0x80880029)));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void testProperSubset(Set superSet, Set subSet) {
+    MutableRoaringBitmap superSetRB = create(superSet);
+    MutableRoaringBitmap subSetRB = create(subSet);
+    assertEquals(superSet.containsAll(subSet), superSetRB.contains(subSetRB));
+    // reverse the test
+    assertEquals(subSet.containsAll(superSet), subSetRB.contains(superSetRB));
+  }
+
+  private MutableRoaringBitmap create(Set set) {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    if (set instanceof ContiguousSet) {
+      ContiguousSet contiguousSet = (ContiguousSet) set;
+      rb.add(contiguousSet.first().longValue(), contiguousSet.last().longValue());
+    } else {
+      for (Integer i : set) {
+        rb.add(i);
+      }
+    }
+    return rb;
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/RoaringBitmapIntervalIntersectionTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/RoaringBitmapIntervalIntersectionTest.java
new file mode 100644
index 000000000..c14036281
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/RoaringBitmapIntervalIntersectionTest.java
@@ -0,0 +1,143 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.roaringbitmap.RoaringBitmap;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class RoaringBitmapIntervalIntersectionTest {
+
+  private static Arguments[] ARGS;
+
+  @BeforeAll
+  public static void before() {
+    ARGS =
+        new Arguments[] {
+          Arguments.of(RoaringBitmap.bitmapOf(1, 2, 3).toMutableRoaringBitmap(), 0, 1 << 16),
+          Arguments.of(RoaringBitmap.bitmapOf(1, 2, 3).toMutableRoaringBitmap(), 1, 1),
+          Arguments.of(
+              RoaringBitmap.bitmapOf(1 << 31 | 1 << 30).toMutableRoaringBitmap(), 0, 1 << 16),
+          Arguments.of(RoaringBitmap.bitmapOf(1 << 31 | 1 << 30).toMutableRoaringBitmap(), 0, 256),
+          Arguments.of(
+              RoaringBitmap.bitmapOf(1, 1 << 31 | 1 << 30).toMutableRoaringBitmap(), 0, 256),
+          Arguments.of(
+              RoaringBitmap.bitmapOf(1, 1 << 16, 1 << 31 | 1 << 30).toMutableRoaringBitmap(),
+              0,
+              1L << 32),
+          Arguments.of(
+              testCase()
+                  .withArrayAt(10)
+                  .withBitmapAt(20)
+                  .withRunAt(30)
+                  .withRange(70000L, 150000L)
+                  .build()
+                  .toMutableRoaringBitmap(),
+              70000L,
+              150000L),
+          Arguments.of(
+              testCase()
+                  .withArrayAt(10)
+                  .withBitmapAt(20)
+                  .withRunAt(30)
+                  .withRange(70000L, 150000L)
+                  .build()
+                  .toMutableRoaringBitmap(),
+              71000L,
+              140000L),
+          Arguments.of(
+              testCase()
+                  .withArrayAt(0)
+                  .withBitmapAt(1)
+                  .withRunAt(20)
+                  .build()
+                  .toMutableRoaringBitmap(),
+              67000,
+              150000),
+          Arguments.of(
+              testCase()
+                  .withBitmapAt(0)
+                  .withArrayAt(1)
+                  .withRunAt(20)
+                  .build()
+                  .toMutableRoaringBitmap(),
+              67000,
+              150000),
+          Arguments.of(
+              testCase()
+                  .withBitmapAt(0)
+                  .withRunAt(1)
+                  .withArrayAt(20)
+                  .build()
+                  .toMutableRoaringBitmap(),
+              67000,
+              150000),
+          Arguments.of(
+              testCase()
+                  .withArrayAt(0)
+                  .withArrayAt(1)
+                  .withArrayAt(2)
+                  .withBitmapAt(200)
+                  .withRunAt(205)
+                  .build()
+                  .toMutableRoaringBitmap(),
+              199 * (1 << 16),
+              200 * (1 << 16) + (1 << 14))
+        };
+  }
+
+  @AfterAll
+  public static void after() {
+    ARGS = null;
+  }
+
+  public static Stream params() {
+    return Stream.of(ARGS);
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void test(MutableRoaringBitmap bitmap, long minimum, long supremum) {
+    MutableRoaringBitmap test = new MutableRoaringBitmap();
+    test.add(minimum, supremum);
+    assertEquals(
+        ImmutableRoaringBitmap.intersects(bitmap, test), bitmap.intersects(minimum, supremum));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void testIntersects(MutableRoaringBitmap bitmap, long minimum, long supremum) {
+    MutableRoaringBitmap test = new MutableRoaringBitmap();
+    test.add(minimum, supremum);
+    assertEquals(
+        MutableRoaringBitmap.intersects(bitmap, test), bitmap.intersects(minimum, supremum));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void testContains(MutableRoaringBitmap bitmap, long minimum, long supremum) {
+    MutableRoaringBitmap test = new MutableRoaringBitmap();
+    test.add(minimum, supremum);
+    assertEquals(!test.isEmpty() && bitmap.contains(test), bitmap.contains(minimum, supremum));
+    assertTrue(test.isEmpty() || test.contains(minimum, supremum));
+  }
+
+  @ParameterizedTest
+  @MethodSource("params")
+  public void ifContainsThenIntersects(MutableRoaringBitmap bitmap, long minimum, long supremum) {
+    boolean contains = bitmap.contains(minimum, supremum);
+    boolean intersects = bitmap.intersects(minimum, supremum);
+    assertTrue(!contains || intersects);
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBitSetUtil.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBitSetUtil.java
similarity index 96%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBitSetUtil.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBitSetUtil.java
index dda8cce32..a6f09607e 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestBitSetUtil.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBitSetUtil.java
@@ -1,5 +1,7 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
@@ -8,12 +10,10 @@
 import java.util.BitSet;
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestBitSetUtil {
-  private static BitSet appendRandomBitset(final Random random, final int offset,
-      final BitSet bitset, final int nbits) {
+  private static BitSet appendRandomBitset(
+      final Random random, final int offset, final BitSet bitset, final int nbits) {
     for (int i = 0; i < nbits; i++) {
       final boolean b = random.nextBoolean();
       bitset.set(offset + i, b);
@@ -26,7 +26,6 @@ private static BitSet randomBitset(final Random random, final int offset, final
     return appendRandomBitset(random, offset, bitset, length);
   }
 
-
   private void assertEqualBitsets(final BitSet bitset, final MutableRoaringBitmap bitmap) {
     assertTrue(BufferBitSetUtil.equals(bitset, bitmap));
   }
@@ -138,9 +137,9 @@ public void testSmallBitSet10000000() {
     assertEqualBitsets(bitset, bitmap);
   }
 
-    /*
-    The ByteBuffer->RoaringBitmap just replicate similar tests written for BitSet/long[]->RoaringBitmap
-   */
+  /*
+   The ByteBuffer->RoaringBitmap just replicate similar tests written for BitSet/long[]->RoaringBitmap
+  */
 
   @Test
   public void testEmptyByteBuffer() {
@@ -205,7 +204,7 @@ public void testRandomByteBuffer() {
     final Random random = new Random(8934);
     final int runs = 100;
     final int maxNbits = 500000;
-    for (int i = 0;i < runs; ++i) {
+    for (int i = 0; i < runs; ++i) {
       final int offset = random.nextInt(maxNbits) & Integer.MAX_VALUE;
       final BitSet bitset = randomBitset(random, offset, random.nextInt(maxNbits));
       final MutableRoaringBitmap bitmap = BufferBitSetUtil.bitmapOf(toByteBuffer(bitset));
@@ -233,5 +232,4 @@ public void testByteArrayWithOnly1And10000000thBitSet() {
   private static ByteBuffer toByteBuffer(BitSet bitset) {
     return ByteBuffer.wrap(bitset.toByteArray());
   }
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBufferAdversarialInputs.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBufferAdversarialInputs.java
new file mode 100644
index 000000000..08f123b70
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBufferAdversarialInputs.java
@@ -0,0 +1,123 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.roaringbitmap.TestAdversarialInputs;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.stream.Stream;
+
+public class TestBufferAdversarialInputs {
+
+  public static Stream badFiles() {
+    return TestAdversarialInputs.badFiles();
+  }
+
+  // copy to a temporary file
+  protected static File copy(String resourceName) throws IOException {
+    File tmpFile = File.createTempFile(TestBufferAdversarialInputs.class.getName(), "bin");
+    tmpFile.deleteOnExit();
+
+    try (InputStream input = TestAdversarialInputs.openInputstream(resourceName)) {
+      Files.copy(input, tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+    }
+
+    return tmpFile;
+  }
+
+  public ByteBuffer memoryMap(String resourceName) throws IOException {
+    File tmpfile = copy(resourceName);
+    long totalcount = tmpfile.length();
+    RandomAccessFile memoryMappedFile = new RandomAccessFile(tmpfile, "r");
+    ByteBuffer bb =
+        memoryMappedFile
+            .getChannel()
+            .map(
+                FileChannel.MapMode.READ_ONLY,
+                0,
+                totalcount); // even though we have two bitmaps, we have one map, maps are
+    // expensive!!!
+    memoryMappedFile.close(); // we can safely close
+    bb.position(0);
+    return bb;
+  }
+
+  @Test
+  public void testInputGoodFile1() throws IOException {
+    File file = copy("/testdata/bitmapwithruns.bin");
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    // should not throw an exception
+    rb.deserialize(new DataInputStream(new FileInputStream(file)));
+    assertEquals(rb.getCardinality(), 200100);
+    file.delete();
+  }
+
+  @Test
+  public void testInputGoodFile1Mapped() throws IOException {
+    ByteBuffer bb = memoryMap("/testdata/bitmapwithruns.bin");
+    ImmutableRoaringBitmap rb = new ImmutableRoaringBitmap(bb);
+    assertEquals(rb.getCardinality(), 200100);
+  }
+
+  @Test
+  public void testInputGoodFile2() throws IOException {
+    File file = copy("/testdata/bitmapwithoutruns.bin");
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    // should not throw an exception
+    rb.deserialize(new DataInputStream(new FileInputStream(file)));
+    assertEquals(rb.getCardinality(), 200100);
+    file.delete();
+  }
+
+  @Test
+  public void testInputGoodFile2Mapped() throws IOException {
+    ByteBuffer bb = memoryMap("/testdata/bitmapwithoutruns.bin");
+    ImmutableRoaringBitmap rb = new ImmutableRoaringBitmap(bb);
+    assertEquals(rb.getCardinality(), 200100);
+  }
+
+  @ParameterizedTest
+  @MethodSource("badFiles")
+  public void testInputBadFileDeserialize(String file) {
+    assertThrows(IOException.class, () -> deserialize(file));
+  }
+
+  @ParameterizedTest
+  @MethodSource("badFiles")
+  public void testInputBadFileMap(String file) {
+    if (file.endsWith("7.bin")) {
+      assertThrows(IllegalArgumentException.class, () -> map(file));
+    } else {
+      assertThrows(IndexOutOfBoundsException.class, () -> map(file));
+    }
+  }
+
+  private void deserialize(String fileName) throws IOException {
+    File file = copy(fileName);
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    // should not work
+    rb.deserialize(new DataInputStream(new FileInputStream(file)));
+    file.delete();
+  }
+
+  private void map(String fileName) throws IOException {
+    ByteBuffer bb = memoryMap(fileName);
+    ImmutableRoaringBitmap rb = new ImmutableRoaringBitmap(bb);
+    System.out.println(rb.getCardinality()); // won't get here
+  }
+}
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBufferRangeCardinality.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBufferRangeCardinality.java
new file mode 100644
index 000000000..3abd87683
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestBufferRangeCardinality.java
@@ -0,0 +1,41 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.nio.ByteBuffer;
+import java.nio.LongBuffer;
+import java.util.stream.Stream;
+
+public class TestBufferRangeCardinality {
+
+  public static Stream data() {
+    return Stream.of(
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 3, 8, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 2, 8, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 3, 7, 2),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 0, 7, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9}, 0, 6, 3),
+        Arguments.of(new int[] {1, 3, 5, 7, 9, Short.MAX_VALUE}, 0, Short.MAX_VALUE + 1, 6),
+        Arguments.of(new int[] {1, 10000, 25000, Short.MAX_VALUE - 1}, 0, Short.MAX_VALUE, 4),
+        Arguments.of(
+            new int[] {1 << 3, 1 << 8, 511, 512, 513, 1 << 12, 1 << 14}, 0, Short.MAX_VALUE, 7));
+  }
+
+  @ParameterizedTest(name = "{index}: cardinalityInBitmapRange({0},{1},{2})={3}")
+  @MethodSource("data")
+  public void testCardinalityInBitmapWordRange(int[] elements, int begin, int end, int expected) {
+    LongBuffer array =
+        ByteBuffer.allocateDirect(MappeableBitmapContainer.MAX_CAPACITY / 8).asLongBuffer();
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(array, 0);
+    for (int e : elements) {
+      bc.add((char) e);
+    }
+    assertFalse(bc.isArrayBacked());
+    assertEquals(expected, BufferUtil.cardinalityInBitmapRange(bc.bitmap, begin, end));
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestCompressionRates.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestCompressionRates.java
similarity index 99%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestCompressionRates.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestCompressionRates.java
index 167b30329..57517a8d9 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestCompressionRates.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestCompressionRates.java
@@ -4,10 +4,9 @@
 
 package org.roaringbitmap.buffer;
 
-import org.junit.jupiter.api.Test;
-
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.junit.jupiter.api.Test;
 
 public class TestCompressionRates {
 
@@ -26,5 +25,4 @@ public void SimpleCompressionRateTest() {
       assertTrue(mrb.serializedSizeInBytes() * 8.0 / N < (maxval + 1));
     }
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestContainer.java
similarity index 93%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestContainer.java
index fbc548373..67e30e49b 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestContainer.java
@@ -4,22 +4,23 @@
 
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.roaringbitmap.CharIterator;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
-import org.roaringbitmap.CharIterator;
 
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
-import static org.junit.jupiter.api.Assertions.*;
-
-
 /**
  * Various tests on Container and its subclasses, ArrayContainer, RunContainer and BitmapContainer
  */
@@ -27,12 +28,14 @@
 @Execution(ExecutionMode.CONCURRENT)
 public class TestContainer {
 
-
   @Test
   public void testNames() {
-    assertEquals(new MappeableBitmapContainer().getContainerName(), MappeableContainer.ContainerNames[0]);
-    assertEquals(new MappeableArrayContainer().getContainerName(), MappeableContainer.ContainerNames[1]);
-    assertEquals(new MappeableRunContainer().getContainerName(), MappeableContainer.ContainerNames[2]);
+    assertEquals(
+        new MappeableBitmapContainer().getContainerName(), MappeableContainer.ContainerNames[0]);
+    assertEquals(
+        new MappeableArrayContainer().getContainerName(), MappeableContainer.ContainerNames[1]);
+    assertEquals(
+        new MappeableRunContainer().getContainerName(), MappeableContainer.ContainerNames[2]);
   }
 
   public static boolean checkContent(MappeableContainer c, char[] s) {
@@ -68,7 +71,6 @@ public static boolean checkContent(MappeableContainer c, char[] s) {
     return !fail;
   }
 
-
   public static MappeableContainer makeContainer(char[] ss) {
     MappeableContainer c = new MappeableArrayContainer();
     for (final char s : ss) {
@@ -77,7 +79,6 @@ public static MappeableContainer makeContainer(char[] ss) {
     return c;
   }
 
-
   @Test
   public void inotTest1() {
     // Array container, range is complete
@@ -94,8 +95,6 @@ public void inotTest1() {
     assertTrue(checkContent(c, s));
   }
 
-
-
   @Test
   public void inotTest10() {
     System.out.println("inotTest10");
@@ -108,13 +107,27 @@ public void inotTest10() {
     final MappeableContainer c1 = c.inot(65190, 65201);
     assertTrue(c1 instanceof MappeableArrayContainer);
     assertEquals(14, c1.getCardinality());
-    assertTrue(checkContent(c1,
-        new char[] {0, 2, 4, (char) 65190, (char) 65191, (char) 65192, (char) 65193,
-            (char) 65194, (char) 65195, (char) 65196, (char) 65197, (char) 65198,
-            (char) 65199, (char) 65200}));
+    assertTrue(
+        checkContent(
+            c1,
+            new char[] {
+              0,
+              2,
+              4,
+              (char) 65190,
+              (char) 65191,
+              (char) 65192,
+              (char) 65193,
+              (char) 65194,
+              (char) 65195,
+              (char) 65196,
+              (char) 65197,
+              (char) 65198,
+              (char) 65199,
+              (char) 65200
+            }));
   }
 
-
   @Test
   public void inotTest10A() {
     System.out.println("inotTest10A");
@@ -126,10 +139,27 @@ public void inotTest10A() {
     final MappeableContainer c1 = c.inot(65190, 65201);
     assertTrue(c1 instanceof MappeableRunContainer);
     assertEquals(16, c1.getCardinality());
-    assertTrue(checkContent(c1,
-        new char[] {1, 2, 3, 4, 5, (char) 65190, (char) 65191, (char) 65192, (char) 65193,
-            (char) 65194, (char) 65195, (char) 65196, (char) 65197, (char) 65198,
-            (char) 65199, (char) 65200}));
+    assertTrue(
+        checkContent(
+            c1,
+            new char[] {
+              1,
+              2,
+              3,
+              4,
+              5,
+              (char) 65190,
+              (char) 65191,
+              (char) 65192,
+              (char) 65193,
+              (char) 65194,
+              (char) 65195,
+              (char) 65196,
+              (char) 65197,
+              (char) 65198,
+              (char) 65199,
+              (char) 65200
+            }));
   }
 
   @Test
@@ -202,7 +232,6 @@ public void inotTest4() {
     assertTrue(checkContent(c, content));
   }
 
-
   @Test
   public void inotTest4A() {
     // Run container, range is partial,
@@ -236,7 +265,6 @@ public void inotTest5() {
     c = c.inot(4, 1000); // back, as a bitmap
     assertTrue(c instanceof MappeableBitmapContainer);
     assertTrue(checkContent(c, content));
-
   }
 
   @Test
@@ -260,7 +288,6 @@ public void inotTest5A() {
     c = c.inot(4, 1000); // back, as a bitmap
     assertTrue(c instanceof MappeableRunContainer);
     assertTrue(checkContent(c, content));
-
   }
 
   @Test
@@ -339,7 +366,6 @@ public void inotTest8() {
     assertTrue(checkContent(c, content));
   }
 
-
   // mostly same tests, except for not. (check original unaffected)
   @Test
   public void notTest1() {
@@ -465,7 +491,6 @@ public void notTest3() {
     }
   }
 
-
   @Test
   public void notTest4() {
     System.out.println("notTest4");
@@ -638,7 +663,6 @@ public void notTest9() {
     assertTrue(checkContent(c2, content));
   }
 
-
   @Test
   public void numberOfRuns() {
     char[] positions = {3, 4, 5, 10, 11, 13, 15, 62, 63, 64, 65};
@@ -656,8 +680,6 @@ public void numberOfRuns() {
     assertEquals(rc.numberOfRuns(), bc.numberOfRuns());
   }
 
-
-
   @Test
   public void rangeOfOnesTest1() {
     final MappeableContainer c = MappeableContainer.rangeOfOnes(4, 11); // sparse
@@ -681,8 +703,6 @@ public void rangeOfOnesTest2() {
     assertEquals(35000 - 1000 + 1, c.getCardinality());
   }
 
-
-
   @Test
   public void rangeOfOnesTest2A() {
     final MappeableContainer c = MappeableContainer.rangeOfOnes(1000, 35001); // dense
@@ -741,7 +761,6 @@ public void transitionTest() {
     c = c.runOptimize();
     assertEquals(c.getCardinality(), 1);
     assertTrue(c instanceof MappeableArrayContainer);
-
   }
 
   @Test
@@ -751,8 +770,10 @@ public void testXorContainer() throws Exception {
     MappeableContainer bc1 = new MappeableBitmapContainer().add(10, 20);
     MappeableContainer bc2 = new MappeableBitmapContainer().add(21, 30);
     MappeableContainer ac1 = new MappeableArrayContainer().add((char) 3).add((char) 79);
-    MappeableContainer ac2 = new MappeableArrayContainer().add((char) 45).add((char) 56).add((char) 109);
-    for (Set test : Sets.powerSet(ImmutableSet.of(rc1, rc2, bc1, bc2, ac1, ac2))) {
+    MappeableContainer ac2 =
+        new MappeableArrayContainer().add((char) 45).add((char) 56).add((char) 109);
+    for (Set test :
+        Sets.powerSet(ImmutableSet.of(rc1, rc2, bc1, bc2, ac1, ac2))) {
       Iterator it = test.iterator();
       if (test.size() == 1) { // compare with self
         MappeableContainer x = it.next();
@@ -828,7 +849,7 @@ public void testConsistentToString() {
     MappeableArrayContainer ac = new MappeableArrayContainer();
     MappeableBitmapContainer bc = new MappeableBitmapContainer();
     MappeableRunContainer rc = new MappeableRunContainer();
-    for (char i : new char[]{0, 2, 17, Short.MAX_VALUE, (char)-3, (char)-1}) {
+    for (char i : new char[] {0, 2, 17, Short.MAX_VALUE, (char) -3, (char) -1}) {
       ac.add(i);
       bc.add(i);
       rc.add(i);
@@ -837,11 +858,8 @@ public void testConsistentToString() {
 
     assertEquals(expected, ac.toString());
     assertEquals(expected, bc.toString());
-    String normalizedRCstr = rc.toString()
-        .replaceAll("\\d+\\]\\[", "")
-        .replace('[', '{')
-        .replaceFirst(",\\d+\\]", "}");
+    String normalizedRCstr =
+        rc.toString().replaceAll("\\d+\\]\\[", "").replace('[', '{').replaceFirst(",\\d+\\]", "}");
     assertEquals(expected, normalizedRCstr);
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestExamples.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestExamples.java
similarity index 90%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestExamples.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestExamples.java
index f3cb11ec7..aad1ec531 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestExamples.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestExamples.java
@@ -6,7 +6,11 @@
 
 import org.junit.jupiter.api.Test;
 
-import java.io.*;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestFastAggregation.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestFastAggregation.java
new file mode 100644
index 000000000..24da6df2d
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestFastAggregation.java
@@ -0,0 +1,451 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.roaringbitmap.SeededTestData.TestDataSet.testCase;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestFastAggregation {
+
+  private static ImmutableRoaringBitmap toDirect(MutableRoaringBitmap r) {
+    ByteBuffer buffer = ByteBuffer.allocateDirect(r.serializedSizeInBytes());
+    r.serialize(buffer);
+    buffer.flip();
+    return new ImmutableRoaringBitmap(buffer);
+  }
+
+  private static ImmutableRoaringBitmap toMapped(MutableRoaringBitmap r) {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    DataOutputStream dos = new DataOutputStream(bos);
+    try {
+      r.serialize(dos);
+      dos.close();
+    } catch (IOException e) {
+      throw new RuntimeException(e.toString());
+    }
+    ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
+    return new ImmutableRoaringBitmap(bb);
+  }
+
+  @Test
+  public void testNaiveAnd() {
+    int[] array1 = {39173, 39174};
+    int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179};
+    int[] array3 = {39173, 39174};
+    int[] array4 = {};
+    MutableRoaringBitmap data1 = MutableRoaringBitmap.bitmapOf(array1);
+    MutableRoaringBitmap data2 = MutableRoaringBitmap.bitmapOf(array2);
+    MutableRoaringBitmap data3 = MutableRoaringBitmap.bitmapOf(array3);
+    MutableRoaringBitmap data4 = MutableRoaringBitmap.bitmapOf(array4);
+    assertEquals(data3, BufferFastAggregation.naive_and(data1, data2));
+    assertEquals(new MutableRoaringBitmap(), BufferFastAggregation.naive_and(data4));
+  }
+
+  @Test
+  public void testPriorityQueueOr() {
+    int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767};
+    int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179};
+    int[] array3 = {
+      1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178, 39179
+    };
+    int[] array4 = {};
+    ArrayList data5 = new ArrayList<>();
+    ArrayList data6 = new ArrayList<>();
+    MutableRoaringBitmap data1 = MutableRoaringBitmap.bitmapOf(array1);
+    MutableRoaringBitmap data2 = MutableRoaringBitmap.bitmapOf(array2);
+    MutableRoaringBitmap data3 = MutableRoaringBitmap.bitmapOf(array3);
+    MutableRoaringBitmap data4 = MutableRoaringBitmap.bitmapOf(array4);
+    data5.add(data1);
+    data5.add(data2);
+    assertEquals(data3, BufferFastAggregation.priorityqueue_or(data1, data2));
+    assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1));
+    assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1, data4));
+    assertEquals(data3, BufferFastAggregation.priorityqueue_or(data5.iterator()));
+    assertEquals(
+        new MutableRoaringBitmap(), BufferFastAggregation.priorityqueue_or(data6.iterator()));
+    data6.add(data1);
+    assertEquals(data1, BufferFastAggregation.priorityqueue_or(data6.iterator()));
+  }
+
+  @Test
+  public void testPriorityQueueXor() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767};
+          int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179};
+          int[] array3 = {
+            1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178,
+            39179
+          };
+          ImmutableRoaringBitmap data1 = MutableRoaringBitmap.bitmapOf(array1);
+          ImmutableRoaringBitmap data2 = MutableRoaringBitmap.bitmapOf(array2);
+          ImmutableRoaringBitmap data3 = MutableRoaringBitmap.bitmapOf(array3);
+          assertEquals(data3, BufferFastAggregation.priorityqueue_xor(data1, data2));
+          BufferFastAggregation.priorityqueue_xor(data1);
+        });
+  }
+
+  @Test
+  public void testNaiveAndMapped() {
+    int[] array1 = {39173, 39174};
+    int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179};
+    int[] array3 = {39173, 39174};
+    int[] array4 = {};
+    ImmutableRoaringBitmap data1 = toMapped(MutableRoaringBitmap.bitmapOf(array1));
+    ImmutableRoaringBitmap data2 = toMapped(MutableRoaringBitmap.bitmapOf(array2));
+    ImmutableRoaringBitmap data3 = toMapped(MutableRoaringBitmap.bitmapOf(array3));
+    ImmutableRoaringBitmap data4 = toMapped(MutableRoaringBitmap.bitmapOf(array4));
+    assertEquals(data3, BufferFastAggregation.naive_and(data1, data2));
+    assertEquals(new MutableRoaringBitmap(), BufferFastAggregation.naive_and(data4));
+  }
+
+  @Test
+  public void testPriorityQueueOrMapped() {
+    int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767};
+    int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179};
+    int[] array3 = {
+      1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178, 39179
+    };
+    int[] array4 = {};
+    ArrayList data5 = new ArrayList<>();
+    ArrayList data6 = new ArrayList<>();
+    ImmutableRoaringBitmap data1 = toMapped(MutableRoaringBitmap.bitmapOf(array1));
+    ImmutableRoaringBitmap data2 = toMapped(MutableRoaringBitmap.bitmapOf(array2));
+    ImmutableRoaringBitmap data3 = toMapped(MutableRoaringBitmap.bitmapOf(array3));
+    ImmutableRoaringBitmap data4 = toMapped(MutableRoaringBitmap.bitmapOf(array4));
+    data5.add(data1);
+    data5.add(data2);
+    assertEquals(data3, BufferFastAggregation.priorityqueue_or(data1, data2));
+    assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1));
+    assertEquals(data1, BufferFastAggregation.priorityqueue_or(data1, data4));
+    assertEquals(data3, BufferFastAggregation.priorityqueue_or(data5.iterator()));
+    assertEquals(
+        new MutableRoaringBitmap(), BufferFastAggregation.priorityqueue_or(data6.iterator()));
+    data6.add(data1);
+    assertEquals(data1, BufferFastAggregation.priorityqueue_or(data6.iterator()));
+  }
+
+  public void testBigOrMapped() {
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb3 = new MutableRoaringBitmap();
+    for (int k = 100; k < 10000; ++k) {
+      if ((k % 3) == 0) {
+        rb1.add(k);
+      }
+      if ((k % 3) == 1) {
+        rb2.add(k);
+      }
+      if ((k % 3) == 2) {
+        rb3.add(k);
+      }
+    }
+    ImmutableRoaringBitmap data1 = toMapped(rb1);
+    ImmutableRoaringBitmap data2 = toMapped(rb2);
+    ImmutableRoaringBitmap data3 = toMapped(rb3);
+    MutableRoaringBitmap mrb = data1.clone().toMutableRoaringBitmap();
+    mrb.add(100L, 10000L);
+    assertEquals(mrb, BufferFastAggregation.or(data1, data2, data3));
+  }
+
+  @Test
+  public void testPriorityQueueXorMapped() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          int[] array1 = {1232, 3324, 123, 43243, 1322, 7897, 8767};
+          int[] array2 = {39173, 39174, 39175, 39176, 39177, 39178, 39179};
+          int[] array3 = {
+            1232, 3324, 123, 43243, 1322, 7897, 8767, 39173, 39174, 39175, 39176, 39177, 39178,
+            39179
+          };
+          ImmutableRoaringBitmap data1 = toMapped(MutableRoaringBitmap.bitmapOf(array1));
+          ImmutableRoaringBitmap data2 = toMapped(MutableRoaringBitmap.bitmapOf(array2));
+          ImmutableRoaringBitmap data3 = toMapped(MutableRoaringBitmap.bitmapOf(array3));
+          assertEquals(data3, BufferFastAggregation.priorityqueue_xor(data1, data2));
+          BufferFastAggregation.priorityqueue_xor(data1);
+        });
+  }
+
+  public static Stream bitmaps() {
+    return Stream.of(
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withBitmapAt(0)
+                    .withRunAt(1)
+                    .withArrayAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withRunAt(1)
+                    .withArrayAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withRunAt(1)
+                    .withArrayAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withArrayAt(0)
+                    .withRunAt(1)
+                    .withBitmapAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withArrayAt(0)
+                    .withRunAt(1)
+                    .withBitmapAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withArrayAt(0)
+                    .withRunAt(1)
+                    .withBitmapAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(3)
+                    .withRunAt(4)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withArrayAt(0)
+                    .withBitmapAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withRunAt(0)
+                    .withArrayAt(1)
+                    .withBitmapAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withRunAt(1)
+                    .withArrayAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(2)
+                    .withRunAt(4)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withArrayAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withArrayAt(0)
+                    .withArrayAt(1)
+                    .withArrayAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withBitmapAt(2)
+                    .withBitmapAt(4)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withRunAt(0)
+                    .withRunAt(1)
+                    .withRunAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withArrayAt(0)
+                    .withArrayAt(1)
+                    .withArrayAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withBitmapAt(2)
+                    .withArrayAt(4)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withRunAt(0)
+                    .withRunAt(1)
+                    .withArrayAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase()
+                    .withArrayAt(0)
+                    .withArrayAt(1)
+                    .withBitmapAt(2)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withBitmapAt(2)
+                    .withBitmapAt(4)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withRunAt(0)
+                    .withRunAt(1)
+                    .withBitmapAt(2)
+                    .build()
+                    .toMutableRoaringBitmap())),
+        Arguments.of(
+            Arrays.asList(
+                testCase().withArrayAt(20).build().toMutableRoaringBitmap(),
+                testCase()
+                    .withBitmapAt(0)
+                    .withBitmapAt(1)
+                    .withBitmapAt(4)
+                    .build()
+                    .toMutableRoaringBitmap(),
+                testCase()
+                    .withRunAt(0)
+                    .withRunAt(1)
+                    .withBitmapAt(3)
+                    .build()
+                    .toMutableRoaringBitmap())));
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testWorkShyAnd")
+  public void testWorkShyAnd(List list) {
+    ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]);
+    long[] buffer = new long[1024];
+    MutableRoaringBitmap result = BufferFastAggregation.and(buffer, bitmaps);
+    MutableRoaringBitmap expected = BufferFastAggregation.naive_and(bitmaps);
+    assertEquals(expected, result);
+    result = BufferFastAggregation.and(bitmaps);
+    assertEquals(expected, result);
+    result = BufferFastAggregation.workAndMemoryShyAnd(buffer, bitmaps);
+    assertEquals(expected, result);
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testWorkShyAnd")
+  public void testWorkShyAndIterator(List bitmaps) {
+    long[] buffer = new long[1024];
+    MutableRoaringBitmap result = BufferFastAggregation.and(buffer, bitmaps.iterator());
+    MutableRoaringBitmap expected = BufferFastAggregation.naive_and(bitmaps.iterator());
+    assertEquals(expected, result);
+    result = BufferFastAggregation.and(bitmaps.iterator());
+    assertEquals(expected, result);
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testWorkShyAnd")
+  public void testWorkShyAndDirect(List list) {
+    ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]);
+    for (int i = 0; i < bitmaps.length; ++i) {
+      bitmaps[i] = toDirect((MutableRoaringBitmap) bitmaps[i]);
+    }
+    long[] buffer = new long[1024];
+    MutableRoaringBitmap result = BufferFastAggregation.and(buffer, bitmaps);
+    MutableRoaringBitmap expected = BufferFastAggregation.naive_and(bitmaps);
+    assertEquals(expected, result);
+    result = BufferFastAggregation.and(bitmaps);
+    assertEquals(expected, result);
+    result = BufferFastAggregation.workAndMemoryShyAnd(buffer, bitmaps);
+    assertEquals(expected, result);
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testAndCardinality")
+  public void testAndCardinality(List list) {
+    ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]);
+    for (int length = 0; length <= bitmaps.length; length++) {
+      ImmutableRoaringBitmap[] subset = Arrays.copyOf(bitmaps, length);
+      ImmutableRoaringBitmap and = BufferFastAggregation.and(subset);
+      int andCardinality = BufferFastAggregation.andCardinality(subset);
+      assertEquals(and.getCardinality(), andCardinality);
+    }
+  }
+
+  @MethodSource("bitmaps")
+  @ParameterizedTest(name = "testOrCardinality")
+  public void testOrCardinality(List list) {
+    ImmutableRoaringBitmap[] bitmaps = list.toArray(new ImmutableRoaringBitmap[0]);
+    for (int length = 0; length <= bitmaps.length; length++) {
+      ImmutableRoaringBitmap[] subset = Arrays.copyOf(bitmaps, length);
+      ImmutableRoaringBitmap or = BufferFastAggregation.or(subset);
+      int andCardinality = BufferFastAggregation.orCardinality(subset);
+      assertEquals(or.getCardinality(), andCardinality);
+    }
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestForEach.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestForEach.java
similarity index 51%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestForEach.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestForEach.java
index 2c4d7f2a4..ea07d5f0e 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestForEach.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestForEach.java
@@ -1,10 +1,10 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import org.junit.jupiter.api.Test;
 import org.roaringbitmap.IntConsumer;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
 
 public class TestForEach {
 
@@ -12,55 +12,62 @@ public class TestForEach {
   public void testContinuous() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     bitmap.add(100L, 10000L);
-  
+
     final MutableInteger cardinality = new MutableInteger();
-    bitmap.forEach(new IntConsumer() {
-      int expected = 100;
-      @Override
-      public void accept(int value) {
-        cardinality.value++;
-        assertEquals(value, expected++);
-      }});
+    bitmap.forEach(
+        new IntConsumer() {
+          int expected = 100;
+
+          @Override
+          public void accept(int value) {
+            cardinality.value++;
+            assertEquals(value, expected++);
+          }
+        });
     assertEquals(cardinality.value, bitmap.getCardinality());
   }
 
   @Test
   public void testDense() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
-    for(int k = 0; k < 100000; k+=3)
-      bitmap.add(k);
-  
+    for (int k = 0; k < 100000; k += 3) bitmap.add(k);
+
     final MutableInteger cardinality = new MutableInteger();
-    bitmap.forEach(new IntConsumer() {
-      int expected = 0;
-      @Override
-      public void accept(int value) {
-        cardinality.value++;
-        assertEquals(value, expected);
-        expected += 3;
-      }});
+    bitmap.forEach(
+        new IntConsumer() {
+          int expected = 0;
+
+          @Override
+          public void accept(int value) {
+            cardinality.value++;
+            assertEquals(value, expected);
+            expected += 3;
+          }
+        });
     assertEquals(cardinality.value, bitmap.getCardinality());
   }
-  
 
   @Test
   public void testSparse() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
-    for(int k = 0; k < 100000; k+=3000)
-      bitmap.add(k);
-  
+    for (int k = 0; k < 100000; k += 3000) bitmap.add(k);
+
     final MutableInteger cardinality = new MutableInteger();
-    bitmap.forEach(new IntConsumer() {
-      int expected = 0;
-      @Override
-      public void accept(int value) {
-        cardinality.value++;
-        assertEquals(value, expected);
-        expected+=3000;
-      }});
+    bitmap.forEach(
+        new IntConsumer() {
+          int expected = 0;
+
+          @Override
+          public void accept(int value) {
+            cardinality.value++;
+            assertEquals(value, expected);
+            expected += 3000;
+          }
+        });
     assertEquals(cardinality.value, bitmap.getCardinality());
   }
 }
+
 class MutableInteger {
   public int value = 0;
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmap.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmap.java
similarity index 68%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmap.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmap.java
index 6af7d67d8..20dfa11ff 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmap.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmap.java
@@ -4,22 +4,41 @@
 
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.Util.toUnsignedLong;
+
+import org.roaringbitmap.IntConsumer;
+import org.roaringbitmap.IntIterator;
+import org.roaringbitmap.InvalidRoaringFormat;
+import org.roaringbitmap.RoaringBitmapWriter;
+import org.roaringbitmap.SeededTestData;
+import org.roaringbitmap.Util;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
-import org.roaringbitmap.*;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.stream.IntStream;
 
-import static org.junit.jupiter.api.Assertions.*;
-import static org.roaringbitmap.Util.toUnsignedLong;
-
 /**
  * Generic testing of the roaring bitmaps
  */
@@ -30,31 +49,32 @@ public class TestImmutableRoaringBitmap {
   static ByteBuffer serializeRoaring(ImmutableRoaringBitmap mrb) throws IOException {
     byte[] backingArray = new byte[mrb.serializedSizeInBytes() + 1024];
     ByteBuffer outbb = ByteBuffer.wrap(backingArray, 1024, mrb.serializedSizeInBytes()).slice();
-    DataOutputStream dos = new DataOutputStream(new OutputStream() {
-      ByteBuffer mBB;
-
-      OutputStream init(ByteBuffer mbb) {
-        mBB = mbb;
-        return this;
-      }
-
-      @Override
-      public void write(byte[] b) {}
-
-      @Override
-      public void write(byte[] b, int off, int l) {
-        mBB.put(b, off, l);
-      }
-
-      @Override
-      public void write(int b) {
-        mBB.put((byte) b);
-      }
-    }.init(outbb));
+    DataOutputStream dos =
+        new DataOutputStream(
+            new OutputStream() {
+              ByteBuffer mBB;
+
+              OutputStream init(ByteBuffer mbb) {
+                mBB = mbb;
+                return this;
+              }
+
+              @Override
+              public void write(byte[] b) {}
+
+              @Override
+              public void write(byte[] b, int off, int l) {
+                mBB.put(b, off, l);
+              }
+
+              @Override
+              public void write(int b) {
+                mBB.put((byte) b);
+              }
+            }.init(outbb));
     mrb.serialize(dos);
     dos.close();
 
-
     return outbb;
   }
 
@@ -106,10 +126,8 @@ public void ANDNOTtest() {
     rr.andNot(rr2);
     assertEquals(correct, rr);
     assertEquals(correct.hashCode(), rr.hashCode());
-
   }
 
-
   @Test
   public void andnottest4() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -133,8 +151,6 @@ public void andnottest4() {
     assertEquals(rb2, off);
   }
 
-
-
   @Test
   public void andnottest4A() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -161,8 +177,6 @@ public void andnottest4A() {
     assertEquals(rb2, off);
   }
 
-
-
   @Test
   public void ANDNOTtestA() {
     // both have run containers
@@ -215,10 +229,8 @@ public void ANDNOTtestA() {
     rr.andNot(rr2);
     assertEquals(correct, rr);
     assertEquals(correct.hashCode(), rr.hashCode());
-
   }
 
-
   @Test
   public void ANDNOTtestB() {
     // first one has run containers but not second.
@@ -270,11 +282,8 @@ public void ANDNOTtestB() {
     rr.andNot(rr2);
     assertEquals(correct, rr);
     assertEquals(correct.hashCode(), rr.hashCode());
-
   }
 
-
-
   @Test
   public void ANDNOTtestC() {
     // second has run containers, but not first
@@ -328,7 +337,6 @@ public void ANDNOTtestC() {
     assertEquals(correct.hashCode(), rr.hashCode());
   }
 
-
   @Test
   public void fliptest1() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -341,8 +349,6 @@ public void fliptest1() {
     assertEquals(result, rb2);
   }
 
-
-
   @Test
   public void fliptest2() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -355,8 +361,6 @@ public void fliptest2() {
     assertEquals(result, rb2);
   }
 
-
-
   @Test
   public void MappeableContainersAccessTest() throws IOException {
     MutableRoaringBitmap mr = new MutableRoaringBitmap();
@@ -435,14 +439,16 @@ public void MappeableContainersAccessTest() throws IOException {
         (mr2.getMappeableRoaringArray().getContainerAtIndex(0)) instanceof MappeableArrayContainer);
     assertTrue(
         (mr2.getMappeableRoaringArray().getContainerAtIndex(1)) instanceof MappeableArrayContainer);
-    assertTrue((mr2.getMappeableRoaringArray()
-        .getContainerAtIndex(2)) instanceof MappeableBitmapContainer);
+    assertTrue(
+        (mr2.getMappeableRoaringArray().getContainerAtIndex(2))
+            instanceof MappeableBitmapContainer);
     assertTrue(
         (mr2.getMappeableRoaringArray().getContainerAtIndex(3)) instanceof MappeableArrayContainer);
     assertTrue(
         (mr2.getMappeableRoaringArray().getContainerAtIndex(4)) instanceof MappeableArrayContainer);
-    assertTrue((mr2.getMappeableRoaringArray()
-        .getContainerAtIndex(5)) instanceof MappeableBitmapContainer);
+    assertTrue(
+        (mr2.getMappeableRoaringArray().getContainerAtIndex(5))
+            instanceof MappeableBitmapContainer);
 
     assertEquals(256, mr2.getMappeableRoaringArray().getContainerAtIndex(0).getCardinality());
     assertEquals(4000, mr2.getMappeableRoaringArray().getContainerAtIndex(1).getCardinality());
@@ -566,7 +572,6 @@ public void MappeableContainersAccessTestA() throws IOException {
     assertEquals(0, mr3.getCardinality());
   }
 
-
   @Test
   public void testContains() throws IOException {
     System.out.println("test contains");
@@ -604,7 +609,6 @@ public void testContainsA() throws IOException {
     }
   }
 
-
   @Test
   public void testHash() {
     MutableRoaringBitmap rbm1 = new MutableRoaringBitmap();
@@ -616,10 +620,8 @@ public void testHash() {
     assertEquals(rbm1.hashCode(), rbm2.hashCode());
   }
 
-
-
   @SuppressWarnings("resource")
-@Test
+  @Test
   public void testHighBits() throws IOException {
     // version without any runcontainers (earlier serialization version)
     for (int offset = 1 << 14; offset < 1 << 18; offset *= 2) {
@@ -632,35 +634,37 @@ public void testHighBits() throws IOException {
       }
       int[] array = rb.toArray();
       ByteBuffer b = ByteBuffer.allocate(rb.serializedSizeInBytes());
-      rb.serialize(new DataOutputStream(new OutputStream() {
-        ByteBuffer mBB;
-
-        @Override
-        public void close() {}
-
-        @Override
-        public void flush() {}
-
-        OutputStream init(final ByteBuffer mbb) {
-          mBB = mbb;
-          return this;
-        }
-
-        @Override
-        public void write(final byte[] b) {
-          mBB.put(b);
-        }
-
-        @Override
-        public void write(final byte[] b, final int off, final int l) {
-          mBB.put(b, off, l);
-        }
-
-        @Override
-        public void write(final int b) {
-          mBB.put((byte) b);
-        }
-      }.init(b)));
+      rb.serialize(
+          new DataOutputStream(
+              new OutputStream() {
+                ByteBuffer mBB;
+
+                @Override
+                public void close() {}
+
+                @Override
+                public void flush() {}
+
+                OutputStream init(final ByteBuffer mbb) {
+                  mBB = mbb;
+                  return this;
+                }
+
+                @Override
+                public void write(final byte[] b) {
+                  mBB.put(b);
+                }
+
+                @Override
+                public void write(final byte[] b, final int off, final int l) {
+                  mBB.put(b, off, l);
+                }
+
+                @Override
+                public void write(final int b) {
+                  mBB.put((byte) b);
+                }
+              }.init(b)));
       b.flip();
       ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(b);
       assertEquals(irb, rb);
@@ -705,35 +709,37 @@ public void testHighBitsA() throws IOException {
       // }
       // assertTrue(pos+runlength == array.length);
       ByteBuffer b = ByteBuffer.allocate(rb.serializedSizeInBytes());
-      rb.serialize(new DataOutputStream(new OutputStream() {
-        ByteBuffer mBB;
-
-        @Override
-        public void close() {}
-
-        @Override
-        public void flush() {}
-
-        OutputStream init(final ByteBuffer mbb) {
-          mBB = mbb;
-          return this;
-        }
-
-        @Override
-        public void write(final byte[] b) {
-          mBB.put(b);
-        }
-
-        @Override
-        public void write(final byte[] b, final int off, final int l) {
-          mBB.put(b, off, l);
-        }
-
-        @Override
-        public void write(final int b) {
-          mBB.put((byte) b);
-        }
-      }.init(b)));
+      rb.serialize(
+          new DataOutputStream(
+              new OutputStream() {
+                ByteBuffer mBB;
+
+                @Override
+                public void close() {}
+
+                @Override
+                public void flush() {}
+
+                OutputStream init(final ByteBuffer mbb) {
+                  mBB = mbb;
+                  return this;
+                }
+
+                @Override
+                public void write(final byte[] b) {
+                  mBB.put(b);
+                }
+
+                @Override
+                public void write(final byte[] b, final int off, final int l) {
+                  mBB.put(b, off, l);
+                }
+
+                @Override
+                public void write(final int b) {
+                  mBB.put((byte) b);
+                }
+              }.init(b)));
       b.flip();
       ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(b);
       assertEquals(irb, rb);
@@ -753,8 +759,6 @@ public void write(final int b) {
     }
   }
 
-
-
   @SuppressWarnings("resource")
   @Test
   public void testProperSerialization() throws IOException {
@@ -768,35 +772,37 @@ public void testProperSerialization() throws IOException {
         }
       }
       ByteBuffer b = ByteBuffer.allocate(r.serializedSizeInBytes());
-      r.serialize(new DataOutputStream(new OutputStream() {
-        ByteBuffer mBB;
-
-        @Override
-        public void close() {}
-
-        @Override
-        public void flush() {}
-
-        OutputStream init(final ByteBuffer mbb) {
-          mBB = mbb;
-          return this;
-        }
-
-        @Override
-        public void write(final byte[] b) {
-          mBB.put(b);
-        }
-
-        @Override
-        public void write(final byte[] b, final int off, final int l) {
-          mBB.put(b, off, l);
-        }
-
-        @Override
-        public void write(final int b) {
-          mBB.put((byte) b);
-        }
-      }.init(b)));
+      r.serialize(
+          new DataOutputStream(
+              new OutputStream() {
+                ByteBuffer mBB;
+
+                @Override
+                public void close() {}
+
+                @Override
+                public void flush() {}
+
+                OutputStream init(final ByteBuffer mbb) {
+                  mBB = mbb;
+                  return this;
+                }
+
+                @Override
+                public void write(final byte[] b) {
+                  mBB.put(b);
+                }
+
+                @Override
+                public void write(final byte[] b, final int off, final int l) {
+                  mBB.put(b, off, l);
+                }
+
+                @Override
+                public void write(final int b) {
+                  mBB.put((byte) b);
+                }
+              }.init(b)));
       b.flip();
       ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(b);
       assertEquals(irb, r);
@@ -820,35 +826,37 @@ public void testProperSerializationA() throws IOException {
       }
       r.runOptimize();
       ByteBuffer b = ByteBuffer.allocate(r.serializedSizeInBytes());
-      r.serialize(new DataOutputStream(new OutputStream() {
-        ByteBuffer mBB;
-
-        @Override
-        public void close() {}
-
-        @Override
-        public void flush() {}
-
-        OutputStream init(final ByteBuffer mbb) {
-          mBB = mbb;
-          return this;
-        }
-
-        @Override
-        public void write(final byte[] b) {
-          mBB.put(b);
-        }
-
-        @Override
-        public void write(final byte[] b, final int off, final int l) {
-          mBB.put(b, off, l);
-        }
-
-        @Override
-        public void write(final int b) {
-          mBB.put((byte) b);
-        }
-      }.init(b)));
+      r.serialize(
+          new DataOutputStream(
+              new OutputStream() {
+                ByteBuffer mBB;
+
+                @Override
+                public void close() {}
+
+                @Override
+                public void flush() {}
+
+                OutputStream init(final ByteBuffer mbb) {
+                  mBB = mbb;
+                  return this;
+                }
+
+                @Override
+                public void write(final byte[] b) {
+                  mBB.put(b);
+                }
+
+                @Override
+                public void write(final byte[] b, final int off, final int l) {
+                  mBB.put(b, off, l);
+                }
+
+                @Override
+                public void write(final int b) {
+                  mBB.put((byte) b);
+                }
+              }.init(b)));
       b.flip();
       ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(b);
       assertEquals(irb.hashCode(), r.hashCode());
@@ -893,14 +901,11 @@ public void testSerializeImmutableA() throws IOException {
     }
   }
 
-
-
-
   @Test
   public void testRangedOr() {
     int length = 1000;
     int NUM_ITER = 10;
-    Random random = new Random(1234);// please use deterministic tests
+    Random random = new Random(1234); // please use deterministic tests
     for (int test = 0; test < 50; ++test) {
       final MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
       final MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
@@ -923,12 +928,12 @@ public void testRangedOr() {
       for (int iter = 0; iter < NUM_ITER; iter++) {
         long rangeStart = random.nextInt(length - 1);
         // +1 to ensure rangeEnd >rangeStart, may
-        long rangeLength = random.nextInt(length - (int)rangeStart) + 1;
+        long rangeLength = random.nextInt(length - (int) rangeStart) + 1;
         long rangeEnd = rangeStart + rangeLength;
         Set expectedResultSet = new TreeSet<>();
-        for (int i = (int)rangeStart; i < rangeEnd; i++) {
+        for (int i = (int) rangeStart; i < rangeEnd; i++) {
           if (unionSet.contains(i)) {
-            expectedResultSet.add((int)i);
+            expectedResultSet.add((int) i);
           }
         }
         List list = new ArrayList<>();
@@ -950,7 +955,7 @@ public void testRangedOr() {
   public void testRangedAnd() {
     int length = 1000;
     int NUM_ITER = 10;
-    Random random = new Random(1234);// please use deterministic tests
+    Random random = new Random(1234); // please use deterministic tests
     for (int test = 0; test < 50; ++test) {
       final MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
       final MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
@@ -999,7 +1004,7 @@ public void testRangedAnd() {
   public void testRangedXor() {
     int length = 1000;
     int NUM_ITER = 10;
-    Random random = new Random(1234);// please use deterministic tests
+    Random random = new Random(1234); // please use deterministic tests
     for (int test = 0; test < 50; ++test) {
       final MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
       final MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
@@ -1026,10 +1031,10 @@ public void testRangedXor() {
       for (int iter = 0; iter < NUM_ITER; iter++) {
         long rangeStart = random.nextInt(length - 1);
         // +1 to ensure rangeEnd >rangeStart, may
-        long rangeLength = random.nextInt(length - (int)rangeStart) + 1;
+        long rangeLength = random.nextInt(length - (int) rangeStart) + 1;
         long rangeEnd = rangeStart + rangeLength;
         Set expectedResultSet = new TreeSet<>();
-        for (int i = (int)rangeStart; i < rangeEnd; i++) {
+        for (int i = (int) rangeStart; i < rangeEnd; i++) {
           if (xorSet.contains(i)) {
             expectedResultSet.add(i);
           }
@@ -1053,7 +1058,7 @@ public void testRangedXor() {
   public void testRangedAndNot() {
     int length = 1000;
     int NUM_ITER = 10;
-    Random random = new Random(1234);// please use deterministic tests
+    Random random = new Random(1234); // please use deterministic tests
     for (int test = 0; test < 50; ++test) {
       final MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
       final MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
@@ -1099,126 +1104,118 @@ public void testRangedAndNot() {
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorAnd() {
 
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
 
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full overlap is on 300000 to 399999
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full overlap is on 300000 to 399999
 
-      MutableRoaringBitmap result = ImmutableRoaringBitmap.and(list.iterator(), 350000L,  450000L); 
-      MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.and(list.iterator(), 350000,  450000);
+    MutableRoaringBitmap result = ImmutableRoaringBitmap.and(list.iterator(), 350000L, 450000L);
+    MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.and(list.iterator(), 350000, 450000);
 
     assertEquals(result, resultInt);
-      assertEquals(50000, result.getCardinality());
+    assertEquals(50000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = ImmutableRoaringBitmap.and(list.iterator(), 300000, 200000);
-      result = ImmutableRoaringBitmap.and(list.iterator(), 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = ImmutableRoaringBitmap.and(list.iterator(), 300000, 200000);
+    result = ImmutableRoaringBitmap.and(list.iterator(), 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorOr() {
 
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full union is 200000 to 499999
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      MutableRoaringBitmap result = ImmutableRoaringBitmap.or(list.iterator(), 250000L,  550000L); 
-      MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.or(list.iterator(), 250000,  550000);
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full union is 200000 to 499999
 
+    MutableRoaringBitmap result = ImmutableRoaringBitmap.or(list.iterator(), 250000L, 550000L);
+    MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.or(list.iterator(), 250000, 550000);
 
     assertEquals(result, resultInt);
-      assertEquals(250000, result.getCardinality());
+    assertEquals(250000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = ImmutableRoaringBitmap.or(list.iterator(), 300000, 200000);
-      result = ImmutableRoaringBitmap.or(list.iterator(), 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = ImmutableRoaringBitmap.or(list.iterator(), 300000, 200000);
+    result = ImmutableRoaringBitmap.or(list.iterator(), 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorAndNot() {
 
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
 
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full andNOToverlap is on 200000 to 299999
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full andNOToverlap is on 200000 to 299999
 
-      MutableRoaringBitmap result = ImmutableRoaringBitmap.andNot(rb1, rb2, 250000L,  450000L); 
-      MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.andNot(rb1, rb2, 250000,  450000);
+    MutableRoaringBitmap result = ImmutableRoaringBitmap.andNot(rb1, rb2, 250000L, 450000L);
+    MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.andNot(rb1, rb2, 250000, 450000);
 
     assertEquals(result, resultInt);
-      assertEquals(50000, result.getCardinality());
+    assertEquals(50000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = ImmutableRoaringBitmap.andNot(rb1, rb2, 300000, 200000);
-      result = ImmutableRoaringBitmap.andNot(rb1, rb2, 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = ImmutableRoaringBitmap.andNot(rb1, rb2, 300000, 200000);
+    result = ImmutableRoaringBitmap.andNot(rb1, rb2, 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedIteratorXor() {
 
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
 
-      List list = new ArrayList<>();
-      list.add(rb1);
-      list.add(rb2);
+    List list = new ArrayList<>();
+    list.add(rb1);
+    list.add(rb2);
 
-      rb1.add(200000L, 400000L);  // two normal positive ranges
-      rb2.add(300000L, 500000L);  // full XOR is 200000 to 299999, 400000-4999999
+    rb1.add(200000L, 400000L); // two normal positive ranges
+    rb2.add(300000L, 500000L); // full XOR is 200000 to 299999, 400000-4999999
 
-      MutableRoaringBitmap result = ImmutableRoaringBitmap.xor(list.iterator(), 250000L,  450000L); 
-      MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.xor(list.iterator(), 250000,  450000);
+    MutableRoaringBitmap result = ImmutableRoaringBitmap.xor(list.iterator(), 250000L, 450000L);
+    MutableRoaringBitmap resultInt = ImmutableRoaringBitmap.xor(list.iterator(), 250000, 450000);
 
     assertEquals(result, resultInt);
-      assertEquals(100000, result.getCardinality());
+    assertEquals(100000, result.getCardinality());
 
-      
-      // empty ranges get empty result
-      resultInt = ImmutableRoaringBitmap.xor(list.iterator(), 300000, 200000);
-      result = ImmutableRoaringBitmap.xor(list.iterator(), 300000L, 200000L);
+    // empty ranges get empty result
+    resultInt = ImmutableRoaringBitmap.xor(list.iterator(), 300000, 200000);
+    result = ImmutableRoaringBitmap.xor(list.iterator(), 300000L, 200000L);
     assertEquals(result, resultInt);
-      assertEquals(0, resultInt.getCardinality());
+    assertEquals(0, resultInt.getCardinality());
   }
 
   @Test
   public void testFirstLast_CreateSparseContainersAfterRun() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
     rb.add(1L, 1 << 14);
-    for(int i = 18; i < 31; ++i) {
+    for (int i = 18; i < 31; ++i) {
       int x = 1 << i;
       rb.add(x);
       assertEquals(1, rb.toImmutableRoaringBitmap().first());
@@ -1229,12 +1226,16 @@ public void testFirstLast_CreateSparseContainersAfterRun() {
 
   @Test
   public void testEmptyFirst() {
-    assertThrows(NoSuchElementException.class, () -> new MutableRoaringBitmap().toImmutableRoaringBitmap().first());
+    assertThrows(
+        NoSuchElementException.class,
+        () -> new MutableRoaringBitmap().toImmutableRoaringBitmap().first());
   }
 
   @Test
   public void testEmptyLast() {
-    assertThrows(NoSuchElementException.class, () -> new MutableRoaringBitmap().toImmutableRoaringBitmap().last());
+    assertThrows(
+        NoSuchElementException.class,
+        () -> new MutableRoaringBitmap().toImmutableRoaringBitmap().last());
   }
 
   @Test
@@ -1251,7 +1252,7 @@ public void testFirstLast() {
     assertEquals(2, rb.toImmutableRoaringBitmap().first());
     assertEquals((1 << 14) - 1, rb.toImmutableRoaringBitmap().last());
 
-    rb.add(1L<< 15, 1L << 30);
+    rb.add(1L << 15, 1L << 30);
     assertEquals(2, rb.toImmutableRoaringBitmap().first());
     assertEquals((1L << 30) - 1, rb.toImmutableRoaringBitmap().last());
   }
@@ -1280,8 +1281,8 @@ public void testHammingSimilarity_BigVsSmall() {
     big.add(1, 2, 3, 4);
     big.add(1L << 17, 1L << 30);
     big.flip((1 << 17) | (1 << 16));
-    for(int i = 1 << 18; i < 1 << 19; ++i) {
-      if(i % 3 == 0) {
+    for (int i = 1 << 18; i < 1 << 19; ++i) {
+      if (i % 3 == 0) {
         big.flip(i);
       }
     }
@@ -1293,8 +1294,8 @@ public void testHammingSimilarity_BigVsSmall() {
   @Test
   public void testHammingSimilarity_Shifted() {
     ImmutableRoaringBitmap baseline = ImmutableRoaringBitmap.bitmapOf(1, 2, 3, 4);
-    ImmutableRoaringBitmap shifted = ImmutableRoaringBitmap.bitmapOf((1 << 17) + 1, (1 << 17) + 2,
-            (1 << 17) + 3, (1 << 17) + 4);
+    ImmutableRoaringBitmap shifted =
+        ImmutableRoaringBitmap.bitmapOf((1 << 17) + 1, (1 << 17) + 2, (1 << 17) + 3, (1 << 17) + 4);
     assertFalse(baseline.isHammingSimilar(shifted, 0));
   }
 
@@ -1372,11 +1373,279 @@ public void testAndNotCardinality_646() {
 
   @Test
   public void testAndNotCardinality_648() {
-    ImmutableRoaringBitmap s1 = ImmutableRoaringBitmap.bitmapOf(-1388308580, 236217409, -805382570, 612285977, 1389629939, 851442526, 375756307, 61533603, 1908301308, 2097309572, 204769050, 703198559, -545810986, 2090296816, -87319453, 158018332, -685188145, -566739002, -1446363859, -372441875, -957637004, -1144076256, -1248859542, -160225853, 14707613, 866274329, 1550526350, 877999004, -1784269953, 1274953255, 1490490469, -1340013077, 2067958239, 51232349, 2060711699, -1802459974, 2039829040, -2079650027, -278950425, 1145674649, 298101576, 1687655442, 1209489632, -762136131, 399832491, 1077638711, -635674559, -1643781464, -1067907341, 144525399, 651571848, 1893053071, -2058528151, 1592871441, 84583235, 374119809, -867104416, -1941224259, 787356209, 1972857336, -720703901, -1310021857, -1831922816, 181898740, 600942551, -1745822849, -856908487, 2060184086, -1217485514, -1680395029, 1539735915, 2042390564, -1539856946, 1824974207, 1695025297, 1908431629, -395090370, -1688185468, 570601902, -701368853, -1211735380, -825285093, 788089714, -857723909, 1400502194, 285106906, -1450842998, -2125215206, 1451519492, -1559357910, 1157633452, -387704829, 2036134025, 1051239778, -1542956455, 357879569, 1962230155, -1994777800, 672516512, 174507423, -299175291, 821891018, 1062886766, -1313955904, 1732661804, -767116537, 1352149580, 2001322279, 1698147357, 40451458, 996819026, 1904959950, 2058544757, 1514282221, 234242255, -1364505429, 1498471146, 1134429786, -918860049, 1430732385, 644983298, 793600316, -1726956640, -538511147, -1945670935, 291567421, 1033590420, -1831809482, 985031287, -773476240, 1724734191, -1364525376, 1208307142, -2126741265, -1851759120, 1083333467, 185208087, -375950074, 48210573, -843304856, -295266615, -843941360, -524390895, -102924717, 836117637, 683196001, -1824825594, -1470017798, -1554712054, 291236023, -907874606, 2068945326, -899352179, -1488751007, -449279886, -1085935420, -2094131785, -474243782, 1306756671, 1353254318, 86944198, 1148225154, 487252515, -229770314, -1484325603, 109043190, -252122045, 1431750974, 1667547537, -1775516477, -512978266, -216545450, -486550865, -1193721685, -1108677522, -628326149, -1568065979, -675571394);
-    ImmutableRoaringBitmap s2 = ImmutableRoaringBitmap.bitmapOf(2060184086, 704452713, 1236293943, -178539376, 2037977331, -78910667, -587409880, 204769050, -854426111, 90628341, -1411939301, -927754519, -211274987, 998450197, -1515133464, -1652963250, 499001553, 383696025, -2019580769, 1583380373, -79264832, 1065614902, 1243463658, 424214238, 1124141647, 271662535, 1415634429, 1893053071, -1624960757, -1933550809, -1170233109, -542340662, -1681838238, 292656484, 1587781520, -1463647396, -124042559, -162307067, 1411905814, -1524651941, 1935844108, 1992426746, 422443777, 679395872, -764857187, -401706366, -2007177999, 1044794027, -1561188953, 1627034126, -401273669, -123973748, -694963705, 838892817, -1640102435, 852253834, -23120023, -2072644924, 1140820264, -550227319, -1692730465, 1491150291, 1607642920, -1015774573, -1801713682, -752796152, -439281693, -792361100, -188208805, 808883165, -1364525376, 896915854, -1672522244, -1718572341);
-    ImmutableRoaringBitmap s3 = ImmutableRoaringBitmap.bitmapOf(-30718004, -1652963250, -762136131, -1552606582, -1933550809, -1230616126, 736584428, -2136360654, 1097548480, 192408815, -295266615);
+    ImmutableRoaringBitmap s1 =
+        ImmutableRoaringBitmap.bitmapOf(
+            -1388308580,
+            236217409,
+            -805382570,
+            612285977,
+            1389629939,
+            851442526,
+            375756307,
+            61533603,
+            1908301308,
+            2097309572,
+            204769050,
+            703198559,
+            -545810986,
+            2090296816,
+            -87319453,
+            158018332,
+            -685188145,
+            -566739002,
+            -1446363859,
+            -372441875,
+            -957637004,
+            -1144076256,
+            -1248859542,
+            -160225853,
+            14707613,
+            866274329,
+            1550526350,
+            877999004,
+            -1784269953,
+            1274953255,
+            1490490469,
+            -1340013077,
+            2067958239,
+            51232349,
+            2060711699,
+            -1802459974,
+            2039829040,
+            -2079650027,
+            -278950425,
+            1145674649,
+            298101576,
+            1687655442,
+            1209489632,
+            -762136131,
+            399832491,
+            1077638711,
+            -635674559,
+            -1643781464,
+            -1067907341,
+            144525399,
+            651571848,
+            1893053071,
+            -2058528151,
+            1592871441,
+            84583235,
+            374119809,
+            -867104416,
+            -1941224259,
+            787356209,
+            1972857336,
+            -720703901,
+            -1310021857,
+            -1831922816,
+            181898740,
+            600942551,
+            -1745822849,
+            -856908487,
+            2060184086,
+            -1217485514,
+            -1680395029,
+            1539735915,
+            2042390564,
+            -1539856946,
+            1824974207,
+            1695025297,
+            1908431629,
+            -395090370,
+            -1688185468,
+            570601902,
+            -701368853,
+            -1211735380,
+            -825285093,
+            788089714,
+            -857723909,
+            1400502194,
+            285106906,
+            -1450842998,
+            -2125215206,
+            1451519492,
+            -1559357910,
+            1157633452,
+            -387704829,
+            2036134025,
+            1051239778,
+            -1542956455,
+            357879569,
+            1962230155,
+            -1994777800,
+            672516512,
+            174507423,
+            -299175291,
+            821891018,
+            1062886766,
+            -1313955904,
+            1732661804,
+            -767116537,
+            1352149580,
+            2001322279,
+            1698147357,
+            40451458,
+            996819026,
+            1904959950,
+            2058544757,
+            1514282221,
+            234242255,
+            -1364505429,
+            1498471146,
+            1134429786,
+            -918860049,
+            1430732385,
+            644983298,
+            793600316,
+            -1726956640,
+            -538511147,
+            -1945670935,
+            291567421,
+            1033590420,
+            -1831809482,
+            985031287,
+            -773476240,
+            1724734191,
+            -1364525376,
+            1208307142,
+            -2126741265,
+            -1851759120,
+            1083333467,
+            185208087,
+            -375950074,
+            48210573,
+            -843304856,
+            -295266615,
+            -843941360,
+            -524390895,
+            -102924717,
+            836117637,
+            683196001,
+            -1824825594,
+            -1470017798,
+            -1554712054,
+            291236023,
+            -907874606,
+            2068945326,
+            -899352179,
+            -1488751007,
+            -449279886,
+            -1085935420,
+            -2094131785,
+            -474243782,
+            1306756671,
+            1353254318,
+            86944198,
+            1148225154,
+            487252515,
+            -229770314,
+            -1484325603,
+            109043190,
+            -252122045,
+            1431750974,
+            1667547537,
+            -1775516477,
+            -512978266,
+            -216545450,
+            -486550865,
+            -1193721685,
+            -1108677522,
+            -628326149,
+            -1568065979,
+            -675571394);
+    ImmutableRoaringBitmap s2 =
+        ImmutableRoaringBitmap.bitmapOf(
+            2060184086,
+            704452713,
+            1236293943,
+            -178539376,
+            2037977331,
+            -78910667,
+            -587409880,
+            204769050,
+            -854426111,
+            90628341,
+            -1411939301,
+            -927754519,
+            -211274987,
+            998450197,
+            -1515133464,
+            -1652963250,
+            499001553,
+            383696025,
+            -2019580769,
+            1583380373,
+            -79264832,
+            1065614902,
+            1243463658,
+            424214238,
+            1124141647,
+            271662535,
+            1415634429,
+            1893053071,
+            -1624960757,
+            -1933550809,
+            -1170233109,
+            -542340662,
+            -1681838238,
+            292656484,
+            1587781520,
+            -1463647396,
+            -124042559,
+            -162307067,
+            1411905814,
+            -1524651941,
+            1935844108,
+            1992426746,
+            422443777,
+            679395872,
+            -764857187,
+            -401706366,
+            -2007177999,
+            1044794027,
+            -1561188953,
+            1627034126,
+            -401273669,
+            -123973748,
+            -694963705,
+            838892817,
+            -1640102435,
+            852253834,
+            -23120023,
+            -2072644924,
+            1140820264,
+            -550227319,
+            -1692730465,
+            1491150291,
+            1607642920,
+            -1015774573,
+            -1801713682,
+            -752796152,
+            -439281693,
+            -792361100,
+            -188208805,
+            808883165,
+            -1364525376,
+            896915854,
+            -1672522244,
+            -1718572341);
+    ImmutableRoaringBitmap s3 =
+        ImmutableRoaringBitmap.bitmapOf(
+            -30718004,
+            -1652963250,
+            -762136131,
+            -1552606582,
+            -1933550809,
+            -1230616126,
+            736584428,
+            -2136360654,
+            1097548480,
+            192408815,
+            -295266615);
     ImmutableRoaringBitmap s1AndS2 = ImmutableRoaringBitmap.and(s1, s2);
-    assertEquals(ImmutableRoaringBitmap.andNot(s1AndS2, s3).getCardinality(), ImmutableRoaringBitmap.andNotCardinality(s1AndS2, s3));
+    assertEquals(
+        ImmutableRoaringBitmap.andNot(s1AndS2, s3).getCardinality(),
+        ImmutableRoaringBitmap.andNotCardinality(s1AndS2, s3));
   }
 
   @Test
@@ -1386,7 +1655,6 @@ public void testRankOverflow() {
     assertEquals(1, ImmutableRoaringBitmap.bitmapOf(65537).rank(65538));
   }
 
-
   @Test
   public void testNegativeAdd() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
@@ -1404,6 +1672,34 @@ public void testNegative_last() {
     assertEquals(-7, bitmap.last());
   }
 
+  @Test
+  public void testFirstLastSigned() {
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(1_111_111, 3_333_333);
+
+    assertEquals(1_111_111, bitmap.firstSigned());
+    assertEquals(3_333_333, bitmap.lastSigned());
+
+    bitmap = MutableRoaringBitmap.bitmapOf(-3_333_333, 3_333_333);
+    assertEquals(-3_333_333, bitmap.firstSigned());
+    assertEquals(3_333_333, bitmap.lastSigned());
+
+    bitmap = MutableRoaringBitmap.bitmapOf(-3_333_333, -1_111_111);
+    assertEquals(-3_333_333, bitmap.firstSigned());
+    assertEquals(-1_111_111, bitmap.lastSigned());
+
+    bitmap = MutableRoaringBitmap.bitmapOfRange(0, 1L << 32);
+    assertEquals(Integer.MIN_VALUE, bitmap.firstSigned());
+    assertEquals(Integer.MAX_VALUE, bitmap.lastSigned());
+  }
+
+  @ParameterizedTest
+  @ValueSource(ints = {Integer.MIN_VALUE, -65_536, 0, 65_536, Integer.MAX_VALUE})
+  public void testFirstLastSigned_SingleValueBitmap(int value) {
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(value);
+    assertEquals(value, bitmap.firstSigned());
+    assertEquals(value, bitmap.lastSigned());
+  }
+
   @Test
   public void testContainsRange_ContiguousBitmap() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
@@ -1436,22 +1732,22 @@ public void testContainsRange_SmallBitmap() {
 
   @Test
   public void testContainsRange_DirtyBitmap() {
-    RoaringBitmapWriter writer = RoaringBitmapWriter.bufferWriter().constantMemory().get();
-    IntStream.range(0, 1_000_000)
-            .map(i -> i * 2)
-            .forEach(writer::add);
+    RoaringBitmapWriter writer =
+        RoaringBitmapWriter.bufferWriter().constantMemory().get();
+    IntStream.range(0, 1_000_000).map(i -> i * 2).forEach(writer::add);
     writer.flush();
     MutableRoaringBitmap bitmap = writer.getUnderlying();
     assertFalse(bitmap.contains(0L, 2_000_000L));
     assertFalse(bitmap.contains(0L, 2L));
     assertTrue(bitmap.contains(0L, 1L));
-    assertTrue(bitmap.contains(1L << 10, 1| (1L << 10)));
+    assertTrue(bitmap.contains(1L << 10, 1 | (1L << 10)));
     assertFalse(bitmap.contains(1L << 31, 1L << 32));
   }
 
   @Test
   public void testNextValue() {
-    ImmutableRoaringBitmap bitmap = SeededTestData.TestDataSet.testCase()
+    ImmutableRoaringBitmap bitmap =
+        SeededTestData.TestDataSet.testCase()
             .withRunAt(0)
             .withBitmapAt(1)
             .withArrayAt(2)
@@ -1466,7 +1762,7 @@ public void testNextValue() {
     long b1 = 0;
     int b2 = 0;
     while (b1 >= 0 && b2 >= 0) {
-      b1 = bitmap.nextValue((int)b1 + 1);
+      b1 = bitmap.nextValue((int) b1 + 1);
       b2 = bitset.nextSetBit(b2 + 1);
       assertEquals(b1, b2);
     }
@@ -1474,14 +1770,16 @@ public void testNextValue() {
 
   @Test
   public void testPreviousValue() {
-    MutableRoaringBitmap bitmap = SeededTestData.TestDataSet.testCase()
+    MutableRoaringBitmap bitmap =
+        SeededTestData.TestDataSet.testCase()
             .withRunAt(0)
             .withBitmapAt(1)
             .withArrayAt(2)
             .withRunAt(3)
             .withBitmapAt(4)
             .withArrayAt(5)
-            .build().toMutableRoaringBitmap();
+            .build()
+            .toMutableRoaringBitmap();
 
     BitSet bitset = new BitSet();
     bitmap.forEach((IntConsumer) bitset::set);
@@ -1497,6 +1795,23 @@ public void testPreviousValue() {
     }
   }
 
+  @Test
+  public void testPreviousValue_AbsentTargetContainer() {
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(-1, 2, 3, 131072);
+    assertEquals(3, bitmap.previousValue(65536));
+    assertEquals(131072, bitmap.previousValue(Integer.MAX_VALUE));
+    assertEquals(131072, bitmap.previousValue(-131072));
+
+    bitmap = MutableRoaringBitmap.bitmapOf(131072);
+    assertEquals(-1, bitmap.previousValue(65536));
+  }
+
+  @Test
+  public void testPreviousValue_LastReturnedAsUnsignedLong() {
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(-650002, -650001, -650000);
+    assertEquals(Util.toUnsignedLong(-650000), bitmap.previousValue(-1));
+  }
+
   @Test
   public void testRangeCardinalityAtBoundary() {
     // See https://github.com/RoaringBitmap/RoaringBitmap/issues/285
@@ -1505,14 +1820,14 @@ public void testRangeCardinalityAtBoundary() {
     assertEquals(1, r.rangeCardinality(60000, 70000));
   }
 
-
   @Test
   public void testAbsentBits() {
     int count = 50;
     List offsets = Arrays.asList(0, 1, -1, 10, -10, 100, -100);
 
     for (int i = 0; i < count; i++) {
-      ImmutableRoaringBitmap bitmap = SeededTestData.TestDataSet.testCase()
+      ImmutableRoaringBitmap bitmap =
+          SeededTestData.TestDataSet.testCase()
               .withRunAt(0)
               .withBitmapAt(1)
               .withArrayAt(2)
@@ -1539,6 +1854,19 @@ public void testAbsentBits() {
 
   @Test
   public void invalidCookie() {
-    assertThrows(InvalidRoaringFormat.class, () -> new ImmutableRoaringBitmap(ByteBuffer.allocate(8)));
+    assertThrows(
+        InvalidRoaringFormat.class, () -> new ImmutableRoaringBitmap(ByteBuffer.allocate(8)));
+  }
+
+  @Test
+  public void testContainerSizeRoaringBitmapMultiple() {
+    ImmutableRoaringBitmap r = ImmutableRoaringBitmap.bitmapOf(1, 1000000);
+    assertEquals(2, r.getContainerCount());
+  }
+
+  @Test
+  public void testContainerSizeRoaringBitmapSingle() {
+    ImmutableRoaringBitmap r = ImmutableRoaringBitmap.bitmapOf(1);
+    assertEquals(1, r.getContainerCount());
   }
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmapOrNot.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmapOrNot.java
new file mode 100644
index 000000000..432f5a337
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestImmutableRoaringBitmapOrNot.java
@@ -0,0 +1,427 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.Util.toUnsignedLong;
+
+import org.roaringbitmap.IntIterator;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestImmutableRoaringBitmapOrNot {
+
+  @Test
+  public void orNot1() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+
+    rb.add(2);
+    rb.add(1);
+    rb.add(1 << 16); // 65536
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
+
+    rb2.add(1 << 16); // 65536
+    rb2.add(3 << 16); // 196608
+
+    rb.orNot(rb2, (4 << 16) - 1);
+
+    assertEquals((4 << 16) - 1, rb.getCardinality());
+
+    IntIterator iterator = rb.getIntIterator();
+
+    for (int i = 0; i < (4 << 16) - 1; ++i) {
+      assertTrue(iterator.hasNext());
+      assertEquals(i, iterator.next());
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot2() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+
+    rb.add(0);
+    rb.add(1 << 16); // 65536
+    rb.add(3 << 16); // 196608
+
+    rb2.add((4 << 16) - 1); // 262143
+
+    rb.orNot(rb2, 4 << 16);
+
+    assertEquals((4 << 16) - 1, rb.getCardinality());
+
+    IntIterator iterator = rb.getIntIterator();
+
+    for (int i = 0; i < (4 << 16) - 1; ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next());
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot3() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    rb.add(2 << 16);
+
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    rb2.add(1 << 14); // 16384
+    rb2.add(3 << 16); // 196608
+
+    rb.orNot(rb2, (5 << 16));
+    assertEquals((5 << 16) - 2, rb.getCardinality());
+
+    IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (5 << 16); ++i) {
+      if ((i != (1 << 14)) && (i != (3 << 16))) {
+        assertTrue(iterator.hasNext(), "Error on iteration " + i);
+        assertEquals(i, iterator.next(), "Error on iteration " + i);
+      }
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot4() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    rb.add(1);
+
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    rb2.add(3 << 16); // 196608
+
+    rb.orNot(rb2, (2 << 16) + (2 << 14)); // 131072 + 32768 = 163840
+    assertEquals((2 << 16) + (2 << 14), rb.getCardinality());
+
+    IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (2 << 16) + (2 << 14); ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next(), "Error on iteration " + i);
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot5() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+
+    rb.add(1);
+    rb.add(1 << 16); // 65536
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
+
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+
+    rb.orNot(rb2, (5 << 16));
+    assertEquals((5 << 16), rb.getCardinality());
+
+    IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (5 << 16); ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next(), "Error on iteration " + i);
+    }
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot6() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+
+    rb.add(1);
+    rb.add((1 << 16) - 1); // 65535
+    rb.add(1 << 16); // 65536
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
+
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+
+    rb.orNot(rb2, (1 << 14));
+
+    // {[0, 2^14], 65535, 65536, 131072, 196608}
+    assertEquals((1 << 14) + 4, rb.getCardinality());
+
+    IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (1 << 14); ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next(), "Error on iteration " + i);
+    }
+
+    assertTrue(iterator.hasNext());
+    assertEquals((1 << 16) - 1, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(1 << 16, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(2 << 16, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(3 << 16, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot7() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+
+    rb.add(1 << 16); // 65536
+    rb.add(2 << 16); // 131072
+    rb.add(3 << 16); // 196608
+
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+
+    rb.orNot(rb2, (1 << 14));
+
+    // {[0, 2^14], 65536, 131072, 196608}
+    assertEquals((1 << 14) + 3, rb.getCardinality());
+
+    IntIterator iterator = rb.getIntIterator();
+    for (int i = 0; i < (1 << 14); ++i) {
+      assertTrue(iterator.hasNext(), "Error on iteration " + i);
+      assertEquals(i, iterator.next(), "Error on iteration " + i);
+    }
+
+    assertTrue(iterator.hasNext());
+    assertEquals(1 << 16, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(2 << 16, iterator.next());
+
+    assertTrue(iterator.hasNext());
+    assertEquals(3 << 16, iterator.next());
+
+    assertFalse(iterator.hasNext());
+  }
+
+  @Test
+  public void orNot9() {
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+
+    rb1.add(1 << 16); // 65536
+    rb1.add(2 << 16); // 131072
+    rb1.add(3 << 16); // 196608
+
+    {
+      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+      MutableRoaringBitmap answer1 = ImmutableRoaringBitmap.orNot(rb1, rb2, (1 << 14));
+
+      // {[0, 2^14] | {65536} {131072} {196608}}
+      assertEquals((1 << 14) + 3, answer1.getCardinality());
+
+      IntIterator iterator1 = answer1.getIntIterator();
+      for (int i = 0; i < (1 << 14); ++i) {
+        assertTrue(iterator1.hasNext(), "Error on iteration " + i);
+        assertEquals(i, iterator1.next(), "Error on iteration " + i);
+      }
+      assertEquals(1 << 16, iterator1.next());
+      assertEquals(2 << 16, iterator1.next());
+      assertEquals(3 << 16, iterator1.next());
+    }
+
+    {
+      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+      MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb1, rb2, (2 << 16));
+
+      // {[0, 2^16] | 131072, 196608}
+      assertEquals((2 << 16) + 2, answer.getCardinality());
+
+      IntIterator iterator = answer.getIntIterator();
+      for (int i = 0; i < (2 << 16) + 1; ++i) {
+        assertTrue(iterator.hasNext(), "Error on iteration " + i);
+        assertEquals(i, iterator.next(), "Error on iteration " + i);
+      }
+      assertEquals(196608, iterator.next());
+    }
+
+    {
+      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+      rb2.add((1 << 16) + (1 << 13));
+      rb2.add((1 << 16) + (1 << 14));
+      rb2.add((1 << 16) + (1 << 15));
+      MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb1, rb2, (2 << 16));
+
+      // {[0, 2^16] | 196608}
+      assertEquals((2 << 16) - 1, answer.getCardinality());
+
+      IntIterator iterator = answer.getIntIterator();
+      for (int i = 0; i < (2 << 16) + 1; ++i) {
+        if ((i != (1 << 16) + (1 << 13))
+            && (i != (1 << 16) + (1 << 14))
+            && (i != (1 << 16) + (1 << 15))) {
+          assertTrue(iterator.hasNext(), "Error on iteration " + i);
+          assertEquals(i, iterator.next(), "Error on iteration " + i);
+        }
+      }
+      assertEquals(196608, iterator.next());
+    }
+
+    {
+      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+      rb2.add(1 << 16);
+      rb2.add(3 << 16);
+      rb2.add(4 << 16);
+
+      MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb1, rb2, (5 << 16));
+
+      // {[0, 2^16]}
+      assertEquals((5 << 16) - 1, answer.getCardinality());
+
+      IntIterator iterator = answer.getIntIterator();
+      for (int i = 0; i < (5 << 16); ++i) {
+        if (i != (4 << 16)) {
+          assertTrue(iterator.hasNext(), "Error on iteration " + i);
+          assertEquals(i, iterator.next(), "Error on iteration " + i);
+        }
+      }
+      assertFalse(iterator.hasNext(), "Number of elements " + (2 << 16));
+    }
+
+    {
+      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+      rb2.add(1 << 16);
+      rb2.add(3 << 16);
+      rb2.add(4 << 16);
+
+      MutableRoaringBitmap answer = ImmutableRoaringBitmap.orNot(rb2, rb1, (5 << 16));
+
+      // {[0, 2^16]}
+      assertEquals((5 << 16) - 1, answer.getCardinality());
+
+      IntIterator iterator = answer.getIntIterator();
+      for (int i = 0; i < (5 << 16); ++i) {
+        if (i != (2 << 16)) {
+          assertTrue(iterator.hasNext(), "Error on iteration " + i);
+          assertEquals(i, iterator.next(), "Error on iteration " + i);
+        }
+      }
+      assertFalse(iterator.hasNext(), "Number of elements " + (2 << 16));
+    }
+  }
+
+  @Test
+  public void orNot10() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+
+    rb.add(5);
+    rb2.add(10);
+
+    rb.orNot(rb2, 6);
+
+    assertEquals(5, rb.last());
+  }
+
+  @Test
+  public void orNot11() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+
+    rb.add((int) (65535L * 65536L + 65523));
+    rb2.add((int) (65493L * 65536L + 65520));
+
+    MutableRoaringBitmap rb3 = ImmutableRoaringBitmap.orNot(rb, rb2, 65535L * 65536L + 65524);
+
+    assertEquals((int) (65535L * 65536L + 65523), rb3.last());
+  }
+
+  @Test
+  public void orNotAgainstFullBitmap() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    MutableRoaringBitmap full = new MutableRoaringBitmap();
+    full.add(0, 0x40000L);
+    rb.orNot(full, 0x30000L);
+    assertTrue(rb.isEmpty());
+  }
+
+  @Test
+  public void orNotNonEmptyAgainstFullBitmap() {
+    MutableRoaringBitmap rb = MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001);
+    MutableRoaringBitmap full = new MutableRoaringBitmap();
+    full.add((long) 0, (long) 0x40000);
+    rb.orNot(full, 0x30000);
+    assertEquals(MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001), rb);
+  }
+
+  @Test
+  public void orNotAgainstFullBitmapStatic() {
+    MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    MutableRoaringBitmap full = new MutableRoaringBitmap();
+    full.add(0, 0x40000L);
+    MutableRoaringBitmap result = ImmutableRoaringBitmap.orNot(rb, full, 0x30000L);
+    assertTrue(result.isEmpty());
+  }
+
+  @Test
+  public void orNotNonEmptyAgainstFullBitmapStatic() {
+    MutableRoaringBitmap rb = MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001);
+    MutableRoaringBitmap full = new MutableRoaringBitmap();
+    full.add(0, 0x40000L);
+    assertEquals(
+        MutableRoaringBitmap.bitmapOf(1, 0x10001, 0x20001),
+        ImmutableRoaringBitmap.orNot(rb, full, 0x30000L));
+  }
+
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testBigOrNot() throws IOException {
+    byte[] bytes =
+        Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json"));
+    Map info = new ObjectMapper().readerFor(Map.class).readValue(bytes);
+    List base64Bitmaps = (List) info.get("bitmaps");
+    ByteBuffer lBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(0)));
+    ByteBuffer rBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(1)));
+    MutableRoaringBitmap l = new MutableRoaringBitmap();
+    l.deserialize(lBuffer);
+    MutableRoaringBitmap r = new MutableRoaringBitmap();
+    r.deserialize(rBuffer);
+
+    MutableRoaringBitmap range = new MutableRoaringBitmap();
+    long limit = toUnsignedLong(l.last()) + 1;
+    range.add(0, limit);
+    range.andNot(r);
+    MutableRoaringBitmap expected = MutableRoaringBitmap.or(l, range);
+
+    MutableRoaringBitmap actual = l.clone();
+    actual.orNot(r, limit);
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testBigOrNotStatic() throws IOException {
+    byte[] bytes =
+        Files.readAllBytes(Paths.get("src/test/resources/testdata/ornot-fuzz-failure.json"));
+    Map info = new ObjectMapper().readerFor(Map.class).readValue(bytes);
+    List base64Bitmaps = (List) info.get("bitmaps");
+    ByteBuffer lBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(0)));
+    ByteBuffer rBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(base64Bitmaps.get(1)));
+    MutableRoaringBitmap l = new MutableRoaringBitmap();
+    l.deserialize(lBuffer);
+    MutableRoaringBitmap r = new MutableRoaringBitmap();
+    r.deserialize(rBuffer);
+
+    MutableRoaringBitmap range = new MutableRoaringBitmap();
+    long limit = toUnsignedLong(l.last()) + 1;
+    range.add(0, limit);
+    range.andNot(r);
+    MutableRoaringBitmap expected = MutableRoaringBitmap.or(l, range);
+
+    MutableRoaringBitmap actual = ImmutableRoaringBitmap.orNot(l, r, limit);
+    assertEquals(expected, actual);
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestIntIteratorFlyweight.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestIntIteratorFlyweight.java
similarity index 86%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestIntIteratorFlyweight.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestIntIteratorFlyweight.java
index f5e74d184..9f9fd1279 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestIntIteratorFlyweight.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestIntIteratorFlyweight.java
@@ -2,24 +2,24 @@
  * (c) the authors Licensed under the Apache License, Version 2.0.
  */
 
-
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import org.roaringbitmap.IntIterator;
+import org.roaringbitmap.PeekableIntIterator;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.primitives.Ints;
 import org.junit.jupiter.api.Test;
-import org.roaringbitmap.IntIterator;
-import org.roaringbitmap.PeekableIntIterator;
 
 import java.util.Arrays;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-
 public class TestIntIteratorFlyweight {
   private static List asList(IntIterator ints) {
     int[] values = new int[10];
@@ -34,7 +34,7 @@ private static List asList(IntIterator ints) {
   }
 
   private static int[] takeSortedAndDistinct(Random source, int count) {
-    LinkedHashSet ints = new LinkedHashSet(count);
+    LinkedHashSet ints = new LinkedHashSet<>(count);
     for (int size = 0; size < count; size++) {
       int next;
       do {
@@ -42,17 +42,14 @@ private static int[] takeSortedAndDistinct(Random source, int count) {
       } while (!ints.add(next));
     }
     // we add a range of continuous values
-    for(int k = 1000; k < 10000; ++k) {
-      if(!ints.contains(k))
-        ints.add(k);
+    for (int k = 1000; k < 10000; ++k) {
+      ints.add(k);
     }
     int[] unboxed = Ints.toArray(ints);
     Arrays.sort(unboxed);
     return unboxed;
   }
 
-
-
   @Test
   public void testEmptyIteration() {
     BufferIntIteratorFlyweight iter = new BufferIntIteratorFlyweight();
@@ -66,10 +63,9 @@ public void testEmptyIteration() {
     assertFalse(reverseIter.hasNext());
   }
 
-
   @Test
   public void testIteration() {
-    final Random source = new Random(0xcb000a2b9b5bdfb6l);
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
     final int[] data = takeSortedAndDistinct(source, 450000);
     MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(data);
 
@@ -78,17 +74,16 @@ public void testIteration() {
 
     BufferIntIteratorFlyweight iter2 = new BufferIntIteratorFlyweight(bitmap);
     PeekableIntIterator j = bitmap.getIntIterator();
-    for(int k = 0; k < data.length; k+=3) {
+    for (int k = 0; k < data.length; k += 3) {
       iter2.advanceIfNeeded(data[k]);
       iter2.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
-      assertEquals(j.peekNext(),data[k]);
-      assertEquals(iter2.peekNext(),data[k]);
+      assertEquals(j.peekNext(), data[k]);
+      assertEquals(iter2.peekNext(), data[k]);
     }
     new BufferIntIteratorFlyweight(bitmap).advanceIfNeeded(-1);
-    bitmap.getIntIterator().advanceIfNeeded(-1);// should not crash
-
+    bitmap.getIntIterator().advanceIfNeeded(-1); // should not crash
 
     BufferReverseIntIteratorFlyweight reverseIter = new BufferReverseIntIteratorFlyweight();
     reverseIter.wrap(bitmap);
@@ -103,30 +98,27 @@ public void testIteration() {
     assertEquals(Lists.reverse(Ints.asList(data)), reverseIntIteratorCopy);
   }
 
-
   @Test
   public void testIterationFromBitmap() {
-    final Random source = new Random(0xcb000a2b9b5bdfb6l);
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
     final int[] data = takeSortedAndDistinct(source, 450000);
     MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(data);
 
     BufferIntIteratorFlyweight iter = new BufferIntIteratorFlyweight(bitmap);
-    assertEquals(iter.peekNext(),data[0]);
-    assertEquals(iter.peekNext(),data[0]);
+    assertEquals(iter.peekNext(), data[0]);
+    assertEquals(iter.peekNext(), data[0]);
 
     BufferIntIteratorFlyweight iter2 = new BufferIntIteratorFlyweight(bitmap);
     PeekableIntIterator j = bitmap.getIntIterator();
-    for(int k = 0; k < data.length; k+=3) {
+    for (int k = 0; k < data.length; k += 3) {
       iter2.advanceIfNeeded(data[k]);
       iter2.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
       j.advanceIfNeeded(data[k]);
-      assertEquals(j.peekNext(),data[k]);
-      assertEquals(iter2.peekNext(),data[k]);
+      assertEquals(data[k], j.peekNext());
+      assertEquals(data[k], iter2.peekNext());
     }
 
-
-
     BufferReverseIntIteratorFlyweight reverseIter = new BufferReverseIntIteratorFlyweight(bitmap);
 
     final List intIteratorCopy = asList(iter);
@@ -139,16 +131,16 @@ public void testIterationFromBitmap() {
     assertEquals(Lists.reverse(Ints.asList(data)), reverseIntIteratorCopy);
   }
 
-
   @Test
   public void testIterationFromBitmapClone() {
-    final Random source = new Random(0xcb000a2b9b5bdfb6l);
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
     final int[] data = takeSortedAndDistinct(source, 450000);
     MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(data);
 
     BufferIntIteratorFlyweight iter = new BufferIntIteratorFlyweight(bitmap);
 
-    BufferReverseIntIteratorFlyweight reverseIter = (BufferReverseIntIteratorFlyweight) new BufferReverseIntIteratorFlyweight(bitmap).clone();
+    BufferReverseIntIteratorFlyweight reverseIter =
+        (BufferReverseIntIteratorFlyweight) new BufferReverseIntIteratorFlyweight(bitmap).clone();
 
     final List intIteratorCopy = asList(iter);
     final List reverseIntIteratorCopy = asList(reverseIter);
@@ -162,11 +154,11 @@ public void testIterationFromBitmapClone() {
 
   @Test
   public void testIteration1() {
-    final Random source = new Random(0xcb000a2b9b5bdfb6l);
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
     final int[] data1 = takeSortedAndDistinct(source, 450000);
     final int[] data = Arrays.copyOf(data1, data1.length + 50000);
 
-    LinkedHashSet data1Members = new LinkedHashSet();
+    LinkedHashSet data1Members = new LinkedHashSet<>();
     for (int i : data1) {
       data1Members.add(i);
     }
@@ -218,6 +210,4 @@ public void testSmallIteration() {
     assertEquals(ImmutableList.of(1, 2, 3), intIteratorCopy);
     assertEquals(ImmutableList.of(3, 2, 1), reverseIntIteratorCopy);
   }
-
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestIterators.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestIterators.java
similarity index 53%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestIterators.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestIterators.java
index 510e0d292..c0fad4c9f 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestIterators.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestIterators.java
@@ -4,6 +4,12 @@
 
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import org.roaringbitmap.CharIterator;
+import org.roaringbitmap.IntIterator;
+import org.roaringbitmap.PeekableIntIterator;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -11,19 +17,19 @@
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
-import org.roaringbitmap.CharIterator;
-import org.roaringbitmap.IntIterator;
-import org.roaringbitmap.PeekableIntIterator;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.LongBuffer;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
 
 @Execution(ExecutionMode.CONCURRENT)
 public class TestIterators {
@@ -41,36 +47,37 @@ private static List asList(IntIterator ints) {
   }
 
   private static List asList(final CharIterator shorts) {
-    return asList(new IntIterator() {
-      @Override
-      public IntIterator clone() {
-        throw new UnsupportedOperationException();
-      }
-
-      @Override
-      public boolean hasNext() {
-        return shorts.hasNext();
-      }
-
-      @Override
-      public int next() {
-        return shorts.next();
-      }
-    });
+    return asList(
+        new IntIterator() {
+          @Override
+          public IntIterator clone() {
+            throw new UnsupportedOperationException();
+          }
+
+          @Override
+          public boolean hasNext() {
+            return shorts.hasNext();
+          }
+
+          @Override
+          public int next() {
+            return shorts.next();
+          }
+        });
   }
 
-
-  private static int[] takeSortedAndDistinct(Random source, int count) {
-    LinkedHashSet ints = new LinkedHashSet(count);
+  private static int[] takeSortedAndDistinct(
+      Random source, int count, Comparator comparator) {
+    HashSet ints = new HashSet(count);
     for (int size = 0; size < count; size++) {
       int next;
       do {
-        next = Math.abs(source.nextInt());
+        next = source.nextInt();
       } while (!ints.add(next));
     }
-    int[] unboxed = Ints.toArray(ints);
-    Arrays.sort(unboxed);
-    return unboxed;
+    ArrayList list = new ArrayList(ints);
+    list.sort(comparator);
+    return Ints.toArray(list);
   }
 
   // https://github.com/RoaringBitmap/RoaringBitmap/issues/475
@@ -82,18 +89,22 @@ public void testCorruptionInfiniteLoop() {
     bitmap.add(Integer.MAX_VALUE - 2);
     // Adding this one leads to the issue
     bitmap.add(Integer.MAX_VALUE - 3);
-    bitmap.forEach((org.roaringbitmap.IntConsumer) e -> {
-      if (!bitmap.contains(e)) {
-        throw new IllegalStateException("Not expecting to find: " + e);
-      }
-    });
+    bitmap.forEach(
+        (org.roaringbitmap.IntConsumer)
+            e -> {
+              if (!bitmap.contains(e)) {
+                throw new IllegalStateException("Not expecting to find: " + e);
+              }
+            });
 
     bitmap.runOptimize(); // This is the line causing the issue
-    bitmap.forEach((org.roaringbitmap.IntConsumer) e -> {
-      if (!bitmap.contains(e)) {
-        throw new IllegalStateException("Not expecting to find: " + e);
-      }
-    });
+    bitmap.forEach(
+        (org.roaringbitmap.IntConsumer)
+            e -> {
+              if (!bitmap.contains(e)) {
+                throw new IllegalStateException("Not expecting to find: " + e);
+              }
+            });
   }
 
   @Test
@@ -101,7 +112,7 @@ public void testBitmapIteration() {
     final MappeableBitmapContainer bits =
         new MappeableBitmapContainer(2, LongBuffer.allocate(2).put(0x1l).put(1l << 63));
 
-      assertEquals(asList(bits.getCharIterator()), ImmutableList.of(0, 127));
+    assertEquals(asList(bits.getCharIterator()), ImmutableList.of(0, 127));
     assertEquals(asList(bits.getReverseCharIterator()), ImmutableList.of(127, 0));
   }
 
@@ -109,130 +120,168 @@ public void testBitmapIteration() {
   public void testEmptyIteration() {
     assertFalse(MutableRoaringBitmap.bitmapOf().iterator().hasNext());
     assertFalse(MutableRoaringBitmap.bitmapOf().getIntIterator().hasNext());
+    assertFalse(MutableRoaringBitmap.bitmapOf().getSignedIntIterator().hasNext());
     assertFalse(MutableRoaringBitmap.bitmapOf().getReverseIntIterator().hasNext());
   }
 
-
   @Test
   public void testIteration() {
     final Random source = new Random(0xcb000a2b9b5bdfb6l);
-    final int[] data = takeSortedAndDistinct(source, 450000);
+    final int[] data = takeSortedAndDistinct(source, 450000, Integer::compareUnsigned);
     MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(data);
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
     final List intIteratorCopy = asList(bitmap.getIntIterator());
+    final List signedIntIteratorCopy = asList(bitmap.getSignedIntIterator());
     final List reverseIntIteratorCopy = asList(bitmap.getReverseIntIterator());
 
     assertEquals(bitmap.getCardinality(), iteratorCopy.size());
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
+    assertEquals(bitmap.getCardinality(), signedIntIteratorCopy.size());
     assertEquals(bitmap.getCardinality(), reverseIntIteratorCopy.size());
     assertEquals(Ints.asList(data), iteratorCopy);
     assertEquals(Ints.asList(data), intIteratorCopy);
+    assertEquals(
+        Ints.asList(data).stream().sorted().collect(Collectors.toList()), signedIntIteratorCopy);
     assertEquals(Lists.reverse(Ints.asList(data)), reverseIntIteratorCopy);
   }
 
-
-
   @Test
   public void testIteration1() {
     final Random source = new Random(0xcb000a2b9b5bdfb6l);
-    final int[] data1 = takeSortedAndDistinct(source, 450000);
-    final int[] data = Arrays.copyOf(data1, data1.length + 50000);
+    final int[] data1 = takeSortedAndDistinct(source, 450000, Integer::compareUnsigned);
 
-    HashSet data1Members = new HashSet();
+    HashSet data1Members = new HashSet(data1.length);
     for (int i : data1) {
       data1Members.add(i);
     }
+    final List data = new ArrayList<>(data1.length + 50000);
+    data.addAll(data1Members);
 
     int counter = 77777;
-    for (int i = data1.length; i < data.length; ++i) {
+    for (int i = data1.length; i < data.size(); ++i) {
       // ensure uniqueness
       while (data1Members.contains(counter)) {
         ++counter;
       }
-      data[i] = counter; // must be unique
+      data.set(i, counter); // must be unique
       counter++;
       if (i % 15 == 0) {
         counter += 10; // runs of length 15 or so, with gaps of 10
       }
     }
-    Arrays.sort(data);
+    data.sort(Integer::compareUnsigned);
 
-    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(data);
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(Ints.toArray(data));
     bitmap.runOptimize(); // result should have some runcontainers and some non.
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
     final List intIteratorCopy = asList(bitmap.getIntIterator());
+    final List signedIntIteratorCopy = asList(bitmap.getSignedIntIterator());
     final List reverseIntIteratorCopy = asList(bitmap.getReverseIntIterator());
 
     assertEquals(bitmap.getCardinality(), iteratorCopy.size());
     assertEquals(bitmap.getCardinality(), intIteratorCopy.size());
+    assertEquals(bitmap.getCardinality(), signedIntIteratorCopy.size());
     assertEquals(bitmap.getCardinality(), reverseIntIteratorCopy.size());
-    assertEquals(Ints.asList(data), iteratorCopy);
-    assertEquals(Ints.asList(data), intIteratorCopy);
-    assertEquals(Lists.reverse(Ints.asList(data)), reverseIntIteratorCopy);
+    assertEquals(data, iteratorCopy);
+    assertEquals(data, intIteratorCopy);
+    assertEquals(data.stream().sorted().collect(Collectors.toList()), signedIntIteratorCopy);
+    assertEquals(Lists.reverse(data), reverseIntIteratorCopy);
   }
 
   @Test
   public void testSmallIteration() {
-    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(1, 2, 3);
+    MutableRoaringBitmap bitmap =
+        MutableRoaringBitmap.bitmapOf(1, 2, 3, -1, -2147483648, 2147483647, 0);
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
     final List intIteratorCopy = asList(bitmap.getIntIterator());
+    final List signedIntIteratorCopy = asList(bitmap.getSignedIntIterator());
     final List reverseIntIteratorCopy = asList(bitmap.getReverseIntIterator());
 
-    assertEquals(ImmutableList.of(1, 2, 3), iteratorCopy);
-    assertEquals(ImmutableList.of(1, 2, 3), intIteratorCopy);
-    assertEquals(ImmutableList.of(3, 2, 1), reverseIntIteratorCopy);
+    assertEquals(ImmutableList.of(0, 1, 2, 3, 2147483647, -2147483648, -1), iteratorCopy);
+    assertEquals(ImmutableList.of(0, 1, 2, 3, 2147483647, -2147483648, -1), intIteratorCopy);
+    assertEquals(ImmutableList.of(-2147483648, -1, 0, 1, 2, 3, 2147483647), signedIntIteratorCopy);
+    assertEquals(ImmutableList.of(-1, -2147483648, 2147483647, 3, 2, 1, 0), reverseIntIteratorCopy);
   }
 
   @Test
   public void testSmallIteration1() {
-    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(1, 2, 3);
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(1, 2, 3, -1);
     bitmap.runOptimize();
 
     final List iteratorCopy = ImmutableList.copyOf(bitmap.iterator());
     final List intIteratorCopy = asList(bitmap.getIntIterator());
+    final List signedIntIteratorCopy = asList(bitmap.getSignedIntIterator());
     final List reverseIntIteratorCopy = asList(bitmap.getReverseIntIterator());
 
-    assertEquals(ImmutableList.of(1, 2, 3), iteratorCopy);
-    assertEquals(ImmutableList.of(1, 2, 3), intIteratorCopy);
-    assertEquals(ImmutableList.of(3, 2, 1), reverseIntIteratorCopy);
+    assertEquals(ImmutableList.of(1, 2, 3, -1), iteratorCopy);
+    assertEquals(ImmutableList.of(1, 2, 3, -1), intIteratorCopy);
+    assertEquals(ImmutableList.of(-1, 1, 2, 3), signedIntIteratorCopy);
+    assertEquals(ImmutableList.of(-1, 3, 2, 1), reverseIntIteratorCopy);
   }
-  
-  
+
   @Test
   public void testSkips() {
-    final Random source = new Random(0xcb000a2b9b5bdfb6l);
-    final int[] data = takeSortedAndDistinct(source, 45000);
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
+    final int[] data = takeSortedAndDistinct(source, 45000, Integer::compareUnsigned);
     MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(data);
     PeekableIntIterator pii = bitmap.getIntIterator();
-    for(int i = 0; i < data.length; ++i) {
+    for (int i = 0; i < data.length; ++i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.peekNext());
     }
     pii = bitmap.getIntIterator();
-    for(int i = 0; i < data.length; ++i) {
+    for (int i = 0; i < data.length; ++i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.next());
     }
     pii = bitmap.getIntIterator();
-    for(int i = 1; i < data.length; ++i) {
-      pii.advanceIfNeeded(data[i-1]);
+    for (int i = 1; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i - 1]);
       pii.next();
-      assertEquals(data[i],pii.peekNext() );
+      assertEquals(data[i], pii.peekNext());
     }
     bitmap.getIntIterator().advanceIfNeeded(-1);
   }
-  
+
+  @Test
+  public void testSkipsSignedIterator() {
+    final Random source = new Random(0xcb000a2b9b5bdfb6L);
+    final int[] data = takeSortedAndDistinct(source, 45000, Integer::compare);
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(data);
+    PeekableIntIterator pii = bitmap.getSignedIntIterator();
+    for (int i = 0; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i]);
+      assertEquals(data[i], pii.peekNext());
+    }
+    pii = bitmap.getSignedIntIterator();
+    for (int i = data.length - 1; i >= 0; --i) { // no backward advancing
+      pii.advanceIfNeeded(data[i]);
+      assertEquals(data[data.length - 1], pii.peekNext());
+    }
+    pii = bitmap.getSignedIntIterator();
+    for (int i = 0; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i]);
+      assertEquals(data[i], pii.next());
+    }
+    pii = bitmap.getSignedIntIterator();
+    for (int i = 1; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i - 1]);
+      pii.next();
+      assertEquals(data[i], pii.peekNext());
+    }
+  }
+
   @Test
   public void testSkipsDense() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     int N = 100000;
-    for(int i = 0; i < N; ++i) {
+    for (int i = 0; i < N; ++i) {
       bitmap.add(2 * i);
     }
-    for(int i = 0; i < N; ++i) {
+    for (int i = 0; i < N; ++i) {
       PeekableIntIterator pii = bitmap.getIntIterator();
       pii.advanceIfNeeded(2 * i);
       assertEquals(pii.peekNext(), 2 * i);
@@ -253,58 +302,55 @@ public void testIndexIterator4() throws Exception {
     }
   }
 
-
   @Test
   public void testSkipsRun() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     bitmap.add(4L, 100000L);
     bitmap.runOptimize();
-    for(int i = 4; i < 100000; ++i) {
+    for (int i = 4; i < 100000; ++i) {
       PeekableIntIterator pii = bitmap.getIntIterator();
       pii.advanceIfNeeded(i);
       assertEquals(pii.peekNext(), i);
       assertEquals(pii.next(), i);
     }
   }
-  
+
   @Test
   public void testEmptySkips() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     PeekableIntIterator it = bitmap.getIntIterator();
     it.advanceIfNeeded(0);
   }
-  
+
   @Test
   public void testIteratorsOnLargeBitmap() throws IOException {
-      MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
 
-      int inc = Short.MAX_VALUE;
+    int inc = Short.MAX_VALUE;
 
-      for (long i = -Integer.MIN_VALUE; i < Integer.MAX_VALUE; i += inc) {
-          bitmap.add((int) i);
-      }
+    for (long i = -Integer.MIN_VALUE; i < Integer.MAX_VALUE; i += inc) {
+      bitmap.add((int) i);
+    }
 
-      ByteArrayOutputStream bos = new ByteArrayOutputStream();
-      DataOutputStream dos = new DataOutputStream(bos);
-      bitmap.serialize(dos);
-      dos.close();
-      ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
-      ImmutableRoaringBitmap rrback1 = new ImmutableRoaringBitmap(bb);
-      int j = 0;
-
-      // we can iterate over the mutable bitmap
-      for (int i : bitmap) {
-          j += i;
-      }
-      
-      int jj = 0;
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    DataOutputStream dos = new DataOutputStream(bos);
+    bitmap.serialize(dos);
+    dos.close();
+    ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
+    ImmutableRoaringBitmap rrback1 = new ImmutableRoaringBitmap(bb);
+    int j = 0;
+
+    // we can iterate over the mutable bitmap
+    for (int i : bitmap) {
+      j += i;
+    }
 
-      // we can iterate over the immutable bitmap
-      for (int i : rrback1) {
-          jj+= i;
-      }
-      assertEquals(j, jj);
+    int jj = 0;
 
+    // we can iterate over the immutable bitmap
+    for (int i : rrback1) {
+      jj += i;
+    }
+    assertEquals(j, jj);
   }
 }
-
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java
similarity index 57%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java
index 8019f7bf2..0a72a2aed 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableArrayContainer.java
@@ -1,9 +1,15 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.roaringbitmap.IntConsumer;
+
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
-import org.roaringbitmap.IntConsumer;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -12,32 +18,34 @@
 import java.nio.CharBuffer;
 import java.util.Arrays;
 
-import static org.junit.jupiter.api.Assertions.*;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestMappeableArrayContainer {
 
   @Test
   public void addEmptyRange() {
     MappeableContainer ac = new MappeableArrayContainer();
-    ac = ac.iadd(1,1);
+    ac = ac.iadd(1, 1);
     assertEquals(0, ac.getCardinality());
   }
 
   @Test
   public void addInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer ac = new MappeableArrayContainer();
-      ac.add(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer ac = new MappeableArrayContainer();
+          ac.add(13, 1);
+        });
   }
 
   @Test
   public void iaddInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer ac = new MappeableArrayContainer();
-      ac.iadd(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer ac = new MappeableArrayContainer();
+          ac.iadd(13, 1);
+        });
   }
 
   @Test
@@ -58,11 +66,11 @@ public void iaddSanityTest() {
     ac = ac.iadd(1, 20);
     assertEquals(79, ac.getCardinality());
   }
-  
+
   @Test
   public void remove() {
     MappeableContainer ac = new MappeableArrayContainer();
-    ac = ac.iadd(1,3);
+    ac = ac.iadd(1, 3);
     ac = ac.remove((char) 2);
     assertEquals(1, ac.getCardinality());
     assertTrue(ac.contains((char) 1));
@@ -70,25 +78,29 @@ public void remove() {
 
   @Test
   public void removeInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer ac = new MappeableArrayContainer();
-      ac.remove(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer ac = new MappeableArrayContainer();
+          ac.remove(13, 1);
+        });
   }
 
   @Test
   public void iremoveEmptyRange() {
     MappeableContainer ac = new MappeableArrayContainer();
-    ac.remove(1,1);
+    ac.remove(1, 1);
     assertEquals(0, ac.getCardinality());
   }
 
   @Test
   public void iremoveInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer ac = new MappeableArrayContainer();
-      ac.iremove(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer ac = new MappeableArrayContainer();
+          ac.iremove(13, 1);
+        });
   }
 
   @Test
@@ -171,9 +183,9 @@ static MappeableArrayContainer newArrayContainer(int firstOfRun, final int lastO
   @Test
   public void iand() {
     MappeableContainer ac = new MappeableArrayContainer();
-    ac = ac.add(10,20);
+    ac = ac.add(10, 20);
     MappeableContainer bc = new MappeableBitmapContainer();
-    bc = bc.add(15,25);
+    bc = bc.add(15, 25);
     ac.iand(bc);
     assertEquals(5, ac.getCardinality());
     for (int i = 15; i < 20; i++) {
@@ -184,8 +196,8 @@ public void iand() {
   @Test
   public void iandNotArray() {
     MappeableContainer ac = new MappeableArrayContainer();
-    ac = ac.add(10,20);
-    MappeableContainer ac2 = newArrayContainer(15,25);
+    ac = ac.add(10, 20);
+    MappeableContainer ac2 = newArrayContainer(15, 25);
     ac.iandNot(ac2);
     assertEquals(5, ac.getCardinality());
     for (int i = 10; i < 15; i++) {
@@ -196,9 +208,9 @@ public void iandNotArray() {
   @Test
   public void iandNotBitmap() {
     MappeableContainer ac = new MappeableArrayContainer();
-    ac = ac.add(10,20);
+    ac = ac.add(10, 20);
     MappeableContainer bc = new MappeableBitmapContainer();
-    bc = bc.add(15,25);
+    bc = bc.add(15, 25);
     ac.iandNot(bc);
     assertEquals(5, ac.getCardinality());
     for (int i = 10; i < 15; i++) {
@@ -209,9 +221,9 @@ public void iandNotBitmap() {
   @Test
   public void intersects() {
     MappeableContainer ac1 = new MappeableArrayContainer();
-    ac1 = ac1.add(10,20);
+    ac1 = ac1.add(10, 20);
     MappeableContainer ac2 = new MappeableArrayContainer();
-    ac2 = ac2.add(15,25);
+    ac2 = ac2.add(15, 25);
     assertTrue(ac1.intersects(ac2));
   }
 
@@ -241,8 +253,8 @@ public void roundtrip() throws Exception {
 
   @Test
   public void orArray() {
-    MappeableContainer ac = newArrayContainer(0,8192);
-    MappeableContainer ac2 = newArrayContainer(15,25);
+    MappeableContainer ac = newArrayContainer(0, 8192);
+    MappeableContainer ac2 = newArrayContainer(15, 25);
     ac = ac.or(ac2);
     assertEquals(8192, ac.getCardinality());
     for (int i = 0; i < 8192; i++) {
@@ -252,8 +264,8 @@ public void orArray() {
 
   @Test
   public void xorArray() {
-    MappeableContainer ac = newArrayContainer(0,8192);
-    MappeableContainer ac2 = newArrayContainer(15,25);
+    MappeableContainer ac = newArrayContainer(0, 8192);
+    MappeableContainer ac2 = newArrayContainer(15, 25);
     ac = ac.xor(ac2);
     assertEquals(8182, ac.getCardinality());
     for (int i = 0; i < 15; i++) {
@@ -267,14 +279,16 @@ public void xorArray() {
   @Test
   public void foreach() {
     MappeableContainer ac = newArrayContainer(0, 64);
-    ac.forEach((char) 0, new IntConsumer() {
-      int expected = 0;
+    ac.forEach(
+        (char) 0,
+        new IntConsumer() {
+          int expected = 0;
 
-      @Override
-      public void accept(int value) {
-        assertEquals(value, expected++);
-      }
-    });
+          @Override
+          public void accept(int value) {
+            assertEquals(value, expected++);
+          }
+        });
   }
 
   @Test
@@ -318,7 +332,21 @@ public void testToString() {
     ac1.add((char) -17);
     assertEquals("{5,6,7,8,9,10,11,12,13,14,65519,65533}", ac1.toString());
   }
-  
+
+  @Test
+  public void testContainsRunContainer_Issue723Case1() {
+    MappeableContainer ac = new MappeableArrayContainer().add(0, 10);
+    MappeableContainer subset = new MappeableRunContainer().add(5, 6);
+    assertTrue(ac.contains(subset));
+  }
+
+  @Test
+  public void testContainsRunContainer_Issue723Case2() {
+    MappeableContainer ac = new MappeableArrayContainer().add(0, 10);
+    MappeableContainer rc = new MappeableRunContainer().add(5, 11);
+    assertFalse(ac.contains(rc));
+  }
+
   @Test
   public void iorNotIncreaseCapacity() {
     MappeableArrayContainer ac1 = new MappeableArrayContainer();
@@ -326,13 +354,13 @@ public void iorNotIncreaseCapacity() {
     ac1.add((char) 128);
     ac1.add((char) 256);
     ac2.add((char) 1024);
-    
+
     ac1.ior(ac2);
     assertTrue(ac1.contains((char) 128));
     assertTrue(ac1.contains((char) 256));
     assertTrue(ac1.contains((char) 1024));
   }
-  
+
   @Test
   public void iorIncreaseCapacity() {
     MappeableArrayContainer ac1 = new MappeableArrayContainer();
@@ -342,7 +370,7 @@ public void iorIncreaseCapacity() {
     ac1.add((char) 512);
     ac1.add((char) 513);
     ac2.add((char) 1024);
-    
+
     ac1.ior(ac2);
     assertTrue(ac1.contains((char) 128));
     assertTrue(ac1.contains((char) 256));
@@ -350,7 +378,7 @@ public void iorIncreaseCapacity() {
     assertTrue(ac1.contains((char) 513));
     assertTrue(ac1.contains((char) 1024));
   }
-  
+
   @Test
   public void iorSanityCheck() {
     MappeableContainer ac = new MappeableArrayContainer().add(0, 10);
@@ -368,10 +396,10 @@ public void testIntersectsWithRange() {
     assertFalse(container.intersects(11, lower16Bits(-1)));
   }
 
-
   @Test
   public void testIntersectsWithRange2() {
-    MappeableContainer container = new MappeableArrayContainer().add(lower16Bits(-50), lower16Bits(-10));
+    MappeableContainer container =
+        new MappeableArrayContainer().add(lower16Bits(-50), lower16Bits(-10));
     assertFalse(container.intersects(0, 1));
     assertTrue(container.intersects(0, lower16Bits(-40)));
     assertFalse(container.intersects(lower16Bits(-100), lower16Bits(-55)));
@@ -379,13 +407,10 @@ public void testIntersectsWithRange2() {
     assertTrue(container.intersects(11, 1 << 16));
   }
 
-
   @Test
   public void testIntersectsWithRange3() {
-    MappeableContainer container = new MappeableArrayContainer()
-            .add((char) 1)
-            .add((char) 300)
-            .add((char) 1024);
+    MappeableContainer container =
+        new MappeableArrayContainer().add((char) 1).add((char) 300).add((char) 1024);
     assertTrue(container.intersects(0, 300));
     assertTrue(container.intersects(1, 300));
     assertFalse(container.intersects(2, 300));
@@ -409,9 +434,7 @@ public void testContainsRange() {
 
   @Test
   public void testContainsRange2() {
-    MappeableContainer ac = new MappeableArrayContainer()
-            .add((char)1).add((char)10)
-            .add(20, 100);
+    MappeableContainer ac = new MappeableArrayContainer().add((char) 1).add((char) 10).add(20, 100);
     assertFalse(ac.contains(1, 21));
     assertFalse(ac.contains(1, 20));
     assertTrue(ac.contains(1, 2));
@@ -430,251 +453,268 @@ public void testContainsRangeUnsigned() {
 
   @Test
   public void testNextValueBeforeStart() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(10, container.nextValue((char)5));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(10, container.nextValue((char) 5));
   }
 
   @Test
   public void testNextValue() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(10, container.nextValue((char)10));
-    assertEquals(20, container.nextValue((char)11));
-    assertEquals(30, container.nextValue((char)30));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(10, container.nextValue((char) 10));
+    assertEquals(20, container.nextValue((char) 11));
+    assertEquals(30, container.nextValue((char) 30));
   }
 
   @Test
   public void testNextValueAfterEnd() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(-1, container.nextValue((char)31));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(-1, container.nextValue((char) 31));
   }
 
   @Test
   public void testNextValue2() {
     MappeableContainer container = new MappeableArrayContainer().iadd(64, 129);
     assertTrue(container instanceof MappeableArrayContainer);
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(-1, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)5000));
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(-1, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 5000));
   }
 
   @Test
   public void testNextValueBetweenRuns() {
     MappeableContainer container = new MappeableArrayContainer().iadd(64, 129).iadd(256, 321);
     assertTrue(container instanceof MappeableArrayContainer);
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(256, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)512));
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(256, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 512));
   }
 
   @Test
   public void testNextValue3() {
-    MappeableContainer container = new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    MappeableContainer container =
+        new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
     assertTrue(container instanceof MappeableArrayContainer);
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)63));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(200, container.nextValue((char)129));
-    assertEquals(200, container.nextValue((char)199));
-    assertEquals(200, container.nextValue((char)200));
-    assertEquals(250, container.nextValue((char)250));
-    assertEquals(5000, container.nextValue((char)2500));
-    assertEquals(5000, container.nextValue((char)5000));
-    assertEquals(5200, container.nextValue((char)5200));
-    assertEquals(-1, container.nextValue((char)5201));
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 63));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(200, container.nextValue((char) 129));
+    assertEquals(200, container.nextValue((char) 199));
+    assertEquals(200, container.nextValue((char) 200));
+    assertEquals(250, container.nextValue((char) 250));
+    assertEquals(5000, container.nextValue((char) 2500));
+    assertEquals(5000, container.nextValue((char) 5000));
+    assertEquals(5200, container.nextValue((char) 5200));
+    assertEquals(-1, container.nextValue((char) 5201));
   }
 
   @Test
   public void testPreviousValue1() {
     MappeableContainer container = new MappeableArrayContainer().iadd(64, 129);
     assertTrue(container instanceof MappeableArrayContainer);
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
   }
 
   @Test
   public void testPreviousValue2() {
-    MappeableContainer container = new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    MappeableContainer container =
+        new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
     assertTrue(container instanceof MappeableArrayContainer);
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
-    assertEquals(128, container.previousValue((char)199));
-    assertEquals(200, container.previousValue((char)200));
-    assertEquals(250, container.previousValue((char)250));
-    assertEquals(500, container.previousValue((char)2500));
-    assertEquals(5000, container.previousValue((char)5000));
-    assertEquals(5200, container.previousValue((char)5200));
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
+    assertEquals(128, container.previousValue((char) 199));
+    assertEquals(200, container.previousValue((char) 200));
+    assertEquals(250, container.previousValue((char) 250));
+    assertEquals(500, container.previousValue((char) 2500));
+    assertEquals(5000, container.previousValue((char) 5000));
+    assertEquals(5200, container.previousValue((char) 5200));
   }
 
   @Test
   public void testPreviousValueBeforeStart() {
-    MappeableContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(-1, container.previousValue((char)5));
+    MappeableContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(-1, container.previousValue((char) 5));
   }
 
   @Test
   public void testPreviousValueSparse() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(-1, container.previousValue((char)9));
-    assertEquals(10, container.previousValue((char)10));
-    assertEquals(10, container.previousValue((char)11));
-    assertEquals(20, container.previousValue((char)21));
-    assertEquals(30, container.previousValue((char)30));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(-1, container.previousValue((char) 9));
+    assertEquals(10, container.previousValue((char) 10));
+    assertEquals(10, container.previousValue((char) 11));
+    assertEquals(20, container.previousValue((char) 21));
+    assertEquals(30, container.previousValue((char) 30));
   }
 
   @Test
   public void testPreviousValueUnsigned() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}), 2);
-    assertEquals(-1, container.previousValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 8)));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(
+            CharBuffer.wrap(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)}), 2);
+    assertEquals(-1, container.previousValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testNextValueUnsigned() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}), 2);
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 7)));
-    assertEquals(-1, container.nextValue((char)((1 << 15) | 8)));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(
+            CharBuffer.wrap(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)}), 2);
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 7)));
+    assertEquals(-1, container.nextValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testPreviousValueAfterEnd() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(30, container.previousValue((char)31));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(30, container.previousValue((char) 31));
   }
 
   @Test
   public void testPreviousAbsentValue1() {
     MappeableContainer container = new MappeableArrayContainer().iadd(64, 129);
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
   }
 
   @Test
   public void testPreviousAbsentValue2() {
-    MappeableContainer container = new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
-    assertEquals(199, container.previousAbsentValue((char)199));
-    assertEquals(199, container.previousAbsentValue((char)200));
-    assertEquals(199, container.previousAbsentValue((char)250));
-    assertEquals(2500, container.previousAbsentValue((char)2500));
-    assertEquals(4999, container.previousAbsentValue((char)5000));
-    assertEquals(4999, container.previousAbsentValue((char)5200));
+    MappeableContainer container =
+        new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
+    assertEquals(199, container.previousAbsentValue((char) 199));
+    assertEquals(199, container.previousAbsentValue((char) 200));
+    assertEquals(199, container.previousAbsentValue((char) 250));
+    assertEquals(2500, container.previousAbsentValue((char) 2500));
+    assertEquals(4999, container.previousAbsentValue((char) 5000));
+    assertEquals(4999, container.previousAbsentValue((char) 5200));
   }
 
   @Test
   public void testPreviousAbsentValueEmpty() {
     MappeableArrayContainer container = new MappeableArrayContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.previousAbsentValue((char)i));
+      assertEquals(i, container.previousAbsentValue((char) i));
     }
   }
 
   @Test
   public void testPreviousAbsentValueSparse() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(9, container.previousAbsentValue((char)9));
-    assertEquals(9, container.previousAbsentValue((char)10));
-    assertEquals(11, container.previousAbsentValue((char)11));
-    assertEquals(21, container.previousAbsentValue((char)21));
-    assertEquals(29, container.previousAbsentValue((char)30));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(9, container.previousAbsentValue((char) 9));
+    assertEquals(9, container.previousAbsentValue((char) 10));
+    assertEquals(11, container.previousAbsentValue((char) 11));
+    assertEquals(21, container.previousAbsentValue((char) 21));
+    assertEquals(29, container.previousAbsentValue((char) 30));
   }
 
   @Test
   public void testPreviousAbsentValueUnsigned() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}), 2);
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char)((1 << 15) | 8)));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(
+            CharBuffer.wrap(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)}), 2);
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testNextAbsentValue1() {
     MappeableContainer container = new MappeableArrayContainer().iadd(64, 129);
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
   }
 
   @Test
   public void testNextAbsentValue2() {
-    MappeableContainer container = new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
-    assertEquals(199, container.nextAbsentValue((char)199));
-    assertEquals(501, container.nextAbsentValue((char)200));
-    assertEquals(501, container.nextAbsentValue((char)250));
-    assertEquals(2500, container.nextAbsentValue((char)2500));
-    assertEquals(5201, container.nextAbsentValue((char)5000));
-    assertEquals(5201, container.nextAbsentValue((char)5200));
+    MappeableContainer container =
+        new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
+    assertEquals(199, container.nextAbsentValue((char) 199));
+    assertEquals(501, container.nextAbsentValue((char) 200));
+    assertEquals(501, container.nextAbsentValue((char) 250));
+    assertEquals(2500, container.nextAbsentValue((char) 2500));
+    assertEquals(5201, container.nextAbsentValue((char) 5000));
+    assertEquals(5201, container.nextAbsentValue((char) 5200));
   }
 
   @Test
   public void testNextAbsentValueEmpty() {
     MappeableArrayContainer container = new MappeableArrayContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.nextAbsentValue((char)i));
+      assertEquals(i, container.nextAbsentValue((char) i));
     }
   }
 
   @Test
   public void testNextAbsentValueSparse() {
-    MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3);
-    assertEquals(9, container.nextAbsentValue((char)9));
-    assertEquals(11, container.nextAbsentValue((char)10));
-    assertEquals(11, container.nextAbsentValue((char)11));
-    assertEquals(21, container.nextAbsentValue((char)21));
-    assertEquals(31, container.nextAbsentValue((char)30));
+    MappeableArrayContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3);
+    assertEquals(9, container.nextAbsentValue((char) 9));
+    assertEquals(11, container.nextAbsentValue((char) 10));
+    assertEquals(11, container.nextAbsentValue((char) 11));
+    assertEquals(21, container.nextAbsentValue((char) 21));
+    assertEquals(31, container.nextAbsentValue((char) 30));
   }
 
   @Test
   public void testNextAbsentValueUnsigned() {
     char[] array = {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)};
     MappeableArrayContainer container = new MappeableArrayContainer(CharBuffer.wrap(array), 2);
-    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 8)));
+    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 8)));
   }
 
   @Test
@@ -714,6 +754,6 @@ public void testOrInto() {
   }
 
   private static int lower16Bits(int x) {
-    return ((char)x);
+    return ((char) x);
   }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainer.java
similarity index 59%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainer.java
index 414c67560..8b9ec4a4d 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainer.java
@@ -4,6 +4,16 @@
 
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY;
+import static org.roaringbitmap.buffer.TestMappeableArrayContainer.newArrayContainer;
+
+import org.roaringbitmap.BitmapContainer;
+import org.roaringbitmap.CharIterator;
+import org.roaringbitmap.IntConsumer;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
@@ -11,9 +21,6 @@
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.roaringbitmap.BitmapContainer;
-import org.roaringbitmap.CharIterator;
-import org.roaringbitmap.IntConsumer;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -25,18 +32,16 @@
 import java.util.Arrays;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.*;
-import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY;
-import static org.roaringbitmap.buffer.TestMappeableArrayContainer.newArrayContainer;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestMappeableBitmapContainer {
 
   private static MappeableBitmapContainer emptyContainer() {
     return new MappeableBitmapContainer(0, LongBuffer.allocate(1));
   }
+
   static MappeableBitmapContainer generateContainer(char min, char max, int sample) {
-    LongBuffer array = ByteBuffer.allocateDirect(MappeableBitmapContainer.MAX_CAPACITY / 8).asLongBuffer();
+    LongBuffer array =
+        ByteBuffer.allocateDirect(MappeableBitmapContainer.MAX_CAPACITY / 8).asLongBuffer();
     MappeableBitmapContainer bc = new MappeableBitmapContainer(array, 0);
     for (int i = min; i < max; i++) {
       if (i % sample != 0) bc.add((char) i);
@@ -52,15 +57,15 @@ public void testToString() {
     String s = bc2.toString();
     assertEquals("{5,6,7,8,9,10,11,12,13,14,65517,65533}", s);
   }
-  
-  @Test  
+
+  @Test
   public void testXOR() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -69,15 +74,15 @@ public void testXOR() {
     bc = (MappeableBitmapContainer) bc.ixor(bc2);
     assertEquals(0, bc.ixor(bc3).getCardinality());
   }
-  
-  @Test  
+
+  @Test
   public void testANDNOT() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -90,40 +95,36 @@ public void testANDNOT() {
     bc3.clear();
     assertEquals(0, bc3.getCardinality());
   }
-  
 
-  @Test  
+  @Test
   public void testAND() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
-    
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
       }
     }
     MappeableRunContainer rc = new MappeableRunContainer();
-    rc.iadd(0, 1<<16);
+    rc.iadd(0, 1 << 16);
     bc = (MappeableBitmapContainer) bc.iand(rc);
     bc = (MappeableBitmapContainer) bc.iand(bc2);
     assertEquals(bc, bc2);
     assertEquals(0, bc.iand(bc3).getCardinality());
   }
 
-  
-
-  @Test  
+  @Test
   public void testOR() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -134,25 +135,24 @@ public void testOR() {
     bc2 = (MappeableBitmapContainer) bc2.ior(bc);
     assertEquals(bc, bc2);
     MappeableRunContainer rc = new MappeableRunContainer();
-    rc.iadd(0, 1<<16);
+    rc.iadd(0, 1 << 16);
     assertEquals(0, bc.iandNot(rc).getCardinality());
   }
 
   private static void removeArray(MappeableBitmapContainer bc) {
-    LongBuffer array = ByteBuffer.allocateDirect((1<<16)/8).asLongBuffer();
-    for(int k = 0; k < bc.bitmap.limit(); ++k)
-      array.put(k, bc.bitmap.get(k));
+    LongBuffer array = ByteBuffer.allocateDirect((1 << 16) / 8).asLongBuffer();
+    for (int k = 0; k < bc.bitmap.limit(); ++k) array.put(k, bc.bitmap.get(k));
     bc.bitmap = array;
   }
 
-  @Test  
+  @Test
   public void testXORNoArray() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -163,15 +163,15 @@ public void testXORNoArray() {
     bc = (MappeableBitmapContainer) bc.ixor(bc2);
     assertEquals(0, bc.ixor(bc3).getCardinality());
   }
-  
-  @Test  
+
+  @Test
   public void testANDNOTNoArray() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -182,16 +182,15 @@ public void testANDNOTNoArray() {
     bc = (MappeableBitmapContainer) bc.iandNot(bc2);
     assertEquals(bc, bc3);
   }
-  
 
-  @Test  
+  @Test
   public void testANDNoArray() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -206,16 +205,14 @@ public void testANDNoArray() {
     assertEquals(0, bc.iand(bc3).getCardinality());
   }
 
-  
-
-  @Test  
+  @Test
   public void testORNoArray() {
-    MappeableBitmapContainer bc = new MappeableBitmapContainer(100,10000);
+    MappeableBitmapContainer bc = new MappeableBitmapContainer(100, 10000);
     MappeableBitmapContainer bc2 = new MappeableBitmapContainer();
     MappeableBitmapContainer bc3 = new MappeableBitmapContainer();
 
-    for(int i = 100; i < 10000; ++i) {
-      if((i%2 ) == 0) {
+    for (int i = 100; i < 10000; ++i) {
+      if ((i % 2) == 0) {
         bc2.add((char) i);
       } else {
         bc3.add((char) i);
@@ -228,153 +225,158 @@ public void testORNoArray() {
     bc2 = (MappeableBitmapContainer) bc2.ior(bc);
     assertEquals(bc, bc2);
   }
-  
+
   @Test
   public void runConstructorForBitmap() {
     System.out.println("runConstructorForBitmap");
-    for(int start = 0; start <= (1<<16); start += 4096 ) {
-      for(int end = start; end <= (1<<16); end += 4096 ) {
-        LongBuffer array = ByteBuffer.allocateDirect((1<<16)/8).asLongBuffer();
-        MappeableBitmapContainer bc = new MappeableBitmapContainer(start,end);
-        MappeableBitmapContainer bc2 = new MappeableBitmapContainer(array,0);
+    for (int start = 0; start <= (1 << 16); start += 4096) {
+      for (int end = start; end <= (1 << 16); end += 4096) {
+        LongBuffer array = ByteBuffer.allocateDirect((1 << 16) / 8).asLongBuffer();
+        MappeableBitmapContainer bc = new MappeableBitmapContainer(start, end);
+        MappeableBitmapContainer bc2 = new MappeableBitmapContainer(array, 0);
         assertFalse(bc2.isArrayBacked());
-        MappeableBitmapContainer bc3 = (MappeableBitmapContainer) bc2.add(start,end);
-        bc2.iadd(start,end);
-        assertEquals(bc.getCardinality(), end-start);
-        assertEquals(bc2.getCardinality(), end-start);
+        MappeableBitmapContainer bc3 = (MappeableBitmapContainer) bc2.add(start, end);
+        bc2.iadd(start, end);
+        assertEquals(bc.getCardinality(), end - start);
+        assertEquals(bc2.getCardinality(), end - start);
         assertEquals(bc, bc2);
         assertEquals(bc, bc3);
-        assertEquals(0,bc2.remove(start, end).getCardinality());
-        assertEquals(bc2.getCardinality(), end-start);
-        assertEquals(0,bc2.not(start, end).getCardinality());
-
-      }  
+        assertEquals(0, bc2.remove(start, end).getCardinality());
+        assertEquals(bc2.getCardinality(), end - start);
+        assertEquals(0, bc2.not(start, end).getCardinality());
+      }
     }
   }
-  
+
   @Test
   public void runConstructorForBitmap2() {
     System.out.println("runConstructorForBitmap2");
-    for(int start = 0; start <= (1<<16); start += 63 ) {
-      for(int end = start; end <= (1<<16); end += 63 ) {
-        LongBuffer array = ByteBuffer.allocateDirect((1<<16)/8).asLongBuffer();
-        MappeableBitmapContainer bc = new MappeableBitmapContainer(start,end);
-        MappeableBitmapContainer bc2 = new MappeableBitmapContainer(array,0);
+    for (int start = 0; start <= (1 << 16); start += 63) {
+      for (int end = start; end <= (1 << 16); end += 63) {
+        LongBuffer array = ByteBuffer.allocateDirect((1 << 16) / 8).asLongBuffer();
+        MappeableBitmapContainer bc = new MappeableBitmapContainer(start, end);
+        MappeableBitmapContainer bc2 = new MappeableBitmapContainer(array, 0);
         assertFalse(bc2.isArrayBacked());
-        MappeableBitmapContainer bc3 = (MappeableBitmapContainer) bc2.add(start,end);
-        bc2.iadd(start,end);
-        assertEquals(bc.getCardinality(), end-start);
-        assertEquals(bc2.getCardinality(), end-start);
+        MappeableBitmapContainer bc3 = (MappeableBitmapContainer) bc2.add(start, end);
+        bc2.iadd(start, end);
+        assertEquals(bc.getCardinality(), end - start);
+        assertEquals(bc2.getCardinality(), end - start);
         assertEquals(bc, bc2);
         assertEquals(bc, bc3);
-        assertEquals(0,bc2.remove(start, end).getCardinality());
-        assertEquals(bc2.getCardinality(), end-start);
-        assertEquals(0,bc2.not(start, end).getCardinality());
-      }  
+        assertEquals(0, bc2.remove(start, end).getCardinality());
+        assertEquals(bc2.getCardinality(), end - start);
+        assertEquals(0, bc2.not(start, end).getCardinality());
+      }
     }
   }
 
-
   @Test
   public void testRangeCardinality() {
-    MappeableBitmapContainer bc = generateContainer((char)100, (char)10000, 5);
+    MappeableBitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
     bc = (MappeableBitmapContainer) bc.add(200, 2000);
     assertEquals(8280, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality2() {
-    MappeableBitmapContainer bc = generateContainer((char)100, (char)10000, 5);
+    MappeableBitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
     bc.iadd(200, 2000);
     assertEquals(8280, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality3() {
-    MappeableBitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    MappeableRunContainer rc = TestMappeableRunContainer.generateContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    MappeableBitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc =
+        TestMappeableRunContainer.generateContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc.ior(rc);
     assertEquals(8677, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality4() {
-    MappeableBitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    MappeableRunContainer rc = TestMappeableRunContainer.generateContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    MappeableBitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc =
+        TestMappeableRunContainer.generateContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc = (MappeableBitmapContainer) bc.andNot(rc);
     assertEquals(5274, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality5() {
-    MappeableBitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    MappeableRunContainer rc = TestMappeableRunContainer.generateContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    MappeableBitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc =
+        TestMappeableRunContainer.generateContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc.iandNot(rc);
     assertEquals(5274, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality6() {
-    MappeableBitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    MappeableRunContainer rc = TestMappeableRunContainer.generateContainer(new char[]{7, 300, 400, 900, 1400, 5200}, 3);
+    MappeableBitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc =
+        TestMappeableRunContainer.generateContainer(new char[] {7, 300, 400, 900, 1400, 5200}, 3);
     bc = (MappeableBitmapContainer) bc.iand(rc);
     assertEquals(5046, bc.cardinality);
   }
 
   @Test
   public void testRangeCardinality7() {
-    MappeableBitmapContainer bc = generateContainer((char)100, (char)10000, 5);
-    MappeableRunContainer rc = TestMappeableRunContainer.generateContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    MappeableBitmapContainer bc = generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc =
+        TestMappeableRunContainer.generateContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     bc.ixor(rc);
     assertEquals(6031, bc.cardinality);
   }
 
   @Test
   public void testNextTooLarge() {
-    assertThrows(IndexOutOfBoundsException.class, () ->
-    emptyContainer().nextSetBit(Short.MAX_VALUE + 1));
+    assertThrows(
+        IndexOutOfBoundsException.class, () -> emptyContainer().nextSetBit(Short.MAX_VALUE + 1));
   }
 
   @Test
   public void testNextTooSmall() {
-    assertThrows(IndexOutOfBoundsException.class, () ->
-    emptyContainer().nextSetBit(-1));
+    assertThrows(IndexOutOfBoundsException.class, () -> emptyContainer().nextSetBit(-1));
   }
 
   @Test
   public void testPreviousTooLarge() {
-    assertThrows(IndexOutOfBoundsException.class, () ->
-    emptyContainer().prevSetBit(Short.MAX_VALUE + 1));
+    assertThrows(
+        IndexOutOfBoundsException.class, () -> emptyContainer().prevSetBit(Short.MAX_VALUE + 1));
   }
 
   @Test
   public void testPreviousTooSmall() {
-    assertThrows(IndexOutOfBoundsException.class, () ->
-    emptyContainer().prevSetBit(-1));
+    assertThrows(IndexOutOfBoundsException.class, () -> emptyContainer().prevSetBit(-1));
   }
 
   @Test
   public void addInvalidRange() {
-    assertThrows(RuntimeException.class, () -> {
-      MappeableBitmapContainer bc = new MappeableBitmapContainer();
-      bc.add(10, 1);
-    });
+    assertThrows(
+        RuntimeException.class,
+        () -> {
+          MappeableBitmapContainer bc = new MappeableBitmapContainer();
+          bc.add(10, 1);
+        });
   }
 
   @Test
   public void iaddInvalidRange() {
-    assertThrows(RuntimeException.class, () -> {
-      MappeableBitmapContainer bc = new MappeableBitmapContainer();
-      bc.iadd(10, 1);
-    });
+    assertThrows(
+        RuntimeException.class,
+        () -> {
+          MappeableBitmapContainer bc = new MappeableBitmapContainer();
+          bc.iadd(10, 1);
+        });
   }
 
   @Test
   public void iand() {
     MappeableBitmapContainer bc = new MappeableBitmapContainer();
     MappeableRunContainer rc = new MappeableRunContainer();
-    bc.iadd(1,13);
-    rc.iadd(5,27);
+    bc.iadd(1, 13);
+    rc.iadd(5, 27);
     MappeableContainer result = bc.iand(rc);
     assertEquals(8, result.getCardinality());
     for (char i = 5; i < 13; i++) {
@@ -386,8 +388,8 @@ public void iand() {
   public void ior() {
     MappeableBitmapContainer bc = new MappeableBitmapContainer();
     MappeableRunContainer rc = new MappeableRunContainer();
-    bc.iadd(1,13);
-    rc.iadd(5,27);
+    bc.iadd(1, 13);
+    rc.iadd(5, 27);
     MappeableContainer result = bc.ior(rc);
     assertEquals(26, result.getCardinality());
     for (char i = 1; i < 27; i++) {
@@ -398,22 +400,24 @@ public void ior() {
   @Test
   public void iremoveEmptyRange() {
     MappeableBitmapContainer bc = new MappeableBitmapContainer();
-    bc.iremove(1,1);
+    bc.iremove(1, 1);
     assertEquals(0, bc.getCardinality());
   }
 
   @Test
   public void iremoveInvalidRange() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableBitmapContainer bc = new MappeableBitmapContainer();
-      bc.iremove(13, 1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableBitmapContainer bc = new MappeableBitmapContainer();
+          bc.iremove(13, 1);
+        });
   }
 
   @Test
   public void iremove() {
     MappeableBitmapContainer bc = new MappeableBitmapContainer();
-    bc.iremove(1,13);
+    bc.iremove(1, 13);
     assertEquals(0, bc.getCardinality());
   }
 
@@ -431,8 +435,8 @@ public void iremove2() {
   @Test
   public void numberOfRuns() {
     MappeableContainer bc = new MappeableBitmapContainer();
-    bc = bc.add(1,13);
-    bc = bc.add(19,27);
+    bc = bc.add(1, 13);
+    bc = bc.add(19, 27);
     assertEquals(2, bc.numberOfRuns());
   }
 
@@ -446,11 +450,13 @@ public void numberOfRuns2() {
 
   @Test
   public void selectInvalidPosition() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer bc = new MappeableBitmapContainer();
-      bc = bc.add(1, 13);
-      bc.select(100);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer bc = new MappeableBitmapContainer();
+          bc = bc.add(1, 13);
+          bc.select(100);
+        });
   }
 
   @Test
@@ -601,14 +607,16 @@ public void foreach() {
     LongBuffer buffer = LongBuffer.allocate(MAX_CAPACITY / 64);
     buffer.put(~0L);
     MappeableContainer bc = new MappeableBitmapContainer(buffer.asReadOnlyBuffer(), 64);
-    bc.forEach((char) 0, new IntConsumer() {
-      int expected = 0;
+    bc.forEach(
+        (char) 0,
+        new IntConsumer() {
+          int expected = 0;
 
-      @Override
-      public void accept(int value) {
-        assertEquals(value, expected++);
-      }
-    });
+          @Override
+          public void accept(int value) {
+            assertEquals(value, expected++);
+          }
+        });
   }
 
   @Test
@@ -707,12 +715,15 @@ public void testLazyORFull3() {
 
   @Test
   public void testFirstLast_SlicedBuffer() {
-    LongBuffer buffer = LongBuffer.allocate(MAX_CAPACITY / 64)
-                                  .put(0, 1L << 62)
-                                  .put(1, 1L << 2 | 1L << 32)
-                                  .slice()
-                                  .asReadOnlyBuffer();
-    assertFalse(BufferUtil.isBackedBySimpleArray(buffer), "Sanity check - aiming to test non array backed branch");
+    LongBuffer buffer =
+        LongBuffer.allocate(MAX_CAPACITY / 64)
+            .put(0, 1L << 62)
+            .put(1, 1L << 2 | 1L << 32)
+            .slice()
+            .asReadOnlyBuffer();
+    assertFalse(
+        BufferUtil.isBackedBySimpleArray(buffer),
+        "Sanity check - aiming to test non array backed branch");
     MappeableBitmapContainer mbc = new MappeableBitmapContainer(buffer, 3);
     assertEquals(62, mbc.first());
     assertEquals(96, mbc.last());
@@ -729,25 +740,27 @@ public void testIntersectsWithRange() {
 
   public static Stream bitmapsForRangeIntersection() {
     return Stream.of(
-            Arguments.of(new MappeableBitmapContainer().add((char)60), 0, 61, true),
-            Arguments.of(new MappeableBitmapContainer().add((char)60), 0, 60, false),
-            Arguments.of(new MappeableBitmapContainer().add((char)1000), 0, 1001, true),
-            Arguments.of(new MappeableBitmapContainer().add((char)1000), 0, 1000, false),
-            Arguments.of(new MappeableBitmapContainer().add((char)1000), 0, 10000, true)
-    );
+        Arguments.of(new MappeableBitmapContainer().add((char) 60), 0, 61, true),
+        Arguments.of(new MappeableBitmapContainer().add((char) 60), 0, 60, false),
+        Arguments.of(new MappeableBitmapContainer().add((char) 1000), 0, 1001, true),
+        Arguments.of(new MappeableBitmapContainer().add((char) 1000), 0, 1000, false),
+        Arguments.of(new MappeableBitmapContainer().add((char) 1000), 0, 10000, true));
   }
 
   @ParameterizedTest
   @MethodSource("bitmapsForRangeIntersection")
-  public void testIntersectsWithRangeUpperBoundaries(MappeableContainer container, int min, int sup, boolean intersects) {
+  public void testIntersectsWithRangeUpperBoundaries(
+      MappeableContainer container, int min, int sup, boolean intersects) {
     assertEquals(intersects, container.intersects(min, sup));
   }
 
-
   @Test
   public void testIntersectsWithRangeHitScan() {
-    MappeableContainer container = new MappeableBitmapContainer().add(0, 10)
-            .add(500, 512).add(lower16Bits(-50), lower16Bits(-10));
+    MappeableContainer container =
+        new MappeableBitmapContainer()
+            .add(0, 10)
+            .add(500, 512)
+            .add(lower16Bits(-50), lower16Bits(-10));
     assertTrue(container.intersects(0, 1));
     assertTrue(container.intersects(0, 101));
     assertTrue(container.intersects(0, 1 << 16));
@@ -755,30 +768,31 @@ public void testIntersectsWithRangeHitScan() {
     assertTrue(container.intersects(501, 511));
   }
 
-
   @Test
   public void testIntersectsWithRangeUnsigned() {
-    MappeableContainer container = new MappeableBitmapContainer().add(lower16Bits(-50), lower16Bits(-10));
+    MappeableContainer container =
+        new MappeableBitmapContainer().add(lower16Bits(-50), lower16Bits(-10));
     assertFalse(container.intersects(0, 1));
     assertTrue(container.intersects(0, lower16Bits(-40)));
     assertFalse(container.intersects(lower16Bits(-100), lower16Bits(-55)));
     assertFalse(container.intersects(lower16Bits(-9), lower16Bits(-1)));
-    //assertTrue(container.intersects(11, (char)-1));// forbidden
+    // assertTrue(container.intersects(11, (char)-1));// forbidden
   }
 
   @Test
   public void testIntersectsAtEndWord() {
-    MappeableContainer container = new MappeableBitmapContainer().add(lower16Bits(-500), lower16Bits(-10));
+    MappeableContainer container =
+        new MappeableBitmapContainer().add(lower16Bits(-500), lower16Bits(-10));
     assertTrue(container.intersects(lower16Bits(-50), lower16Bits(-10)));
     assertTrue(container.intersects(lower16Bits(-400), lower16Bits(-11)));
     assertTrue(container.intersects(lower16Bits(-11), lower16Bits(-1)));
     assertFalse(container.intersects(lower16Bits(-10), lower16Bits(-1)));
   }
 
-
   @Test
   public void testIntersectsAtEndWord2() {
-    MappeableContainer container = new MappeableBitmapContainer().add(lower16Bits(500), lower16Bits(-500));
+    MappeableContainer container =
+        new MappeableBitmapContainer().add(lower16Bits(500), lower16Bits(-500));
     assertTrue(container.intersects(lower16Bits(-650), lower16Bits(-500)));
     assertTrue(container.intersects(lower16Bits(-501), lower16Bits(-1)));
     assertFalse(container.intersects(lower16Bits(-500), lower16Bits(-1)));
@@ -790,7 +804,8 @@ public void testContainsRangeSingleWord() {
     long[] bitmap = evenBits();
     bitmap[10] = -1L;
     int cardinality = 32 + 1 << 15;
-    MappeableBitmapContainer container = new MappeableBitmapContainer(LongBuffer.wrap(bitmap), cardinality);
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer(LongBuffer.wrap(bitmap), cardinality);
     assertTrue(container.contains(0, 1));
     assertTrue(container.contains(64 * 10, 64 * 11));
     assertFalse(container.contains(64 * 10, 2 + 64 * 11));
@@ -804,7 +819,8 @@ public void testContainsRangeMultiWord() {
     bitmap[11] = -1L;
     bitmap[12] |= ((1L << 32) - 1);
     int cardinality = 32 + 32 + 16 + 1 << 15;
-    MappeableBitmapContainer container = new MappeableBitmapContainer(LongBuffer.wrap(bitmap), cardinality);
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer(LongBuffer.wrap(bitmap), cardinality);
     assertTrue(container.contains(0, 1));
     assertFalse(container.contains(64 * 10, (64 * 13) - 30));
     assertTrue(container.contains(64 * 10, (64 * 13) - 31));
@@ -813,13 +829,13 @@ public void testContainsRangeMultiWord() {
     assertFalse(container.contains(64 * 10, 2 + 64 * 13));
   }
 
-
   @Test
   public void testContainsRangeSubWord() {
     long[] bitmap = evenBits();
     bitmap[bitmap.length - 1] = ~((1L << 63) | 1L);
     int cardinality = 32 + 32 + 16 + 1 << 15;
-    MappeableBitmapContainer container = new MappeableBitmapContainer(LongBuffer.wrap(bitmap), cardinality);
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer(LongBuffer.wrap(bitmap), cardinality);
     assertFalse(container.contains(64 * 1023, 64 * 1024));
     assertFalse(container.contains(64 * 1023, 64 * 1024 - 1));
     assertTrue(container.contains(1 + 64 * 1023, 64 * 1024 - 1));
@@ -830,273 +846,316 @@ public void testContainsRangeSubWord() {
 
   @Test
   public void testNextValue() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3).toBitmapContainer();
-    assertEquals(10, container.nextValue((char)10));
-    assertEquals(20, container.nextValue((char)11));
-    assertEquals(30, container.nextValue((char)30));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3)
+            .toBitmapContainer();
+    assertEquals(10, container.nextValue((char) 10));
+    assertEquals(20, container.nextValue((char) 11));
+    assertEquals(30, container.nextValue((char) 30));
   }
 
   @Test
   public void testNextValueAfterEnd() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3).toBitmapContainer();
-    assertEquals(-1, container.nextValue((char)31));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3)
+            .toBitmapContainer();
+    assertEquals(-1, container.nextValue((char) 31));
   }
 
   @Test
   public void testNextValue2() {
-    MappeableBitmapContainer container = new MappeableBitmapContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(-1, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)5000));
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer().iadd(64, 129).toBitmapContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(-1, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 5000));
   }
 
   @Test
   public void testNextValueBetweenRuns() {
-    MappeableBitmapContainer container = new MappeableBitmapContainer().iadd(64, 129).iadd(256, 321).toBitmapContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(256, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)512));
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer().iadd(64, 129).iadd(256, 321).toBitmapContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(256, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 512));
   }
 
   @Test
   public void testNextValue3() {
-    MappeableBitmapContainer container = new MappeableBitmapContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)63));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(200, container.nextValue((char)129));
-    assertEquals(200, container.nextValue((char)199));
-    assertEquals(200, container.nextValue((char)200));
-    assertEquals(250, container.nextValue((char)250));
-    assertEquals(5000, container.nextValue((char)2500));
-    assertEquals(5000, container.nextValue((char)5000));
-    assertEquals(5200, container.nextValue((char)5200));
-    assertEquals(-1, container.nextValue((char)5201));
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer()
+            .iadd(64, 129)
+            .iadd(200, 501)
+            .iadd(5000, 5201)
+            .toBitmapContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 63));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(200, container.nextValue((char) 129));
+    assertEquals(200, container.nextValue((char) 199));
+    assertEquals(200, container.nextValue((char) 200));
+    assertEquals(250, container.nextValue((char) 250));
+    assertEquals(5000, container.nextValue((char) 2500));
+    assertEquals(5000, container.nextValue((char) 5000));
+    assertEquals(5200, container.nextValue((char) 5200));
+    assertEquals(-1, container.nextValue((char) 5201));
   }
 
   @Test
   public void testPreviousValue1() {
-    MappeableBitmapContainer container = new MappeableBitmapContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer().iadd(64, 129).toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
   }
 
   @Test
   public void testPreviousValue2() {
-    MappeableBitmapContainer container = new MappeableBitmapContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
-    assertEquals(128, container.previousValue((char)199));
-    assertEquals(200, container.previousValue((char)200));
-    assertEquals(250, container.previousValue((char)250));
-    assertEquals(500, container.previousValue((char)2500));
-    assertEquals(5000, container.previousValue((char)5000));
-    assertEquals(5200, container.previousValue((char)5200));
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer()
+            .iadd(64, 129)
+            .iadd(200, 501)
+            .iadd(5000, 5201)
+            .toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
+    assertEquals(128, container.previousValue((char) 199));
+    assertEquals(200, container.previousValue((char) 200));
+    assertEquals(250, container.previousValue((char) 250));
+    assertEquals(500, container.previousValue((char) 2500));
+    assertEquals(5000, container.previousValue((char) 5000));
+    assertEquals(5200, container.previousValue((char) 5200));
   }
 
   @Test
   public void testPreviousValueBeforeStart() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)5));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3)
+            .toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) 5));
   }
 
   @Test
   public void testPreviousValueSparse() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3).toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)9));
-    assertEquals(10, container.previousValue((char)10));
-    assertEquals(10, container.previousValue((char)11));
-    assertEquals(20, container.previousValue((char)21));
-    assertEquals(30, container.previousValue((char)30));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3)
+            .toBitmapContainer();
+    assertEquals(-1, container.previousValue((char) 9));
+    assertEquals(10, container.previousValue((char) 10));
+    assertEquals(10, container.previousValue((char) 11));
+    assertEquals(20, container.previousValue((char) 21));
+    assertEquals(30, container.previousValue((char) 30));
   }
 
   @Test
   public void testPreviousValueAfterEnd() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3).toBitmapContainer();
-    assertEquals(30, container.previousValue((char)31));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3)
+            .toBitmapContainer();
+    assertEquals(30, container.previousValue((char) 31));
   }
 
   @Test
   public void testPreviousEvenBits() {
     MappeableContainer container = new BitmapContainer(evenBits(), 1 << 15).toMappeableContainer();
-    assertEquals(0, container.previousValue((char)0));
-    assertEquals(0, container.previousValue((char)1));
-    assertEquals(2, container.previousValue((char)2));
-    assertEquals(2, container.previousValue((char)3));
+    assertEquals(0, container.previousValue((char) 0));
+    assertEquals(0, container.previousValue((char) 1));
+    assertEquals(2, container.previousValue((char) 2));
+    assertEquals(2, container.previousValue((char) 3));
   }
 
   @Test
   public void testPreviousValueUnsigned() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}), 2)
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(
+                CharBuffer.wrap(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)}), 2)
             .toBitmapContainer();
-    assertEquals(-1, container.previousValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 8)));
+    assertEquals(-1, container.previousValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testNextValueUnsigned() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { (char)((1 << 15) | 5), (char)((1 << 15) | 7)}), 2).toBitmapContainer();
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 7)));
-    assertEquals(-1, container.nextValue((char)((1 << 15) | 8)));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(
+                CharBuffer.wrap(new char[] {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)}), 2)
+            .toBitmapContainer();
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 7)));
+    assertEquals(-1, container.nextValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testPreviousAbsentValue1() {
-    MappeableBitmapContainer container = new MappeableArrayContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer().iadd(64, 129).toBitmapContainer();
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
   }
 
   @Test
   public void testPreviousAbsentValue2() {
-    MappeableBitmapContainer container = new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201).toBitmapContainer();
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
-    assertEquals(199, container.previousAbsentValue((char)199));
-    assertEquals(199, container.previousAbsentValue((char)200));
-    assertEquals(199, container.previousAbsentValue((char)250));
-    assertEquals(2500, container.previousAbsentValue((char)2500));
-    assertEquals(4999, container.previousAbsentValue((char)5000));
-    assertEquals(4999, container.previousAbsentValue((char)5200));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer()
+            .iadd(64, 129)
+            .iadd(200, 501)
+            .iadd(5000, 5201)
+            .toBitmapContainer();
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
+    assertEquals(199, container.previousAbsentValue((char) 199));
+    assertEquals(199, container.previousAbsentValue((char) 200));
+    assertEquals(199, container.previousAbsentValue((char) 250));
+    assertEquals(2500, container.previousAbsentValue((char) 2500));
+    assertEquals(4999, container.previousAbsentValue((char) 5000));
+    assertEquals(4999, container.previousAbsentValue((char) 5200));
   }
 
   @Test
   public void testPreviousAbsentValueEmpty() {
     MappeableBitmapContainer container = new MappeableArrayContainer().toBitmapContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.previousAbsentValue((char)i));
+      assertEquals(i, container.previousAbsentValue((char) i));
     }
   }
 
   @Test
   public void testPreviousAbsentValueSparse() {
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(new char[] { 10, 20, 30}), 3).toBitmapContainer();
-    assertEquals(9, container.previousAbsentValue((char)9));
-    assertEquals(9, container.previousAbsentValue((char)10));
-    assertEquals(11, container.previousAbsentValue((char)11));
-    assertEquals(21, container.previousAbsentValue((char)21));
-    assertEquals(29, container.previousAbsentValue((char)30));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {10, 20, 30}), 3)
+            .toBitmapContainer();
+    assertEquals(9, container.previousAbsentValue((char) 9));
+    assertEquals(9, container.previousAbsentValue((char) 10));
+    assertEquals(11, container.previousAbsentValue((char) 11));
+    assertEquals(21, container.previousAbsentValue((char) 21));
+    assertEquals(29, container.previousAbsentValue((char) 30));
   }
 
   @Test
   public void testPreviousAbsentEvenBits() {
     MappeableContainer container = new BitmapContainer(evenBits(), 1 << 15).toMappeableContainer();
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i - 1, container.previousAbsentValue((char)i));
-      assertEquals(i + 1, container.previousAbsentValue((char)(i+1)));
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i - 1, container.previousAbsentValue((char) i));
+      assertEquals(i + 1, container.previousAbsentValue((char) (i + 1)));
     }
   }
 
   @Test
   public void testPreviousAbsentValueUnsigned() {
     char[] array = {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)};
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(array), 2).toBitmapContainer();
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char)((1 << 15) | 8)));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(array), 2).toBitmapContainer();
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testNextAbsentValue1() {
-    MappeableBitmapContainer container = new MappeableArrayContainer().iadd(64, 129).toBitmapContainer();
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer().iadd(64, 129).toBitmapContainer();
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
   }
 
   @Test
   public void testNextAbsentValue2() {
-    MappeableBitmapContainer container = new MappeableArrayContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201)
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer()
+            .iadd(64, 129)
+            .iadd(200, 501)
+            .iadd(5000, 5201)
             .toBitmapContainer();
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
-    assertEquals(199, container.nextAbsentValue((char)199));
-    assertEquals(501, container.nextAbsentValue((char)200));
-    assertEquals(501, container.nextAbsentValue((char)250));
-    assertEquals(2500, container.nextAbsentValue((char)2500));
-    assertEquals(5201, container.nextAbsentValue((char)5000));
-    assertEquals(5201, container.nextAbsentValue((char)5200));
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
+    assertEquals(199, container.nextAbsentValue((char) 199));
+    assertEquals(501, container.nextAbsentValue((char) 200));
+    assertEquals(501, container.nextAbsentValue((char) 250));
+    assertEquals(2500, container.nextAbsentValue((char) 2500));
+    assertEquals(5201, container.nextAbsentValue((char) 5000));
+    assertEquals(5201, container.nextAbsentValue((char) 5200));
   }
 
   @Test
   public void testNextAbsentValueEmpty() {
     MappeableBitmapContainer container = new MappeableArrayContainer().toBitmapContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.nextAbsentValue((char)i));
+      assertEquals(i, container.nextAbsentValue((char) i));
     }
   }
 
   @Test
   public void testNextAbsentValueSparse() {
     char[] array = {10, 20, 30};
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(array), 3).toBitmapContainer();
-    assertEquals(9, container.nextAbsentValue((char)9));
-    assertEquals(11, container.nextAbsentValue((char)10));
-    assertEquals(11, container.nextAbsentValue((char)11));
-    assertEquals(21, container.nextAbsentValue((char)21));
-    assertEquals(31, container.nextAbsentValue((char)30));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(array), 3).toBitmapContainer();
+    assertEquals(9, container.nextAbsentValue((char) 9));
+    assertEquals(11, container.nextAbsentValue((char) 10));
+    assertEquals(11, container.nextAbsentValue((char) 11));
+    assertEquals(21, container.nextAbsentValue((char) 21));
+    assertEquals(31, container.nextAbsentValue((char) 30));
   }
 
   @Test
   public void testNextAbsentEvenBits() {
     int cardinality = 32 + 1 << 15;
-    MappeableBitmapContainer container = new MappeableBitmapContainer(LongBuffer.wrap(evenBits()), cardinality);
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i + 1, container.nextAbsentValue((char)i));
-      assertEquals(i + 1, container.nextAbsentValue((char)(i+1)));
+    MappeableBitmapContainer container =
+        new MappeableBitmapContainer(LongBuffer.wrap(evenBits()), cardinality);
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i + 1, container.nextAbsentValue((char) i));
+      assertEquals(i + 1, container.nextAbsentValue((char) (i + 1)));
     }
   }
 
   @Test
   public void testNextAbsentValueUnsigned() {
     char[] array = {(char) ((1 << 15) | 5), (char) ((1 << 15) | 7)};
-    MappeableBitmapContainer container = new MappeableArrayContainer(CharBuffer.wrap(array), 2).toBitmapContainer();
-    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 8)));
+    MappeableBitmapContainer container =
+        new MappeableArrayContainer(CharBuffer.wrap(array), 2).toBitmapContainer();
+    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 8)));
   }
 
   @Test
@@ -1142,7 +1201,6 @@ private static long[] evenBits() {
   }
 
   private static int lower16Bits(int x) {
-    return ((char)x);
+    return ((char) x);
   }
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainerCharIterator.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainerCharIterator.java
new file mode 100644
index 000000000..b3ed445fb
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableBitmapContainerCharIterator.java
@@ -0,0 +1,46 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.roaringbitmap.buffer.MappeableArrayContainer.DEFAULT_MAX_SIZE;
+
+import org.roaringbitmap.PeekableCharIterator;
+
+import com.google.common.primitives.Ints;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestMappeableBitmapContainerCharIterator {
+
+  private static List asList(PeekableCharIterator ints) {
+    int[] values = new int[10];
+    int size = 0;
+    while (ints.hasNext()) {
+      if (!(size < values.length)) {
+        values = Arrays.copyOf(values, values.length * 2);
+      }
+      values[size++] = ints.next();
+    }
+    return Ints.asList(Arrays.copyOf(values, size));
+  }
+
+  @Test
+  public void testClone() {
+    MappeableBitmapContainer mappeableBitmapContainer = new MappeableBitmapContainer();
+    for (int k = 0; k < 2 * DEFAULT_MAX_SIZE; ++k) {
+      mappeableBitmapContainer.add((char) (k * 10));
+    }
+    MappeableBitmapContainerCharIterator tmbc =
+        new MappeableBitmapContainerCharIterator(mappeableBitmapContainer);
+    PeekableCharIterator tmbcClone = tmbc.clone();
+    assertNotNull(tmbcClone);
+    final List tmbcList = asList(tmbc);
+    final List tmbcCloneList = asList(tmbcClone);
+    assertEquals(tmbcList, tmbcCloneList);
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableRunContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableRunContainer.java
similarity index 87%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableRunContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableRunContainer.java
index 2dec26118..19e81d987 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableRunContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMappeableRunContainer.java
@@ -1,5 +1,11 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY;
+import static org.roaringbitmap.buffer.TestMappeableArrayContainer.newArrayContainer;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
@@ -14,10 +20,6 @@
 import java.nio.LongBuffer;
 import java.util.Arrays;
 
-import static org.junit.jupiter.api.Assertions.*;
-import static org.roaringbitmap.buffer.MappeableBitmapContainer.MAX_CAPACITY;
-import static org.roaringbitmap.buffer.TestMappeableArrayContainer.newArrayContainer;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestMappeableRunContainer {
 
@@ -67,17 +69,19 @@ public void not() {
   static MappeableRunContainer newRunContainer(int firstOfRun, final int lastOfRun) {
     CharBuffer buffer = CharBuffer.allocate(2);
     buffer.put((char) firstOfRun);
-    buffer.put((char) (lastOfRun-firstOfRun-1));
+    buffer.put((char) (lastOfRun - firstOfRun - 1));
     return new MappeableRunContainer(buffer.asReadOnlyBuffer(), 1);
   }
 
   @Test
   public void selectInvalidPosition() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer bc = new MappeableRunContainer();
-      bc = bc.add(1, 13);
-      bc.select(100);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer bc = new MappeableRunContainer();
+          bc = bc.add(1, 13);
+          bc.select(100);
+        });
   }
 
   @Test
@@ -221,18 +225,20 @@ public void testLazyORFull3() {
 
   @Test
   public void testRangeCardinality() {
-    MappeableBitmapContainer bc = TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    MappeableRunContainer rc = generateContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    MappeableBitmapContainer bc =
+        TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc = generateContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     MappeableContainer result = rc.or(bc);
     assertEquals(8677, result.getCardinality());
   }
 
   @Test
   public void testRangeCardinality2() {
-    MappeableBitmapContainer bc = TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    bc.add((char)22345); //important case to have greater element than run container
-    bc.add((char)Short.MAX_VALUE);
-    MappeableRunContainer rc = generateContainer(new char[]{7, 300, 400, 900, 1400, 18000}, 3);
+    MappeableBitmapContainer bc =
+        TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
+    bc.add((char) 22345); // important case to have greater element than run container
+    bc.add((char) Short.MAX_VALUE);
+    MappeableRunContainer rc = generateContainer(new char[] {7, 300, 400, 900, 1400, 18000}, 3);
     assertTrue(rc.getCardinality() > MappeableArrayContainer.DEFAULT_MAX_SIZE);
     MappeableContainer result = rc.andNot(bc);
     assertEquals(11437, result.getCardinality());
@@ -240,16 +246,18 @@ public void testRangeCardinality2() {
 
   @Test
   public void testRangeCardinality3() {
-    MappeableBitmapContainer bc = TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    MappeableRunContainer rc = generateContainer(new char[]{7, 300, 400, 900, 1400, 5200}, 3);
+    MappeableBitmapContainer bc =
+        TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc = generateContainer(new char[] {7, 300, 400, 900, 1400, 5200}, 3);
     MappeableBitmapContainer result = (MappeableBitmapContainer) rc.and(bc);
     assertEquals(5046, result.getCardinality());
   }
 
   @Test
   public void testRangeCardinality4() {
-    MappeableBitmapContainer bc = TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
-    MappeableRunContainer rc = generateContainer(new char[]{7, 300, 400, 900, 1400, 2200}, 3);
+    MappeableBitmapContainer bc =
+        TestMappeableBitmapContainer.generateContainer((char) 100, (char) 10000, 5);
+    MappeableRunContainer rc = generateContainer(new char[] {7, 300, 400, 900, 1400, 2200}, 3);
     MappeableBitmapContainer result = (MappeableBitmapContainer) rc.xor(bc);
     assertEquals(6031, result.getCardinality());
   }
@@ -290,7 +298,7 @@ public void testEqualsArrayContainer_NotEqual_ArrayShifted() {
   public void testEqualsArrayContainer_NotEqual_ArrayDiscontiguous() {
     MappeableContainer rc = new MappeableRunContainer().add(0, 10);
     MappeableContainer ac = new MappeableArrayContainer().add(0, 11);
-    ac.flip((char)9);
+    ac.flip((char) 9);
     assertFalse(rc.equals(ac));
     assertFalse(ac.equals(rc));
   }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMemory.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMemory.java
similarity index 80%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMemory.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMemory.java
index b81bd2355..85ac81c31 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMemory.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMemory.java
@@ -1,19 +1,22 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
 
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 public class TestMemory {
   @Test
   public void testGCStability() {
     final int N = 10000;
     final int M = 5000000;
-    System.out.println("[testGCStability] testing GC stability with " + N + " bitmaps containing ~"
-        + M / N + " values each on average");
+    System.out.println(
+        "[testGCStability] testing GC stability with "
+            + N
+            + " bitmaps containing ~"
+            + M / N
+            + " values each on average");
     System.out.println("Universe size = " + M);
     final MutableRoaringBitmap[] bitmaps = new MutableRoaringBitmap[N];
     for (int i = 0; i < N; i++) {
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMemoryMapping.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMemoryMapping.java
similarity index 83%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMemoryMapping.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMemoryMapping.java
index 7ded57cf3..c5dd83db1 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestMemoryMapping.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestMemoryMapping.java
@@ -4,13 +4,27 @@
 
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.roaringbitmap.IntIterator;
+import org.roaringbitmap.RoaringBitmap;
+
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.roaringbitmap.IntIterator;
-import org.roaringbitmap.RoaringBitmap;
 
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.MappedByteBuffer;
@@ -21,9 +35,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import static org.junit.jupiter.api.Assertions.*;
-
-
 class ByteBufferBackedInputStream extends InputStream {
 
   ByteBuffer buf;
@@ -72,7 +83,6 @@ public long skip(long n) {
   }
 }
 
-
 class ByteBufferBackedOutputStream extends OutputStream {
   ByteBuffer buf;
 
@@ -94,10 +104,8 @@ public synchronized void write(byte[] bytes, int off, int len) throws IOExceptio
   public synchronized void write(int b) throws IOException {
     buf.put((byte) b);
   }
-
 }
 
-
 @SuppressWarnings({"static-method"})
 public class TestMemoryMapping {
 
@@ -217,8 +225,11 @@ public static void initFiles() throws IOException {
           rb2.serialize(dos);
           long paft = fos.getChannel().position();
           if (paft - pbef != rb2.serializedSizeInBytes()) {
-            throw new RuntimeException("wrong serializedSizeInBytes:: paft-pbef = " + (paft - pbef)
-                + ", serializedSize = " + rb2.serializedSizeInBytes());
+            throw new RuntimeException(
+                "wrong serializedSizeInBytes:: paft-pbef = "
+                    + (paft - pbef)
+                    + ", serializedSize = "
+                    + rb2.serializedSizeInBytes());
           }
           dos.flush();
           rambitmaps.add(rb2);
@@ -249,7 +260,9 @@ public static void initFiles() throws IOException {
         ImmutableRoaringBitmap newbitmap = new ImmutableRoaringBitmap(bb);
         if (newbitmap.serializedSizeInBytes() != rambitmaps.get(k).serializedSizeInBytes()) {
           throw new RuntimeException(
-              "faulty reported serialization size " + newbitmap.serializedSizeInBytes() + " "
+              "faulty reported serialization size "
+                  + newbitmap.serializedSizeInBytes()
+                  + " "
                   + rambitmaps.get(k).serializedSizeInBytes());
         }
         if (!newbitmap.equals(rambitmaps.get(k))) {
@@ -262,8 +275,12 @@ public static void initFiles() throws IOException {
         }
       }
       final long aft = System.currentTimeMillis();
-      System.out.println("[TestMemoryMapping] Mapped " + (offsets.size() - 1) + " bitmaps in "
-          + (aft - bef) + "ms");
+      System.out.println(
+          "[TestMemoryMapping] Mapped "
+              + (offsets.size() - 1)
+              + " bitmaps in "
+              + (aft - bef)
+              + "ms");
     } finally {
       memoryMappedFile.close();
     }
@@ -349,10 +366,18 @@ public void intersections() {
     }
 
     for (int k = 0; k < mappedbitmaps.size() - 4; k += 4) {
-      final MutableRoaringBitmap rb = BufferFastAggregation.and(mappedbitmaps.get(k),
-          mappedbitmaps.get(k + 1), mappedbitmaps.get(k + 3), mappedbitmaps.get(k + 4));
-      final MutableRoaringBitmap rbram = BufferFastAggregation.and(rambitmaps.get(k),
-          rambitmaps.get(k + 1), rambitmaps.get(k + 3), rambitmaps.get(k + 4));
+      final MutableRoaringBitmap rb =
+          BufferFastAggregation.and(
+              mappedbitmaps.get(k),
+              mappedbitmaps.get(k + 1),
+              mappedbitmaps.get(k + 3),
+              mappedbitmaps.get(k + 4));
+      final MutableRoaringBitmap rbram =
+          BufferFastAggregation.and(
+              rambitmaps.get(k),
+              rambitmaps.get(k + 1),
+              rambitmaps.get(k + 3),
+              rambitmaps.get(k + 4));
       assertTrue(rb.equals(rbram));
     }
   }
@@ -384,27 +409,28 @@ public void multithreadingTest() throws InterruptedException, IOException {
 
     for (int i = 0; i < numThreads; i++) {
       final int ti = i;
-      executorService.execute(new Runnable() {
-
-        @Override
-        public void run() {
-          ready.countDown();
-          try {
-            ready.await();
-            final int elementToCheck = Short.MAX_VALUE * ti;
-            for (int j = 0; j < 10000000; j++) {
+      executorService.execute(
+          new Runnable() {
+
+            @Override
+            public void run() {
+              ready.countDown();
               try {
-                assertTrue(rrback1.contains(elementToCheck));
-              } catch (Throwable t) {
-                errors[ti] = t;
+                ready.await();
+                final int elementToCheck = Short.MAX_VALUE * ti;
+                for (int j = 0; j < 10000000; j++) {
+                  try {
+                    assertTrue(rrback1.contains(elementToCheck));
+                  } catch (Throwable t) {
+                    errors[ti] = t;
+                  }
+                }
+              } catch (Throwable e) {
+                errors[ti] = e;
               }
+              finished.countDown();
             }
-          } catch (Throwable e) {
-            errors[ti] = e;
-          }
-          finished.countDown();
-        }
-      });
+          });
     }
     finished.await(5, TimeUnit.SECONDS);
     for (int i = 0; i < numThreads; i++) {
@@ -414,19 +440,15 @@ public void run() {
       }
     }
   }
-  
 
   @Test
-  public void containsTest() throws IOException  {
+  public void containsTest() throws IOException {
     System.out.println("[containsTest]");
-    for(int z = 0; z < 100; ++z) {
+    for (int z = 0; z < 100; ++z) {
       final MutableRoaringBitmap rr1 = new MutableRoaringBitmap();
-      for(int k = 0; k < 100; k+=10)
-        rr1.add(k + z);
-      for(int k = 100000; k < 200000; k+=2)
-        rr1.add(k + z);
-      for(int k = 400000; k < 500000; k++)
-        rr1.add(k + z);    
+      for (int k = 0; k < 100; k += 10) rr1.add(k + z);
+      for (int k = 100000; k < 200000; k += 2) rr1.add(k + z);
+      for (int k = 400000; k < 500000; k++) rr1.add(k + z);
       rr1.runOptimize();
       ByteArrayOutputStream bos = new ByteArrayOutputStream();
       DataOutputStream dos = new DataOutputStream(bos);
@@ -436,12 +458,11 @@ public void containsTest() throws IOException  {
       final ImmutableRoaringBitmap rrback1 = new ImmutableRoaringBitmap(bb);
       assertEquals(rrback1.getLongSizeInBytes(), rr1.getLongSizeInBytes());
       assertEquals(rrback1.serializedSizeInBytes(), rr1.serializedSizeInBytes());
-      for(int k = 0; k < 1000000; k += 100) {
+      for (int k = 0; k < 1000000; k += 100) {
         assertEquals(rrback1.contains(k), rr1.contains(k));
       }
     }
   }
-  
 
   @Test
   public void oneFormat() throws IOException {
@@ -462,11 +483,10 @@ public void oneFormat() throws IOException {
       arr = null;
       RoaringBitmap rrasroaring = rr.toRoaringBitmap();
       assertEquals(newr, rrasroaring);
-      System.out
-          .println("[TestMemoryMapping] testing compat. bitmap " + k + " out of " + ms + ". ok.");
+      System.out.println(
+          "[TestMemoryMapping] testing compat. bitmap " + k + " out of " + ms + ". ok.");
     }
     System.out.println("[TestMemoryMapping] Format compatibility ok");
-
   }
 
   @Test
@@ -535,7 +555,6 @@ public void standardTest1() throws IOException {
     assertEquals(rr1.hashCode(), rrback1c.hashCode());
     assertEquals(rr2.hashCode(), rrback2.hashCode());
     assertEquals(rr2.hashCode(), rrback2c.hashCode());
-
   }
 
   @Test
@@ -544,8 +563,11 @@ public void testIterator() {
     final int ms = mappedbitmaps.size();
     System.out.println("We first test in-memory (RoaringBitmap) iterators.");
     for (int k = 0; k < ms; ++k) {
-      System.out.println("[TestMemoryMapping] testing copy via iterators using RoaringBitmap copy "
-          + k + " out of " + ms);
+      System.out.println(
+          "[TestMemoryMapping] testing copy via iterators using RoaringBitmap copy "
+              + k
+              + " out of "
+              + ms);
       final RoaringBitmap target = mappedbitmaps.get(k).toRoaringBitmap();
       final int truecard = target.getCardinality();
       System.out.println("Cardinality = " + truecard);
@@ -577,8 +599,12 @@ public void testIterator() {
       long t4 = System.nanoTime();
       System.out.println(" iterator two ns/ops = " + (t4 - t3) * 1.0 / truecard);
       assertEquals(truecard, card2);
-      System.out.println("[TestMemoryMapping] testing copy via iterators using RoaringBitmap copy "
-          + k + " out of " + ms + " ok");
+      System.out.println(
+          "[TestMemoryMapping] testing copy via iterators using RoaringBitmap copy "
+              + k
+              + " out of "
+              + ms
+              + " ok");
     }
 
     System.out.println("Next, we test mapped (ImmutableRoaringBitmap) iterators.");
@@ -617,8 +643,8 @@ public void testIterator() {
       long t4 = System.nanoTime();
       System.out.println(" iterator two ns/ops = " + (t4 - t3) * 1.0 / truecard);
       assertEquals(truecard, card2);
-      System.out
-          .println("[TestMemoryMapping] testing copy via iterators " + k + " out of " + ms + " ok");
+      System.out.println(
+          "[TestMemoryMapping] testing copy via iterators " + k + " out of " + ms + " ok");
     }
     System.out.println("[TestMemoryMapping] testing a custom iterator copy  ");
 
@@ -647,10 +673,18 @@ public void testIterator() {
   public void unions() {
     System.out.println("[TestMemoryMapping] testing Unions");
     for (int k = 0; k < mappedbitmaps.size() - 4; k += 4) {
-      final MutableRoaringBitmap rb = BufferFastAggregation.or(mappedbitmaps.get(k),
-          mappedbitmaps.get(k + 1), mappedbitmaps.get(k + 3), mappedbitmaps.get(k + 4));
-      final MutableRoaringBitmap rbram = BufferFastAggregation.or(rambitmaps.get(k),
-          rambitmaps.get(k + 1), rambitmaps.get(k + 3), rambitmaps.get(k + 4));
+      final MutableRoaringBitmap rb =
+          BufferFastAggregation.or(
+              mappedbitmaps.get(k),
+              mappedbitmaps.get(k + 1),
+              mappedbitmaps.get(k + 3),
+              mappedbitmaps.get(k + 4));
+      final MutableRoaringBitmap rbram =
+          BufferFastAggregation.or(
+              rambitmaps.get(k),
+              rambitmaps.get(k + 1),
+              rambitmaps.get(k + 3),
+              rambitmaps.get(k + 4));
       assertTrue(rb.equals(rbram));
     }
   }
@@ -659,10 +693,18 @@ public void unions() {
   public void XORs() {
     System.out.println("[TestMemoryMapping] testing XORs");
     for (int k = 0; k < mappedbitmaps.size() - 4; k += 4) {
-      final MutableRoaringBitmap rb = BufferFastAggregation.xor(mappedbitmaps.get(k),
-          mappedbitmaps.get(k + 1), mappedbitmaps.get(k + 3), mappedbitmaps.get(k + 4));
-      final MutableRoaringBitmap rbram = BufferFastAggregation.xor(rambitmaps.get(k),
-          rambitmaps.get(k + 1), rambitmaps.get(k + 3), rambitmaps.get(k + 4));
+      final MutableRoaringBitmap rb =
+          BufferFastAggregation.xor(
+              mappedbitmaps.get(k),
+              mappedbitmaps.get(k + 1),
+              mappedbitmaps.get(k + 3),
+              mappedbitmaps.get(k + 4));
+      final MutableRoaringBitmap rbram =
+          BufferFastAggregation.xor(
+              rambitmaps.get(k),
+              rambitmaps.get(k + 1),
+              rambitmaps.get(k + 3),
+              rambitmaps.get(k + 4));
       assertTrue(rb.equals(rbram));
     }
   }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRange.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRange.java
similarity index 85%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRange.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRange.java
index c5f8c2f9a..054b40060 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRange.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRange.java
@@ -1,14 +1,16 @@
 package org.roaringbitmap.buffer;
 
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import org.roaringbitmap.IntIterator;
 
+import org.junit.jupiter.api.Test;
+
 import java.util.BitSet;
 import java.util.Random;
 
-import static org.junit.jupiter.api.Assertions.*;
-
-
 public class TestRange {
   @Test
   public void flip64() {
@@ -20,22 +22,22 @@ public void flip64() {
     assertEquals(1, i.next());
     assertFalse(i.hasNext());
   }
-  
+
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedMemberFlip() {
     MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
     rb1.flip(300000, 500000);
     MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
     rb2.flip(300000L, 500000L);
     assertEquals(rb1, rb2);
-    rb1.flip(Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-    rb2.flip(Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1.flip(Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2.flip(Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
-  private static int fillWithRandomBits(final MutableRoaringBitmap bitmap, final BitSet bitset,
-      final int bits) {
+  private static int fillWithRandomBits(
+      final MutableRoaringBitmap bitmap, final BitSet bitset, final int bits) {
     int added = 0;
     Random r = new Random(1011);
     for (int j = 0; j < bits; j++) {
@@ -78,7 +80,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.add(start, end);
       rbstatic = MutableRoaringBitmap.add(rbstatic, start, end);
-      bs.set((int)start, (int)end);
+      bs.set((int) start, (int) end);
 
       //
       start = r.nextInt(65536 * 20);
@@ -102,7 +104,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.add(start, end);
       rbstatic = MutableRoaringBitmap.add(rbstatic, start, end);
-      bs.set((int)start, (int)end);
+      bs.set((int) start, (int) end);
 
       //
       start = r.nextInt(65536 * 20);
@@ -114,7 +116,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.add(start, end);
       rbstatic = MutableRoaringBitmap.add(rbstatic, start, end);
-      bs.set((int)start, (int)end);
+      bs.set((int) start, (int) end);
       //
       start = r.nextInt(20) * 65536;
       end = r.nextInt(65536 * 20);
@@ -125,7 +127,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.remove(start, end);
       rbstatic = MutableRoaringBitmap.remove(rbstatic, start, end);
-      bs.clear((int)start, (int)end);
+      bs.clear((int) start, (int) end);
 
       //
       start = r.nextInt(65536 * 20);
@@ -137,7 +139,7 @@ public void rangeAddRemoveBig() {
       }
       rbinplace.remove(start, end);
       rbstatic = MutableRoaringBitmap.remove(rbstatic, start, end);
-      bs.clear((int)start, (int)end);
+      bs.clear((int) start, (int) end);
     }
     assertTrue(TestRoaringBitmap.equals(bs, rbstatic));
     assertTrue(TestRoaringBitmap.equals(bs, rbinplace));
@@ -198,8 +200,6 @@ public void setTest1A() {
     assertTrue(TestRoaringBitmap.equals(bs, rb1));
   }
 
-
-
   @Test
   public void setTest2() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -227,7 +227,6 @@ public void setTest2A() {
     assertTrue(TestRoaringBitmap.equals(bs, rb));
   }
 
-
   @Test
   public void setTest3() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -245,7 +244,6 @@ public void setTest3() {
     assertTrue(TestRoaringBitmap.equals(bs, rb));
   }
 
-
   @Test
   public void setTest3A() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -265,7 +263,6 @@ public void setTest3A() {
     assertTrue(TestRoaringBitmap.equals(bs, rb2));
   }
 
-
   @Test
   public void setTest4() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -440,7 +437,6 @@ public void setTest7A() {
     assertEquals(rb2, rb3);
     assertTrue(TestRoaringBitmap.equals(bs, rb3));
 
-
     rb3 = MutableRoaringBitmap.add(rb3, 65536 * 3 + 195L, 65536 * 3 + 245);
     bs.set(65536 * 3 + 195, 65536 * 3 + 245);
     rb2.add(65536L * 3 + 195, 65536L * 3 + 245);
@@ -453,7 +449,6 @@ public void setTest7A() {
 
     // now removing
 
-
     rb3 = MutableRoaringBitmap.remove(rb3, 65536L * 3 + 195, 65536L * 3 + 245);
     bs.clear(65536 * 3 + 195, 65536 * 3 + 245);
     rb2.remove(65536L * 3 + 195, 65536L * 3 + 245);
@@ -475,14 +470,11 @@ public void setTest7A() {
     assertEquals(rb2, rb3);
     assertTrue(TestRoaringBitmap.equals(bs, rb3));
 
-
     rb2 = MutableRoaringBitmap.remove(rb1, 130L, 185L);
     bs.clear(130, 185);
     rb.remove(130L, 185L);
     assertEquals(rb2, rb);
     assertTrue(TestRoaringBitmap.equals(bs, rb2));
-
-
   }
 
   @Test
@@ -598,7 +590,7 @@ public void testClearRanges() {
   public void testFlipRanges() {
     int N = 256;
     for (long end = 1; end < N; ++end) {
-        for (long start = 0; start < end; ++start) {
+      for (long start = 0; start < end; ++start) {
         MutableRoaringBitmap bs1 = new MutableRoaringBitmap();
         for (int k = (int) start; k < end; ++k) {
           bs1.flip(k);
@@ -690,7 +682,7 @@ private void testRangeRemovalWithRandomBits(boolean withRunCompression) {
       }
 
       // clear and check bitmap, if really empty
-      bitmap.remove(0L, (long)  bits);
+      bitmap.remove(0L, (long) bits);
       assertEquals(0, bitmap.getCardinality(), "fails with bits: " + bitset);
       assertTrue(bitmap.isEmpty());
 
@@ -719,7 +711,7 @@ public void testSetRanges() {
     for (long end = 1; end < N; ++end) {
       for (long start = 0; start < end; ++start) {
         MutableRoaringBitmap bs1 = new MutableRoaringBitmap();
-        for (int k = (int)start; k < end; ++k) {
+        for (int k = (int) start; k < end; ++k) {
           bs1.add(k);
         }
         MutableRoaringBitmap bs2 = new MutableRoaringBitmap();
@@ -747,7 +739,6 @@ public void testStaticClearRanges() {
     }
   }
 
-
   @Test
   public void testStaticSetRanges() {
     int N = 256;
@@ -765,91 +756,88 @@ public void testStaticSetRanges() {
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedStaticAdd() {
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      MutableRoaringBitmap.add(rb1, 300000, 500000);
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-      MutableRoaringBitmap.add(rb2,300000L, 500000L);
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap.add(rb1, 300000, 500000);
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    MutableRoaringBitmap.add(rb2, 300000L, 500000L);
     assertEquals(rb1, rb2);
-      MutableRoaringBitmap.add( rb1, Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      MutableRoaringBitmap.add( rb2, Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    MutableRoaringBitmap.add(rb1, Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    MutableRoaringBitmap.add(rb2, Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedStaticFlip() {
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      MutableRoaringBitmap.flip(rb1, 300000, 500000);
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-      MutableRoaringBitmap.flip(rb2,300000L, 500000L);
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap.flip(rb1, 300000, 500000);
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    MutableRoaringBitmap.flip(rb2, 300000L, 500000L);
     assertEquals(rb1, rb2);
-      MutableRoaringBitmap.flip( rb1, Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      MutableRoaringBitmap.flip( rb2, Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    MutableRoaringBitmap.flip(rb1, Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    MutableRoaringBitmap.flip(rb2, Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedStaticRemove() {
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      MutableRoaringBitmap.add(rb1,200000L, 400000L);
-      MutableRoaringBitmap.remove(rb1, 300000, 500000);
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-      MutableRoaringBitmap.add(rb2,200000L, 400000L);
-      MutableRoaringBitmap.remove(rb2,300000L, 500000L);
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    MutableRoaringBitmap.add(rb1, 200000L, 400000L);
+    MutableRoaringBitmap.remove(rb1, 300000, 500000);
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    MutableRoaringBitmap.add(rb2, 200000L, 400000L);
+    MutableRoaringBitmap.remove(rb2, 300000L, 500000L);
     assertEquals(rb1, rb2);
 
-      MutableRoaringBitmap.add( rb1, Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      MutableRoaringBitmap.add( rb2, Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      MutableRoaringBitmap.remove( rb1, Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      MutableRoaringBitmap.remove( rb2, Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    MutableRoaringBitmap.add(rb1, Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    MutableRoaringBitmap.add(rb2, Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    MutableRoaringBitmap.remove(rb1, Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    MutableRoaringBitmap.remove(rb2, Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedAdd() {
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      rb1.add(300000, 500000);
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-      rb2.add(300000L, 500000L);
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    rb1.add(300000, 500000);
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    rb2.add(300000L, 500000L);
     assertEquals(rb1, rb2);
-      rb1.add( Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      rb2.add( Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1.add(Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2.add(Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
-
   @Test
-  @SuppressWarnings( "deprecation" )
+  @SuppressWarnings("deprecation")
   public void testDeprecatedRemove() {
-      MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-      rb1.add(200000L, 400000L);
-      rb1.remove(300000, 500000);
-      MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-      rb2.add(200000L, 400000L);
-      rb2.remove(300000L, 500000L);
+    MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
+    rb1.add(200000L, 400000L);
+    rb1.remove(300000, 500000);
+    MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
+    rb2.add(200000L, 400000L);
+    rb2.remove(300000L, 500000L);
     assertEquals(rb1, rb2);
 
-      rb1.add(Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      rb2.add(Integer.MAX_VALUE+200000L, Integer.MAX_VALUE+400000L);
-      rb1.remove(Integer.MAX_VALUE+300000, Integer.MAX_VALUE+500000);
-      rb2.remove(Integer.MAX_VALUE+300000L, Integer.MAX_VALUE+500000L);
+    rb1.add(Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    rb2.add(Integer.MAX_VALUE + 200000L, Integer.MAX_VALUE + 400000L);
+    rb1.remove(Integer.MAX_VALUE + 300000, Integer.MAX_VALUE + 500000);
+    rb2.remove(Integer.MAX_VALUE + 300000L, Integer.MAX_VALUE + 500000L);
     assertEquals(rb1, rb2);
   }
 
   @Test
   public void regressionTestIssue588() {
     // see https://github.com/RoaringBitmap/RoaringBitmap/issues/588
-     int valueInBitmap = 27470832;
-     int baseValue = 27597418;
-     int minValueThatWorks = 27459584;
-     ImmutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(valueInBitmap);
-     assertTrue(bitmap.intersects(minValueThatWorks, baseValue));
-     assertTrue(bitmap.intersects(minValueThatWorks-1, baseValue));
+    int valueInBitmap = 27470832;
+    int baseValue = 27597418;
+    int minValueThatWorks = 27459584;
+    ImmutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOf(valueInBitmap);
+    assertTrue(bitmap.intersects(minValueThatWorks, baseValue));
+    assertTrue(bitmap.intersects(minValueThatWorks - 1, baseValue));
   }
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestReverseMappeableRunContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestReverseMappeableRunContainer.java
new file mode 100644
index 000000000..33bc432f3
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestReverseMappeableRunContainer.java
@@ -0,0 +1,67 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.roaringbitmap.CharIterator;
+
+import com.google.common.primitives.Ints;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestReverseMappeableRunContainer {
+
+  private static List asList(CharIterator ints) {
+    int[] values = new int[10];
+    int size = 0;
+    while (ints.hasNext()) {
+      if (!(size < values.length)) {
+        values = Arrays.copyOf(values, values.length * 2);
+      }
+      values[size++] = ints.next();
+    }
+    return Ints.asList(Arrays.copyOf(values, size));
+  }
+
+  @Test
+  public void testClone() {
+    MappeableRunContainer mappeableRunContainer = new MappeableRunContainer();
+    for (char i = 10; i < 20; ++i) {
+      mappeableRunContainer.add(i);
+    }
+    ReverseMappeableRunContainerCharIterator rmr =
+        new ReverseMappeableRunContainerCharIterator(mappeableRunContainer);
+    CharIterator rmrClone = rmr.clone();
+    final List rmrList = asList(rmr);
+    assertNotNull(rmrClone);
+    final List rmrCloneList = asList(rmrClone);
+    assertEquals(rmrList, rmrCloneList);
+  }
+
+  @Test
+  public void testNextAsInt() {
+    MappeableRunContainer mappeableRunContainer = new MappeableRunContainer();
+    for (char i = 10; i < 15; ++i) {
+      mappeableRunContainer.add(i);
+    }
+    ReverseMappeableRunContainerCharIterator rmr =
+        new ReverseMappeableRunContainerCharIterator(mappeableRunContainer);
+    assertEquals(14, rmr.nextAsInt());
+    rmr.next();
+    rmr.next();
+    rmr.next();
+    rmr.next();
+    rmr.next();
+    rmr.nextAsInt();
+    rmr.nextAsInt();
+    rmr.nextAsInt();
+    rmr.nextAsInt();
+    rmr.nextAsInt();
+    assertEquals(13, rmr.nextAsInt());
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRoaringBitmap.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRoaringBitmap.java
similarity index 60%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRoaringBitmap.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRoaringBitmap.java
index 687236f2c..547d89144 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRoaringBitmap.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRoaringBitmap.java
@@ -4,21 +4,39 @@
 
 package org.roaringbitmap.buffer;
 
-
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.roaringbitmap.IntConsumer;
+import org.roaringbitmap.IntIterator;
+import org.roaringbitmap.PeekableIntIterator;
+import org.roaringbitmap.RoaringBitmap;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
-import org.roaringbitmap.*;
 
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Vector;
 
 /**
  * Generic testing of the roaring bitmaps
@@ -28,51 +46,49 @@
 public class TestRoaringBitmap {
   @Test
   public void testRangeCardinality() {
-		MutableRoaringBitmap r = new MutableRoaringBitmap();
-		  long Min = 0L;
-		  long Max = 1000000L;
-		  r.add(Min, Max);
-		  for(long s = Min; s <= Max ; s+= 100 ) {
-			  for(long e = s; e <= Max; e+= 100 ) {
-				 assertEquals(e - s, r.rangeCardinality(s, e));
-			  }
-		  }
-  }
-  
+    MutableRoaringBitmap r = new MutableRoaringBitmap();
+    long Min = 0L;
+    long Max = 1000000L;
+    r.add(Min, Max);
+    for (long s = Min; s <= Max; s += 100) {
+      for (long e = s; e <= Max; e += 100) {
+        assertEquals(e - s, r.rangeCardinality(s, e));
+      }
+    }
+  }
+
   @Test
   public void testRangeCardinality2() {
-		MutableRoaringBitmap r = new MutableRoaringBitmap();
-		  long Min = 1L << 16;
-		  long Max = 1L << 18;
-		  r.add(Min, Max);
-		  for(long s = Min; s <= Max ; s+= 1024 ) {
-			  for(long e = s; e <= Max; e+= 1024 ) {
-				 assertEquals(e - s, r.rangeCardinality(s, e));
-			  }
-		  }
-  }	
-  
+    MutableRoaringBitmap r = new MutableRoaringBitmap();
+    long Min = 1L << 16;
+    long Max = 1L << 18;
+    r.add(Min, Max);
+    for (long s = Min; s <= Max; s += 1024) {
+      for (long e = s; e <= Max; e += 1024) {
+        assertEquals(e - s, r.rangeCardinality(s, e));
+      }
+    }
+  }
+
   @Test
   public void testMultipleAdd() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     bitmap.add(1);
     bitmap.add(1, 2, 3);
     bitmap.add(0xFFFFFFFF);
-    bitmap.add(0xFFFFFFFEL,0xFFFFFFFFL);
-    assertEquals("{1,2,3,4294967294,4294967295}",bitmap.toString());
+    bitmap.add(0xFFFFFFFEL, 0xFFFFFFFFL);
+    assertEquals("{1,2,3,4294967294,4294967295}", bitmap.toString());
   }
-    
-  @Test 
+
+  @Test
   public void binaryTest() throws IOException {
     Random rand = new Random(1234);
     rand.setSeed(11111);
-    for(int z = 0; z < 1000; ++z) {
+    for (int z = 0; z < 1000; ++z) {
       final MutableRoaringBitmap rr1 = new MutableRoaringBitmap();
-      for(int k = 0; k < 100; k++)
-        rr1.add((rand.nextInt() & 0xFFFF) << 16);
+      for (int k = 0; k < 100; k++) rr1.add((rand.nextInt() & 0xFFFF) << 16);
       final MutableRoaringBitmap rr2 = new MutableRoaringBitmap();
-      for(int k = 0; k < 100; k++)
-        rr2.add((rand.nextInt() & 0xFFFF) << 16);
+      for (int k = 0; k < 100; k++) rr2.add((rand.nextInt() & 0xFFFF) << 16);
       ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
       DataOutputStream dos1 = new DataOutputStream(bos1);
       rr1.serialize(dos1);
@@ -85,197 +101,199 @@ public void binaryTest() throws IOException {
       dos2.close();
       ByteBuffer bb2 = ByteBuffer.wrap(bos2.toByteArray());
       final ImmutableRoaringBitmap rrback2 = new ImmutableRoaringBitmap(bb2);
-      assertEquals(ImmutableRoaringBitmap.and(rrback1, rrback2),
-          MutableRoaringBitmap.and(rr1, rr2));
-      assertEquals(ImmutableRoaringBitmap.and(rrback2, rrback1),
-          MutableRoaringBitmap.and(rr2, rr1));
-      assertEquals(ImmutableRoaringBitmap.andNot(rrback1, rrback2),
-          MutableRoaringBitmap.andNot(rr1, rr2));
-      assertEquals(ImmutableRoaringBitmap.andNot(rrback2, rrback1),
-          MutableRoaringBitmap.andNot(rr2, rr1));
-      assertEquals(ImmutableRoaringBitmap.xor(rrback1, rrback2),
-          MutableRoaringBitmap.xor(rr1, rr2));
-      assertEquals(ImmutableRoaringBitmap.xor(rrback2, rrback1),
-          MutableRoaringBitmap.xor(rr2, rr1));
-      assertEquals(ImmutableRoaringBitmap.or(rrback1, rrback2),
-          MutableRoaringBitmap.or(rr1, rr2));
-      assertEquals(ImmutableRoaringBitmap.or(rrback2, rrback1),
-          MutableRoaringBitmap.or(rr2, rr1));      
-    }
-  }
-
-	@Test
-	public void testStringer() {
-	    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
-	    bitmap.add(1);
-	    bitmap.add(2);
-	    bitmap.add(3);
-	    bitmap.add(0xFFFFFFFF);
-	    assertEquals("{1,2,3,4294967295}",bitmap.toString());
-	}
-	
-	@Test
-	public  void report128() {
-	    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
-        bitmap.add(59798854);
-        bitmap.add(91274955);
-        bitmap.add(97569495);
-        bitmap.add(101993170);
-        PeekableIntIterator it = bitmap.getIntIterator();
-        it.advanceIfNeeded(100620278);
-        assertTrue(it.hasNext());
-        assertEquals(101993170, it.next());
-        assertFalse(it.hasNext());
-	}
-	
-	@Test
-	public  void report128_fly() {
-	    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
-        bitmap.add(59798854);
-        bitmap.add(91274955);
-        bitmap.add(97569495);
-        bitmap.add(101993170);
-        BufferIntIteratorFlyweight it = new BufferIntIteratorFlyweight();
-        it.wrap(bitmap);
-        it.advanceIfNeeded(100620278);
-        assertTrue(it.hasNext());
-        assertEquals(101993170, it.next());
-        assertFalse(it.hasNext());
-	}
-	@Test
-	public  void limitBug2() {
-		class MyConsumer implements IntConsumer {
-			public int count = 0;
-			@Override public void accept(int value) { count++; }
-		}
-
-		MutableRoaringBitmap r = new MutableRoaringBitmap();
-		int count = 0;
-		for (int i = 0; i < 500; i++) {
-			for (int j = 0; j < 9943; j++) {
-				if (i % 2 == 0) r.add(count); count++;
-			}
-		}
-		MutableRoaringBitmap limited = r.limit(1000000);
-		assertEquals(1000000,limited.getCardinality());
-		MyConsumer c = new MyConsumer();
-		limited.forEach(c);
-		assertEquals(1000000,c.count);
-		assertEquals(1000000,limited.toArray().length);
-
-	}
-  
+      assertEquals(
+          ImmutableRoaringBitmap.and(rrback1, rrback2), MutableRoaringBitmap.and(rr1, rr2));
+      assertEquals(
+          ImmutableRoaringBitmap.and(rrback2, rrback1), MutableRoaringBitmap.and(rr2, rr1));
+      assertEquals(
+          ImmutableRoaringBitmap.andNot(rrback1, rrback2), MutableRoaringBitmap.andNot(rr1, rr2));
+      assertEquals(
+          ImmutableRoaringBitmap.andNot(rrback2, rrback1), MutableRoaringBitmap.andNot(rr2, rr1));
+      assertEquals(
+          ImmutableRoaringBitmap.xor(rrback1, rrback2), MutableRoaringBitmap.xor(rr1, rr2));
+      assertEquals(
+          ImmutableRoaringBitmap.xor(rrback2, rrback1), MutableRoaringBitmap.xor(rr2, rr1));
+      assertEquals(ImmutableRoaringBitmap.or(rrback1, rrback2), MutableRoaringBitmap.or(rr1, rr2));
+      assertEquals(ImmutableRoaringBitmap.or(rrback2, rrback1), MutableRoaringBitmap.or(rr2, rr1));
+    }
+  }
+
+  @Test
+  public void testStringer() {
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    bitmap.add(1);
+    bitmap.add(2);
+    bitmap.add(3);
+    bitmap.add(0xFFFFFFFF);
+    assertEquals("{1,2,3,4294967295}", bitmap.toString());
+  }
+
+  @Test
+  public void report128() {
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    bitmap.add(59798854);
+    bitmap.add(91274955);
+    bitmap.add(97569495);
+    bitmap.add(101993170);
+    PeekableIntIterator it = bitmap.getIntIterator();
+    it.advanceIfNeeded(100620278);
+    assertTrue(it.hasNext());
+    assertEquals(101993170, it.next());
+    assertFalse(it.hasNext());
+  }
+
+  @Test
+  public void report128_fly() {
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    bitmap.add(59798854);
+    bitmap.add(91274955);
+    bitmap.add(97569495);
+    bitmap.add(101993170);
+    BufferIntIteratorFlyweight it = new BufferIntIteratorFlyweight();
+    it.wrap(bitmap);
+    it.advanceIfNeeded(100620278);
+    assertTrue(it.hasNext());
+    assertEquals(101993170, it.next());
+    assertFalse(it.hasNext());
+  }
+
+  @Test
+  public void limitBug2() {
+    class MyConsumer implements IntConsumer {
+      public int count = 0;
+
+      @Override
+      public void accept(int value) {
+        count++;
+      }
+    }
+
+    MutableRoaringBitmap r = new MutableRoaringBitmap();
+    int count = 0;
+    for (int i = 0; i < 500; i++) {
+      for (int j = 0; j < 9943; j++) {
+        if (i % 2 == 0) r.add(count);
+        count++;
+      }
+    }
+    MutableRoaringBitmap limited = r.limit(1000000);
+    assertEquals(1000000, limited.getCardinality());
+    MyConsumer c = new MyConsumer();
+    limited.forEach(c);
+    assertEquals(1000000, c.count);
+    assertEquals(1000000, limited.toArray().length);
+  }
+
   @Test
   public void limitTest() {
     MutableRoaringBitmap r = new MutableRoaringBitmap();
     r.add(0l, 10000000l);
-    assertEquals(1,r.limit(1).getCardinality());
-    assertEquals(10,r.limit(10).getCardinality());
-    assertEquals(100,r.limit(100).getCardinality());
-    assertEquals(1000,r.limit(1000).getCardinality());
-    assertEquals(10000,r.limit(10000).getCardinality());
-    assertEquals(100000,r.limit(100000).getCardinality());
-    assertEquals(1000000,r.limit(1000000).getCardinality());
+    assertEquals(1, r.limit(1).getCardinality());
+    assertEquals(10, r.limit(10).getCardinality());
+    assertEquals(100, r.limit(100).getCardinality());
+    assertEquals(1000, r.limit(1000).getCardinality());
+    assertEquals(10000, r.limit(10000).getCardinality());
+    assertEquals(100000, r.limit(100000).getCardinality());
+    assertEquals(1000000, r.limit(1000000).getCardinality());
   }
-  
+
   @Test
   public void pointerContainerTest() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
-    for (int i = 0; i < (1 << 16); i+=2) {
+    for (int i = 0; i < (1 << 16); i += 2) {
       rb.add(i);
     }
-    for (int i = (1 << 16); i < 2*((1 << 16)); i+= 512) {
+    for (int i = (1 << 16); i < 2 * ((1 << 16)); i += 512) {
       rb.add(i);
     }
-    for (int i = 2*(1 << 16); i < 3*((1 << 16)); i++) {
+    for (int i = 2 * (1 << 16); i < 3 * ((1 << 16)); i++) {
       rb.add(i);
-    }    
+    }
     rb.runOptimize();
     MappeableContainerPointer cp = rb.getContainerPointer();
-    MappeableContainerPointer cpo =  (MappeableContainerPointer) cp.clone();
+    MappeableContainerPointer cpo = (MappeableContainerPointer) cp.clone();
     assertNotEquals(cp.getContainer(), null);
     assertNotEquals(cpo.getContainer(), null);
 
-    assertEquals(cp.compareTo(cpo),0);
-    
-    assertEquals(cp.getCardinality(), (1<<16)/2);
+    assertEquals(cp.compareTo(cpo), 0);
+
+    assertEquals(cp.getCardinality(), (1 << 16) / 2);
     assertTrue(cp.isBitmapContainer());
     assertFalse(cp.isRunContainer());
 
     cp.advance();
-    assertTrue(cp.compareTo(cpo)>0);
+    assertTrue(cp.compareTo(cpo) > 0);
     assertNotEquals(cp.getContainer(), null);
-    assertEquals(cp.getCardinality(), (1<<16)/512);
+    assertEquals(cp.getCardinality(), (1 << 16) / 512);
     assertFalse(cp.isBitmapContainer());
     assertFalse(cp.isRunContainer());
 
     cp.advance();
-    assertTrue(cp.compareTo(cpo)>0);
+    assertTrue(cp.compareTo(cpo) > 0);
     assertNotEquals(cp.getContainer(), null);
-    assertEquals(cp.getCardinality(), (1<<16));
+    assertEquals(cp.getCardinality(), (1 << 16));
     assertFalse(cp.isBitmapContainer());
     assertTrue(cp.isRunContainer());
 
     cpo.advance();
-    assertTrue(cp.compareTo(cpo)>0);
+    assertTrue(cp.compareTo(cpo) > 0);
     cpo.advance();
-    assertTrue(cp.compareTo(cpo)==0);
+    assertTrue(cp.compareTo(cpo) == 0);
 
     cp.advance();
 
     assertEquals(cp.getContainer(), null);
-    
   }
+
   @Test
   public void pointerImmutableContainerTest() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
-    for (int i = 0; i < (1 << 16); i+=2) {
+    for (int i = 0; i < (1 << 16); i += 2) {
       rb.add(i);
     }
-    for (int i = (1 << 16); i < 2*((1 << 16)); i+= 512) {
+    for (int i = (1 << 16); i < 2 * ((1 << 16)); i += 512) {
       rb.add(i);
     }
-    for (int i = 2*(1 << 16); i < 3*((1 << 16)); i++) {
+    for (int i = 2 * (1 << 16); i < 3 * ((1 << 16)); i++) {
       rb.add(i);
-    }    
+    }
     rb.runOptimize();
-    ImmutableRoaringBitmap irb =toMapped(rb);
+    ImmutableRoaringBitmap irb = toMapped(rb);
     MappeableContainerPointer cp = irb.getContainerPointer();
-    MappeableContainerPointer cpo =  (MappeableContainerPointer) cp.clone();
+    MappeableContainerPointer cpo = (MappeableContainerPointer) cp.clone();
     assertNotEquals(cp.getContainer(), null);
     assertNotEquals(cpo.getContainer(), null);
 
-    assertEquals(cp.compareTo(cpo),0);
-    
-    assertEquals(cp.getCardinality(), (1<<16)/2);
+    assertEquals(cp.compareTo(cpo), 0);
+
+    assertEquals(cp.getCardinality(), (1 << 16) / 2);
     assertTrue(cp.isBitmapContainer());
     assertFalse(cp.isRunContainer());
 
     cp.advance();
-    assertTrue(cp.compareTo(cpo)>0);
+    assertTrue(cp.compareTo(cpo) > 0);
     assertNotEquals(cp.getContainer(), null);
-    assertEquals(cp.getCardinality(), (1<<16)/512);
+    assertEquals(cp.getCardinality(), (1 << 16) / 512);
     assertFalse(cp.isBitmapContainer());
     assertFalse(cp.isRunContainer());
 
     cp.advance();
-    assertTrue(cp.compareTo(cpo)>0);
+    assertTrue(cp.compareTo(cpo) > 0);
     assertNotEquals(cp.getContainer(), null);
-    assertEquals(cp.getCardinality(), (1<<16));
+    assertEquals(cp.getCardinality(), (1 << 16));
     assertFalse(cp.isBitmapContainer());
     assertTrue(cp.isRunContainer());
 
     cpo.advance();
-    assertTrue(cp.compareTo(cpo)>0);
+    assertTrue(cp.compareTo(cpo) > 0);
     cpo.advance();
-    assertTrue(cp.compareTo(cpo)==0);
+    assertTrue(cp.compareTo(cpo) == 0);
 
     cp.advance();
 
     assertEquals(cp.getContainer(), null);
-    
   }
-  
+
   private static ImmutableRoaringBitmap toMapped(MutableRoaringBitmap r) {
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
     DataOutputStream dos = new DataOutputStream(bos);
@@ -289,7 +307,6 @@ private static ImmutableRoaringBitmap toMapped(MutableRoaringBitmap r) {
     return new ImmutableRoaringBitmap(bb);
   }
 
-
   @Test
   public void conversionTest() {
     RoaringBitmap rb = new RoaringBitmap();
@@ -308,25 +325,21 @@ public void conversionTest() {
     assertEquals(rb, rb2);
     ImmutableRoaringBitmap irb = toMapped(mrb);
     assertEquals(irb.toRoaringBitmap(), rb2);
-    
   }
 
-   @Test
+  @Test
   public void testFlipBigInts() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
     for (int i = 0; i < 1 << 20; ++i) {
-        rb.flip((1<<31)+i);
+      rb.flip((1 << 31) + i);
       assertEquals(rb.getCardinality(), i + 1);
     }
     for (int i = (1 << 20) - 1; i >= 0; --i) {
-        rb.flip((1<<31)+i);
+      rb.flip((1 << 31) + i);
       assertEquals(rb.getCardinality(), i);
     }
   }
 
-
-
-
   @Test
   public void testFlipOnEmpty() {
     MutableRoaringBitmap r1 = new MutableRoaringBitmap();
@@ -389,464 +402,468 @@ public void testAstesana() {
 
   @Test
   public void testOr001() {
-    int[] array1 = {22871, 22873, 22876, 22880, 22886, 22889, 22893, 22897, 22901, 22905, 22910,
-        22915, 22919, 22927, 22934, 22940, 24750, 38579, 48470, 50533, 53256, 53717, 53752, 53802,
-        53938, 54727, 54865, 55202, 55815, 55822, 55940, 56711, 56977, 57122, 59933, 60037, 60402,
-        60520, 60853, 61163, 61340, 61549, 61632, 62097, 62373, 62961, 62993, 63031, 63075, 64209,
-        64644, 64762, 64893, 64927, 64997, 65117, 65128, 65173, 65201, 65472, 65536, 65622, 66092,
-        66162, 66302, 66381, 66551, 103979, 104644, 106866, 117285, 123372, 127548, 132167, 132168,
-        136283, 136433, 137661, 138019, 138239, 138380, 138816, 138916, 138933, 139414, 140342,
-        140914, 142751, 142994, 143895, 145081, 147331, 147686, 148021, 148375, 148587, 149114,
-        149734, 152696, 153608, 154741, 154932, 155263, 157121, 158947, 159444, 161102, 161383,
-        162735, 164298, 168043, 169398, 169536, 170419, 170846, 171153, 177016, 177471, 178305,
-        178673, 183731, 183936, 184083, 184106, 185663, 188371, 189495, 189531, 196189, 198419,
-        198758, 198796, 200645, 201137, 216865, 216936, 217770, 217810, 217836, 217909, 218569,
-        218700, 218931, 219363, 220009, 225925, 234706, 241183, 241561, 242140, 242281, 245018,
-        245056, 249935, 250442, 250615, 251696, 252825, 254178, 256788, 256906, 257289, 258833,
-        260432, 260563, 260930, 262684, 262834, 263128, 265919, 268662, 269542, 270217, 271673,
-        273776, 274560, 275649, 305458, 306241, 306550, 307580, 310891, 312701, 313514, 318134,
-        319185, 320757, 321280, 322046, 322743, 323211, 324667, 325382, 326450, 327159, 328836,
-        329075, 331179, 332836, 332997, 333071, 333205, 333488, 333595, 335045, 335803, 336417,
-        336610, 338487, 339827, 339992, 346123, 348858, 351257, 351957, 353896, 354559, 357142,
-        358253, 366662, 378768, 391984, 392282, 415077, 429446, 429449, 429452, 429453, 429476,
-        429480, 429486, 429492, 429497, 429501, 429504, 429505, 429510, 429515, 429519, 429524,
-        429530, 429533, 429541, 429546, 429553, 429554, 429564, 429572, 429577, 429579, 429586,
-        429589, 429596, 429604, 429606, 429612, 429615, 429616, 429624, 429632, 429639, 429642,
-        429646, 429651, 429656, 429664, 429670, 429674, 429678, 429681, 429686, 429695, 429701,
-        429706, 429717, 429721, 429725, 429733, 429736, 429739, 429743, 429748, 429754, 429761,
-        429767, 429772, 429780, 429791, 429792, 429793, 429794, 429795, 429817, 429822, 429823,
-        429831, 429836, 429842, 429849, 429855, 429859, 429863, 429866, 429873, 429876, 429882,
-        429885, 429900, 429903, 429913, 429921, 429923, 429927, 429932, 429939, 429947, 429950,
-        429955, 429964, 429968, 429974, 429982, 429987, 429993, 429999, 430003, 430011, 430015,
-        430023, 430028, 430033, 430039, 430044, 430048, 430053, 430057, 430059, 430063, 430068,
-        430073, 430077, 430082, 430086, 430093, 430098, 430101, 430114, 430120, 430126, 430131,
-        430135, 430139, 430144, 430149, 430155, 430157, 430167, 430175, 430181, 430186, 430194,
-        430195, 430196, 430214, 430223, 430228, 430236, 430253, 430258, 430263, 430269, 430277,
-        430284, 430288, 430293, 430297, 430303, 430309, 430316, 430321, 430332, 430338, 430343,
-        430346, 430348, 430355, 430358, 430369, 430375, 430384, 430391, 430397, 430410, 430415,
-        430420, 430424, 430430, 430435, 430437, 430445, 430449, 430461, 430467, 430473, 430482,
-        430486, 430490, 430496, 430500, 430506, 430511, 430515, 430535, 430539, 430550, 430568,
-        430575, 430581, 430588, 430591, 430596, 430605, 430612, 430617, 430625, 430629, 430633,
-        430638, 430643, 430649, 430656, 430663, 430666, 430672, 430679, 430684, 430692, 430696,
-        430700, 430707, 430716, 430723, 430728, 430733, 430745, 430751, 430755, 430759, 430767,
-        430770, 430782, 430787, 430791, 430804, 430810, 430814, 430821, 430825, 430829, 430833,
-        430838, 430844, 430849, 430852, 430859, 430864, 430867, 430870, 430877, 430881, 430887,
-        430891, 430896, 430901, 430907, 430912, 430917, 430923, 430927, 430932, 430936, 430944,
-        430947, 430953, 430959, 430967, 430971, 430979, 430985, 430989, 430993, 430997, 431003,
-        431006, 431015, 431021, 431022, 431033, 431039, 431046, 431050, 431054, 431059, 431065,
-        431069, 431074, 431081, 431085, 431092, 431097, 431104, 431110, 431120, 431125, 431133,
-        431138, 431142, 431147, 431157, 431164, 431171, 431175, 431180, 431186, 431190, 431195,
-        431207, 431213, 431218, 431220, 431224, 431228, 431233, 431235, 431240, 431245, 431251,
-        431259, 431264, 431271, 431272, 431280, 431287, 431294, 431299, 431307, 431315, 431319,
-        431324, 431330, 431334, 431339, 431345, 431352, 431356, 431363, 431375, 431379, 431383,
-        431388, 431393, 431398, 431405, 431409, 431416, 431422, 431426, 431433, 431438, 431444,
-        431451, 431455, 431464, 431469, 431472, 431477, 431483, 431490, 431496, 431506, 431513,
-        431516, 431521, 431526, 431534, 431536, 431545, 431550, 431559, 431564, 431571, 431573,
-        431579, 431584, 431587, 431592, 431604, 431614, 431624, 431629, 431634, 431638, 431645,
-        431651, 431659, 431663, 431674, 431678, 431684, 431692, 431696, 431700, 431706, 431712,
-        431719, 431723, 431729, 431736, 431741, 431747, 431755, 431758, 431762, 431767, 431777,
-        431782, 431787, 431791, 431796, 431799, 431805, 431809, 431814, 431819, 431823, 431828,
-        431832, 431838, 431842, 431849, 431853, 431858, 431862, 431866, 431869, 431874, 431881,
-        431887, 431894, 431900, 431906, 431912, 431917, 431925, 431931, 431936, 431943, 431948,
-        431956, 431958, 431964, 431971, 431976, 431981, 431988, 431994, 431998, 432008, 432012,
-        432024, 432029, 432033, 432038, 432045, 432048, 432058, 432062, 432066, 432070, 432076,
-        432077, 432087, 432093, 432098, 432104, 432114, 432123, 432128, 432133, 432139, 432145,
-        432151, 432161, 432168, 432177, 432181, 432188, 432189, 432203, 432209, 432216, 432222,
-        432227, 432232, 432242, 432247, 432256, 432259, 432264, 432269, 432271, 432277, 432286,
-        432294, 432297, 432302, 432308, 432313, 432319, 432326, 432331, 432337, 432345, 432349,
-        432353, 432356, 432361, 432366, 432370, 432378, 432384, 432390, 432391, 432397, 432400,
-        432403, 432408, 432413, 432419, 432422, 432427, 432433, 432440, 432443, 432450, 432455,
-        432460, 432466, 432467, 432481, 432489, 432493, 432498, 432504, 432511, 432513, 432517,
-        432525, 432531, 432537, 432544, 432546, 432555, 432561, 432565, 432569, 432574, 432579,
-        432586, 432590, 432597, 432605, 432611, 432619, 432626, 432630, 432637, 432644, 432646,
-        432653, 432654, 432664, 432670, 432674, 432679, 432682, 432687, 432694, 432706, 432711,
-        432714, 432721, 432726, 432732, 432741, 432747, 432753, 432755, 432761, 432764, 432768,
-        432774, 432779, 432784, 432792, 432798, 432801, 432808, 432815, 432823, 432825, 432833,
-        432838, 432842, 432847, 432853, 432861, 432866, 432873, 432879, 432889, 432895, 432901,
-        432906, 432913, 432917, 432920, 432926, 432935, 432940, 432949, 432953, 432958, 432960,
-        432966, 432967, 432968, 432969, 432970, 432971, 432972, 432996, 432999, 433004, 433010,
-        433020, 433026, 433029, 433033, 433042, 433045, 433050, 433054, 433058, 433062, 433065,
-        433070, 433076, 433086, 433095, 433101, 433102, 433116, 433122, 433129, 433132, 433140,
-        433146, 433151, 433157, 433163, 433169, 433176, 433181, 433188, 433198, 433204, 433219,
-        433229, 433236, 433240, 433246, 433250, 433259, 433263, 433274, 433277, 433282, 433286,
-        433291, 433295, 433299, 433306, 433316, 433318, 433322, 433327, 433335, 433342, 433348,
-        433351, 433359, 433362, 433367, 433371, 433377, 433384, 433393, 433398, 433403, 433407,
-        433411, 433425, 433430, 433437, 433441, 433445, 433452, 433453, 433458, 433462, 433469,
-        433473, 433478, 433484, 433490, 433495, 433501, 433506, 433514, 433517, 433521, 433527,
-        433534, 433544, 433549, 433552, 433561, 433565, 433569, 433576, 433585, 433589, 433594,
-        433597, 433600, 433603, 433606, 433613, 433619, 433623, 433627, 433639, 433643, 433648,
-        433654, 433658, 433665, 433673, 433678, 433681, 433689, 433696, 433704, 433709, 433716,
-        433721, 433725, 433729, 433734, 433738, 433744, 433749, 433755, 433760, 433766, 433771,
-        433776, 433781, 433785, 433790, 433798, 433803, 433810, 433814, 433817, 433822, 433828,
-        433833, 433837, 433843, 433849, 433852, 433858, 433863, 433871, 433875, 433881, 433883,
-        433884, 433897, 433903, 433909, 433913, 433921, 433926, 433932, 433936, 433942, 433946,
-        433951, 433959, 433965, 433976, 433981, 433989, 433996, 434004, 434011, 434013, 434019,
-        434023, 434029, 434036, 434041, 434048, 434050, 434056, 434060, 434068, 434074, 434079,
-        434085, 434091, 434096, 434100, 434105, 434110, 434119, 434123, 434129, 434133, 434139,
-        434146, 434150, 434156, 434161, 434168, 434173, 434183, 434188, 434193, 434200, 434208,
-        434213, 434219, 434223, 434229, 434235, 434241, 434247, 434258, 434262, 434269, 434275,
-        434282, 434287, 434291, 434296, 434303, 434308, 434313, 434316, 434323, 434327, 434335,
-        434342, 434349, 434353, 434360, 434366, 434372, 434373, 434381, 434387, 434392, 434397,
-        434401, 434403, 434409, 434414, 434420, 434427, 434433, 434440, 434445, 434449, 434454,
-        434460, 434467, 434473, 434479, 434481, 434490, 434494, 434501, 434505, 434510, 434517,
-        434526, 434537, 434542, 434548, 434553, 434558, 434563, 434569, 434574, 434580, 434586,
-        434588, 434595, 434603, 434606, 434617, 434620, 434626, 434630, 434638, 434644, 434647,
-        434651, 434658, 434666, 434671, 434679, 434681, 434685, 434692, 434699, 434703, 434708,
-        434713, 434720, 434723, 434729, 434734, 434738, 434742, 434746, 434753, 434762, 434766,
-        434773, 434781, 434790, 434799, 434805, 434810, 434814, 434823, 434831, 434839, 434845,
-        434850, 434856, 434859, 434863, 434869, 434870, 434882, 434890, 434896, 434899, 434906,
-        434912, 434917, 434921, 434930, 434935, 434940, 434945, 434949, 434956, 434961, 434967,
-        434977, 434982, 434987, 434992, 434995, 435002, 435005, 435009, 435016, 435021, 435025,
-        435028, 435034, 435041, 435050, 435055, 435065, 435069, 435075, 435078, 435083, 435091,
-        435097, 435102, 435105, 435107, 435113, 435118, 435124, 435131, 435141, 435144, 435150,
-        435154, 435159, 435167, 435171, 435177, 435181, 435187, 435192, 435198, 435204, 435211,
-        435212, 435221, 435228, 435231, 435237, 435244, 435246, 435254, 435258, 435264, 435275,
-        435283, 435289, 435301, 435304, 435312, 435318, 435323, 435329, 435334, 435340, 435343,
-        435347, 435351, 435358, 435363, 435368, 435375, 435382, 435388, 435391, 435396, 435399,
-        435405, 435412, 435416, 435422, 435425, 435429, 435437, 435444, 435447, 435453, 435458,
-        435470, 435477, 435486, 435491, 435497, 435500, 435511, 435516, 435520, 435526, 435533,
-        435539, 435545, 435551, 435559, 435564, 435569, 435575, 435579, 435585, 435590, 435597,
-        435599, 435600, 435610, 435616, 435618, 435623, 435628, 435636, 435643, 435649, 435654,
-        435659, 435663, 435671, 435675, 435678, 435683, 435689, 435702, 435705, 435712, 435718,
-        435749, 435755, 435759, 435764, 435771, 435775, 435780, 435785, 435791, 435794, 435802,
-        435811, 435816, 435822, 435828, 435833, 435838, 435844, 435851, 435859, 435861, 435866,
-        435869, 435876, 435882, 435890, 435897, 435900, 435908, 435913, 435923, 435929, 435934,
-        435937, 435942, 435945, 435951, 435953, 435959, 435965, 435969, 435975, 435982, 435987,
-        435992, 436000, 436008, 436013, 436017, 436022, 436027, 436033, 436038, 436043, 436048,
-        436052, 436062, 436065, 436069, 436073, 436079, 436088, 436092, 436100, 436106, 436116,
-        436123, 436127, 436133, 436139, 436147, 436153, 436159, 436165, 436172, 436179, 436184,
-        436190, 436194, 436199, 436206, 436210, 436211, 436217, 436223, 436229, 436234, 436240,
-        436245, 436253, 436258, 436262, 436268, 436273, 436282, 436287, 436294, 436303, 436306,
-        436313, 436316, 436321, 436329, 436337, 436341, 436349, 436353, 436358, 436365, 436368,
-        436373, 436378, 436387, 436391, 436396, 436401, 436408, 436412, 436420, 436423, 436428,
-        436435, 436441, 436447, 436451, 436461, 436463, 436467, 436471, 436477, 436479, 436485,
-        436489, 436494, 436502, 436509, 436512, 436518, 436529, 436538, 436543, 436552, 436553,
-        436560, 436564, 436569, 436575, 436580, 436585, 436591, 436597, 436603, 436605, 436610,
-        436616, 436619, 436628, 436633, 436637, 436640, 436644, 436649, 436653, 436659, 436666,
-        436674, 436681, 436687, 436694, 436700, 436703, 436710, 436720, 436723, 436730, 436735,
-        436742, 436748, 436756, 436761, 436766, 436772, 436778, 436783, 436787, 436792, 436799,
-        436808, 436810, 436812, 436817, 436823, 436832, 436838, 436845, 436849, 436853, 436859,
-        436865, 436872, 436878, 436882, 436885, 436891, 436898, 436903, 436910, 436911, 436922,
-        436928, 436932, 436939, 436942, 436948, 436950, 436956, 436963, 436968, 436975, 436984,
-        436988, 436994, 437003, 437009, 437013, 437020, 437023, 437028, 437033, 437043, 437053,
-        437058, 437063, 437073, 437076, 437079, 437089, 437093, 437095, 437101, 437111, 437119,
-        437121, 437127, 437135, 437140, 437147, 437151, 437155, 437160, 437165, 437171, 437173,
-        437180, 437186, 437194, 437199, 437205, 437213, 437217, 437223, 437227, 437231, 437243,
-        437250, 437256, 437261, 437267, 437271, 437277, 437284, 437289, 437295, 437300, 437304,
-        437312, 437322, 437326, 437333, 437338, 437354, 437357, 437362, 437366, 437370, 437374,
-        437380, 437386, 437391, 437395, 437399, 437404, 437412, 437416, 437419, 437427, 437432,
-        437433, 437451, 437456, 437461, 437467, 437468, 437477, 437485, 437492, 437495, 437501,
-        437502, 437506, 437513, 437524, 437526, 437539, 437544, 437552, 437558, 437562, 437568,
-        437573, 437578, 437587, 437592, 437596, 437600, 437605, 437610, 437619, 437625, 437630,
-        437631, 437639, 437647, 437648, 437655, 437661, 437667, 437672, 437676, 437680, 437687,
-        437689, 437693, 437697, 437704, 437707, 437716, 437723, 437730, 437737, 437740, 437741,
-        437757, 437763, 437771, 437778, 437784, 437789, 437793, 437800, 437804, 437811, 437812,
-        437819, 437823, 437827, 437833, 437841, 437844, 437853, 437857, 437861, 437866, 437874,
-        437881, 437886, 437892, 437901, 437902, 437909, 437914, 437922, 437928, 437934, 437939,
-        437948, 437951, 437957, 437963, 437965, 437971, 437980, 437985, 437990, 437996, 438002,
-        438008, 438013, 438017, 438025, 438030, 438036, 438041, 438052, 438060, 438065, 438072,
-        438073, 438079, 438084, 438091, 438097, 438099, 438107, 438111, 438119, 438125, 438136,
-        438144, 438148, 438153, 438158, 438164, 438166, 438173, 438176, 438183, 438184, 438192,
-        438198, 438204, 438209, 438216, 438228, 438231, 438237, 438243, 438248, 438257, 438267,
-        438269, 438274, 438282, 438287, 438295, 438301, 438306, 438313, 438318, 438323, 438328,
-        438335, 438339, 438346, 438352, 438357, 438363, 438370, 438374, 438380, 438384, 438388,
-        438394, 438399, 438404, 438409, 438413, 438422, 438428, 438436, 438439, 438444, 438453,
-        438461, 438471, 438477, 438483, 438491, 438503, 438505, 438511, 438518, 438527, 438531,
-        438541, 438546, 438552, 438556, 438562, 438566, 438570, 438580, 438585, 438593, 438595,
-        438603, 438605, 438607, 438614, 438619, 438626, 438631, 438634, 438641, 438646, 438652,
-        438657, 438663, 438664, 438665, 438673, 438677, 438682, 438692, 438700, 438706, 438708,
-        438715, 438723, 438727, 438737, 438742, 438753, 438760, 438764, 438771, 438775, 438780,
-        438783, 438789, 438797, 438806, 438810, 438815, 438832, 438837, 438841, 438845, 438852,
-        438860, 438865, 438873, 438883, 438884, 438896, 438908, 438912, 438920, 438924, 438927,
-        438934, 438936, 438940, 438946, 438953, 438961, 438968, 438976, 438980, 438985, 438994,
-        439006, 439011, 439017, 439021, 439027, 439032, 439036, 439043, 439047, 439055, 439059,
-        439065, 439070, 439075, 439083, 439087, 439093, 439099, 439104, 439109, 439114, 439120,
-        439123, 439128, 439130, 439134, 439139, 439147, 439157, 439162, 439167, 439172, 439178,
-        439183, 439187, 439194, 439201, 439205, 439210, 439216, 439222, 439225, 439231, 439235,
-        439245, 439251, 439255, 439261, 439277, 439282, 439288, 439295, 439302, 439308, 439309,
-        439314, 439320, 439328, 439332, 439339, 439345, 439350, 439354, 439359, 439365, 439372,
-        439377, 439379, 439386, 439391, 439404, 439410, 439416, 439419, 439425, 439430, 439434,
-        439438, 439455, 439461, 439465, 439472, 439476, 439482, 439488, 439493, 439496, 439506,
-        439510, 439516, 439521, 439527, 439536, 439543, 439551, 439554, 439557, 439564, 439569,
-        439574, 439577, 439584, 439588, 439593, 439597, 439602, 439607, 439613, 439618, 439624,
-        439625, 439633, 439638, 439641, 439645, 439650, 439655, 439659, 439669, 439670, 439671,
-        439682, 439692, 439696, 439701, 439709, 439718, 439725, 439730, 439733, 439739, 439745,
-        439757, 439764, 439768, 439771, 439778, 439783, 439788, 439796, 439805, 439811, 439815,
-        439820, 439827, 439830, 439840, 439846, 439850, 439854, 439865, 439873, 439879, 439886,
-        439891, 439898, 439903, 439909, 439917, 439925, 439928, 439933, 439938, 439944, 439948,
-        439955, 439959, 439965, 439969, 439974, 439988, 439989, 440005, 440008, 440011, 440015,
-        440020, 440026, 440030, 440035, 440043, 440044, 440055, 440060, 440078, 440091, 440096,
-        440101, 440106, 440111, 440116, 440120, 440134, 440139, 440143, 440149, 440157, 440163,
-        440167, 440171, 440179, 440187, 440191, 440196, 440201, 440207, 440213, 440218, 440223,
-        440228, 440233, 440239, 440244, 440249, 440256, 440262, 440268, 440274, 440277, 440282,
-        440289, 440295, 440307, 440311, 440315, 440321, 440327, 440331, 440336, 440341, 440346,
-        440355, 440361, 440368, 440375, 440379, 440388, 440394, 440399, 440402, 440410, 440413,
-        440421, 440427, 440431, 440435, 440440, 440446, 440454, 440461, 440467, 440476, 440481,
-        440486, 440490, 440495, 440500, 440506, 440512, 440523, 440529, 440533, 440539, 440546,
-        440552, 440560, 440568, 440578, 440584, 440590, 440594, 440598, 440606, 440612, 440620,
-        440623, 440629, 440634, 440641, 440647, 440651, 440655, 440663, 440669, 440674, 440682,
-        440689, 440694, 440698, 440702, 440706, 440713, 440719, 440727, 440733, 440737, 440743,
-        440747, 440753, 440760, 440767, 440772, 440779, 440783, 440789, 440792, 440798, 440806,
-        440808, 440812, 440819, 440823, 440826, 440830, 440835, 440840, 440845, 440853, 440856,
-        440861, 440867, 440872, 440876, 440882, 440888, 440893, 440903, 440910, 440915, 440921,
-        440927, 440933, 440938, 440945, 440950, 440958, 440966, 440969, 440973, 440977, 440983,
-        440987, 440992, 440996, 441005, 441008, 441013, 441028, 441035, 441042, 441047, 441052,
-        441056, 441061, 441068, 441075, 441080, 441087, 441094, 441097, 441106, 441111, 441115,
-        441121, 441125, 441132, 441136, 441143, 441150, 441157, 441161, 441167, 441171, 441175,
-        441179, 441185, 441193, 441196, 441200, 441204, 441210, 441216, 441223, 441226, 441234,
-        441238, 441243, 441253, 441260, 441268, 441276, 441287, 441294, 441297, 441306, 441313,
-        441315, 441323, 441332, 441339, 441346, 441353, 441358, 441362, 441368, 441373, 441378,
-        441382, 441390, 441394, 441399, 441404, 441411, 441416, 441420, 441427, 441432, 441440,
-        441445, 441448, 441453, 441456, 441461, 441467, 441473, 441479, 441484, 441491, 441497,
-        441506, 441509, 441515, 441521, 441526, 441531, 441535, 441542, 441547, 441551, 441555,
-        441559, 441565, 441569, 441574, 441579, 441596, 441599, 441605, 441610, 441617, 441619,
-        441623, 441628, 441630, 441636, 441637, 441651, 441652, 441662, 441664, 441667, 441671,
-        441681, 441684, 441689, 441693, 441701, 441705, 441710, 441718, 441720, 441726, 441740,
-        441746, 441757, 441759, 441766, 441773, 441775, 441780, 441793, 441794, 441799, 441807,
-        441817, 441822, 441828, 441831, 441834, 441838, 441845, 441853, 441857, 441863, 441866,
-        441872, 441880, 441883, 441886, 441891, 441895, 441900, 441910, 441915, 441921, 441928,
-        441934, 441939, 441945, 441947, 441952, 441957, 441964, 441971, 441974, 441980, 441985,
-        441990, 441994, 441998, 442002, 442007, 442010, 442017, 442019, 442027, 442043, 442046,
-        442054, 442060, 442067, 442074, 442076, 442081, 442086, 442093, 442099, 442103, 442108,
-        442112, 442120, 442131, 442135, 442139, 442144, 442148, 442156, 442161, 442165, 442170,
-        442181, 442186, 442192, 442197, 442203, 442220, 442226, 442233, 442239, 442245, 442249,
-        442254, 442259, 442267, 442275, 442281, 442284, 442287, 442292, 442299, 442308, 442314,
-        442318, 442325, 442332, 442333, 442334, 442346, 442351, 442354, 442358, 442364, 442370,
-        442372, 442377, 442381, 442389, 442397, 442402, 442409, 442415, 442419, 442424, 442430,
-        442438, 442443, 442451, 442459, 442470, 442473, 442482, 442490, 442496, 442501, 442506,
-        442514, 442520, 442524, 442530, 442534, 442541, 442546, 442549, 442554, 442558, 442563,
-        442573, 442586, 442591, 442595, 442600, 442607, 442613, 442618, 442624, 442628, 442632,
-        442640, 442647, 442651, 442657, 442666, 442674, 442679, 442682, 442686, 442692, 442699,
-        442705, 442714, 442718, 442722, 442729, 442734, 442739, 442748, 442751, 442754, 442757,
-        442765, 442770, 442778, 442783, 442792, 442798, 442802, 442813, 442820, 442829, 442833,
-        442841, 442845, 442851, 442857, 442860, 442865, 442871, 442877, 442882, 442886, 442892,
-        442898, 442904, 442906, 442911, 442915, 442922, 442929, 442934, 442940, 442944, 442946,
-        442952, 442956, 442963, 442971, 442973, 442979, 442985, 442997, 443001, 443006, 443017,
-        443019, 443024, 443027, 443036, 443046, 443050, 443057, 443066, 443069, 443078, 443083,
-        443089, 443093, 443100, 443104, 443109, 443118, 443126, 443134, 443141, 443146, 443151,
-        443158, 443164, 443169, 443174, 443179, 443182, 443189, 443195, 443198, 443206, 443211,
-        443213, 443214, 443222, 443224, 443228, 443235, 443240, 443246, 443255, 443259, 443269,
-        443270, 443277, 443285, 443291, 443299, 443303, 443311, 443313, 443319, 443322, 443328,
-        443338, 443342, 443350, 443351, 443356, 443362, 443365, 443368, 443371, 443375, 443378,
-        443384, 443388, 443391, 443397, 443404, 443412, 443416, 443421, 443424, 443428, 443433,
-        443438, 443442, 443449, 443462, 443463, 443470, 443474, 443482, 443490, 443495, 443499,
-        443506, 443519, 443523, 443527, 443533, 443540, 443548, 443550, 443556, 443559, 443564,
-        443568, 443574, 443582, 443589, 443594, 443596, 443602, 443610, 443612, 443616, 443620,
-        443625, 443631, 443638, 443643, 443649, 443656, 443660, 443669, 443672, 443680, 443691,
-        443695, 443699, 443706, 443710, 443714, 443718, 443721, 443726, 443734, 443739, 443745,
-        443752, 443758, 443765, 443771, 443774, 443781, 443786, 443789, 443793, 443797, 443802,
-        443811, 443812, 443820, 443829, 443832, 443838, 443847, 443851, 443856, 443857, 443864,
-        443871, 443877, 443886, 443892, 443896, 443903, 443909, 443913, 443920, 443925, 443930,
-        443935, 443942, 443946, 443954, 443963, 443966, 443969, 443975, 443979, 443982, 443988,
-        443996, 443999, 444003, 444007, 444012, 444019, 444026, 444030, 444040, 444049, 444056,
-        444060, 444064, 444069, 444073, 444075, 444078, 444083, 444091, 444098, 444103, 444111,
-        444121, 444124, 444130, 444136, 444140, 444145, 444150, 444156, 444162, 444168, 444172,
-        444179, 444182, 444186, 444189, 444193, 444198, 444203, 444208, 444212, 444218, 444225,
-        444231, 444234, 444240, 444246, 444258, 444265, 444273, 444277, 444281, 444288, 444292,
-        444298, 444301, 444309, 444314, 444319, 444327, 444332, 444338, 444349, 444354, 444359,
-        444364, 444374, 444377, 444381, 444386, 444388, 444394, 444401, 444406, 444417, 444422,
-        444429, 444438, 444439, 444448, 444449, 444456, 444461, 444467, 444473, 444480, 444486,
-        444490, 444495, 444500, 444503, 444508, 444514, 444518, 444525, 444528, 444535, 444540,
-        444544, 444550, 444556, 444563, 444570, 444576, 444580, 444583, 444587, 444591, 444599,
-        444605, 444608, 444612, 444619, 444629, 444635, 444643, 444646, 444652, 444660, 444671,
-        444676, 444681, 444686, 444690, 444696, 444703, 444710, 444711, 444720, 444723, 444734,
-        444742, 444752, 444758, 444763, 444767, 444770, 444774, 444786, 444789, 444794, 444800,
-        444809, 444818, 444822, 444830, 444836, 444841, 444846, 444853, 444859, 444866, 444873,
-        444878, 444885, 444890, 444896, 444904, 444907, 444914, 444922, 444924, 444931, 446357,
-        488475, 495304, 496119, 497438, 498593, 498603, 498917, 499048, 499713, 500776, 501348,
-        503424, 508844, 518359, 519305, 519446, 523627, 523776, 523878, 523902, 524135, 524329,
-        524515, 524611, 524686, 524798, 524852, 525209, 525700, 525913, 525954, 526158, 526332,
-        526356, 536810, 537279, 563933, 578719, 579248, 579791, 584191, 591485, 592871, 613176,
-        615012, 616428, 619153, 636103, 640708, 643141, 645080, 646349, 647043, 649345, 651085,
-        652849, 653092, 653169, 653227, 653586, 655241, 656093, 658355, 658564, 659381, 659518,
-        690513, 693218, 693746, 694340, 694842, 695155, 695563, 695776, 696380, 697608, 697797,
-        698222, 698835, 699307, 700154, 700203, 700235, 700404, 700806, 700900, 701796, 702155,
-        702956, 702998, 705105, 705377, 705631, 708650, 709265, 709787, 725122, 735376, 737115,
-        737174, 738005, 741377, 741986, 746045, 746404, 746590, 748212, 753574, 754379, 764728,
-        765776, 766863, 769126, 782626, 782723, 783529, 786875, 787544, 807281, 811132, 821933,
-        822194, 829768, 830997, 831095, 832481, 834082, 844664, 845574, 845764, 846820, 849481,
-        855607, 857775, 872350, 876126, 902029, 903509, 904449, 904469, 905915, 910463, 911856,
-        924365, 928664, 929314, 929606, 929983, 930478, 933195, 933819, 935628, 935911, 935922,
-        936002, 937668, 941895, 942677, 943721, 944661, 944980, 945121, 945268, 945360, 950756,
-        951007, 959993, 960787, 961048, 961084, 961238, 961589, 962000, 962797, 962827, 962910,
-        963788, 964272, 964343, 964431, 964573, 964949, 965017, 965036, 965041, 965598, 965674,
-        965957, 966014, 966032, 966092, 966144, 966226, 966234, 966265, 966291, 978103, 980858,
-        987212, 987458, 987498, 988368, 988513, 988939, 990571, 993183, 1005493, 1007972, 1008230,
-        1009675, 1010075, 1010685, 1011441, 1011828, 1012269, 1012310, 1013612, 1013907, 1014379,
-        1018659, 1018923, 1022035, 1024567, 1024568, 1025024, 1026699, 1027212, 1027840, 1029108,
-        1031846, 1032670, 1032970, 1034016, 1039255, 1040626, 1040796, 1043457, 1043632, 1051053,
-        1052581, 1091611, 1092316, 1092564, 1092634, 1096386, 1096820, 1098606, 1104201, 1107101,
-        1110019, 1111384, 1111707, 1128990, 1129111, 1129147, 1129160, 1129367, 1129408, 1129508,
-        1129577, 1129699, 1129750, 1129840, 1129951, 1129988, 1130041, 1130139, 1130177, 1130241,
-        1130248, 1130268, 1130276, 1130367, 1130540, 1130562, 1130636, 1130637, 1130662, 1130716,
-        1131139, 1131218, 1131250, 1131454, 1131541, 1131775, 1132208, 1132280, 1132901, 1133264,
-        1133474, 1133475, 1133764, 1133841, 1133988, 1134290, 1134533, 1134553, 1134614, 1134667,
-        1134710, 1134861, 1134896, 1135008, 1135178, 1135544, 1135551, 1135573, 1136260, 1136385,
-        1136458, 1136782, 1136960, 1137342, 1137713, 1137824, 1138160, 1138291, 1138340, 1138457,
-        1138468, 1138516, 1138526, 1138610, 1138648, 1138700, 1138801, 1138869, 1138999, 1139010,
-        1139102, 1139114, 1139145, 1139302, 1139322, 1139417, 1139496, 1139581, 1139668, 1139852,
-        1139930, 1139958, 1140325, 1140616, 1140811, 1140861, 1141056, 1141197, 1141311, 1141346,
-        1141551, 1141666, 1141735, 1141786, 1141895, 1142017, 1142228, 1142242, 1142415, 1142484,
-        1142579, 1142599, 1142867, 1142929, 1143057, 1143132, 1143191, 1143203, 1143293, 1143476,
-        1143860, 1143997, 1144044, 1144321, 1144338, 1144459, 1144548, 1144564, 1144588, 1144592,
-        1144606, 1144623, 1144718, 1144792, 1144906, 1144997, 1145007, 1145082, 1145274, 1145380,
-        1145430, 1145584, 1145731, 1145778, 1145869, 1145914, 1145925, 1146025, 1146158, 1146212,
-        1146223, 1146448, 1146594, 1146663, 1146761, 1146803, 1146826, 1146833, 1146898, 1147078,
-        1147099, 1147330, 1147382, 1147424, 1147431, 1147472, 1147545, 1147592, 1147627, 1147657,
-        1147742, 1148005, 1148699, 1155013, 1155166, 1155915, 1178902, 1179255, 1180871, 1184802,
-        1187587, 1190670, 1198632, 1198646, 1198832, 1199211, 1199259, 1199330, 1200318, 1200824,
-        1200959, 1201200, 1202513, 1210077, 1210208, 1210296, 1211774, 1211775, 1211776, 1211777,
-        1212528, 1212529, 1212843, 1216377, 1219904, 1220650, 1232492, 1235492, 1243381, 1243807,
-        1267467, 1267561, 1267615, 1267691, 1267708, 1267731, 1267797, 1273165, 1278015, 1278076,
-        1278615, 1279032, 1279185, 1279756, 1281009, 1281074, 1282368, 1284002, 1284572, 1285041,
-        1285278, 1285788, 1285969, 1286573, 1286679, 1287001, 1287466, 1287714, 1287819, 1288542,
-        1288897, 1289486, 1290086, 1290286, 1291047, 1291363, 1291498, 1291749, 1291853, 1292129,
-        1292571, 1292828, 1292855, 1292859, 1292892, 1292893, 1292909, 1292910, 1292956, 1292957,
-        1292985, 1293133, 1293185, 1293926, 1294446, 1294490, 1294571, 1294966, 1295003, 1295395,
-        1295491, 1296604, 1298327, 1298527, 1298685, 1300235, 1300501, 1301193, 1301345, 1301536,
-        1301908, 1301969, 1301988, 1302146, 1302158, 1302810, 1303060, 1303244, 1303275, 1303487,
-        1303721, 1303831, 1303943, 1304875, 1305210, 1305677, 1305687, 1306397, 1306865, 1307044,
-        1307745, 1307926, 1308080, 1308680, 1309204, 1309475, 1310596, 1312574, 1313313, 1313764,
-        1313792, 1313963, 1314093, 1314284, 1314743, 1315154, 1315292, 1315503, 1315994, 1316517,
-        1316872, 1316909, 1317089, 1317327, 1318223, 1319657, 1321070, 1321083, 1321495, 1321517,
-        1322195, 1322221, 1322293, 1322330, 1322471, 1322496, 1322569, 1322634, 1322716, 1322859,
-        1323066, 1323356, 1323530, 1323539, 1323614, 1323868, 1323925, 1328650, 1329210, 1332937,
-        1333431, 1335482, 1338092, 1342268, 1345890, 1346245, 1346532, 1346613, 1346783, 1347371,
-        1347858, 1348077, 1348468, 1349166, 1349298, 1349335, 1350775, 1350809, 1351329, 1352877};
-    int[] array2 = {14402, 14403, 14404, 14405, 14406, 14407, 23246, 23247, 23248, 23249, 23250,
-        23936, 23937, 23938, 23939, 23940, 23941, 23942, 29721, 29722, 29723, 29724, 29725, 30226,
-        30227, 30228, 30229, 30230, 32141, 32142, 32143, 47737, 47738, 47739, 47740, 47741, 47742,
-        47743, 47744, 47745, 47746, 47747, 47748, 47749, 47750, 47751, 47752, 68770, 68771, 68772,
-        68773, 68774, 68775, 68776, 68777, 68778, 68779, 68780, 72301, 72302, 83071, 83072, 83073,
-        83074, 85302, 85303, 85304, 85305, 85306, 85307, 85308, 85309, 85310, 85311, 85312, 85313,
-        85314, 85315, 85316, 97108, 97109, 97110, 97111, 103442, 103443, 103444, 103445, 103446,
-        103447, 103448, 103449, 103450, 103451, 103452, 103453, 103454, 103455, 103456, 103457,
-        103458, 103459, 103460, 103461, 103462, 103463, 103464, 103465, 103466, 103467, 103468,
-        103469, 128488, 128489, 128490, 128491, 128492, 128493, 135003, 135004, 135005, 135006,
-        135007, 135008, 135009, 135010, 135011, 135012, 135013, 135014, 140363, 140364, 140365,
-        140366, 140367, 140368, 140369, 140370, 140371, 140372, 149844, 149845, 149846, 149847,
-        149848, 149849, 149850, 149851, 149852, 149853, 149854, 149855, 149856, 149857, 149858,
-        149859, 149860, 149861, 149862, 149863, 149864, 172805, 172806, 172807, 172808, 172809,
-        172810, 172811, 172812, 172813, 172814, 172815, 172816, 172817, 172818, 172819, 172820,
-        172821, 172822, 172823, 172824, 172825, 172826, 172827, 172828, 172829, 172830, 172831,
-        172832, 172833, 172834, 172835, 172836, 172837, 172838, 172839, 172840, 172841, 172842,
-        172843, 172844, 172845, 172846, 172847, 172848, 172849, 172850, 172851, 172852, 172853,
-        172854, 172855, 172856, 172857, 172858, 172859, 172860, 172861, 172862, 172863, 172864,
-        172865, 172866, 172867, 172868, 172869, 172870, 172871, 202530, 202531, 202532, 209488,
-        209489, 209490, 209491, 209492, 209493, 209494, 209495, 209496, 209497, 209498, 209499,
-        209500, 209501, 209502, 209503, 209504, 209505, 209506, 225554, 225555, 225556, 225557,
-        225558, 225559, 225560, 225561, 225562, 225563, 225564, 225565, 225566, 225567, 225568,
-        225569, 225570, 225571, 225572, 225573, 225574, 225575, 225576, 225577, 225578, 225579,
-        225580, 225581, 227917, 227918, 227919, 227920, 227921, 227922, 227923, 227924, 227925,
-        227926, 227927, 227928, 227929, 227930, 227931, 227932, 227933, 227934, 227935, 227936,
-        227937, 227938, 227939, 252773, 252774, 252775, 252776, 252777, 252778, 252779, 252780,
-        252781, 252782, 252783, 252784, 252785, 252786, 252787, 252788, 252789, 252790, 252791,
-        252792, 252793, 252794, 278695, 278696, 278697, 278698, 278699, 301237, 301238, 301239,
-        301240, 301241, 301242, 301243, 301244, 301245, 301246, 301247, 301248, 301249, 301250,
-        301251, 301252, 301253, 301254, 301255, 301256, 301257, 301258, 301259, 301260, 301261,
-        301262, 301263, 301264, 301265, 320515, 320516, 320517, 320518, 320519, 320520, 320521,
-        320522, 320523, 320524, 320525, 320526, 320527, 320528, 320529, 320530, 320531, 320532,
-        320533, 320534, 320535, 320536, 320537, 320538, 320539, 320540, 320541, 320542, 320543,
-        320544, 320545, 320546, 320547, 320548, 329641, 329642, 329643, 329644, 329645, 329646,
-        329647, 329648, 329649, 329650, 329651, 329652, 329653, 329654, 329655, 329656, 329657,
-        329658, 329659, 342703, 342704, 342705, 342706, 349520, 349521, 349522, 349523, 349524,
-        349525, 349526, 349527, 349528, 349529, 349530, 362716, 362717, 362718, 362719, 362720,
-        362721, 362722, 362723, 362724, 362725, 362726, 362727, 378643, 378644, 378645, 378646,
-        390154, 390155, 390156, 390157, 390158, 390159, 390160, 390161, 390162, 390163, 390164,
-        390165, 390166, 390167, 390168, 390169, 395108, 395109, 395110, 395111, 395112, 395113,
-        395114, 395115, 403260, 403261, 403262, 403263, 403264, 403265, 403266, 403267, 403268,
-        403269, 403270, 403271, 417315, 417316, 417317, 417318, 417319, 417320, 432653, 432654,
-        432655, 432656, 432657, 432658, 432659, 432660, 432661, 432662, 432663, 432664, 432665,
-        432666, 432667, 432668, 432669, 432670, 432671, 432672, 432673, 432674, 432675, 432676,
-        432677, 432678, 449394, 449395, 449396, 449397, 449398, 459961, 459962, 459963, 459964,
-        474537, 474538, 474539, 474540, 474541, 474542, 474543, 474544, 474545, 474546, 474547,
-        474548, 474549, 474550, 474551, 474552, 474553, 474554, 474555, 474556, 474557, 474558,
-        474559, 474560, 474561, 474562, 474563, 474564, 474565, 474566, 474567, 474568, 474569,
-        474570, 474571, 474572, 474573, 474574, 474575, 474576, 474577, 474578, 474579, 474580,
-        474581, 474582, 474583, 474584, 474585, 474586, 474587, 474588, 474589, 474590, 474591,
-        474592, 474593, 474594, 474595, 474596, 474597, 483571, 483572, 483573, 483574, 483575,
-        483576, 489641, 489642, 489643, 489644, 489645, 489646, 489647, 489648, 489649, 489650,
-        489651, 491296, 491297, 491298, 495868, 495869, 495870, 502769, 502770, 502771, 502772,
-        502773, 502774, 502775, 502776, 502777, 502778, 502779, 502780, 502781, 502782, 502783,
-        513810, 513811, 513812, 513813, 513814, 513815, 513816, 513817, 513818, 513819, 513820,
-        513821, 513822, 513823, 513824, 513825, 513826, 513827, 513828, 513829, 513830, 513831,
-        513832, 517220, 517221, 517222, 517223, 517224, 517225, 517226, 517227, 519778, 519779,
-        519780, 519781, 519782, 519783, 519784, 519785, 524240, 524241, 524242, 524243, 524244,
-        524245, 524246, 524247, 524248, 524249, 527255, 527256, 527257, 527258, 527259, 533697,
-        533698, 533699, 533700, 533701, 533702, 533703, 533704, 533705, 533706, 533707, 533708,
-        533709, 539237, 539238, 539239, 539240, 539241, 539242, 539243, 562203, 562204, 562205,
-        562206, 569773, 569774, 569775, 569776, 569777, 569778, 569779, 569780, 569781, 569782,
-        569783, 569784, 569785, 569786, 569787, 569788, 569789, 569790, 569791, 569792, 569793,
-        569794, 569795, 569796, 569797, 569798, 569799, 569800, 569801, 569802, 569803, 569804,
-        569805, 569806, 569807, 569808, 569809, 569810, 569811, 569812, 569813, 569814, 569815,
-        569816, 569817, 569818, 569819, 569820, 569821, 580161, 580162, 580163, 580164, 580165,
-        580166, 580167, 580168, 580169, 580170, 580171, 580172, 580173, 580174, 580175, 580176,
-        588299, 588300, 588301, 588302, 588303, 588304, 588305, 588306, 588307, 588308, 588309,
-        588310, 588311, 588312, 588313, 588314, 588315, 588316, 588317, 588318, 588319, 588320,
-        588321, 588322, 588323, 588324, 588325, 588326, 588327, 588328, 588329, 588330, 588331,
-        588332, 588333, 588334, 588335, 608580, 608581, 608582, 608583, 608584, 608585, 608586,
-        608587, 608588, 608589, 608590, 608591, 608592, 608593, 608594, 608595, 608596, 608597,
-        608598, 608599, 608600, 608601, 608602, 608603, 608604, 608605, 618326, 618327, 618328,
-        618329, 618330, 618331, 618332, 618333, 618334, 618335, 618336, 618337, 618338, 618339,
-        618340, 618341, 618342, 618343, 618344, 618345, 618346, 618347, 618348, 618349, 626895,
-        626896, 626897, 626898, 626899, 626900, 635313, 635314, 635315, 635316, 635317, 635318,
-        635319, 635320, 635321, 635322, 635323, 635324, 635325, 635326, 635327, 635328, 635329,
-        635330, 635331, 635332, 635333, 635334, 635335, 635336, 635337, 635338, 635339, 635340,
-        635341, 635342, 635343, 635344, 635345, 635346, 635347, 635348, 635349, 635350, 635351,
-        635352, 635353, 635354, 635355, 648087, 648088, 648089, 648090, 648091, 648092, 648093,
-        648094, 648095, 648096, 648097, 648098, 648099, 648100, 648101, 648102, 648103, 648104,
-        648105, 648106, 648107, 648108, 648109, 648110, 661574, 661575, 661576, 661577, 674566,
-        674567, 674568, 674569, 674570, 674571, 674572, 674573, 674574, 674575, 674576, 674577,
-        674578, 674579, 674580, 674581, 674582, 674583, 674584, 674585, 689328, 689329, 689330,
-        689331, 689332, 689333, 689334, 689335, 689336, 689337, 697978, 697979, 697980, 697981,
-        697982, 697983, 697984, 697985, 697986, 697987, 697988, 697989, 697990, 697991, 697992,
-        697993, 697994, 726676, 726677, 726678, 726679, 726680, 726681, 782220, 782221, 782222,
-        782223, 782224, 782225, 782226, 782227, 782228, 782229, 782230, 782231, 782232, 782233,
-        782234, 782235, 782236, 782237, 782238, 782239, 797574, 797575, 797576, 797577, 797578,
-        797579, 797580, 797581, 797582, 804283, 804284, 804285, 822332, 822333, 822334, 822335,
-        822336, 831020, 831021, 831022, 831023, 831024, 831025, 831026, 831027, 831028, 831029,
-        831030, 831031, 831032, 831033, 831034, 831035, 831036, 831037, 831038, 831039, 831040,
-        847227, 847228, 847229, 847230, 847231, 847232, 847233, 847234, 847235, 847236, 847237,
-        847238, 847239, 847240, 847241, 847242, 847243, 847244, 847245, 857616, 857617, 857618,
-        857619, 857620, 857621, 857622, 857623, 857624, 857625, 867324, 867325, 867326, 867327,
-        867328, 867329, 867330, 867331, 867332, 867333, 867334, 867335, 867336, 867337, 867338,
-        867339, 877587, 877588, 877589, 877590, 877591, 877592, 877593, 877594, 877595, 877596,
-        877597, 877598, 877599, 877600, 877601, 877602, 877603, 877604, 877605, 877606, 877607,
-        877608, 877609, 877610, 877611, 877612, 877613, 877614, 877615, 896235, 896236, 896237,
-        896238, 896239, 896240, 916629, 916630, 916631, 916632, 929361, 929362, 929363, 929364,
-        929365, 929366, 929367, 929368, 929369, 929370, 929371, 948695, 948696, 948697, 948698,
-        948699, 948700, 948701, 948702, 949573, 949574, 957768, 957769, 957770, 957771, 957772,
-        957773, 957774, 957775, 961032, 961033, 961034, 961035, 987440, 987441, 987442, 987443,
-        1001434, 1001435, 1001436, 1001437, 1001438, 1001439, 1001440, 1001441, 1001442, 1001443,
-        1001444, 1001445, 1001446, 1001447, 1001448, 1001449, 1001450, 1001451, 1001452, 1001453,
-        1001454, 1001455, 1001456, 1001457, 1001458, 1001459, 1001460, 1009985, 1009986, 1009987,
-        1009988, 1009989, 1037191, 1037192, 1037193, 1037194, 1037195, 1037196, 1037197, 1037198,
-        1037199, 1037200, 1037201, 1037202, 1037203, 1037204, 1053198, 1053199, 1053200, 1053201,
-        1053202, 1053203, 1053204, 1053205, 1053206, 1053207, 1053208, 1053209, 1053210, 1053211,
-        1053212, 1053213, 1053214, 1053215, 1053216, 1053217, 1053218, 1053219, 1053220, 1053221,
-        1053222, 1053223, 1053224, 1084019, 1084020, 1084021, 1084022, 1084023, 1084024, 1084025,
-        1088361, 1088362, 1088363, 1088364, 1088365, 1088366, 1089312, 1089313, 1089314, 1089315,
-        1089316, 1089317, 1089318, 1092235, 1092236, 1092237, 1092238, 1092239, 1092240, 1092241,
-        1092242, 1092243, 1092244, 1102836, 1102837, 1102838, 1102839, 1102840, 1102841, 1102842,
-        1102843, 1102844, 1102845, 1102846, 1102847, 1108575, 1108576, 1108577, 1108578, 1108579,
-        1108580, 1108581, 1108582, 1108583, 1108584, 1108585, 1108586, 1108587, 1108588, 1108589,
-        1108590, 1108591, 1108592, 1108593, 1108594, 1108595, 1108596, 1108597, 1108598, 1134091,
-        1134092, 1134093, 1134094, 1134095, 1134096, 1134097, 1134098, 1134099, 1134100, 1134101,
-        1134102, 1134103, 1134104, 1134105, 1134106, 1134107, 1134108, 1134109, 1134110, 1134111,
-        1134112, 1134113, 1134114, 1134115, 1134116, 1134117, 1134118, 1134119, 1134120, 1134121,
-        1134122, 1134123, 1134124, 1134125, 1134126, 1134127, 1134128, 1134129, 1151732, 1151733,
-        1151734, 1151735, 1151736, 1151737, 1151738, 1151739, 1151740, 1151741, 1151742, 1151743,
-        1151744, 1151745, 1151746, 1151747, 1199223, 1199224, 1199225, 1199226, 1203252, 1203253,
-        1203254, 1203255, 1203256, 1203257, 1203258, 1203259, 1203260, 1217223, 1217224, 1217225,
-        1217226, 1226505, 1226506, 1226507, 1226508, 1226509, 1226510, 1226511, 1226512, 1231411,
-        1231412, 1231413, 1231414, 1231415, 1231416, 1231417, 1231418, 1231419, 1231420, 1231421,
-        1231422, 1231423, 1243464, 1243465, 1243466, 1243467, 1243468, 1243469, 1243470, 1247919,
-        1247920, 1247921, 1255972, 1255973, 1255974, 1255975, 1255976, 1255977, 1255978, 1255979,
-        1255980, 1263675, 1263676, 1263677, 1263678, 1263679, 1277693, 1277694, 1277695, 1277696,
-        1277697, 1277698, 1277699, 1277700, 1283492, 1283493, 1283494, 1283495, 1283496, 1283497,
-        1283498, 1283499, 1283500, 1283501, 1283502, 1283503, 1283504, 1283505, 1283506, 1283507,
-        1283508, 1283509, 1283510, 1283511, 1283512, 1283513, 1283514, 1325789, 1325790, 1325791,
-        1325792, 1325793, 1325794, 1325795, 1325796, 1325797, 1325798, 1325799};
+    int[] array1 = {
+      22871, 22873, 22876, 22880, 22886, 22889, 22893, 22897, 22901, 22905, 22910, 22915, 22919,
+      22927, 22934, 22940, 24750, 38579, 48470, 50533, 53256, 53717, 53752, 53802, 53938, 54727,
+      54865, 55202, 55815, 55822, 55940, 56711, 56977, 57122, 59933, 60037, 60402, 60520, 60853,
+      61163, 61340, 61549, 61632, 62097, 62373, 62961, 62993, 63031, 63075, 64209, 64644, 64762,
+      64893, 64927, 64997, 65117, 65128, 65173, 65201, 65472, 65536, 65622, 66092, 66162, 66302,
+      66381, 66551, 103979, 104644, 106866, 117285, 123372, 127548, 132167, 132168, 136283, 136433,
+      137661, 138019, 138239, 138380, 138816, 138916, 138933, 139414, 140342, 140914, 142751,
+      142994, 143895, 145081, 147331, 147686, 148021, 148375, 148587, 149114, 149734, 152696,
+      153608, 154741, 154932, 155263, 157121, 158947, 159444, 161102, 161383, 162735, 164298,
+      168043, 169398, 169536, 170419, 170846, 171153, 177016, 177471, 178305, 178673, 183731,
+      183936, 184083, 184106, 185663, 188371, 189495, 189531, 196189, 198419, 198758, 198796,
+      200645, 201137, 216865, 216936, 217770, 217810, 217836, 217909, 218569, 218700, 218931,
+      219363, 220009, 225925, 234706, 241183, 241561, 242140, 242281, 245018, 245056, 249935,
+      250442, 250615, 251696, 252825, 254178, 256788, 256906, 257289, 258833, 260432, 260563,
+      260930, 262684, 262834, 263128, 265919, 268662, 269542, 270217, 271673, 273776, 274560,
+      275649, 305458, 306241, 306550, 307580, 310891, 312701, 313514, 318134, 319185, 320757,
+      321280, 322046, 322743, 323211, 324667, 325382, 326450, 327159, 328836, 329075, 331179,
+      332836, 332997, 333071, 333205, 333488, 333595, 335045, 335803, 336417, 336610, 338487,
+      339827, 339992, 346123, 348858, 351257, 351957, 353896, 354559, 357142, 358253, 366662,
+      378768, 391984, 392282, 415077, 429446, 429449, 429452, 429453, 429476, 429480, 429486,
+      429492, 429497, 429501, 429504, 429505, 429510, 429515, 429519, 429524, 429530, 429533,
+      429541, 429546, 429553, 429554, 429564, 429572, 429577, 429579, 429586, 429589, 429596,
+      429604, 429606, 429612, 429615, 429616, 429624, 429632, 429639, 429642, 429646, 429651,
+      429656, 429664, 429670, 429674, 429678, 429681, 429686, 429695, 429701, 429706, 429717,
+      429721, 429725, 429733, 429736, 429739, 429743, 429748, 429754, 429761, 429767, 429772,
+      429780, 429791, 429792, 429793, 429794, 429795, 429817, 429822, 429823, 429831, 429836,
+      429842, 429849, 429855, 429859, 429863, 429866, 429873, 429876, 429882, 429885, 429900,
+      429903, 429913, 429921, 429923, 429927, 429932, 429939, 429947, 429950, 429955, 429964,
+      429968, 429974, 429982, 429987, 429993, 429999, 430003, 430011, 430015, 430023, 430028,
+      430033, 430039, 430044, 430048, 430053, 430057, 430059, 430063, 430068, 430073, 430077,
+      430082, 430086, 430093, 430098, 430101, 430114, 430120, 430126, 430131, 430135, 430139,
+      430144, 430149, 430155, 430157, 430167, 430175, 430181, 430186, 430194, 430195, 430196,
+      430214, 430223, 430228, 430236, 430253, 430258, 430263, 430269, 430277, 430284, 430288,
+      430293, 430297, 430303, 430309, 430316, 430321, 430332, 430338, 430343, 430346, 430348,
+      430355, 430358, 430369, 430375, 430384, 430391, 430397, 430410, 430415, 430420, 430424,
+      430430, 430435, 430437, 430445, 430449, 430461, 430467, 430473, 430482, 430486, 430490,
+      430496, 430500, 430506, 430511, 430515, 430535, 430539, 430550, 430568, 430575, 430581,
+      430588, 430591, 430596, 430605, 430612, 430617, 430625, 430629, 430633, 430638, 430643,
+      430649, 430656, 430663, 430666, 430672, 430679, 430684, 430692, 430696, 430700, 430707,
+      430716, 430723, 430728, 430733, 430745, 430751, 430755, 430759, 430767, 430770, 430782,
+      430787, 430791, 430804, 430810, 430814, 430821, 430825, 430829, 430833, 430838, 430844,
+      430849, 430852, 430859, 430864, 430867, 430870, 430877, 430881, 430887, 430891, 430896,
+      430901, 430907, 430912, 430917, 430923, 430927, 430932, 430936, 430944, 430947, 430953,
+      430959, 430967, 430971, 430979, 430985, 430989, 430993, 430997, 431003, 431006, 431015,
+      431021, 431022, 431033, 431039, 431046, 431050, 431054, 431059, 431065, 431069, 431074,
+      431081, 431085, 431092, 431097, 431104, 431110, 431120, 431125, 431133, 431138, 431142,
+      431147, 431157, 431164, 431171, 431175, 431180, 431186, 431190, 431195, 431207, 431213,
+      431218, 431220, 431224, 431228, 431233, 431235, 431240, 431245, 431251, 431259, 431264,
+      431271, 431272, 431280, 431287, 431294, 431299, 431307, 431315, 431319, 431324, 431330,
+      431334, 431339, 431345, 431352, 431356, 431363, 431375, 431379, 431383, 431388, 431393,
+      431398, 431405, 431409, 431416, 431422, 431426, 431433, 431438, 431444, 431451, 431455,
+      431464, 431469, 431472, 431477, 431483, 431490, 431496, 431506, 431513, 431516, 431521,
+      431526, 431534, 431536, 431545, 431550, 431559, 431564, 431571, 431573, 431579, 431584,
+      431587, 431592, 431604, 431614, 431624, 431629, 431634, 431638, 431645, 431651, 431659,
+      431663, 431674, 431678, 431684, 431692, 431696, 431700, 431706, 431712, 431719, 431723,
+      431729, 431736, 431741, 431747, 431755, 431758, 431762, 431767, 431777, 431782, 431787,
+      431791, 431796, 431799, 431805, 431809, 431814, 431819, 431823, 431828, 431832, 431838,
+      431842, 431849, 431853, 431858, 431862, 431866, 431869, 431874, 431881, 431887, 431894,
+      431900, 431906, 431912, 431917, 431925, 431931, 431936, 431943, 431948, 431956, 431958,
+      431964, 431971, 431976, 431981, 431988, 431994, 431998, 432008, 432012, 432024, 432029,
+      432033, 432038, 432045, 432048, 432058, 432062, 432066, 432070, 432076, 432077, 432087,
+      432093, 432098, 432104, 432114, 432123, 432128, 432133, 432139, 432145, 432151, 432161,
+      432168, 432177, 432181, 432188, 432189, 432203, 432209, 432216, 432222, 432227, 432232,
+      432242, 432247, 432256, 432259, 432264, 432269, 432271, 432277, 432286, 432294, 432297,
+      432302, 432308, 432313, 432319, 432326, 432331, 432337, 432345, 432349, 432353, 432356,
+      432361, 432366, 432370, 432378, 432384, 432390, 432391, 432397, 432400, 432403, 432408,
+      432413, 432419, 432422, 432427, 432433, 432440, 432443, 432450, 432455, 432460, 432466,
+      432467, 432481, 432489, 432493, 432498, 432504, 432511, 432513, 432517, 432525, 432531,
+      432537, 432544, 432546, 432555, 432561, 432565, 432569, 432574, 432579, 432586, 432590,
+      432597, 432605, 432611, 432619, 432626, 432630, 432637, 432644, 432646, 432653, 432654,
+      432664, 432670, 432674, 432679, 432682, 432687, 432694, 432706, 432711, 432714, 432721,
+      432726, 432732, 432741, 432747, 432753, 432755, 432761, 432764, 432768, 432774, 432779,
+      432784, 432792, 432798, 432801, 432808, 432815, 432823, 432825, 432833, 432838, 432842,
+      432847, 432853, 432861, 432866, 432873, 432879, 432889, 432895, 432901, 432906, 432913,
+      432917, 432920, 432926, 432935, 432940, 432949, 432953, 432958, 432960, 432966, 432967,
+      432968, 432969, 432970, 432971, 432972, 432996, 432999, 433004, 433010, 433020, 433026,
+      433029, 433033, 433042, 433045, 433050, 433054, 433058, 433062, 433065, 433070, 433076,
+      433086, 433095, 433101, 433102, 433116, 433122, 433129, 433132, 433140, 433146, 433151,
+      433157, 433163, 433169, 433176, 433181, 433188, 433198, 433204, 433219, 433229, 433236,
+      433240, 433246, 433250, 433259, 433263, 433274, 433277, 433282, 433286, 433291, 433295,
+      433299, 433306, 433316, 433318, 433322, 433327, 433335, 433342, 433348, 433351, 433359,
+      433362, 433367, 433371, 433377, 433384, 433393, 433398, 433403, 433407, 433411, 433425,
+      433430, 433437, 433441, 433445, 433452, 433453, 433458, 433462, 433469, 433473, 433478,
+      433484, 433490, 433495, 433501, 433506, 433514, 433517, 433521, 433527, 433534, 433544,
+      433549, 433552, 433561, 433565, 433569, 433576, 433585, 433589, 433594, 433597, 433600,
+      433603, 433606, 433613, 433619, 433623, 433627, 433639, 433643, 433648, 433654, 433658,
+      433665, 433673, 433678, 433681, 433689, 433696, 433704, 433709, 433716, 433721, 433725,
+      433729, 433734, 433738, 433744, 433749, 433755, 433760, 433766, 433771, 433776, 433781,
+      433785, 433790, 433798, 433803, 433810, 433814, 433817, 433822, 433828, 433833, 433837,
+      433843, 433849, 433852, 433858, 433863, 433871, 433875, 433881, 433883, 433884, 433897,
+      433903, 433909, 433913, 433921, 433926, 433932, 433936, 433942, 433946, 433951, 433959,
+      433965, 433976, 433981, 433989, 433996, 434004, 434011, 434013, 434019, 434023, 434029,
+      434036, 434041, 434048, 434050, 434056, 434060, 434068, 434074, 434079, 434085, 434091,
+      434096, 434100, 434105, 434110, 434119, 434123, 434129, 434133, 434139, 434146, 434150,
+      434156, 434161, 434168, 434173, 434183, 434188, 434193, 434200, 434208, 434213, 434219,
+      434223, 434229, 434235, 434241, 434247, 434258, 434262, 434269, 434275, 434282, 434287,
+      434291, 434296, 434303, 434308, 434313, 434316, 434323, 434327, 434335, 434342, 434349,
+      434353, 434360, 434366, 434372, 434373, 434381, 434387, 434392, 434397, 434401, 434403,
+      434409, 434414, 434420, 434427, 434433, 434440, 434445, 434449, 434454, 434460, 434467,
+      434473, 434479, 434481, 434490, 434494, 434501, 434505, 434510, 434517, 434526, 434537,
+      434542, 434548, 434553, 434558, 434563, 434569, 434574, 434580, 434586, 434588, 434595,
+      434603, 434606, 434617, 434620, 434626, 434630, 434638, 434644, 434647, 434651, 434658,
+      434666, 434671, 434679, 434681, 434685, 434692, 434699, 434703, 434708, 434713, 434720,
+      434723, 434729, 434734, 434738, 434742, 434746, 434753, 434762, 434766, 434773, 434781,
+      434790, 434799, 434805, 434810, 434814, 434823, 434831, 434839, 434845, 434850, 434856,
+      434859, 434863, 434869, 434870, 434882, 434890, 434896, 434899, 434906, 434912, 434917,
+      434921, 434930, 434935, 434940, 434945, 434949, 434956, 434961, 434967, 434977, 434982,
+      434987, 434992, 434995, 435002, 435005, 435009, 435016, 435021, 435025, 435028, 435034,
+      435041, 435050, 435055, 435065, 435069, 435075, 435078, 435083, 435091, 435097, 435102,
+      435105, 435107, 435113, 435118, 435124, 435131, 435141, 435144, 435150, 435154, 435159,
+      435167, 435171, 435177, 435181, 435187, 435192, 435198, 435204, 435211, 435212, 435221,
+      435228, 435231, 435237, 435244, 435246, 435254, 435258, 435264, 435275, 435283, 435289,
+      435301, 435304, 435312, 435318, 435323, 435329, 435334, 435340, 435343, 435347, 435351,
+      435358, 435363, 435368, 435375, 435382, 435388, 435391, 435396, 435399, 435405, 435412,
+      435416, 435422, 435425, 435429, 435437, 435444, 435447, 435453, 435458, 435470, 435477,
+      435486, 435491, 435497, 435500, 435511, 435516, 435520, 435526, 435533, 435539, 435545,
+      435551, 435559, 435564, 435569, 435575, 435579, 435585, 435590, 435597, 435599, 435600,
+      435610, 435616, 435618, 435623, 435628, 435636, 435643, 435649, 435654, 435659, 435663,
+      435671, 435675, 435678, 435683, 435689, 435702, 435705, 435712, 435718, 435749, 435755,
+      435759, 435764, 435771, 435775, 435780, 435785, 435791, 435794, 435802, 435811, 435816,
+      435822, 435828, 435833, 435838, 435844, 435851, 435859, 435861, 435866, 435869, 435876,
+      435882, 435890, 435897, 435900, 435908, 435913, 435923, 435929, 435934, 435937, 435942,
+      435945, 435951, 435953, 435959, 435965, 435969, 435975, 435982, 435987, 435992, 436000,
+      436008, 436013, 436017, 436022, 436027, 436033, 436038, 436043, 436048, 436052, 436062,
+      436065, 436069, 436073, 436079, 436088, 436092, 436100, 436106, 436116, 436123, 436127,
+      436133, 436139, 436147, 436153, 436159, 436165, 436172, 436179, 436184, 436190, 436194,
+      436199, 436206, 436210, 436211, 436217, 436223, 436229, 436234, 436240, 436245, 436253,
+      436258, 436262, 436268, 436273, 436282, 436287, 436294, 436303, 436306, 436313, 436316,
+      436321, 436329, 436337, 436341, 436349, 436353, 436358, 436365, 436368, 436373, 436378,
+      436387, 436391, 436396, 436401, 436408, 436412, 436420, 436423, 436428, 436435, 436441,
+      436447, 436451, 436461, 436463, 436467, 436471, 436477, 436479, 436485, 436489, 436494,
+      436502, 436509, 436512, 436518, 436529, 436538, 436543, 436552, 436553, 436560, 436564,
+      436569, 436575, 436580, 436585, 436591, 436597, 436603, 436605, 436610, 436616, 436619,
+      436628, 436633, 436637, 436640, 436644, 436649, 436653, 436659, 436666, 436674, 436681,
+      436687, 436694, 436700, 436703, 436710, 436720, 436723, 436730, 436735, 436742, 436748,
+      436756, 436761, 436766, 436772, 436778, 436783, 436787, 436792, 436799, 436808, 436810,
+      436812, 436817, 436823, 436832, 436838, 436845, 436849, 436853, 436859, 436865, 436872,
+      436878, 436882, 436885, 436891, 436898, 436903, 436910, 436911, 436922, 436928, 436932,
+      436939, 436942, 436948, 436950, 436956, 436963, 436968, 436975, 436984, 436988, 436994,
+      437003, 437009, 437013, 437020, 437023, 437028, 437033, 437043, 437053, 437058, 437063,
+      437073, 437076, 437079, 437089, 437093, 437095, 437101, 437111, 437119, 437121, 437127,
+      437135, 437140, 437147, 437151, 437155, 437160, 437165, 437171, 437173, 437180, 437186,
+      437194, 437199, 437205, 437213, 437217, 437223, 437227, 437231, 437243, 437250, 437256,
+      437261, 437267, 437271, 437277, 437284, 437289, 437295, 437300, 437304, 437312, 437322,
+      437326, 437333, 437338, 437354, 437357, 437362, 437366, 437370, 437374, 437380, 437386,
+      437391, 437395, 437399, 437404, 437412, 437416, 437419, 437427, 437432, 437433, 437451,
+      437456, 437461, 437467, 437468, 437477, 437485, 437492, 437495, 437501, 437502, 437506,
+      437513, 437524, 437526, 437539, 437544, 437552, 437558, 437562, 437568, 437573, 437578,
+      437587, 437592, 437596, 437600, 437605, 437610, 437619, 437625, 437630, 437631, 437639,
+      437647, 437648, 437655, 437661, 437667, 437672, 437676, 437680, 437687, 437689, 437693,
+      437697, 437704, 437707, 437716, 437723, 437730, 437737, 437740, 437741, 437757, 437763,
+      437771, 437778, 437784, 437789, 437793, 437800, 437804, 437811, 437812, 437819, 437823,
+      437827, 437833, 437841, 437844, 437853, 437857, 437861, 437866, 437874, 437881, 437886,
+      437892, 437901, 437902, 437909, 437914, 437922, 437928, 437934, 437939, 437948, 437951,
+      437957, 437963, 437965, 437971, 437980, 437985, 437990, 437996, 438002, 438008, 438013,
+      438017, 438025, 438030, 438036, 438041, 438052, 438060, 438065, 438072, 438073, 438079,
+      438084, 438091, 438097, 438099, 438107, 438111, 438119, 438125, 438136, 438144, 438148,
+      438153, 438158, 438164, 438166, 438173, 438176, 438183, 438184, 438192, 438198, 438204,
+      438209, 438216, 438228, 438231, 438237, 438243, 438248, 438257, 438267, 438269, 438274,
+      438282, 438287, 438295, 438301, 438306, 438313, 438318, 438323, 438328, 438335, 438339,
+      438346, 438352, 438357, 438363, 438370, 438374, 438380, 438384, 438388, 438394, 438399,
+      438404, 438409, 438413, 438422, 438428, 438436, 438439, 438444, 438453, 438461, 438471,
+      438477, 438483, 438491, 438503, 438505, 438511, 438518, 438527, 438531, 438541, 438546,
+      438552, 438556, 438562, 438566, 438570, 438580, 438585, 438593, 438595, 438603, 438605,
+      438607, 438614, 438619, 438626, 438631, 438634, 438641, 438646, 438652, 438657, 438663,
+      438664, 438665, 438673, 438677, 438682, 438692, 438700, 438706, 438708, 438715, 438723,
+      438727, 438737, 438742, 438753, 438760, 438764, 438771, 438775, 438780, 438783, 438789,
+      438797, 438806, 438810, 438815, 438832, 438837, 438841, 438845, 438852, 438860, 438865,
+      438873, 438883, 438884, 438896, 438908, 438912, 438920, 438924, 438927, 438934, 438936,
+      438940, 438946, 438953, 438961, 438968, 438976, 438980, 438985, 438994, 439006, 439011,
+      439017, 439021, 439027, 439032, 439036, 439043, 439047, 439055, 439059, 439065, 439070,
+      439075, 439083, 439087, 439093, 439099, 439104, 439109, 439114, 439120, 439123, 439128,
+      439130, 439134, 439139, 439147, 439157, 439162, 439167, 439172, 439178, 439183, 439187,
+      439194, 439201, 439205, 439210, 439216, 439222, 439225, 439231, 439235, 439245, 439251,
+      439255, 439261, 439277, 439282, 439288, 439295, 439302, 439308, 439309, 439314, 439320,
+      439328, 439332, 439339, 439345, 439350, 439354, 439359, 439365, 439372, 439377, 439379,
+      439386, 439391, 439404, 439410, 439416, 439419, 439425, 439430, 439434, 439438, 439455,
+      439461, 439465, 439472, 439476, 439482, 439488, 439493, 439496, 439506, 439510, 439516,
+      439521, 439527, 439536, 439543, 439551, 439554, 439557, 439564, 439569, 439574, 439577,
+      439584, 439588, 439593, 439597, 439602, 439607, 439613, 439618, 439624, 439625, 439633,
+      439638, 439641, 439645, 439650, 439655, 439659, 439669, 439670, 439671, 439682, 439692,
+      439696, 439701, 439709, 439718, 439725, 439730, 439733, 439739, 439745, 439757, 439764,
+      439768, 439771, 439778, 439783, 439788, 439796, 439805, 439811, 439815, 439820, 439827,
+      439830, 439840, 439846, 439850, 439854, 439865, 439873, 439879, 439886, 439891, 439898,
+      439903, 439909, 439917, 439925, 439928, 439933, 439938, 439944, 439948, 439955, 439959,
+      439965, 439969, 439974, 439988, 439989, 440005, 440008, 440011, 440015, 440020, 440026,
+      440030, 440035, 440043, 440044, 440055, 440060, 440078, 440091, 440096, 440101, 440106,
+      440111, 440116, 440120, 440134, 440139, 440143, 440149, 440157, 440163, 440167, 440171,
+      440179, 440187, 440191, 440196, 440201, 440207, 440213, 440218, 440223, 440228, 440233,
+      440239, 440244, 440249, 440256, 440262, 440268, 440274, 440277, 440282, 440289, 440295,
+      440307, 440311, 440315, 440321, 440327, 440331, 440336, 440341, 440346, 440355, 440361,
+      440368, 440375, 440379, 440388, 440394, 440399, 440402, 440410, 440413, 440421, 440427,
+      440431, 440435, 440440, 440446, 440454, 440461, 440467, 440476, 440481, 440486, 440490,
+      440495, 440500, 440506, 440512, 440523, 440529, 440533, 440539, 440546, 440552, 440560,
+      440568, 440578, 440584, 440590, 440594, 440598, 440606, 440612, 440620, 440623, 440629,
+      440634, 440641, 440647, 440651, 440655, 440663, 440669, 440674, 440682, 440689, 440694,
+      440698, 440702, 440706, 440713, 440719, 440727, 440733, 440737, 440743, 440747, 440753,
+      440760, 440767, 440772, 440779, 440783, 440789, 440792, 440798, 440806, 440808, 440812,
+      440819, 440823, 440826, 440830, 440835, 440840, 440845, 440853, 440856, 440861, 440867,
+      440872, 440876, 440882, 440888, 440893, 440903, 440910, 440915, 440921, 440927, 440933,
+      440938, 440945, 440950, 440958, 440966, 440969, 440973, 440977, 440983, 440987, 440992,
+      440996, 441005, 441008, 441013, 441028, 441035, 441042, 441047, 441052, 441056, 441061,
+      441068, 441075, 441080, 441087, 441094, 441097, 441106, 441111, 441115, 441121, 441125,
+      441132, 441136, 441143, 441150, 441157, 441161, 441167, 441171, 441175, 441179, 441185,
+      441193, 441196, 441200, 441204, 441210, 441216, 441223, 441226, 441234, 441238, 441243,
+      441253, 441260, 441268, 441276, 441287, 441294, 441297, 441306, 441313, 441315, 441323,
+      441332, 441339, 441346, 441353, 441358, 441362, 441368, 441373, 441378, 441382, 441390,
+      441394, 441399, 441404, 441411, 441416, 441420, 441427, 441432, 441440, 441445, 441448,
+      441453, 441456, 441461, 441467, 441473, 441479, 441484, 441491, 441497, 441506, 441509,
+      441515, 441521, 441526, 441531, 441535, 441542, 441547, 441551, 441555, 441559, 441565,
+      441569, 441574, 441579, 441596, 441599, 441605, 441610, 441617, 441619, 441623, 441628,
+      441630, 441636, 441637, 441651, 441652, 441662, 441664, 441667, 441671, 441681, 441684,
+      441689, 441693, 441701, 441705, 441710, 441718, 441720, 441726, 441740, 441746, 441757,
+      441759, 441766, 441773, 441775, 441780, 441793, 441794, 441799, 441807, 441817, 441822,
+      441828, 441831, 441834, 441838, 441845, 441853, 441857, 441863, 441866, 441872, 441880,
+      441883, 441886, 441891, 441895, 441900, 441910, 441915, 441921, 441928, 441934, 441939,
+      441945, 441947, 441952, 441957, 441964, 441971, 441974, 441980, 441985, 441990, 441994,
+      441998, 442002, 442007, 442010, 442017, 442019, 442027, 442043, 442046, 442054, 442060,
+      442067, 442074, 442076, 442081, 442086, 442093, 442099, 442103, 442108, 442112, 442120,
+      442131, 442135, 442139, 442144, 442148, 442156, 442161, 442165, 442170, 442181, 442186,
+      442192, 442197, 442203, 442220, 442226, 442233, 442239, 442245, 442249, 442254, 442259,
+      442267, 442275, 442281, 442284, 442287, 442292, 442299, 442308, 442314, 442318, 442325,
+      442332, 442333, 442334, 442346, 442351, 442354, 442358, 442364, 442370, 442372, 442377,
+      442381, 442389, 442397, 442402, 442409, 442415, 442419, 442424, 442430, 442438, 442443,
+      442451, 442459, 442470, 442473, 442482, 442490, 442496, 442501, 442506, 442514, 442520,
+      442524, 442530, 442534, 442541, 442546, 442549, 442554, 442558, 442563, 442573, 442586,
+      442591, 442595, 442600, 442607, 442613, 442618, 442624, 442628, 442632, 442640, 442647,
+      442651, 442657, 442666, 442674, 442679, 442682, 442686, 442692, 442699, 442705, 442714,
+      442718, 442722, 442729, 442734, 442739, 442748, 442751, 442754, 442757, 442765, 442770,
+      442778, 442783, 442792, 442798, 442802, 442813, 442820, 442829, 442833, 442841, 442845,
+      442851, 442857, 442860, 442865, 442871, 442877, 442882, 442886, 442892, 442898, 442904,
+      442906, 442911, 442915, 442922, 442929, 442934, 442940, 442944, 442946, 442952, 442956,
+      442963, 442971, 442973, 442979, 442985, 442997, 443001, 443006, 443017, 443019, 443024,
+      443027, 443036, 443046, 443050, 443057, 443066, 443069, 443078, 443083, 443089, 443093,
+      443100, 443104, 443109, 443118, 443126, 443134, 443141, 443146, 443151, 443158, 443164,
+      443169, 443174, 443179, 443182, 443189, 443195, 443198, 443206, 443211, 443213, 443214,
+      443222, 443224, 443228, 443235, 443240, 443246, 443255, 443259, 443269, 443270, 443277,
+      443285, 443291, 443299, 443303, 443311, 443313, 443319, 443322, 443328, 443338, 443342,
+      443350, 443351, 443356, 443362, 443365, 443368, 443371, 443375, 443378, 443384, 443388,
+      443391, 443397, 443404, 443412, 443416, 443421, 443424, 443428, 443433, 443438, 443442,
+      443449, 443462, 443463, 443470, 443474, 443482, 443490, 443495, 443499, 443506, 443519,
+      443523, 443527, 443533, 443540, 443548, 443550, 443556, 443559, 443564, 443568, 443574,
+      443582, 443589, 443594, 443596, 443602, 443610, 443612, 443616, 443620, 443625, 443631,
+      443638, 443643, 443649, 443656, 443660, 443669, 443672, 443680, 443691, 443695, 443699,
+      443706, 443710, 443714, 443718, 443721, 443726, 443734, 443739, 443745, 443752, 443758,
+      443765, 443771, 443774, 443781, 443786, 443789, 443793, 443797, 443802, 443811, 443812,
+      443820, 443829, 443832, 443838, 443847, 443851, 443856, 443857, 443864, 443871, 443877,
+      443886, 443892, 443896, 443903, 443909, 443913, 443920, 443925, 443930, 443935, 443942,
+      443946, 443954, 443963, 443966, 443969, 443975, 443979, 443982, 443988, 443996, 443999,
+      444003, 444007, 444012, 444019, 444026, 444030, 444040, 444049, 444056, 444060, 444064,
+      444069, 444073, 444075, 444078, 444083, 444091, 444098, 444103, 444111, 444121, 444124,
+      444130, 444136, 444140, 444145, 444150, 444156, 444162, 444168, 444172, 444179, 444182,
+      444186, 444189, 444193, 444198, 444203, 444208, 444212, 444218, 444225, 444231, 444234,
+      444240, 444246, 444258, 444265, 444273, 444277, 444281, 444288, 444292, 444298, 444301,
+      444309, 444314, 444319, 444327, 444332, 444338, 444349, 444354, 444359, 444364, 444374,
+      444377, 444381, 444386, 444388, 444394, 444401, 444406, 444417, 444422, 444429, 444438,
+      444439, 444448, 444449, 444456, 444461, 444467, 444473, 444480, 444486, 444490, 444495,
+      444500, 444503, 444508, 444514, 444518, 444525, 444528, 444535, 444540, 444544, 444550,
+      444556, 444563, 444570, 444576, 444580, 444583, 444587, 444591, 444599, 444605, 444608,
+      444612, 444619, 444629, 444635, 444643, 444646, 444652, 444660, 444671, 444676, 444681,
+      444686, 444690, 444696, 444703, 444710, 444711, 444720, 444723, 444734, 444742, 444752,
+      444758, 444763, 444767, 444770, 444774, 444786, 444789, 444794, 444800, 444809, 444818,
+      444822, 444830, 444836, 444841, 444846, 444853, 444859, 444866, 444873, 444878, 444885,
+      444890, 444896, 444904, 444907, 444914, 444922, 444924, 444931, 446357, 488475, 495304,
+      496119, 497438, 498593, 498603, 498917, 499048, 499713, 500776, 501348, 503424, 508844,
+      518359, 519305, 519446, 523627, 523776, 523878, 523902, 524135, 524329, 524515, 524611,
+      524686, 524798, 524852, 525209, 525700, 525913, 525954, 526158, 526332, 526356, 536810,
+      537279, 563933, 578719, 579248, 579791, 584191, 591485, 592871, 613176, 615012, 616428,
+      619153, 636103, 640708, 643141, 645080, 646349, 647043, 649345, 651085, 652849, 653092,
+      653169, 653227, 653586, 655241, 656093, 658355, 658564, 659381, 659518, 690513, 693218,
+      693746, 694340, 694842, 695155, 695563, 695776, 696380, 697608, 697797, 698222, 698835,
+      699307, 700154, 700203, 700235, 700404, 700806, 700900, 701796, 702155, 702956, 702998,
+      705105, 705377, 705631, 708650, 709265, 709787, 725122, 735376, 737115, 737174, 738005,
+      741377, 741986, 746045, 746404, 746590, 748212, 753574, 754379, 764728, 765776, 766863,
+      769126, 782626, 782723, 783529, 786875, 787544, 807281, 811132, 821933, 822194, 829768,
+      830997, 831095, 832481, 834082, 844664, 845574, 845764, 846820, 849481, 855607, 857775,
+      872350, 876126, 902029, 903509, 904449, 904469, 905915, 910463, 911856, 924365, 928664,
+      929314, 929606, 929983, 930478, 933195, 933819, 935628, 935911, 935922, 936002, 937668,
+      941895, 942677, 943721, 944661, 944980, 945121, 945268, 945360, 950756, 951007, 959993,
+      960787, 961048, 961084, 961238, 961589, 962000, 962797, 962827, 962910, 963788, 964272,
+      964343, 964431, 964573, 964949, 965017, 965036, 965041, 965598, 965674, 965957, 966014,
+      966032, 966092, 966144, 966226, 966234, 966265, 966291, 978103, 980858, 987212, 987458,
+      987498, 988368, 988513, 988939, 990571, 993183, 1005493, 1007972, 1008230, 1009675, 1010075,
+      1010685, 1011441, 1011828, 1012269, 1012310, 1013612, 1013907, 1014379, 1018659, 1018923,
+      1022035, 1024567, 1024568, 1025024, 1026699, 1027212, 1027840, 1029108, 1031846, 1032670,
+      1032970, 1034016, 1039255, 1040626, 1040796, 1043457, 1043632, 1051053, 1052581, 1091611,
+      1092316, 1092564, 1092634, 1096386, 1096820, 1098606, 1104201, 1107101, 1110019, 1111384,
+      1111707, 1128990, 1129111, 1129147, 1129160, 1129367, 1129408, 1129508, 1129577, 1129699,
+      1129750, 1129840, 1129951, 1129988, 1130041, 1130139, 1130177, 1130241, 1130248, 1130268,
+      1130276, 1130367, 1130540, 1130562, 1130636, 1130637, 1130662, 1130716, 1131139, 1131218,
+      1131250, 1131454, 1131541, 1131775, 1132208, 1132280, 1132901, 1133264, 1133474, 1133475,
+      1133764, 1133841, 1133988, 1134290, 1134533, 1134553, 1134614, 1134667, 1134710, 1134861,
+      1134896, 1135008, 1135178, 1135544, 1135551, 1135573, 1136260, 1136385, 1136458, 1136782,
+      1136960, 1137342, 1137713, 1137824, 1138160, 1138291, 1138340, 1138457, 1138468, 1138516,
+      1138526, 1138610, 1138648, 1138700, 1138801, 1138869, 1138999, 1139010, 1139102, 1139114,
+      1139145, 1139302, 1139322, 1139417, 1139496, 1139581, 1139668, 1139852, 1139930, 1139958,
+      1140325, 1140616, 1140811, 1140861, 1141056, 1141197, 1141311, 1141346, 1141551, 1141666,
+      1141735, 1141786, 1141895, 1142017, 1142228, 1142242, 1142415, 1142484, 1142579, 1142599,
+      1142867, 1142929, 1143057, 1143132, 1143191, 1143203, 1143293, 1143476, 1143860, 1143997,
+      1144044, 1144321, 1144338, 1144459, 1144548, 1144564, 1144588, 1144592, 1144606, 1144623,
+      1144718, 1144792, 1144906, 1144997, 1145007, 1145082, 1145274, 1145380, 1145430, 1145584,
+      1145731, 1145778, 1145869, 1145914, 1145925, 1146025, 1146158, 1146212, 1146223, 1146448,
+      1146594, 1146663, 1146761, 1146803, 1146826, 1146833, 1146898, 1147078, 1147099, 1147330,
+      1147382, 1147424, 1147431, 1147472, 1147545, 1147592, 1147627, 1147657, 1147742, 1148005,
+      1148699, 1155013, 1155166, 1155915, 1178902, 1179255, 1180871, 1184802, 1187587, 1190670,
+      1198632, 1198646, 1198832, 1199211, 1199259, 1199330, 1200318, 1200824, 1200959, 1201200,
+      1202513, 1210077, 1210208, 1210296, 1211774, 1211775, 1211776, 1211777, 1212528, 1212529,
+      1212843, 1216377, 1219904, 1220650, 1232492, 1235492, 1243381, 1243807, 1267467, 1267561,
+      1267615, 1267691, 1267708, 1267731, 1267797, 1273165, 1278015, 1278076, 1278615, 1279032,
+      1279185, 1279756, 1281009, 1281074, 1282368, 1284002, 1284572, 1285041, 1285278, 1285788,
+      1285969, 1286573, 1286679, 1287001, 1287466, 1287714, 1287819, 1288542, 1288897, 1289486,
+      1290086, 1290286, 1291047, 1291363, 1291498, 1291749, 1291853, 1292129, 1292571, 1292828,
+      1292855, 1292859, 1292892, 1292893, 1292909, 1292910, 1292956, 1292957, 1292985, 1293133,
+      1293185, 1293926, 1294446, 1294490, 1294571, 1294966, 1295003, 1295395, 1295491, 1296604,
+      1298327, 1298527, 1298685, 1300235, 1300501, 1301193, 1301345, 1301536, 1301908, 1301969,
+      1301988, 1302146, 1302158, 1302810, 1303060, 1303244, 1303275, 1303487, 1303721, 1303831,
+      1303943, 1304875, 1305210, 1305677, 1305687, 1306397, 1306865, 1307044, 1307745, 1307926,
+      1308080, 1308680, 1309204, 1309475, 1310596, 1312574, 1313313, 1313764, 1313792, 1313963,
+      1314093, 1314284, 1314743, 1315154, 1315292, 1315503, 1315994, 1316517, 1316872, 1316909,
+      1317089, 1317327, 1318223, 1319657, 1321070, 1321083, 1321495, 1321517, 1322195, 1322221,
+      1322293, 1322330, 1322471, 1322496, 1322569, 1322634, 1322716, 1322859, 1323066, 1323356,
+      1323530, 1323539, 1323614, 1323868, 1323925, 1328650, 1329210, 1332937, 1333431, 1335482,
+      1338092, 1342268, 1345890, 1346245, 1346532, 1346613, 1346783, 1347371, 1347858, 1348077,
+      1348468, 1349166, 1349298, 1349335, 1350775, 1350809, 1351329, 1352877
+    };
+    int[] array2 = {
+      14402, 14403, 14404, 14405, 14406, 14407, 23246, 23247, 23248, 23249, 23250, 23936, 23937,
+      23938, 23939, 23940, 23941, 23942, 29721, 29722, 29723, 29724, 29725, 30226, 30227, 30228,
+      30229, 30230, 32141, 32142, 32143, 47737, 47738, 47739, 47740, 47741, 47742, 47743, 47744,
+      47745, 47746, 47747, 47748, 47749, 47750, 47751, 47752, 68770, 68771, 68772, 68773, 68774,
+      68775, 68776, 68777, 68778, 68779, 68780, 72301, 72302, 83071, 83072, 83073, 83074, 85302,
+      85303, 85304, 85305, 85306, 85307, 85308, 85309, 85310, 85311, 85312, 85313, 85314, 85315,
+      85316, 97108, 97109, 97110, 97111, 103442, 103443, 103444, 103445, 103446, 103447, 103448,
+      103449, 103450, 103451, 103452, 103453, 103454, 103455, 103456, 103457, 103458, 103459,
+      103460, 103461, 103462, 103463, 103464, 103465, 103466, 103467, 103468, 103469, 128488,
+      128489, 128490, 128491, 128492, 128493, 135003, 135004, 135005, 135006, 135007, 135008,
+      135009, 135010, 135011, 135012, 135013, 135014, 140363, 140364, 140365, 140366, 140367,
+      140368, 140369, 140370, 140371, 140372, 149844, 149845, 149846, 149847, 149848, 149849,
+      149850, 149851, 149852, 149853, 149854, 149855, 149856, 149857, 149858, 149859, 149860,
+      149861, 149862, 149863, 149864, 172805, 172806, 172807, 172808, 172809, 172810, 172811,
+      172812, 172813, 172814, 172815, 172816, 172817, 172818, 172819, 172820, 172821, 172822,
+      172823, 172824, 172825, 172826, 172827, 172828, 172829, 172830, 172831, 172832, 172833,
+      172834, 172835, 172836, 172837, 172838, 172839, 172840, 172841, 172842, 172843, 172844,
+      172845, 172846, 172847, 172848, 172849, 172850, 172851, 172852, 172853, 172854, 172855,
+      172856, 172857, 172858, 172859, 172860, 172861, 172862, 172863, 172864, 172865, 172866,
+      172867, 172868, 172869, 172870, 172871, 202530, 202531, 202532, 209488, 209489, 209490,
+      209491, 209492, 209493, 209494, 209495, 209496, 209497, 209498, 209499, 209500, 209501,
+      209502, 209503, 209504, 209505, 209506, 225554, 225555, 225556, 225557, 225558, 225559,
+      225560, 225561, 225562, 225563, 225564, 225565, 225566, 225567, 225568, 225569, 225570,
+      225571, 225572, 225573, 225574, 225575, 225576, 225577, 225578, 225579, 225580, 225581,
+      227917, 227918, 227919, 227920, 227921, 227922, 227923, 227924, 227925, 227926, 227927,
+      227928, 227929, 227930, 227931, 227932, 227933, 227934, 227935, 227936, 227937, 227938,
+      227939, 252773, 252774, 252775, 252776, 252777, 252778, 252779, 252780, 252781, 252782,
+      252783, 252784, 252785, 252786, 252787, 252788, 252789, 252790, 252791, 252792, 252793,
+      252794, 278695, 278696, 278697, 278698, 278699, 301237, 301238, 301239, 301240, 301241,
+      301242, 301243, 301244, 301245, 301246, 301247, 301248, 301249, 301250, 301251, 301252,
+      301253, 301254, 301255, 301256, 301257, 301258, 301259, 301260, 301261, 301262, 301263,
+      301264, 301265, 320515, 320516, 320517, 320518, 320519, 320520, 320521, 320522, 320523,
+      320524, 320525, 320526, 320527, 320528, 320529, 320530, 320531, 320532, 320533, 320534,
+      320535, 320536, 320537, 320538, 320539, 320540, 320541, 320542, 320543, 320544, 320545,
+      320546, 320547, 320548, 329641, 329642, 329643, 329644, 329645, 329646, 329647, 329648,
+      329649, 329650, 329651, 329652, 329653, 329654, 329655, 329656, 329657, 329658, 329659,
+      342703, 342704, 342705, 342706, 349520, 349521, 349522, 349523, 349524, 349525, 349526,
+      349527, 349528, 349529, 349530, 362716, 362717, 362718, 362719, 362720, 362721, 362722,
+      362723, 362724, 362725, 362726, 362727, 378643, 378644, 378645, 378646, 390154, 390155,
+      390156, 390157, 390158, 390159, 390160, 390161, 390162, 390163, 390164, 390165, 390166,
+      390167, 390168, 390169, 395108, 395109, 395110, 395111, 395112, 395113, 395114, 395115,
+      403260, 403261, 403262, 403263, 403264, 403265, 403266, 403267, 403268, 403269, 403270,
+      403271, 417315, 417316, 417317, 417318, 417319, 417320, 432653, 432654, 432655, 432656,
+      432657, 432658, 432659, 432660, 432661, 432662, 432663, 432664, 432665, 432666, 432667,
+      432668, 432669, 432670, 432671, 432672, 432673, 432674, 432675, 432676, 432677, 432678,
+      449394, 449395, 449396, 449397, 449398, 459961, 459962, 459963, 459964, 474537, 474538,
+      474539, 474540, 474541, 474542, 474543, 474544, 474545, 474546, 474547, 474548, 474549,
+      474550, 474551, 474552, 474553, 474554, 474555, 474556, 474557, 474558, 474559, 474560,
+      474561, 474562, 474563, 474564, 474565, 474566, 474567, 474568, 474569, 474570, 474571,
+      474572, 474573, 474574, 474575, 474576, 474577, 474578, 474579, 474580, 474581, 474582,
+      474583, 474584, 474585, 474586, 474587, 474588, 474589, 474590, 474591, 474592, 474593,
+      474594, 474595, 474596, 474597, 483571, 483572, 483573, 483574, 483575, 483576, 489641,
+      489642, 489643, 489644, 489645, 489646, 489647, 489648, 489649, 489650, 489651, 491296,
+      491297, 491298, 495868, 495869, 495870, 502769, 502770, 502771, 502772, 502773, 502774,
+      502775, 502776, 502777, 502778, 502779, 502780, 502781, 502782, 502783, 513810, 513811,
+      513812, 513813, 513814, 513815, 513816, 513817, 513818, 513819, 513820, 513821, 513822,
+      513823, 513824, 513825, 513826, 513827, 513828, 513829, 513830, 513831, 513832, 517220,
+      517221, 517222, 517223, 517224, 517225, 517226, 517227, 519778, 519779, 519780, 519781,
+      519782, 519783, 519784, 519785, 524240, 524241, 524242, 524243, 524244, 524245, 524246,
+      524247, 524248, 524249, 527255, 527256, 527257, 527258, 527259, 533697, 533698, 533699,
+      533700, 533701, 533702, 533703, 533704, 533705, 533706, 533707, 533708, 533709, 539237,
+      539238, 539239, 539240, 539241, 539242, 539243, 562203, 562204, 562205, 562206, 569773,
+      569774, 569775, 569776, 569777, 569778, 569779, 569780, 569781, 569782, 569783, 569784,
+      569785, 569786, 569787, 569788, 569789, 569790, 569791, 569792, 569793, 569794, 569795,
+      569796, 569797, 569798, 569799, 569800, 569801, 569802, 569803, 569804, 569805, 569806,
+      569807, 569808, 569809, 569810, 569811, 569812, 569813, 569814, 569815, 569816, 569817,
+      569818, 569819, 569820, 569821, 580161, 580162, 580163, 580164, 580165, 580166, 580167,
+      580168, 580169, 580170, 580171, 580172, 580173, 580174, 580175, 580176, 588299, 588300,
+      588301, 588302, 588303, 588304, 588305, 588306, 588307, 588308, 588309, 588310, 588311,
+      588312, 588313, 588314, 588315, 588316, 588317, 588318, 588319, 588320, 588321, 588322,
+      588323, 588324, 588325, 588326, 588327, 588328, 588329, 588330, 588331, 588332, 588333,
+      588334, 588335, 608580, 608581, 608582, 608583, 608584, 608585, 608586, 608587, 608588,
+      608589, 608590, 608591, 608592, 608593, 608594, 608595, 608596, 608597, 608598, 608599,
+      608600, 608601, 608602, 608603, 608604, 608605, 618326, 618327, 618328, 618329, 618330,
+      618331, 618332, 618333, 618334, 618335, 618336, 618337, 618338, 618339, 618340, 618341,
+      618342, 618343, 618344, 618345, 618346, 618347, 618348, 618349, 626895, 626896, 626897,
+      626898, 626899, 626900, 635313, 635314, 635315, 635316, 635317, 635318, 635319, 635320,
+      635321, 635322, 635323, 635324, 635325, 635326, 635327, 635328, 635329, 635330, 635331,
+      635332, 635333, 635334, 635335, 635336, 635337, 635338, 635339, 635340, 635341, 635342,
+      635343, 635344, 635345, 635346, 635347, 635348, 635349, 635350, 635351, 635352, 635353,
+      635354, 635355, 648087, 648088, 648089, 648090, 648091, 648092, 648093, 648094, 648095,
+      648096, 648097, 648098, 648099, 648100, 648101, 648102, 648103, 648104, 648105, 648106,
+      648107, 648108, 648109, 648110, 661574, 661575, 661576, 661577, 674566, 674567, 674568,
+      674569, 674570, 674571, 674572, 674573, 674574, 674575, 674576, 674577, 674578, 674579,
+      674580, 674581, 674582, 674583, 674584, 674585, 689328, 689329, 689330, 689331, 689332,
+      689333, 689334, 689335, 689336, 689337, 697978, 697979, 697980, 697981, 697982, 697983,
+      697984, 697985, 697986, 697987, 697988, 697989, 697990, 697991, 697992, 697993, 697994,
+      726676, 726677, 726678, 726679, 726680, 726681, 782220, 782221, 782222, 782223, 782224,
+      782225, 782226, 782227, 782228, 782229, 782230, 782231, 782232, 782233, 782234, 782235,
+      782236, 782237, 782238, 782239, 797574, 797575, 797576, 797577, 797578, 797579, 797580,
+      797581, 797582, 804283, 804284, 804285, 822332, 822333, 822334, 822335, 822336, 831020,
+      831021, 831022, 831023, 831024, 831025, 831026, 831027, 831028, 831029, 831030, 831031,
+      831032, 831033, 831034, 831035, 831036, 831037, 831038, 831039, 831040, 847227, 847228,
+      847229, 847230, 847231, 847232, 847233, 847234, 847235, 847236, 847237, 847238, 847239,
+      847240, 847241, 847242, 847243, 847244, 847245, 857616, 857617, 857618, 857619, 857620,
+      857621, 857622, 857623, 857624, 857625, 867324, 867325, 867326, 867327, 867328, 867329,
+      867330, 867331, 867332, 867333, 867334, 867335, 867336, 867337, 867338, 867339, 877587,
+      877588, 877589, 877590, 877591, 877592, 877593, 877594, 877595, 877596, 877597, 877598,
+      877599, 877600, 877601, 877602, 877603, 877604, 877605, 877606, 877607, 877608, 877609,
+      877610, 877611, 877612, 877613, 877614, 877615, 896235, 896236, 896237, 896238, 896239,
+      896240, 916629, 916630, 916631, 916632, 929361, 929362, 929363, 929364, 929365, 929366,
+      929367, 929368, 929369, 929370, 929371, 948695, 948696, 948697, 948698, 948699, 948700,
+      948701, 948702, 949573, 949574, 957768, 957769, 957770, 957771, 957772, 957773, 957774,
+      957775, 961032, 961033, 961034, 961035, 987440, 987441, 987442, 987443, 1001434, 1001435,
+      1001436, 1001437, 1001438, 1001439, 1001440, 1001441, 1001442, 1001443, 1001444, 1001445,
+      1001446, 1001447, 1001448, 1001449, 1001450, 1001451, 1001452, 1001453, 1001454, 1001455,
+      1001456, 1001457, 1001458, 1001459, 1001460, 1009985, 1009986, 1009987, 1009988, 1009989,
+      1037191, 1037192, 1037193, 1037194, 1037195, 1037196, 1037197, 1037198, 1037199, 1037200,
+      1037201, 1037202, 1037203, 1037204, 1053198, 1053199, 1053200, 1053201, 1053202, 1053203,
+      1053204, 1053205, 1053206, 1053207, 1053208, 1053209, 1053210, 1053211, 1053212, 1053213,
+      1053214, 1053215, 1053216, 1053217, 1053218, 1053219, 1053220, 1053221, 1053222, 1053223,
+      1053224, 1084019, 1084020, 1084021, 1084022, 1084023, 1084024, 1084025, 1088361, 1088362,
+      1088363, 1088364, 1088365, 1088366, 1089312, 1089313, 1089314, 1089315, 1089316, 1089317,
+      1089318, 1092235, 1092236, 1092237, 1092238, 1092239, 1092240, 1092241, 1092242, 1092243,
+      1092244, 1102836, 1102837, 1102838, 1102839, 1102840, 1102841, 1102842, 1102843, 1102844,
+      1102845, 1102846, 1102847, 1108575, 1108576, 1108577, 1108578, 1108579, 1108580, 1108581,
+      1108582, 1108583, 1108584, 1108585, 1108586, 1108587, 1108588, 1108589, 1108590, 1108591,
+      1108592, 1108593, 1108594, 1108595, 1108596, 1108597, 1108598, 1134091, 1134092, 1134093,
+      1134094, 1134095, 1134096, 1134097, 1134098, 1134099, 1134100, 1134101, 1134102, 1134103,
+      1134104, 1134105, 1134106, 1134107, 1134108, 1134109, 1134110, 1134111, 1134112, 1134113,
+      1134114, 1134115, 1134116, 1134117, 1134118, 1134119, 1134120, 1134121, 1134122, 1134123,
+      1134124, 1134125, 1134126, 1134127, 1134128, 1134129, 1151732, 1151733, 1151734, 1151735,
+      1151736, 1151737, 1151738, 1151739, 1151740, 1151741, 1151742, 1151743, 1151744, 1151745,
+      1151746, 1151747, 1199223, 1199224, 1199225, 1199226, 1203252, 1203253, 1203254, 1203255,
+      1203256, 1203257, 1203258, 1203259, 1203260, 1217223, 1217224, 1217225, 1217226, 1226505,
+      1226506, 1226507, 1226508, 1226509, 1226510, 1226511, 1226512, 1231411, 1231412, 1231413,
+      1231414, 1231415, 1231416, 1231417, 1231418, 1231419, 1231420, 1231421, 1231422, 1231423,
+      1243464, 1243465, 1243466, 1243467, 1243468, 1243469, 1243470, 1247919, 1247920, 1247921,
+      1255972, 1255973, 1255974, 1255975, 1255976, 1255977, 1255978, 1255979, 1255980, 1263675,
+      1263676, 1263677, 1263678, 1263679, 1277693, 1277694, 1277695, 1277696, 1277697, 1277698,
+      1277699, 1277700, 1283492, 1283493, 1283494, 1283495, 1283496, 1283497, 1283498, 1283499,
+      1283500, 1283501, 1283502, 1283503, 1283504, 1283505, 1283506, 1283507, 1283508, 1283509,
+      1283510, 1283511, 1283512, 1283513, 1283514, 1325789, 1325790, 1325791, 1325792, 1325793,
+      1325794, 1325795, 1325796, 1325797, 1325798, 1325799
+    };
     MutableRoaringBitmap rb1 = MutableRoaringBitmap.bitmapOf(array1);
     MutableRoaringBitmap rb2 = MutableRoaringBitmap.bitmapOf(array2);
     MutableRoaringBitmap rrb1 = rb1.clone();
@@ -858,8 +875,10 @@ public void testOr001() {
 
   @Test
   public void testAndNot() {
-    int[] array1 = {39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183,
-        39184, 39185, 39186, 39187, 39188};
+    int[] array1 = {
+      39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183, 39184, 39185,
+      39186, 39187, 39188
+    };
     int[] array2 = {14205};
     MutableRoaringBitmap rb1 = MutableRoaringBitmap.bitmapOf(array1);
     MutableRoaringBitmap rb2 = MutableRoaringBitmap.bitmapOf(array2);
@@ -909,7 +928,6 @@ public void testHighBits() {
     }
   }
 
-
   @Test
   public void testCheckedRemove() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -932,7 +950,6 @@ public void testCheckedRemove() {
     }
   }
 
-
   @Test
   public void testCheckedAdd() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -980,13 +997,13 @@ public void testSetUtilIntersection() {
     assertTrue(Arrays.equals(expectedresult, result));
   }
 
-
   @Test
   public void testXORSimple() {
     MutableRoaringBitmap a = MutableRoaringBitmap.bitmapOf(73647, 83469);
-    MutableRoaringBitmap b = MutableRoaringBitmap.bitmapOf(1, 2, 3, 5, 6, 8, 9, 10, 11, 13, 14, 16,
-        17, 18, 19, 20, 21, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 39, 40, 41, 50, 51, 69,
-        79, 80, 81, 88, 89, 172);
+    MutableRoaringBitmap b =
+        MutableRoaringBitmap.bitmapOf(
+            1, 2, 3, 5, 6, 8, 9, 10, 11, 13, 14, 16, 17, 18, 19, 20, 21, 25, 26, 27, 28, 29, 30, 32,
+            33, 34, 35, 36, 37, 39, 40, 41, 50, 51, 69, 79, 80, 81, 88, 89, 172);
     MutableRoaringBitmap rxor = ImmutableRoaringBitmap.xor(a, b);
     MutableRoaringBitmap ror = MutableRoaringBitmap.or(a, b);
     assertTrue(rxor.equals(ror));
@@ -1009,25 +1026,23 @@ public void testRank() {
     }
   }
 
-
   @Test
   public void testRankBigInts() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
     for (int k = 0; k < 100000; k += 7) {
-      rb.add((1<<31)+k);
+      rb.add((1 << 31) + k);
     }
     for (int k = 100000; k < 200000; k += 1000) {
-      rb.add((1<<31)+k);
+      rb.add((1 << 31) + k);
     }
     for (int k = 0; k < 100000; ++k) {
-      assertEquals(1 + k / 7, rb.rank((1<<31)+k));
+      assertEquals(1 + k / 7, rb.rank((1 << 31) + k));
     }
     for (int k = 100000; k < 200000; ++k) {
-      assertEquals(1 + 100000 / 7 + 1 + (k - 100000) / 1000, rb.rank((1<<31)+k));
+      assertEquals(1 + 100000 / 7 + 1 + (k - 100000) / 1000, rb.rank((1 << 31) + k));
     }
   }
 
-
   @Test
   public void testSelect() {
     for (int gap = 1; gap <= 1024; gap *= 2) {
@@ -1041,16 +1056,15 @@ public void testSelect() {
     }
   }
 
-
   @Test
   public void testSelectBigInts() {
     for (int gap = 1; gap <= 1024; gap *= 2) {
       MutableRoaringBitmap rb = new MutableRoaringBitmap();
       for (int k = 0; k < 100000; k += gap) {
-        rb.add((1<<31)+k);
+        rb.add((1 << 31) + k);
       }
       for (int k = 0; k < 100000 / gap; ++k) {
-        assertEquals((1<<31)+k * gap, rb.select(k));
+        assertEquals((1 << 31) + k * gap, rb.select(k));
       }
     }
   }
@@ -1072,14 +1086,12 @@ public void testLimit() {
     }
   }
 
-
-
   @Test
   public void testLimitBitInts() {
     for (int gap = 1; gap <= 1024; gap *= 2) {
       MutableRoaringBitmap rb = new MutableRoaringBitmap();
       for (int k = 0; k < 100000; k += gap) {
-          rb.add((1<<31)+k);
+        rb.add((1 << 31) + k);
       }
       int thiscard = rb.getCardinality();
       for (int k = 0; k < thiscard; k += 100) {
@@ -1091,59 +1103,69 @@ public void testLimitBitInts() {
     }
   }
 
-
   @Test
   public void testHorizontalOrCardinality() {
     int[] vals = {65535, 131071, 196607, 262143, 327679, 393215, 458751, 524287};
     final MutableRoaringBitmap[] b = new MutableRoaringBitmap[2];
     b[0] = MutableRoaringBitmap.bitmapOf(vals);
     b[1] = MutableRoaringBitmap.bitmapOf(vals);
-    MutableRoaringBitmap a = BufferFastAggregation.or(new Iterator() {
-      int k = 0;
-
-      @Override
-      public boolean hasNext() {
-        return k < b.length;
-      }
-
-      @Override
-      public void remove() {}
-
-      @Override
-      public ImmutableRoaringBitmap next() {
-        return b[k++];
-      }
-    });
+    MutableRoaringBitmap a =
+        BufferFastAggregation.or(
+            new Iterator() {
+              int k = 0;
+
+              @Override
+              public boolean hasNext() {
+                return k < b.length;
+              }
+
+              @Override
+              public void remove() {}
+
+              @Override
+              public ImmutableRoaringBitmap next() {
+                return b[k++];
+              }
+            });
     assertEquals(8, a.getCardinality());
   }
 
-
- @Test
+  @Test
   public void testHorizontalOrCardinalityBigInts() {
-     int[] vals = {(1<<31)+65535, (1<<31)+131071, (1<<31)+196607, (1<<31)+262143, (1<<31)+327679, (1<<31)+393215, (1<<31)+458751, (1<<31)+524287};
+    int[] vals = {
+      (1 << 31) + 65535,
+      (1 << 31) + 131071,
+      (1 << 31) + 196607,
+      (1 << 31) + 262143,
+      (1 << 31) + 327679,
+      (1 << 31) + 393215,
+      (1 << 31) + 458751,
+      (1 << 31) + 524287
+    };
     final MutableRoaringBitmap[] b = new MutableRoaringBitmap[2];
     b[0] = MutableRoaringBitmap.bitmapOf(vals);
     b[1] = MutableRoaringBitmap.bitmapOf(vals);
-    MutableRoaringBitmap a = BufferFastAggregation.or(new Iterator() {
-      int k = 0;
-
-      @Override
-      public boolean hasNext() {
-        return k < b.length;
-      }
-
-      @Override
-      public void remove() {}
-
-      @Override
-      public ImmutableRoaringBitmap next() {
-        return b[k++];
-      }
-    });
+    MutableRoaringBitmap a =
+        BufferFastAggregation.or(
+            new Iterator() {
+              int k = 0;
+
+              @Override
+              public boolean hasNext() {
+                return k < b.length;
+              }
+
+              @Override
+              public void remove() {}
+
+              @Override
+              public ImmutableRoaringBitmap next() {
+                return b[k++];
+              }
+            });
     assertEquals(8, a.getCardinality());
   }
 
-
   @Test
   public void testContains() throws IOException {
     MutableRoaringBitmap rbm1 = new MutableRoaringBitmap();
@@ -1263,7 +1285,6 @@ public void andnottest4() {
     assertEquals(rb2, off);
     rb2.andNot(rb);
     assertEquals(rb2, off);
-
   }
 
   @Test
@@ -1430,7 +1451,6 @@ public void andtest3() {
     final int[] arrayres = rrand.toArray();
 
     assertTrue(Arrays.equals(arrayand, arrayres));
-
   }
 
   @Test
@@ -1473,7 +1493,6 @@ public void andtest4() {
     final MutableRoaringBitmap rc = MutableRoaringBitmap.and(rb, rb2);
     rb.and(rb2);
     assertEquals(rc.getCardinality(), rb.getCardinality());
-
   }
 
   @Test
@@ -1523,7 +1542,7 @@ public void trimTest() {
     MappeableContainerPointer cp = ra.getContainerPointer();
     while (cp.getContainer() != null) {
       if (cp.isBitmapContainer()) {
-        ; //nothing wasted
+        ; // nothing wasted
       } else if (cp.isRunContainer()) {
         MappeableRunContainer rc = (MappeableRunContainer) cp.getContainer();
         wastedBytes += Short.BYTES * (rc.valueslength.limit() - rc.numberOfRuns());
@@ -1567,7 +1586,7 @@ public void basictest() {
     rr.add(110000);
     a[pos++] = 110000;
     final int[] array = rr.toArray();
- 
+
     assertTrue(Arrays.equals(array, a));
   }
 
@@ -1633,8 +1652,7 @@ public void cardinalityTest() {
         }
         assertEquals(MutableRoaringBitmap.and(rb, rb2).getCardinality(), N / offset);
         assertEquals(MutableRoaringBitmap.or(rb, rb2).getCardinality(), 2 * N - N / offset);
-        assertEquals(MutableRoaringBitmap.xor(rb, rb2).getCardinality(),
-            2 * N - 2 * N / offset);
+        assertEquals(MutableRoaringBitmap.xor(rb, rb2).getCardinality(), 2 * N - 2 * N / offset);
       }
     }
   }
@@ -1993,17 +2011,16 @@ public void flipTest7A() { // within 1 word, first container
   @Test
   public void flipTestBigInt() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
-    rb.add( Integer.MAX_VALUE + 100000);
-    rb.add( Integer.MAX_VALUE + 100002);
-    final MutableRoaringBitmap rb2 = MutableRoaringBitmap.flip(rb, Integer.MAX_VALUE+100001L , 
-                                                     Integer.MAX_VALUE+200000L);
+    rb.add((int) (Integer.MAX_VALUE + 100000L));
+    rb.add((int) (Integer.MAX_VALUE + 100002L));
+    final MutableRoaringBitmap rb2 =
+        MutableRoaringBitmap.flip(rb, Integer.MAX_VALUE + 100001L, Integer.MAX_VALUE + 200000L);
     assertEquals(99999, rb2.getCardinality());
-    assertTrue(rb2.contains(Integer.MAX_VALUE+100000));
-    assertFalse(rb2.contains(Integer.MAX_VALUE+100002));
-    assertTrue(rb2.contains(Integer.MAX_VALUE+199999));
+    assertTrue(rb2.contains((int) (Integer.MAX_VALUE + 100000L)));
+    assertFalse(rb2.contains((int) (Integer.MAX_VALUE + 100002L)));
+    assertTrue(rb2.contains((int) (Integer.MAX_VALUE + 199999L)));
   }
 
-
   @Test
   public void flipTestBig() {
     final int numCases = 1000;
@@ -2019,9 +2036,8 @@ public void flipTestBig() {
         end = start + r.nextInt(100);
       }
       rb.flip(start, end);
-      if (start < end)
-       {
-           bs.flip((int)start, (int) end); // throws exception
+      if (start < end) {
+        bs.flip((int) start, (int) end); // throws exception
       }
       // otherwise
       // insert some more ANDs to keep things sparser
@@ -2031,7 +2047,7 @@ public void flipTestBig() {
         final long startM = r.nextInt(65536 * 20);
         final long endM = startM + 100000;
         mask.flip(startM, endM);
-        mask1.flip((int)startM, (int)endM);
+        mask1.flip((int) startM, (int) endM);
         mask.flip(0L, 65536L * 20 + 100000);
         mask1.flip(0, 65536 * 20 + 100000);
         rb.and(mask);
@@ -2068,20 +2084,19 @@ public void flipTestBigA() {
       }
 
       if ((i & 1) == 0) {
-        rb2 = MutableRoaringBitmap.flip(rb1, (long)start, (long)end);
+        rb2 = MutableRoaringBitmap.flip(rb1, (long) start, (long) end);
         // tweak the other, catch bad sharing
         long r1 = r.nextInt(65536 * 20);
         long r2 = r.nextInt(65536 * 20);
         rb1.flip(r1, r2);
       } else {
-        rb1 = MutableRoaringBitmap.flip(rb2, (long) start,(long) end);
+        rb1 = MutableRoaringBitmap.flip(rb2, (long) start, (long) end);
         long r1 = r.nextInt(65536 * 20);
         long r2 = r.nextInt(65536 * 20);
         rb2.flip(r1, r2);
       }
 
-      if (start < end)
-       {
+      if (start < end) {
         bs.flip(start, end); // throws exception
       }
       // otherwise
@@ -2091,7 +2106,7 @@ public void flipTestBigA() {
         final BitSet mask1 = new BitSet();
         final int startM = r.nextInt(65536 * 20);
         final int endM = startM + 100000;
-        mask.flip((long)startM, (long)endM);
+        mask.flip((long) startM, (long) endM);
         mask1.flip(startM, endM);
         mask.flip(0L, 65536L * 20 + 100000);
         mask1.flip(0, 65536 * 20 + 100000);
@@ -2147,7 +2162,6 @@ public void ortest() {
     rr.or(rr2);
     final int[] arrayirr = rr.toArray();
     assertTrue(Arrays.equals(array, arrayirr));
-
   }
 
   @Test
@@ -2352,7 +2366,6 @@ public void ortest4() {
     assertEquals(rb2.getCardinality() + rb.getCardinality(), orresult2.getCardinality());
     rb.or(rb2);
     assertTrue(rb.equals(orresult2));
-
   }
 
   @Test
@@ -2363,11 +2376,11 @@ public void orNot() {
     rb.add(2);
     rb.add(1);
     rb.add(1 << 16); // 65 536
-    rb.add(2 << 16); //131 072
-    rb.add(3 << 16); //196 608
+    rb.add(2 << 16); // 131 072
+    rb.add(3 << 16); // 196 608
 
-    rb2.add(1 << 16);// 65 536
-    rb2.add(3 << 16);//196 608
+    rb2.add(1 << 16); // 65 536
+    rb2.add(3 << 16); // 196 608
 
     rb.orNot(rb2, (4 << 16) - 1);
 
@@ -2382,7 +2395,6 @@ public void orNot() {
     assertFalse(iterator.hasNext());
   }
 
-
   @Test
   public void orNotRegressionTest() {
     long len = 3L;
@@ -2419,7 +2431,6 @@ public void orNotLimitLowerThanFirstPreservesBitmap() {
     assertEquals(one, MutableRoaringBitmap.bitmapOf(32));
   }
 
-
   @Test
   public void orNotLimitHigherThanFirstBitPreservesBitmap() {
     MutableRoaringBitmap one = new MutableRoaringBitmap();
@@ -2439,9 +2450,9 @@ public void orNotWithSparseBitmaps() {
 
     rb.add(0);
     rb.add(1 << 16); // 65 536
-    rb.add(3 << 16); //196 608
+    rb.add(3 << 16); // 196 608
 
-    rb2.add((4 << 16) - 1); //262 143
+    rb2.add((4 << 16) - 1); // 262 143
 
     rb.orNot(rb2, 4 << 16);
 
@@ -2462,8 +2473,8 @@ public void orNotWithOtherBiggerThanOriginal() {
     rb.add(1);
 
     MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-    rb2.add(1 << 14); //16 384
-    rb2.add(3 << 16); //196 608
+    rb2.add(1 << 14); // 16 384
+    rb2.add(3 << 16); // 196 608
 
     rb.orNot(rb2, (5 << 16));
     assertEquals((5 << 16) - 2, rb.getCardinality());
@@ -2484,9 +2495,9 @@ public void orNotWithOtherBiggerThanOriginalAndEndRange() {
     rb.add(1);
 
     final MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
-    rb2.add(3 << 16); //196 608
+    rb2.add(3 << 16); // 196 608
 
-    rb.orNot(rb2, (2 << 16) + (2 << 14)); //131 072 + 32 768 = 163 840
+    rb.orNot(rb2, (2 << 16) + (2 << 14)); // 131 072 + 32 768 = 163 840
     assertEquals((2 << 16) + (2 << 14), rb.getCardinality());
 
     final IntIterator iterator = rb.getIntIterator();
@@ -2503,8 +2514,8 @@ public void orNotWithOriginalBiggerThanOther() {
 
     rb.add(1);
     rb.add(1 << 16); // 65 536
-    rb.add(2 << 16); //131 072
-    rb.add(3 << 16); //196 608
+    rb.add(2 << 16); // 131 072
+    rb.add(3 << 16); // 196 608
 
     MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
 
@@ -2526,8 +2537,8 @@ public void orNotWithOriginalBiggerThanOther2() {
     rb.add(1);
     rb.add((1 << 16) - 1); // 65 535
     rb.add(1 << 16); // 65 536
-    rb.add(2 << 16); //131 072
-    rb.add(3 << 16); //196 608
+    rb.add(2 << 16); // 131 072
+    rb.add(3 << 16); // 196 608
 
     MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
 
@@ -2566,7 +2577,6 @@ public void randomTest() {
     rTest(65536 * 16);
   }
 
-
   public void rTest(final int N) {
     for (int gap = 1; gap <= 65536; gap *= 2) {
       final BitSet bs1 = new BitSet();
@@ -2609,10 +2619,14 @@ public void rTest(final int N) {
             throw new RuntimeException("bug inplace and");
           }
           if (!t.equals(MutableRoaringBitmap.and(rb1, rb2))) {
-            System.out
-                .println(t.highLowContainer.getContainerAtIndex(0).getClass().getCanonicalName());
-            System.out.println(MutableRoaringBitmap.and(rb1, rb2).highLowContainer
-                .getContainerAtIndex(0).getClass().getCanonicalName());
+            System.out.println(
+                t.highLowContainer.getContainerAtIndex(0).getClass().getCanonicalName());
+            System.out.println(
+                MutableRoaringBitmap.and(rb1, rb2)
+                    .highLowContainer
+                    .getContainerAtIndex(0)
+                    .getClass()
+                    .getCanonicalName());
 
             throw new RuntimeException("bug inplace and");
           }
@@ -2637,7 +2651,6 @@ public void rTest(final int N) {
           if (!t.toString().equals(MutableRoaringBitmap.or(rb1, rb2).toString())) {
             throw new RuntimeException("bug or");
           }
-
         }
         // testing XOR
         clonebs1 = (BitSet) bs1.clone();
@@ -2655,8 +2668,8 @@ public void rTest(final int N) {
           if (!t.equals(MutableRoaringBitmap.xor(rb1, rb2))) {
             System.out.println(t);
             System.out.println(MutableRoaringBitmap.xor(rb1, rb2));
-            System.out
-                .println(Arrays.equals(t.toArray(), MutableRoaringBitmap.xor(rb1, rb2).toArray()));
+            System.out.println(
+                Arrays.equals(t.toArray(), MutableRoaringBitmap.xor(rb1, rb2).toArray()));
             throw new RuntimeException("bug xor");
           }
         }
@@ -2705,7 +2718,6 @@ public void rTest(final int N) {
           }
         }
       }
-
     }
   }
 
@@ -2724,7 +2736,6 @@ public void simplecardinalityTest() {
       rb.add(k * gap);
       assertEquals(rb.getCardinality(), N);
     }
-
   }
 
   @Test
@@ -2759,12 +2770,11 @@ public void testSerialization() throws IOException, ClassNotFoundException {
     assertTrue(rr.equals(rrback));
   }
 
-
   @Test
   public void testSerializationBigInts() throws IOException, ClassNotFoundException {
     final MutableRoaringBitmap rr = new MutableRoaringBitmap();
     for (int k = 65000; k < 2 * 65000; ++k) {
-        rr.add((1<<31)+k);
+      rr.add((1 << 31) + k);
     }
     final ByteArrayOutputStream bos = new ByteArrayOutputStream();
     // Note: you could use a file output steam instead of
@@ -2841,7 +2851,6 @@ public void testSerialization4() throws IOException, ClassNotFoundException {
     assertTrue(rr.equals(rrback));
   }
 
-
   @Test
   public void sparseXor() {
     final MutableRoaringBitmap rr1 = new MutableRoaringBitmap();
@@ -2857,7 +2866,6 @@ public void sparseXor() {
     assertTrue(xor.contains(1));
   }
 
-
   @Test
   public void XORtest() {
     final MutableRoaringBitmap rr = new MutableRoaringBitmap();
@@ -2941,15 +2949,14 @@ public void testIterator() {
     assertTrue(copy2.equals(rb));
   }
 
-
   @Test
   public void testIteratorBigInts() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
     for (int k = 0; k < 4000; ++k) {
-      rb.add((1<<31)+k);
+      rb.add((1 << 31) + k);
     }
     for (int k = 0; k < 1000; ++k) {
-      rb.add((1<<31)+k * 100);
+      rb.add((1 << 31) + k * 100);
     }
     MutableRoaringBitmap copy1 = new MutableRoaringBitmap();
     for (int x : rb) {
@@ -2976,10 +2983,6 @@ public void testIteratorBigInts() {
     assertTrue(copy2.equals(rb));
   }
 
-
-
-
-  
   @Test
   public void testIteratorMapped() {
     MutableRoaringBitmap orb = new MutableRoaringBitmap();
@@ -3013,16 +3016,15 @@ public void testIteratorMapped() {
     }
     assertTrue(copy2.equals(toMapped(orb)));
   }
- 
 
- @Test
+  @Test
   public void testIteratorMappedBigInts() {
     MutableRoaringBitmap orb = new MutableRoaringBitmap();
     for (int k = 0; k < 4000; ++k) {
-        orb.add((1<<32)+k);
+      orb.add((1 << 31) + k);
     }
     for (int k = 0; k < 1000; ++k) {
-      orb.add((1<<32)+k * 100);
+      orb.add((1 << 31) + k * 100);
     }
     MutableRoaringBitmap ocopy1 = new MutableRoaringBitmap();
     for (int x : orb) {
@@ -3048,10 +3050,8 @@ public void testIteratorMappedBigInts() {
     }
     assertTrue(copy2.equals(toMapped(orb)));
   }
- 
-
 
- @Test
+  @Test
   public void xortest1() {
     final HashSet V1 = new HashSet();
     final HashSet V2 = new HashSet();
@@ -3175,7 +3175,6 @@ public void xortest4() {
     assertEquals(rb2.getCardinality() + rb.getCardinality(), xorresult2.getCardinality());
     rb.xor(rb2);
     assertTrue(xorresult2.equals(rb));
-
   }
 
   boolean validate(MappeableBitmapContainer bc, MappeableArrayContainer ac) {
@@ -3213,8 +3212,6 @@ public static boolean equals(BitSet bs, MutableRoaringBitmap rr) {
     return Arrays.equals(rr.toArray(), a);
   }
 
-
-
   /**
    * Test massive and.
    */
@@ -3229,7 +3226,7 @@ public void testMassiveAnd() {
       ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k);
     }
     for (int k = 3; k < ewah.length; k += 3) {
-        ewah[k].flip(13L, (long) howmany / 2);
+      ewah[k].flip(13L, (long) howmany / 2);
     }
     for (int N = 2; N < ewah.length; ++N) {
       MutableRoaringBitmap answer = ewah[0];
@@ -3245,13 +3242,10 @@ public void testMassiveAnd() {
       MutableRoaringBitmap answer2b = BufferFastAggregation.and(z);
       assertTrue(answer.equals(answer2b));
       assertTrue(answer.getCardinality() == answer2b.getCardinality());
-
     }
   }
 
-
-
- @Test
+  @Test
   public void testMassiveAndBigInts() {
     MutableRoaringBitmap[] ewah = new MutableRoaringBitmap[1024];
     for (int k = 0; k < ewah.length; ++k) {
@@ -3259,10 +3253,10 @@ public void testMassiveAndBigInts() {
     }
     int howmany = 1000000;
     for (int k = 0; k < howmany; ++k) {
-        ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1<<31)+k);
+      ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k);
     }
     for (int k = 3; k < ewah.length; k += 3) {
-        ewah[k].flip( (1L<<31)+13L,  (1L<<31)+(long) howmany / 2);
+      ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2);
     }
     for (int N = 2; N < ewah.length; ++N) {
       MutableRoaringBitmap answer = ewah[0];
@@ -3278,11 +3272,9 @@ public void testMassiveAndBigInts() {
       MutableRoaringBitmap answer2b = BufferFastAggregation.and(z);
       assertTrue(answer.equals(answer2b));
       assertTrue(answer.getCardinality() == answer2b.getCardinality());
-
     }
   }
 
-
   private static  Iterator toIterator(final T[] x) {
     return new Iterator() {
       int pos = 0;
@@ -3295,7 +3287,6 @@ public boolean hasNext() {
       @Override
       public void remove() {}
 
-
       @Override
       public T next() {
         return x[pos++];
@@ -3303,7 +3294,6 @@ public T next() {
     };
   }
 
-
   /**
    * Test massive or.
    */
@@ -3338,7 +3328,7 @@ public void testMassiveOr() {
     }
   }
 
-@Test
+  @Test
   public void testMassiveOrBigInts() {
     final int N = 128;
     for (int howmany = 512; howmany <= 1000000; howmany *= 2) {
@@ -3347,10 +3337,10 @@ public void testMassiveOrBigInts() {
         ewah[k] = new MutableRoaringBitmap();
       }
       for (int k = 0; k < howmany; ++k) {
-        ewah[Math.abs(k + 2 * k * k) % ewah.length].add( (1<<31)+k);
+        ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k);
       }
       for (int k = 3; k < ewah.length; k += 3) {
-        ewah[k].flip( (1L<<31)+13L,  (1L<<31)+(long) howmany / 2);
+        ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2);
       }
       MutableRoaringBitmap answer = ewah[0];
       for (int k = 1; k < ewah.length; ++k) {
@@ -3369,7 +3359,6 @@ public void testMassiveOrBigInts() {
     }
   }
 
-
   /**
    * Test massive xor.
    */
@@ -3385,7 +3374,7 @@ public void testMassiveXOr() {
         ewah[Math.abs(k + 2 * k * k) % ewah.length].add(k);
       }
       for (int k = 3; k < ewah.length; k += 3) {
-        ewah[k].flip(13L, (long)howmany / 2);
+        ewah[k].flip(13L, (long) howmany / 2);
       }
 
       MutableRoaringBitmap answer = ewah[0];
@@ -3408,10 +3397,10 @@ public void testMassiveXOrBigInts() {
         ewah[k] = new MutableRoaringBitmap();
       }
       for (int k = 0; k < howmany; ++k) {
-          ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1<<31)+k);
+        ewah[Math.abs(k + 2 * k * k) % ewah.length].add((1 << 31) + k);
       }
       for (int k = 3; k < ewah.length; k += 3) {
-        ewah[k].flip((1L<<31)+13L, (1L<<31)+(long)howmany / 2);
+        ewah[k].flip((1L << 31) + 13L, (1L << 31) + (long) howmany / 2);
       }
 
       MutableRoaringBitmap answer = ewah[0];
@@ -3425,7 +3414,6 @@ public void testMassiveXOrBigInts() {
     }
   }
 
-
   @Test
   public void intersecttestWithRange() {
     MutableRoaringBitmap rr1 = new MutableRoaringBitmap();
@@ -3436,7 +3424,6 @@ public void intersecttestWithRange() {
     rr1.add(1L, 4L);
     rr1.add(6L, 10L);
 
-
     // This one will be Array Containers
     rr2.add(0);
     rr2.add(2);
@@ -3465,9 +3452,6 @@ public void intersecttestWithRange() {
     assertTrue(rr3.intersects(5, 10));
   }
 
-
-
-
   @Test
   public void testRandomLists() {
     MutableRoaringBitmap rb1 =
@@ -3478,8 +3462,6 @@ public void testRandomLists() {
     assertTrue(rbor.equals(BufferFastAggregation.horizontal_or(rb1, rb2)));
   }
 
-
-
   @Test
   public void intersecttest() {
     final MutableRoaringBitmap rr1 = new MutableRoaringBitmap();
@@ -3506,30 +3488,33 @@ public void intersecttest() {
   // this had created an array out of bounds error
   @Test
   public void fliptest_Karpenske() {
-    long[] array = new long[] {343798, 343799, 343800, 343801, 343803, 343804, 343805, 343807, 343809,
-        343811, 343812, 343815, 343816, 343817, 343818, 343819, 343821, 343825, 343827, 343828,
-        343830, 343831, 343832, 343833, 343835, 343836, 343837, 343838, 343839, 343840, 343841,
-        343842, 343843, 343844, 343845, 343847, 343848, 343849, 343850, 343851, 343853, 343854,
-        343855, 343856, 343858, 343859, 343860, 343861, 343862, 343863, 343864, 343865, 343866,
-        343868, 343869, 343874, 343875, 343877, 343879, 343880, 343881, 343882, 343883, 343887,
-        343889, 343890, 343891, 343894, 343895, 343898, 343899, 343900, 343901, 343902, 343904,
-        343906, 343907, 343908, 343909, 343910, 343911, 343912, 343913, 343914, 343915, 343916,
-        343917, 343918, 343919, 343921, 343922, 343923, 343924, 343927, 343928, 343929, 343930,
-        343931, 343932, 343933, 343934, 343935, 343938, 343939, 343941, 343942, 343943, 343944,
-        343945, 343946, 343949, 343951, 343953, 343954, 343955, 343956, 343958, 343959, 343961,
-        343962, 343964, 343965, 343966, 343967, 343968, 343969, 343971, 343972, 343973, 343974,
-        343976, 343978, 343979, 343981, 343982, 343983, 343985, 343987, 343988, 343989, 343992,
-        343993, 343994, 343995, 343996, 343997, 343998, 344000, 344001, 344002, 344003, 344004,
-        344006, 344008, 344009, 344011, 344012, 344013, 344015, 344017, 344019, 344020, 344021,
-        344023, 344025, 344026, 344027, 344028, 344029, 344030, 344031, 344034, 344035, 344036,
-        344037, 344038, 344039, 344040, 344042, 344043, 344046, 344047};
+    long[] array =
+        new long[] {
+          343798, 343799, 343800, 343801, 343803, 343804, 343805, 343807, 343809, 343811, 343812,
+          343815, 343816, 343817, 343818, 343819, 343821, 343825, 343827, 343828, 343830, 343831,
+          343832, 343833, 343835, 343836, 343837, 343838, 343839, 343840, 343841, 343842, 343843,
+          343844, 343845, 343847, 343848, 343849, 343850, 343851, 343853, 343854, 343855, 343856,
+          343858, 343859, 343860, 343861, 343862, 343863, 343864, 343865, 343866, 343868, 343869,
+          343874, 343875, 343877, 343879, 343880, 343881, 343882, 343883, 343887, 343889, 343890,
+          343891, 343894, 343895, 343898, 343899, 343900, 343901, 343902, 343904, 343906, 343907,
+          343908, 343909, 343910, 343911, 343912, 343913, 343914, 343915, 343916, 343917, 343918,
+          343919, 343921, 343922, 343923, 343924, 343927, 343928, 343929, 343930, 343931, 343932,
+          343933, 343934, 343935, 343938, 343939, 343941, 343942, 343943, 343944, 343945, 343946,
+          343949, 343951, 343953, 343954, 343955, 343956, 343958, 343959, 343961, 343962, 343964,
+          343965, 343966, 343967, 343968, 343969, 343971, 343972, 343973, 343974, 343976, 343978,
+          343979, 343981, 343982, 343983, 343985, 343987, 343988, 343989, 343992, 343993, 343994,
+          343995, 343996, 343997, 343998, 344000, 344001, 344002, 344003, 344004, 344006, 344008,
+          344009, 344011, 344012, 344013, 344015, 344017, 344019, 344020, 344021, 344023, 344025,
+          344026, 344027, 344028, 344029, 344030, 344031, 344034, 344035, 344036, 344037, 344038,
+          344039, 344040, 344042, 344043, 344046, 344047
+        };
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     long[] indexes = array;
     int rangeStart = 0;
     for (int rangeEnd = 1; rangeEnd < indexes.length; rangeEnd++) {
       if (indexes[rangeEnd - 1] + 1 != indexes[rangeEnd]) {
         if (rangeStart == rangeEnd - 1) {
-            bitmap.add((int)indexes[rangeStart]);
+          bitmap.add((int) indexes[rangeStart]);
         } else {
           bitmap.flip(indexes[rangeStart], indexes[rangeEnd - 1] + 1);
         }
@@ -3537,7 +3522,7 @@ public void fliptest_Karpenske() {
       }
     }
     if (rangeStart == indexes.length - 1) {
-        bitmap.add((int)indexes[rangeStart]);
+      bitmap.add((int) indexes[rangeStart]);
     } else {
       bitmap.flip(indexes[rangeStart], indexes[indexes.length - 1] + 1);
     }
@@ -3607,7 +3592,6 @@ public void andCounttest3() {
     assertEquals(rrand.getCardinality(), rrandCount);
     final int rrandCountm = ImmutableRoaringBitmap.andCardinality(toMapped(rr), toMapped(rr2));
     assertEquals(rrand.getCardinality(), rrandCountm);
-
   }
 
   @Test
@@ -3649,15 +3633,14 @@ public void orcount() {
 
     final MutableRoaringBitmap rror = ImmutableRoaringBitmap.or(rr, rr2);
     assertEquals(rror.getCardinality(), ImmutableRoaringBitmap.orCardinality(rr, rr2));
-
   }
 
   @Test
   public void testLazyOr() {
     MutableRoaringBitmap rb1 = new MutableRoaringBitmap();
-    rb1.add(1<<16);
-    rb1.add(1<<18);
-    rb1.add(1<<19);
+    rb1.add(1 << 16);
+    rb1.add(1 << 18);
+    rb1.add(1 << 19);
     MutableRoaringBitmap rb2 = new MutableRoaringBitmap();
     rb2.add(4);
     rb2.add(7);
@@ -3669,9 +3652,9 @@ public void testLazyOr() {
     rb3.add(3);
     rb3.add(4);
     rb3.add(5);
-    rb3.add(1<<16);
-    rb3.add(1<<17);
-    rb3.add(1<<20);
+    rb3.add(1 << 16);
+    rb3.add(1 << 17);
+    rb3.add(1 << 20);
     rb1.lazyor(rb2);
     rb1.lazyor(rb3);
     MutableRoaringBitmap rb4 = new MutableRoaringBitmap();
@@ -3683,11 +3666,11 @@ public void testLazyOr() {
     rb4.add(7);
     rb4.add(8);
     rb4.add(9);
-    rb4.add(1<<16);
-    rb4.add(1<<17);
-    rb4.add(1<<18);
-    rb4.add(1<<19);
-    rb4.add(1<<20);
+    rb4.add(1 << 16);
+    rb4.add(1 << 17);
+    rb4.add(1 << 18);
+    rb4.add(1 << 19);
+    rb4.add(1 << 20);
     assertEquals(rb4, rb1);
   }
 
@@ -3695,7 +3678,7 @@ public void testLazyOr() {
   public void testFirstLast_CreateSparseContainersAfterRun() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
     rb.add(1L, 1 << 14);
-    for(int i = 18; i < 31; ++i) {
+    for (int i = 18; i < 31; ++i) {
       int x = 1 << i;
       rb.add(x);
       assertEquals(1, rb.first());
@@ -3727,7 +3710,7 @@ public void testFirstLast() {
     assertEquals(2, rb.first());
     assertEquals((1 << 14) - 1, rb.last());
 
-    rb.add(1L<< 15, 1L << 30);
+    rb.add(1L << 15, 1L << 30);
     assertEquals(2, rb.first());
     assertEquals((1L << 30) - 1, rb.last());
   }
@@ -3741,62 +3724,63 @@ public void testAndCardinality() {
     baseline.add((1 << 21) + 3);
     baseline.add((1 << 21) + 5);
     assertEquals(baseline, MutableRoaringBitmap.and(baseline, baseline));
-    assertEquals(baseline.getCardinality(), MutableRoaringBitmap.andCardinality(baseline, baseline));
+    assertEquals(
+        baseline.getCardinality(), MutableRoaringBitmap.andCardinality(baseline, baseline));
   }
 
   @Test
-  public void addoffset() { 
+  public void addoffset() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
     rb.add(10);
     rb.add(0xFFFF);
     rb.add(0x010101);
     for (int i = 100000; i < 200000; i += 4) {
-        rb.add(i);
+      rb.add(i);
     }
     rb.add(400000L, 1400000L);
-    for(int offset = 3; offset < 1000000; offset *= 3) {
+    for (int offset = 3; offset < 1000000; offset *= 3) {
       MutableRoaringBitmap rboff = MutableRoaringBitmap.addOffset(rb, offset);
       IntIterator i = rb.getIntIterator();
       IntIterator j = rboff.getIntIterator();
-      while(i.hasNext() && j.hasNext()) {
-        assertTrue(i.next() + offset ==  j.next());  
-      }System.out.println("offset = "+offset);
-      assertTrue(i.hasNext() ==  j.hasNext());
+      while (i.hasNext() && j.hasNext()) {
+        assertTrue(i.next() + offset == j.next());
+      }
+      System.out.println("offset = " + offset);
+      assertTrue(i.hasNext() == j.hasNext());
     }
-    for(int offset = 1024; offset < 1000000; offset *= 2) {
+    for (int offset = 1024; offset < 1000000; offset *= 2) {
       MutableRoaringBitmap rboff = MutableRoaringBitmap.addOffset(rb, offset);
       IntIterator i = rb.getIntIterator();
       IntIterator j = rboff.getIntIterator();
-      while(i.hasNext() && j.hasNext()) {
-      assertTrue(i.next() + offset ==  j.next());  
+      while (i.hasNext() && j.hasNext()) {
+        assertTrue(i.next() + offset == j.next());
       }
-      assertTrue(i.hasNext() ==  j.hasNext());
+      assertTrue(i.hasNext() == j.hasNext());
     }
   }
 
-
   @Test
   public void issue418() {
-      final MutableRoaringBitmap rb = new MutableRoaringBitmap();
-      rb.add(0);
-      assertEquals(rb.contains(0), true);
-      assertEquals(rb.getCardinality(), 1);
-      long vals[] = { 100, 0xFFFF0000L, 0xFFFF0001L };
-      for(long s : vals) {
-        MutableRoaringBitmap shifted = MutableRoaringBitmap.addOffset(rb, s);
-          System.out.println("moved "+shifted);
-          assertEquals(shifted.contains((int)s), true);
-          assertEquals(shifted.getCardinality(), 1);
-          System.out.println("moving back by "+(-s));
+    final MutableRoaringBitmap rb = new MutableRoaringBitmap();
+    rb.add(0);
+    assertEquals(rb.contains(0), true);
+    assertEquals(rb.getCardinality(), 1);
+    long vals[] = {100, 0xFFFF0000L, 0xFFFF0001L};
+    for (long s : vals) {
+      MutableRoaringBitmap shifted = MutableRoaringBitmap.addOffset(rb, s);
+      System.out.println("moved " + shifted);
+      assertEquals(shifted.contains((int) s), true);
+      assertEquals(shifted.getCardinality(), 1);
+      System.out.println("moving back by " + (-s));
 
-          shifted = MutableRoaringBitmap.addOffset(shifted, -s);
-          System.out.println("back "+shifted);
+      shifted = MutableRoaringBitmap.addOffset(shifted, -s);
+      System.out.println("back " + shifted);
 
-          assertEquals(shifted.contains(0), true);
-          assertEquals(shifted.getCardinality(), 1);
-      }
+      assertEquals(shifted.contains(0), true);
+      assertEquals(shifted.getCardinality(), 1);
+    }
   }
-  
+
   @Test
   public void addNegativeOffset() {
     final MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -3807,41 +3791,40 @@ public void addNegativeOffset() {
       rb.add(i);
     }
     rb.add(400000L, 1400000L);
-    for(int offset = 3; offset < 1000000; offset *= 3) {
+    for (int offset = 3; offset < 1000000; offset *= 3) {
       MutableRoaringBitmap rbposoff = MutableRoaringBitmap.addOffset(rb, offset);
-      if(rb.getLongCardinality() != rbposoff.getLongCardinality()) {
+      if (rb.getLongCardinality() != rbposoff.getLongCardinality()) {
         throw new RuntimeException("data loss");
       }
       MutableRoaringBitmap rboff = MutableRoaringBitmap.addOffset(rbposoff, -offset);
-      if(rb.getLongCardinality() != rboff.getLongCardinality()) {
+      if (rb.getLongCardinality() != rboff.getLongCardinality()) {
         throw new RuntimeException("data loss");
       }
       IntIterator i = rb.getIntIterator();
       IntIterator j = rboff.getIntIterator();
-      while(i.hasNext() && j.hasNext()) {
-        assertTrue(i.next()  ==  j.next());
+      while (i.hasNext() && j.hasNext()) {
+        assertTrue(i.next() == j.next());
       }
-      assertTrue(i.hasNext() ==  j.hasNext());
+      assertTrue(i.hasNext() == j.hasNext());
     }
-    for(int offset = 1024; offset < 1000000; offset *= 2) {
+    for (int offset = 1024; offset < 1000000; offset *= 2) {
       MutableRoaringBitmap rbposoff = MutableRoaringBitmap.addOffset(rb, offset);
-      if(rb.getLongCardinality() != rbposoff.getLongCardinality()) {
+      if (rb.getLongCardinality() != rbposoff.getLongCardinality()) {
         throw new RuntimeException("data loss");
       }
       MutableRoaringBitmap rboff = MutableRoaringBitmap.addOffset(rbposoff, -offset);
-      if(rb.getLongCardinality() != rboff.getLongCardinality()) {
+      if (rb.getLongCardinality() != rboff.getLongCardinality()) {
         throw new RuntimeException("data loss");
       }
       IntIterator i = rb.getIntIterator();
       IntIterator j = rboff.getIntIterator();
-      while(i.hasNext() && j.hasNext()) {
-        assertTrue(i.next() ==  j.next());
+      while (i.hasNext() && j.hasNext()) {
+        assertTrue(i.next() == j.next());
       }
-      assertTrue(i.hasNext() ==  j.hasNext());
+      assertTrue(i.hasNext() == j.hasNext());
     }
   }
 
-
   @Test
   public void testNextValueArray() {
     MutableRoaringBitmap r = new MutableRoaringBitmap();
@@ -3852,8 +3835,24 @@ public void testNextValueArray() {
   @Test
   public void regressionTestEquals370() {
     // see https://github.com/RoaringBitmap/RoaringBitmap/issues/370
-    int[] a = {239,240,241,242,243,244,259,260,261,262,263,264,265,266,267,268,269,270,273,274,275,276,277,278,398,399,400,401,402,403,404,405,406,408,409,410,411,412,413,420,421,422,509,510,511,512,513,514,539,540,541,542,543,544,547,548,549,550,551,552,553,554,555,556,557,558,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,624,625,634,635,636,649,650,651,652,653,654,714,715,716,718,719,720,721,722,723,724,725,726,728,729,730,731,732,733,734,735,736,739,740,741,742,743,744,771,772,773};
-    int[] b = {239,240,241,242,243,244,259,260,261,262,263,264,265,266,267,268,269,270,273,274,275,276,277,278,398,399,400,401,402,403,404,405,406,408,409,410,411,412,413,420,421,422,509,510,511,512,513,514,539,540,541,542,543,544,547,548,549,550,551,552,553,554,555,556,557,558,578,579,580,581,582,583,584,585,586,607,608,634,635,636,649,650,651,652,653,654,714,715,716,718,719,720,721,722,723,724,725,726,728,729,730,731,732,733,734,735,736,739,740,741,742,743,744,771,772,773};
+    int[] a = {
+      239, 240, 241, 242, 243, 244, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 273,
+      274, 275, 276, 277, 278, 398, 399, 400, 401, 402, 403, 404, 405, 406, 408, 409, 410, 411, 412,
+      413, 420, 421, 422, 509, 510, 511, 512, 513, 514, 539, 540, 541, 542, 543, 544, 547, 548, 549,
+      550, 551, 552, 553, 554, 555, 556, 557, 558, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587,
+      588, 589, 590, 591, 592, 593, 594, 595, 624, 625, 634, 635, 636, 649, 650, 651, 652, 653, 654,
+      714, 715, 716, 718, 719, 720, 721, 722, 723, 724, 725, 726, 728, 729, 730, 731, 732, 733, 734,
+      735, 736, 739, 740, 741, 742, 743, 744, 771, 772, 773
+    };
+    int[] b = {
+      239, 240, 241, 242, 243, 244, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 273,
+      274, 275, 276, 277, 278, 398, 399, 400, 401, 402, 403, 404, 405, 406, 408, 409, 410, 411, 412,
+      413, 420, 421, 422, 509, 510, 511, 512, 513, 514, 539, 540, 541, 542, 543, 544, 547, 548, 549,
+      550, 551, 552, 553, 554, 555, 556, 557, 558, 578, 579, 580, 581, 582, 583, 584, 585, 586, 607,
+      608, 634, 635, 636, 649, 650, 651, 652, 653, 654, 714, 715, 716, 718, 719, 720, 721, 722, 723,
+      724, 725, 726, 728, 729, 730, 731, 732, 733, 734, 735, 736, 739, 740, 741, 742, 743, 744, 771,
+      772, 773
+    };
 
     MutableRoaringBitmap rbA = MutableRoaringBitmap.bitmapOf(a);
     MutableRoaringBitmap rbB = MutableRoaringBitmap.bitmapOf(b);
@@ -3867,33 +3866,37 @@ public void regressionTestEquals370() {
 
   @Test
   public void regressionTestRemove377() {
-     // https://github.com/RoaringBitmap/RoaringBitmap/issues/377
-     MutableRoaringBitmap map = new MutableRoaringBitmap();
-     map.add(0L, 64L);
-     for (int i = 0; i < 64; i++) {
-       if (i != 30 && i != 32) {
-         map.remove(i);
-       }
-     }
-     map.remove(0L, 31L);
-     assertFalse(map.contains(30));
-     assertTrue(map.contains(32));
+    // https://github.com/RoaringBitmap/RoaringBitmap/issues/377
+    MutableRoaringBitmap map = new MutableRoaringBitmap();
+    map.add(0L, 64L);
+    for (int i = 0; i < 64; i++) {
+      if (i != 30 && i != 32) {
+        map.remove(i);
+      }
+    }
+    map.remove(0L, 31L);
+    assertFalse(map.contains(30));
+    assertTrue(map.contains(32));
   }
 
   @Test
   public void invalidCookieBuffer() {
-    assertThrows(IOException.class, () -> {
-      MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
-      bitmap.deserialize(ByteBuffer.allocate(4));
-    });
+    assertThrows(
+        IOException.class,
+        () -> {
+          MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+          bitmap.deserialize(ByteBuffer.allocate(4));
+        });
   }
 
   @Test
   public void invalidCookieDataInput() {
-    assertThrows(IOException.class, () -> {
-      MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
-      bitmap.deserialize(new DataInputStream(new ByteArrayInputStream(new byte[4])));
-    });
+    assertThrows(
+        IOException.class,
+        () -> {
+          MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+          bitmap.deserialize(new DataInputStream(new ByteArrayInputStream(new byte[4])));
+        });
   }
 
   @Test
@@ -3901,7 +3904,7 @@ public void testCardinalityExceeds() {
     MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
     long runLength = 20_000L;
     bitmap.add(0L, runLength);
-    for (int i = (1 << 16) + 1; i < 1 << 17; i+= 2) {
+    for (int i = (1 << 16) + 1; i < 1 << 17; i += 2) {
       bitmap.add(i);
     }
     long bitmapCount = 1 << 15;
@@ -3919,15 +3922,15 @@ public void testCardinalityExceeds() {
 
   @Test
   public void testWithYourself() {
-    MutableRoaringBitmap b1 = MutableRoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10);
+    MutableRoaringBitmap b1 = MutableRoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     b1.runOptimize();
     b1.or(b1);
-    assertTrue(b1.equals(MutableRoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10)));
+    assertTrue(b1.equals(MutableRoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
     b1.xor(b1);
     assertTrue(b1.isEmpty());
-    b1 = MutableRoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10);
+    b1 = MutableRoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     b1.and(b1);
-    assertTrue(b1.equals(MutableRoaringBitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10)));
+    assertTrue(b1.equals(MutableRoaringBitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
     b1.andNot(b1);
     assertTrue(b1.isEmpty());
   }
@@ -3942,18 +3945,19 @@ public void testPreviousValueRegression() {
   @Test
   public void testRangeExtremeEnd() {
     MutableRoaringBitmap x = new MutableRoaringBitmap();
-    long rangeStart =  (1L << 32) - 2;
+    long rangeStart = (1L << 32) - 2;
     long rangeEnd = (1L << 32);
     x.add(rangeStart, rangeEnd);
 
     Assertions.assertEquals(2L, x.getLongCardinality());
     Assertions.assertArrayEquals(new int[] {-2, -1}, x.toArray());
   }
+
   @Test
   public void issue623() {
     MutableRoaringBitmap r = new MutableRoaringBitmap();
     r.add(65535);
-    r.add(65535+1);
+    r.add(65535 + 1);
     assertTrue(r.contains(65535));
     assertTrue(r.contains(65535 + 1));
     assertTrue(r.contains(65535L, 65535L + 1));
@@ -3965,4 +3969,56 @@ public void issue623() {
     }
   }
 
+  @Test
+  public void test1235() {
+    MutableRoaringBitmap r = MutableRoaringBitmap.bitmapOf(1, 2, 3, 5);
+    r.flip(4);
+    assertEquals(r, MutableRoaringBitmap.bitmapOf(1, 2, 3, 4, 5));
+  }
+
+  @Test
+  public void test2345() {
+    MutableRoaringBitmap r = MutableRoaringBitmap.bitmapOf(1, 2, 3, 4, 5);
+    r.flip(1);
+    assertEquals(r, MutableRoaringBitmap.bitmapOf(2, 3, 4, 5));
+  }
+
+  @Test
+  public void testPreviousValueLimit() {
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    bitmap.add(1);
+    assertEquals(-1l, bitmap.previousValue(0));
+  }
+
+  @Test
+  public void testPreviousAbsentValueLimit() {
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    bitmap.add(0);
+    assertEquals(-1L, bitmap.previousAbsentValue(0));
+  }
+
+  @Test
+  public void testNextValueLimit() {
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    bitmap.add(0xffffffff - 1);
+    assertEquals(-1L, bitmap.nextValue(0xffffffff));
+  }
+
+  @Test
+  public void testNextAbsentValueLimit() {
+    MutableRoaringBitmap bitmap = new MutableRoaringBitmap();
+    bitmap.add(-1);
+    assertEquals(-1L, bitmap.nextAbsentValue(-1));
+  }
+
+  @Test
+  public void testSelectRange() {
+    MutableRoaringBitmap r = MutableRoaringBitmap.bitmapOfRange(1, 1000000);
+    for (int i = 1; i <= 1000000; i += 1000) {
+      for (int j = i; j <= 1000000; j += 1000) {
+        MutableRoaringBitmap rr = r.selectRange(i, j);
+        assertEquals(rr, MutableRoaringBitmap.bitmapOfRange(i, j));
+      }
+    }
+  }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRunContainer.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRunContainer.java
similarity index 85%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRunContainer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRunContainer.java
index ad8c29bad..cea078161 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestRunContainer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestRunContainer.java
@@ -1,22 +1,33 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.buffer.MappeableArrayContainer.DEFAULT_MAX_SIZE;
 
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.parallel.Execution;
-import org.junit.jupiter.api.parallel.ExecutionMode;
 import org.roaringbitmap.CharIterator;
 import org.roaringbitmap.IntIterator;
 import org.roaringbitmap.RunContainer;
 
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.roaringbitmap.buffer.MappeableArrayContainer.DEFAULT_MAX_SIZE;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
 
 @Execution(ExecutionMode.CONCURRENT)
 public class TestRunContainer {
@@ -36,25 +47,25 @@ private static ImmutableRoaringBitmap toMapped(MutableRoaringBitmap r) {
   @Test
   public void testToString() {
     MappeableRunContainer rc = new MappeableRunContainer(32200, 35000);
-    rc.add((char)-1);
+    rc.add((char) -1);
     assertEquals("[32200,34999][65535,65535]", rc.toString());
   }
 
   @Test
   public void testRunOpti() {
     MutableRoaringBitmap mrb = new MutableRoaringBitmap();
-    for(int r = 0; r< 100000; r+=3 ) {
+    for (int r = 0; r < 100000; r += 3) {
       mrb.add(r);
     }
     mrb.add(1000000);
-    for(int r = 2000000; r < 3000000; ++r) {
+    for (int r = 2000000; r < 3000000; ++r) {
       mrb.add(r);
     }
     MutableRoaringBitmap m2 = mrb.clone();
     m2.runOptimize();
     IntIterator x = m2.getReverseIntIterator();
     int count = 0;
-    while(x.hasNext()) {
+    while (x.hasNext()) {
       x.next();
       count++;
     }
@@ -104,8 +115,8 @@ static int[] generateUniformHash(Random rand, int N, int Max) {
     return ans;
   }
 
-  private static void getSetOfMappeableRunContainers(ArrayList set,
-      ArrayList setb) {
+  private static void getSetOfMappeableRunContainers(
+      ArrayList set, ArrayList setb) {
     MappeableRunContainer r1 = new MappeableRunContainer();
     r1 = (MappeableRunContainer) r1.iadd(0, (1 << 16));
     MappeableContainer b1 = new MappeableArrayContainer();
@@ -163,7 +174,6 @@ private static void getSetOfMappeableRunContainers(ArrayList {
-      MappeableContainer rc = new MappeableRunContainer();
-      rc.iadd(10, 9);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer rc = new MappeableRunContainer();
+          rc.iadd(10, 9);
+        });
   }
 
   @Test
   public void iaddInvalidRange2() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer rc = new MappeableRunContainer();
-      rc.iadd(0, 1 << 20);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer rc = new MappeableRunContainer();
+          rc.iadd(0, 1 << 20);
+        });
   }
 
   @Test
@@ -737,7 +750,6 @@ public void iaddRange5() {
     assertEquals(16, rc.getSizeInBytes());
   }
 
-
   @Test
   public void iaddRange6() {
     MappeableContainer rc = new MappeableRunContainer();
@@ -864,8 +876,6 @@ public void intersectionTest1() {
     assertEquals(ac, rc.and(ac));
   }
 
-
-
   @Test
   public void intersectionTest2() {
     MappeableContainer ac = new MappeableArrayContainer();
@@ -940,8 +950,6 @@ public void iremove10() {
     assertEquals(8, rc.getSizeInBytes());
   }
 
-
-
   @Test
   public void iremove11() {
     MappeableContainer rc = new MappeableRunContainer();
@@ -951,7 +959,6 @@ public void iremove11() {
     assertEquals(0, rc.getCardinality());
   }
 
-
   @Test
   public void iremove12() {
     MappeableContainer rc = new MappeableRunContainer();
@@ -977,7 +984,6 @@ public void iremove13() {
     assertEquals(12, rc.getSizeInBytes());
   }
 
-
   @Test
   public void iremove14() {
     MappeableContainer rc = new MappeableRunContainer();
@@ -1134,18 +1140,22 @@ public void iremove9() {
 
   @Test
   public void iremoveInvalidRange1() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer rc = new MappeableRunContainer();
-      rc.iremove(10, 9);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer rc = new MappeableRunContainer();
+          rc.iremove(10, 9);
+        });
   }
 
   @Test
   public void iremoveInvalidRange2() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      MappeableContainer rc = new MappeableRunContainer();
-      rc.remove(0, 1 << 20);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          MappeableContainer rc = new MappeableRunContainer();
+          rc.remove(0, 1 << 20);
+        });
   }
 
   @Test
@@ -1315,22 +1325,28 @@ public void MappeableRunContainerArg_ArrayANDNOT() {
 
   @Test
   public void RunContainerArg_ArrayANDNOT2() {
-    MappeableArrayContainer ac = new MappeableArrayContainer(CharBuffer.wrap(new char[]{0, 2, 4, 8, 10, 15, 16, 48, 50, 61, 80, (char)-2}), 12);
-    MappeableContainer rc = new MappeableRunContainer(CharBuffer.wrap(new char[]{7, 3, 17, 2, 20, 3, 30, 3, 36, 6, 60, 5, (char)-3, 2}), 7);
-    assertEquals(new MappeableArrayContainer(CharBuffer.wrap(new char[]{0, 2, 4, 15, 16, 48, 50, 80}), 8), ac.andNot(rc));
+    MappeableArrayContainer ac =
+        new MappeableArrayContainer(
+            CharBuffer.wrap(new char[] {0, 2, 4, 8, 10, 15, 16, 48, 50, 61, 80, (char) -2}), 12);
+    MappeableContainer rc =
+        new MappeableRunContainer(
+            CharBuffer.wrap(new char[] {7, 3, 17, 2, 20, 3, 30, 3, 36, 6, 60, 5, (char) -3, 2}), 7);
+    assertEquals(
+        new MappeableArrayContainer(CharBuffer.wrap(new char[] {0, 2, 4, 15, 16, 48, 50, 80}), 8),
+        ac.andNot(rc));
   }
 
   @Test
   public void FullRunContainerArg_ArrayANDNOT2() {
-    MappeableArrayContainer ac = new MappeableArrayContainer(CharBuffer.wrap(new char[]{3}), 1);
+    MappeableArrayContainer ac = new MappeableArrayContainer(CharBuffer.wrap(new char[] {3}), 1);
     MappeableContainer rc = MappeableRunContainer.full();
     assertEquals(new MappeableArrayContainer(), ac.andNot(rc));
   }
 
   @Test
   public void RunContainerArg_ArrayANDNOT3() {
-    MappeableArrayContainer ac = new MappeableArrayContainer(CharBuffer.wrap(new char[]{5}), 1);
-    MappeableContainer rc = new MappeableRunContainer(CharBuffer.wrap(new char[]{3, 10}), 1);
+    MappeableArrayContainer ac = new MappeableArrayContainer(CharBuffer.wrap(new char[] {5}), 1);
+    MappeableContainer rc = new MappeableRunContainer(CharBuffer.wrap(new char[] {3, 10}), 1);
     assertEquals(new MappeableArrayContainer(), ac.andNot(rc));
   }
 
@@ -1483,22 +1499,20 @@ public void not10() {
     }
   }
 
-
   /*
    * @Test public void safeSerialization() throws Exception { MappeableRunContainer container = new
    * MappeableRunContainer(); container.add((char) 0); container.add((char) 2);
    * container.add((char) 55); container.add((char) 64); container.add((char) 256);
-   * 
+   *
    * ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new
    * ObjectOutputStream(bos); out.writeObject(container);
-   * 
+   *
    * ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream in =
    * new ObjectInputStream(bis); MappeableRunContainer newContainer = (MappeableRunContainer)
    * in.readObject(); assertEquals(container, newContainer);
    * assertEquals(container.serializedSizeInBytes(), newContainer.serializedSizeInBytes()); }
    */
 
-
   @Test
   public void not11() {
     MappeableRunContainer container = new MappeableRunContainer();
@@ -1521,7 +1535,6 @@ public void not11() {
     }
   }
 
-
   @Test
   public void not12() {
     MappeableRunContainer container = new MappeableRunContainer();
@@ -1622,7 +1635,6 @@ public void not3() {
     }
   }
 
-
   @Test
   public void not4() {
     MappeableRunContainer container = new MappeableRunContainer();
@@ -1673,7 +1685,6 @@ public void not6() {
     }
   }
 
-
   @Test
   public void not7() {
     MappeableRunContainer container = new MappeableRunContainer();
@@ -1684,7 +1695,6 @@ public void not7() {
     container.add((char) 504);
     container.add((char) 505);
 
-
     // one run, spans the range
     MappeableContainer result = container.not(502, 504);
 
@@ -1694,7 +1704,6 @@ public void not7() {
     }
   }
 
-
   @Test
   public void not8() {
     MappeableRunContainer container = new MappeableRunContainer();
@@ -1715,7 +1724,6 @@ public void not8() {
     }
   }
 
-
   @Test
   public void not9() {
     MappeableRunContainer container = new MappeableRunContainer();
@@ -1735,7 +1743,6 @@ public void not9() {
     }
   }
 
-
   @Test
   public void randomFun() {
     final int bitsetperword1 = 32;
@@ -1748,7 +1755,6 @@ public void randomFun() {
     int[] values1 = generateUniformHash(rand, bitsetperword1 * howmanywords, max);
     int[] values2 = generateUniformHash(rand, bitsetperword2 * howmanywords, max);
 
-
     rc1 = new MappeableRunContainer();
     rc1 = fillMeUp(rc1, values1);
 
@@ -1769,7 +1775,6 @@ public void randomFun() {
       throw new RuntimeException("second containers do not match");
     }
 
-
     if (!rc1.or(rc2).equals(ac1.or(ac2))) {
       throw new RuntimeException("ors do not match");
     }
@@ -1785,10 +1790,8 @@ public void randomFun() {
     if (!rc1.xor(rc2).equals(ac1.xor(ac2))) {
       throw new RuntimeException("xors do not match");
     }
-
   }
 
-
   @Test
   public void rank() {
     MappeableRunContainer container = new MappeableRunContainer();
@@ -1821,7 +1824,6 @@ public void remove() {
     assertEquals(0, newContainer.getCardinality());
   }
 
-
   @Test
   public void safeor() {
     MappeableContainer rc1 = new MappeableRunContainer();
@@ -1837,8 +1839,6 @@ public void safeor() {
     }
   }
 
-
-
   @Test
   public void safeSerialization() throws Exception {
     System.out.println("write safeSerialization"); /******************************/
@@ -1859,8 +1859,6 @@ public void select() {
     assertEquals(256, container.select(4));
   }
 
-
-
   @Test
   public void simpleIterator() {
     MappeableContainer x = new MappeableRunContainer();
@@ -1875,12 +1873,12 @@ public void simpleIterator() {
     assertFalse(i.hasNext());
   }
 
-
-
   @Test
   public void testAndNot() {
-    int[] array1 = {39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183,
-        39184, 39185, 39186, 39187, 39188};
+    int[] array1 = {
+      39173, 39174, 39175, 39176, 39177, 39178, 39179, 39180, 39181, 39182, 39183, 39184, 39185,
+      39186, 39187, 39188
+    };
     int[] array2 = {14205};
     MutableRoaringBitmap rb1 = MutableRoaringBitmap.bitmapOf(array1);
     rb1.runOptimize();
@@ -1889,8 +1887,6 @@ public void testAndNot() {
     assertEquals(answer.getCardinality(), array1.length);
   }
 
-
-
   @Test
   public void testRoaringWithOptimize() {
     // create the same bitmap over and over again, with optimizing it
@@ -1908,7 +1904,6 @@ public void testRoaringWithOptimize() {
     assertEquals(1, setWithOptimize.size());
   }
 
-
   @Test
   public void testRoaringWithoutOptimize() {
     // create the same bitmap over and over again, without optimizing it
@@ -1925,7 +1920,6 @@ public void testRoaringWithoutOptimize() {
     assertEquals(1, setWithoutOptimize.size());
   }
 
-
   @Test
   public void toBitmapOrArrayContainer() {
     MappeableRunContainer rc = new MappeableRunContainer();
@@ -1986,7 +1980,6 @@ public void union2() {
     assertEquals(N, rc.getCardinality());
   }
 
-
   @Test
   public void xor() {
     MappeableContainer bc = new MappeableBitmapContainer();
@@ -2007,7 +2000,6 @@ public void xor() {
     assertEquals(4 * DEFAULT_MAX_SIZE, rc.getCardinality());
   }
 
-
   @Test
   public void xor_array() {
     MappeableContainer bc = new MappeableArrayContainer();
@@ -2028,7 +2020,6 @@ public void xor_array() {
     assertEquals(4 * DEFAULT_MAX_SIZE, rc.getCardinality());
   }
 
-
   @Test
   public void xor1() {
     MappeableContainer bc = new MappeableBitmapContainer();
@@ -2039,8 +2030,6 @@ public void xor1() {
     assertTrue(result.contains((char) 1));
   }
 
-
-
   @Test
   public void xor1a() {
     MappeableContainer bc = new MappeableArrayContainer();
@@ -2051,7 +2040,6 @@ public void xor1a() {
     assertTrue(result.contains((char) 1));
   }
 
-
   @Test
   public void xor2() {
     MappeableContainer bc = new MappeableBitmapContainer();
@@ -2062,7 +2050,6 @@ public void xor2() {
     assertTrue(result.contains((char) 1));
   }
 
-
   @Test
   public void xor2a() {
     MappeableContainer bc = new MappeableArrayContainer();
@@ -2093,7 +2080,6 @@ public void xor3a() {
     assertEquals(0, result.getCardinality());
   }
 
-
   @Test
   public void xor4() {
     MappeableContainer bc = new MappeableArrayContainer();
@@ -2125,9 +2111,9 @@ public void iorArray() {
     assertEquals(13, rc.getCardinality());
 
     rc = new MappeableRunContainer();
-    rc = rc.add(0, 1<<16);
+    rc = rc.add(0, 1 << 16);
     rc = rc.ior(ac);
-    assertEquals(1<<16, rc.getCardinality());
+    assertEquals(1 << 16, rc.getCardinality());
   }
 
   @Test
@@ -2140,9 +2126,9 @@ public void iorBitmap() {
     assertEquals(1, rc.getCardinality());
 
     rc = new MappeableRunContainer();
-    rc = rc.add(0, 1<<16);
+    rc = rc.add(0, 1 << 16);
     rc = rc.ior(bc);
-    assertEquals(1<<16, rc.getCardinality());
+    assertEquals(1 << 16, rc.getCardinality());
   }
 
   @Test
@@ -2160,12 +2146,11 @@ public void iorRun() {
     assertEquals(13, rc1.getCardinality());
 
     rc1 = new MappeableRunContainer();
-    rc1 = rc1.add(0, 1<<16);
+    rc1 = rc1.add(0, 1 << 16);
     rc1 = rc1.ior(rc2);
-    assertEquals(1<<16, rc1.getCardinality());
+    assertEquals(1 << 16, rc1.getCardinality());
   }
 
-
   @Test
   public void intersectsRun() {
     MappeableContainer rc1 = new MappeableRunContainer();
@@ -2223,48 +2208,75 @@ public void testContainsMappeableBitmapContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsMappeableBitmapContainer_IncludeProperSubset() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableBitmapContainer().add(0,9);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableBitmapContainer().add(0, 9);
     assertTrue(rc.contains(subset));
   }
 
-
   @Test
   public void testContainsMappeableBitmapContainer_IncludeProperSubsetDifferentStart() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableBitmapContainer().add(1,9);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableBitmapContainer().add(1, 9);
+    assertTrue(rc.contains(subset));
+  }
+
+  @Test
+  public void testContainsBitmapContainer_IncludeProperSubsetMultiWordRun() {
+    MappeableContainer rc = new MappeableRunContainer().add(0, 80);
+    MappeableContainer subset = new MappeableBitmapContainer().add(0, 79);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableBitmapContainer_ExcludeShiftedSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableBitmapContainer().add(2,12);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableBitmapContainer().add(2, 12);
     assertFalse(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableBitmapContainer_IncludeSelf() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableBitmapContainer().add(0,10);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableBitmapContainer().add(0, 10);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableBitmapContainer_ExcludeSuperSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer superset = new MappeableBitmapContainer().add(0,20);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer superset = new MappeableBitmapContainer().add(0, 20);
     assertFalse(rc.contains(superset));
   }
 
   @Test
   public void testContainsMappeableBitmapContainer_ExcludeDisJointSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
     MappeableContainer disjoint = new MappeableBitmapContainer().add(20, 40);
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
   }
 
+  @Test
+  public void testContainsMappeableBitmapContainer_Issue721Case1() {
+    MappeableContainer rc = new MappeableRunContainer().add(0, 60).add(63, 64).add(66, 67);
+    MappeableContainer subset = new MappeableBitmapContainer().add(63, 64);
+    assertTrue(rc.contains(subset));
+  }
+
+  @Test
+  public void testContainsMappeableBitmapContainer_Issue721Case2() {
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10).add(12, 13);
+    MappeableContainer disjoint = new MappeableBitmapContainer().add(11, 12);
+    assertFalse(rc.contains(disjoint));
+  }
+
+  @Test
+  public void testContainsMappeableBitmapContainer_SkipEmptyWords() {
+    MappeableContainer rc = new MappeableRunContainer().add(128, 512);
+    MappeableContainer subset = new MappeableBitmapContainer().add(256, 320);
+    assertTrue(rc.contains(subset));
+  }
+
   @Test
   public void testContainsMappeableRunContainer_EmptyContainsEmpty() {
     MappeableContainer rc = new MappeableRunContainer();
@@ -2274,42 +2286,42 @@ public void testContainsMappeableRunContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsMappeableRunContainer_IncludeProperSubset() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableRunContainer().add(0,9);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableRunContainer().add(0, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableRunContainer_IncludeSelf() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableRunContainer().add(0,10);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableRunContainer().add(0, 10);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableRunContainer_ExcludeSuperSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer superset = new MappeableRunContainer().add(0,20);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer superset = new MappeableRunContainer().add(0, 20);
     assertFalse(rc.contains(superset));
   }
 
   @Test
   public void testContainsMappeableRunContainer_IncludeProperSubsetDifferentStart() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableRunContainer().add(1,9);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableRunContainer().add(1, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableRunContainer_ExcludeShiftedSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableRunContainer().add(2,12);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableRunContainer().add(2, 12);
     assertFalse(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableRunContainer_ExcludeDisJointSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
     MappeableContainer disjoint = new MappeableRunContainer().add(20, 40);
     assertFalse(rc.contains(disjoint));
     assertFalse(disjoint.contains(rc));
@@ -2324,36 +2336,36 @@ public void testContainsMappeableArrayContainer_EmptyContainsEmpty() {
 
   @Test
   public void testContainsMappeableArrayContainer_IncludeProperSubset() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableArrayContainer().add(0,9);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableArrayContainer().add(0, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableArrayContainer_IncludeProperSubsetDifferentStart() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableArrayContainer().add(2,9);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableArrayContainer().add(2, 9);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableArrayContainer_ExcludeShiftedSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer shifted = new MappeableArrayContainer().add(2,12);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer shifted = new MappeableArrayContainer().add(2, 12);
     assertFalse(rc.contains(shifted));
   }
 
   @Test
   public void testContainsMappeableArrayContainer_IncludeSelf() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer subset = new MappeableArrayContainer().add(0,10);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer subset = new MappeableArrayContainer().add(0, 10);
     assertTrue(rc.contains(subset));
   }
 
   @Test
   public void testContainsMappeableArrayContainer_ExcludeSuperSet() {
-    MappeableContainer rc = new MappeableRunContainer().add(0,10);
-    MappeableContainer superset = new MappeableArrayContainer().add(0,20);
+    MappeableContainer rc = new MappeableRunContainer().add(0, 10);
+    MappeableContainer superset = new MappeableArrayContainer().add(0, 20);
     assertFalse(rc.contains(superset));
   }
 
@@ -2401,7 +2413,7 @@ public void testEqualsMappeableArrayContainer_NotEqual_ArrayShifted() {
   public void testEqualsMappeableArrayContainer_NotEqual_ArrayDiscontiguous() {
     MappeableContainer rc = new MappeableRunContainer().add(0, 10);
     MappeableContainer ac = new MappeableArrayContainer().add(0, 11);
-    ac.flip((char)9);
+    ac.flip((char) 9);
     assertNotEquals(rc, ac);
     assertNotEquals(ac, rc);
   }
@@ -2461,21 +2473,21 @@ public void testIntersectsWithRange() {
     assertFalse(container.intersects(11, 1 << 16));
   }
 
-
   @Test
   public void testIntersectsWithRangeUnsigned() {
-    MappeableContainer container = new MappeableRunContainer().add(lower16Bits(-50), lower16Bits(-10));
+    MappeableContainer container =
+        new MappeableRunContainer().add(lower16Bits(-50), lower16Bits(-10));
     assertFalse(container.intersects(0, 1));
     assertTrue(container.intersects(0, lower16Bits(-40)));
     assertFalse(container.intersects(lower16Bits(-100), lower16Bits(-55)));
-    //assertFalse(container.intersects(-9, 1 << 16));// forbidden
+    // assertFalse(container.intersects(-9, 1 << 16));// forbidden
     assertTrue(container.intersects(11, 1 << 16));
   }
 
-
   @Test
   public void testIntersectsWithRangeManyRuns() {
-    MappeableContainer container = new MappeableRunContainer().add(0, 10).add(lower16Bits(-50), lower16Bits(-10));
+    MappeableContainer container =
+        new MappeableRunContainer().add(0, 10).add(lower16Bits(-50), lower16Bits(-10));
     assertTrue(container.intersects(0, 1));
     assertTrue(container.intersects(0, 101));
     assertTrue(container.intersects(0, lower16Bits(-1)));
@@ -2489,7 +2501,7 @@ public void testIntersectsWithRangeManyRuns() {
   @Test
   public void testContainsFull() {
     assertTrue(MappeableRunContainer.full().contains(0, 1 << 16));
-    assertFalse(MappeableRunContainer.full().flip((char)(1 << 15)).contains(0, 1 << 16));
+    assertFalse(MappeableRunContainer.full().flip((char) (1 << 15)).contains(0, 1 << 16));
   }
 
   @Test
@@ -2512,9 +2524,7 @@ public void testContainsRange() {
 
   @Test
   public void testContainsRange2() {
-    MappeableContainer rc = new MappeableRunContainer().add(1, 100)
-            .add(300, 400)
-            .add(5000, 10000);
+    MappeableContainer rc = new MappeableRunContainer().add(1, 100).add(300, 400).add(5000, 10000);
     assertFalse(rc.contains(0, 100));
     assertFalse(rc.contains(0, 100000));
     assertTrue(rc.contains(1, 100));
@@ -2531,10 +2541,11 @@ public void testContainsRange2() {
     assertFalse(rc.contains(10001, 20000));
   }
 
-
   @Test
   public void testContainsRange3() {
-    MappeableContainer rc = new MappeableRunContainer().add(1, 100)
+    MappeableContainer rc =
+        new MappeableRunContainer()
+            .add(1, 100)
             .add(300, 300)
             .add(400, 500)
             .add(502, 600)
@@ -2550,142 +2561,146 @@ public void testContainsRange3() {
 
   @Test
   public void testNextValue() {
-    MappeableContainer container = new RunContainer(new char[] { 64, 64 }, 1).toMappeableContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(-1, container.nextValue((char)129));
+    MappeableContainer container = new RunContainer(new char[] {64, 64}, 1).toMappeableContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(-1, container.nextValue((char) 129));
   }
 
   @Test
   public void testNextValueBetweenRuns() {
-    MappeableContainer container = new RunContainer(new char[] { 64, 64, 256, 64 }, 2)
-            .toMappeableContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(256, container.nextValue((char)129));
-    assertEquals(-1, container.nextValue((char)512));
+    MappeableContainer container =
+        new RunContainer(new char[] {64, 64, 256, 64}, 2).toMappeableContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(256, container.nextValue((char) 129));
+    assertEquals(-1, container.nextValue((char) 512));
   }
 
   @Test
   public void testNextValue2() {
-    MappeableContainer container = new RunContainer(new char[] { 64, 64, 200, 300, 5000, 200 }, 3)
-            .toMappeableContainer();
-    assertEquals(64, container.nextValue((char)0));
-    assertEquals(64, container.nextValue((char)63));
-    assertEquals(64, container.nextValue((char)64));
-    assertEquals(65, container.nextValue((char)65));
-    assertEquals(128, container.nextValue((char)128));
-    assertEquals(200, container.nextValue((char)129));
-    assertEquals(200, container.nextValue((char)199));
-    assertEquals(200, container.nextValue((char)200));
-    assertEquals(250, container.nextValue((char)250));
-    assertEquals(5000, container.nextValue((char)2500));
-    assertEquals(5000, container.nextValue((char)5000));
-    assertEquals(5200, container.nextValue((char)5200));
-    assertEquals(-1, container.nextValue((char)5201));
+    MappeableContainer container =
+        new RunContainer(new char[] {64, 64, 200, 300, 5000, 200}, 3).toMappeableContainer();
+    assertEquals(64, container.nextValue((char) 0));
+    assertEquals(64, container.nextValue((char) 63));
+    assertEquals(64, container.nextValue((char) 64));
+    assertEquals(65, container.nextValue((char) 65));
+    assertEquals(128, container.nextValue((char) 128));
+    assertEquals(200, container.nextValue((char) 129));
+    assertEquals(200, container.nextValue((char) 199));
+    assertEquals(200, container.nextValue((char) 200));
+    assertEquals(250, container.nextValue((char) 250));
+    assertEquals(5000, container.nextValue((char) 2500));
+    assertEquals(5000, container.nextValue((char) 5000));
+    assertEquals(5200, container.nextValue((char) 5200));
+    assertEquals(-1, container.nextValue((char) 5201));
   }
 
   @Test
   public void testPreviousValue1() {
-    MappeableContainer container = new RunContainer(new char[] { 64, 64 }, 1)
-            .toMappeableContainer();
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
+    MappeableContainer container = new RunContainer(new char[] {64, 64}, 1).toMappeableContainer();
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
   }
 
   @Test
   public void testPreviousValue2() {
-    MappeableContainer container = new RunContainer(new char[] { 64, 64, 200, 300, 5000, 200 }, 3)
-            .toMappeableContainer();
-    assertEquals(-1, container.previousValue((char)0));
-    assertEquals(-1, container.previousValue((char)63));
-    assertEquals(64, container.previousValue((char)64));
-    assertEquals(65, container.previousValue((char)65));
-    assertEquals(128, container.previousValue((char)128));
-    assertEquals(128, container.previousValue((char)129));
-    assertEquals(128, container.previousValue((char)199));
-    assertEquals(200, container.previousValue((char)200));
-    assertEquals(250, container.previousValue((char)250));
-    assertEquals(500, container.previousValue((char)2500));
-    assertEquals(5000, container.previousValue((char)5000));
-    assertEquals(5200, container.previousValue((char)5200));
+    MappeableContainer container =
+        new RunContainer(new char[] {64, 64, 200, 300, 5000, 200}, 3).toMappeableContainer();
+    assertEquals(-1, container.previousValue((char) 0));
+    assertEquals(-1, container.previousValue((char) 63));
+    assertEquals(64, container.previousValue((char) 64));
+    assertEquals(65, container.previousValue((char) 65));
+    assertEquals(128, container.previousValue((char) 128));
+    assertEquals(128, container.previousValue((char) 129));
+    assertEquals(128, container.previousValue((char) 199));
+    assertEquals(200, container.previousValue((char) 200));
+    assertEquals(250, container.previousValue((char) 250));
+    assertEquals(500, container.previousValue((char) 2500));
+    assertEquals(5000, container.previousValue((char) 5000));
+    assertEquals(5200, container.previousValue((char) 5200));
   }
 
   @Test
   public void testPreviousValueUnsigned() {
-    MappeableContainer container = new RunContainer(new char[] { (char)((1 << 15) | 5), (char)0, (char)((1 << 15) | 7), (char)0}, 2)
+    MappeableContainer container =
+        new RunContainer(
+                new char[] {(char) ((1 << 15) | 5), (char) 0, (char) ((1 << 15) | 7), (char) 0}, 2)
             .toMappeableContainer();
-    assertEquals(-1, container.previousValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 5), container.previousValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 7), container.previousValue((char)((1 << 15) | 8)));
+    assertEquals(-1, container.previousValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 5), container.previousValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 7), container.previousValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testNextValueUnsigned() {
-    MappeableContainer container = new RunContainer(new char[] { (char)((1 << 15) | 5), (char)0, (char)((1 << 15) | 7), (char)0}, 2)
+    MappeableContainer container =
+        new RunContainer(
+                new char[] {(char) ((1 << 15) | 5), (char) 0, (char) ((1 << 15) | 7), (char) 0}, 2)
             .toMappeableContainer();
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 5), container.nextValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 7), container.nextValue((char)((1 << 15) | 7)));
-    assertEquals(-1, container.nextValue((char)((1 << 15) | 8)));
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 5), container.nextValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 7), container.nextValue((char) ((1 << 15) | 7)));
+    assertEquals(-1, container.nextValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testPreviousAbsentValue1() {
     MappeableContainer container = new MappeableRunContainer().iadd(64, 129);
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
   }
 
   @Test
   public void testPreviousAbsentValue2() {
-    MappeableContainer container = new MappeableRunContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
-    assertEquals(0, container.previousAbsentValue((char)0));
-    assertEquals(63, container.previousAbsentValue((char)63));
-    assertEquals(63, container.previousAbsentValue((char)64));
-    assertEquals(63, container.previousAbsentValue((char)65));
-    assertEquals(63, container.previousAbsentValue((char)128));
-    assertEquals(129, container.previousAbsentValue((char)129));
-    assertEquals(199, container.previousAbsentValue((char)199));
-    assertEquals(199, container.previousAbsentValue((char)200));
-    assertEquals(199, container.previousAbsentValue((char)250));
-    assertEquals(2500, container.previousAbsentValue((char)2500));
-    assertEquals(4999, container.previousAbsentValue((char)5000));
-    assertEquals(4999, container.previousAbsentValue((char)5200));
+    MappeableContainer container =
+        new MappeableRunContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertEquals(0, container.previousAbsentValue((char) 0));
+    assertEquals(63, container.previousAbsentValue((char) 63));
+    assertEquals(63, container.previousAbsentValue((char) 64));
+    assertEquals(63, container.previousAbsentValue((char) 65));
+    assertEquals(63, container.previousAbsentValue((char) 128));
+    assertEquals(129, container.previousAbsentValue((char) 129));
+    assertEquals(199, container.previousAbsentValue((char) 199));
+    assertEquals(199, container.previousAbsentValue((char) 200));
+    assertEquals(199, container.previousAbsentValue((char) 250));
+    assertEquals(2500, container.previousAbsentValue((char) 2500));
+    assertEquals(4999, container.previousAbsentValue((char) 5000));
+    assertEquals(4999, container.previousAbsentValue((char) 5200));
   }
 
   @Test
   public void testPreviousAbsentValueEmpty() {
     MappeableRunContainer container = new MappeableRunContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.previousAbsentValue((char)i));
+      assertEquals(i, container.previousAbsentValue((char) i));
     }
   }
 
   @Test
   public void testPreviousAbsentValueSparse() {
-    MappeableRunContainer container = new MappeableRunContainer(CharBuffer.wrap(new char[] { 10, 0, 20, 0, 30, 0}), 3);
-    assertEquals(9, container.previousAbsentValue((char)9));
-    assertEquals(9, container.previousAbsentValue((char)10));
-    assertEquals(11, container.previousAbsentValue((char)11));
-    assertEquals(21, container.previousAbsentValue((char)21));
-    assertEquals(29, container.previousAbsentValue((char)30));
+    MappeableRunContainer container =
+        new MappeableRunContainer(CharBuffer.wrap(new char[] {10, 0, 20, 0, 30, 0}), 3);
+    assertEquals(9, container.previousAbsentValue((char) 9));
+    assertEquals(9, container.previousAbsentValue((char) 10));
+    assertEquals(11, container.previousAbsentValue((char) 11));
+    assertEquals(21, container.previousAbsentValue((char) 21));
+    assertEquals(29, container.previousAbsentValue((char) 30));
   }
 
   @Test
@@ -2697,9 +2712,9 @@ public void testPreviousAbsentEvenBits() {
     }
 
     MappeableRunContainer container = new MappeableRunContainer(CharBuffer.wrap(evenBits), 1 << 14);
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i - 1, container.previousAbsentValue((char)i));
-      assertEquals(i + 1, container.previousAbsentValue((char)(i+1)));
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i - 1, container.previousAbsentValue((char) i));
+      assertEquals(i + 1, container.previousAbsentValue((char) (i + 1)));
     }
   }
 
@@ -2707,58 +2722,59 @@ public void testPreviousAbsentEvenBits() {
   public void testPreviousAbsentValueUnsigned() {
     char[] array = {(char) ((1 << 15) | 5), 0, (char) ((1 << 15) | 7), 0};
     MappeableRunContainer container = new MappeableRunContainer(CharBuffer.wrap(array), 2);
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char)((1 << 15) | 8)));
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 4), container.previousAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 6), container.previousAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.previousAbsentValue((char) ((1 << 15) | 8)));
   }
 
-
   @Test
   public void testNextAbsentValue1() {
     MappeableContainer container = new MappeableRunContainer().iadd(64, 129);
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
   }
 
   @Test
   public void testNextAbsentValue2() {
-    MappeableContainer container = new MappeableRunContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
-    assertEquals(0, container.nextAbsentValue((char)0));
-    assertEquals(63, container.nextAbsentValue((char)63));
-    assertEquals(129, container.nextAbsentValue((char)64));
-    assertEquals(129, container.nextAbsentValue((char)65));
-    assertEquals(129, container.nextAbsentValue((char)128));
-    assertEquals(129, container.nextAbsentValue((char)129));
-    assertEquals(199, container.nextAbsentValue((char)199));
-    assertEquals(501, container.nextAbsentValue((char)200));
-    assertEquals(501, container.nextAbsentValue((char)250));
-    assertEquals(2500, container.nextAbsentValue((char)2500));
-    assertEquals(5201, container.nextAbsentValue((char)5000));
-    assertEquals(5201, container.nextAbsentValue((char)5200));
+    MappeableContainer container =
+        new MappeableRunContainer().iadd(64, 129).iadd(200, 501).iadd(5000, 5201);
+    assertEquals(0, container.nextAbsentValue((char) 0));
+    assertEquals(63, container.nextAbsentValue((char) 63));
+    assertEquals(129, container.nextAbsentValue((char) 64));
+    assertEquals(129, container.nextAbsentValue((char) 65));
+    assertEquals(129, container.nextAbsentValue((char) 128));
+    assertEquals(129, container.nextAbsentValue((char) 129));
+    assertEquals(199, container.nextAbsentValue((char) 199));
+    assertEquals(501, container.nextAbsentValue((char) 200));
+    assertEquals(501, container.nextAbsentValue((char) 250));
+    assertEquals(2500, container.nextAbsentValue((char) 2500));
+    assertEquals(5201, container.nextAbsentValue((char) 5000));
+    assertEquals(5201, container.nextAbsentValue((char) 5200));
   }
 
   @Test
   public void testNextAbsentValueEmpty() {
     MappeableRunContainer container = new MappeableRunContainer();
     for (int i = 0; i < 1000; i++) {
-      assertEquals(i, container.nextAbsentValue((char)i));
+      assertEquals(i, container.nextAbsentValue((char) i));
     }
   }
 
   @Test
   public void testNextAbsentValueSparse() {
-    MappeableContainer container = new MappeableRunContainer(CharBuffer.wrap(new char[] { 10, 0, 20, 0, 30, 0}), 3);
-    assertEquals(9, container.nextAbsentValue((char)9));
-    assertEquals(11, container.nextAbsentValue((char)10));
-    assertEquals(11, container.nextAbsentValue((char)11));
-    assertEquals(21, container.nextAbsentValue((char)21));
-    assertEquals(31, container.nextAbsentValue((char)30));
+    MappeableContainer container =
+        new MappeableRunContainer(CharBuffer.wrap(new char[] {10, 0, 20, 0, 30, 0}), 3);
+    assertEquals(9, container.nextAbsentValue((char) 9));
+    assertEquals(11, container.nextAbsentValue((char) 10));
+    assertEquals(11, container.nextAbsentValue((char) 11));
+    assertEquals(21, container.nextAbsentValue((char) 21));
+    assertEquals(31, container.nextAbsentValue((char) 30));
   }
 
   @Test
@@ -2770,9 +2786,9 @@ public void testNextAbsentEvenBits() {
     }
 
     MappeableRunContainer container = new MappeableRunContainer(CharBuffer.wrap(evenBits), 1 << 14);
-    for (int i = 0; i < 1 << 10; i+=2) {
-      assertEquals(i + 1, container.nextAbsentValue((char)i));
-      assertEquals(i + 1, container.nextAbsentValue((char)(i+1)));
+    for (int i = 0; i < 1 << 10; i += 2) {
+      assertEquals(i + 1, container.nextAbsentValue((char) i));
+      assertEquals(i + 1, container.nextAbsentValue((char) (i + 1)));
     }
   }
 
@@ -2780,21 +2796,20 @@ public void testNextAbsentEvenBits() {
   public void testNextAbsentValueUnsigned() {
     char[] array = {(char) ((1 << 15) | 5), 0, (char) ((1 << 15) | 7), 0};
     MappeableRunContainer container = new MappeableRunContainer(CharBuffer.wrap(array), 2);
-    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char)((1 << 15) | 4)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 5)));
-    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char)((1 << 15) | 6)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 7)));
-    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char)((1 << 15) | 8)));
+    assertEquals(((1 << 15) | 4), container.nextAbsentValue((char) ((1 << 15) | 4)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 5)));
+    assertEquals(((1 << 15) | 6), container.nextAbsentValue((char) ((1 << 15) | 6)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 7)));
+    assertEquals(((1 << 15) | 8), container.nextAbsentValue((char) ((1 << 15) | 8)));
   }
 
   @Test
   public void testContains() {
-    MappeableRunContainer rc = new MappeableRunContainer(CharBuffer.wrap(new char[]{23, 24}), 1);
+    MappeableRunContainer rc = new MappeableRunContainer(CharBuffer.wrap(new char[] {23, 24}), 1);
     assertFalse(rc.contains(48, 49));
   }
 
-
   private static int lower16Bits(int x) {
-    return ((char)x) & 0xFFFF;
+    return ((char) x) & 0xFFFF;
   }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestSerializationViaByteBuffer.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestSerializationViaByteBuffer.java
similarity index 61%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestSerializationViaByteBuffer.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestSerializationViaByteBuffer.java
index a948aa83f..5dc82d1d5 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestSerializationViaByteBuffer.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestSerializationViaByteBuffer.java
@@ -1,5 +1,11 @@
 package org.roaringbitmap.buffer;
 
+import static java.nio.channels.FileChannel.MapMode.READ_WRITE;
+import static java.nio.file.Files.delete;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.roaringbitmap.SeededTestData;
+
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -9,9 +15,13 @@
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.roaringbitmap.SeededTestData;
 
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.FileChannel;
@@ -20,10 +30,6 @@
 import java.util.UUID;
 import java.util.stream.Stream;
 
-import static java.nio.channels.FileChannel.MapMode.READ_WRITE;
-import static java.nio.file.Files.delete;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 @Execution(ExecutionMode.CONCURRENT)
 public class TestSerializationViaByteBuffer {
 
@@ -34,63 +40,62 @@ public static void cleanup() {
 
   public static Stream params() {
     return Stream.of(
-            Arguments.of(2, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(2, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(3, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(3, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(4, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(4, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(5, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(5, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(6, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(6, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(7, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(7, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(8, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(8, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(9, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(9, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(10, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(10, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(11, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(11, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(12, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(12, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(13, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(13, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(14, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(14, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(15, ByteOrder.BIG_ENDIAN, true),
-            Arguments.of(15, ByteOrder.LITTLE_ENDIAN, true),
-            Arguments.of(2, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(2, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(3, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(3, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(4, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(4, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(5, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(5, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(6, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(6, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(7, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(7, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(8, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(8, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(9, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(9, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(10, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(10, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(11, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(11, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(12, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(12, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(13, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(13, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(14, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(14, ByteOrder.LITTLE_ENDIAN, false),
-            Arguments.of(15, ByteOrder.BIG_ENDIAN, false),
-            Arguments.of(15, ByteOrder.LITTLE_ENDIAN, false)
-    );
+        Arguments.of(2, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(2, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(3, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(3, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(4, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(4, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(5, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(5, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(6, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(6, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(7, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(7, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(8, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(8, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(9, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(9, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(10, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(10, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(11, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(11, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(12, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(12, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(13, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(13, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(14, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(14, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(15, ByteOrder.BIG_ENDIAN, true),
+        Arguments.of(15, ByteOrder.LITTLE_ENDIAN, true),
+        Arguments.of(2, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(2, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(3, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(3, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(4, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(4, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(5, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(5, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(6, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(6, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(7, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(7, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(8, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(8, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(9, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(9, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(10, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(10, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(11, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(11, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(12, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(12, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(13, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(13, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(14, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(14, ByteOrder.LITTLE_ENDIAN, false),
+        Arguments.of(15, ByteOrder.BIG_ENDIAN, false),
+        Arguments.of(15, ByteOrder.LITTLE_ENDIAN, false));
   }
 
   private Path file;
@@ -114,11 +119,12 @@ public void after() throws IOException {
 
   @ParameterizedTest
   @MethodSource("params")
-  public void testDeserializeFromMappedFile(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromMappedFile(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     try (RandomAccessFile raf = new RandomAccessFile(file.toFile(), "rw");
-         FileChannel channel = raf.getChannel()) {
+        FileChannel channel = raf.getChannel()) {
       ByteBuffer buffer = channel.map(READ_WRITE, 0, serialised.length);
       buffer.put(serialised);
       buffer.flip();
@@ -129,14 +135,14 @@ public void testDeserializeFromMappedFile(int keys, ByteOrder order, boolean run
     }
   }
 
-
   @ParameterizedTest
   @MethodSource("params")
-  public void testSerializeMappedBitmap(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testSerializeMappedBitmap(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     try (RandomAccessFile raf = new RandomAccessFile(file.toFile(), "rw");
-         FileChannel channel = raf.getChannel()) {
+        FileChannel channel = raf.getChannel()) {
       ByteBuffer buffer = channel.map(READ_WRITE, 0, serialised.length);
       buffer.put(serialised);
       buffer.flip();
@@ -151,7 +157,8 @@ public void testSerializeMappedBitmap(int keys, ByteOrder order, boolean runOpti
 
   @ParameterizedTest
   @MethodSource("params")
-  public void testDeserializeFromHeap(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromHeap(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.wrap(serialised).order(order);
@@ -162,7 +169,8 @@ public void testDeserializeFromHeap(int keys, ByteOrder order, boolean runOptimi
 
   @ParameterizedTest
   @MethodSource("params")
-  public void testDeserializeFromDirect(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromDirect(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocateDirect(serialised.length).order(order);
@@ -175,7 +183,8 @@ public void testDeserializeFromDirect(int keys, ByteOrder order, boolean runOpti
 
   @ParameterizedTest
   @MethodSource("params")
-  public void testDeserializeFromDirectWithOffset(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testDeserializeFromDirectWithOffset(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocateDirect(10 + serialised.length).order(order);
@@ -189,7 +198,8 @@ public void testDeserializeFromDirectWithOffset(int keys, ByteOrder order, boole
 
   @ParameterizedTest
   @MethodSource("params")
-  public void testSerializeCorrectOffset(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testSerializeCorrectOffset(int keys, ByteOrder order, boolean runOptimise)
+      throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocateDirect(10 + serialised.length).order(order);
@@ -201,7 +211,8 @@ public void testSerializeCorrectOffset(int keys, ByteOrder order, boolean runOpt
 
   @ParameterizedTest
   @MethodSource("params")
-  public void testSerializeToByteBufferDeserializeViaStream(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testSerializeToByteBufferDeserializeViaStream(
+      int keys, ByteOrder order, boolean runOptimise) throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocate(serialised.length).order(order);
@@ -216,7 +227,8 @@ public void testSerializeToByteBufferDeserializeViaStream(int keys, ByteOrder or
 
   @ParameterizedTest
   @MethodSource("params")
-  public void testSerializeToByteBufferDeserializeByteBuffer(int keys, ByteOrder order, boolean runOptimise) throws IOException {
+  public void testSerializeToByteBufferDeserializeByteBuffer(
+      int keys, ByteOrder order, boolean runOptimise) throws IOException {
     MutableRoaringBitmap input = SeededTestData.randomBitmap(keys).toMutableRoaringBitmap();
     byte[] serialised = serialise(input, runOptimise);
     ByteBuffer buffer = ByteBuffer.allocate(serialised.length).order(order);
@@ -228,12 +240,13 @@ public void testSerializeToByteBufferDeserializeByteBuffer(int keys, ByteOrder o
     assertEquals(input, roundtrip);
   }
 
-  private static byte[] serialise(MutableRoaringBitmap input, boolean runOptimise) throws IOException {
+  private static byte[] serialise(MutableRoaringBitmap input, boolean runOptimise)
+      throws IOException {
     if (runOptimise) {
       input.runOptimize();
     }
     try (ByteArrayOutputStream bos = new ByteArrayOutputStream(input.serializedSizeInBytes());
-         DataOutputStream dos = new DataOutputStream(bos)) {
+        DataOutputStream dos = new DataOutputStream(bos)) {
       input.serialize(dos);
       return bos.toByteArray();
     }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestSerializedSize.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestSerializedSize.java
similarity index 93%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestSerializedSize.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestSerializedSize.java
index 3cb8b6c2c..a68ff0116 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestSerializedSize.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestSerializedSize.java
@@ -1,13 +1,11 @@
 package org.roaringbitmap.buffer;
 
-import org.junit.jupiter.api.Test;
-
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.junit.jupiter.api.Test;
 
 public class TestSerializedSize {
 
-
   @Test
   public void testEmpty() {
     MutableRoaringBitmap rb = new MutableRoaringBitmap();
@@ -19,8 +17,6 @@ public void testEmpty() {
     assertTrue(rac <= c);
   }
 
-
-
   @Test
   public void testOne() {
     for (int k = 0; k < 100000; k += 100) {
@@ -35,7 +31,6 @@ public void testOne() {
     }
   }
 
-
   @Test
   public void testRange() {
     for (int k = 0; k < 100000; k += 100) {
@@ -50,7 +45,6 @@ public void testRange() {
     }
   }
 
-
   @Test
   public void testLarge() {
     for (long scale = 15; scale < 2048; scale *= 15) {
@@ -59,8 +53,7 @@ public void testLarge() {
       int universe_size = 0;
       for (int k = 0; k < N; ++k) {
         int val = (int) (scale * k);
-        if (val > universe_size)
-          universe_size = val;
+        if (val > universe_size) universe_size = val;
         rb.add((int) (scale * k));
       }
       universe_size++;
@@ -79,14 +72,13 @@ public void testManyRanges() {
       for (long step = 1; step < 500; ++step) {
         MutableRoaringBitmap rb = new MutableRoaringBitmap();
         int universe_size = 0;
-        
+
         for (int i = 0; i < step; ++i) {
           final int maxv = i * (1 << 16) + stepsize;
           rb.add(i * (1L << 16), i * (1L << 16) + stepsize);
-          if (maxv > universe_size)
-            universe_size = maxv;
+          if (maxv > universe_size) universe_size = maxv;
         }
-        long c = MutableRoaringBitmap.maximumSerializedSize(rb.getCardinality(),universe_size);
+        long c = MutableRoaringBitmap.maximumSerializedSize(rb.getCardinality(), universe_size);
         long ac = rb.serializedSizeInBytes();
         assertTrue(ac <= c);
         rb.runOptimize();
@@ -94,5 +86,4 @@ public void testManyRanges() {
         assertTrue(rac <= c);
       }
   }
-
 }
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestUtil.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestUtil.java
new file mode 100644
index 000000000..3fd5ed9b5
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestUtil.java
@@ -0,0 +1,176 @@
+package org.roaringbitmap.buffer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.SeededTestData.denseRegion;
+import static org.roaringbitmap.SeededTestData.rleRegion;
+import static org.roaringbitmap.SeededTestData.sparseRegion;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Execution;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.LongBuffer;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+@Execution(ExecutionMode.CONCURRENT)
+public class TestUtil {
+
+  @Test
+  public void testCopy() {
+    CharBuffer sb = CharBuffer.allocate(64);
+    sb.position(32);
+    CharBuffer slice = sb.slice();
+    CharBuffer dest = CharBuffer.allocate(64);
+    for (int k = 0; k < 32; ++k) slice.put(k, (char) k);
+    BufferUtil.arraycopy(slice, 16, dest, 16, 16);
+    for (int k = 16; k < 32; ++k) assertEquals((char) k, dest.get(k));
+    BufferUtil.arraycopy(slice, 0, dest, 16, 16);
+    for (int k = 16; k < 32; ++k) assertEquals((char) (k - 16), dest.get(k));
+    BufferUtil.arraycopy(slice, 16, dest, 0, 16);
+    for (int k = 0; k < 16; ++k) assertEquals((char) (k + 16), dest.get(k));
+  }
+
+  @Test
+  public void testFillArrayANDNOT() {
+    LongBuffer data1 = LongBuffer.wrap(new long[] {1, 2, 4, 8, 16});
+    LongBuffer data2 = LongBuffer.wrap(new long[] {2, 1, 3, 7, 15});
+    char[] content = new char[5];
+    char[] result = {0, 65, 130, 195, 260};
+    BufferUtil.fillArrayANDNOT(content, data1, data2);
+    assertTrue(Arrays.equals(content, result));
+  }
+
+  @Test
+  public void testFillArrayANDNOTException() {
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          LongBuffer data1 = LongBuffer.wrap(new long[] {1, 2, 4, 8, 16});
+          LongBuffer data2 = LongBuffer.wrap(new long[] {2, 1, 3, 7});
+          char[] content = new char[5];
+          BufferUtil.fillArrayANDNOT(content, data1, data2);
+        });
+  }
+
+  @Test
+  public void testUnsignedIntersects() {
+    CharBuffer data1 =
+        CharBuffer.wrap(
+            fromShorts(new short[] {-100, -98, -96, -94, -92, -90, -88, -86, -84, -82, -80}));
+    CharBuffer data2 =
+        CharBuffer.wrap(
+            fromShorts(new short[] {-99, -97, -95, -93, -91, -89, -87, -85, -83, -81, -79}));
+    CharBuffer data3 =
+        CharBuffer.wrap(
+            fromShorts(new short[] {-99, -97, -95, -93, -91, -89, -87, -85, -83, -81, -80}));
+    CharBuffer data4 = CharBuffer.wrap(new char[] {});
+    CharBuffer data5 = CharBuffer.wrap(new char[] {});
+    assertFalse(BufferUtil.unsignedIntersects(data1, data1.limit(), data2, data2.limit()));
+    assertTrue(BufferUtil.unsignedIntersects(data1, data1.limit(), data3, data3.limit()));
+    assertFalse(BufferUtil.unsignedIntersects(data4, data4.limit(), data5, data5.limit()));
+  }
+
+  @Test
+  public void testAdvanceUntil() {
+    CharBuffer data = CharBuffer.wrap(fromShorts(new short[] {0, 3, 16, 18, 21, 29, 30, -342}));
+    assertEquals(1, BufferUtil.advanceUntil(data, -1, data.limit(), (char) 3));
+    assertEquals(5, BufferUtil.advanceUntil(data, -1, data.limit(), (char) 28));
+    assertEquals(5, BufferUtil.advanceUntil(data, -1, data.limit(), (char) 29));
+    assertEquals(7, BufferUtil.advanceUntil(data, -1, data.limit(), (char) -342));
+  }
+
+  @Test
+  public void testIterateUntil() {
+    CharBuffer data = CharBuffer.wrap(fromShorts(new short[] {0, 3, 16, 18, 21, 29, 30, -342}));
+    assertEquals(1, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) 3)));
+    assertEquals(5, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) 28)));
+    assertEquals(5, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) 29)));
+    assertEquals(7, BufferUtil.iterateUntil(data, 0, data.limit(), ((char) -342)));
+  }
+
+  static char[] fromShorts(short[] array) {
+    char[] result = new char[array.length];
+    for (int i = 0; i < array.length; ++i) {
+      result[i] = (char) (array[i] & 0xFFFF);
+    }
+    return result;
+  }
+
+  public static Stream sets() {
+    return Stream.of(true, false)
+        .flatMap(
+            direct ->
+                Stream.of(
+                    Arguments.of(direct, rleRegion().toArray(), rleRegion().toArray()),
+                    Arguments.of(direct, denseRegion().toArray(), rleRegion().toArray()),
+                    Arguments.of(direct, sparseRegion().toArray(), rleRegion().toArray()),
+                    Arguments.of(direct, rleRegion().toArray(), denseRegion().toArray()),
+                    Arguments.of(direct, denseRegion().toArray(), denseRegion().toArray()),
+                    Arguments.of(direct, sparseRegion().toArray(), denseRegion().toArray()),
+                    Arguments.of(direct, rleRegion().toArray(), sparseRegion().toArray()),
+                    Arguments.of(direct, denseRegion().toArray(), sparseRegion().toArray()),
+                    Arguments.of(direct, sparseRegion().toArray(), sparseRegion().toArray())));
+  }
+
+  @MethodSource("sets")
+  @ParameterizedTest(name = "direct={0}")
+  public void testIntersectBitmapWithArray(boolean direct, int[] set1, int[] set2) {
+    LongBuffer bitmap =
+        direct ? ByteBuffer.allocateDirect(8192).asLongBuffer() : LongBuffer.allocate(1024);
+    for (int i : set1) {
+      bitmap.put(i >>> 6, bitmap.get(i >>> 6) | (1L << i));
+    }
+    LongBuffer referenceBitmap =
+        direct ? ByteBuffer.allocateDirect(8192).asLongBuffer() : LongBuffer.allocate(1024);
+    CharBuffer array =
+        direct
+            ? ByteBuffer.allocateDirect(2 * set2.length).asCharBuffer()
+            : CharBuffer.allocate(set2.length);
+    int pos = 0;
+    for (int i : set2) {
+      referenceBitmap.put(i >>> 6, referenceBitmap.get(i >>> 6) | (1L << i));
+      array.put(pos++, (char) i);
+    }
+    int expectedCardinality = 0;
+    for (int i = 0; i < 1024; ++i) {
+      referenceBitmap.put(i, referenceBitmap.get(i) & bitmap.get(i));
+      expectedCardinality += Long.bitCount(referenceBitmap.get(i));
+    }
+    int cardinality = BufferUtil.intersectArrayIntoBitmap(bitmap, array, set2.length);
+    assertEquals(expectedCardinality, cardinality);
+    for (int i = 0; i < bitmap.limit(); ++i) {
+      assertEquals(bitmap.get(i), referenceBitmap.get(i), "mismatch at " + i);
+    }
+  }
+
+  @Test
+  public void bitmapOfRange() {
+    assertBitmapRange(0, 10); // begin of first container
+    assertBitmapRange(0, 1 << 16 - 1); // early full container
+    assertBitmapRange(0, 1 << 16); // full first container
+    assertBitmapRange(0, 1 << 16 + 1); // full first container + one value the second
+    assertBitmapRange(10, 1 << 16); // without first several integers
+    assertBitmapRange(1 << 16, (1 << 16) * 2); // full second container
+    assertBitmapRange(10, 100); // some integers inside interval
+    assertBitmapRange((1 << 16) - 5, (1 << 16) + 7); // first to second container
+    assertBitmapRange(0, 100_000); // more than one container
+    assertBitmapRange(100_000, 200_000); // second to third container
+    assertBitmapRange(200_000, 400_000); // more containers inside
+  }
+
+  private static void assertBitmapRange(int start, int end) {
+    MutableRoaringBitmap bitmap = MutableRoaringBitmap.bitmapOfRange(start, end);
+    assertEquals(end - start, bitmap.getCardinality());
+    assertEquals(start, bitmap.first());
+    assertEquals(end - 1, bitmap.last());
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestVeryLargeBitmap.java b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestVeryLargeBitmap.java
similarity index 99%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestVeryLargeBitmap.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestVeryLargeBitmap.java
index 334e3c397..700798020 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/buffer/TestVeryLargeBitmap.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/buffer/TestVeryLargeBitmap.java
@@ -1,10 +1,9 @@
 package org.roaringbitmap.buffer;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 public class TestVeryLargeBitmap {
   @Test
   public void testSelect() {
@@ -13,7 +12,7 @@ public void testSelect() {
     assertEquals(-2, map.select(-2));
     assertEquals(-1, map.select(-1));
   }
-  
+
   @Test // this should run fine given enough memory
   public void stupidlyLarge() {
     try {
@@ -32,5 +31,4 @@ public void stupidlyLarge() {
       ome.printStackTrace();
     }
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/insights/BitmapAnalyserTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/insights/BitmapAnalyserTest.java
similarity index 83%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/insights/BitmapAnalyserTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/insights/BitmapAnalyserTest.java
index 82fc80009..2fc0cbdce 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/insights/BitmapAnalyserTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/insights/BitmapAnalyserTest.java
@@ -1,18 +1,17 @@
 package org.roaringbitmap.insights;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.roaringbitmap.RoaringBitmap;
+import org.roaringbitmap.SeededTestData;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.parallel.Execution;
 import org.junit.jupiter.api.parallel.ExecutionMode;
-import org.roaringbitmap.RoaringBitmap;
-import org.roaringbitmap.SeededTestData;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-
 @Execution(ExecutionMode.CONCURRENT)
 public class BitmapAnalyserTest {
 
@@ -25,7 +24,8 @@ public void analyseSingleBitmap() {
       rb.add(i);
     }
     BitmapStatistics result = BitmapAnalyser.analyse(rb);
-    BitmapStatistics expected = new BitmapStatistics(new BitmapStatistics.ArrayContainersStats(1, 6), 1, 1);
+    BitmapStatistics expected =
+        new BitmapStatistics(new BitmapStatistics.ArrayContainersStats(1, 6), 1, 1);
     assertEquals(expected, result);
   }
 
@@ -41,7 +41,10 @@ public void analyseRandomBitmap() {
 
     assertEquals(runFraction, result.containerFraction(result.getRunContainerCount()), delta);
     assertEquals(bitmapFraction, result.containerFraction(result.getBitmapContainerCount()), delta);
-    assertEquals(arrayFraction, result.containerFraction(result.getArrayContainersStats().getContainersCount()), delta);
+    assertEquals(
+        arrayFraction,
+        result.containerFraction(result.getArrayContainersStats().getContainersCount()),
+        delta);
   }
 
   @Test
@@ -62,8 +65,10 @@ public void analyseRandomBitmaps() {
 
     assertEquals(runFraction, result.containerFraction(result.getRunContainerCount()), delta);
     assertEquals(bitmapFraction, result.containerFraction(result.getBitmapContainerCount()), delta);
-    assertEquals(arrayFraction, result.containerFraction(result.getArrayContainersStats().getContainersCount()), delta);
+    assertEquals(
+        arrayFraction,
+        result.containerFraction(result.getArrayContainersStats().getContainersCount()),
+        delta);
     assertEquals(totalBitmaps, result.getBitmapsCount());
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/insights/BitmapStatisticsTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/insights/BitmapStatisticsTest.java
similarity index 85%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/insights/BitmapStatisticsTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/insights/BitmapStatisticsTest.java
index e75b78ea9..1b34c1f04 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/insights/BitmapStatisticsTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/insights/BitmapStatisticsTest.java
@@ -1,19 +1,16 @@
 package org.roaringbitmap.insights;
 
-
-import org.junit.jupiter.api.Test;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.junit.jupiter.api.Test;
+
 public class BitmapStatisticsTest {
 
   @Test
   public void toStringWorks() {
-    BitmapStatistics statistics = new BitmapStatistics(
-      new BitmapStatistics.ArrayContainersStats(10, 50),
-      2,
-      1);
+    BitmapStatistics statistics =
+        new BitmapStatistics(new BitmapStatistics.ArrayContainersStats(10, 50), 2, 1);
 
     String string = statistics.toString();
 
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/insights/NaiveWriterRecommenderTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/insights/NaiveWriterRecommenderTest.java
similarity index 61%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/insights/NaiveWriterRecommenderTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/insights/NaiveWriterRecommenderTest.java
index 97df7d22e..bb9ec30d4 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/insights/NaiveWriterRecommenderTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/insights/NaiveWriterRecommenderTest.java
@@ -1,11 +1,10 @@
 package org.roaringbitmap.insights;
 
-
-import org.junit.jupiter.api.Test;
-
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.junit.jupiter.api.Test;
+
 public class NaiveWriterRecommenderTest {
 
   @Test
@@ -15,15 +14,17 @@ public void recommendForArrays() {
     int bitmapContainerCount = 2;
     int runContainerCount = 50;
     int bitmapsCount = 10;
-    BitmapStatistics stats = new BitmapStatistics(
-      new BitmapStatistics.ArrayContainersStats(arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
-      bitmapContainerCount,
-      runContainerCount,
-      bitmapsCount);
+    BitmapStatistics stats =
+        new BitmapStatistics(
+            new BitmapStatistics.ArrayContainersStats(
+                arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
+            bitmapContainerCount,
+            runContainerCount,
+            bitmapsCount);
 
     String recommendation = NaiveWriterRecommender.recommend(stats);
 
-    //System.out.println(recommendation);
+    // System.out.println(recommendation);
     assertTrue(recommendation.contains(".initialCapacity(2005)"));
     assertTrue(recommendation.contains(".optimiseForArrays()"));
     assertTrue(recommendation.contains(".expectedContainerSize(10)"));
@@ -36,29 +37,33 @@ public void recommendForDenseArrays() {
     int bitmapContainerCount = 2;
     int runContainerCount = 50;
     int bitmapsCount = 10;
-    BitmapStatistics stats = new BitmapStatistics(
-      new BitmapStatistics.ArrayContainersStats(arrayContainerCount, arrayContainerCount * denseAveragePerArrayContaier),
-      bitmapContainerCount,
-      runContainerCount,
-      bitmapsCount);
+    BitmapStatistics stats =
+        new BitmapStatistics(
+            new BitmapStatistics.ArrayContainersStats(
+                arrayContainerCount, arrayContainerCount * denseAveragePerArrayContaier),
+            bitmapContainerCount,
+            runContainerCount,
+            bitmapsCount);
 
     String recommendation = NaiveWriterRecommender.recommend(stats);
 
     assertTrue(recommendation.contains(".constantMemory()"));
   }
 
-    @Test
+  @Test
   public void recommendForRuns() {
     int arrayContainerCount = 100;
     int averagePerArrayContaier = 10;
     int bitmapContainerCount = 200;
     int runContainerCount = 50000;
     int bitmapsCount = 70;
-    BitmapStatistics stats = new BitmapStatistics(
-      new BitmapStatistics.ArrayContainersStats(arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
-      bitmapContainerCount,
-      runContainerCount,
-      bitmapsCount);
+    BitmapStatistics stats =
+        new BitmapStatistics(
+            new BitmapStatistics.ArrayContainersStats(
+                arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
+            bitmapContainerCount,
+            runContainerCount,
+            bitmapsCount);
 
     String recommendation = NaiveWriterRecommender.recommend(stats);
 
@@ -66,7 +71,6 @@ public void recommendForRuns() {
     assertTrue(recommendation.contains(".optimiseForRuns()"));
   }
 
-
   @Test
   public void recommendForUniform() {
     int arrayContainerCount = 10000;
@@ -74,11 +78,13 @@ public void recommendForUniform() {
     int bitmapContainerCount = 10000;
     int runContainerCount = 10000;
     int bitmapsCount = 120;
-    BitmapStatistics stats = new BitmapStatistics(
-      new BitmapStatistics.ArrayContainersStats(arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
-      bitmapContainerCount,
-      runContainerCount,
-      bitmapsCount);
+    BitmapStatistics stats =
+        new BitmapStatistics(
+            new BitmapStatistics.ArrayContainersStats(
+                arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
+            bitmapContainerCount,
+            runContainerCount,
+            bitmapsCount);
 
     String recommendation = NaiveWriterRecommender.recommend(stats);
 
@@ -93,11 +99,13 @@ public void recommendForBitmaps() {
     int bitmapContainerCount = 100000;
     int runContainerCount = 40;
     int bitmapsCount = 190;
-    BitmapStatistics stats = new BitmapStatistics(
-      new BitmapStatistics.ArrayContainersStats(arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
-      bitmapContainerCount,
-      runContainerCount,
-      bitmapsCount);
+    BitmapStatistics stats =
+        new BitmapStatistics(
+            new BitmapStatistics.ArrayContainersStats(
+                arrayContainerCount, arrayContainerCount * averagePerArrayContaier),
+            bitmapContainerCount,
+            runContainerCount,
+            bitmapsCount);
 
     String recommendation = NaiveWriterRecommender.recommend(stats);
 
@@ -106,9 +114,8 @@ public void recommendForBitmaps() {
   }
 
   @Test
-  public void notRecommendForEmptyStats(){
+  public void notRecommendForEmptyStats() {
     String recommendation = NaiveWriterRecommender.recommend(BitmapStatistics.empty);
     assertFalse(recommendation.contains(".initialCapacity"));
   }
-
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/ArtTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/ArtTest.java
similarity index 83%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/longlong/ArtTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/longlong/ArtTest.java
index 0a8bd6d75..661dd0ee8 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/ArtTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/ArtTest.java
@@ -1,5 +1,13 @@
 package org.roaringbitmap.longlong;
 
+import org.roaringbitmap.art.Art;
+import org.roaringbitmap.art.LeafNode;
+import org.roaringbitmap.art.LeafNodeIterator;
+import org.roaringbitmap.art.Node;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
@@ -7,19 +15,13 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.roaringbitmap.art.Art;
-import org.roaringbitmap.art.LeafNode;
-import org.roaringbitmap.art.LeafNodeIterator;
-import org.roaringbitmap.art.Node;
 
 public class ArtTest {
 
-  //one leaf node
+  // one leaf node
   @Test
   public void testLeafNode() {
-    byte[] key1 = new byte[]{1, 2, 3, 4, 5, 0};
+    byte[] key1 = new byte[] {1, 2, 3, 4, 5, 0};
     Art art = new Art();
     insert5PrefixCommonBytesIntoArt(art, 1);
     LeafNodeIterator leafNodeIterator = art.leafNodeIterator(false, null);
@@ -34,11 +36,11 @@ public void testLeafNode() {
     Assertions.assertTrue(art.findByKey(key1) == Node.ILLEGAL_IDX);
   }
 
-  //one node4 with two leaf nodes
+  // one node4 with two leaf nodes
   @Test
   public void testNode4() {
-    byte[] key1 = new byte[]{1, 2, 3, 4, 5, 0};
-    byte[] key2 = new byte[]{1, 2, 3, 4, 5, 1};
+    byte[] key1 = new byte[] {1, 2, 3, 4, 5, 0};
+    byte[] key2 = new byte[] {1, 2, 3, 4, 5, 1};
     Art art = new Art();
     insert5PrefixCommonBytesIntoArt(art, 2);
     LeafNodeIterator leafNodeIterator = art.leafNodeIterator(false, null);
@@ -55,19 +57,19 @@ public void testNode4() {
     hasNext = leafNodeIterator.hasNext();
     Assertions.assertTrue(!hasNext);
     art.remove(key1);
-    //shrink to leaf node
+    // shrink to leaf node
     long containerIdx2 = art.findByKey(key2);
     Assertions.assertEquals(1, containerIdx2);
   }
 
-  //1 node16
+  // 1 node16
   @Test
   public void testNode16() throws Exception {
-    byte[] key1 = new byte[]{1, 2, 3, 4, 5, 0};
-    byte[] key2 = new byte[]{1, 2, 3, 4, 5, 1};
-    byte[] key3 = new byte[]{1, 2, 3, 4, 5, 2};
-    byte[] key4 = new byte[]{1, 2, 3, 4, 5, 3};
-    byte[] key5 = new byte[]{1, 2, 3, 4, 5, 4};
+    byte[] key1 = new byte[] {1, 2, 3, 4, 5, 0};
+    byte[] key2 = new byte[] {1, 2, 3, 4, 5, 1};
+    byte[] key3 = new byte[] {1, 2, 3, 4, 5, 2};
+    byte[] key4 = new byte[] {1, 2, 3, 4, 5, 3};
+    byte[] key5 = new byte[] {1, 2, 3, 4, 5, 4};
     Art art = new Art();
     insert5PrefixCommonBytesIntoArt(art, 5);
     LeafNodeIterator leafNodeIterator = art.leafNodeIterator(false, null);
@@ -87,13 +89,13 @@ public void testNode16() throws Exception {
     Assertions.assertEquals(3, containerIdx);
     containerIdx = art.findByKey(key5);
     Assertions.assertEquals(4, containerIdx);
-    //ser/deser
+    // ser/deser
     int sizeInBytes = (int) art.serializeSizeInBytes();
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
     DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
     art.serializeArt(dataOutputStream);
-    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
-        byteArrayOutputStream.toByteArray());
+    ByteArrayInputStream byteArrayInputStream =
+        new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
     DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
     Art deserArt = new Art();
     deserArt.deserializeArt(dataInputStream);
@@ -107,33 +109,33 @@ public void testNode16() throws Exception {
 
     art.remove(key5);
     art.remove(key4);
-    //shrink to node4
+    // shrink to node4
     long containerIdx4 = art.findByKey(key3);
     Assertions.assertEquals(2, containerIdx4);
   }
 
-  //node48
+  // node48
   @Test
   public void testNode48() throws Exception {
     Art art = new Art();
     insert5PrefixCommonBytesIntoArt(art, 17);
-    byte[] key = new byte[]{1, 2, 3, 4, 5, 0};
+    byte[] key = new byte[] {1, 2, 3, 4, 5, 0};
     long containerIdx = art.findByKey(key);
     Assertions.assertTrue(containerIdx == 0);
-    key = new byte[]{1, 2, 3, 4, 5, 10};
+    key = new byte[] {1, 2, 3, 4, 5, 10};
     containerIdx = art.findByKey(key);
     Assertions.assertTrue(containerIdx == 10);
-    key = new byte[]{1, 2, 3, 4, 5, 12};
+    key = new byte[] {1, 2, 3, 4, 5, 12};
     containerIdx = art.findByKey(key);
     Assertions.assertTrue(containerIdx == 12);
-    byte[] key13 = new byte[]{1, 2, 3, 4, 5, 12};
-    //ser/deser
+    byte[] key13 = new byte[] {1, 2, 3, 4, 5, 12};
+    // ser/deser
     int sizeInBytes = (int) art.serializeSizeInBytes();
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(sizeInBytes);
     DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
     art.serializeArt(dataOutputStream);
-    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
-        byteArrayOutputStream.toByteArray());
+    ByteArrayInputStream byteArrayInputStream =
+        new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
     DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
     Art deserArt = new Art();
     deserArt.deserializeArt(dataInputStream);
@@ -146,34 +148,34 @@ public void testNode48() throws Exception {
     Assertions.assertEquals(art.findByKey(key13), deserArt.findByKey(key13));
     Assertions.assertEquals(art.getKeySize(), deserArt.getKeySize());
 
-    //shrink to node16
+    // shrink to node16
     for (int i = 0; i < 6; i++) {
       key13[5] = (byte) (12 + i);
       art.remove(key13);
     }
-    byte[] key12 = new byte[]{1, 2, 3, 4, 5, 11};
+    byte[] key12 = new byte[] {1, 2, 3, 4, 5, 11};
     long containerIdx12 = art.findByKey(key12);
     Assertions.assertEquals(11, containerIdx12);
   }
 
-  //node256
+  // node256
   @Test
   public void testNode256() throws IOException {
     Art art = new Art();
     insert5PrefixCommonBytesIntoArt(art, 50);
-    byte[] key = new byte[]{1, 2, 3, 4, 5, 0};
+    byte[] key = new byte[] {1, 2, 3, 4, 5, 0};
     long containerIdx = art.findByKey(key);
     Assertions.assertTrue(containerIdx == 0);
-    key = new byte[]{1, 2, 3, 4, 5, 10};
+    key = new byte[] {1, 2, 3, 4, 5, 10};
     containerIdx = art.findByKey(key);
     Assertions.assertEquals(10, containerIdx);
-    key = new byte[]{1, 2, 3, 4, 5, 16};
+    key = new byte[] {1, 2, 3, 4, 5, 16};
     containerIdx = art.findByKey(key);
     Assertions.assertTrue(containerIdx == 16);
-    key = new byte[]{1, 2, 3, 4, 5, 36};
+    key = new byte[] {1, 2, 3, 4, 5, 36};
     containerIdx = art.findByKey(key);
     Assertions.assertTrue(containerIdx == 36);
-    key = new byte[]{1, 2, 3, 4, 5, 51};
+    key = new byte[] {1, 2, 3, 4, 5, 51};
     containerIdx = art.findByKey(key);
     Assertions.assertTrue(containerIdx == Node.ILLEGAL_IDX);
     long sizeInBytesL = art.serializeSizeInBytes();
@@ -183,10 +185,10 @@ public void testNode256() throws IOException {
     art.serializeArt(dataOutputStream);
     Assertions.assertEquals(sizeInBytesI, byteArrayOutputStream.toByteArray().length);
     Art deserArt = new Art();
-    DataInputStream dataInputStream = new DataInputStream(
-        new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
+    DataInputStream dataInputStream =
+        new DataInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
     deserArt.deserializeArt(dataInputStream);
-    key = new byte[]{1, 2, 3, 4, 5, 36};
+    key = new byte[] {1, 2, 3, 4, 5, 36};
     containerIdx = deserArt.findByKey(key);
     Assertions.assertEquals(36, containerIdx);
 
@@ -198,18 +200,18 @@ public void testNode256() throws IOException {
     containerIdx = deserBBOne.findByKey(key);
     Assertions.assertEquals(36, containerIdx);
 
-    //shrink to node48
+    // shrink to node48
     deserArt.remove(key);
-    key = new byte[]{1, 2, 3, 4, 5, 10};
+    key = new byte[] {1, 2, 3, 4, 5, 10};
     containerIdx = deserArt.findByKey(key);
     Assertions.assertTrue(containerIdx == 10);
   }
 
   @Test
   public void testNodeSeek() {
-    byte[] key0 = new byte[]{1, 2, 3, 4, 5, 0};
-    byte[] key1 = new byte[]{1, 2, 3, 4, 5, 1};
-    byte[] key2 = new byte[]{1, 2, 3, 4, 5, 2};
+    byte[] key0 = new byte[] {1, 2, 3, 4, 5, 0};
+    byte[] key1 = new byte[] {1, 2, 3, 4, 5, 1};
+    byte[] key2 = new byte[] {1, 2, 3, 4, 5, 2};
     Art art = new Art();
     insert5PrefixCommonBytesIntoArt(art, 3);
     LeafNodeIterator lnIt = art.leafNodeIterator(false, null);
@@ -236,7 +238,8 @@ public void testNodeSeek() {
     Assertions.assertTrue(BytesUtil.same(lnIt.next().getKeyBytes(), key2));
     Assertions.assertFalse(lnIt.hasNext());
 
-    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher levels
+    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher
+    // levels
     // (as it is)
     lnIt.seek(LongUtils.toLong(key1, (char) 0));
     Assertions.assertTrue(lnIt.hasNext());
@@ -245,9 +248,9 @@ public void testNodeSeek() {
 
   @Test
   public void testNodeSeekReverse() {
-    byte[] key0 = new byte[]{1, 2, 3, 4, 5, 0};
-    byte[] key1 = new byte[]{1, 2, 3, 4, 5, 1};
-    byte[] key2 = new byte[]{1, 2, 3, 4, 5, 2};
+    byte[] key0 = new byte[] {1, 2, 3, 4, 5, 0};
+    byte[] key1 = new byte[] {1, 2, 3, 4, 5, 1};
+    byte[] key2 = new byte[] {1, 2, 3, 4, 5, 2};
     Art art = new Art();
     insert5PrefixCommonBytesIntoArt(art, 3);
     LeafNodeIterator lnIt = art.leafNodeIterator(true, null);
@@ -274,7 +277,8 @@ public void testNodeSeekReverse() {
     Assertions.assertTrue(BytesUtil.same(lnIt.next().getKeyBytes(), key0));
     Assertions.assertFalse(lnIt.hasNext());
 
-    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher levels
+    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher
+    // levels
     // (as it is)
     lnIt.seek(LongUtils.toLong(key1, (char) 0));
     Assertions.assertTrue(lnIt.hasNext());
@@ -283,13 +287,13 @@ public void testNodeSeekReverse() {
 
   @Test
   public void testNodeSeekOverGaps() {
-    byte[] start0 = new byte[]{0, 2, 3, 4, 5, 0};
-    byte[] key0 = new byte[]{1, 2, 3, 4, 5, 0};
-    byte[] gap1 = new byte[]{1, 2, 3, 4, 5, 1};
-    byte[] key1 = new byte[]{1, 2, 3, 4, 5, 2};
-    byte[] gap2 = new byte[]{1, 2, 3, 4, 5, 3};
-    byte[] key2 = new byte[]{1, 2, 3, 4, 5, 4};
-    byte[] end1 = new byte[]{2, 2, 3, 4, 5, 4};
+    byte[] start0 = new byte[] {0, 2, 3, 4, 5, 0};
+    byte[] key0 = new byte[] {1, 2, 3, 4, 5, 0};
+    byte[] gap1 = new byte[] {1, 2, 3, 4, 5, 1};
+    byte[] key1 = new byte[] {1, 2, 3, 4, 5, 2};
+    byte[] gap2 = new byte[] {1, 2, 3, 4, 5, 3};
+    byte[] key2 = new byte[] {1, 2, 3, 4, 5, 4};
+    byte[] end1 = new byte[] {2, 2, 3, 4, 5, 4};
 
     Art art = new Art();
     insert5PrefixCommonWithGapBytesIntoArt(art, 3);
@@ -317,7 +321,8 @@ public void testNodeSeekOverGaps() {
     Assertions.assertTrue(BytesUtil.same(lnIt.next().getKeyBytes(), key2));
     Assertions.assertFalse(lnIt.hasNext());
 
-    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher levels
+    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher
+    // levels
     // (as it is)
     lnIt.seek(LongUtils.toLong(key0, (char) 0));
     Assertions.assertTrue(lnIt.hasNext());
@@ -342,21 +347,20 @@ public void testNodeSeekOverGaps() {
     Assertions.assertFalse(lnIt.hasNext());
 
     // going the before the first should "return" the first
-    lnIt.seek(LongUtils.toLong(start0, (char)0));
+    lnIt.seek(LongUtils.toLong(start0, (char) 0));
     Assertions.assertTrue(lnIt.hasNext());
     Assertions.assertTrue(BytesUtil.same(lnIt.peekNext().getKeyBytes(), key0));
-
   }
 
   @Test
   public void testNodeSeekOverGapsReverse() {
-    byte[] start0 = new byte[]{2, 2, 3, 4, 5, 0};
-    byte[] key0 = new byte[]{1, 2, 3, 4, 5, 4};
-    byte[] gap1 = new byte[]{1, 2, 3, 4, 5, 3};
-    byte[] key1 = new byte[]{1, 2, 3, 4, 5, 2};
-    byte[] gap2 = new byte[]{1, 2, 3, 4, 5, 1};
-    byte[] key2 = new byte[]{1, 2, 3, 4, 5, 0};
-    byte[] end1 = new byte[]{0, 2, 3, 4, 5, 0};
+    byte[] start0 = new byte[] {2, 2, 3, 4, 5, 0};
+    byte[] key0 = new byte[] {1, 2, 3, 4, 5, 4};
+    byte[] gap1 = new byte[] {1, 2, 3, 4, 5, 3};
+    byte[] key1 = new byte[] {1, 2, 3, 4, 5, 2};
+    byte[] gap2 = new byte[] {1, 2, 3, 4, 5, 1};
+    byte[] key2 = new byte[] {1, 2, 3, 4, 5, 0};
+    byte[] end1 = new byte[] {0, 2, 3, 4, 5, 0};
 
     Art art = new Art();
     insert5PrefixCommonWithGapBytesIntoArt(art, 3);
@@ -384,7 +388,8 @@ public void testNodeSeekOverGapsReverse() {
     Assertions.assertTrue(BytesUtil.same(lnIt.next().getKeyBytes(), key2));
     Assertions.assertFalse(lnIt.hasNext());
 
-    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher levels
+    // seeking to the prior "1" takes you there.. so this needs to be guarded against, in higher
+    // levels
     // (as it is)
     lnIt.seek(LongUtils.toLong(key0, (char) 0));
     Assertions.assertTrue(lnIt.hasNext());
@@ -409,32 +414,32 @@ public void testNodeSeekOverGapsReverse() {
     Assertions.assertFalse(lnIt.hasNext());
 
     // going the before the first should "return" the first
-    lnIt.seek(LongUtils.toLong(start0, (char)0));
+    lnIt.seek(LongUtils.toLong(start0, (char) 0));
     Assertions.assertTrue(lnIt.hasNext());
     Assertions.assertTrue(BytesUtil.same(lnIt.peekNext().getKeyBytes(), key0));
   }
 
   private void insert5PrefixCommonBytesIntoArt(Art art, int keyNum) {
-    byte[] key = new byte[]{1, 2, 3, 4, 5, 0};
+    byte[] key = new byte[] {1, 2, 3, 4, 5, 0};
     byte b = 0;
     long containerIdx = 0;
     for (int i = 0; i < keyNum; i++) {
       key[5] = b;
       art.insert(key, containerIdx);
-      key = new byte[]{1, 2, 3, 4, 5, 0};
+      key = new byte[] {1, 2, 3, 4, 5, 0};
       b++;
       containerIdx++;
     }
   }
 
   private void insert5PrefixCommonWithGapBytesIntoArt(Art art, int keyNum) {
-    byte[] key = new byte[]{1, 2, 3, 4, 5, 0};
+    byte[] key = new byte[] {1, 2, 3, 4, 5, 0};
     byte b = 0;
     long containerIdx = 0;
     for (int i = 0; i < keyNum; i++) {
       key[5] = b;
       art.insert(key, containerIdx);
-      key = new byte[]{1, 2, 3, 4, 5, 0};
+      key = new byte[] {1, 2, 3, 4, 5, 0};
       b += 2;
       containerIdx++;
     }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/BytesUtil.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/BytesUtil.java
similarity index 100%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/longlong/BytesUtil.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/longlong/BytesUtil.java
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/ContainersTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/ContainersTest.java
similarity index 95%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/longlong/ContainersTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/longlong/ContainersTest.java
index 1342d6e2f..162959ec2 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/ContainersTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/ContainersTest.java
@@ -1,5 +1,15 @@
 package org.roaringbitmap.longlong;
 
+import org.roaringbitmap.ArrayContainer;
+import org.roaringbitmap.BitmapContainer;
+import org.roaringbitmap.Container;
+import org.roaringbitmap.RunContainer;
+import org.roaringbitmap.art.ContainerIterator;
+import org.roaringbitmap.art.Containers;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
@@ -7,14 +17,6 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.roaringbitmap.ArrayContainer;
-import org.roaringbitmap.BitmapContainer;
-import org.roaringbitmap.Container;
-import org.roaringbitmap.RunContainer;
-import org.roaringbitmap.art.ContainerIterator;
-import org.roaringbitmap.art.Containers;
 
 public class ContainersTest {
 
@@ -49,7 +51,7 @@ public void test1() {
       if (i == 0) {
         long currentContainerIdx = containerIterator.getCurrentContainerIdx();
         Assertions.assertEquals(cidx0, currentContainerIdx);
-        RunContainer rc = new RunContainer(new char[]{23, 24}, 1);
+        RunContainer rc = new RunContainer(new char[] {23, 24}, 1);
         containerIterator.replace(rc);
       }
       i++;
@@ -57,7 +59,7 @@ public void test1() {
     Assertions.assertTrue(i == 3);
     Container replacedContainer = containers.getContainer(cidx0);
     Assertions.assertEquals(23, replacedContainer.select(0));
-    ArrayContainer arrayContainer1 = new ArrayContainer(new char[]{10, 20, 30});
+    ArrayContainer arrayContainer1 = new ArrayContainer(new char[] {10, 20, 30});
     containers.replace(cidx1, arrayContainer1);
     replacedContainer = containers.getContainer(cidx1);
     Assertions.assertTrue(replacedContainer == arrayContainer1);
@@ -77,8 +79,8 @@ public void test2() throws IOException {
     DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
     containers.serialize(dataOutputStream);
     Containers deseredOne = new Containers();
-    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
-        byteArrayOutputStream.toByteArray());
+    ByteArrayInputStream byteArrayInputStream =
+        new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
     DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
     deseredOne.deserialize(dataInputStream);
     long containerSize = deseredOne.getContainerSize();
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/IntegerUtilTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/IntegerUtilTest.java
similarity index 93%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/longlong/IntegerUtilTest.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/longlong/IntegerUtilTest.java
index f74c682d1..94ead800d 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/IntegerUtilTest.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/IntegerUtilTest.java
@@ -1,9 +1,9 @@
 package org.roaringbitmap.longlong;
 
-import org.junit.jupiter.api.Test;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
+import org.junit.jupiter.api.Test;
+
 public class IntegerUtilTest {
 
   @Test
@@ -25,10 +25,10 @@ public void testConvertIntToBytes() {
   @Test
   public void testSetByte() {
     for (int i = 0; i < 4; ++i) {
-      int value = IntegerUtil.setByte(0x55555555, (byte)0xAA, i);
+      int value = IntegerUtil.setByte(0x55555555, (byte) 0xAA, i);
       byte[] bytes = IntegerUtil.toBDBytes(value);
       for (int j = 0; j < 4; ++j) {
-        byte expected = i == j ? (byte)0xAA : (byte)0x55;
+        byte expected = i == j ? (byte) 0xAA : (byte) 0x55;
         assertEquals(expected, bytes[j]);
       }
     }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/Issue319.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/Issue319.java
similarity index 61%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/longlong/Issue319.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/longlong/Issue319.java
index 8eab5a8d1..f3473994d 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/Issue319.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/Issue319.java
@@ -12,8 +12,7 @@ public class Issue319 {
 
   public static void main(String[] args) throws IOException {
     RoaringBitmap mrb = RoaringBitmap.bitmapOf(1, 2, 3, 1000);
-    for (int k = 0; k < 1000000000; k += 13)
-      mrb.add(k);
+    for (int k = 0; k < 1000000000; k += 13) mrb.add(k);
     mrb.runOptimize();
     int count = 30;
     byte[] array = serialize(mrb);
@@ -25,26 +24,28 @@ public static void main(String[] args) throws IOException {
       bef = System.currentTimeMillis();
       RoaringBitmap ret = new RoaringBitmap();
       try {
-        ret.deserialize(new java.io.DataInputStream(new java.io.InputStream() {
-          int c = 0;
-
-          @Override
-          public int read() {
-            return array[c++] & 0xff;
-          }
-
-          @Override
-          public int read(byte b[]) {
-            return read(b, 0, b.length);
-          }
-
-          @Override
-          public int read(byte[] b, int off, int l) {
-            System.arraycopy(array, c, b, off, l);
-            c += l;
-            return l;
-          }
-        }));
+        ret.deserialize(
+            new java.io.DataInputStream(
+                new java.io.InputStream() {
+                  int c = 0;
+
+                  @Override
+                  public int read() {
+                    return array[c++] & 0xff;
+                  }
+
+                  @Override
+                  public int read(byte b[]) {
+                    return read(b, 0, b.length);
+                  }
+
+                  @Override
+                  public int read(byte[] b, int off, int l) {
+                    System.arraycopy(array, c, b, off, l);
+                    c += l;
+                    return l;
+                  }
+                }));
       } catch (IOException ioe) {
         // should never happen because we read from a byte array
         throw new RuntimeException("unexpected error while deserializing from a byte array");
@@ -52,12 +53,10 @@ public int read(byte[] b, int off, int l) {
       aft = System.currentTimeMillis();
       System.out.print(aft - bef + " ms ");
       sum += aft - bef;
-      if (!ret.equals(mrb))
-        throw new RuntimeException("bug");
+      if (!ret.equals(mrb)) throw new RuntimeException("bug");
     }
     System.out.println("\naverage: " + sum / count);
 
-
     System.out.println("via ByteArrayInputStream: ");
     sum = 0;
     for (int k = 0; k < count; k++) {
@@ -67,8 +66,7 @@ public int read(byte[] b, int off, int l) {
       aft = System.currentTimeMillis();
       System.out.print(aft - bef + " ms ");
       sum += aft - bef;
-      if (!ret.equals(mrb))
-        throw new RuntimeException("bug");
+      if (!ret.equals(mrb)) throw new RuntimeException("bug");
     }
     System.out.println("\naverage: " + sum / count);
 
@@ -80,8 +78,7 @@ public int read(byte[] b, int off, int l) {
       aft = System.currentTimeMillis();
       System.out.print(aft - bef + " ms ");
       sum += aft - bef;
-      if (!ret.equals(mrb))
-        throw new RuntimeException("bug");
+      if (!ret.equals(mrb)) throw new RuntimeException("bug");
     }
     System.out.println("\naverage: " + sum / count);
 
@@ -94,41 +91,41 @@ public int read(byte[] b, int off, int l) {
       aft = System.currentTimeMillis();
       System.out.print(aft - bef + " ms ");
       sum += aft - bef;
-      if (!ret.equals(mrb))
-        throw new RuntimeException("bug");
+      if (!ret.equals(mrb)) throw new RuntimeException("bug");
     }
     System.out.println("\naverage: " + sum / count);
-
   }
 
   private static byte[] serialize(RoaringBitmap mrb) {
     byte[] array = new byte[mrb.serializedSizeInBytes()];
     try {
-      mrb.serialize(new java.io.DataOutputStream(new java.io.OutputStream() {
-        int c = 0;
-
-        @Override
-        public void close() {}
-
-        @Override
-        public void flush() {}
-
-        @Override
-        public void write(int b) {
-          array[c++] = (byte) b;
-        }
-
-        @Override
-        public void write(byte[] b) {
-          write(b, 0, b.length);
-        }
-
-        @Override
-        public void write(byte[] b, int off, int l) {
-          System.arraycopy(b, off, array, c, l);
-          c += l;
-        }
-      }));
+      mrb.serialize(
+          new java.io.DataOutputStream(
+              new java.io.OutputStream() {
+                int c = 0;
+
+                @Override
+                public void close() {}
+
+                @Override
+                public void flush() {}
+
+                @Override
+                public void write(int b) {
+                  array[c++] = (byte) b;
+                }
+
+                @Override
+                public void write(byte[] b) {
+                  write(b, 0, b.length);
+                }
+
+                @Override
+                public void write(byte[] b, int off, int l) {
+                  System.arraycopy(b, off, array, c, l);
+                  c += l;
+                }
+              }));
     } catch (IOException ioe) {
       // should never happen because we write to a byte array
       throw new RuntimeException("unexpected error while serializing to a byte array");
diff --git a/roaringbitmap/src/test/java/org/roaringbitmap/longlong/JolBenchmarksTest.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/JolBenchmarksTest.java
new file mode 100644
index 000000000..635563b00
--- /dev/null
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/JolBenchmarksTest.java
@@ -0,0 +1,139 @@
+package org.roaringbitmap.longlong;
+
+import com.google.common.primitives.Ints;
+import org.openjdk.jol.info.GraphLayout;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+
+/**
+ * This runs benchmarks over {@link Roaring64NavigableMap} memory layout, as suggested in
+ * https://github.com/RoaringBitmap/RoaringBitmap/issues/346
+ */
+// https://github.com/openjdk/jol
+// https://github.com/RoaringBitmap/RoaringBitmap/issues/346
+public class JolBenchmarksTest {
+
+  @SuppressWarnings("restriction")
+  public static void main(String[] args) {
+    // distinctHigherRadices();
+    // sameHigherRadix();
+    statisticsWithGrowingSizes();
+  }
+
+  private static void distinctHigherRadices() {
+    int valuesPerRadix = 1 << 16;
+    int distance = 2000;
+    Roaring64NavigableMap bitmapMap = new Roaring64NavigableMap();
+    long[] radices = new long[1024];
+    for (int i = 0; i < radices.length; ++i) {
+      radices[i] = ((long) i) << 48;
+    }
+    for (int i = 0; i < radices.length; i++) {
+      for (int j = 0; j < valuesPerRadix; ++j) {
+        bitmapMap.addLong(radices[i] | (j * distance));
+      }
+    }
+
+    long[] bitmapArray = bitmapMap.toArray();
+
+    Roaring64Bitmap bitmapArt = new Roaring64Bitmap();
+    bitmapArt.add(bitmapArray);
+
+    System.out.println("---distinctHigherRadices---");
+    System.out.println(GraphLayout.parseInstance(bitmapArray).toFootprint());
+
+    System.out.println("---");
+    System.out.println(GraphLayout.parseInstance(bitmapMap).toFootprint());
+    System.out.println(bitmapMap.getLongSizeInBytes());
+    bitmapMap.runOptimize();
+    System.out.println(GraphLayout.parseInstance(bitmapMap).toFootprint());
+    System.out.println(bitmapMap.getLongSizeInBytes());
+
+    System.out.println("---");
+    System.out.println(GraphLayout.parseInstance(bitmapArt).toFootprint());
+    System.out.println(bitmapArt.getLongSizeInBytes());
+    bitmapArt.runOptimize();
+    System.out.println(GraphLayout.parseInstance(bitmapArt).toFootprint());
+    System.out.println(bitmapArt.getLongSizeInBytes());
+  }
+
+  private static void sameHigherRadix() {
+    int numValues = (1 << 16) * 1024;
+    int distance = 2000;
+    Roaring64NavigableMap bitmap = new Roaring64NavigableMap();
+
+    long x = 0L;
+    for (int i = 0; i < numValues; i++) {
+      bitmap.addLong(x);
+      x += distance;
+    }
+
+    long[] array = bitmap.toArray();
+
+    Roaring64Bitmap bitmapOpt = new Roaring64Bitmap();
+    bitmapOpt.add(array);
+
+    System.out.println("---sameHigherRadix---");
+    System.out.println(GraphLayout.parseInstance(array).toFootprint());
+
+    System.out.println("---");
+    System.out.println(GraphLayout.parseInstance(bitmap).toFootprint());
+    bitmap.runOptimize();
+    System.out.println(GraphLayout.parseInstance(bitmap).toFootprint());
+
+    System.out.println("---");
+    System.out.println(GraphLayout.parseInstance(bitmapOpt).toFootprint());
+    bitmapOpt.runOptimize();
+    System.out.println(GraphLayout.parseInstance(bitmapOpt).toFootprint());
+  }
+
+  public static void statisticsWithGrowingSizes() {
+    Random r = new Random();
+
+    // We re-use the bitmaps so that we accumulate the longs into them
+    // We then expect to have denser buckets (around 0)
+    Roaring64Bitmap bitmap64Art = new Roaring64Bitmap();
+    Roaring64NavigableMap bitmap64Map = new Roaring64NavigableMap();
+
+    for (long size = 0; size < 1024; size++) {
+      long max = (1L + size * size * size * size * size);
+      System.out.println(size + " in [-" + max + ", " + max + "[");
+
+      long fSize = size;
+      long[] array =
+          IntStream.range(0, Ints.checkedCast(size))
+              .mapToLong(i -> i)
+              .flatMap(i -> LongStream.generate(() -> r.nextLong() % max).limit(fSize))
+              .toArray();
+
+      reportBitmapsMemory(array, bitmap64Art, bitmap64Map);
+    }
+  }
+
+  private static void reportBitmapsMemory(
+      long[] array, LongBitmapDataProvider bitmap, LongBitmapDataProvider bitmap2) {
+    reportBitmapsMemory(array, bitmap);
+    reportBitmapsMemory(array, bitmap2);
+
+    if (!Arrays.equals(bitmap.toArray(), bitmap.toArray())) {
+      throw new IllegalStateException("Issue with: " + Arrays.toString(array));
+    }
+  }
+
+  private static void reportBitmapsMemory(long[] array, LongBitmapDataProvider bitmap) {
+    LongStream.of(array).forEach(bitmap::addLong);
+    long jolSize = GraphLayout.parseInstance(bitmap).totalSize();
+    long ownEstimation = bitmap.getLongSizeInBytes();
+    System.out.println(
+        bitmap.getClass().getSimpleName()
+            + ": "
+            + String.format("%,d", jolSize)
+            + "(real) vs "
+            + String.format("%,d", ownEstimation)
+            + "(estimated) "
+            + (ownEstimation < jolSize ? "optimistic" : "pessimistic"));
+  }
+}
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64Bitmap.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64Bitmap.java
similarity index 77%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64Bitmap.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64Bitmap.java
index 7470d7a72..b1b1ed1e4 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64Bitmap.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64Bitmap.java
@@ -1,7 +1,5 @@
 package org.roaringbitmap.longlong;
 
-import org.apache.commons.lang3.SerializationUtils;
-
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -11,9 +9,20 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import static org.roaringbitmap.Util.toUnsignedLong;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
+import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
+
+import org.roaringbitmap.RoaringBitmap;
+import org.roaringbitmap.ValidationRangeConsumer;
+import org.roaringbitmap.art.LeafNode;
+import org.roaringbitmap.art.LeafNodeIterator;
 
 import com.google.common.primitives.Ints;
 import com.google.common.primitives.Longs;
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
@@ -21,16 +30,15 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.util.*;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-import org.roaringbitmap.RoaringBitmap;
-import org.roaringbitmap.ValidationRangeConsumer;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.ABSENT;
-import static org.roaringbitmap.ValidationRangeConsumer.Value.PRESENT;
-import org.roaringbitmap.art.LeafNode;
-import org.roaringbitmap.art.LeafNodeIterator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
 
 public class TestRoaring64Bitmap {
 
@@ -38,7 +46,7 @@ private Roaring64Bitmap newDefaultCtor() {
     return new Roaring64Bitmap();
   }
 
-  private Set getSourceForAllKindsOfNodeTypes() {
+  public static Set getSourceForAllKindsOfNodeTypes() {
     Random random = new Random(1234);
     Set source = new HashSet<>();
     int total = 10000;
@@ -98,7 +106,7 @@ public void testAllKindOfNodeTypesSerDeser() throws Exception {
       i++;
     }
     Assertions.assertEquals(source.size(), i);
-    //test all kind of nodes's serialization/deserialization
+    // test all kind of nodes's serialization/deserialization
     long sizeL = roaring64Bitmap.serializedSizeInBytes();
     if (sizeL > Integer.MAX_VALUE) {
       return;
@@ -108,8 +116,8 @@ public void testAllKindOfNodeTypesSerDeser() throws Exception {
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(sizeInt);
     DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
     roaring64Bitmap.serialize(dataOutputStream);
-    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
-        byteArrayOutputStream.toByteArray());
+    ByteArrayInputStream byteArrayInputStream =
+        new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
     DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
     Roaring64Bitmap deserStreamOne = new Roaring64Bitmap();
     deserStreamOne.deserialize(dataInputStream);
@@ -165,7 +173,6 @@ public void testZero() {
     assertEquals(1, map.rankLong(Long.MAX_VALUE));
   }
 
-
   @Test
   public void testMinusOne_Unsigned() {
     Roaring64Bitmap map = newDefaultCtor();
@@ -187,7 +194,7 @@ public void testMinusOne_Unsigned() {
     assertEquals(0, map.rankLong(Long.MAX_VALUE));
     assertEquals(0, map.rankLong(-2));
     assertEquals(1, map.rankLong(-1));
-    assertArrayEquals(new long[]{-1L}, map.toArray());
+    assertArrayEquals(new long[] {-1L}, map.toArray());
   }
 
   @Test
@@ -215,16 +222,18 @@ public void testSimpleIntegers() {
     assertEquals(2, map.rankLong(235));
     assertEquals(2, map.rankLong(Integer.MAX_VALUE + 1L));
     assertEquals(2, map.rankLong(Long.MAX_VALUE));
-    assertArrayEquals(new long[]{123L, 234L}, map.toArray());
+    assertArrayEquals(new long[] {123L, 234L}, map.toArray());
   }
 
   @Test
   public void testAddOneSelect2() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64Bitmap map = newDefaultCtor();
-      map.addLong(123);
-      map.select(1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64Bitmap map = newDefaultCtor();
+          map.addLong(123);
+          map.select(1);
+        });
   }
 
   @Test
@@ -244,10 +253,12 @@ public void testIterator_NextWithoutHasNext_Filled() {
 
   @Test
   public void testIterator_NextWithoutHasNext_Empty() {
-    assertThrows(IllegalStateException.class, () -> {
-      Roaring64Bitmap map = newDefaultCtor();
-      map.getLongIterator().next();
-    });
+    assertThrows(
+        IllegalStateException.class,
+        () -> {
+          Roaring64Bitmap map = newDefaultCtor();
+          map.getLongIterator().next();
+        });
   }
 
   @Test
@@ -267,7 +278,7 @@ public void testLongMaxValue() {
     assertEquals(0, map.rankLong(1));
     assertEquals(0, map.rankLong(Long.MAX_VALUE - 1));
     assertEquals(1, map.rankLong(Long.MAX_VALUE));
-    assertArrayEquals(new long[]{Long.MAX_VALUE}, map.toArray());
+    assertArrayEquals(new long[] {Long.MAX_VALUE}, map.toArray());
   }
 
   @Test
@@ -318,13 +329,14 @@ public void testLongMinValueZeroOneMaxValue() {
     assertEquals(3, map.rankLong(Long.MAX_VALUE));
 
     final List foreach = new ArrayList<>();
-    map.forEach(new LongConsumer() {
-
-      @Override
-      public void accept(long value) {
-        foreach.add(value);
-      }
-    });
+    map.forEach(
+        new LongConsumer() {
+
+          @Override
+          public void accept(long value) {
+            foreach.add(value);
+          }
+        });
     assertEquals(Arrays.asList(0L, 1L, Long.MAX_VALUE, Long.MIN_VALUE), foreach);
   }
 
@@ -472,7 +484,6 @@ public void testLargeSelectLong() {
     assertEquals(negative, last);
   }
 
-
   @Test
   public void testLargeRankLong() {
     long positive = 1;
@@ -483,7 +494,6 @@ public void testLargeRankLong() {
     assertEquals(2, map.rankLong(negative));
   }
 
-
   @Test
   public void testIterationOrder() {
     long positive = 1;
@@ -525,8 +535,8 @@ public void testSerializationEmpty() throws IOException, ClassNotFoundException
   public void testSerialization_ToBigEndianBuffer() throws IOException {
     final Roaring64Bitmap map = newDefaultCtor();
     map.addLong(123);
-    ByteBuffer buffer = ByteBuffer.allocate((int) map.serializedSizeInBytes())
-        .order(ByteOrder.BIG_ENDIAN);
+    ByteBuffer buffer =
+        ByteBuffer.allocate((int) map.serializedSizeInBytes()).order(ByteOrder.BIG_ENDIAN);
     map.serialize(buffer);
     assertEquals(map.serializedSizeInBytes(), buffer.position());
   }
@@ -546,7 +556,6 @@ public void testSerialization_OneValue() throws IOException, ClassNotFoundExcept
     assertEquals(123, clone.select(0));
   }
 
-
   @Test
   public void testSerialization() throws IOException, ClassNotFoundException {
     final Roaring64Bitmap map = newDefaultCtor();
@@ -562,10 +571,8 @@ public void testSerialization() throws IOException, ClassNotFoundException {
     assertEquals(123, clone.select(0));
   }
 
-
   @Test
-  public void testSerializationMultipleBuckets()
-      throws IOException, ClassNotFoundException {
+  public void testSerializationMultipleBuckets() throws IOException, ClassNotFoundException {
     final Roaring64Bitmap map = newDefaultCtor();
     map.addLong(-123);
     map.addLong(123);
@@ -593,7 +600,6 @@ public void testSerializationMultipleBuckets()
     assertEquals(-123, anotherDeserMap.select(2));
   }
 
-
   @Test
   public void testOrSameBucket() {
     Roaring64Bitmap left = newDefaultCtor();
@@ -602,12 +608,18 @@ public void testOrSameBucket() {
     left.addLong(123);
     right.addLong(234);
 
+    Roaring64Bitmap orNotInPlace = Roaring64Bitmap.or(left, right);
     left.or(right);
 
     assertEquals(2, left.getLongCardinality());
 
     assertEquals(123, left.select(0));
     assertEquals(234, left.select(1));
+
+    assertEquals(2, orNotInPlace.getLongCardinality());
+
+    assertEquals(123, orNotInPlace.select(0));
+    assertEquals(234, orNotInPlace.select(1));
   }
 
   @Test
@@ -619,6 +631,7 @@ public void testOrMultipleBuckets() {
     left.addLong(Long.MAX_VALUE);
     right.addLong(234);
 
+    Roaring64Bitmap orNotInPlace = Roaring64Bitmap.or(left, right);
     left.or(right);
 
     assertEquals(3, left.getLongCardinality());
@@ -626,6 +639,12 @@ public void testOrMultipleBuckets() {
     assertEquals(123, left.select(0));
     assertEquals(234, left.select(1));
     assertEquals(Long.MAX_VALUE, left.select(2));
+
+    assertEquals(3, orNotInPlace.getLongCardinality());
+
+    assertEquals(123, orNotInPlace.select(0));
+    assertEquals(234, orNotInPlace.select(1));
+    assertEquals(Long.MAX_VALUE, orNotInPlace.select(2));
   }
 
   @Test
@@ -636,14 +655,19 @@ public void testOrDifferentBucket() {
     left.addLong(123);
     right.addLong(Long.MAX_VALUE / 2);
 
+    Roaring64Bitmap orNotInPlace = Roaring64Bitmap.or(left, right);
     left.or(right);
 
     assertEquals(2, left.getLongCardinality());
 
     assertEquals(123, left.select(0));
     assertEquals(Long.MAX_VALUE / 2, left.select(1));
-  }
 
+    assertEquals(2, orNotInPlace.getLongCardinality());
+
+    assertEquals(123, orNotInPlace.select(0));
+    assertEquals(Long.MAX_VALUE / 2, orNotInPlace.select(1));
+  }
 
   @Test
   public void testOrDifferentBucket2() {
@@ -653,12 +677,18 @@ public void testOrDifferentBucket2() {
     left.addLong(123);
     right.addLong(Long.MAX_VALUE);
 
+    Roaring64Bitmap orNotInPlace = Roaring64Bitmap.or(left, right);
     left.or(right);
 
     assertEquals(2, left.getLongCardinality());
 
     assertEquals(123, left.select(0));
     assertEquals(Long.MAX_VALUE, left.select(1));
+
+    assertEquals(2, orNotInPlace.getLongCardinality());
+
+    assertEquals(123, orNotInPlace.select(0));
+    assertEquals(Long.MAX_VALUE, orNotInPlace.select(1));
   }
 
   @Test
@@ -682,7 +712,6 @@ public void testOrCloneInput() {
     assertEquals(123, right.select(0));
   }
 
-
   @Test
   public void testXorBucket() {
     Roaring64Bitmap left = newDefaultCtor();
@@ -694,11 +723,16 @@ public void testXorBucket() {
     right.addLong(345);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap xorNotInPlace = Roaring64Bitmap.xor(left, right);
     left.xor(right);
 
     assertEquals(2, left.getLongCardinality());
     assertEquals(123, left.select(0));
     assertEquals(345, left.select(1));
+
+    assertEquals(2, xorNotInPlace.getLongCardinality());
+    assertEquals(123, xorNotInPlace.select(0));
+    assertEquals(345, xorNotInPlace.select(1));
   }
 
   @Test
@@ -711,11 +745,16 @@ public void testXor() {
     right.addLong(234);
     right.addLong(345);
 
+    Roaring64Bitmap xorNotInPlace = Roaring64Bitmap.xor(left, right);
     left.xor(right);
 
     assertEquals(2, left.getLongCardinality());
     assertEquals(123, left.select(0));
     assertEquals(345, left.select(1));
+
+    assertEquals(2, xorNotInPlace.getLongCardinality());
+    assertEquals(123, xorNotInPlace.select(0));
+    assertEquals(345, xorNotInPlace.select(1));
   }
 
   @Test
@@ -727,11 +766,16 @@ public void testXorDifferentBucket() {
     right.addLong(Long.MAX_VALUE);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap xorNotInPlace = Roaring64Bitmap.xor(left, right);
     left.xor(right);
 
     assertEquals(2, left.getLongCardinality());
     assertEquals(123, left.select(0));
     assertEquals(Long.MAX_VALUE, left.select(1));
+
+    assertEquals(2, xorNotInPlace.getLongCardinality());
+    assertEquals(123, xorNotInPlace.select(0));
+    assertEquals(Long.MAX_VALUE, xorNotInPlace.select(1));
   }
 
   @Test
@@ -744,12 +788,15 @@ public void testXor_MultipleBucket() {
     right.addLong(Long.MAX_VALUE);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap xorNotInPlace = Roaring64Bitmap.xor(left, right);
     left.xor(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(123, left.select(0));
-  }
 
+    assertEquals(1, xorNotInPlace.getLongCardinality());
+    assertEquals(123, xorNotInPlace.select(0));
+  }
 
   @Test
   public void testAndSingleBucket() {
@@ -762,10 +809,14 @@ public void testAndSingleBucket() {
     right.addLong(345);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap andNotInPlace = Roaring64Bitmap.and(left, right);
     left.and(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(234, left.select(0));
+
+    assertEquals(1, andNotInPlace.getLongCardinality());
+    assertEquals(234, andNotInPlace.select(0));
   }
 
   @Test
@@ -777,32 +828,44 @@ public void testAnd() {
     right.addLong(123);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap andNotInPlace = Roaring64Bitmap.and(left, right);
     left.and(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(123, left.select(0));
+
+    assertEquals(1, andNotInPlace.getLongCardinality());
+    assertEquals(123, andNotInPlace.select(0));
   }
 
   @Test
   public void testAndDisjoint() {
     // There are no shared values between these maps.
-    final long[] leftData = new long[]{1076595327100L, 1074755534972L, 5060192403580L, 5060308664444L};
-    final long[] rightData = new long[]{3470563844L};
+    final long[] leftData =
+        new long[] {1076595327100L, 1074755534972L, 5060192403580L, 5060308664444L};
+    final long[] rightData = new long[] {3470563844L};
 
     Roaring64Bitmap left = Roaring64Bitmap.bitmapOf(leftData);
     Roaring64Bitmap right = Roaring64Bitmap.bitmapOf(rightData);
 
+    Roaring64Bitmap andNotInPlace = Roaring64Bitmap.and(left, right);
     left.and(right);
 
     Roaring64Bitmap swapLeft = Roaring64Bitmap.bitmapOf(rightData);
     Roaring64Bitmap swapRight = Roaring64Bitmap.bitmapOf(leftData);
 
+    Roaring64Bitmap swapAndNotInPlace = Roaring64Bitmap.and(left, right);
     swapLeft.and(swapRight);
 
     assertEquals(0, left.getLongCardinality());
     assertEquals(0, swapLeft.getLongCardinality());
     assertThrows(IllegalArgumentException.class, () -> left.select(0));
     assertThrows(IllegalArgumentException.class, () -> swapLeft.select(0));
+
+    assertEquals(0, andNotInPlace.getLongCardinality());
+    assertEquals(0, swapAndNotInPlace.getLongCardinality());
+    assertThrows(IllegalArgumentException.class, () -> andNotInPlace.select(0));
+    assertThrows(IllegalArgumentException.class, () -> swapAndNotInPlace.select(0));
   }
 
   @Test
@@ -812,10 +875,12 @@ void testToArrayAfterAndOptHasEmptyContainer() {
 
     Roaring64Bitmap bitmap2 = new Roaring64Bitmap();
     bitmap2.addLong(1);
-    //bit and
+    // bit and
+    Roaring64Bitmap andNotInPlace = Roaring64Bitmap.and(bitmap, bitmap2);
     bitmap.and(bitmap2);
-    //to array
+    // to array
     Assertions.assertDoesNotThrow(bitmap::toArray);
+    Assertions.assertDoesNotThrow(andNotInPlace::toArray);
   }
 
   @Test
@@ -842,12 +907,118 @@ public void testAndMultipleBucket() {
     right.addLong(Long.MAX_VALUE);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap andNotInPlace = Roaring64Bitmap.and(left, right);
     left.and(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(Long.MAX_VALUE, left.select(0));
+
+    assertEquals(1, andNotInPlace.getLongCardinality());
+    assertEquals(Long.MAX_VALUE, andNotInPlace.select(0));
+  }
+
+  @Test
+  public void intersecttest() {
+    final Roaring64Bitmap rr1 = new Roaring64Bitmap();
+    final Roaring64Bitmap rr2 = new Roaring64Bitmap();
+    for (int k = 0; k < 40000; ++k) {
+      rr1.add(2 * k);
+      rr2.add(2 * k + 1);
+    }
+    assertFalse(Roaring64Bitmap.intersects(rr1, rr2));
+    rr1.add(2 * 500 + 1);
+    assertTrue(Roaring64Bitmap.intersects(rr1, rr2));
+    final Roaring64Bitmap rr3 = new Roaring64Bitmap();
+    rr3.add(2 * 501 + 1);
+    assertTrue(Roaring64Bitmap.intersects(rr3, rr2));
+    assertFalse(Roaring64Bitmap.intersects(rr3, rr1));
+    for (int k = 0; k < 40000; ++k) {
+      rr1.add(2 * k + 1);
+    }
+    rr1.runOptimize();
+    assertTrue(Roaring64Bitmap.intersects(rr1, rr2));
   }
 
+  @Test
+  public void andcounttest() {
+    // This is based on andtest
+    final Roaring64Bitmap rr = new Roaring64Bitmap();
+    for (int k = 0; k < 4000; ++k) {
+      rr.add(k);
+    }
+    rr.add(100000);
+    rr.add(110000);
+    final Roaring64Bitmap rr2 = new Roaring64Bitmap();
+    rr2.add(13);
+    final Roaring64Bitmap rrand = Roaring64Bitmap.and(rr, rr2);
+    assertEquals(rrand.getLongCardinality(), Roaring64Bitmap.andCardinality(rr, rr2));
+    assertEquals(rrand.getLongCardinality(), Roaring64Bitmap.andCardinality(rr2, rr));
+    rr.and(rr2);
+    assertEquals(rrand.getLongCardinality(), Roaring64Bitmap.andCardinality(rr2, rr));
+  }
+
+  @Test
+  public void andCounttest3() {
+    // This is based on andtest3
+    final int[] arrayand = new int[11256];
+    int pos = 0;
+    final Roaring64Bitmap rr = new Roaring64Bitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr.add(k);
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536; k < 3 * 65536 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 3 * 65536 + 7000; k < 3 * 65536 + 9000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 4 * 65536; k < 4 * 65536 + 7000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 6 * 65536; k < 6 * 65536 + 10000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 8 * 65536; k < 8 * 65536 + 1000; ++k) {
+      rr.add(k);
+    }
+    for (int k = 9 * 65536; k < 9 * 65536 + 30000; ++k) {
+      rr.add(k);
+    }
+    final Roaring64Bitmap rr2 = new Roaring64Bitmap();
+    for (int k = 4000; k < 4256; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 65536; k < 65536 + 4000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 3 * 65536 + 1000; k < 3 * 65536 + 7000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 6 * 65536; k < 6 * 65536 + 1000; ++k) {
+      rr2.add(k);
+      arrayand[pos++] = k;
+    }
+    for (int k = 7 * 65536; k < 7 * 65536 + 1000; ++k) {
+      rr2.add(k);
+    }
+    for (int k = 10 * 65536; k < 10 * 65536 + 5000; ++k) {
+      rr2.add(k);
+    }
+
+    final Roaring64Bitmap rrand = Roaring64Bitmap.and(rr, rr2);
+    final long rrandCount = Roaring64Bitmap.andCardinality(rr, rr2);
+
+    assertEquals(rrand.getLongCardinality(), rrandCount);
+  }
 
   @Test
   public void testAndNotSingleBucket() {
@@ -860,10 +1031,14 @@ public void testAndNotSingleBucket() {
     right.addLong(345);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap andNotNotInPlace = Roaring64Bitmap.andNot(left, right);
     left.andNot(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(123, left.select(0));
+
+    assertEquals(1, andNotNotInPlace.getLongCardinality());
+    assertEquals(123, andNotNotInPlace.select(0));
   }
 
   @Test
@@ -875,10 +1050,14 @@ public void testAndNot() {
     right.addLong(234);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap andNotNotInPlace = Roaring64Bitmap.andNot(left, right);
     left.andNot(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(123, left.select(0));
+
+    assertEquals(1, andNotNotInPlace.getLongCardinality());
+    assertEquals(123, andNotNotInPlace.select(0));
   }
 
   @Test
@@ -890,10 +1069,14 @@ public void testAndNotDifferentBucket() {
     right.addLong(Long.MAX_VALUE);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap andNotNotInPlace = Roaring64Bitmap.andNot(left, right);
     left.andNot(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(123, left.select(0));
+
+    assertEquals(1, andNotNotInPlace.getLongCardinality());
+    assertEquals(123, andNotNotInPlace.select(0));
   }
 
   @Test
@@ -906,10 +1089,14 @@ public void testAndNot_MultipleBucket() {
     right.addLong(Long.MAX_VALUE);
 
     // We have 1 shared value: 234
+    Roaring64Bitmap andNotNotInPlace = Roaring64Bitmap.andNot(left, right);
     left.andNot(right);
 
     assertEquals(1, left.getLongCardinality());
     assertEquals(123, left.select(0));
+
+    assertEquals(1, andNotNotInPlace.getLongCardinality());
+    assertEquals(123, andNotNotInPlace.select(0));
   }
 
   @Test
@@ -917,7 +1104,7 @@ public void testFlipSameContainer() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(1,2);
+    map.flip(1, 2);
 
     assertEquals(2, map.getLongCardinality());
     assertEquals(1, map.select(1));
@@ -930,7 +1117,7 @@ public void testFlipMiddleContainer() {
     map.addLong(0);
     map.addLong(0x20001);
 
-    map.flip(0x10001,0x10002);
+    map.flip(0x10001, 0x10002);
 
     assertEquals(3, map.getLongCardinality());
     assertEquals(0x10001, map.select(1));
@@ -941,7 +1128,7 @@ public void testFlipNextContainer() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(0x10001,0x10002);
+    map.flip(0x10001, 0x10002);
 
     assertEquals(2, map.getLongCardinality());
     assertEquals(0x10001, map.select(1));
@@ -952,7 +1139,7 @@ public void testFlipToEdgeContainer() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(0xFFFF,0x10000);
+    map.flip(0xFFFF, 0x10000);
 
     assertEquals(2, map.getLongCardinality());
     assertEquals(0xFFFF, map.select(1));
@@ -963,7 +1150,7 @@ public void testFlipOverEdgeContainer() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(0xFFFF,0x10002);
+    map.flip(0xFFFF, 0x10002);
 
     assertEquals(4, map.getLongCardinality());
     assertEquals(0x10001, map.select(3));
@@ -974,7 +1161,7 @@ public void testFlipPriorContainer() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0x10001);
-    map.flip(1L,2L);
+    map.flip(1L, 2L);
 
     assertEquals(2, map.getLongCardinality());
     assertEquals(1, map.select(0));
@@ -986,7 +1173,7 @@ public void testFlipSameNonZeroValuesNoChange() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(1L,1L);
+    map.flip(1L, 1L);
 
     assertEquals(1, map.getLongCardinality());
     assertEquals(0, map.select(0));
@@ -997,7 +1184,7 @@ public void testFlipPositiveStartGreaterThanEndNoChange() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(2L,1L);
+    map.flip(2L, 1L);
 
     assertEquals(1, map.getLongCardinality());
     assertEquals(0, map.select(0));
@@ -1008,7 +1195,7 @@ public void testFlipNegStartGreaterThanEndNoChange() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(-1L,-3L);
+    map.flip(-1L, -3L);
 
     assertEquals(1, map.getLongCardinality());
     assertEquals(0, map.select(0));
@@ -1019,7 +1206,7 @@ public void testFlipNegStartGreaterThanPosEndNoChange() {
     Roaring64Bitmap map = newDefaultCtor();
 
     map.addLong(0);
-    map.flip(-1L,0x7FffFFffFFffFFffL);
+    map.flip(-1L, 0x7FffFFffFFffFFffL);
 
     assertEquals(1, map.getLongCardinality());
     assertEquals(0, map.select(0));
@@ -1089,7 +1276,7 @@ public void testToString() {
   @Test
   public void testInvalidIntMask() {
     Roaring64Bitmap map = new Roaring64Bitmap();
-    int a = 0xFFFFFFFF;  // -1 in two's compliment
+    int a = 0xFFFFFFFF; // -1 in two's compliment
     map.addInt(a);
     assertEquals(map.getIntCardinality(), 1);
     long addedInt = map.getLongIterator().next();
@@ -1108,7 +1295,8 @@ public void testAddInvalidRange() {
 
     // Different higher parts
     assertThrows(IllegalArgumentException.class, () -> map.addRange(Long.MAX_VALUE, 0L));
-    assertThrows(IllegalArgumentException.class, () -> map.addRange(Long.MIN_VALUE, Long.MAX_VALUE));
+    assertThrows(
+        IllegalArgumentException.class, () -> map.addRange(Long.MIN_VALUE, Long.MAX_VALUE));
   }
 
   @Test
@@ -1137,7 +1325,6 @@ public void testAddRangeEndExcludingNextBitmapFirstLow() {
     assertEquals(end - 1, map.select(1));
   }
 
-
   @Test
   public void testAddRangeMultipleBuckets() {
     Roaring64Bitmap map = newDefaultCtor();
@@ -1154,17 +1341,18 @@ public void testAddRangeMultipleBuckets() {
     assertEquals(to - 1, map.select(nbItems - 1));
   }
 
-
   public static final long outOfRoaringBitmapRange = 2L * Integer.MAX_VALUE + 3L;
 
   // Check this range is not handled by RoaringBitmap
   @Test
   public void testCardinalityAboveIntegerMaxValue_RoaringBitmap() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      RoaringBitmap map = new RoaringBitmap();
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          RoaringBitmap map = new RoaringBitmap();
 
-      map.add(0L, outOfRoaringBitmapRange);
-    });
+          map.add(0L, outOfRoaringBitmapRange);
+        });
   }
 
   @Test
@@ -1181,7 +1369,6 @@ public void testCardinalityAboveIntegerMaxValue() {
 
     assertEquals(0, map.select(0));
     assertEquals(outOfSingleRoaring - 1, map.select(outOfSingleRoaring - 1));
-
   }
 
   @Test
@@ -1195,7 +1382,6 @@ public void testRoaringBitmapSelectAboveIntegerMaxValue() {
     assertEquals(-1, map.select(-1));
   }
 
-
   @Test
   public void testTrim() {
     Roaring64Bitmap map = newDefaultCtor();
@@ -1234,22 +1420,23 @@ public void testAutoboxedIterator() {
 
   @Test
   public void testAutoboxedIteratorCanNotRemove() {
-    assertThrows(UnsupportedOperationException.class, () -> {
-      Roaring64Bitmap map = newDefaultCtor();
+    assertThrows(
+        UnsupportedOperationException.class,
+        () -> {
+          Roaring64Bitmap map = newDefaultCtor();
 
-      map.addLong(123);
-      map.addLong(234);
+          map.addLong(123);
+          map.addLong(234);
 
-      Iterator it = map.iterator();
+          Iterator it = map.iterator();
 
-      assertTrue(it.hasNext());
+          assertTrue(it.hasNext());
 
-      // Should throw a UnsupportedOperationException
-      it.remove();
-    });
+          // Should throw a UnsupportedOperationException
+          it.remove();
+        });
   }
 
-
   @Test
   public void testSelectMultipleBuckets() {
     Roaring64Bitmap map = newDefaultCtor();
@@ -1263,33 +1450,37 @@ public void testSelectMultipleBuckets() {
 
   @Test
   public void testSelectEmpty() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64Bitmap map = newDefaultCtor();
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64Bitmap map = newDefaultCtor();
 
-      map.select(0);
-    });
+          map.select(0);
+        });
   }
 
-
   @Test
   public void testSelectOutOfBoundsMatchCardinality() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64Bitmap map = newDefaultCtor();
-      map.addLong(123);
-      map.select(1);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64Bitmap map = newDefaultCtor();
+          map.addLong(123);
+          map.select(1);
+        });
   }
 
   @Test
   public void testSelectOutOfBoundsOtherCardinality() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64Bitmap map = newDefaultCtor();
-      map.addLong(123);
-      map.select(2);
-    });
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64Bitmap map = newDefaultCtor();
+          map.addLong(123);
+          map.select(2);
+        });
   }
 
-
   @Test
   public void testRankMultipleBuckets() {
     Roaring64Bitmap map = newDefaultCtor();
@@ -1427,21 +1618,22 @@ public void testHashCodeEquals() {
   public void testIssue428() {
     long input = 1353768194141061120L;
 
-    long[] compare = new long[]{
-        5192650370358181888L,
-        5193776270265024512L,
-        5194532734264934400L,
-        5194544828892839936L,
-        5194545653526560768L,
-        5194545688960040960L,
-        5194545692181266432L,
-        5194545705066168320L,
-        5194545722246037504L,
-        5194545928404467712L,
-        5194550326450978816L,
-        5194620695195156480L,
-        5206161169240293376L
-    };
+    long[] compare =
+        new long[] {
+          5192650370358181888L,
+          5193776270265024512L,
+          5194532734264934400L,
+          5194544828892839936L,
+          5194545653526560768L,
+          5194545688960040960L,
+          5194545692181266432L,
+          5194545705066168320L,
+          5194545722246037504L,
+          5194545928404467712L,
+          5194550326450978816L,
+          5194620695195156480L,
+          5206161169240293376L
+        };
 
     Roaring64Bitmap inputRB = new Roaring64Bitmap();
     inputRB.add(input);
@@ -1465,11 +1657,23 @@ public void testIssue428() {
   @Test
   public void shouldNotThrowNPE() {
 
-    long[] inputs = new long[]{5183829215128059904L};
-    long[] crossers = new long[]{4413527634823086080L, 4418031234450456576L, 4421408934170984448L,
-        4421690409147695104L, 4421479302915162112L, 4421426526357028864L, 4421413332217495552L,
-        4421416630752378880L, 4421416905630285824L, 4421417111788716032L, 4421417128968585216L,
-        4421417133263552512L, 4421417134337294336L};
+    long[] inputs = new long[] {5183829215128059904L};
+    long[] crossers =
+        new long[] {
+          4413527634823086080L,
+          4418031234450456576L,
+          4421408934170984448L,
+          4421690409147695104L,
+          4421479302915162112L,
+          4421426526357028864L,
+          4421413332217495552L,
+          4421416630752378880L,
+          4421416905630285824L,
+          4421417111788716032L,
+          4421417128968585216L,
+          4421417133263552512L,
+          4421417134337294336L
+        };
 
     Roaring64Bitmap refRB = new Roaring64Bitmap();
     refRB.add(inputs);
@@ -1481,11 +1685,23 @@ public void shouldNotThrowNPE() {
 
   @Test
   public void shouldNotThrowAIOOB() {
-    long[] inputs = new long[]{5183829215128059904L};
-    long[] crossers = new long[]{4413527634823086080L, 4418031234450456576L, 4421408934170984448L,
-        4421127459194273792L, 4420916352961740800L, 4420863576403607552L, 4420850382264074240L,
-        4420847083729190912L, 4420847358607097856L, 4420847564765528064L, 4420847616305135616L,
-        4420847620600102912L, 4420847623821328384L};
+    long[] inputs = new long[] {5183829215128059904L};
+    long[] crossers =
+        new long[] {
+          4413527634823086080L,
+          4418031234450456576L,
+          4421408934170984448L,
+          4421127459194273792L,
+          4420916352961740800L,
+          4420863576403607552L,
+          4420850382264074240L,
+          4420847083729190912L,
+          4420847358607097856L,
+          4420847564765528064L,
+          4420847616305135616L,
+          4420847620600102912L,
+          4420847623821328384L
+        };
     Roaring64Bitmap referenceRB = new Roaring64Bitmap();
     referenceRB.add(inputs);
     Roaring64Bitmap crossRB = new Roaring64Bitmap();
@@ -1497,8 +1713,8 @@ public void shouldNotThrowAIOOB() {
   @Test
   public void shouldNotThrowIAE() {
 
-    long[] inputs = new long[]{5183829215128059904L};
-    long[] crossers = new long[]{4421416447812311717L, 4420658333523655893L, 4420658332008999025L};
+    long[] inputs = new long[] {5183829215128059904L};
+    long[] crossers = new long[] {4421416447812311717L, 4420658333523655893L, 4420658332008999025L};
 
     Roaring64Bitmap referenceRB = new Roaring64Bitmap();
     referenceRB.add(inputs);
@@ -1507,45 +1723,42 @@ public void shouldNotThrowIAE() {
     crossRB.and(referenceRB);
     assertEquals(0, crossRB.getIntCardinality());
   }
-  
-  
-  
-  
+
   @Test
   public void testSkips() {
     final Random source = new Random(0xcb000a2b9b5bdfb6l);
     final long[] data = takeSortedAndDistinct(source, 45000);
     Roaring64Bitmap bitmap = Roaring64Bitmap.bitmapOf(data);
     PeekableLongIterator pii = bitmap.getLongIterator();
-    for(int i = 0; i < data.length; ++i) {
+    for (int i = 0; i < data.length; ++i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.peekNext());
     }
     pii = bitmap.getLongIterator();
-    for(int i = 0; i < data.length; ++i) {
+    for (int i = 0; i < data.length; ++i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.next());
     }
     pii = bitmap.getLongIterator();
-    for(int i = 1; i < data.length; ++i) {
-      pii.advanceIfNeeded(data[i-1]);
-      assertEquals(data[i-1], pii.next());
+    for (int i = 1; i < data.length; ++i) {
+      pii.advanceIfNeeded(data[i - 1]);
+      assertEquals(data[i - 1], pii.next());
       assertEquals(data[i], pii.peekNext());
     }
     bitmap.getLongIterator().advanceIfNeeded(-1); // should not crash
     bitmap.getLongIteratorFrom(-1); // should not crash
   }
-  
+
   @Test
   public void testSkipsDense() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
     int n = 100000;
-    for(long i = 0; i < n; ++i) {
+    for (long i = 0; i < n; ++i) {
       bitmap.add(2 * i + Integer.MAX_VALUE);
     }
 
     // use advance
-    for(long i = 0; i < n; ++i) {
+    for (long i = 0; i < n; ++i) {
       PeekableLongIterator pii = bitmap.getLongIterator();
       long expected = 2 * i + Integer.MAX_VALUE;
       pii.advanceIfNeeded(expected);
@@ -1554,31 +1767,31 @@ public void testSkipsDense() {
     }
 
     // use iterator from
-    for(long i = 0; i < n; ++i) {
+    for (long i = 0; i < n; ++i) {
       long expected = 2 * i + Integer.MAX_VALUE;
       PeekableLongIterator pii = bitmap.getLongIteratorFrom(expected);
       assertEquals(expected, pii.peekNext());
       assertEquals(expected, pii.next());
     }
   }
-  
+
   @Test
   public void testSkipsMultipleHighPoints() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
-    
+
     int n = 100000;
     int numHighPoints = 10;
-    for(long h = 0; h < numHighPoints; ++h) {
+    for (long h = 0; h < numHighPoints; ++h) {
       long base = h << 16;
-      for(long i = 0; i < n; ++i) {
+      for (long i = 0; i < n; ++i) {
         bitmap.add(2 * i + base);
       }
     }
-    for(long h = 0; h < numHighPoints; ++h) {
+    for (long h = 0; h < numHighPoints; ++h) {
       long base = h << 16;
 
       // use advance
-      for(long i = 0; i < n; ++i) {
+      for (long i = 0; i < n; ++i) {
         PeekableLongIterator pii = bitmap.getLongIterator();
         long expected = 2 * i + base;
         pii.advanceIfNeeded(expected);
@@ -1587,7 +1800,7 @@ public void testSkipsMultipleHighPoints() {
       }
 
       // use iterator from
-      for(long i = 0; i < n; ++i) {
+      for (long i = 0; i < n; ++i) {
         long expected = 2 * i + base;
         PeekableLongIterator pii = bitmap.getLongIteratorFrom(expected);
         assertEquals(expected, pii.peekNext());
@@ -1595,7 +1808,6 @@ public void testSkipsMultipleHighPoints() {
       }
     }
   }
-  
 
   @Test
   public void testSkipsRun() {
@@ -1603,20 +1815,20 @@ public void testSkipsRun() {
     bitmap.addRange(4L, 100000L);
     bitmap.runOptimize();
     // use advance
-    for(int i = 4; i < 100000; ++i) {
+    for (int i = 4; i < 100000; ++i) {
       PeekableLongIterator pii = bitmap.getLongIterator();
       pii.advanceIfNeeded(i);
       assertEquals(i, pii.peekNext());
       assertEquals(i, pii.next());
     }
     // use iterator from
-    for(int i = 4; i < 100000; ++i) {
+    for (int i = 4; i < 100000; ++i) {
       PeekableLongIterator pii = bitmap.getLongIteratorFrom(i);
       assertEquals(i, pii.peekNext());
       assertEquals(i, pii.next());
     }
   }
-  
+
   @Test
   public void testEmptySkips() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
@@ -1625,42 +1837,41 @@ public void testEmptySkips() {
 
     bitmap.getLongIteratorFrom(0);
   }
-  
-  
+
   @Test
   public void testSkipsReverse() {
     final Random source = new Random(0xcb000a2b9b5bdfb6l);
     final long[] data = takeSortedAndDistinct(source, 45000);
     Roaring64Bitmap bitmap = Roaring64Bitmap.bitmapOf(data);
     PeekableLongIterator pii = bitmap.getReverseLongIterator();
-    for(int i = data.length -1; i >= 0 ; --i) {
+    for (int i = data.length - 1; i >= 0; --i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.peekNext());
     }
     pii = bitmap.getReverseLongIterator();
-    for(int i = data.length -1; i >= 0 ; --i) {
+    for (int i = data.length - 1; i >= 0; --i) {
       pii.advanceIfNeeded(data[i]);
       assertEquals(data[i], pii.next());
     }
     pii = bitmap.getReverseLongIterator();
-    for(int i = data.length -2; i >= 0 ; --i) {
-      pii.advanceIfNeeded(data[i+1]);
+    for (int i = data.length - 2; i >= 0; --i) {
+      pii.advanceIfNeeded(data[i + 1]);
       pii.next();
-      assertEquals(data[i],pii.peekNext() );
+      assertEquals(data[i], pii.peekNext());
     }
-    bitmap.getReverseLongIterator().advanceIfNeeded(-1);// should not crash
-    bitmap.getReverseLongIteratorFrom(-1);// should not crash
+    bitmap.getReverseLongIterator().advanceIfNeeded(-1); // should not crash
+    bitmap.getReverseLongIteratorFrom(-1); // should not crash
   }
-  
+
   @Test
   public void testSkipsDenseReverse() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
     int n = 100000;
-    for(long i = 0; i < n; ++i) {
+    for (long i = 0; i < n; ++i) {
       bitmap.add(2 * i + Integer.MAX_VALUE);
     }
     // use advance
-    for(long i = n - 1; i >= 0; --i) {
+    for (long i = n - 1; i >= 0; --i) {
       long expected = 2 * i + Integer.MAX_VALUE;
       PeekableLongIterator pii = bitmap.getReverseLongIterator();
       pii.advanceIfNeeded(expected);
@@ -1669,31 +1880,31 @@ public void testSkipsDenseReverse() {
     }
 
     // use iterator from
-    for(long i = n - 1; i >= 0; --i) {
+    for (long i = n - 1; i >= 0; --i) {
       long expected = 2 * i + Integer.MAX_VALUE;
       PeekableLongIterator pii = bitmap.getReverseLongIteratorFrom(expected);
       assertEquals(expected, pii.peekNext());
       assertEquals(expected, pii.next());
     }
   }
-  
+
   @Test
   public void testSkipsMultipleHighPointsReverse() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
-    
+
     int n = 100000;
     int numHighPoints = 10;
-    for(long h = 0; h < numHighPoints; ++h) {
+    for (long h = 0; h < numHighPoints; ++h) {
       long base = h << 16;
-      for(long i = 0; i < n; ++i) {
+      for (long i = 0; i < n; ++i) {
         bitmap.add(2 * i + base);
       }
     }
-    for(long h = 0; h < numHighPoints; ++h) {
+    for (long h = 0; h < numHighPoints; ++h) {
       long base = h << 16;
 
       // use advance
-      for(long i = n - 1; i >= 0 ; --i) {
+      for (long i = n - 1; i >= 0; --i) {
         PeekableLongIterator pii = bitmap.getReverseLongIterator();
         long expected = 2 * i + base;
         pii.advanceIfNeeded(expected);
@@ -1702,7 +1913,7 @@ public void testSkipsMultipleHighPointsReverse() {
       }
 
       // use iterator from
-      for(long i = n - 1; i >= 0 ; --i) {
+      for (long i = n - 1; i >= 0; --i) {
         long expected = 2 * i + base;
         PeekableLongIterator pii = bitmap.getReverseLongIteratorFrom(expected);
         assertEquals(expected, pii.peekNext());
@@ -1718,7 +1929,7 @@ public void testSkipsRunReverse() {
     bitmap.runOptimize();
 
     // use advance
-    for(int i = 99999; i >= 4; --i) {
+    for (int i = 99999; i >= 4; --i) {
       PeekableLongIterator pii = bitmap.getReverseLongIterator();
       pii.advanceIfNeeded(i);
       assertEquals(i, pii.peekNext());
@@ -1726,13 +1937,13 @@ public void testSkipsRunReverse() {
     }
 
     // use iterator from
-    for(int i = 99999; i >= 4; --i) {
+    for (int i = 99999; i >= 4; --i) {
       PeekableLongIterator pii = bitmap.getReverseLongIteratorFrom(i);
       assertEquals(i, pii.peekNext());
       assertEquals(i, pii.next());
     }
   }
-  
+
   @Test
   public void testEmptySkipsReverse() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
@@ -1784,7 +1995,7 @@ public void testSkipIntoGaps() {
   @Test
   public void testSkipIntoFarAwayGaps() {
     Roaring64Bitmap bitset = new Roaring64Bitmap();
-    //long runLength = 18500L;
+    // long runLength = 18500L;
     long runLength = 4 << 20; // ~ 4mio
     long b1 = 2000000000L;
     long b1e = b1 + runLength;
@@ -1883,7 +2094,7 @@ public void testSkipIntoGapsReverse() {
   @Test
   public void testSkipIntoFarAwayGapsReverse() {
     Roaring64Bitmap bitset = new Roaring64Bitmap();
-    //long runLength = 18500L;
+    // long runLength = 18500L;
     long runLength = 4 << 20; // ~ 4mio
     long b1 = 2000000000L;
     long b1e = b1 + runLength;
@@ -2010,15 +2221,15 @@ public void testForAllInRangeContinuous() {
     bitmap.forAllInRange(10001, 1000, consumer2);
     assertEquals(1000, consumer2.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer3 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[]{
-        ABSENT, ABSENT, PRESENT, PRESENT, PRESENT
-    });
+    ValidationRangeConsumer consumer3 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {ABSENT, ABSENT, PRESENT, PRESENT, PRESENT});
     bitmap.forAllInRange(98, 5, consumer3);
     assertEquals(5, consumer3.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer4 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[]{
-        PRESENT, PRESENT, ABSENT, ABSENT, ABSENT
-    });
+    ValidationRangeConsumer consumer4 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {PRESENT, PRESENT, ABSENT, ABSENT, ABSENT});
     bitmap.forAllInRange(9998, 5, consumer4);
     assertEquals(5, consumer4.getNumberOfValuesConsumed());
   }
@@ -2037,19 +2248,20 @@ public void testForAllInRangeDense() {
     bitmap.forAllInRange(0, 100000, consumer);
     assertEquals(100000, consumer.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer.Value[] expectedSubRange = Arrays.copyOfRange(expected,2500, 6000);
+    ValidationRangeConsumer.Value[] expectedSubRange = Arrays.copyOfRange(expected, 2500, 6000);
     ValidationRangeConsumer consumer2 = ValidationRangeConsumer.validate(expectedSubRange);
     bitmap.forAllInRange(2500, 3500, consumer2);
     assertEquals(3500, consumer2.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer consumer3 = ValidationRangeConsumer.validate(new ValidationRangeConsumer.Value[]{
-        expected[99997], expected[99998], expected[99999], ABSENT, ABSENT, ABSENT
-    });
+    ValidationRangeConsumer consumer3 =
+        ValidationRangeConsumer.validate(
+            new ValidationRangeConsumer.Value[] {
+              expected[99997], expected[99998], expected[99999], ABSENT, ABSENT, ABSENT
+            });
     bitmap.forAllInRange(99997, 6, consumer3);
     assertEquals(6, consumer3.getNumberOfValuesConsumed());
   }
 
-
   @Test
   public void testForAllInRangeSparse() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
@@ -2064,7 +2276,7 @@ public void testForAllInRangeSparse() {
     bitmap.forAllInRange(0, 100000, consumer);
     assertEquals(100000, consumer.getNumberOfValuesConsumed());
 
-    ValidationRangeConsumer.Value[] expectedSubRange = Arrays.copyOfRange(expected,2500, 6001);
+    ValidationRangeConsumer.Value[] expectedSubRange = Arrays.copyOfRange(expected, 2500, 6001);
     ValidationRangeConsumer consumer2 = ValidationRangeConsumer.validate(expectedSubRange);
     bitmap.forAllInRange(2500, 3500, consumer2);
     assertEquals(3500, consumer2.getNumberOfValuesConsumed());
@@ -2079,25 +2291,82 @@ public void testForAllInRangeSparse() {
   public void testIssue537() {
     Roaring64Bitmap a = Roaring64Bitmap.bitmapOf(275846320L);
     Roaring64Bitmap b = Roaring64Bitmap.bitmapOf(275846320L);
-    Roaring64Bitmap c = Roaring64Bitmap.bitmapOf(275845652L,275845746L,275846148L,275847372L,275847380L,275847388L,275847459L,275847528L,275847586L,
-                                                 275847588L,275847600L,275847607L,275847610L,275847613L,275847631L,275847664L,275847672L,275847677L,
-                                                 275847680L,275847742L,275847808L,275847811L,275847824L,275847830L,275847856L,275847861L,275847863L,
-                                                 275847872L,275847896L,275847923L,275847924L,275847975L,275847990L,275847995L,275848003L,275848080L,
-                                                 275848081L,275848084L,275848095L,275848100L,275848120L,275848129L,275848134L,275848163L,275848174L,
-                                                 275848206L,275848218L,275848231L,275848272L,275848281L,275848308L,275848344L,275848376L,275848382L,
-                                                 275848395L,275848400L,275848411L,275848426L,275848445L,275848449L,275848451L,275848454L,275848469L);
+    Roaring64Bitmap c =
+        Roaring64Bitmap.bitmapOf(
+            275845652L,
+            275845746L,
+            275846148L,
+            275847372L,
+            275847380L,
+            275847388L,
+            275847459L,
+            275847528L,
+            275847586L,
+            275847588L,
+            275847600L,
+            275847607L,
+            275847610L,
+            275847613L,
+            275847631L,
+            275847664L,
+            275847672L,
+            275847677L,
+            275847680L,
+            275847742L,
+            275847808L,
+            275847811L,
+            275847824L,
+            275847830L,
+            275847856L,
+            275847861L,
+            275847863L,
+            275847872L,
+            275847896L,
+            275847923L,
+            275847924L,
+            275847975L,
+            275847990L,
+            275847995L,
+            275848003L,
+            275848080L,
+            275848081L,
+            275848084L,
+            275848095L,
+            275848100L,
+            275848120L,
+            275848129L,
+            275848134L,
+            275848163L,
+            275848174L,
+            275848206L,
+            275848218L,
+            275848231L,
+            275848272L,
+            275848281L,
+            275848308L,
+            275848344L,
+            275848376L,
+            275848382L,
+            275848395L,
+            275848400L,
+            275848411L,
+            275848426L,
+            275848445L,
+            275848449L,
+            275848451L,
+            275848454L,
+            275848469L);
     c.and(b);
     assertFalse(c.contains(275846320L));
     c.and(a);
     assertFalse(c.contains(275846320L));
   }
 
-
   @Test
   public void testIssue558() {
     Roaring64Bitmap rb = new Roaring64Bitmap();
     Random random = new Random(1234);
-    for (int i = 0 ; i < 1000000; i++) {
+    for (int i = 0; i < 1000000; i++) {
       rb.addLong(random.nextLong());
       rb.removeLong(random.nextLong());
     }
@@ -2107,71 +2376,84 @@ public void testIssue558() {
   public void testIssue577Case1() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
     bitmap.add(
-        45011744312L, 45008074636L, 41842920068L, 41829418930L, 40860008694L, 40232297287L,
-        40182908832L, 40171852270L, 39933922233L, 39794107638L);
+        45011744312L,
+        45008074636L,
+        41842920068L,
+        41829418930L,
+        40860008694L,
+        40232297287L,
+        40182908832L,
+        40171852270L,
+        39933922233L,
+        39794107638L);
     long maxLong = bitmap.getReverseLongIterator().peekNext();
     assertEquals(maxLong, 45011744312L);
 
-    bitmap.forEachInRange(46000000000L, 1000000000,
-        value -> fail("No values in this range, but got: " + value));
+    bitmap.forEachInRange(
+        46000000000L, 1000000000, value -> fail("No values in this range, but got: " + value));
   }
 
   @Test
   public void testIssue577Case2() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
-    bitmap.add(
-        30385375409L, 30399869293L, 34362979339L, 35541844320L, 36637965094L);
+    bitmap.add(30385375409L, 30399869293L, 34362979339L, 35541844320L, 36637965094L);
 
-    bitmap.forEachInRange(33000000000L, 1000000000,
-        value -> assertEquals(34362979339L, value));
+    bitmap.forEachInRange(33000000000L, 1000000000, value -> assertEquals(34362979339L, value));
   }
 
   @Test
   public void testIssue577Case3() {
     Roaring64Bitmap bitmap = new Roaring64Bitmap();
-    bitmap.add(
-        14510802367L, 26338197481L, 32716744974L, 32725817880L, 35679129730L);
+    bitmap.add(14510802367L, 26338197481L, 32716744974L, 32725817880L, 35679129730L);
 
-    final long[] expected = new long[]{32716744974L, 32725817880L};
+    final long[] expected = new long[] {32716744974L, 32725817880L};
 
-    bitmap.forEachInRange(32000000000L, 1000000000, new LongConsumer() {
+    bitmap.forEachInRange(
+        32000000000L,
+        1000000000,
+        new LongConsumer() {
 
-      int offset = 0;
+          int offset = 0;
 
-      @Override
-      public void accept(long value) {
-        assertEquals(expected[offset], value);
-        offset++;
-      }
-    });
+          @Override
+          public void accept(long value) {
+            assertEquals(expected[offset], value);
+            offset++;
+          }
+        });
   }
 
-
   @Test
   public void testWithYourself() {
-    Roaring64Bitmap b1 = Roaring64Bitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10);
+    Roaring64Bitmap b1 = Roaring64Bitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     b1.runOptimize();
     b1.or(b1);
-    assertTrue(b1.equals(Roaring64Bitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10)));
+    assertTrue(b1.equals(Roaring64Bitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
     b1.xor(b1);
     assertTrue(b1.isEmpty());
-    b1 = Roaring64Bitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10);
+    b1 = Roaring64Bitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     b1.and(b1);
-    assertTrue(b1.equals(Roaring64Bitmap.bitmapOf(1,2,3,4,5,6,7,8,9,10)));
+    assertTrue(b1.equals(Roaring64Bitmap.bitmapOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
     b1.andNot(b1);
     assertTrue(b1.isEmpty());
   }
 
   @Test
   public void testIssue580() {
-    Roaring64Bitmap rb = Roaring64Bitmap.bitmapOf(3242766498713841665L, 3492544636360507394L,
-      3418218112527884289L, 3220956490660966402L, 3495344165583036418L, 3495023214002368514L,
-      3485108231289675778L);
+    Roaring64Bitmap rb =
+        Roaring64Bitmap.bitmapOf(
+            3242766498713841665L,
+            3492544636360507394L,
+            3418218112527884289L,
+            3220956490660966402L,
+            3495344165583036418L,
+            3495023214002368514L,
+            3485108231289675778L);
     LongIterator it = rb.getLongIterator();
     int count = 0;
-    while(it.hasNext()) {
-        it.next();
-        count++;
+    while (it.hasNext()) {
+      it.next();
+      count++;
     }
     assertEquals(count, 7);
   }
@@ -2193,7 +2475,9 @@ public void testRangeAroundLongMax() {
     x.addRange(Long.MAX_VALUE - 1L, Long.MAX_VALUE + 3L);
 
     Assertions.assertEquals(4L, x.getLongCardinality());
-    Assertions.assertArrayEquals(x.toArray(), new long[] {Long.MAX_VALUE - 1L, Long.MAX_VALUE, Long.MIN_VALUE, Long.MIN_VALUE + 1L});
+    Assertions.assertArrayEquals(
+        x.toArray(),
+        new long[] {Long.MAX_VALUE - 1L, Long.MAX_VALUE, Long.MIN_VALUE, Long.MIN_VALUE + 1L});
   }
 
   @Test
@@ -2257,11 +2541,11 @@ public void testFirstLast_AllKindsOfNodeTypes() {
     Set source = getSourceForAllKindsOfNodeTypes();
     source.forEach(rb::addLong);
 
-    assertEquals(source.stream().min((l,r) -> Long.compareUnsigned(l, r)).get(), rb.first());
-    assertEquals(source.stream().max((l,r) -> Long.compareUnsigned(l, r)).get(), rb.last());
+    assertEquals(source.stream().min((l, r) -> Long.compareUnsigned(l, r)).get(), rb.first());
+    assertEquals(source.stream().max((l, r) -> Long.compareUnsigned(l, r)).get(), rb.last());
   }
 
- @Test
+  @Test
   public void testIssue619() {
     long[] CLEANER_VALUES = {140664568792144l};
     long[] ADDRESS_SPACE_VALUES = {140662937752432l};
@@ -2273,7 +2557,7 @@ public void testIssue619() {
       addressSpace.add(ADDRESS_SPACE_VALUES);
       addressSpace.add(CLEANER_VALUES);
       if (iteration == 33) {
-        //This test case can safely break here.
+        // This test case can safely break here.
         break;
       }
       addressSpace.andNot(cleaner);
@@ -2281,4 +2565,9 @@ public void testIssue619() {
     }
     assertEquals(2, addressSpace.getIntCardinality());
   }
+
+  @Test
+  public void testEmptyRoaring64BitmapClonesWithoutException() {
+    assertEquals(new Roaring64Bitmap(), new Roaring64Bitmap().clone());
+  }
 }
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64NavigableMap.java b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64NavigableMap.java
similarity index 71%
rename from RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64NavigableMap.java
rename to roaringbitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64NavigableMap.java
index 6fd4dcb1e..169cefd34 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64NavigableMap.java
+++ b/roaringbitmap/src/test/java/org/roaringbitmap/longlong/TestRoaring64NavigableMap.java
@@ -1,5 +1,23 @@
 package org.roaringbitmap.longlong;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.roaringbitmap.longlong.TestRoaring64Bitmap.getSourceForAllKindsOfNodeTypes;
+
+import org.roaringbitmap.BitmapDataProvider;
+import org.roaringbitmap.RoaringBitmap;
+import org.roaringbitmap.RoaringBitmapSupplier;
+import org.roaringbitmap.TestAdversarialInputs;
+import org.roaringbitmap.Util;
+import org.roaringbitmap.buffer.MutableRoaringBitmap;
+import org.roaringbitmap.buffer.MutableRoaringBitmapSupplier;
+
 import com.google.common.io.ByteStreams;
 import com.google.common.primitives.Ints;
 import com.google.common.primitives.Longs;
@@ -7,15 +25,22 @@
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
-import org.roaringbitmap.*;
-import org.roaringbitmap.buffer.MutableRoaringBitmap;
-import org.roaringbitmap.buffer.MutableRoaringBitmapSupplier;
-
-import java.io.*;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.*;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
 
 public class TestRoaring64NavigableMap {
 
@@ -24,7 +49,6 @@ private Roaring64NavigableMap newDefaultCtor() {
     return new Roaring64NavigableMap();
   }
 
-  // Testing the nocache behavior should not depends on bitmap being on-heap of buffered
   private Roaring64NavigableMap newNoCache() {
     return new Roaring64NavigableMap(true, false);
   }
@@ -59,11 +83,13 @@ protected void checkCardinalities(Roaring64NavigableMap bitmap) {
       index++;
     }
 
-    assertArrayEquals(expectedCardinalities,
+    assertArrayEquals(
+        expectedCardinalities,
         Arrays.copyOf(bitmap.getSortedCumulatedCardinality(), expectedCardinalities.length));
   }
 
-  public static void checkSerializeBytes(ImmutableLongBitmapDataProvider bitmap) throws IOException {
+  public static void checkSerializeBytes(ImmutableLongBitmapDataProvider bitmap)
+      throws IOException {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     try (DataOutputStream oos = new DataOutputStream(baos)) {
       bitmap.serialize(oos);
@@ -126,7 +152,6 @@ public void testZero() {
     assertEquals(1, map.rankLong(Long.MAX_VALUE));
   }
 
-
   @Test
   public void testMinusOne_Unsigned() {
     Roaring64NavigableMap map = newUnsignedHeap();
@@ -156,11 +181,9 @@ public void testMinusOne_Unsigned() {
     assertEquals(0, map.rankLong(-2));
     assertEquals(1, map.rankLong(-1));
 
-
     assertArrayEquals(new long[] {-1L}, map.toArray());
   }
 
-
   @Test
   public void testAddNotAddLong() {
     Roaring64NavigableMap map = newSignedBuffered();
@@ -229,8 +252,6 @@ public void testSimpleIntegers() {
     assertArrayEquals(new long[] {123L, 234L}, map.toArray());
   }
 
-
-
   @Test
   public void testHashCodeEquals() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -247,16 +268,17 @@ public void testHashCodeEquals() {
 
   @Test
   public void testAddOneSelect2() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64NavigableMap map = newDefaultCtor();
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64NavigableMap map = newDefaultCtor();
 
-      map.addLong(123);
+          map.addLong(123);
 
-      map.select(1);
-    });
+          map.select(1);
+        });
   }
 
-
   @Test
   public void testAddInt() {
     Roaring64NavigableMap map = newDefaultCtor();
@@ -278,11 +300,13 @@ public void testIterator_NextWithoutHasNext_Filled() {
 
   @Test
   public void testIterator_NextWithoutHasNext_Empty() {
-    assertThrows(IllegalStateException.class, () -> {
-      Roaring64NavigableMap map = newDefaultCtor();
+    assertThrows(
+        IllegalStateException.class,
+        () -> {
+          Roaring64NavigableMap map = newDefaultCtor();
 
-      map.getLongIterator().next();
-    });
+          map.getLongIterator().next();
+        });
   }
 
   @Test
@@ -372,13 +396,14 @@ public void testLongMinValueZeroOneMaxValue() {
     assertEquals(4, map.rankLong(Long.MAX_VALUE));
 
     final List foreach = new ArrayList<>();
-    map.forEach(new LongConsumer() {
-
-      @Override
-      public void accept(long value) {
-        foreach.add(value);
-      }
-    });
+    map.forEach(
+        new LongConsumer() {
+
+          @Override
+          public void accept(long value) {
+            foreach.add(value);
+          }
+        });
     assertEquals(Arrays.asList(Long.MIN_VALUE, 0L, 1L, Long.MAX_VALUE), foreach);
   }
 
@@ -585,13 +610,14 @@ public void testPerfManyDifferentBuckets_NoCache() {
 
   @Test
   public void testComparator() {
-    Comparator natural = new Comparator() {
-
-      @Override
-      public int compare(Integer o1, Integer o2) {
-        return Integer.compare(o1, o2);
-      }
-    };
+    Comparator natural =
+        new Comparator() {
+
+          @Override
+          public int compare(Integer o1, Integer o2) {
+            return Integer.compare(o1, o2);
+          }
+        };
     Comparator unsigned = RoaringIntPacking.unsignedComparator();
 
     // Comparator a negative and a positive differs from natural comparison
@@ -694,7 +720,8 @@ public void testAddingLowValueAfterHighValue() {
     assertEquals(Long.MAX_VALUE, map.select(1));
   }
 
-  private Roaring64NavigableMap clone(Roaring64NavigableMap map) throws IOException, ClassNotFoundException {
+  private Roaring64NavigableMap clone(Roaring64NavigableMap map)
+      throws IOException, ClassNotFoundException {
     return SerializationUtils.clone(map);
   }
 
@@ -722,7 +749,6 @@ public void testSerialization_OneValue() throws IOException, ClassNotFoundExcept
     assertEquals(123, clone.select(0));
   }
 
-
   @Test
   public void testSerialization_Unsigned() throws IOException, ClassNotFoundException {
     final Roaring64NavigableMap map = newUnsignedHeap();
@@ -736,9 +762,9 @@ public void testSerialization_Unsigned() throws IOException, ClassNotFoundExcept
     assertEquals(123, clone.select(0));
   }
 
-
   @Test
-  public void testSerialization_MultipleBuckets_Signed() throws IOException, ClassNotFoundException {
+  public void testSerialization_MultipleBuckets_Signed()
+      throws IOException, ClassNotFoundException {
     final Roaring64NavigableMap map = newSignedBuffered();
     map.addLong(-123);
     map.addLong(123);
@@ -755,7 +781,8 @@ public void testSerialization_MultipleBuckets_Signed() throws IOException, Class
   }
 
   @Test
-  public void testSerialization_MultipleBuckets_Unsigned() throws IOException, ClassNotFoundException {
+  public void testSerialization_MultipleBuckets_Unsigned()
+      throws IOException, ClassNotFoundException {
     final Roaring64NavigableMap map = newUnsignedHeap();
     map.addLong(-123);
     map.addLong(123);
@@ -772,7 +799,8 @@ public void testSerialization_MultipleBuckets_Unsigned() throws IOException, Cla
   }
 
   @Test
-  public void testSerializationSizeInBytes_singleBucket() throws IOException, ClassNotFoundException {
+  public void testSerializationSizeInBytes_singleBucket()
+      throws IOException, ClassNotFoundException {
     final Roaring64NavigableMap map = newDefaultCtor();
     map.addLong(123);
 
@@ -780,7 +808,8 @@ public void testSerializationSizeInBytes_singleBucket() throws IOException, Clas
   }
 
   @Test
-  public void testSerializationSizeInBytes_multipleBuckets() throws IOException, ClassNotFoundException {
+  public void testSerializationSizeInBytes_multipleBuckets()
+      throws IOException, ClassNotFoundException {
     final Roaring64NavigableMap map = newDefaultCtor();
     map.addLong(123);
     map.addLong(Long.MAX_VALUE);
@@ -789,14 +818,16 @@ public void testSerializationSizeInBytes_multipleBuckets() throws IOException, C
   }
 
   @Test
-  public void testSupplierIsTransient_defaultIsImmutable() throws IOException, ClassNotFoundException, NoSuchFieldException {
+  public void testSupplierIsTransient_defaultIsImmutable()
+      throws IOException, ClassNotFoundException, NoSuchFieldException {
     Roaring64NavigableMap map = new Roaring64NavigableMap(new MutableRoaringBitmapSupplier());
     map.add(0);
 
     final Roaring64NavigableMap clone = clone(map);
 
     // Demonstrate we fallback to RoaringBitmapSupplier as default
-    Assertions.assertTrue(map.getHighToBitmap().firstEntry().getValue() instanceof MutableRoaringBitmap);
+    Assertions.assertTrue(
+        map.getHighToBitmap().firstEntry().getValue() instanceof MutableRoaringBitmap);
     Assertions.assertTrue(clone.getHighToBitmap().firstEntry().getValue() instanceof RoaringBitmap);
   }
 
@@ -816,6 +847,27 @@ public void testOr_SameBucket() {
     assertEquals(234, left.select(1));
   }
 
+  @Test
+  public void testOr_Static_SameBucket() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    right.addLong(234);
+
+    Roaring64NavigableMap result = Roaring64NavigableMap.or(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(234, right.select(0));
+
+    assertEquals(2, result.getLongCardinality());
+
+    assertEquals(123, result.select(0));
+    assertEquals(234, result.select(1));
+  }
+
   @Test
   public void testOr_MultipleBuckets() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -834,6 +886,30 @@ public void testOr_MultipleBuckets() {
     assertEquals(Long.MAX_VALUE, left.select(2));
   }
 
+  @Test
+  public void testOr_Static_MultipleBuckets() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    left.addLong(Long.MAX_VALUE);
+    right.addLong(234);
+
+    Roaring64NavigableMap result = Roaring64NavigableMap.or(left, right);
+    // check that inputs have not changed
+    assertEquals(2, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(Long.MAX_VALUE, left.select(1));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(234, right.select(0));
+
+    assertEquals(3, result.getLongCardinality());
+
+    assertEquals(123, result.select(0));
+    assertEquals(234, result.select(1));
+    assertEquals(Long.MAX_VALUE, result.select(2));
+  }
+
   @Test
   public void testOr_DifferentBucket_NotBuffer() {
     Roaring64NavigableMap left = newSignedBuffered();
@@ -850,6 +926,26 @@ public void testOr_DifferentBucket_NotBuffer() {
     assertEquals(Long.MAX_VALUE / 2, left.select(1));
   }
 
+  @Test
+  public void testOr_Static_DifferentBucket_NotBuffer() {
+    Roaring64NavigableMap left = newSignedBuffered();
+    Roaring64NavigableMap right = newSignedBuffered();
+
+    left.addLong(123);
+    right.addLong(Long.MAX_VALUE / 2);
+
+    Roaring64NavigableMap result = Roaring64NavigableMap.or(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(Long.MAX_VALUE / 2, right.select(0));
+
+    assertEquals(2, result.getLongCardinality());
+
+    assertEquals(123, result.select(0));
+    assertEquals(Long.MAX_VALUE / 2, result.select(1));
+  }
 
   @Test
   public void testOr_SameBucket_NotBuffer() {
@@ -867,6 +963,27 @@ public void testOr_SameBucket_NotBuffer() {
     assertEquals(234, left.select(1));
   }
 
+  @Test
+  public void testOr_Static_SameBucket_NotBuffer() {
+    Roaring64NavigableMap left = new Roaring64NavigableMap(true, new RoaringBitmapSupplier());
+    Roaring64NavigableMap right = new Roaring64NavigableMap(true, new RoaringBitmapSupplier());
+
+    left.addLong(123);
+    right.addLong(234);
+
+    Roaring64NavigableMap result = Roaring64NavigableMap.or(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(234, right.select(0));
+
+    assertEquals(2, result.getLongCardinality());
+
+    assertEquals(123, result.select(0));
+    assertEquals(234, result.select(1));
+  }
+
   @Test
   public void testOr_DifferentBucket_Buffer() {
     Roaring64NavigableMap left = newSignedBuffered();
@@ -883,6 +1000,27 @@ public void testOr_DifferentBucket_Buffer() {
     assertEquals(Long.MAX_VALUE, left.select(1));
   }
 
+  @Test
+  public void testOr_Static_DifferentBucket_Buffer() {
+    Roaring64NavigableMap left = newSignedBuffered();
+    Roaring64NavigableMap right = newSignedBuffered();
+
+    left.addLong(123);
+    right.addLong(Long.MAX_VALUE);
+
+    Roaring64NavigableMap result = Roaring64NavigableMap.or(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(Long.MAX_VALUE, right.select(0));
+
+    assertEquals(2, result.getLongCardinality());
+
+    assertEquals(123, result.select(0));
+    assertEquals(Long.MAX_VALUE, result.select(1));
+  }
+
   @Test
   public void testOr_SameBucket_Buffer() {
     Roaring64NavigableMap left = newSignedBuffered();
@@ -899,6 +1037,27 @@ public void testOr_SameBucket_Buffer() {
     assertEquals(234, left.select(1));
   }
 
+  @Test
+  public void testOr_Static_SameBucket_Buffer() {
+    Roaring64NavigableMap left = newSignedBuffered();
+    Roaring64NavigableMap right = newSignedBuffered();
+
+    left.addLong(123);
+    right.addLong(234);
+
+    Roaring64NavigableMap result = Roaring64NavigableMap.or(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(234, right.select(0));
+
+    assertEquals(2, result.getLongCardinality());
+
+    assertEquals(123, result.select(0));
+    assertEquals(234, result.select(1));
+  }
+
   @Test
   public void testOr_CloneInput() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -920,6 +1079,30 @@ public void testOr_CloneInput() {
     assertEquals(123, right.select(0));
   }
 
+  @Test
+  public void testOr_Static_CloneInput() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    right.addLong(123);
+
+    // We push in left a bucket which does not exist
+    Roaring64NavigableMap result = Roaring64NavigableMap.or(left, right);
+    // check that inputs have not changed
+    assertEquals(0, left.getLongCardinality());
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(123, right.select(0));
+
+    // Then we mutate left: ensure it does not impact right as it should remain unchanged
+    result.addLong(234);
+
+    assertEquals(2, result.getLongCardinality());
+    assertEquals(123, result.select(0));
+    assertEquals(234, result.select(1));
+
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(123, right.select(0));
+  }
 
   @Test
   public void testXor_SingleBucket() {
@@ -988,7 +1171,6 @@ public void testXor_MultipleBucket() {
     assertEquals(123, left.select(0));
   }
 
-
   @Test
   public void testAnd_SingleBucket() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -1006,6 +1188,30 @@ public void testAnd_SingleBucket() {
     assertEquals(234, left.select(0));
   }
 
+  @Test
+  public void testAnd_Static_SingleBucket() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    left.addLong(234);
+    right.addLong(234);
+    right.addLong(345);
+
+    // We have 1 shared value: 234
+    Roaring64NavigableMap result = Roaring64NavigableMap.and(left, right);
+    // check that inputs have not changed
+    assertEquals(2, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(234, left.select(1));
+    assertEquals(2, right.getLongCardinality());
+    assertEquals(234, right.select(0));
+    assertEquals(345, right.select(1));
+
+    assertEquals(1, result.getLongCardinality());
+    assertEquals(234, result.select(0));
+  }
+
   @Test
   public void testAnd_Buffer() {
     Roaring64NavigableMap left = newSignedBuffered();
@@ -1021,6 +1227,26 @@ public void testAnd_Buffer() {
     assertEquals(123, left.select(0));
   }
 
+  @Test
+  public void testAnd_Static_Buffer() {
+    Roaring64NavigableMap left = newSignedBuffered();
+    Roaring64NavigableMap right = newSignedBuffered();
+
+    left.addLong(123);
+    right.addLong(123);
+
+    // We have 1 shared value: 234
+    Roaring64NavigableMap result = Roaring64NavigableMap.and(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(123, right.select(0));
+
+    assertEquals(1, result.getLongCardinality());
+    assertEquals(123, result.select(0));
+  }
+
   @Test
   public void testAnd_DifferentBucket() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -1035,6 +1261,25 @@ public void testAnd_DifferentBucket() {
     assertEquals(0, left.getLongCardinality());
   }
 
+  @Test
+  public void testAnd_Static_DifferentBucket() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    right.addLong(Long.MAX_VALUE);
+
+    // We have 1 shared value: 234
+    Roaring64NavigableMap result = Roaring64NavigableMap.and(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(Long.MAX_VALUE, right.select(0));
+
+    assertEquals(0, result.getLongCardinality());
+  }
+
   @Test
   public void testAnd_MultipleBucket() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -1051,6 +1296,27 @@ public void testAnd_MultipleBucket() {
     assertEquals(Long.MAX_VALUE, left.select(0));
   }
 
+  @Test
+  public void testAnd_Static_MultipleBucket() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    left.addLong(Long.MAX_VALUE);
+    right.addLong(Long.MAX_VALUE);
+
+    // We have 1 shared value: 234
+    Roaring64NavigableMap result = Roaring64NavigableMap.and(left, right);
+    // check that inputs have not changed
+    assertEquals(2, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(Long.MAX_VALUE, left.select(1));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(Long.MAX_VALUE, right.select(0));
+
+    assertEquals(1, result.getLongCardinality());
+    assertEquals(Long.MAX_VALUE, result.select(0));
+  }
 
   @Test
   public void testAndNot_SingleBucket() {
@@ -1069,6 +1335,30 @@ public void testAndNot_SingleBucket() {
     assertEquals(123, left.select(0));
   }
 
+  @Test
+  public void testAndNot_Static_SingleBucket() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    left.addLong(234);
+    right.addLong(234);
+    right.addLong(345);
+
+    // We have 1 shared value: 234
+    Roaring64NavigableMap result = Roaring64NavigableMap.andNot(left, right);
+    // check that inputs have not changed
+    assertEquals(2, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(234, left.select(1));
+    assertEquals(2, right.getLongCardinality());
+    assertEquals(234, right.select(0));
+    assertEquals(345, right.select(1));
+
+    assertEquals(1, result.getLongCardinality());
+    assertEquals(123, result.select(0));
+  }
+
   @Test
   public void testAndNot_Buffer() {
     Roaring64NavigableMap left = newSignedBuffered();
@@ -1084,6 +1374,25 @@ public void testAndNot_Buffer() {
     assertEquals(123, left.select(0));
   }
 
+  @Test
+  public void testAndNot_Static_Buffer() {
+    Roaring64NavigableMap left = newSignedBuffered();
+    Roaring64NavigableMap right = newSignedBuffered();
+
+    left.addLong(123);
+    right.addLong(234);
+
+    Roaring64NavigableMap result = Roaring64NavigableMap.andNot(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(234, right.select(0));
+
+    assertEquals(1, result.getLongCardinality());
+    assertEquals(123, result.select(0));
+  }
+
   @Test
   public void testAndNot_DifferentBucket() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -1099,6 +1408,26 @@ public void testAndNot_DifferentBucket() {
     assertEquals(123, left.select(0));
   }
 
+  @Test
+  public void testAndNot_Static_DifferentBucket() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    right.addLong(Long.MAX_VALUE);
+
+    // We have 1 shared value: 234
+    Roaring64NavigableMap result = Roaring64NavigableMap.andNot(left, right);
+    // check that inputs have not changed
+    assertEquals(1, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(Long.MAX_VALUE, right.select(0));
+
+    assertEquals(1, result.getLongCardinality());
+    assertEquals(123, result.select(0));
+  }
+
   @Test
   public void testAndNot_MultipleBucket() {
     Roaring64NavigableMap left = newDefaultCtor();
@@ -1115,6 +1444,28 @@ public void testAndNot_MultipleBucket() {
     assertEquals(123, left.select(0));
   }
 
+  @Test
+  public void testAndNot_Static_MultipleBucket() {
+    Roaring64NavigableMap left = newDefaultCtor();
+    Roaring64NavigableMap right = newDefaultCtor();
+
+    left.addLong(123);
+    left.addLong(Long.MAX_VALUE);
+    right.addLong(Long.MAX_VALUE);
+
+    // We have 1 shared value: Long.MAX_VALUE
+    Roaring64NavigableMap result = Roaring64NavigableMap.andNot(left, right);
+    // check that inputs have not changed
+    assertEquals(2, left.getLongCardinality());
+    assertEquals(123, left.select(0));
+    assertEquals(Long.MAX_VALUE, left.select(1));
+    assertEquals(1, right.getLongCardinality());
+    assertEquals(Long.MAX_VALUE, right.select(0));
+
+    assertEquals(1, result.getLongCardinality());
+    assertEquals(123, result.select(0));
+  }
+
   @Test
   public void testToString_signed() {
     Roaring64NavigableMap map = new Roaring64NavigableMap(true);
@@ -1148,7 +1499,6 @@ public void testAddRange_SingleBucket_NotBuffer() {
     assertEquals(11L, map.select(6L));
   }
 
-
   @Test
   public void testAddRange_SingleBucket_Buffer() {
     Roaring64NavigableMap map = newSignedBuffered();
@@ -1175,7 +1525,6 @@ public void testAddRange_EndExcludingNextBitmapFirstLow() {
     assertEquals(end - 1, map.select(1));
   }
 
-
   @Test
   public void testAddRange_MultipleBuckets() {
     Roaring64NavigableMap map = newDefaultCtor();
@@ -1192,17 +1541,18 @@ public void testAddRange_MultipleBuckets() {
     assertEquals(to - 1, map.select(nbItems - 1));
   }
 
-
   public static final long outOfRoaringBitmapRange = 2L * Integer.MAX_VALUE + 3L;
 
   // Check this range is not handled by RoaringBitmap
   @Test
   public void testCardinalityAboveIntegerMaxValue_RoaringBitmap() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      RoaringBitmap map = new RoaringBitmap();
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          RoaringBitmap map = new RoaringBitmap();
 
-      map.add(0L, outOfRoaringBitmapRange);
-    });
+          map.add(0L, outOfRoaringBitmapRange);
+        });
   }
 
   @Test
@@ -1219,7 +1569,6 @@ public void testCardinalityAboveIntegerMaxValue() {
 
     assertEquals(0, map.select(0));
     assertEquals(outOfSingleRoaring - 1, map.select(outOfSingleRoaring - 1));
-
   }
 
   @Test
@@ -1282,23 +1631,23 @@ public void testAutoboxedIterator() {
 
   @Test
   public void testAutoboxedIterator_CanNotRemove() {
-    assertThrows(UnsupportedOperationException.class, () -> {
-      Roaring64NavigableMap map = newUnsignedHeap();
+    assertThrows(
+        UnsupportedOperationException.class,
+        () -> {
+          Roaring64NavigableMap map = newUnsignedHeap();
 
-      map.addLong(123);
-      map.addLong(234);
+          map.addLong(123);
+          map.addLong(234);
 
-      Iterator it = map.iterator();
+          Iterator it = map.iterator();
 
-      assertTrue(it.hasNext());
+          assertTrue(it.hasNext());
 
-      // Should throw a UnsupportedOperationException
-      it.remove();
-    });
+          // Should throw a UnsupportedOperationException
+          it.remove();
+        });
   }
 
-
-
   @Test
   public void testSelect_NoCache_MultipleBuckets() {
     Roaring64NavigableMap map = newNoCache();
@@ -1312,37 +1661,41 @@ public void testSelect_NoCache_MultipleBuckets() {
 
   @Test
   public void testSelect_Empty() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64NavigableMap map = newUnsignedHeap();
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64NavigableMap map = newUnsignedHeap();
 
-      map.select(0);
-    });
+          map.select(0);
+        });
   }
 
-
   @Test
   public void testSelect_OutOfBounds_MatchCardinality() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64NavigableMap map = newUnsignedHeap();
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64NavigableMap map = newUnsignedHeap();
 
-      map.addLong(123);
+          map.addLong(123);
 
-      map.select(1);
-    });
+          map.select(1);
+        });
   }
 
   @Test
   public void testSelect_OutOfBounds_OtherCardinality() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      Roaring64NavigableMap map = newUnsignedHeap();
+    assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          Roaring64NavigableMap map = newUnsignedHeap();
 
-      map.addLong(123);
+          map.addLong(123);
 
-      map.select(2);
-    });
+          map.select(2);
+        });
   }
 
-
   @Test
   public void testRank_NoCache_MultipleBuckets() {
     Roaring64NavigableMap map = newNoCache();
@@ -1503,12 +1856,12 @@ public void testLongSizeInBytes() {
     map.add(0);
     map.add(2L * Integer.MAX_VALUE);
     map.addRange(8L * Integer.MAX_VALUE, 8L * Integer.MAX_VALUE + 1024);
-    
+
     assertEquals(3, map.getHighToBitmap().size());
 
     // Size with multiple entries
     assertEquals(228, map.getLongSizeInBytes());
-    
+
     // Select does allocate some cache
     map.select(16);
     assertEquals(264, map.getLongSizeInBytes());
@@ -1516,11 +1869,14 @@ public void testLongSizeInBytes() {
 
   @Test
   public void testLazyOr() {
-    Roaring64NavigableMap map1 = Roaring64NavigableMap.bitmapOf(1 << 16, 1 << 18, 1 << 19, 1 << 33);
+    Roaring64NavigableMap map1 =
+        Roaring64NavigableMap.bitmapOf(1 << 16, 1 << 18, 1 << 19, 1L << 33);
     map1.naivelazyor(Roaring64NavigableMap.bitmapOf(4, 7, 8, 9));
     map1.naivelazyor(Roaring64NavigableMap.bitmapOf(1, 2, 3, 4, 5, 1 << 16, 1 << 17, 1 << 20));
     map1.repairAfterLazy();
-    Roaring64NavigableMap map2 = Roaring64NavigableMap.bitmapOf(1, 2, 3, 4, 5, 7, 8, 9, 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20 , 1 << 33);
+    Roaring64NavigableMap map2 =
+        Roaring64NavigableMap.bitmapOf(
+            1, 2, 3, 4, 5, 7, 8, 9, 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1L << 33);
     assertEquals(map2, map1);
   }
 
@@ -1545,6 +1901,26 @@ public void testAnd_ImplicitRoaringBitmap() {
     }
   }
 
+  @Test
+  public void testAnd_Static_ImplicitRoaringBitmap() {
+    // Based on RoaringBitmap
+    Roaring64NavigableMap x = new Roaring64NavigableMap();
+    x.addRange(123, 124);
+    Assertions.assertTrue(x.getHighToBitmap().values().iterator().next() instanceof RoaringBitmap);
+
+    // Based on MutableRoaringBitmap
+    Roaring64NavigableMap y = Roaring64NavigableMap.bitmapOf(4L);
+    Assertions.assertTrue(y.getHighToBitmap().values().iterator().next() instanceof RoaringBitmap);
+
+    {
+      Roaring64NavigableMap result = Roaring64NavigableMap.and(x, y);
+
+      BitmapDataProvider singleBitmap = result.getHighToBitmap().values().iterator().next();
+      Assertions.assertTrue(singleBitmap instanceof RoaringBitmap);
+      Assertions.assertTrue(singleBitmap.isEmpty());
+    }
+  }
+
   @Test
   public void testAnd_MutableRoaringBitmap() {
     // Based on RoaringBitmap
@@ -1560,6 +1936,21 @@ public void testAnd_MutableRoaringBitmap() {
     Assertions.assertEquals(8L, x.getLongCardinality());
   }
 
+  @Test
+  public void testAnd_Static_MutableRoaringBitmap() {
+    // Based on RoaringBitmap
+    Roaring64NavigableMap x = new Roaring64NavigableMap(new MutableRoaringBitmapSupplier());
+    x.addRange(0, 16);
+
+    // Based on MutableRoaringBitmap
+    Roaring64NavigableMap y = new Roaring64NavigableMap(new MutableRoaringBitmapSupplier());
+    y.addRange(8, 32);
+
+    Assertions.assertEquals(16L, x.getLongCardinality());
+    Roaring64NavigableMap result = Roaring64NavigableMap.and(x, y);
+    Assertions.assertEquals(8L, result.getLongCardinality());
+  }
+
   @Test
   public void testAnd_IncompatibleImplementations() {
     // Based on RoaringBitmap
@@ -1573,6 +1964,20 @@ public void testAnd_IncompatibleImplementations() {
     Assertions.assertThrows(UnsupportedOperationException.class, () -> x.and(y));
   }
 
+  @Test
+  public void testAnd_Static_IncompatibleImplementations() {
+    // Based on RoaringBitmap
+    Roaring64NavigableMap x = new Roaring64NavigableMap(new RoaringBitmapSupplier());
+    x.addRange(0, 16);
+
+    // Based on MutableRoaringBitmap
+    Roaring64NavigableMap y = new Roaring64NavigableMap(new MutableRoaringBitmapSupplier());
+    y.addRange(8, 32);
+
+    Assertions.assertThrows(
+        UnsupportedOperationException.class, () -> Roaring64NavigableMap.and(x, y));
+  }
+
   @Test
   public void testAndNot_ImplicitRoaringBitmap() {
     // Based on RoaringBitmap
@@ -1594,6 +1999,27 @@ public void testAndNot_ImplicitRoaringBitmap() {
     }
   }
 
+  @Test
+  public void testAndNot_Static_ImplicitRoaringBitmap() {
+    // Based on RoaringBitmap
+    Roaring64NavigableMap x = new Roaring64NavigableMap();
+    x.addRange(8, 16);
+
+    // Based on MutableRoaringBitmap
+    Roaring64NavigableMap y = new Roaring64NavigableMap();
+    y.addRange(12, 32);
+
+    {
+      Roaring64NavigableMap result = Roaring64NavigableMap.andNot(x, y);
+
+      BitmapDataProvider singleBitmap = result.getHighToBitmap().values().iterator().next();
+      Assertions.assertTrue(singleBitmap instanceof RoaringBitmap);
+      Assertions.assertEquals(4L, singleBitmap.getLongCardinality());
+      Assertions.assertEquals(8L, singleBitmap.select(0));
+      Assertions.assertEquals(11L, singleBitmap.select(3));
+    }
+  }
+
   @Test
   public void testOr_ImplicitRoaringBitmap() {
     // Based on RoaringBitmap
@@ -1631,7 +2057,8 @@ public void testNaivelazyor_ImplicitRoaringBitmap() {
     }
   }
 
-  private void checkConsistencyWithResource(String resourceName, Roaring64NavigableMap bitmap) throws IOException {
+  private void checkConsistencyWithResource(String resourceName, Roaring64NavigableMap bitmap)
+      throws IOException {
     byte[] reference = ByteStreams.toByteArray(TestAdversarialInputs.openInputstream(resourceName));
 
     Assertions.assertEquals(reference.length, bitmap.serializedSizeInBytes());
@@ -1643,7 +2070,8 @@ private void checkConsistencyWithResource(String resourceName, Roaring64Navigabl
 
   @Test
   public void testSerialization_empty() throws IOException, ClassNotFoundException {
-    // This example binary comes from https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
+    // This example binary comes from
+    // https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
     String resourceName = "/testdata/64mapempty.bin";
     InputStream inputStream = TestAdversarialInputs.openInputstream(resourceName);
 
@@ -1661,7 +2089,8 @@ public void testSerialization_empty() throws IOException, ClassNotFoundException
 
   @Test
   public void testSerialization_64map32bitvals() throws IOException, ClassNotFoundException {
-    // This example binary comes from https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
+    // This example binary comes from
+    // https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
     String resourceName = "/testdata/64map32bitvals.bin";
     InputStream inputStream = TestAdversarialInputs.openInputstream(resourceName);
 
@@ -1679,9 +2108,46 @@ public void testSerialization_64map32bitvals() throws IOException, ClassNotFound
     checkConsistencyWithResource(resourceName, bitmap);
   }
 
+  @Test
+  public void testAllKindOfNodeTypesSerDeser() throws Exception {
+    Set source = getSourceForAllKindsOfNodeTypes();
+
+    Roaring64NavigableMap map = new Roaring64NavigableMap();
+    for (long x : source) {
+      map.addLong(x);
+    }
+
+    LongIterator longIterator = map.getLongIterator();
+    int i = 0;
+    while (longIterator.hasNext()) {
+      long actual = longIterator.next();
+      Assertions.assertTrue(source.contains(actual));
+      i++;
+    }
+    Assertions.assertEquals(source.size(), i);
+    // test all kind of nodes' serialization/deserialization
+    long sizeL = map.serializedSizeInBytes();
+    if (sizeL > Integer.MAX_VALUE) {
+      return;
+    }
+
+    int sizeInt = (int) sizeL;
+    long select2 = map.select(2);
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(sizeInt);
+    DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
+    map.serialize(dataOutputStream);
+    ByteArrayInputStream byteArrayInputStream =
+        new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
+    DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
+    Roaring64NavigableMap deserStreamOne = new Roaring64NavigableMap();
+    deserStreamOne.deserialize(dataInputStream);
+    Assertions.assertEquals(select2, deserStreamOne.select(2));
+  }
+
   @Test
   public void testSerialization_spreadvals() throws IOException, ClassNotFoundException {
-    // This example binary comes from https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
+    // This example binary comes from
+    // https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
     String resourceName = "/testdata/64mapspreadvals.bin";
     InputStream inputStream = TestAdversarialInputs.openInputstream(resourceName);
 
@@ -1704,7 +2170,8 @@ public void testSerialization_spreadvals() throws IOException, ClassNotFoundExce
 
   @Test
   public void testSerialization_highvals() throws IOException, ClassNotFoundException {
-    // This example binary comes from https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
+    // This example binary comes from
+    // https://github.com/RoaringBitmap/CRoaring/tree/master/tests/testdata
     String resourceName = "/testdata/64maphighvals.bin";
     InputStream inputStream = TestAdversarialInputs.openInputstream(resourceName);
 
@@ -1774,7 +2241,11 @@ public void testRangeAroundIntegerMax() {
 
     Assertions.assertEquals(4L, x.getLongCardinality());
     Assertions.assertEquals(1L, x.getHighToBitmap().size());
-    Assertions.assertArrayEquals(new long[] {Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, Integer.MAX_VALUE + 2L}, x.toArray());
+    Assertions.assertArrayEquals(
+        new long[] {
+          Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, Integer.MAX_VALUE + 2L
+        },
+        x.toArray());
   }
 
   @Test
@@ -1785,7 +2256,8 @@ public void testRangeAround2TimesIntegerMax() {
 
     Assertions.assertEquals(4L, x.getLongCardinality());
     Assertions.assertEquals(2L, x.getHighToBitmap().size());
-    Assertions.assertArrayEquals(new long[] {rangeStart, rangeStart+1L, rangeStart+2L, rangeStart+3L}, x.toArray());
+    Assertions.assertArrayEquals(
+        new long[] {rangeStart, rangeStart + 1L, rangeStart + 2L, rangeStart + 3L}, x.toArray());
   }
 
   @Test
@@ -1794,16 +2266,20 @@ public void testRangeAroundLongMax() {
     x.addRange(Long.MAX_VALUE - 1L, Long.MAX_VALUE + 3L);
 
     Assertions.assertEquals(4L, x.getLongCardinality());
-    Assertions.assertArrayEquals(new long[] {Long.MAX_VALUE - 1L, Long.MAX_VALUE, Long.MIN_VALUE, Long.MIN_VALUE + 1L}, x.toArray());
+    Assertions.assertArrayEquals(
+        new long[] {Long.MAX_VALUE - 1L, Long.MAX_VALUE, Long.MIN_VALUE, Long.MIN_VALUE + 1L},
+        x.toArray());
   }
 
   @Test()
   public void testRangeAroundLongMax_signed() {
     Roaring64NavigableMap x = newSignedBuffered();
 
-    Assertions.assertThrows(IllegalArgumentException.class, () -> {
-        x.addRange(Long.MAX_VALUE - 1L, Long.MAX_VALUE + 3L);
-    });
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> {
+          x.addRange(Long.MAX_VALUE - 1L, Long.MAX_VALUE + 3L);
+        });
   }
 
   @Test
@@ -1816,7 +2292,6 @@ public void testEmptyLast() {
     assertThrows(NoSuchElementException.class, () -> newDefaultCtor().last());
   }
 
-
   @Test
   public void testFirstLast_32b() {
     Roaring64NavigableMap rb = newDefaultCtor();
diff --git a/RoaringBitmap/src/test/resources/junit-platform.properties b/roaringbitmap/src/test/resources/junit-platform.properties
similarity index 100%
rename from RoaringBitmap/src/test/resources/junit-platform.properties
rename to roaringbitmap/src/test/resources/junit-platform.properties
diff --git a/RoaringBitmap/src/test/resources/testdata/64map32bitvals.bin b/roaringbitmap/src/test/resources/testdata/64map32bitvals.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/64map32bitvals.bin
rename to roaringbitmap/src/test/resources/testdata/64map32bitvals.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/64mapempty.bin b/roaringbitmap/src/test/resources/testdata/64mapempty.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/64mapempty.bin
rename to roaringbitmap/src/test/resources/testdata/64mapempty.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/64maphighvals.bin b/roaringbitmap/src/test/resources/testdata/64maphighvals.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/64maphighvals.bin
rename to roaringbitmap/src/test/resources/testdata/64maphighvals.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/64mapspreadvals.bin b/roaringbitmap/src/test/resources/testdata/64mapspreadvals.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/64mapspreadvals.bin
rename to roaringbitmap/src/test/resources/testdata/64mapspreadvals.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/bitmapwithoutruns.bin b/roaringbitmap/src/test/resources/testdata/bitmapwithoutruns.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/bitmapwithoutruns.bin
rename to roaringbitmap/src/test/resources/testdata/bitmapwithoutruns.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/bitmapwithruns.bin b/roaringbitmap/src/test/resources/testdata/bitmapwithruns.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/bitmapwithruns.bin
rename to roaringbitmap/src/test/resources/testdata/bitmapwithruns.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput1.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput1.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput1.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput1.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput2.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput2.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput2.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput2.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput3.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput3.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput3.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput3.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput4.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput4.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput4.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput4.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput5.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput5.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput5.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput5.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput6.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput6.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput6.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput6.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput7.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput7.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput7.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput7.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/crashproneinput8.bin b/roaringbitmap/src/test/resources/testdata/crashproneinput8.bin
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/crashproneinput8.bin
rename to roaringbitmap/src/test/resources/testdata/crashproneinput8.bin
diff --git a/RoaringBitmap/src/test/resources/testdata/offset_failure_case_1.txt b/roaringbitmap/src/test/resources/testdata/offset_failure_case_1.txt
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/offset_failure_case_1.txt
rename to roaringbitmap/src/test/resources/testdata/offset_failure_case_1.txt
diff --git a/RoaringBitmap/src/test/resources/testdata/offset_failure_case_2.txt b/roaringbitmap/src/test/resources/testdata/offset_failure_case_2.txt
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/offset_failure_case_2.txt
rename to roaringbitmap/src/test/resources/testdata/offset_failure_case_2.txt
diff --git a/RoaringBitmap/src/test/resources/testdata/offset_failure_case_3.txt b/roaringbitmap/src/test/resources/testdata/offset_failure_case_3.txt
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/offset_failure_case_3.txt
rename to roaringbitmap/src/test/resources/testdata/offset_failure_case_3.txt
diff --git a/RoaringBitmap/src/test/resources/testdata/ornot-fuzz-failure.json b/roaringbitmap/src/test/resources/testdata/ornot-fuzz-failure.json
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/ornot-fuzz-failure.json
rename to roaringbitmap/src/test/resources/testdata/ornot-fuzz-failure.json
diff --git a/RoaringBitmap/src/test/resources/testdata/prevvalue-regression.txt b/roaringbitmap/src/test/resources/testdata/prevvalue-regression.txt
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/prevvalue-regression.txt
rename to roaringbitmap/src/test/resources/testdata/prevvalue-regression.txt
diff --git a/roaringbitmap/src/test/resources/testdata/rangebitmap_regression.txt b/roaringbitmap/src/test/resources/testdata/rangebitmap_regression.txt
new file mode 100644
index 000000000..c25bace4d
--- /dev/null
+++ b/roaringbitmap/src/test/resources/testdata/rangebitmap_regression.txt
@@ -0,0 +1 @@
+140350,140350,140352,140353,140353,140370,140375,140379,140393,140396,140396,140397,140397,140401,140405,140405,140405,140405,140405,140406,140406,140406,140406,140406,140406,140406,140407,140407,140409,140410,140412,140412,140412,140412,140416,140417,140421,140425,140425,140425,140426,140427,140427,140428,140428,140430,140431,140432,140432,140432,140432,140432,140432,140433,140434,140434,140436,140442,140442,140443,140445,140445,140453,140453,140453,140453,140453,140453,140453,140454,140454,140454,140454,140454,140458,140458,140458,140458,140458,140458,140458,140458,140459,140459,140459,140461,140463,140465,140468,140468,140468,140469,140469,140471,140471,140472,140473,140474,140474,140475,140475,140477,140477,140478,140482,140482,140482,140482,140482,140482,140487,140487,140487,140487,140488,140489,140489,140496,140500,140500,140501,140502,140502,140502,140502,140503,140505,140506,140506,140506,140506,140507,140507,140509,140515,140515,140515,140516,140516,140519,140519,140520,140521,140521,140521,140521,140525,140526,140526,140527,140527,140527,140535,140536,140536,140537,140541,140541,140541,140543,140546,140546,140549,140549,140553,140553,140555,140558,140561,140563,140564,140565,140568,140575,140578,140592,140599,140599,140600,140600,140600,140600,140611,140614,140616,140617,140625,140625,140635,140635,140656,140669,140671,140672,140672,140672,140672,140672,140672,140672,140672,140672,140672,140674,140675,140675,140675,140677,140677,140681,140682,140682,140683,140683,140685,140687,140688,140689,140689,140699,140707,140714,140714,140714,140714,140714,140714,140714,140714,140715,140722,140722,140722,140730,140731,140734,140735,140739,140741,140753,140757,140757,140759,140759,140761,140763,140763,140764,140764,140764,140767,140771,140771,140772,140772,140774,140781,140786,140793,140793,140793,140793,140793,140793,140795,140795,140795,140795,140795,140795,140798,140800,140803,140804,140804,140807,140808,140813,140815,140815,140815,140815,140816,140817,140818,140818,140818,140819,140819,140821,140823,140827,140829,140829,140840,140845,140845,140845,140848,140850,140852,140853,140854,140854,140854,140854,140854,140857,140857,140858,140870,140870,140870,140870,140870,140870,140870,140870,140874,140876,140876,140879,140881,140883,140883,140883,140893,140893,140901,140903,140904,140905,140908,140908,140908,140908,140913,140920,140920,140920,140928,140929,140929,140929,140929,140929,140929,140930,140931,140941,140946,140946,140946,140946,140946,140946,140946,140946,140946,140952,140952,140952,140955,140968,140969,140970,140974,140974,140975,140975,140975,140977,140979,140979,140979,140979,140979,140979,140979,140979,140981,140981,140981,140981,140984,140987,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140988,140989,140990,140990,140990,140990,140992,140992,140992,140994,140994,140998,141004,141007,141014,141016,141016,141016,141016,141017,141018,141018,141025,141026,141026,141028,141037,141037,141037,141037,141048,141048,141055,141057,141065,141067,141067,141072,141072,141072,141072,141072,141072,141072,141072,141072,141072,141084,141084,141084,141084,141084,141084,141084,141084,141084,141085,141086,141086,141087,141088,141088,141089,141097,141097,141097,141097,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141098,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141099,141100,141100,141100,141100,141101,141101,141101,141101,141101,141101,141101,141101,141101,141101,141101,141101,141101,141102,141102,141102,141102,141102,141102,141102,141102,141102,141102,141102,141102,141102,141102,141103,141103,141103,141103,141103,141103,141104,141104,141104,141104,141104,141104,141104,141104,141104,141104,141104,141105,141106,141108,141108,141108,141108,141108,141109,141109,141109,141110,141110,141110,141110,141111,141112,141113,141113,141114,141114,141114,141114,141116,141117,141117,141118,141121,141121,141121,141122,141122,141122,141122,141123,141123,141124,141127,141127,141127,141128,141128,141128,141128,141128,141128,141128,141129,141131,141131,141131,141131,141131,141133,141133,141133,141133,141133,141135,141135,141135,141137,141139,141139,141139,141143,141144,141147,141147,141147,141147,141149,141149,141149,141154,141155,141155,141157,141157,141161,141162,141167,141167,141167,141168,141168,141168,141168,141168,141168,141168,141168,141168,141168,141168,141168,141169,141169,141169,141169,141169,141169,141169,141169,141169,141169,141169,141169,141169,141170,141170,141170,141170,141170,141170,141170,141170,141171,141172,141172,141176,141177,141177,141177,141178,141180,141180,141180,141180,141180,141180,141180,141180,141180,141180,141180,141183,141187,141187,141189,141189,141189,141190,141191,141191,141191,141195,141195,141195,141195,141195,141195,141195,141197,141197,141197,141197,141197,141197,141197,141197,141197,141197,141199,141200,141200,141200,141200,141200,141200,141200,141201,141202,141202,141202,141204,141204,141207,141207,141210,141212,141217,141220,141220,141221,141222,141224,141224,141225,141225,141225,141225,141225,141227,141230,141230,141230,141230,141230,141231,141240,141244,141244,141245,141245,141248,141254,141254,141254,141254,141264,141264,141264,141264,141267,141268,141269,141275,141275,141280,141281,141286,141287,141287,141287,141287,141287,141293,141293,141300,141305,141324,141324,141325,141330,141330,141336,141339,141342,141342,141343,141343,141344,141345,141346,141347,141348,141348,141348,141348,141349,141350,141357,141359,141359,141359,141360,141361,141367,141368,141368,141368,141370,141371,141372,141379,141381,141387,141394,141394,141395,141400,141400,141400,141401,141401,141402,141402,141411,141411,141411,141412,141415,141416,141416,141419,141423,141430,141431,141431,141435,141435,141438,141438,141438,141439,141439,141440,141440,141440,141441,141441,141441,141441,141443,141447,141447,141448,141448,141448,141448,141449,141449,141450,141452,141452,141455,141455,141455,141455,141457,141457,141457,141457,141458,141458,141460,141461,141461,141461,141461,141461,141461,141461,141463,141464,141467,141467,141473,141481,141481,141481,141481,141482,141482,141483,141483,141483,141484,141484,141484,141487,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141489,141490,141490,141495,141495,141495,141495,141497,141497,141500,141500,141506,141506,141507,141508,141509,141514,141514,141514,141514,141514,141517,141518,141518,141522,141524,141524,141528,141528,141529,141529,141530,141530,141532,141532,141533,141535,141535,141537,141537,141537,141537,141540,141540,141540,141540,141544,141544,141547,141547,141548,141548,141550,141551,141551,141551,141551,141554,141554,141556,141557,141557,141559,141559,141560,141563,141563,141563,141569,141571,141571,141571,141573,141576,141576,141576,141577,141577,141580,141582,141582,141583,141590,141594,141594,141595,141596,141609,141609,141618,141618,141621,141621,141622,141624,141625,141625,141625,141625,141625,141625,141625,141626,141627,141630,141630,141630,141635,141635,141636,141637,141640,141640,141640,141643,141643,141646,141646,141648,141650,141650,141650,141650,141652,141653,141653,141656,141659,141659,141659,141660,141663,141663,141668,141668,141671,141671,141672,141672,141672,141674,141676,141676,141685,141686,141686,141688,141690,141692,141693,141698,141702,141702,141703,141705,141707,141710,141713,141713,141713,141715,141715,141716,141718,141719,141719,141725,141725,141731,141731,141732,141732,141746,141746,141746,141746,141748,141750,141751,141753,141753,141753,141754,141755,141758,141765,141765,141767,141768,141770,141771,141778,141778,141778,141778,141783,141783,141791,141793,141802,141804,141808,141821,141824,141824,141831,141831,141832,141837,141841,141841,141847,141848,141848,141852,141852,141853,141853,141856,141858,141860,141864,141865,141869,141869,141869,141873,141876,141876,141876,141876,141876,141876,141876,141876,141876,141877,141882,141883,141888,141889,141892,141892,141894,141906,141911,141911,141911,141912,141915,141924,141927,141930,141936,141937,141937,141937,141941,141942,141942,141942,141942,141942,141942,141942,141945,141950,141950,141950,141950,141950,141950,141950,141950,141950,141950,141950,141951,141951,141951,141951,141951,141951,141952,141952,141953,141953,141957,141965,141965,141968,141972,141976,141977,141979,141980,141982,141982,141982,141982,141983,141984,141985,141989,141989,141990,141990,141997,141997,141999,141999,142003,142004,142004,142011,142017,142020,142020,142020,142020,142021,142023,142023,142023,142024,142025,142025,142029,142030,142034,142035,142035,142040,142040,142046,142047,142052,142053,142073,142073,142073,142075,142079,142086,142086,142096,142096,142096,142099,142108,142114,142115,142120,142121,142121,142125,142125,142127,142129,142136,142136,142136,142136,142136,142139,142141,142143,142143,142143,142143,142143,142143,142148,142149,142149,142149,142150,142150,142151,142151,142152,142152,142157,142159,142161,142161,142161,142163,142163,142171,142176,142176,142176,142177,142177,142187,142188,142188,142192,142192,142192,142192,142197,142203,142204,142205,142205,142205,142211,142211,142211,142217,142223,142232,142234,142234,142234,142234,142234,142245,142246,142249,142251,142254,142257,142257,142257,142257,142257,142260,142260,142260,142260,142260,142265,142270,142271,142272,142273,142273,142282,142295,142300,142300,142306,142306,142309,142310,142310,142344,142351,142353,142355,142360,142370,142371,142374,142376,142379,142379,142379,142379,142379,142379,142379,142379,142379,142379,142379,142380,142381,142386,142387,142387,142387,142390,142393,142394,142394,142395,142396,142397,142407,142410,142412,142412,142412,142412,142413,142416,142416,142419,142419,142422,142428,142432,142432,142435,142445,142449,142454,142454,142456,142456,142456,142456,142461,142468,142476,142478,142480,142482,142483,142483,142483,142484,142485,142489,142489,142490,142491,142493,142495,142498,142506,142515,142518,142523,142524,142524,142524,142524,142524,142524,142524,142527,142529,142531,142531,142532,142542,142544,142544,142544,142544,142544,142544,142545,142545,142545,142545,142545,142545,142546,142546,142546,142546,142546,142546,142547,142547,142547,142547,142547,142548,142548,142548,142549,142549,142549,142550,142550,142550,142550,142554,142555,142555,142555,142555,142555,142555,142555,142555,142555,142555,142555,142555,142555,142556,142556,142556,142556,142557,142557,142557,142560,142566,142568,142576,142577,142578,142593,142598,142598,142603,142606,142614,142614,142615,142617,142618,142619,142632,142634,142634,142634,142634,142636,142637,142637,142638,142638,142638,142638,142638,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142639,142640,142641,142641,142649,142651,142653,142653,142654,142654,142654,142661,142661,142662,142664,142665,142670,142670,142670,142670,142671,142673,142673,142673,142674,142674,142677,142679,142680,142680,142680,142680,142680,142680,142681,142681,142682,142683,142683,142683,142683,142684,142689,142689,142689,142689,142689,142691,142692,142692,142692,142692,142692,142695,142695,142695,142695,142696,142696,142696,142696,142696,142697,142697,142699,142699,142699,142699,142700,142701,142701,142702,142702,142702,142702,142703,142703,142703,142703,142703,142704,142704,142704,142704,142704,142704,142704,142705,142705,142705,142705,142707,142707,142707,142707,142707,142707,142707,142707,142707,142707,142708,142708,142708,142708,142708,142708,142708,142709,142709,142709,142709,142710,142710,142711,142711,142711,142712,142713,142714,142714,142714,142714,142715,142715,142716,142717,142719,142719,142720,142720,142720,142720,142720,142723,142724,142726,142727,142727,142728,142735,142735,142741,142742,142742,142746,142746,142748,142748,142748,142750,142750,142750,142750,142750,142758,142761,142761,142762,142764,142767,142768,142769,142769,142769,142769,142771,142773,142775,142776,142776,142776,142776,142776,142776,142776,142776,142777,142778,142778,142784,142792,142793,142797,142806,142807,142808,142809,142818,142818,142818,142818,142820,142828,142828,142841,142844,142847,142847,142851,142852,142854,142858,142859,142862,142862,142867,142868,142876,142882,142882,142884,142885,142885,142887,142887,142888,142888,142890,142891,142891,142893,142894,142896,142896,142897,142897,142898,142899,142902,142902,142903,142904,142904,142904,142904,142905,142906,142907,142909,142910,142911,142911,142911,142917,142922,142923,142924,142929,142933,142937,142940,142940,142941,142946,142949,142950,142951,142959,142964,142968,142968,142969,142975,142986,142988,142989,142989,142989,142991,142995,143003,143003,143009,143020,143020,143021,143024,143025,143025,143026,143026,143029,143036,143036,143036,143036,143036,143036,143036,143036,143038,143038,143038,143039,143044,143044,143044,143046,143047,143051,143059,143060,143062,143065,143079,143079,143079,143082,143083,143084,143084,143084,143084,143087,143087,143087,143087,143088,143090,143093,143094,143098,143100,143100,143102,143102,143103,143107,143107,143108,143111,143111,143111,143112,143112,143114,143114,143118,143118,143118,143118,143118,143118,143118,143118,143118,143118,143118,143118,143120,143122,143122,143128,143134,143134,143137,143137,143137,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143139,143142,143148,143152,143157,143158,143161,143169,143176,143182,143184,143187,143195,143195,143198,143198,143200,143214,143218,143218,143220,143223,143223,143223,143225,143225,143227,143232,143233,143235,143236,143236,143238,143246,143248,143248,143248,143250,143250,143250,143254,143257,143257,143257,143262,143268,143268,143268,143268,143268,143269,143276,143282,143288,143293,143294,143294,143297,143298,143298,143300,143300,143300,143306,143307,143308,143319,143321,143322,143322,143333,143337,143337,143338,143338,143339,143346,143347,143347,143348,143348,143348,143348,143353,143353,143353,143354,143355,143357,143359,143366,143374,143374,143374,143375,143378,143381,143381,143381,143381,143381,143381,143382,143382,143382,143382,143387,143387,143387,143387,143389,143389,143396,143398,143405,143407,143408,143410,143411,143411,143411,143416,143420,143425,143425,143431,143435,143441,143441,143443,143443,143444,143444,143445,143445,143445,143445,143447,143448,143448,143448,143448,143449,143449,143449,143450,143450,143451,143451,143451,143452,143453,143453,143466,143472,143479,143479,143480,143482,143483,143485,143494,143495,143495,143495,143502,143502,143502,143502,143502,143502,143502,143502,143502,143502,143502,143502,143502,143502,143503,143503,143507,143507,143510,143510,143510,143510,143510,143513,143513,143516,143518,143519,143521,143523,143523,143524,143524,143524,143524,143525,143532,143536,143541,143541,143542,143542,143542,143549,143551,143554,143554,143554,143556,143563,143564,143567,143571,143574,143578,143580,143583,143584,143584,143586,143586,143586,143586,143588,143590,143598,143610,143611,143611,143613,143617,143620,143621,143623,143623,143624,143624,143624,143624,143624,143625,143625,143630,143640,143643,143643,143643,143643,143643,143645,143645,143645,143646,143646,143647,143647,143653,143653,143659,143665,143668,143668,143670,143670,143670,143677,143678,143679,143681,143683,143701,143704,143704,143706,143709,143718,143718,143718,143718,143718,143718,143718,143718,143718,143718,143718,143718,143725,143725,143725,143725,143725,143725,143742,143749,143753,143753,143753,143755,143758,143763,143767,143770,143772,143774,143776,143778,143779,143780,143780,143784,143793,143793,143793,143794,143794,143796,143801,143804,143804,143805,143805,143806,143809,143809,143809,143809,143810,143810,143810,143810,143810,143810,143811,143811,143812,143812,143814,143814,143815,143815,143815,143815,143815,143818,143818,143818,143818,143821,143821,143821,143827,143827,143827,143832,143836,143836,143836,143847,143855,143857,143857,143857,143857,143861,143877,143881,143883,143887,143889,143889,143891,143891,143891,143891,143891,143894,143901,143901,143901,143901,143901,143901,143901,143901,143901,143901,143901,143904,143904,143904,143904,143904,143905,143906,143906,143907,143907,143907,143909,143910,143911,143911,143917,143917,143921,143921,143921,143921,143933,143933,143936,143939,143940,143940,143940,143940,143945,143945,143945,143947,143947,143947,143947,143947,143947,143949,143950,143951,143955,143955,143955,143955,143955,143955,143955,143955,143955,143955,143955,143955,143955,143955,143956,143956,143963,143968,143968,143971,143972,143984,143984,143987,143987,143988,143988,143988,143988,143989,143989,143990,143992,143992,143993,143995,144001,144004,144004,144005,144012,144013,144013,144013,144013,144015,144019,144020,144020,144023,144024,144025,144025,144028,144029,144029,144034,144040,144040,144040,144040,144048,144053,144055,144056,144056,144063,144065,144067,144071,144071,144071,144071,144071,144071,144071,144072,144073,144073,144073,144073,144079,144082,144082,144088,144092,144098,144101,144104,144105,144105,144105,144105,144105,144105,144105,144105,144110,144111,144111,144111,144113,144115,144115,144115,144118,144118,144121,144121,144122,144126,144126,144126,144126,144126,144129,144129,144129,144129,144129,144129,144131,144135,144135,144135,144135,144136,144136,144136,144136,144137,144137,144137,144137,144137,144145,144145,144145,144145,144145,144148,144151,144151,144151,144151,144151,144151,144151,144154,144154,144154,144154,144159,144159,144159,144159,144159,144159,144159,144159,144159,144159,144159,144159,144159,144159,144160,144160,144160,144166,144166,144167,144167,144167,144167,144167,144167,144167,144167,144168,144170,144174,144175,144179,144179,144179,144181,144182,144188,144189,144191,144194,144194,144194,144195,144195,144197,144199,144199,144199,144199,144202,144202,144202,144207,144210,144210,144210,144211,144225,144226,144226,144227,144230,144230,144230,144231,144234,144237,144237,144239,144239,144240,144243,144246,144246,144246,144248,144248,144248,144248,144249,144249,144250,144251,144253,144258,144258,144259,144259,144259,144259,144259,144259,144259,144259,144259,144261,144261,144266,144266,144266,144267,144272,144278,144278,144284,144286,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144290,144291,144296,144301,144304,144304,144305,144305,144306,144306,144306,144309,144309,144309,144311,144314,144314,144314,144315,144319,144323,144323,144323,144324,144325,144328,144328,144328,144328,144328,144329,144329,144334,144335,144335,144335,144341,144343,144346,144347,144349,144351,144351,144351,144351,144352,144352,144352,144352,144352,144354,144362,144362,144362,144367,144367,144367,144369,144370,144380,144381,144381,144381,144381,144385,144387,144390,144391,144392,144392,144394,144394,144395,144395,144395,144395,144396,144396,144398,144398,144398,144398,144399,144399,144399,144403,144406,144406,144406,144406,144406,144406,144407,144407,144407,144408,144408,144409,144411,144414,144415,144415,144415,144415,144416,144416,144419,144419,144419,144422,144422,144423,144423,144423,144426,144428,144428,144428,144428,144437,144437,144437,144437,144437,144441,144442,144445,144447,144447,144447,144447,144448,144448,144448,144448,144448,144448,144448,144448,144448,144450,144450,144450,144451,144453,144453,144454,144456,144459,144459,144461,144463,144466,144466,144466,144466,144466,144466,144466,144467,144471,144472,144472,144472,144472,144475,144477,144481,144494,144494,144499,144501,144501,144506,144506,144507,144510,144514,144517,144519,144520,144520,144520,144524,144527,144527,144529,144530,144530,144531,144531,144531,144533,144545,144545,144550,144550,144550,144551,144553,144553,144553,144553,144558,144559,144559,144560,144563,144565,144565,144565,144565,144565,144565,144565,144571,144575,144578,144583,144585,144587,144587,144592,144592,144595,144595,144595,144604,144604,144604,144612,144613,144613,144613,144613,144613,144613,144615,144618,144619,144619,144621,144621,144622,144623,144628,144630,144635,144639,144643,144647,144647,144648,144648,144651,144656,144656,144658,144660,144662,144668,144672,144674,144674,144674,144680,144681,144684,144692,144692,144692,144692,144692,144692,144692,144692,144692,144692,144692,144692,144693,144693,144697,144697,144697,144697,144697,144697,144697,144697,144697,144697,144701,144701,144701,144706,144707,144707,144707,144707,144712,144713,144713,144713,144713,144714,144714,144714,144714,144714,144714,144714,144715,144715,144717,144721,144727,144727,144735,144736,144736,144737,144741,144744,144745,144748,144749,144749,144754,144754,144754,144755,144758,144760,144760,144760,144761,144762,144765,144771,144776,144782,144782,144784,144785,144785,144789,144790,144793,144801,144812,144812,144812,144812,144812,144814,144816,144817,144819,144828,144832,144836,144838,144844,144847,144852,144852,144858,144858,144858,144858,144862,144862,144865,144865,144866,144867,144872,144873,144874,144876,144876,144879,144879,144879,144879,144879,144879,144882,144885,144885,144889,144898,144898,144901,144901,144901,144901,144902,144912,144918,144918,144919,144919,144919,144919,144926,144926,144926,144930,144930,144930,144931,144932,144943,144946,144950,144952,144965,144966,144970,144970,144972,144979,144979,144982,144992,144993,144993,145008,145009,145019,145023,145030,145032,145034,145034,145034,145034,145035,145037,145037,145039,145048,145051,145052,145054,145054,145054,145058,145067,145076,145077,145080,145081,145087,145089,145089,145089,145092,145092,145092,145094,145099,145100,145100,145100,145100,145100,145100,145100,145100,145102,145102,145103,145109,145116,145123,145124,145124,145129,145129,145130,145130,145130,145131,145133,145133,145133,145136,145139,145139,145143,145145,145155,145167,145167,145167,145168,145170,145172,145176,145176,145184,145193,145202,145205,145207,145208,145215,145222,145222,145222,145222,145222,145222,145222,145222,145224,145224,145237,145247,145247,145247,145247,145247,145252,145257,145257,145258,145260,145260,145260,145260,145260,145260,145260,145260,145263,145263,145263,145266,145273,145273,145276,145276,145276,145287,145288,145290,145292,145299,145299,145299,145299,145302,145302,145302,145302,145302,145303,145303,145305,145313,145326,145332,145338,145340,145340,145347,145347,145347,145354,145361,145361,145364,145364,145366,145369,145370,145373,145374,145374,145383,145386,145386,145386,145387,145388,145388,145388,145389,145389,145389,145390,145390,145391,145393,145395,145396,145396,145397,145404,145405,145405,145410,145410,145412,145412,145418,145418,145422,145424,145424,145424,145424,145425,145426,145426,145426,145426,145426,145427,145428,145429,145430,145430,145430,145430,145431,145431,145431,145431,145431,145431,145432,145432,145432,145433,145433,145436,145438,145440,145440,145441,145442,145442,145446,145446,145446,145447,145450,145450,145450,145455,145459,145466,145469,145469,145469,145471,145471,145471,145471,145471,145471,145473,145480,145480,145488,145489,145492,145492,145492,145499,145499,145499,145499,145499,145499,145499,145500,145500,145500,145500,145501,145502,145502,145502,145502,145505,145507,145507,145509,145512,145513,145517,145518,145518,145518,145519,145519,145519,145520,145524,145535,145535,145535,145536,145537,145539,145540,145540,145540,145540,145540,145540,145540,145542,145544,145544,145544,145547,145547,145547,145552,145552,145552,145553,145553,145553,145553,145555,145555,145555,145555,145555,145556,145556,145556,145556,145556,145556,145557,145559,145563,145565,145565,145568,145568,145568,145572,145573,145574,145574,145574,145574,145574,145574,145575,145577,145581,145583,145584,145585,145585,145585,145585,145588,145590,145590,145590,145592,145598,145603,145604,145608,145611,145611,145614,145623,145623,145623,145623,145623,145623,145623,145624,145627,145627,145628,145629,145630,145632,145632,145632,145632,145632,145633,145634,145635,145635,145636,145638,145642,145642,145643,145643,145643,145648,145648,145651,145652,145652,145652,145663,145663,145663,145668,145670,145671,145673,145673,145673,145673,145675,145677,145686,145690,145690,145691,145693,145693,145707,145719,145726,145726,145726,145726,145727,145728,145728,145731,145732,145733,145733,145733,145733,145739,145740,145742,145744,145746,145746,145746,145746,145746,145749,145749,145749,145749,145749,145749,145749,145753,145756,145756,145760,145761,145763,145763,145763,145767,145767,145769,145773,145774,145776,145781,145786,145791,145795,145799,145810,145815,145817,145822,145823,145823,145823,145823,145826,145832,145841,145841,145845,145846,145851,145856,145859,145864,145864,145867,145870,145870,145872,145875,145875,145875,145875,145877,145877,145877,145882,145884,145885,145887,145895,145897,145899,145900,145900,145900,145900,145900,145900,145900,145902,145903,145903,145903,145906,145907,145909,145913,145913,145913,145913,145913,145913,145913,145913,145913,145913,145938,145938,145948,145953,145960,145970,145974,145974,145974,145975,145976,145983,145983,145983,145985,145986,145988,145990,145994,146006,146009,146009,146015,146015,146019,146023,146023,146024,146030,146030,146030,146030,146030,146030,146031,146032,146034,146038,146044,146046,146046,146050,146050,146050,146051,146053,146054,146057,146057,146068,146073,146076,146082,146083,146083,146083,146086,146088,146088,146088,146088,146089,146089,146092,146098,146099,146099,146104,146105,146105,146110,146110,146112,146112,146113,146113,146113,146113,146115,146116,146117,146122,146131,146132,146135,146140,146140,146144,146144,146144,146144,146144,146146,146155,146159,146159,146159,146159,146161,146161,146161,146168,146174,146174,146175,146176,146179,146185,146185,146189,146201,146204,146207,146207,146207,146221,146224,146224,146225,146228,146228,146228,146228,146235,146237,146240,146241,146244,146246,146246,146246,146258,146260,146260,146260,146264,146264,146276,146276,146276,146276,146276,146277,146277,146277,146290,146293,146297,146297,146297,146297,146298,146299,146300,146300,146300,146300,146300,146308,146309,146309,146309,146309,146310,146312,146312,146312,146313,146317,146318,146318,146318,146319,146348,146350,146352,146371,146371,146371,146373,146373,146374,146376,146385,146388,146393,146393,146396,146397,146399,146414,146432,146434,146438,146441,146442,146446,146448,146448,146448,146448,146450,146450,146450,146450,146450,146450,146450,146453,146453,146455,146455,146457,146464,146464,146464,146464,146467,146467,146471,146472,146472,146480,146486,146487,146487,146489,146489,146490,146490,146499,146499,146499,146499,146499,146501,146502,146510,146519,146525,146525,146528,146529,146529,146531,146532,146532,146534,146536,146536,146536,146536,146538,146546,146546,146546,146550,146553,146562,146562,146562,146562,146568,146568,146568,146568,146568,146568,146568,146572,146572,146579,146581,146582,146582,146582,146582,146582,146584,146592,146600,146600,146600,146601,146617,146620,146621,146621,146621,146622,146622,146622,146622,146628,146628,146628,146631,146638,146646,146647,146647,146647,146647,146647,146647,146647,146648,146654,146656,146660,146660,146660,146660,146660,146660,146660,146660,146660,146660,146661,146662,146662,146662,146662,146664,146665,146671,146680,146682,146683,146683,146691,146692,146694,146697,146702,146703,146705,146707,146716,146717,146720,146721,146721,146722,146726,146727,146727,146727,146730,146730,146730,146730,146732,146732,146733,146737,146740,146746,146758,146774,146775,146782,146784,146784,146785,146785,146785,146785,146785,146785,146786,146786,146786,146786,146786,146786,146788,146800,146808,146808,146808,146814,146814,146814,146814,146814,146814,146814,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146820,146823,146828,146830,146833,146833,146833,146833,146833,146833,146833,146833,146833,146838,146838,146838,146838,146840,146840,146841,146841,146847,146847,146847,146850,146852,146859,146864,146865,146872,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146876,146878,146878,146880,146883,146883,146889,146889,146893,146896,146896,146897,146900,146900,146900,146901,146901,146901,146901,146903,146904,146905,146905,146906,146906,146906,146907,146907,146907,146907,146907,146907,146907,146907,146907,146908,146909,146909,146909,146909,146911,146911,146911,146911,146912,146912,146912,146913,146914,146916,146921,146921,146922,146922,146924,146924,146925,146925,146925,146925,146925,146926,146926,146930,146931,146931,146933,146935,146935,146937,146938,146940,146940,146940,146942,146946,146946,146946,146949,146950,146953,146959,146959,146959,146959,146959,146959,146959,146960,146967,146967,146967,146969,146979,146979,146980,146984,146985,146987,146987,146990,146991,146993,146993,146998,146999,146999,147002,147002,147004,147014,147015,147019,147019,147021,147024,147024,147026,147026,147027,147027,147027,147027,147031,147036,147038,147038,147040,147040,147042,147042,147042,147052,147052,147060,147060,147066,147070,147073,147075,147075,147077,147084,147084,147084,147084,147084,147084,147084,147085,147086,147089,147089,147104,147107,147110,147118,147119,147122,147123,147126,147128,147129,147129,147129,147130,147130,147133,147135,147135,147137,147141,147142,147148,147151,147161,147180,147180,147180,147180,147183,147184,147191,147191,147192,147206,147208,147214,147214,147218,147219,147219,147224,147238,147238,147242,147245,147246,147249,147249,147249,147254,147255,147255,147255,147255,147255,147259,147269,147269,147271,147271,147275,147281,147281,147282,147287,147287,147293,147293,147296,147296,147301,147305,147305,147311,147311,147313,147315,147319,147321,147327,147368,147368,147368,147368,147368,147368,147368,147371,147372,147372,147390,147391,147398,147398,147401,147402,147403,147413,147413,147413,147413,147413,147413,147418,147421,147426,147427,147429,147430,147431,147437,147437,147445,147447,147447,147455,147463,147463,147463,147478,147478,147478,147478,147478,147478,147478,147478,147484,147484,147485,147485,147485,147487,147492,147492,147492,147492,147494,147502,147504,147514,147525,147527,147531,147536,147536,147537,147537,147543,147543,147543,147550,147556,147558,147561,147561,147562,147562,147569,147569,147570,147578,147580,147582,147587,147607,147625,147625,147625,147625,147625,147625,147625,147625,147639,147641,147643,147646,147646,147649,147651,147651,147653,147657,147661,147663,147663,147663,147666,147669,147669,147674,147674,147683,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147684,147686,147686,147686,147687,147689,147689,147690,147690,147690,147691,147693,147695,147696,147698,147698,147698,147698,147698,147698,147699,147702,147702,147706,147706,147706,147706,147706,147706,147706,147706,147706,147706,147706,147706,147706,147708,147709,147709,147709,147709,147709,147709,147709,147709,147709,147709,147709,147709,147710,147711,147711,147712,147712,147712,147713,147713,147713,147713,147714,147714,147714,147714,147714,147714,147714,147715,147718,147719,147719,147720,147730,147732,147732,147737,147739,147741,147742,147742,147743,147743,147754,147755,147755,147756,147756,147756,147759,147759,147761,147762,147762,147765,147765,147768,147769,147770,147771,147773,147778,147779,147779,147779,147779,147780,147780,147780,147780,147780,147780,147781,147781,147782,147783,147784,147786,147786,147791,147791,147794,147794,147794,147794,147794,147795,147795,147797,147798,147798,147798,147798,147798,147798,147799,147799,147799,147799,147802,147802,147802,147802,147802,147802,147802,147802,147803,147803,147803,147804,147804,147815,147817,147817,147820,147820,147822,147824,147825,147825,147825,147825,147827,147829,147831,147833,147833,147837,147837,147843,147843,147846,147850,147850,147851,147852,147852,147852,147852,147852,147853,147853,147853,147853,147853,147853,147855,147855,147858,147860,147860,147862,147862,147867,147868,147871,147872,147880,147881,147884,147884,147884,147884,147884,147888,147888,147888,147888,147889,147890,147890,147891,147891,147891,147892,147894,147894,147894,147901,147901,147901,147901,147901,147902,147906,147907,147909,147910,147911,147913,147913,147916,147920,147920,147922,147924,147927,147928,147928,147930,147931,147931,147931,147931,147935,147936,147937,147938,147938,147938,147938,147949,147950,147950,147950,147955,147958,147960,147969,147969,147975,147975,147976,147978,147979,147984,147985,147985,147985,147988,147988,147988,147988,147992,147995,147995,147998,147998,148000,148002,148002,148002,148002,148002,148002,148005,148007,148007,148008,148009,148010,148010,148010,148010,148013,148013,148014,148015,148015,148015,148019,148019,148020,148020,148020,148020,148020,148020,148020,148025,148032,148032,148032,148034,148035,148038,148039,148043,148045,148045,148045,148046,148047,148053,148058,148070,148070,148070,148070,148070,148070,148072,148072,148076,148080,148082,148082,148086,148086,148087,148087,148088,148088,148089,148089,148089,148093,148094,148100,148100,148104,148104,148104,148107,148109,148120,148122,148123,148128,148143,148145,148145,148147,148148,148149,148149,148151,148151,148152,148154,148161,148162,148169,148169,148170,148170,148177,148181,148183,148183,148183,148183,148185,148189,148189,148197,148201,148201,148206,148209,148209,148209,148209,148209,148210,148211,148211,148212,148214,148214,148215,148216,148216,148216,148217,148218,148220,148221,148228,148228,148228,148228,148231,148231,148234,148234,148236,148237,148237,148237,148240,148248,148252,148252,148258,148261,148262,148262,148262,148264,148264,148264,148264,148265,148266,148267,148268,148273,148273,148273,148274,148276,148278,148279,148279,148283,148289,148292,148299,148299,148306,148306,148306,148306,148308,148309,148310,148311,148316,148318,148321,148327,148331,148331,148336,148338,148338,148338,148338,148339,148341,148341,148343,148354,148357,148359,148359,148375,148381,148386,148388,148388,148388,148389,148390,148390,148396,148401,148401,148401,148401,148402,148403,148403,148403,148403,148403,148404,148408,148411,148411,148411,148411,148411,148412,148415,148417,148418,148419,148437,148438,148438,148443,148443,148443,148447,148450,148450,148450,148459,148460,148460,148460,148469,148471,148473,148477,148477,148477,148477,148477,148477,148480,148480,148480,148482,148482,148482,148487,148487,148487,148487,148492,148497,148502,148506,148508,148508,148516,148516,148516,148516,148516,148516,148518,148518,148519,148527,148531,148531,148531,148554,148558,148569,148574,148592,148594,148612,148613,148616,148621,148624,148634,148636,148637,148645,148652,148656,148657,148660,148661,148670,148670,148670,148671,148674,148675,148676,148677,148680,148681,148683,148686,148690,148690,148705,148710,148717,148720,148721,148721,148725,148733,148733,148733,148738,148738,148738,148738,148738,148738,148738,148738,148738,148738,148742,148745,148756,148756,148756,148759,148759,148759,148762,148767,148767,148767,148768,148768,148768,148768,148771,148775,148778,148783,148787,148790,148801,148803,148813,148815,148817,148819,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148823,148825,148828,148830,148830,148830,148835,148851,148852,148858,148858,148862,148862,148862,148864,148866,148866,148866,148866,148866,148866,148866,148872,148874,148875,148875,148878,148879,148879,148879,148879,148885,148886,148887,148894,148894,148894,148897,148898,148898,148898,148898,148898,148898,148899,148899,148904,148906,148906,148906,148906,148906,148906,148907,148907,148912,148913,148914,148922,148922,148922,148923,148927,148927,148927,148928,148928,148928,148928,148928,148929,148929,148929,148929,148929,148930,148930,148930,148930,148930,148930,148931,148932,148932,148933,148933,148933,148933,148933,148936,148943,148948,148949,148949,148949,148951,148951,148951,148951,148952,148956,148956,148960,148960,148961,148963,148964,148964,148966,148966,148966,148966,148967,148969,148975,148976,148980,148980,148981,148984,148987,148994,148996,148997,149002,149002,149002,149003,149007,149010,149010,149011,149012,149012,149012,149015,149015,149018,149018,149019,149019,149019,149019,149019,149020,149020,149021,149023,149024,149028,149029,149029,149030,149030,149038,149038,149040,149040,149040,149041,149044,149044,149046,149046,149046,149047,149047,149049,149049,149049,149049,149051,149051,149051,149051,149051,149051,149052,149055,149059,149059,149059,149059,149063,149066,149066,149074,149075,149076,149078,149080,149080,149080,149082,149082,149083,149083,149083,149087,149087,149090,149091,149093,149099,149099,149099,149100,149101,149105,149107,149107,149108,149108,149108,149110,149110,149112,149116,149117,149117,149117,149117,149119,149122,149122,149123,149123,149126,149129,149130,149130,149133,149133,149135,149137,149139,149139,149145,149149,149155,149155,149159,149162,149162,149162,149166,149176,149184,149186,149197,149197,149197,149197,149215,149219,149219,149229,149229,149229,149230,149230,149230,149236,149238,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149239,149240,149240,149240,149240,149240,149243,149244,149247,149249,149249,149260,149269,149274,149275,149277,149279,149283,149285,149286,149289,149290,149291,149296,149299,149299,149299,149304,149312,149323,149326,149327,149327,149327,149327,149327,149328,149328,149329,149329,149332,149332,149333,149338,149338,149338,149338,149341,149344,149344,149349,149353,149353,149355,149359,149362,149362,149369,149380,149381,149381,149383,149386,149386,149386,149387,149388,149391,149391,149391,149391,149391,149391,149391,149391,149391,149397,149398,149404,149404,149406,149407,149407,149407,149407,149411,149411,149411,149411,149411,149411,149411,149422,149422,149422,149422,149424,149424,149424,149424,149424,149429,149436,149448,149450,149450,149463,149464,149465,149465,149465,149465,149466,149468,149468,149470,149470,149470,149471,149481,149489,149495,149511,149511,149511,149511,149521,149526,149527,149528,149528,149528,149529,149529,149529,149529,149529,149529,149529,149531,149531,149532,149535,149542,149542,149542,149542,149542,149542,149542,149542,149542,149542,149542,149542,149542,149542,149542,149542,149543,149543,149543,149546,149547,149548,149559,149561,149565,149575,149576,149581,149583,149586,149588,149594,149595,149597,149603,149603,149603,149609,149609,149609,149609,149609,149611,149612,149614,149615,149623,149624,149627,149630,149633,149635,149636,149638,149638,149640,149640,149641,149643,149644,149647,149648,149648,149650,149654,149654,149654,149657,149660,149661,149661,149662,149662,149663,149671,149674,149674,149674,149674,149691,149704,149717,149717,149719,149720,149721,149723,149723,149724,149725,149726,149726,149726,149729,149730,149731,149738,149738,149740,149740,149740,149741,149741,149742,149742,149742,149742,149743,149743,149743,149744,149745,149752,149752,149752,149757,149758,149764,149765,149765,149766,149768,149770,149777,149779,149780,149782,149782,149782,149790,149791,149791,149791,149793,149795,149795,149795,149795,149795,149796,149803,149803,149807,149811,149813,149819,149821,149824,149828,149829,149831,149833,149835,149837,149838,149842,149843,149844,149845,149848,149853,149855,149856,149857,149861,149863,149864,149864,149864,149870,149882,149882,149882,149882,149882,149882,149882,149882,149882,149882,149882,149882,149882,149896,149899,149901,149901,149904,149907,149907,149907,149907,149907,149907,149915,149915,149915,149916,149920,149921,149921,149921,149926,149933,149936,149942,149946,149961,149972,149974,149977,149979,149979,149980,149980,149980,149982,149983,149987,149989,149989,149997,149997,150001,150001,150001,150001,150004,150019,150022,150029,150030,150033,150033,150033,150034,150043,150045,150045,150046,150046,150046,150046,150046,150046,150046,150046,150046,150046,150046,150046,150046,150046,150053,150053,150060,150060,150060,150060,150060,150060,150060,150060,150068,150068,150068,150072,150082,150082,150082,150082,150082,150096,150096,150104,150109,150111,150125,150131,150134,150135,150135,150138,150138,150138,150138,150138,150139,150139,150140,150143,150145,150148,150148,150150,150151,150151,150159,150166,150166,150166,150166,150173,150176,150184,150186,150186,150186,150193,150196,150198,150199,150199,150199,150201,150208,150208,150208,150209,150212,150212,150214,150214,150220,150221,150228,150229,150229,150234,150235,150238,150256,150257,150258,150263,150266,150268,150269,150269,150275,150301,150307,150311,150318,150324,150327,150332,150348,150348,150348,150349,150349,150349,150353,150353,150361,150368,150368,150371,150375,150391,150392,150409,150414,150415,150415,150415,150415,150415,150415,150415,150417,150421,150422,150422,150422,150428,150428,150428,150430,150430,150433,150433,150433,150433,150434,150438,150439,150441,150443,150443,150446,150446,150449,150452,150475,150477,150477,150477,150480,150480,150480,150481,150492,150505,150506,150506,150514,150517,150517,150517,150518,150522,150522,150523,150523,150523,150523,150523,150523,150523,150523,150528,150533,150536,150536,150539,150539,150543,150547,150550,150553,150555,150555,150556,150557,150566,150566,150567,150572,150576,150576,150576,150576,150578,150579,150579,150580,150580,150580,150580,150580,150582,150587,150587,150590,150590,150590,150590,150590,150590,150590,150590,150591,150591,150594,150597,150600,150600,150600,150600,150600,150601,150601,150601,150604,150607,150609,150611,150612,150614,150614,150616,150616,150618,150618,150618,150620,150620,150629,150632,150634,150637,150647,150647,150647,150652,150656,150666,150668,150675,150675,150680,150680,150680,150681,150681,150681,150681,150684,150714,150732,150732,150732,150732,150732,150732,150732,150732,150732,150732,150732,150732,150734,150734,150734,150734,150734,150739,150742,150743,150743,150746,150751,150752,150754,150754,150754,150762,150766,150773,150773,150775,150775,150787,150795,150795,150795,150800,150800,150800,150808,150808,150808,150808,150809,150811,150811,150814,150814,150815,150816,150818,150818,150823,150824,150825,150825,150825,150825,150825,150831,150831,150831,150831,150831,150831,150833,150839,150845,150851,150852,150854,150858,150859,150861,150861,150861,150867,150867,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150868,150870,150875,150876,150884,150889,150889,150889,150893,150893,150898,150898,150899,150901,150901,150901,150906,150907,150907,150907,150907,150907,150907,150911,150916,150929,150929,150930,150931,150931,150931,150931,150931,150931,150931,150931,150931,150931,150931,150931,150931,150931,150931,150937,150938,150938,150948,150948,150948,150948,150948,150948,150948,150950,150950,150954,150955,150958,150958,150958,150962,150962,150962,150965,150967,150967,150969,150969,150972,150972,150973,150973,150973,150973,150973,150976,150978,150980,150980,150981,150981,150981,150983,150993,151004,151005,151005,151005,151005,151005,151005,151005,151013,151013,151013,151017,151021,151032,151032,151033,151044,151071,151077,151079,151079,151079,151079,151079,151079,151079,151079,151079,151079,151079,151082,151082,151082,151082,151082,151082,151082,151082,151082,151082,151088,151093,151096,151112,151113,151120,151120,151120,151120,151120,151120,151120,151120,151120,151120,151120,151120,151120,151120,151120,151121,151125,151139,151148,151148,151148,151151,151152,151153,151154,151173,151173,151173,151179,151180,151180,151185,151186,151187,151194,151198,151198,151204,151227,151229,151240,151252,151266,151266,151266,151266,151266,151266,151266,151266,151266,151296,151309,151314,151314,151314,151317,151318,151318,151318,151321,151322,151322,151330,151330,151330,151330,151335,151343,151354,151356,151358,151366,151366,151367,151367,151369,151369,151373,151377,151387,151389,151390,151390,151390,151390,151390,151391,151395,151395,151395,151396,151396,151410,151418,151421,151428,151433,151434,151434,151434,151434,151434,151434,151438,151445,151449,151454,151456,151459,151462,151462,151463,151464,151477,151477,151479,151485,151496,151498,151498,151500,151502,151506,151515,151515,151516,151529,151529,151529,151529,151529,151529,151532,151532,151532,151533,151533,151533,151534,151534,151534,151534,151534,151534,151535,151536,151536,151536,151537,151537,151537,151537,151537,151537,151537,151537,151537,151538,151538,151539,151539,151540,151540,151543,151543,151546,151549,151553,151554,151556,151556,151557,151557,151561,151563,151566,151568,151568,151568,151569,151571,151574,151578,151578,151578,151581,151581,151581,151582,151584,151584,151584,151584,151585,151585,151585,151586,151588,151596,151597,151597,151597,151597,151597,151598,151598,151598,151598,151598,151598,151604,151607,151609,151615,151615,151616,151618,151619,151620,151620,151620,151622,151631,151632,151632,151633,151634,151634,151634,151635,151641,151641,151641,151642,151643,151643,151643,151643,151644,151644,151644,151647,151652,151658,151660,151660,151660,151660,151663,151664,151665,151667,151668,151669,151669,151670,151670,151670,151672,151672,151672,151672,151672,151672,151672,151672,151672,151680,151680,151681,151681,151682,151682,151682,151682,151682,151682,151684,151685,151685,151686,151691,151691,151691,151693,151693,151693,151693,151693,151693,151693,151694,151694,151697,151697,151698,151703,151705,151710,151712,151712,151713,151714,151719,151720,151720,151722,151722,151722,151722,151723,151731,151735,151735,151736,151736,151737,151738,151742,151742,151742,151745,151745,151748,151749,151750,151750,151754,151756,151760,151760,151760,151760,151761,151761,151761,151764,151765,151766,151771,151772,151773,151773,151774,151774,151774,151776,151776,151786,151787,151787,151796,151796,151796,151796,151796,151796,151796,151802,151802,151805,151807,151807,151810,151820,151820,151822,151822,151822,151829,151845,151857,151881,151881,151881,151883,151883,151883,151883,151885,151885,151885,151885,151885,151885,151885,151886,151886,151886,151887,151893,151897,151897,151897,151897,151905,151908,151911,151911,151917,151925,151925,151930,151936,151938,151938,151938,151940,151942,151942,151942,151943,151943,151943,151943,151944,151946,151947,151947,151949,151954,151957,151958,151961,151963,151964,151964,151965,151965,151965,151967,151967,151969,151977,151979,151980,151980,151981,151983,151984,151984,151985,151985,151985,151985,151985,151989,151990,151990,151991,151993,151995,151997,151998,152000,152008,152008,152017,152019,152019,152021,152026,152026,152026,152027,152029,152030,152030,152031,152031,152032,152038,152038,152039,152041,152041,152048,152054,152060,152066,152080,152081,152084,152085,152091,152093,152101,152106,152106,152106,152111,152115,152116,152117,152118,152118,152135,152135,152135,152136,152137,152138,152140,152140,152145,152153,152156,152156,152156,152160,152161,152161,152161,152166,152167,152167,152168,152168,152170,152172,152173,152173,152176,152176,152176,152176,152177,152188,152191,152193,152194,152194,152200,152201,152201,152202,152202,152205,152205,152205,152205,152205,152205,152205,152205,152205,152205,152205,152205,152205,152205,152210,152210,152213,152213,152225,152226,152227,152227,152232,152233,152234,152234,152241,152242,152246,152247,152247,152247,152247,152247,152247,152250,152253,152255,152262,152263,152266,152266,152266,152268,152270,152272,152274,152274,152277,152278,152278,152279,152283,152283,152284,152285,152285,152285,152286,152287,152288,152291,152293,152293,152293,152295,152301,152301,152304,152310,152310,152313,152313,152314,152321,152321,152321,152321,152322,152325,152327,152330,152335,152338,152342,152347,152347,152347,152354,152354,152354,152354,152355,152355,152355,152360,152362,152364,152375,152376,152380,152380,152383,152387,152389,152395,152397,152398,152398,152407,152412,152414,152419,152419,152419,152419,152421,152421,152421,152424,152426,152434,152434,152437,152438,152444,152450,152451,152452,152461,152461,152474,152476,152482,152483,152486,152486,152488,152495,152495,152497,152498,152511,152518,152520,152521,152533,152537,152538,152538,152539,152546,152546,152549,152556,152558,152560,152566,152567,152575,152575,152575,152575,152576,152578,152579,152580,152583,152583,152590,152590,152597,152597,152601,152615,152622,152646,152646,152651,152651,152662,152666,152670,152675,152678,152685,152686,152692,152692,152692,152701,152702,152709,152709,152711,152711,152711,152713,152714,152714,152714,152714,152717,152718,152725,152729,152730,152730,152733,152734,152736,152737,152745,152745,152745,152745,152747,152747,152750,152757,152757,152757,152757,152757,152757,152758,152759,152759,152760,152766,152767,152770,152771,152774,152784,152785,152790,152790,152791,152797,152807,152807,152831,152831,152836,152867,152868,152870,152870,152870,152870,152870,152871,152877,152884,152884,152885,152894,152899,152899,152900,152900,152900,152900,152900,152900,152900,152912,152912,152912,152912,152912,152912,152912,152912,152913,152913,152913,152920,152924,152924,152924,152924,152927,152927,152927,152940,152945,152945,152946,152947,152947,152949,152950,152950,152962,152971,152981,152982,152985,152985,152987,152989,152993,153006,153013,153029,153031,153031,153038,153039,153045,153046,153046,153046,153047,153047,153047,153049,153052,153062,153062,153063,153080,153080,153080,153080,153080,153082,153083,153083,153083,153083,153089,153093,153097,153097,153098,153098,153098,153098,153098,153098,153098,153098,153099,153101,153101,153105,153105,153119,153120,153121,153122,153122,153127,153128,153128,153131,153134,153136,153141,153141,153141,153141,153143,153149,153149,153149,153149,153150,153150,153154,153154,153158,153158,153158,153158,153162,153165,153166,153166,153166,153170,153172,153177,153184,153197,153199,153203,153203,153204,153208,153208,153208,153208,153219,153223,153225,153225,153225,153225,153225,153225,153225,153225,153225,153225,153227,153232,153232,153234,153236,153241,153249,153256,153256,153270,153277,153287,153290,153294,153305,153307,153312,153322,153326,153341,153342,153348,153350,153351,153351,153352,153364,153364,153364,153366,153366,153366,153366,153366,153366,153366,153366,153369,153380,153380,153399,153405,153406,153406,153412,153412,153421,153423,153431,153432,153439,153442,153442,153442,153444,153445,153445,153445,153445,153445,153445,153445,153451,153453,153460,153467,153467,153475,153475,153475,153476,153476,153479,153482,153485,153486,153486,153492,153492,153496,153496,153502,153505,153505,153507,153507,153522,153528,153533,153539,153540,153541,153545,153546,153548,153548,153561,153564,153564,153564,153565,153567,153567,153572,153577,153577,153577,153579,153582,153588,153592,153598,153611,153619,153623,153623,153625,153625,153630,153630,153634,153636,153636,153640,153640,153641,153651,153659,153660,153666,153666,153666,153666,153666,153666,153666,153666,153673,153673,153673,153673,153673,153673,153675,153684,153685,153685,153688,153697,153706,153709,153709,153709,153710,153710,153710,153710,153711,153714,153722,153722,153722,153727,153736,153757,153784,153785,153785,153785,153787,153793,153794,153798,153798,153798,153798,153798,153799,153802,153806,153807,153807,153817,153817,153818,153818,153825,153825,153829,153832,153835,153837,153842,153845,153845,153845,153852,153856,153857,153857,153857,153857,153866,153866,153866,153870,153871,153871,153871,153871,153874,153874,153874,153874,153874,153875,153877,153878,153883,153886,153887,153889,153893,153894,153894,153896,153897,153903,153904,153907,153915,153917,153920,153920,153923,153923,153929,153934,153935,153935,153937,153941,153943,153951,153951,153955,153961,153962,153962,153963,153963,153963,153963,153963,153963,153963,153963,153964,153966,153966,153967,153972,153976,153976,153976,153976,153993,153998,154005,154007,154020,154021,154021,154021,154021,154022,154022,154022,154022,154024,154025,154026,154030,154032,154033,154035,154035,154036,154036,154042,154042,154042,154055,154056,154057,154059,154065,154069,154069,154069,154073,154078,154079,154084,154086,154086,154096,154096,154096,154099,154099,154104,154104,154106,154108,154112,154121,154121,154123,154123,154123,154123,154124,154124,154125,154125,154132,154136,154143,154144,154146,154148,154148,154148,154148,154149,154164,154169,154170,154173,154177,154180,154181,154189,154190,154195,154196,154216,154218,154230,154235,154242,154245,154245,154245,154248,154248,154248,154248,154250,154258,154259,154264,154264,154266,154269,154269,154269,154269,154269,154270,154270,154270,154270,154275,154279,154281,154293,154296,154302,154302,154302,154302,154302,154302,154309,154310,154310,154310,154319,154322,154329,154330,154330,154335,154339,154339,154343,154345,154346,154346,154346,154350,154354,154354,154354,154355,154357,154357,154360,154361,154361,154363,154366,154381,154381,154381,154383,154383,154384,154384,154384,154384,154385,154385,154385,154385,154385,154385,154389,154392,154392,154392,154392,154392,154396,154396,154398,154401,154401,154402,154407,154407,154407,154409,154409,154409,154409,154410,154410,154410,154410,154413,154413,154413,154415,154415,154418,154418,154419,154419,154419,154419,154419,154419,154419,154420,154421,154423,154423,154423,154425,154426,154428,154428,154432,154438,154440,154440,154441,154443,154446,154448,154448,154448,154449,154449,154452,154456,154458,154459,154459,154459,154459,154459,154459,154459,154459,154459,154464,154464,154466,154466,154467,154467,154467,154470,154470,154471,154471,154471,154473,154473,154473,154474,154474,154478,154478,154478,154480,154481,154482,154482,154483,154484,154484,154489,154489,154489,154491,154496,154497,154498,154498,154499,154500,154501,154513,154519,154520,154522,154522,154526,154526,154535,154536,154537,154537,154538,154538,154543,154555,154555,154556,154557,154558,154561,154562,154562,154565,154569,154569,154570,154571,154571,154572,154577,154588,154591,154591,154591,154592,154594,154595,154595,154599,154599,154602,154602,154605,154605,154605,154607,154608,154608,154609,154613,154620,154620,154622,154622,154622,154622,154622,154622,154624,154628,154630,154630,154631,154631,154636,154638,154641,154643,154645,154645,154647,154657,154660,154670,154671,154676,154676,154676,154676,154676,154676,154676,154676,154676,154676,154676,154676,154680,154683,154693,154698,154700,154708,154708,154708,154709,154709,154709,154710,154717,154723,154735,154735,154742,154743,154748,154748,154759,154761,154764,154764,154766,154767,154772,154772,154774,154774,154779,154781,154781,154781,154782,154784,154787,154788,154789,154793,154794,154795,154796,154797,154797,154801,154803,154803,154804,154822,154826,154826,154826,154826,154826,154830,154835,154840,154841,154843,154851,154856,154867,154871,154871,154871,154871,154871,154871,154871,154871,154871,154871,154871,154871,154871,154876,154879,154879,154880,154881,154883,154883,154883,154886,154887,154889,154889,154889,154890,154890,154890,154890,154892,154892,154898,154899,154902,154911,154911,154911,154912,154913,154921,154921,154923,154934,154935,154945,154951,154953,154958,154960,154961,154964,154964,154965,154965,154969,154969,154971,154971,154971,154972,154977,154981,154981,154990,154994,154994,154994,154995,154995,155003,155007,155013,155013,155016,155016,155016,155018,155022,155026,155033,155033,155033,155034,155037,155045,155047,155052,155052,155052,155052,155052,155052,155052,155052,155052,155052,155052,155055,155055,155056,155056,155058,155058,155060,155065,155065,155068,155073,155082,155082,155088,155089,155091,155091,155091,155091,155091,155093,155094,155096,155097,155099,155100,155101,155104,155107,155107,155107,155107,155107,155107,155107,155107,155111,155117,155117,155117,155117,155119,155119,155119,155119,155119,155119,155119,155122,155129,155129,155129,155129,155129,155129,155131,155143,155153,155163,155165,155165,155165,155168,155169,155171,155172,155173,155173,155173,155173,155174,155181,155185,155185,155190,155191,155192,155196,155197,155197,155197,155197,155197,155211,155214,155220,155221,155222,155222,155222,155223,155227,155227,155231,155231,155231,155234,155235,155236,155238,155243,155244,155247,155252,155253,155255,155257,155257,155268,155269,155277,155282,155282,155286,155286,155299,155307,155308,155309,155317,155330,155340,155340,155340,155341,155342,155343,155343,155346,155346,155346,155346,155346,155346,155346,155346,155346,155346,155346,155354,155355,155356,155356,155359,155361,155365,155367,155368,155368,155372,155374,155374,155376,155380,155381,155381,155382,155385,155388,155388,155390,155390,155391,155394,155396,155405,155405,155405,155410,155411,155412,155416,155417,155417,155419,155419,155419,155426,155427,155427,155430,155433,155435,155435,155436,155440,155445,155445,155445,155448,155485,155485,155486,155490,155491,155494,155496,155502,155514,155520,155520,155520,155534,155534,155537,155537,155537,155555,155556,155568,155574,155595,155596,155596,155596,155596,155597,155600,155610,155614,155615,155615,155618,155622,155629,155632,155634,155636,155645,155651,155653,155653,155655,155658,155659,155669,155679,155683,155683,155683,155683,155683,155683,155687,155687,155687,155687,155688,155688,155689,155689,155689,155692,155709,155718,155731,155739,155742,155742,155744,155744,155746,155749,155754,155755,155756,155758,155759,155761,155761,155761,155761,155761,155763,155763,155767,155773,155777,155778,155789,155789,155789,155794,155795,155796,155814,155822,155827,155827,155827,155833,155833,155833,155837,155839,155840,155840,155845,155845,155845,155845,155855,155855,155855,155855,155855,155857,155866,155870,155872,155872,155874,155876,155877,155882,155886,155890,155890,155894,155895,155898,155898,155898,155899,155899,155899,155899,155899,155899,155900,155909,155918,155920,155920,155920,155920,155920,155922,155922,155923,155929,155930,155930,155932,155932,155932,155932,155932,155932,155932,155933,155935,155935,155935,155935,155937,155937,155937,155937,155938,155938,155938,155938,155938,155939,155939,155939,155939,155939,155944,155944,155948,155952,155952,155956,155975,155975,155975,155984,155998,156001,156005,156005,156010,156013,156013,156018,156019,156022,156022,156023,156026,156034,156034,156034,156034,156034,156034,156036,156036,156039,156047,156050,156052,156053,156054,156055,156055,156055,156065,156066,156076,156085,156085,156085,156085,156085,156087,156087,156088,156091,156091,156094,156094,156094,156097,156097,156104,156108,156111,156116,156116,156116,156122,156124,156130,156130,156133,156134,156138,156139,156139,156139,156139,156139,156139,156139,156139,156139,156143,156145,156147,156154,156155,156155,156156,156156,156161,156172,156173,156173,156173,156180,156180,156180,156184,156193,156197,156202,156205,156208,156214,156217,156217,156221,156226,156231,156233,156234,156234,156234,156247,156247,156247,156251,156251,156251,156251,156253,156259,156259,156261,156268,156269,156269,156278,156278,156279,156281,156282,156282,156284,156286,156286,156286,156286,156288,156288,156290,156293,156294,156294,156305,156306,156306,156306,156306,156306,156306,156306,156306,156306,156306,156306,156307,156307,156308,156312,156317,156318,156318,156318,156329,156330,156331,156331,156331,156331,156334,156335,156336,156340,156340,156346,156346,156348,156348,156349,156349,156350,156351,156351,156354,156357,156360,156364,156373,156373,156373,156383,156388,156390,156399,156404,156409,156409,156409,156410,156410,156412,156414,156414,156414,156416,156427,156433,156433,156434,156434,156434,156434,156436,156437,156437,156441,156448,156448,156448,156451,156451,156451,156466,156481,156481,156488,156489,156490,156491,156493,156494,156494,156502,156507,156515,156520,156522,156522,156523,156525,156527,156532,156534,156540,156544,156544,156548,156548,156548,156552,156552,156561,156563,156563,156565,156567,156570,156570,156572,156574,156580,156581,156582,156582,156582,156582,156584,156587,156589,156592,156592,156594,156595,156595,156596,156599,156603,156610,156613,156613,156621,156621,156623,156623,156623,156623,156625,156625,156627,156627,156637,156642,156650,156652,156653,156653,156654,156654,156660,156665,156667,156675,156675,156675,156675,156675,156675,156675,156675,156675,156675,156675,156678,156679,156680,156681,156682,156682,156691,156692,156703,156708,156709,156711,156711,156718,156718,156718,156718,156718,156718,156718,156718,156718,156718,156719,156723,156729,156730,156734,156734,156734,156734,156737,156737,156737,156737,156737,156748,156749,156762,156762,156762,156767,156768,156768,156772,156787,156788,156788,156788,156791,156792,156794,156803,156803,156813,156814,156819,156820,156827,156829,156831,156833,156834,156835,156836,156836,156837,156838,156841,156842,156848,156848,156854,156855,156855,156860,156865,156872,156879,156879,156882,156883,156885,156889,156891,156891,156891,156892,156892,156892,156892,156899,156899,156900,156905,156910,156910,156913,156918,156926,156926,156926,156926,156936,156939,156939,156942,156942,156944,156944,156950,156954,156954,156954,156954,156954,156960,156960,156960,156960,156963,156964,156966,156966,156967,156968,156977,156979,156980,156980,156980,156981,156984,156984,156990,156995,156995,157005,157005,157007,157010,157010,157010,157010,157011,157011,157011,157011,157011,157011,157011,157011,157011,157013,157018,157025,157047,157055,157055,157058,157064,157064,157068,157072,157073,157075,157084,157084,157087,157094,157100,157103,157103,157103,157104,157104,157104,157107,157107,157110,157110,157110,157113,157113,157113,157115,157115,157115,157121,157121,157121,157122,157122,157122,157125,157125,157125,157135,157136,157137,157144,157144,157144,157144,157146,157153,157157,157160,157161,157162,157163,157165,157171,157171,157171,157171,157182,157188,157188,157191,157198,157198,157205,157205,157206,157212,157213,157215,157215,157219,157219,157219,157219,157219,157220,157220,157220,157220,157220,157222,157231,157233,157240,157242,157245,157246,157247,157247,157251,157254,157254,157255,157255,157257,157260,157263,157268,157279,157279,157282,157292,157295,157298,157300,157302,157305,157305,157305,157306,157308,157308,157308,157308,157308,157308,157308,157308,157308,157312,157313,157313,157313,157313,157313,157319,157319,157322,157323,157335,157335,157335,157335,157346,157348,157351,157351,157352,157352,157354,157354,157355,157355,157355,157357,157360,157361,157372,157374,157376,157379,157385,157396,157396,157396,157396,157396,157396,157396,157396,157396,157397,157397,157400,157404,157404,157404,157404,157404,157407,157408,157409,157410,157410,157411,157412,157412,157414,157414,157416,157419,157420,157421,157424,157424,157426,157431,157432,157434,157437,157444,157450,157451,157452,157452,157454,157454,157454,157456,157459,157463,157463,157463,157463,157463,157467,157468,157468,157470,157470,157474,157478,157487,157504,157505,157506,157506,157506,157508,157522,157522,157531,157537,157538,157541,157541,157541,157542,157548,157548,157548,157553,157553,157554,157554,157554,157554,157554,157556,157560,157575,157586,157595,157595,157595,157595,157597,157599,157601,157603,157603,157604,157604,157604,157605,157605,157607,157608,157613,157613,157613,157614,157619,157621,157623,157623,157623,157624,157625,157635,157635,157636,157637,157637,157638,157640,157640,157643,157651,157654,157654,157655,157655,157655,157655,157657,157661,157666,157673,157673,157674,157674,157674,157675,157679,157682,157687,157687,157689,157696,157701,157704,157707,157707,157714,157715,157715,157728,157730,157737,157738,157744,157747,157748,157748,157752,157753,157753,157753,157755,157755,157755,157756,157758,157758,157758,157759,157759,157762,157765,157766,157767,157767,157767,157769,157773,157774,157774,157792,157801,157806,157806,157808,157818,157820,157820,157823,157824,157826,157828,157829,157835,157839,157845,157854,157859,157862,157872,157874,157878,157880,157880,157881,157893,157896,157896,157899,157900,157902,157903,157908,157908,157908,157913,157916,157918,157920,157924,157928,157933,157936,157936,157954,157954,157954,157954,157954,157962,157963,157963,157963,157968,157968,157968,157975,157977,157977,157980,157981,157981,157981,157981,157981,157981,157981,157981,157981,157981,157981,157982,157984,157984,157984,157988,157995,157997,157997,157998,158003,158003,158003,158003,158003,158003,158005,158005,158005,158005,158005,158007,158013,158019,158022,158024,158026,158027,158028,158032,158038,158040,158049,158050,158050,158054,158054,158055,158056,158056,158059,158059,158059,158060,158060,158061,158062,158062,158062,158062,158062,158063,158063,158063,158063,158065,158066,158066,158066,158067,158073,158077,158078,158081,158081,158081,158085,158085,158085,158085,158085,158086,158088,158091,158095,158095,158095,158095,158095,158095,158098,158100,158104,158105,158109,158109,158110,158110,158110,158110,158110,158110,158110,158115,158117,158117,158117,158118,158119,158121,158122,158124,158128,158128,158133,158139,158139,158139,158140,158140,158143,158143,158144,158148,158153,158154,158154,158155,158155,158156,158156,158156,158157,158158,158163,158167,158171,158171,158177,158177,158177,158177,158180,158180,158181,158183,158183,158184,158189,158190,158191,158194,158205,158209,158209,158209,158210,158214,158214,158214,158214,158218,158218,158219,158219,158225,158227,158228,158230,158236,158239,158246,158250,158250,158251,158251,158251,158255,158255,158255,158255,158255,158256,158256,158259,158259,158259,158259,158261,158261,158261,158261,158263,158273,158274,158274,158277,158280,158285,158288,158289,158289,158289,158289,158290,158292,158292,158294,158294,158294,158294,158301,158303,158305,158305,158305,158305,158312,158318,158326,158337,158342,158342,158345,158345,158346,158348,158349,158355,158356,158356,158370,158377,158377,158393,158394,158394,158394,158396,158396,158400,158400,158400,158400,158400,158401,158402,158403,158403,158403,158406,158406,158407,158409,158415,158417,158417,158417,158419,158421,158421,158428,158428,158429,158430,158430,158432,158433,158437,158437,158437,158437,158441,158448,158448,158448,158448,158449,158449,158449,158449,158449,158449,158460,158464,158468,158469,158469,158469,158470,158470,158470,158470,158470,158470,158474,158474,158474,158488,158491,158491,158505,158506,158507,158507,158507,158515,158527,158530,158530,158533,158533,158533,158533,158533,158533,158533,158533,158533,158533,158533,158537,158538,158538,158538,158539,158539,158540,158540,158540,158540,158540,158540,158540,158542,158544,158547,158550,158557,158560,158561,158562,158562,158562,158562,158563,158565,158566,158568,158568,158569,158573,158578,158580,158580,158580,158580,158580,158581,158583,158584,158588,158596,158601,158602,158611,158617,158617,158617,158624,158628,158628,158633,158638,158638,158640,158641,158652,158652,158653,158653,158655,158655,158655,158657,158661,158667,158675,158678,158678,158682,158682,158687,158699,158702,158702,158702,158702,158708,158729,158736,158736,158737,158737,158766,158770,158770,158778,158778,158780,158781,158783,158787,158789,158789,158789,158791,158794,158797,158800,158810,158810,158820,158820,158820,158820,158839,158849,158863,158863,158873,158874,158876,158879,158883,158888,158889,158889,158889,158889,158890,158891,158891,158891,158893,158893,158893,158893,158901,158902,158902,158902,158902,158902,158904,158904,158908,158913,158913,158913,158914,158924,158929,158932,158936,158936,158938,158938,158942,158942,158942,158942,158942,158946,158948,158950,158950,158955,158955,158960,158960,158960,158960,158965,158965,158967,158967,158968,158972,158975,158976,158977,158977,158980,158980,158980,158980,158980,158984,158987,158990,158991,158995,158995,158995,158996,158998,159003,159007,159007,159011,159012,159012,159016,159017,159018,159024,159026,159031,159036,159037,159037,159037,159037,159037,159042,159046,159051,159055,159055,159055,159056,159056,159056,159056,159057,159057,159058,159059,159059,159062,159062,159065,159067,159068,159072,159077,159077,159077,159082,159084,159089,159094,159103,159109,159109,159109,159109,159109,159109,159109,159109,159113,159120,159133,159141,159143,159145,159145,159148,159148,159148,159152,159153,159154,159157,159159,159160,159160,159160,159160,159161,159164,159170,159170,159172,159181,159183,159183,159183,159184,159186,159186,159190,159190,159191,159196,159199,159199,159199,159202,159202,159202,159205,159209,159215,159218,159222,159228,159232,159232,159237,159237,159244,159245,159245,159245,159245,159254,159257,159259,159259,159263,159267,159270,159274,159278,159278,159281,159281,159283,159283,159283,159288,159288,159288,159288,159288,159288,159290,159290,159290,159291,159291,159291,159291,159291,159292,159292,159295,159301,159303,159303,159304,159304,159304,159304,159304,159306,159306,159311,159311,159311,159314,159314,159314,159314,159314,159316,159316,159316,159323,159324,159331,159344,159344,159347,159350,159350,159358,159372,159383,159383,159383,159383,159388,159389,159389,159393,159408,159408,159409,159416,159416,159416,159418,159422,159425,159440,159444,159451,159452,159454,159454,159454,159454,159454,159454,159460,159460,159460,159468,159476,159476,159483,159485,159492,159499,159500,159502,159524,159526,159530,159535,159536,159536,159536,159538,159540,159544,159547,159548,159548,159548,159549,159563,159573,159575,159576,159578,159578,159578,159578,159578,159578,159578,159578,159578,159578,159582,159583,159583,159586,159587,159598,159612,159612,159612,159612,159612,159615,159617,159618,159618,159620,159621,159621,159623,159642,159652,159665,159665,159665,159667,159667,159667,159671,159672,159672,159676,159676,159684,159689,159703,159708,159708,159711,159711,159711,159717,159721,159726,159730,159731,159731,159731,159732,159732,159732,159733,159734,159734,159734,159734,159737,159737,159737,159737,159738,159738,159741,159741,159741,159748,159750,159751,159751,159752,159752,159752,159753,159753,159754,159754,159755,159755,159755,159755,159755,159759,159759,159761,159761,159763,159763,159763,159764,159767,159767,159771,159774,159774,159774,159775,159775,159785,159786,159786,159789,159789,159791,159793,159794,159799,159799,159799,159800,159800,159801,159801,159802,159804,159806,159806,159810,159811,159811,159812,159812,159812,159813,159813,159815,159815,159820,159820,159821,159829,159837,159840,159840,159840,159846,159848,159849,159849,159850,159854,159854,159856,159856,159863,159868,159875,159875,159875,159878,159878,159879,159880,159881,159881,159881,159882,159892,159895,159895,159895,159895,159895,159895,159898,159900,159901,159906,159906,159906,159907,159911,159912,159913,159913,159915,159919,159924,159926,159926,159933,159933,159933,159933,159933,159934,159939,159943,159947,159947,159947,159947,159947,159947,159948,159951,159951,159951,159954,159965,159966,159967,159971,159971,159971,159971,159973,159974,159976,159977,159977,159980,159981,159982,159983,159983,159984,159989,159989,159990,159990,159992,159998,159999,159999,160000,160001,160001,160003,160005,160005,160008,160009,160012,160019,160019,160019,160021,160021,160022,160023,160025,160025,160036,160039,160046,160046,160047,160047,160049,160051,160052,160054,160056,160056,160059,160059,160060,160063,160064,160064,160064,160065,160068,160068,160071,160072,160072,160074,160076,160076,160076,160080,160085,160085,160087,160087,160088,160089,160089,160091,160091,160091,160091,160091,160097,160097,160101,160102,160104,160106,160106,160115,160119,160119,160130,160130,160131,160132,160145,160147,160147,160148,160149,160152,160152,160154,160156,160156,160157,160157,160157,160160,160162,160162,160164,160164,160164,160164,160165,160165,160165,160166,160167,160167,160167,160167,160167,160167,160167,160168,160169,160169,160169,160169,160169,160171,160171,160173,160173,160173,160173,160173,160176,160183,160183,160183,160183,160190,160190,160194,160195,160197,160197,160199,160199,160199,160200,160200,160200,160201,160201,160203,160215,160216,160216,160218,160224,160226,160226,160226,160226,160226,160226,160226,160226,160226,160226,160226,160226,160227,160227,160227,160227,160228,160228,160236,160238,160239,160241,160241,160242,160242,160242,160243,160243,160244,160244,160246,160248,160251,160258,160258,160258,160262,160264,160264,160264,160264,160264,160264,160265,160265,160267,160267,160267,160267,160272,160285,160288,160289,160290,160291,160291,160296,160301,160320,160320,160320,160320,160320,160320,160333,160333,160334,160334,160335,160336,160336,160338,160338,160340,160340,160340,160340,160340,160344,160344,160344,160345,160345,160346,160351,160356,160361,160364,160364,160365,160365,160365,160366,160367,160367,160367,160369,160369,160371,160371,160372,160374,160375,160378,160385,160385,160385,160388,160388,160388,160390,160390,160390,160390,160393,160396,160399,160399,160405,160408,160408,160409,160411,160411,160411,160411,160411,160411,160413,160414,160415,160418,160418,160419,160420,160421,160421,160422,160422,160425,160426,160427,160427,160427,160427,160428,160429,160429,160430,160430,160430,160430,160433,160433,160434,160435,160435,160437,160437,160437,160437,160437,160441,160443,160445,160445,160448,160450,160451,160451,160452,160452,160452,160452,160454,160461,160462,160462,160467,160468,160469,160469,160471,160471,160477,160477,160477,160477,160486,160487,160488,160488,160489,160489,160489,160489,160489,160489,160489,160489,160504,160504,160504,160506,160507,160507,160511,160511,160520,160520,160520,160520,160522,160522,160522,160522,160522,160522,160522,160523,160524,160526,160526,160526,160526,160526,160528,160532,160532,160536,160538,160541,160541,160541,160541,160546,160547,160549,160551,160554,160557,160557,160557,160557,160557,160557,160557,160567,160569,160569,160569,160569,160570,160572,160580,160580,160582,160589,160590,160595,160595,160595,160595,160595,160595,160595,160595,160597,160598,160604,160606,160610,160613,160619,160619,160619,160621,160625,160628,160630,160640,160640,160641,160641,160641,160645,160646,160648,160655,160655,160655,160656,160656,160657,160660,160662,160663,160663,160663,160663,160665,160670,160673,160680,160680,160682,160682,160685,160686,160686,160686,160686,160689,160689,160689,160689,160689,160690,160690,160690,160690,160690,160690,160690,160690,160690,160690,160690,160690,160690,160692,160692,160692,160692,160693,160693,160693,160693,160693,160693,160693,160693,160694,160694,160694,160694,160694,160694,160694,160694,160695,160695,160699,160699,160701,160701,160702,160704,160704,160708,160708,160708,160708,160708,160712,160712,160712,160712,160712,160713,160713,160713,160713,160713,160714,160714,160714,160715,160715,160715,160715,160715,160715,160715,160715,160715,160717,160718,160720,160721,160721,160721,160721,160723,160723,160725,160728,160728,160729,160730,160730,160730,160730,160731,160732,160733,160733,160733,160733,160733,160734,160737,160738,160739,160739,160739,160739,160742,160742,160745,160746,160747,160748,160748,160748,160748,160751,160753,160753,160753,160753,160755,160756,160756,160757,160758,160758,160759,160761,160761,160761,160767,160768,160769,160769,160770,160770,160771,160774,160774,160775,160777,160778,160779,160780,160782,160783,160785,160785,160786,160787,160788,160788,160788,160789,160789,160789,160789,160789,160789,160791,160793,160793,160795,160795,160796,160796,160797,160798,160798,160798,160799,160803,160803,160803,160803,160803,160803,160803,160805,160817,160817,160817,160818,160818,160818,160819,160819,160819,160819,160821,160821,160823,160823,160823,160824,160824,160827,160830,160831,160832,160832,160832,160832,160832,160834,160836,160836,160836,160836,160836,160836,160836,160836,160836,160836,160838,160838,160838,160839,160839,160839,160839,160839,160839,160839,160839,160839,160840,160840,160841,160841,160841,160841,160842,160843,160843,160843,160844,160844,160844,160847,160847,160847,160847,160849,160852,160852,160852,160853,160853,160858,160859,160859,160859,160860,160860,160865,160867,160870,160871,160871,160871,160874,160875,160877,160886,160886,160886,160899,160903,160907,160907,160907,160907,160907,160911,160911,160911,160916,160916,160917,160917,160917,160917,160917,160917,160919,160920,160927,160927,160927,160929,160932,160933,160937,160938,160938,160939,160939,160939,160940,160940,160940,160942,160942,160947,160949,160952,160952,160953,160953,160956,160957,160960,160960,160961,160962,160962,160965,160966,160966,160966,160967,160969,160969,160969,160969,160970,160974,160974,160975,160978,160979,160980,160982,160982,160982,160982,160982,160983,160987,160992,160999,160999,160999,160999,161002,161006,161007,161007,161007,161007,161012,161013,161022,161022,161022,161023,161027,161028,161028,161031,161033,161035,161035,161035,161036,161037,161040,161041,161041,161041,161041,161041,161041,161045,161045,161045,161049,161051,161051,161051,161052,161054,161057,161057,161057,161057,161059,161061,161062,161062,161062,161062,161063,161063,161069,161069,161071,161072,161072,161072,161074,161082,161083,161087,161093,161094,161094,161094,161099,161105,161106,161106,161111,161111,161111,161111,161111,161111,161117,161117,161120,161120,161120,161121,161121,161121,161123,161125,161126,161126,161128,161128,161130,161130,161134,161137,161139,161139,161139,161139,161141,161141,161141,161141,161141,161142,161142,161144,161144,161144,161145,161146,161146,161147,161156,161158,161158,161158,161158,161158,161158,161158,161158,161158,161160,161160,161160,161161,161165,161167,161179,161184,161185,161185,161186,161186,161196,161198,161198,161207,161207,161207,161210,161211,161211,161213,161215,161217,161217,161217,161218,161220,161222,161222,161222,161222,161222,161222,161222,161222,161222,161222,161223,161233,161234,161234,161234,161234,161234,161234,161234,161236,161239,161239,161239,161239,161241,161252,161252,161253,161255,161255,161260,161261,161266,161266,161266,161267,161273,161275,161277,161277,161278,161280,161280,161281,161284,161284,161288,161292,161293,161294,161295,161296,161300,161300,161300,161300,161300,161306,161307,161307,161307,161307,161307,161310,161310,161311,161312,161312,161317,161321,161321,161321,161321,161321,161321,161321,161321,161321,161324,161324,161327,161327,161328,161339,161352,161353,161356,161357,161358,161360,161361,161362,161365,161366,161366,161366,161366,161369,161369,161371,161371,161371,161372,161374,161382,161383,161383,161384,161388,161391,161394,161395,161395,161396,161396,161396,161397,161397,161401,161402,161402,161403,161403,161403,161403,161403,161403,161403,161403,161403,161403,161403,161404,161407,161409,161414,161414,161415,161415,161415,161416,161418,161418,161419,161424,161425,161425,161425,161428,161430,161432,161432,161432,161432,161437,161437,161437,161438,161443,161443,161443,161443,161443,161443,161443,161443,161444,161444,161444,161444,161447,161447,161447,161447,161447,161447,161447,161447,161447,161449,161449,161449,161451,161451,161451,161451,161451,161451,161451,161451,161451,161451,161451,161452,161452,161452,161452,161452,161454,161454,161454,161454,161455,161455,161455,161455,161457,161459,161461,161462,161462,161462,161462,161462,161462,161462,161462,161463,161464,161466,161468,161468,161470,161472,161473,161473,161473,161473,161473,161473,161473,161473,161475,161476,161476,161476,161479,161479,161480,161480,161480,161480,161480,161480,161480,161480,161480,161480,161480,161480,161481,161486,161491,161495,161499,161505,161505,161508,161508,161508,161508,161509,161510,161511,161513,161523,161524,161525,161530,161535,161539,161543,161543,161545,161545,161550,161552,161553,161553,161553,161553,161555,161556,161557,161558,161560,161560,161560,161563,161564,161564,161567,161567,161567,161567,161567,161567,161578,161580,161581,161583,161583,161584,161585,161585,161585,161585,161585,161585,161585,161585,161585,161585,161585,161589,161591,161595,161599,161599,161599,161601,161605,161605,161605,161605,161605,161606,161606,161606,161606,161611,161611,161613,161613,161617,161618,161618,161633,161637,161637,161637,161638,161638,161643,161644,161647,161647,161649,161650,161650,161650,161650,161650,161651,161652,161652,161654,161654,161654,161657,161657,161672,161672,161682,161682,161682,161684,161684,161703,161706,161711,161711,161716,161720,161733,161736,161737,161737,161738,161738,161738,161738,161738,161741,161743,161743,161743,161747,161747,161753,161753,161753,161754,161754,161756,161758,161758,161758,161758,161758,161758,161758,161758,161758,161758,161758,161758,161758,161758,161761,161761,161761,161762,161762,161764,161764,161765,161765,161765,161765,161766,161766,161773,161774,161776,161776,161778,161781,161782,161782,161784,161784,161784,161786,161786,161786,161786,161786,161789,161792,161792,161792,161792,161792,161792,161793,161800,161801,161802,161802,161802,161802,161802,161802,161804,161804,161812,161812,161812,161827,161835,161838,161838,161839,161839,161839,161840,161840,161844,161849,161851,161851,161851,161852,161855,161856,161857,161865,161865,161869,161875,161875,161875,161875,161875,161875,161875,161883,161883,161885,161885,161889,161890,161893,161893,161895,161899,161899,161899,161899,161899,161900,161902,161907,161907,161907,161907,161908,161908,161909,161911,161911,161911,161917,161917,161920,161920,161924,161928,161928,161929,161929,161934,161934,161934,161934,161937,161937,161937,161937,161937,161938,161939,161944,161945,161945,161947,161952,161952,161955,161957,161957,161957,161957,161957,161957,161958,161960,161961,161969,161972,161972,161983,161983,161985,161985,161985,161993,161995,161995,161997,161998,161998,161998,161998,161998,161998,161999,161999,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162000,162004,162011,162011,162013,162013,162013,162018,162018,162023,162023,162023,162023,162023,162023,162032,162033,162033,162033,162033,162035,162038,162038,162039,162039,162044,162045,162045,162045,162046,162049,162049,162060,162075,162078,162079,162079,162082,162082,162084,162084,162089,162089,162089,162090,162092,162104,162113,162113,162113,162113,162117,162119,162119,162121,162132,162139,162139,162139,162139,162139,162139,162145,162149,162151,162151,162151,162153,162153,162157,162163,162165,162165,162165,162165,162165,162165,162165,162165,162165,162165,162165,162165,162165,162165,162166,162166,162166,162173,162176,162179,162179,162179,162183,162183,162185,162185,162192,162193,162194,162198,162198,162198,162200,162201,162201,162201,162201,162201,162201,162203,162205,162208,162208,162208,162208,162208,162209,162211,162211,162212,162213,162219,162219,162219,162227,162227,162227,162227,162227,162228,162230,162230,162234,162238,162238,162238,162250,162250,162250,162252,162257,162257,162260,162263,162263,162263,162268,162272,162272,162272,162280,162283,162283,162294,162294,162295,162295,162299,162301,162302,162302,162309,162313,162314,162318,162319,162319,162319,162320,162321,162323,162323,162324,162324,162324,162325,162325,162325,162325,162327,162327,162327,162327,162330,162330,162330,162330,162331,162331,162341,162343,162344,162345,162348,162348,162351,162351,162366,162366,162369,162376,162377,162377,162378,162379,162379,162379,162383,162383,162384,162384,162386,162386,162390,162393,162394,162395,162400,162401,162404,162406,162407,162407,162407,162408,162408,162410,162410,162410,162410,162411,162411,162412,162414,162421,162421,162421,162421,162421,162425,162427,162427,162427,162427,162427,162427,162427,162427,162427,162427,162427,162427,162430,162435,162438,162439,162439,162440,162440,162445,162451,162453,162453,162453,162454,162461,162466,162466,162466,162466,162466,162481,162482,162482,162484,162488,162488,162497,162498,162502,162506,162506,162506,162506,162506,162511,162511,162511,162511,162511,162513,162519,162521,162521,162521,162524,162525,162525,162525,162525,162527,162528,162529,162530,162531,162533,162533,162536,162540,162540,162540,162540,162542,162544,162554,162554,162555,162557,162557,162557,162570,162573,162573,162574,162578,162580,162580,162583,162584,162584,162584,162587,162589,162593,162593,162595,162595,162596,162596,162598,162599,162600,162600,162600,162606,162610,162610,162610,162610,162611,162616,162623,162623,162628,162629,162630,162632,162633,162636,162636,162636,162637,162637,162639,162639,162639,162639,162640,162640,162642,162643,162643,162643,162643,162644,162646,162646,162646,162648,162648,162652,162653,162653,162654,162654,162661,162661,162661,162661,162668,162668,162668,162679,162688,162689,162690,162692,162695,162707,162707,162709,162709,162709,162709,162709,162709,162709,162709,162709,162709,162709,162709,162709,162709,162719,162719,162719,162719,162730,162734,162734,162737,162737,162737,162742,162746,162746,162750,162752,162753,162757,162758,162760,162766,162766,162768,162771,162771,162780,162783,162783,162784,162784,162784,162787,162787,162791,162791,162795,162795,162798,162798,162801,162805,162805,162806,162806,162806,162806,162806,162811,162816,162817,162819,162821,162823,162828,162829,162832,162835,162839,162843,162850,162859,162865,162869,162870,162870,162876,162878,162878,162878,162878,162878,162879,162879,162885,162887,162887,162889,162890,162890,162890,162893,162895,162896,162896,162897,162897,162898,162898,162898,162898,162900,162900,162901,162903,162906,162907,162907,162907,162942,162942,162950,162950,162950,162950,162950,162950,162950,162950,162950,162950,162950,162950,162950,162952,162952,162954,162954,162954,162960,162960,162960,162960,162960,162961,162961,162961,162961,162963,162967,162968,162968,162970,162976,162980,162982,162982,162984,162985,162985,162990,162992,162992,162992,162993,162993,162993,162993,162993,162994,162996,162996,162996,162996,162997,163004,163004,163004,163004,163004,163004,163004,163004,163004,163004,163004,163004,163004,163004,163007,163014,163019,163024,163031,163033,163035,163037,163037,163039,163039,163045,163046,163060,163063,163066,163082,163084,163086,163086,163086,163093,163097,163097,163106,163106,163108,163113,163115,163117,163118,163118,163121,163129,163142,163156,163160,163160,163163,163163,163163,163172,163178,163179,163179,163179,163179,163185,163186,163187,163192,163199,163200,163202,163206,163207,163207,163207,163210,163212,163220,163223,163223,163225,163234,163236,163236,163241,163246,163255,163255,163259,163259,163261,163261,163261,163261,163264,163264,163264,163275,163277,163277,163278,163278,163279,163280,163281,163281,163282,163282,163284,163284,163284,163284,163285,163285,163285,163285,163285,163285,163285,163286,163286,163289,163290,163290,163291,163292,163299,163301,163303,163303,163305,163305,163306,163307,163307,163312,163317,163318,163324,163325,163327,163331,163333,163333,163334,163341,163341,163341,163341,163343,163346,163351,163353,163358,163359,163360,163361,163369,163369,163369,163369,163369,163369,163369,163369,163369,163369,163369,163369,163370,163370,163370,163370,163370,163370,163370,163370,163370,163370,163373,163374,163375,163379,163379,163379,163379,163379,163381,163383,163383,163383,163383,163385,163389,163390,163392,163392,163393,163394,163396,163400,163400,163400,163400,163400,163404,163405,163405,163405,163405,163405,163406,163406,163406,163406,163408,163408,163409,163410,163411,163416,163416,163416,163416,163417,163418,163418,163419,163422,163422,163423,163423,163424,163425,163426,163427,163427,163435,163436,163436,163436,163439,163439,163439,163440,163442,163446,163449,163451,163451,163453,163456,163456,163457,163460,163461,163464,163464,163468,163477,163478,163482,163485,163487,163488,163490,163496,163497,163497,163506,163506,163506,163506,163506,163509,163515,163519,163519,163521,163527,163532,163534,163538,163544,163545,163547,163547,163547,163547,163548,163551,163551,163553,163553,163553,163555,163556,163557,163558,163558,163558,163558,163559,163560,163561,163561,163563,163563,163566,163566,163576,163577,163578,163579,163580,163581,163581,163581,163583,163584,163592,163595,163607,163607,163607,163612,163615,163616,163618,163621,163622,163622,163622,163622,163622,163623,163623,163625,163631,163631,163632,163632,163632,163632,163632,163632,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163633,163634,163635,163635,163635,163635,163640,163642,163647,163649,163650,163651,163654,163656,163656,163658,163659,163659,163662,163662,163664,163666,163667,163669,163674,163674,163675,163676,163676,163676,163677,163677,163677,163679,163679,163679,163679,163680,163680,163680,163680,163680,163680,163680,163681,163684,163684,163684,163685,163685,163685,163686,163686,163691,163692,163692,163692,163694,163695,163695,163706,163707,163708,163709,163710,163710,163711,163713,163714,163716,163717,163718,163719,163720,163721,163728,163729,163730,163731,163734,163734,163735,163735,163736,163736,163736,163736,163737,163737,163738,163738,163738,163738,163740,163740,163740,163740,163741,163742,163742,163748,163750,163753,163756,163759,163759,163759,163761,163761,163763,163766,163770,163770,163770,163775,163776,163780,163781,163781,163781,163781,163781,163781,163781,163781,163781,163781,163781,163781,163781,163785,163787,163797,163800,163800,163800,163800,163800,163800,163800,163800,163801,163804,163805,163808,163808,163809,163812,163815,163820,163824,163824,163826,163827,163827,163827,163831,163832,163838,163839,163839,163839,163839,163851,163855,163855,163862,163867,163869,163870,163872,163877,163881,163887,163889,163893,163893,163896,163901,163904,163905,163907,163907,163907,163912,163912,163916,163917,163919,163926,163928,163928,163928,163928,163928,163936,163936,163938,163939,163939,163950,163960,163960,163960,163960,163960,163961,163962,163962,163962,163962,163963,163963,163963,163963,163963,163965,163970,163977,163980,163980,163980,163980,163984,163992,163992,163994,163994,163994,164002,164004,164006,164007,164007,164029,164034,164049,164050,164059,164059,164059,164059,164059,164059,164063,164064,164064,164070,164070,164073,164074,164077,164079,164079,164079,164079,164079,164080,164080,164080,164084,164088,164089,164089,164089,164092,164092,164093,164093,164093,164104,164107,164107,164118,164118,164127,164127,164136,164140,164140,164140,164141,164141,164141,164141,164143,164148,164161,164165,164167,164175,164176,164177,164179,164181,164181,164181,164181,164181,164184,164186,164191,164205,164207,164207,164212,164216,164217,164217,164222,164233,164242,164244,164247,164254,164254,164255,164255,164255,164266,164267,164267,164267,164267,164267,164267,164267,164267,164267,164267,164267,164272,164287,164287,164287,164288,164289,164289,164291,164297,164305,164305,164305,164307,164307,164307,164313,164320,164327,164327,164331,164344,164353,164353,164353,164353,164354,164354,164354,164354,164356,164358,164359,164362,164365,164365,164370,164370,164370,164370,164370,164372,164372,164373,164374,164377,164382,164382,164382,164382,164382,164386,164386,164387,164388,164392,164394,164397,164397,164407,164407,164407,164408,164414,164415,164422,164422,164436,164441,164446,164446,164446,164446,164446,164446,164447,164454,164457,164462,164464,164467,164480,164489,164506,164508,164508,164509,164512,164516,164520,164522,164524,164525,164528,164528,164533,164535,164542,164545,164545,164545,164548,164548,164552,164554,164554,164559,164560,164563,164563,164580,164583,164583,164584,164584,164606,164607,164607,164608,164621,164622,164623,164624,164625,164628,164630,164630,164630,164632,164633,164633,164633,164636,164638,164645,164645,164650,164655,164659,164675,164682,164682,164686,164688,164688,164688,164691,164695,164695,164701,164701,164703,164704,164704,164705,164707,164707,164717,164719,164719,164727,164736,164736,164741,164744,164744,164744,164744,164748,164753,164754,164754,164757,164757,164757,164758,164758,164758,164758,164758,164761,164761,164762,164762,164762,164762,164762,164762,164762,164762,164766,164767,164770,164776,164781,164785,164789,164795,164797,164798,164798,164798,164798,164799,164802,164802,164803,164804,164804,164804,164807,164807,164808,164808,164818,164818,164825,164828,164829,164837,164842,164843,164844,164846,164877,164878,164882,164888,164888,164888,164894,164901,164903,164904,164904,164905,164905,164907,164907,164908,164911,164915,164925,164937,164939,164946,164946,164947,164949,164949,164957,164958,164958,164958,164958,164959,164959,164959,164959,164959,164959,164959,164959,164959,164959,164959,164959,164960,164960,164961,164963,164963,164964,164964,164964,164965,164965,164965,164968,164970,164970,164970,164970,164970,164970,164970,164970,164970,164970,164970,164970,164970,164970,164970,164970,164978,164979,164980,164982,164990,164993,165000,165000,165002,165004,165004,165004,165004,165006,165006,165007,165007,165007,165007,165007,165007,165008,165009,165009,165010,165013,165013,165017,165017,165018,165019,165019,165020,165020,165020,165020,165020,165020,165023,165023,165023,165030,165030,165030,165031,165031,165035,165035,165035,165037,165037,165037,165037,165037,165042,165047,165048,165054,165054,165059,165059,165065,165066,165069,165072,165074,165076,165076,165077,165080,165085,165085,165085,165086,165088,165092,165093,165094,165096,165100,165102,165104,165105,165107,165107,165107,165109,165109,165109,165112,165114,165119,165120,165122,165124,165124,165124,165126,165128,165128,165130,165138,165139,165139,165139,165139,165139,165140,165140,165140,165142,165146,165147,165151,165153,165155,165160,165160,165161,165161,165161,165161,165161,165164,165165,165174,165174,165175,165179,165180,165180,165181,165182,165183,165183,165183,165184,165185,165185,165185,165187,165190,165195,165195,165196,165198,165199,165199,165199,165200,165200,165200,165200,165201,165204,165204,165205,165206,165209,165209,165209,165209,165210,165210,165210,165210,165210,165210,165210,165211,165214,165214,165214,165215,165216,165218,165221,165223,165225,165227,165231,165231,165236,165240,165242,165247,165247,165247,165247,165251,165252,165255,165258,165258,165258,165258,165258,165258,165259,165261,165261,165265,165265,165268,165269,165269,165281,165285,165288,165292,165294,165294,165294,165294,165296,165300,165306,165307,165310,165313,165315,165317,165321,165323,165324,165330,165330,165332,165332,165332,165332,165332,165334,165334,165334,165334,165334,165334,165336,165336,165336,165336,165337,165338,165340,165350,165350,165353,165354,165358,165359,165363,165363,165367,165373,165374,165374,165375,165376,165378,165379,165379,165380,165383,165383,165383,165386,165386,165387,165390,165390,165391,165393,165394,165400,165404,165412,165413,165413,165414,165416,165417,165417,165417,165417,165417,165419,165422,165425,165428,165433,165433,165433,165433,165433,165434,165434,165434,165434,165434,165436,165436,165436,165438,165439,165439,165439,165441,165443,165445,165446,165446,165452,165462,165462,165462,165464,165467,165471,165471,165472,165473,165473,165478,165478,165481,165483,165485,165486,165488,165490,165490,165492,165492,165492,165493,165493,165493,165493,165493,165493,165493,165493,165493,165493,165494,165494,165494,165497,165498,165498,165507,165507,165512,165513,165513,165526,165527,165528,165533,165535,165535,165537,165543,165545,165554,165559,165559,165559,165559,165559,165559,165559,165560,165560,165560,165560,165569,165569,165569,165569,165573,165576,165576,165576,165582,165582,165593,165596,165598,165611,165611,165611,165612,165612,165614,165615,165617,165618,165618,165618,165618,165618,165618,165618,165618,165618,165618,165618,165618,165618,165618,165618,165620,165624,165628,165628,165643,165645,165645,165645,165646,165647,165647,165656,165664,165664,165664,165665,165668,165674,165674,165677,165684,165684,165684,165685,165687,165689,165695,165695,165700,165706,165707,165707,165713,165713,165714,165714,165719,165719,165719,165720,165720,165720,165721,165721,165721,165721,165723,165723,165729,165729,165729,165741,165742,165743,165743,165744,165744,165756,165756,165756,165758,165758,165758,165765,165779,165779,165779,165781,165781,165781,165786,165786,165786,165786,165786,165786,165786,165787,165789,165789,165790,165792,165795,165798,165802,165807,165807,165809,165811,165813,165813,165815,165816,165816,165822,165822,165822,165825,165825,165827,165827,165827,165827,165828,165828,165828,165828,165830,165835,165835,165835,165835,165835,165835,165836,165836,165836,165838,165839,165839,165839,165840,165840,165842,165842,165843,165844,165851,165852,165852,165852,165852,165852,165852,165853,165853,165854,165854,165857,165857,165857,165859,165859,165859,165860,165861,165861,165861,165861,165861,165861,165861,165861,165865,165866,165867,165867,165873,165875,165877,165877,165879,165881,165882,165882,165882,165882,165882,165882,165882,165882,165882,165885,165889,165891,165891,165892,165896,165896,165899,165901,165902,165903,165904,165904,165907,165912,165913,165913,165913,165914,165915,165918,165921,165921,165921,165922,165922,165922,165923,165923,165924,165925,165927,165928,165929,165929,165932,165932,165933,165937,165939,165943,165943,165949,165949,165950,165950,165952,165952,165954,165955,165955,165955,165955,165955,165955,165962,165965,165967,165968,165968,165969,165971,165971,165971,165971,165982,165982,165986,165987,165987,165987,165987,165988,165988,165988,165988,165993,165994,165994,165994,165994,166000,166001,166001,166004,166005,166007,166010,166010,166011,166011,166013,166014,166014,166014,166014,166014,166014,166015,166015,166015,166015,166016,166016,166030,166033,166033,166033,166034,166034,166039,166049,166049,166051,166051,166054,166054,166059,166073,166077,166077,166077,166079,166080,166080,166083,166084,166095,166101,166102,166102,166108,166111,166112,166113,166113,166114,166115,166115,166115,166121,166121,166121,166122,166126,166128,166129,166134,166140,166141,166142,166143,166144,166147,166147,166147,166150,166150,166150,166150,166156,166158,166165,166165,166170,166172,166173,166173,166175,166175,166177,166193,166193,166203,166203,166214,166214,166214,166217,166218,166226,166227,166227,166227,166228,166231,166231,166231,166231,166232,166239,166240,166240,166241,166242,166244,166244,166251,166256,166261,166265,166266,166266,166266,166266,166273,166274,166277,166279,166287,166291,166293,166295,166297,166297,166297,166298,166298,166298,166303,166303,166303,166305,166309,166309,166310,166310,166312,166312,166312,166312,166313,166313,166313,166313,166314,166315,166315,166318,166323,166323,166326,166326,166328,166329,166330,166330,166331,166334,166335,166335,166335,166337,166337,166339,166339,166339,166339,166339,166339,166339,166339,166340,166342,166342,166342,166342,166342,166349,166357,166357,166359,166359,166364,166364,166365,166365,166367,166367,166367,166367,166367,166367,166372,166372,166372,166374,166374,166379,166384,166384,166385,166387,166396,166396,166397,166397,166399,166402,166402,166402,166402,166403,166404,166409,166410,166410,166410,166413,166413,166413,166420,166427,166452,166452,166457,166457,166457,166458,166460,166460,166462,166462,166462,166462,166462,166463,166464,166464,166466,166467,166467,166467,166471,166471,166475,166476,166477,166477,166486,166488,166488,166490,166491,166491,166491,166491,166499,166499,166504,166504,166504,166504,166504,166508,166508,166508,166511,166513,166515,166515,166523,166525,166530,166530,166531,166533,166534,166534,166534,166539,166542,166547,166551,166551,166560,166580,166589,166590,166590,166590,166590,166590,166590,166590,166590,166597,166603,166605,166607,166607,166609,166609,166609,166609,166609,166609,166609,166609,166612,166613,166613,166614,166615,166615,166629,166631,166638,166641,166644,166646,166648,166654,166662,166664,166664,166674,166680,166681,166682,166686,166690,166694,166694,166706,166710,166713,166713,166715,166722,166722,166728,166731,166736,166737,166741,166742,166744,166752,166756,166782,166782,166783,166783,166784,166784,166787,166788,166798,166799,166804,166805,166806,166807,166808,166808,166810,166813,166813,166819,166819,166822,166823,166824,166825,166825,166825,166827,166835,166836,166836,166836,166838,166839,166839,166839,166842,166844,166850,166861,166864,166865,166865,166877,166879,166884,166884,166895,166895,166897,166897,166897,166898,166904,166904,166904,166907,166913,166914,166914,166915,166926,166929,166930,166932,166932,166932,166934,166936,166939,166939,166941,166944,166944,166945,166948,166948,166957,166957,166962,166962,166966,166972,166985,166991,166993,166993,167008,167008,167012,167013,167013,167013,167017,167017,167035,167036,167036,167036,167037,167040,167041,167053,167054,167054,167059,167059,167061,167061,167074,167075,167076,167080,167080,167080,167087,167095,167096,167100,167100,167108,167113,167113,167113,167121,167122,167123,167126,167128,167129,167132,167138,167139,167139,167139,167145,167150,167151,167153,167163,167163,167163,167164,167164,167164,167166,167170,167170,167177,167181,167185,167206,167209,167214,167214,167215,167215,167215,167218,167219,167219,167227,167228,167229,167229,167242,167243,167255,167256,167259,167263,167264,167271,167275,167283,167289,167295,167313,167314,167318,167325,167325,167327,167329,167329,167329,167329,167329,167329,167329,167329,167329,167329,167329,167329,167330,167332,167342,167349,167349,167353,167353,167366,167373,167373,167377,167379,167380,167380,167392,167401,167408,167408,167408,167408,167409,167409,167411,167412,167413,167413,167413,167414,167420,167420,167420,167429,167437,167437,167437,167443,167443,167443,167443,167443,167457,167457,167457,167464,167464,167473,167476,167478,167480,167505,167510,167513,167513,167513,167513,167513,167513,167515,167519,167519,167527,167541,167543,167544,167545,167549,167550,167551,167559,167559,167559,167566,167569,167570,167570,167570,167574,167574,167576,167579,167587,167589,167595,167595,167598,167601,167613,167613,167614,167614,167629,167629,167629,167636,167650,167650,167650,167651,167653,167657,167657,167657,167657,167658,167660,167665,167667,167675,167677,167678,167682,167685,167685,167686,167686,167691,167694,167694,167694,167700,167705,167708,167713,167713,167713,167713,167713,167716,167717,167728,167732,167734,167734,167736,167737,167740,167742,167743,167744,167752,167763,167765,167768,167769,167778,167784,167785,167794,167795,167796,167800,167800,167800,167800,167803,167803,167813,167813,167819,167819,167837,167846,167851,167851,167859,167862,167866,167867,167867,167867,167869,167870,167872,167872,167879,167891,167891,167892,167895,167896,167903,167913,167913,167916,167920,167921,167921,167921,167921,167922,167922,167925,167925,167927,167928,167928,167928,167928,167932,167932,167934,167938,167949,167950,167953,167955,167955,167963,167963,167964,167972,167972,167972,167972,167972,167974,167975,167978,167979,167979,167980,167988,167989,167995,167995,168013,168023,168032,168035,168035,168035,168036,168044,168051,168052,168053,168059,168062,168062,168063,168066,168066,168067,168067,168067,168070,168070,168070,168070,168071,168074,168075,168078,168081,168083,168084,168084,168093,168093,168097,168097,168099,168099,168100,168100,168100,168103,168105,168106,168110,168114,168114,168116,168119,168119,168156,168156,168156,168156,168156,168160,168160,168160,168162,168162,168162,168162,168162,168166,168166,168166,168166,168166,168166,168166,168170,168170,168171,168179,168186,168188,168193,168200,168201,168209,168211,168215,168215,168221,168224,168224,168230,168230,168233,168233,168233,168233,168233,168237,168240,168244,168249,168259,168261,168289,168295,168304,168308,168308,168309,168309,168309,168309,168312,168314,168314,168314,168320,168323,168325,168333,168341,168345,168355,168361,168362,168372,168387,168387,168387,168387,168387,168395,168404,168405,168406,168414,168414,168417,168422,168422,168441,168455,168456,168457,168457,168461,168474,168480,168485,168491,168492,168496,168497,168500,168500,168500,168502,168512,168514,168515,168520,168521,168524,168524,168524,168526,168536,168536,168536,168536,168539,168554,168554,168554,168558,168563,168566,168575,168583,168590,168590,168591,168596,168597,168597,168597,168597,168597,168598,168608,168611,168612,168612,168613,168615,168615,168617,168631,168634,168645,168649,168649,168656,168663,168670,168674,168674,168678,168678,168695,168699,168701,168705,168705,168705,168709,168710,168710,168712,168714,168721,168722,168722,168730,168734,168735,168740,168740,168742,168742,168743,168752,168753,168753,168760,168768,168770,168772,168772,168773,168773,168776,168776,168777,168779,168780,168780,168783,168784,168784,168787,168787,168787,168787,168787,168789,168789,168792,168792,168792,168795,168799,168804,168807,168811,168814,168817,168823,168827,168834,168835,168837,168848,168848,168848,168854,168880,168881,168884,168892,168895,168896,168896,168901,168902,168913,168913,168921,168922,168923,168925,168939,168940,168940,168940,168940,168945,168947,168948,168949,168951,168955,168957,168957,168957,168957,168957,168961,168961,168962,168962,168964,168976,168977,168977,168977,168977,168977,168977,168977,168978,168980,168988,168989,168999,169004,169004,169006,169014,169014,169015,169017,169023,169023,169024,169026,169029,169031,169031,169031,169031,169043,169043,169046,169046,169046,169046,169046,169046,169046,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169048,169055,169056,169056,169056,169057,169059,169065,169073,169077,169077,169079,169080,169084,169092,169105,169105,169105,169105,169108,169114,169114,169114,169115,169115,169117,169118,169120,169120,169120,169120,169120,169120,169120,169121,169122,169122,169122,169124,169124,169125,169125,169125,169125,169125,169125,169125,169125,169126,169126,169126,169126,169127,169127,169127,169127,169127,169127,169127,169128,169132,169132,169132,169132,169132,169132,169133,169133,169133,169133,169133,169133,169133,169133,169134,169134,169134,169135,169135,169135,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169137,169138,169138,169138,169142,169143,169143,169143,169143,169143,169147,169147,169151,169154,169155,169156,169156,169158,169159,169159,169160,169162,169166,169167,169168,169169,169170,169170,169170,169170,169171,169175,169175,169175,169175,169175,169175,169175,169176,169176,169176,169177,169177,169177,169178,169178,169178,169179,169179,169180,169180,169182,169182,169182,169183,169183,169183,169185,169185,169187,169187,169189,169189,169189,169191,169191,169192,169192,169192,169192,169192,169192,169193,169193,169193,169194,169194,169194,169194,169194,169195,169197,169198,169198,169203,169204,169204,169205,169210,169211,169211,169214,169216,169219,169220,169223,169225,169232,169232,169234,169236,169239,169239,169239,169241,169241,169241,169241,169241,169241,169242,169243,169244,169246,169246,169246,169246,169246,169246,169246,169246,169246,169246,169247,169251,169252,169253,169253,169260,169261,169261,169261,169261,169264,169264,169266,169266,169270,169270,169272,169273,169275,169281,169284,169284,169287,169287,169292,169300,169303,169306,169306,169306,169306,169312,169314,169314,169314,169316,169321,169321,169323,169331,169331,169331,169334,169336,169342,169342,169342,169342,169345,169351,169355,169355,169355,169356,169356,169356,169365,169365,169365,169366,169370,169371,169371,169371,169379,169379,169382,169389,169393,169397,169397,169399,169402,169402,169402,169403,169409,169409,169409,169412,169412,169412,169412,169412,169412,169412,169412,169412,169412,169413,169413,169414,169416,169419,169419,169420,169433,169434,169434,169441,169450,169459,169463,169471,169472,169472,169481,169481,169485,169486,169490,169495,169498,169501,169505,169508,169508,169512,169514,169514,169514,169516,169517,169529,169529,169529,169538,169538,169539,169543,169543,169543,169548,169551,169559,169561,169564,169565,169565,169565,169569,169583,169584,169584,169584,169584,169584,169584,169584,169585,169585,169585,169603,169603,169603,169605,169614,169615,169619,169627,169637,169637,169655,169655,169655,169655,169655,169658,169659,169666,169673,169678,169686,169686,169689,169689,169689,169690,169690,169692,169695,169699,169701,169704,169705,169709,169712,169714,169714,169714,169714,169714,169717,169717,169718,169722,169730,169734,169735,169741,169745,169749,169755,169755,169755,169758,169761,169761,169761,169763,169763,169763,169764,169764,169764,169764,169764,169764,169764,169764,169764,169764,169764,169766,169768,169768,169768,169780,169788,169792,169792,169795,169795,169795,169795,169795,169795,169795,169795,169795,169795,169795,169795,169795,169795,169798,169809,169813,169813,169813,169822,169822,169824,169825,169826,169828,169829,169830,169836,169836,169836,169837,169837,169837,169837,169837,169843,169843,169843,169843,169843,169845,169849,169849,169849,169849,169851,169853,169854,169869,169870,169870,169870,169876,169876,169876,169879,169880,169880,169880,169883,169883,169883,169883,169883,169883,169889,169892,169901,169903,169903,169903,169906,169906,169910,169914,169914,169917,169918,169926,169932,169935,169936,169940,169942,169943,169943,169943,169954,169959,169977,169978,169980,169982,169983,169987,169989,169993,169993,169996,170000,170011,170013,170016,170025,170025,170026,170039,170040,170042,170042,170042,170045,170048,170050,170052,170053,170054,170055,170059,170064,170065,170067,170071,170073,170079,170080,170083,170083,170083,170085,170086,170087,170087,170095,170096,170099,170100,170100,170105,170105,170105,170111,170111,170113,170114,170114,170115,170117,170122,170127,170135,170137,170137,170138,170138,170138,170141,170147,170151,170153,170169,170173,170177,170177,170177,170177,170178,170180,170181,170184,170191,170193,170195,170195,170195,170195,170195,170195,170201,170204,170207,170208,170210,170210,170214,170214,170214,170214,170214,170231,170232,170232,170232,170232,170240,170245,170251,170258,170258,170261,170261,170263,170264,170265,170265,170267,170267,170273,170274,170276,170279,170283,170293,170297,170297,170299,170303,170309,170309,170313,170314,170315,170315,170316,170316,170316,170318,170326,170326,170326,170326,170326,170327,170329,170330,170330,170336,170336,170336,170337,170338,170338,170339,170343,170356,170358,170363,170367,170373,170374,170381,170387,170390,170390,170390,170391,170401,170414,170414,170418,170426,170426,170431,170435,170444,170448,170448,170450,170452,170452,170452,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170457,170466,170474,170474,170474,170480,170485,170486,170487,170489,170492,170499,170502,170506,170507,170508,170514,170514,170518,170518,170518,170518,170518,170518,170519,170521,170522,170522,170522,170522,170523,170526,170529,170529,170529,170529,170534,170534,170538,170538,170549,170553,170559,170562,170562,170562,170562,170562,170569,170577,170584,170585,170585,170586,170586,170586,170588,170588,170590,170592,170594,170594,170599,170600,170600,170600,170600,170600,170600,170600,170600,170607,170611,170612,170613,170613,170614,170622,170622,170622,170622,170622,170626,170629,170629,170630,170642,170642,170649,170653,170653,170664,170670,170673,170684,170687,170687,170692,170696,170696,170700,170700,170700,170700,170700,170700,170700,170700,170700,170700,170700,170700,170700,170700,170700,170702,170707,170708,170712,170713,170713,170713,170713,170715,170715,170716,170717,170723,170723,170724,170724,170724,170734,170736,170737,170737,170743,170744,170747,170748,170750,170750,170755,170758,170759,170759,170761,170761,170762,170766,170780,170780,170797,170801,170802,170809,170814,170814,170814,170814,170816,170817,170820,170820,170820,170820,170820,170820,170833,170835,170836,170838,170839,170839,170845,170845,170859,170859,170862,170864,170864,170877,170877,170877,170880,170882,170890,170891,170891,170897,170897,170897,170899,170900,170903,170907,170913,170913,170915,170923,170924,170924,170924,170929,170930,170935,170938,170938,170943,170943,170947,170948,170949,170950,170951,170951,170951,170951,170953,170961,170963,170963,170963,170968,170969,170970,170973,170986,170987,170988,170988,170988,170994,170995,170996,170999,170999,171001,171001,171002,171003,171003,171005,171005,171005,171005,171005,171005,171005,171005,171006,171007,171008,171008,171008,171008,171008,171008,171014,171014,171014,171014,171014,171014,171014,171014,171022,171023,171025,171030,171033,171033,171037,171038,171038,171038,171039,171039,171039,171039,171039,171039,171039,171039,171041,171041,171044,171048,171049,171056,171056,171064,171070,171074,171074,171084,171084,171084,171086,171086,171086,171086,171088,171091,171094,171098,171099,171099,171099,171099,171105,171106,171113,171114,171114,171118,171134,171134,171134,171139,171143,171143,171156,171156,171156,171156,171156,171156,171156,171166,171170,171173,171174,171178,171178,171183,171185,171186,171186,171187,171190,171190,171198,171199,171203,171203,171203,171204,171213,171214,171219,171220,171222,171222,171224,171225,171228,171232,171232,171235,171237,171237,171237,171237,171241,171243,171245,171250,171252,171261,171263,171266,171268,171268,171273,171273,171273,171274,171278,171280,171280,171281,171281,171281,171281,171281,171282,171284,171284,171287,171293,171296,171296,171296,171296,171296,171301,171301,171307,171307,171309,171310,171313,171314,171314,171316,171319,171319,171319,171323,171324,171324,171324,171324,171326,171332,171339,171341,171346,171347,171353,171353,171353,171353,171353,171359,171359,171359,171360,171360,171361,171369,171376,171383,171383,171383,171385,171388,171393,171395,171396,171396,171396,171397,171398,171398,171398,171399,171399,171404,171413,171415,171415,171415,171415,171418,171418,171418,171430,171434,171434,171438,171438,171446,171446,171446,171447,171447,171447,171447,171447,171449,171451,171454,171457,171457,171465,171465,171466,171470,171477,171479,171480,171484,171484,171484,171484,171484,171487,171488,171491,171491,171494,171498,171499,171499,171499,171500,171500,171502,171505,171507,171509,171512,171513,171513,171513,171513,171513,171513,171514,171514,171514,171515,171518,171518,171518,171521,171526,171526,171526,171526,171526,171528,171528,171529,171530,171530,171530,171531,171531,171531,171532,171532,171533,171533,171533,171537,171537,171537,171537,171538,171538,171539,171539,171539,171539,171539,171539,171539,171542,171543,171543,171543,171543,171543,171543,171543,171543,171544,171544,171545,171547,171547,171547,171547,171547,171547,171548,171548,171549,171549,171549,171549,171550,171557,171558,171558,171558,171560,171561,171562,171563,171564,171569,171572,171576,171577,171578,171578,171578,171579,171579,171581,171581,171581,171581,171581,171581,171591,171596,171598,171598,171599,171600,171604,171604,171604,171606,171606,171607,171607,171608,171608,171608,171608,171608,171608,171608,171608,171608,171608,171608,171608,171609,171609,171609,171609,171614,171614,171616,171616,171616,171616,171617,171617,171618,171618,171618,171618,171619,171619,171619,171619,171619,171620,171621,171621,171621,171622,171622,171622,171622,171627,171629,171632,171635,171635,171635,171636,171636,171636,171636,171636,171636,171637,171638,171639,171640,171640,171640,171640,171640,171641,171642,171644,171645,171646,171656,171656,171656,171656,171656,171656,171656,171657,171657,171657,171657,171660,171662,171673,171676,171676,171678,171680,171681,171681,171683,171683,171684,171697,171697,171697,171697,171697,171698,171703,171703,171704,171704,171704,171707,171713,171713,171714,171714,171717,171722,171722,171722,171722,171728,171729,171729,171730,171735,171735,171735,171735,171735,171736,171736,171736,171740,171741,171745,171745,171746,171747,171747,171752,171753,171753,171753,171753,171753,171753,171753,171753,171754,171754,171755,171756,171756,171756,171756,171759,171760,171761,171762,171762,171763,171763,171765,171768,171770,171770,171770,171770,171770,171771,171771,171772,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171780,171782,171786,171786,171788,171789,171792,171793,171793,171796,171796,171802,171802,171803,171807,171807,171807,171813,171814,171815,171815,171819,171819,171819,171822,171822,171822,171827,171827,171828,171831,171833,171833,171833,171834,171835,171838,171839,171839,171840,171842,171843,171846,171857,171859,171869,171869,171872,171883,171890,171890,171891,171891,171893,171898,171898,171898,171898,171898,171898,171898,171898,171900,171906,171906,171906,171909,171914,171914,171917,171920,171921,171922,171922,171923,171923,171925,171925,171927,171927,171936,171937,171938,171938,171938,171938,171938,171938,171938,171939,171941,171941,171941,171942,171942,171944,171946,171946,171946,171949,171949,171949,171949,171951,171951,171951,171953,171955,171957,171957,171961,171961,171963,171964,171967,171968,171968,171971,171973,171974,171975,171975,171975,171983,171983,171985,171989,171989,171989,171989,171989,171989,171989,171991,171992,171992,171999,172002,172003,172005,172006,172008,172013,172014,172015,172016,172017,172018,172018,172021,172021,172022,172024,172026,172026,172026,172026,172026,172026,172026,172028,172037,172038,172039,172039,172040,172040,172046,172046,172047,172052,172053,172056,172057,172058,172058,172061,172062,172066,172069,172069,172074,172076,172078,172083,172091,172091,172091,172092,172093,172093,172093,172093,172093,172094,172094,172094,172094,172096,172100,172100,172101,172101,172104,172107,172108,172112,172113,172113,172113,172115,172117,172117,172118,172118,172119,172120,172124,172126,172126,172127,172129,172129,172130,172132,172132,172132,172133,172136,172136,172136,172140,172140,172140,172146,172149,172149,172151,172151,172151,172155,172156,172156,172161,172170,172179,172180,172184,172184,172184,172191,172192,172192,172195,172197,172201,172201,172207,172208,172214,172214,172214,172214,172214,172240,172251,172251,172254,172255,172257,172259,172260,172263,172265,172269,172270,172271,172274,172274,172274,172274,172275,172277,172280,172280,172281,172281,172281,172282,172282,172284,172293,172296,172298,172299,172301,172301,172304,172307,172313,172314,172314,172315,172315,172316,172316,172317,172319,172322,172324,172328,172328,172330,172330,172331,172332,172332,172332,172332,172332,172332,172351,172359,172363,172364,172364,172366,172369,172370,172374,172375,172376,172385,172385,172385,172385,172385,172386,172386,172386,172386,172390,172390,172391,172393,172395,172397,172397,172397,172397,172397,172408,172410,172410,172410,172413,172413,172414,172418,172422,172427,172427,172428,172431,172437,172446,172448,172456,172456,172456,172457,172458,172463,172466,172474,172476,172481,172481,172481,172485,172488,172493,172495,172495,172495,172498,172498,172499,172501,172501,172501,172504,172504,172504,172508,172509,172514,172514,172514,172514,172514,172514,172514,172518,172525,172526,172533,172533,172541,172546,172547,172548,172554,172554,172558,172558,172564,172566,172567,172570,172573,172577,172577,172578,172584,172588,172590,172590,172596,172599,172599,172599,172599,172599,172604,172606,172606,172606,172606,172606,172609,172609,172611,172612,172613,172613,172613,172613,172613,172618,172623,172623,172623,172625,172625,172641,172643,172643,172643,172646,172647,172656,172656,172657,172665,172665,172667,172667,172679,172679,172679,172679,172687,172694,172695,172695,172695,172696,172696,172696,172697,172699,172702,172702,172707,172709,172710,172714,172714,172714,172714,172726,172727,172730,172738,172740,172740,172740,172740,172740,172753,172755,172755,172755,172757,172758,172758,172758,172758,172758,172762,172766,172767,172781,172783,172789,172801,172811,172811,172811,172811,172813,172814,172814,172814,172814,172814,172814,172816,172816,172816,172822,172827,172828,172829,172829,172829,172829,172830,172830,172830,172830,172831,172831,172842,172844,172855,172859,172864,172865,172869,172870,172870,172876,172898,172903,172904,172911,172911,172911,172913,172914,172914,172914,172914,172914,172914,172914,172914,172914,172914,172914,172914,172915,172916,172921,172922,172925,172929,172929,172929,172935,172935,172935,172935,172937,172943,172944,172945,172946,172948,172958,172965,172969,172970,172970,172975,172981,172981,172982,172985,172987,172987,172987,172987,172987,172987,172987,172987,172987,172994,172994,172994,172997,173000,173000,173000,173000,173002,173002,173002,173002,173002,173002,173003,173003,173006,173010,173011,173013,173013,173013,173014,173016,173016,173016,173016,173017,173022,173023,173027,173037,173037,173039,173040,173044,173048,173059,173059,173061,173063,173063,173064,173064,173076,173076,173080,173082,173084,173084,173084,173084,173084,173084,173084,173087,173087,173090,173090,173091,173098,173103,173103,173106,173112,173112,173114,173114,173114,173114,173114,173116,173117,173117,173117,173117,173122,173125,173125,173125,173126,173128,173131,173131,173135,173135,173138,173141,173142,173142,173142,173142,173142,173143,173143,173145,173148,173149,173149,173149,173151,173151,173156,173157,173167,173171,173171,173177,173180,173184,173187,173199,173199,173203,173205,173209,173213,173213,173213,173213,173215,173215,173226,173226,173231,173234,173235,173237,173237,173238,173240,173240,173240,173240,173259,173272,173278,173289,173295,173295,173295,173295,173295,173296,173300,173302,173313,173313,173314,173314,173317,173320,173321,173321,173321,173321,173335,173342,173342,173345,173345,173346,173346,173346,173346,173346,173347,173349,173353,173356,173361,173373,173377,173379,173381,173381,173385,173385,173396,173400,173401,173403,173403,173403,173406,173407,173410,173413,173413,173414,173415,173417,173417,173417,173417,173417,173417,173421,173422,173425,173425,173425,173437,173437,173437,173437,173437,173437,173437,173438,173438,173439,173440,173443,173443,173443,173446,173446,173451,173456,173457,173463,173473,173476,173479,173483,173483,173483,173504,173504,173505,173505,173513,173513,173513,173513,173513,173523,173523,173523,173532,173532,173532,173532,173532,173533,173533,173535,173535,173536,173540,173544,173544,173544,173550,173553,173559,173559,173561,173564,173566,173573,173573,173576,173577,173578,173579,173596,173600,173603,173607,173609,173614,173620,173621,173624,173627,173630,173634,173634,173638,173638,173638,173638,173639,173639,173639,173639,173639,173640,173644,173644,173645,173645,173652,173652,173654,173667,173671,173671,173672,173672,173672,173676,173677,173677,173680,173682,173687,173689,173689,173696,173698,173698,173702,173702,173702,173702,173702,173702,173702,173705,173714,173726,173726,173726,173726,173727,173733,173733,173734,173735,173735,173735,173735,173735,173735,173735,173735,173735,173735,173736,173736,173736,173736,173736,173736,173737,173737,173738,173738,173738,173738,173738,173738,173739,173739,173739,173739,173739,173739,173739,173739,173739,173741,173741,173742,173742,173742,173744,173744,173745,173745,173745,173745,173745,173745,173745,173746,173746,173747,173750,173751,173755,173757,173759,173760,173760,173764,173766,173767,173773,173775,173775,173778,173779,173779,173779,173780,173780,173780,173780,173783,173784,173784,173784,173785,173785,173785,173785,173785,173785,173785,173785,173785,173786,173786,173786,173786,173787,173787,173787,173787,173787,173787,173788,173788,173789,173789,173789,173790,173790,173790,173790,173792,173792,173794,173794,173796,173796,173797,173798,173800,173800,173800,173800,173800,173800,173800,173800,173800,173800,173800,173800,173804,173804,173804,173804,173808,173808,173808,173808,173808,173808,173808,173808,173808,173808,173810,173810,173812,173812,173813,173813,173813,173813,173813,173813,173813,173813,173815,173815,173818,173818,173819,173819,173819,173819,173819,173819,173819,173819,173819,173819,173820,173823,173823,173828,173829,173829,173832,173832,173832,173832,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173833,173837,173839,173839,173839,173839,173841,173842,173842,173843,173843,173843,173844,173844,173844,173845,173845,173845,173845,173845,173845,173846,173847,173852,173853,173853,173853,173853,173853,173853,173854,173854,173854,173854,173855,173856,173856,173856,173856,173856,173856,173856,173856,173856,173856,173856,173856,173856,173856,173856,173860,173860,173861,173862,173864,173865,173865,173865,173865,173865,173865,173865,173865,173866,173866,173866,173866,173866,173868,173869,173870,173870,173871,173871,173871,173871,173874,173878,173879,173882,173883,173886,173890,173891,173891,173891,173891,173891,173892,173896,173896,173896,173898,173899,173899,173899,173899,173901,173901,173901,173904,173907,173907,173911,173911,173912,173912,173912,173912,173914,173914,173917,173917,173917,173919,173919,173919,173922,173922,173926,173927,173931,173931,173934,173941,173941,173941,173941,173941,173943,173943,173944,173944,173945,173946,173946,173946,173952,173955,173956,173956,173957,173957,173957,173957,173962,173962,173968,173968,173968,173970,173971,173971,173972,173972,173972,173973,173973,173973,173975,173979,173979,173982,173983,173983,173985,173986,173987,173988,173990,173990,173993,173993,173994,173994,173994,173994,173994,173994,173995,173996,173996,173996,173996,173997,173997,173997,173997,174001,174003,174003,174005,174005,174008,174008,174008,174012,174016,174016,174017,174022,174025,174026,174026,174026,174026,174026,174026,174026,174026,174026,174028,174030,174032,174032,174032,174032,174032,174034,174034,174034,174038,174038,174038,174039,174041,174045,174046,174047,174049,174049,174055,174057,174061,174065,174065,174069,174069,174073,174073,174073,174074,174082,174083,174086,174101,174101,174106,174108,174108,174108,174108,174109,174109,174109,174109,174109,174111,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174113,174115,174115,174115,174115,174117,174117,174118,174118,174118,174118,174118,174119,174119,174119,174119,174120,174121,174122,174124,174124,174124,174127,174127,174128,174139,174144,174145,174147,174150,174150,174151,174151,174154,174154,174159,174160,174162,174165,174165,174165,174166,174169,174169,174169,174171,174174,174176,174176,174176,174176,174176,174176,174178,174180,174181,174181,174183,174185,174185,174188,174188,174188,174188,174188,174188,174188,174188,174189,174189,174189,174189,174189,174191,174191,174191,174201,174201,174201,174207,174207,174209,174214,174218,174220,174220,174227,174227,174229,174232,174232,174237,174237,174237,174242,174242,174242,174243,174244,174245,174254,174254,174254,174258,174258,174259,174259,174259,174261,174261,174263,174265,174265,174265,174268,174269,174269,174269,174269,174269,174270,174270,174272,174272,174272,174272,174272,174272,174272,174274,174274,174274,174274,174274,174283,174283,174294,174302,174305,174306,174307,174307,174307,174307,174307,174314,174314,174314,174314,174315,174316,174316,174318,174318,174318,174318,174318,174325,174325,174333,174333,174333,174337,174339,174339,174342,174342,174345,174360,174369,174372,174372,174375,174376,174378,174378,174379,174379,174379,174379,174379,174379,174379,174381,174382,174383,174384,174384,174386,174386,174386,174386,174386,174387,174390,174390,174390,174395,174408,174411,174411,174411,174413,174423,174424,174424,174424,174424,174424,174424,174424,174424,174424,174424,174424,174424,174426,174426,174428,174433,174433,174439,174444,174444,174451,174451,174451,174451,174453,174454,174461,174461,174461,174461,174462,174464,174464,174466,174466,174466,174466,174466,174469,174471,174473,174476,174477,174479,174479,174480,174484,174484,174485,174485,174485,174485,174491,174495,174499,174499,174500,174501,174501,174501,174501,174506,174511,174511,174511,174513,174516,174523,174531,174537,174543,174543,174543,174545,174546,174546,174546,174546,174554,174554,174554,174554,174554,174554,174554,174555,174556,174557,174558,174558,174558,174558,174558,174562,174563,174563,174563,174563,174563,174563,174563,174563,174563,174564,174565,174567,174570,174570,174570,174571,174573,174574,174575,174576,174578,174583,174583,174583,174583,174588,174598,174598,174598,174598,174598,174598,174608,174614,174614,174614,174614,174622,174622,174628,174629,174629,174629,174630,174630,174631,174634,174634,174643,174643,174649,174650,174650,174657,174657,174657,174658,174661,174661,174661,174661,174663,174665,174665,174666,174666,174666,174666,174669,174673,174673,174675,174678,174686,174686,174686,174686,174686,174691,174693,174693,174693,174694,174696,174702,174708,174710,174711,174711,174711,174718,174721,174722,174727,174729,174739,174743,174753,174753,174753,174753,174758,174758,174758,174762,174766,174766,174772,174772,174773,174778,174781,174782,174784,174786,174793,174798,174801,174801,174805,174809,174811,174811,174817,174817,174817,174818,174819,174822,174822,174824,174824,174825,174827,174827,174829,174829,174833,174834,174836,174837,174839,174841,174842,174844,174845,174845,174845,174845,174847,174851,174851,174851,174854,174861,174867,174869,174875,174876,174885,174885,174903,174903,174915,174917,174917,174917,174917,174922,174922,174922,174924,174924,174932,174935,174935,174936,174938,174938,174939,174943,174943,174943,174944,174944,174950,174951,174951,174955,174956,174964,174965,174965,174970,174970,174970,174974,174975,174975,174975,174980,174986,174986,174986,174990,174991,174994,175005,175005,175005,175005,175009,175011,175014,175025,175025,175036,175036,175036,175038,175038,175038,175038,175038,175039,175046,175047,175048,175048,175048,175048,175048,175048,175048,175051,175053,175053,175053,175057,175059,175061,175062,175062,175062,175064,175064,175066,175072,175073,175078,175078,175082,175082,175085,175085,175088,175095,175100,175100,175100,175101,175105,175105,175105,175111,175111,175120,175122,175137,175139,175141,175155,175158,175158,175158,175158,175158,175160,175162,175162,175166,175166,175168,175168,175169,175169,175169,175169,175172,175175,175176,175176,175176,175176,175182,175182,175184,175187,175188,175191,175191,175191,175194,175196,175203,175203,175210,175212,175222,175222,175222,175222,175222,175222,175222,175224,175225,175225,175226,175226,175226,175226,175226,175226,175226,175226,175234,175234,175241,175241,175246,175246,175259,175262,175265,175265,175265,175265,175265,175265,175265,175266,175267,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175269,175271,175280,175283,175283,175283,175283,175283,175283,175283,175283,175283,175283,175283,175283,175283,175283,175283,175284,175284,175284,175286,175286,175286,175286,175286,175291,175295,175297,175297,175297,175297,175297,175297,175297,175297,175299,175299,175301,175302,175303,175311,175312,175312,175312,175312,175312,175312,175313,175317,175317,175317,175320,175321,175321,175321,175324,175327,175334,175334,175335,175335,175335,175335,175343,175343,175343,175345,175346,175346,175346,175346,175346,175347,175347,175349,175352,175353,175355,175356,175357,175357,175357,175357,175360,175362,175362,175365,175365,175366,175366,175367,175367,175371,175371,175372,175372,175372,175372,175372,175381,175383,175383,175386,175390,175390,175390,175394,175397,175401,175401,175401,175401,175401,175401,175401,175404,175404,175404,175404,175404,175404,175404,175404,175405,175405,175407,175407,175407,175407,175407,175408,175409,175411,175411,175411,175413,175413,175413,175414,175417,175418,175420,175420,175420,175420,175420,175420,175423,175433,175436,175437,175444,175445,175447,175452,175452,175452,175452,175457,175457,175458,175460,175469,175469,175469,175470,175470,175470,175470,175470,175470,175472,175477,175477,175477,175483,175483,175483,175483,175483,175484,175485,175485,175489,175493,175493,175493,175498,175500,175504,175504,175504,175509,175509,175510,175511,175512,175515,175515,175518,175518,175518,175518,175518,175518,175518,175518,175524,175524,175536,175537,175538,175539,175539,175539,175540,175540,175540,175543,175544,175545,175547,175548,175549,175551,175551,175551,175556,175556,175556,175556,175557,175557,175557,175557,175557,175557,175557,175560,175565,175565,175565,175565,175565,175571,175586,175586,175586,175586,175586,175588,175588,175589,175592,175595,175595,175595,175611,175611,175611,175615,175616,175616,175616,175616,175632,175632,175645,175645,175645,175646,175652,175662,175662,175664,175664,175664,175666,175666,175666,175666,175666,175666,175666,175675,175682,175682,175688,175689,175689,175690,175690,175690,175690,175690,175690,175690,175690,175695,175695,175696,175696,175696,175696,175697,175699,175699,175699,175701,175704,175707,175707,175708,175708,175711,175715,175715,175719,175721,175724,175727,175730,175732,175738,175742,175746,175750,175752,175757,175757,175757,175759,175768,175768,175769,175769,175769,175770,175771,175773,175773,175774,175777,175780,175783,175783,175784,175789,175790,175795,175796,175796,175796,175800,175800,175802,175802,175802,175810,175812,175812,175812,175812,175816,175817,175817,175822,175823,175827,175837,175837,175839,175843,175843,175843,175843,175847,175848,175849,175849,175851,175851,175851,175851,175851,175852,175852,175852,175852,175852,175852,175855,175855,175858,175860,175867,175875,175885,175886,175886,175886,175894,175894,175900,175911,175911,175911,175911,175911,175914,175919,175920,175921,175924,175925,175929,175931,175939,175939,175939,175942,175942,175943,175943,175943,175950,175950,175950,175961,175961,175961,175961,175961,175963,175966,175966,175966,175966,175967,175968,175971,175977,175977,175977,175977,175977,175977,175977,175977,175977,175978,175978,175980,175981,175981,175981,175981,175982,175982,175982,175982,175982,175982,175982,175982,175985,175988,175988,175988,175988,175988,175988,175988,175988,175988,175990,175992,175995,175998,176001,176001,176002,176002,176004,176007,176008,176009,176009,176009,176009,176010,176011,176011,176016,176021,176022,176022,176022,176022,176022,176022,176022,176022,176024,176033,176035,176035,176039,176042,176044,176046,176048,176050,176054,176056,176057,176057,176059,176071,176071,176080,176083,176083,176090,176090,176090,176090,176091,176091,176098,176098,176099,176101,176103,176106,176110,176110,176110,176114,176114,176114,176114,176115,176115,176115,176117,176119,176119,176119,176120,176123,176126,176128,176132,176133,176133,176134,176137,176138,176138,176139,176141,176141,176141,176141,176141,176141,176142,176142,176143,176143,176143,176143,176143,176144,176144,176144,176144,176147,176147,176147,176153,176155,176157,176157,176161,176161,176161,176165,176169,176171,176171,176171,176172,176173,176173,176174,176178,176179,176181,176181,176182,176184,176184,176184,176186,176190,176194,176201,176202,176202,176202,176206,176210,176212,176213,176213,176213,176213,176213,176214,176214,176214,176214,176214,176214,176214,176214,176214,176214,176214,176215,176216,176224,176224,176234,176238,176238,176240,176240,176244,176247,176251,176251,176252,176252,176252,176252,176253,176253,176257,176257,176257,176257,176257,176257,176261,176261,176261,176262,176266,176266,176266,176266,176266,176266,176266,176266,176273,176277,176278,176278,176281,176281,176284,176293,176294,176298,176299,176301,176301,176302,176302,176302,176302,176302,176302,176303,176303,176303,176303,176303,176303,176303,176303,176305,176305,176305,176305,176306,176307,176308,176308,176314,176314,176316,176316,176318,176318,176318,176318,176318,176318,176318,176318,176318,176321,176321,176322,176323,176332,176332,176332,176332,176332,176332,176332,176332,176333,176337,176337,176341,176351,176353,176353,176353,176356,176356,176356,176357,176357,176361,176365,176365,176370,176370,176372,176372,176373,176373,176379,176383,176383,176389,176394,176406,176406,176406,176414,176418,176423,176427,176432,176445,176450,176453,176456,176461,176461,176464,176464,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176465,176466,176466,176466,176466,176466,176468,176468,176468,176468,176468,176468,176468,176468,176469,176469,176471,176471,176472,176472,176472,176473,176475,176478,176479,176480,176480,176480,176480,176480,176480,176480,176480,176480,176480,176480,176480,176482,176482,176483,176483,176483,176483,176483,176483,176484,176485,176485,176485,176485,176485,176486,176486,176486,176486,176486,176486,176487,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176488,176489,176489,176489,176489,176489,176489,176490,176490,176491,176491,176493,176493,176493,176493,176493,176493,176494,176495,176495,176495,176495,176495,176495,176495,176495,176495,176495,176495,176495,176495,176497,176498,176498,176500,176500,176500,176500,176500,176500,176502,176502,176502,176502,176502,176502,176503,176505,176505,176505,176505,176506,176507,176507,176507,176509,176509,176509,176509,176509,176509,176510,176511,176512,176513,176513,176513,176513,176516,176516,176516,176516,176516,176516,176517,176517,176517,176520,176520,176520,176520,176520,176521,176526,176527,176527,176527,176527,176527,176529,176531,176532,176532,176534,176537,176537,176537,176537,176537,176537,176537,176537,176538,176539,176540,176542,176543,176543,176547,176547,176547,176549,176551,176551,176551,176551,176551,176551,176552,176554,176554,176554,176554,176554,176555,176555,176556,176559,176562,176563,176563,176563,176563,176564,176565,176566,176566,176567,176569,176570,176570,176570,176571,176571,176571,176574,176574,176576,176580,176582,176582,176585,176588,176588,176588,176588,176588,176588,176589,176592,176592,176592,176592,176592,176594,176598,176600,176602,176602,176602,176602,176602,176602,176605,176607,176609,176609,176609,176609,176610,176612,176615,176617,176617,176617,176621,176621,176621,176623,176623,176628,176629,176629,176633,176633,176634,176636,176636,176636,176636,176636,176637,176646,176648,176651,176652,176652,176653,176653,176654,176657,176657,176657,176658,176658,176658,176658,176658,176663,176665,176666,176667,176673,176674,176674,176676,176677,176677,176677,176678,176678,176680,176680,176680,176682,176682,176682,176683,176686,176686,176693,176694,176696,176696,176696,176696,176696,176696,176699,176701,176702,176702,176703,176706,176711,176711,176711,176719,176720,176723,176723,176740,176740,176740,176742,176742,176746,176754,176760,176760,176761,176761,176766,176767,176768,176771,176772,176773,176773,176774,176777,176781,176787,176787,176787,176787,176787,176792,176792,176792,176796,176797,176798,176798,176799,176802,176802,176804,176806,176808,176808,176808,176808,176808,176808,176808,176808,176808,176808,176808,176808,176808,176809,176809,176809,176809,176813,176813,176813,176813,176816,176821,176821,176821,176822,176822,176822,176828,176830,176838,176839,176846,176852,176852,176852,176852,176854,176857,176860,176861,176861,176861,176867,176867,176867,176869,176869,176869,176869,176870,176870,176870,176870,176882,176882,176882,176882,176885,176885,176899,176899,176899,176899,176902,176907,176907,176910,176910,176911,176911,176920,176921,176922,176922,176922,176922,176922,176922,176922,176922,176922,176923,176924,176924,176927,176927,176929,176929,176936,176938,176941,176952,176953,176957,176957,176958,176958,176960,176967,176967,176967,176967,176967,176969,176970,176971,176971,176971,176971,176973,176976,176976,176976,176976,176976,176977,176979,176979,176979,176983,176983,176983,176983,176983,176983,176983,176983,176989,176989,176990,176990,176995,176995,176996,176996,176997,176998,177000,177002,177002,177003,177003,177003,177003,177003,177005,177007,177007,177007,177010,177011,177011,177011,177011,177012,177012,177012,177013,177013,177019,177023,177023,177026,177026,177026,177026,177026,177026,177029,177042,177043,177043,177045,177050,177050,177050,177050,177050,177050,177050,177050,177050,177050,177051,177051,177051,177051,177054,177054,177055,177055,177056,177056,177056,177056,177057,177057,177064,177064,177064,177064,177064,177064,177064,177071,177081,177081,177084,177084,177094,177095,177095,177095,177095,177095,177095,177111,177111,177111,177111,177111,177111,177111,177112,177116,177116,177117,177117,177117,177117,177117,177117,177117,177118,177118,177121,177121,177121,177123,177123,177123,177125,177125,177125,177125,177125,177125,177126,177129,177131,177131,177131,177131,177131,177131,177132,177132,177145,177149,177149,177151,177151,177152,177152,177153,177159,177159,177166,177166,177174,177176,177181,177182,177184,177185,177190,177199,177199,177199,177199,177200,177205,177205,177207,177208,177209,177209,177209,177210,177210,177210,177211,177211,177214,177215,177215,177215,177215,177215,177217,177217,177220,177220,177220,177220,177221,177223,177224,177224,177228,177228,177230,177231,177232,177234,177234,177235,177236,177252,177252,177254,177257,177258,177258,177258,177258,177258,177264,177264,177264,177264,177264,177268,177272,177272,177272,177272,177272,177272,177273,177273,177278,177279,177284,177284,177284,177284,177284,177284,177284,177284,177285,177285,177288,177291,177291,177293,177298,177298,177304,177305,177307,177307,177307,177308,177308,177308,177311,177314,177316,177317,177320,177323,177329,177329,177329,177330,177332,177335,177337,177340,177340,177340,177340,177341,177341,177341,177341,177341,177341,177341,177341,177342,177342,177342,177343,177343,177343,177343,177343,177343,177343,177343,177343,177344,177344,177344,177344,177344,177344,177344,177344,177344,177344,177344,177347,177348,177349,177352,177352,177353,177353,177353,177354,177354,177356,177358,177358,177362,177364,177374,177386,177386,177387,177387,177387,177394,177394,177394,177394,177394,177394,177394,177394,177396,177397,177399,177399,177399,177400,177400,177400,177401,177401,177407,177409,177409,177410,177412,177412,177412,177412,177413,177413,177416,177416,177416,177416,177419,177419,177419,177420,177424,177424,177424,177425,177425,177425,177425,177425,177430,177432,177432,177432,177434,177435,177435,177435,177435,177437,177437,177437,177437,177437,177438,177439,177439,177439,177440,177446,177452,177452,177452,177453,177454,177454,177454,177457,177464,177465,177465,177466,177466,177466,177466,177466,177466,177467,177468,177473,177474,177474,177474,177474,177474,177477,177480,177480,177480,177480,177480,177480,177484,177484,177487,177491,177500,177500,177507,177507,177507,177507,177507,177511,177511,177511,177513,177520,177520,177520,177520,177520,177526,177527,177527,177527,177528,177528,177529,177530,177531,177531,177533,177533,177535,177535,177535,177536,177537,177537,177537,177539,177539,177539,177539,177539,177539,177539,177540,177542,177546,177549,177549,177549,177549,177549,177549,177549,177549,177549,177549,177549,177549,177549,177550,177553,177554,177554,177554,177554,177554,177556,177556,177560,177560,177560,177560,177560,177560,177560,177562,177563,177566,177566,177566,177567,177567,177568,177571,177571,177572,177572,177572,177572,177572,177572,177576,177576,177580,177584,177590,177593,177594,177594,177601,177602,177611,177611,177611,177614,177614,177614,177614,177614,177614,177614,177619,177643,177646,177647,177653,177654,177654,177655,177656,177658,177659,177659,177660,177660,177664,177664,177671,177671,177671,177680,177683,177686,177686,177686,177695,177698,177699,177700,177701,177712,177712,177712,177712,177712,177716,177721,177725,177730,177730,177737,177737,177738,177739,177739,177741,177746,177749,177751,177751,177752,177752,177752,177755,177759,177761,177761,177761,177761,177761,177761,177763,177766,177766,177766,177766,177769,177770,177770,177770,177770,177770,177770,177771,177772,177772,177775,177775,177775,177775,177776,177776,177776,177776,177777,177777,177777,177783,177783,177783,177784,177784,177788,177788,177793,177797,177799,177799,177799,177800,177801,177801,177801,177801,177805,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177811,177815,177819,177823,177823,177824,177824,177827,177827,177830,177832,177840,177840,177840,177844,177852,177852,177852,177852,177853,177855,177857,177858,177858,177858,177868,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177869,177870,177870,177870,177870,177870,177870,177870,177870,177870,177870,177870,177872,177873,177873,177873,177873,177877,177880,177880,177880,177880,177881,177881,177883,177884,177884,177884,177884,177884,177886,177886,177886,177887,177888,177888,177893,177893,177894,177894,177894,177894,177895,177895,177895,177895,177895,177897,177898,177899,177905,177905,177905,177905,177907,177907,177913,177914,177914,177920,177924,177929,177929,177930,177930,177931,177933,177933,177933,177934,177934,177934,177934,177936,177939,177940,177941,177941,177942,177943,177943,177943,177943,177943,177943,177946,177947,177947,177948,177948,177948,177949,177949,177949,177949,177950,177950,177952,177953,177955,177955,177956,177956,177961,177961,177962,177966,177966,177967,177968,177972,177973,177973,177974,177974,177974,177978,177978,177981,177984,177984,177986,177986,177995,177995,177999,177999,178000,178002,178008,178012,178012,178012,178014,178015,178017,178017,178020,178020,178020,178020,178027,178028,178028,178028,178028,178030,178034,178034,178036,178039,178039,178042,178042,178043,178043,178046,178049,178051,178051,178051,178054,178054,178056,178056,178059,178059,178059,178060,178061,178062,178062,178064,178065,178065,178065,178065,178065,178065,178065,178065,178065,178065,178065,178066,178066,178066,178066,178066,178066,178066,178066,178067,178067,178067,178067,178067,178067,178067,178067,178067,178067,178068,178071,178071,178071,178074,178076,178077,178079,178084,178086,178088,178092,178092,178093,178094,178096,178097,178097,178100,178107,178107,178108,178110,178110,178111,178111,178111,178111,178114,178120,178120,178123,178124,178130,178130,178130,178130,178133,178133,178133,178138,178140,178140,178140,178140,178140,178144,178144,178148,178152,178152,178154,178154,178158,178158,178158,178161,178161,178165,178167,178168,178172,178184,178184,178184,178184,178185,178191,178193,178196,178199,178211,178211,178214,178218,178218,178225,178228,178228,178228,178228,178228,178230,178230,178230,178230,178231,178235,178235,178235,178235,178235,178241,178242,178243,178247,178249,178250,178252,178253,178253,178253,178253,178253,178256,178256,178257,178259,178259,178260,178262,178262,178262,178264,178264,178265,178265,178267,178268,178268,178268,178269,178270,178280,178280,178282,178284,178285,178286,178286,178286,178286,178286,178288,178288,178290,178290,178291,178291,178291,178291,178291,178291,178291,178294,178294,178294,178294,178294,178298,178299,178305,178305,178305,178305,178305,178305,178306,178306,178308,178311,178311,178317,178317,178317,178325,178326,178332,178332,178332,178337,178337,178337,178337,178338,178338,178338,178338,178341,178341,178341,178341,178342,178343,178345,178346,178347,178348,178348,178348,178348,178350,178350,178353,178353,178353,178353,178353,178354,178354,178359,178359,178360,178360,178360,178360,178360,178366,178368,178368,178373,178373,178377,178379,178384,178384,178392,178392,178397,178400,178401,178401,178401,178401,178405,178405,178405,178405,178405,178405,178405,178405,178406,178406,178406,178407,178408,178408,178408,178411,178411,178411,178412,178412,178412,178414,178414,178414,178422,178422,178422,178422,178424,178425,178425,178425,178425,178425,178425,178425,178427,178427,178428,178429,178436,178449,178452,178458,178458,178458,178466,178471,178473,178473,178478,178480,178480,178480,178480,178485,178487,178489,178489,178489,178489,178491,178495,178495,178500,178510,178510,178514,178516,178522,178531,178536,178542,178542,178542,178542,178543,178543,178543,178543,178545,178545,178546,178546,178546,178548,178550,178553,178556,178556,178556,178558,178560,178561,178566,178571,178573,178573,178575,178576,178576,178576,178577,178581,178587,178587,178587,178587,178587,178589,178595,178597,178604,178604,178605,178605,178606,178610,178612,178612,178612,178612,178612,178612,178621,178621,178623,178625,178625,178626,178627,178627,178628,178628,178628,178628,178628,178628,178628,178629,178629,178633,178634,178636,178639,178639,178644,178650,178653,178653,178653,178653,178656,178657,178663,178663,178663,178665,178666,178676,178676,178679,178681,178683,178683,178683,178686,178693,178693,178697,178699,178699,178699,178701,178701,178702,178702,178702,178703,178703,178703,178705,178707,178707,178707,178707,178710,178710,178710,178710,178710,178710,178710,178710,178710,178710,178711,178711,178711,178711,178711,178711,178712,178712,178716,178716,178717,178717,178719,178719,178719,178719,178719,178719,178719,178720,178720,178720,178720,178721,178721,178722,178723,178724,178724,178728,178728,178728,178728,178730,178730,178731,178731,178733,178733,178736,178737,178742,178742,178742,178743,178743,178743,178749,178749,178749,178753,178753,178753,178753,178753,178754,178754,178754,178756,178756,178756,178756,178756,178756,178756,178756,178756,178757,178757,178757,178758,178758,178759,178760,178762,178762,178762,178763,178763,178763,178763,178763,178763,178763,178763,178763,178763,178763,178763,178763,178764,178764,178764,178765,178768,178769,178770,178771,178773,178773,178773,178773,178775,178775,178775,178775,178775,178777,178780,178780,178780,178781,178781,178781,178782,178783,178783,178783,178786,178787,178787,178787,178790,178790,178790,178791,178791,178792,178792,178792,178792,178792,178792,178792,178795,178799,178800,178800,178800,178801,178802,178804,178807,178807,178807,178807,178810,178811,178811,178812,178812,178813,178813,178813,178813,178813,178816,178818,178819,178830,178835,178841,178843,178843,178843,178850,178850,178850,178851,178857,178861,178863,178864,178866,178866,178866,178866,178866,178866,178867,178867,178867,178867,178867,178867,178867,178867,178868,178868,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178869,178870,178870,178870,178871,178871,178871,178871,178871,178871,178871,178872,178873,178873,178874,178874,178875,178876,178878,178879,178879,178879,178879,178880,178882,178883,178883,178883,178883,178883,178885,178885,178887,178887,178887,178891,178895,178897,178898,178898,178898,178898,178899,178899,178900,178901,178902,178904,178904,178904,178906,178910,178910,178911,178912,178912,178914,178914,178919,178926,178927,178933,178933,178934,178935,178939,178941,178942,178943,178943,178943,178943,178945,178946,178947,178950,178952,178952,178952,178953,178955,178955,178957,178958,178959,178966,178966,178966,178981,178981,178981,178981,178982,178982,178990,178990,178992,178994,178997,178997,179001,179001,179006,179006,179007,179007,179012,179015,179015,179015,179017,179020,179024,179030,179031,179031,179036,179037,179039,179040,179040,179041,179041,179041,179041,179041,179046,179047,179047,179047,179047,179048,179049,179051,179051,179052,179053,179054,179057,179057,179057,179057,179057,179057,179058,179058,179058,179058,179063,179063,179063,179069,179073,179073,179075,179075,179079,179079,179084,179090,179090,179097,179098,179104,179108,179108,179116,179117,179117,179127,179127,179127,179127,179127,179140,179140,179141,179142,179142,179142,179142,179144,179144,179144,179149,179155,179158,179161,179166,179175,179175,179179,179183,179184,179184,179186,179199,179199,179199,179199,179199,179210,179211,179211,179215,179217,179226,179234,179238,179238,179240,179244,179245,179245,179245,179253,179254,179257,179259,179266,179266,179266,179269,179275,179277,179277,179277,179282,179286,179301,179301,179301,179301,179303,179307,179311,179311,179314,179320,179321,179323,179331,179335,179342,179342,179342,179342,179346,179346,179347,179349,179351,179351,179351,179351,179354,179354,179356,179356,179356,179367,179367,179369,179371,179373,179379,179382,179382,179382,179382,179383,179384,179384,179384,179385,179385,179388,179388,179388,179388,179388,179389,179396,179398,179400,179403,179403,179403,179406,179407,179407,179410,179412,179413,179416,179416,179416,179418,179425,179425,179425,179425,179425,179426,179427,179427,179427,179431,179431,179436,179438,179440,179444,179444,179448,179452,179457,179460,179462,179463,179464,179468,179476,179481,179484,179487,179489,179489,179492,179496,179500,179510,179511,179511,179511,179511,179515,179519,179524,179529,179529,179529,179538,179539,179539,179539,179539,179541,179544,179544,179544,179547,179550,179551,179551,179553,179555,179555,179558,179559,179560,179560,179560,179566,179566,179566,179568,179569,179573,179582,179583,179583,179584,179584,179585,179586,179590,179592,179592,179594,179601,179601,179601,179601,179601,179602,179602,179606,179606,179609,179610,179611,179613,179616,179618,179625,179626,179626,179629,179632,179636,179638,179645,179654,179654,179655,179657,179657,179657,179660,179660,179660,179662,179667,179667,179667,179668,179670,179670,179672,179672,179684,179684,179684,179692,179696,179697,179698,179720,179723,179730,179743,179744,179744,179744,179746,179746,179756,179756,179756,179760,179760,179763,179765,179767,179769,179771,179771,179771,179776,179777,179782,179782,179782,179783,179783,179785,179785,179787,179795,179796,179799,179800,179800,179803,179807,179807,179807,179809,179809,179811,179811,179811,179814,179815,179835,179839,179839,179839,179841,179841,179841,179841,179848,179848,179849,179850,179851,179851,179852,179852,179852,179855,179855,179856,179858,179859,179859,179859,179863,179863,179868,179868,179878,179882,179883,179883,179883,179883,179883,179883,179883,179883,179883,179883,179883,179883,179883,179883,179883,179885,179885,179891,179891,179891,179901,179901,179901,179907,179907,179907,179907,179907,179907,179907,179909,179911,179911,179911,179911,179915,179915,179915,179920,179920,179920,179924,179924,179924,179924,179926,179927,179928,179929,179929,179929,179929,179930,179930,179930,179930,179930,179930,179930,179930,179930,179932,179932,179936,179936,179936,179936,179936,179936,179936,179938,179940,179940,179940,179940,179940,179940,179941,179941,179941,179942,179946,179946,179947,179948,179951,179954,179954,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179955,179956,179959,179960,179962,179964,179970,179971,179974,179975,179975,179982,179984,179984,179984,179984,179993,179994,179994,179996,180012,180015,180026,180026,180026,180030,180031,180034,180037,180038,180039,180043,180043,180044,180044,180049,180050,180050,180051,180053,180062,180063,180070,180073,180074,180074,180074,180074,180074,180074,180074,180075,180085,180086,180086,180086,180086,180088,180095,180102,180111,180111,180114,180114,180123,180124,180125,180125,180127,180127,180128,180128,180128,180128,180128,180131,180131,180137,180138,180139,180139,180140,180140,180142,180143,180146,180146,180146,180147,180151,180152,180152,180152,180153,180154,180154,180156,180156,180156,180157,180157,180157,180158,180159,180159,180159,180161,180161,180161,180162,180162,180163,180164,180169,180173,180177,180182,180184,180184,180184,180184,180184,180184,180194,180198,180198,180199,180199,180199,180199,180202,180205,180205,180205,180205,180205,180208,180208,180208,180209,180209,180209,180209,180209,180210,180210,180210,180210,180210,180210,180210,180210,180210,180211,180213,180213,180216,180219,180225,180225,180228,180236,180241,180251,180251,180251,180252,180257,180257,180257,180257,180257,180257,180257,180258,180262,180264,180265,180265,180270,180271,180272,180272,180272,180281,180281,180281,180282,180282,180283,180283,180286,180287,180288,180288,180289,180292,180292,180294,180294,180294,180294,180294,180294,180294,180294,180295,180295,180296,180300,180300,180300,180300,180300,180301,180301,180301,180306,180306,180307,180307,180310,180311,180314,180314,180314,180318,180322,180323,180323,180333,180334,180334,180350,180358,180365,180368,180369,180374,180377,180378,180382,180386,180398,180398,180398,180398,180398,180398,180400,180400,180400,180405,180412,180420,180420,180420,180421,180421,180421,180421,180424,180430,180432,180432,180440,180450,180451,180452,180452,180452,180457,180460,180463,180465,180466,180467,180468,180470,180470,180470,180470,180473,180473,180473,180473,180473,180474,180477,180477,180477,180477,180481,180482,180482,180482,180482,180483,180483,180483,180483,180483,180483,180484,180484,180484,180484,180485,180485,180485,180487,180487,180487,180487,180487,180489,180489,180490,180490,180490,180491,180491,180491,180493,180493,180496,180496,180497,180498,180498,180498,180498,180498,180498,180498,180499,180499,180499,180499,180500,180500,180500,180501,180505,180505,180505,180505,180505,180505,180507,180507,180507,180507,180507,180507,180509,180509,180509,180509,180511,180511,180511,180511,180511,180511,180515,180516,180516,180518,180519,180521,180521,180521,180521,180521,180521,180522,180522,180522,180522,180524,180524,180524,180525,180526,180526,180526,180526,180528,180529,180529,180529,180529,180531,180531,180533,180534,180534,180535,180535,180535,180535,180535,180535,180535,180535,180535,180535,180536,180539,180540,180540,180542,180542,180545,180545,180547,180548,180548,180549,180552,180552,180552,180552,180552,180552,180552,180552,180554,180556,180556,180556,180556,180557,180557,180557,180557,180557,180557,180558,180558,180558,180558,180562,180563,180567,180573,180573,180574,180576,180576,180579,180583,180589,180589,180589,180589,180589,180589,180589,180589,180589,180590,180590,180590,180590,180596,180596,180596,180596,180597,180599,180600,180600,180603,180603,180607,180607,180607,180607,180609,180609,180611,180611,180616,180624,180625,180628,180629,180633,180635,180643,180643,180646,180646,180646,180649,180652,180655,180660,180661,180666,180671,180675,180675,180675,180675,180675,180675,180675,180675,180675,180675,180675,180675,180678,180680,180681,180681,180681,180681,180681,180683,180683,180685,180686,180686,180686,180689,180694,180697,180699,180706,180707,180713,180718,180720,180724,180725,180725,180733,180738,180738,180739,180739,180739,180739,180739,180749,180759,180762,180762,180764,180778,180778,180778,180779,180780,180782,180782,180788,180788,180788,180788,180788,180789,180789,180792,180792,180797,180797,180797,180812,180814,180834,180836,180850,180851,180851,180851,180851,180851,180853,180855,180855,180866,180867,180868,180868,180870,180872,180872,180876,180876,180876,180878,180879,180879,180884,180884,180884,180890,180890,180890,180890,180893,180893,180894,180901,180904,180906,180908,180908,180908,180908,180910,180912,180913,180913,180913,180916,180916,180920,180921,180924,180930,180930,180936,180936,180936,180937,180937,180937,180937,180938,180943,180943,180943,180944,180944,180944,180944,180944,180947,180950,180951,180951,180951,180952,180952,180954,180955,180957,180958,180958,180958,180958,180958,180958,180961,180961,180963,180965,180965,180965,180965,180967,180973,180977,180978,180991,180992,180992,180992,180993,180993,180993,180993,180993,180993,181005,181015,181020,181025,181042,181042,181045,181045,181046,181046,181047,181047,181051,181051,181052,181052,181052,181052,181052,181052,181052,181052,181054,181055,181056,181056,181056,181057,181058,181060,181060,181062,181062,181062,181062,181062,181062,181062,181062,181063,181063,181063,181063,181063,181064,181064,181064,181065,181065,181065,181065,181066,181066,181066,181066,181066,181066,181068,181068,181068,181068,181069,181069,181070,181070,181070,181070,181070,181072,181072,181073,181073,181074,181075,181075,181076,181076,181078,181079,181079,181080,181081,181081,181084,181086,181086,181087,181090,181091,181096,181098,181099,181099,181101,181106,181107,181107,181107,181116,181121,181122,181122,181122,181122,181124,181128,181128,181129,181130,181133,181134,181135,181138,181142,181142,181142,181145,181146,181146,181146,181146,181149,181150,181151,181151,181154,181154,181154,181155,181157,181157,181164,181165,181175,181179,181179,181179,181179,181179,181179,181179,181179,181179,181179,181183,181185,181189,181189,181189,181192,181194,181194,181194,181195,181195,181199,181199,181199,181199,181199,181199,181199,181199,181199,181199,181199,181199,181199,181200,181200,181200,181200,181200,181200,181200,181200,181200,181200,181200,181201,181201,181201,181201,181201,181202,181202,181203,181203,181203,181203,181203,181204,181205,181205,181205,181205,181206,181206,181206,181207,181209,181209,181210,181210,181214,181214,181214,181214,181215,181215,181216,181216,181218,181218,181218,181222,181223,181223,181223,181224,181224,181224,181224,181224,181225,181225,181225,181225,181225,181226,181226,181227,181227,181227,181227,181227,181228,181228,181229,181229,181229,181230,181230,181230,181231,181231,181231,181231,181231,181231,181232,181232,181232,181232,181232,181232,181233,181234,181235,181235,181235,181235,181238,181238,181240,181242,181242,181243,181244,181244,181246,181248,181250,181250,181251,181252,181253,181254,181255,181255,181255,181258,181259,181259,181260,181260,181263,181266,181267,181269,181270,181270,181270,181270,181270,181271,181271,181271,181271,181271,181271,181271,181271,181271,181272,181272,181272,181272,181272,181272,181272,181273,181273,181273,181273,181273,181273,181273,181273,181273,181273,181273,181273,181273,181274,181275,181275,181275,181275,181275,181275,181277,181277,181277,181281,181281,181283,181284,181284,181284,181285,181294,181295,181295,181295,181295,181295,181296,181296,181296,181296,181298,181306,181307,181308,181309,181309,181309,181310,181310,181310,181310,181317,181318,181323,181328,181328,181328,181330,181345,181345,181345,181345,181349,181349,181349,181350,181351,181357,181361,181362,181363,181363,181365,181365,181365,181365,181366,181368,181368,181368,181368,181369,181370,181371,181372,181372,181374,181376,181376,181382,181385,181387,181389,181397,181397,181398,181404,181410,181413,181421,181424,181424,181424,181424,181424,181424,181426,181426,181426,181426,181432,181435,181435,181436,181440,181446,181449,181449,181449,181451,181451,181451,181451,181455,181458,181464,181467,181476,181476,181477,181477,181478,181479,181479,181481,181481,181481,181481,181482,181482,181482,181484,181484,181484,181485,181486,181486,181486,181486,181488,181488,181488,181489,181489,181489,181489,181491,181492,181492,181493,181494,181494,181497,181498,181508,181513,181513,181515,181519,181519,181519,181519,181519,181519,181519,181519,181521,181521,181524,181527,181528,181534,181534,181534,181536,181548,181556,181558,181558,181561,181561,181561,181569,181573,181579,181586,181589,181593,181597,181600,181602,181606,181606,181607,181608,181611,181614,181615,181617,181620,181624,181628,181632,181636,181640,181643,181643,181643,181653,181656,181658,181660,181661,181662,181662,181662,181666,181670,181672,181681,181681,181686,181687,181687,181687,181687,181687,181687,181687,181687,181687,181688,181688,181688,181693,181696,181704,181706,181706,181709,181709,181710,181712,181712,181715,181715,181716,181717,181718,181722,181722,181722,181723,181728,181728,181728,181728,181728,181731,181732,181735,181739,181739,181746,181748,181748,181748,181748,181748,181748,181748,181748,181748,181748,181752,181752,181754,181754,181754,181754,181755,181763,181765,181766,181766,181766,181767,181775,181789,181792,181796,181796,181800,181816,181823,181823,181823,181824,181826,181836,181836,181837,181838,181838,181841,181844,181845,181845,181845,181845,181845,181851,181857,181858,181864,181865,181867,181873,181873,181873,181873,181873,181873,181873,181873,181874,181874,181874,181876,181876,181877,181877,181881,181882,181891,181891,181892,181895,181895,181899,181900,181902,181905,181912,181913,181914,181915,181921,181921,181921,181921,181921,181921,181922,181923,181926,181927,181928,181931,181931,181933,181938,181940,181942,181944,181944,181944,181946,181959,181962,181966,181966,181966,181969,181971,181973,181975,181984,181985,181992,181993,181996,182011,182016,182019,182027,182029,182035,182037,182040,182040,182040,182040,182040,182041,182041,182042,182042,182044,182045,182049,182052,182052,182052,182052,182053,182053,182053,182053,182053,182053,182054,182054,182054,182054,182054,182054,182055,182055,182055,182056,182057,182060,182066,182066,182066,182066,182066,182067,182069,182071,182073,182073,182075,182075,182075,182079,182079,182096,182102,182104,182108,182108,182108,182116,182117,182117,182118,182118,182121,182125,182126,182127,182127,182127,182130,182137,182145,182149,182154,182154,182154,182156,182158,182158,182158,182159,182160,182163,182164,182167,182168,182168,182169,182170,182178,182179,182180,182183,182183,182183,182183,182183,182192,182192,182193,182195,182196,182196,182200,182203,182204,182204,182204,182204,182210,182213,182213,182213,182215,182215,182215,182217,182220,182220,182225,182231,182236,182238,182238,182238,182249,182250,182250,182253,182254,182256,182256,182258,182258,182266,182267,182267,182267,182271,182273,182273,182273,182273,182273,182274,182274,182274,182274,182276,182279,182281,182285,182285,182291,182295,182296,182297,182297,182306,182307,182308,182318,182318,182318,182318,182318,182321,182321,182323,182329,182331,182333,182335,182338,182340,182342,182344,182352,182354,182354,182354,182354,182354,182355,182355,182355,182356,182356,182356,182356,182357,182357,182358,182360,182361,182363,182363,182363,182365,182371,182374,182376,182376,182376,182377,182377,182377,182379,182382,182386,182393,182398,182398,182398,182398,182398,182398,182398,182398,182398,182406,182412,182418,182418,182420,182421,182421,182421,182422,182424,182425,182427,182434,182436,182446,182450,182458,182463,182463,182472,182480,182482,182484,182485,182488,182489,182494,182494,182494,182494,182494,182498,182502,182520,182520,182520,182526,182526,182526,182528,182530,182536,182546,182546,182547,182548,182554,182570,182573,182575,182587,182590,182590,182590,182590,182590,182590,182591,182592,182592,182592,182592,182592,182592,182593,182593,182593,182593,182602,182602,182602,182602,182602,182602,182602,182605,182605,182605,182606,182607,182607,182607,182607,182609,182615,182621,182630,182630,182630,182630,182630,182636,182639,182639,182640,182641,182643,182647,182651,182656,182658,182666,182667,182667,182667,182667,182670,182670,182678,182678,182678,182694,182696,182696,182706,182711,182713,182719,182723,182723,182723,182735,182741,182744,182746,182749,182766,182770,182770,182770,182771,182775,182778,182797,182802,182809,182809,182820,182825,182830,182830,182834,182845,182848,182849,182860,182863,182863,182863,182863,182865,182865,182865,182865,182865,182867,182867,182867,182876,182877,182877,182877,182877,182897,182897,182901,182906,182912,182915,182915,182916,182916,182924,182925,182931,182936,182938,182943,182944,182944,182951,182953,182961,182966,182968,182973,182976,182976,182976,182977,182985,182987,182987,182987,182987,182993,182993,182998,183003,183006,183006,183006,183006,183006,183006,183013,183017,183017,183017,183017,183022,183023,183026,183028,183029,183029,183031,183037,183045,183050,183051,183058,183058,183058,183058,183060,183060,183060,183060,183061,183064,183065,183065,183073,183073,183073,183075,183075,183078,183082,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183083,183086,183086,183087,183093,183093,183095,183095,183095,183096,183097,183097,183098,183098,183103,183103,183103,183104,183107,183112,183120,183121,183121,183127,183132,183140,183144,183146,183148,183148,183155,183161,183161,183164,183170,183172,183174,183174,183174,183177,183177,183179,183185,183191,183191,183197,183205,183209,183214,183226,183226,183228,183230,183236,183242,183243,183243,183254,183254,183261,183264,183269,183272,183272,183273,183273,183274,183274,183277,183277,183277,183281,183282,183292,183297,183299,183300,183302,183306,183306,183306,183306,183314,183322,183330,183342,183349,183350,183352,183354,183358,183364,183364,183364,183364,183364,183364,183364,183373,183374,183382,183382,183386,183388,183393,183399,183404,183406,183412,183420,183422,183424,183428,183434,183435,183437,183438,183440,183442,183442,183448,183451,183451,183461,183462,183465,183466,183468,183468,183468,183468,183468,183470,183470,183470,183473,183474,183479,183482,183485,183485,183485,183485,183489,183489,183492,183495,183499,183503,183507,183511,183515,183516,183516,183517,183517,183517,183517,183517,183519,183528,183529,183530,183535,183540,183549,183554,183563,183563,183564,183569,183569,183572,183576,183577,183578,183581,183581,183582,183583,183583,183583,183583,183583,183583,183583,183583,183583,183583,183588,183590,183591,183594,183594,183594,183596,183596,183597,183599,183604,183604,183604,183604,183604,183607,183614,183614,183615,183615,183615,183617,183618,183620,183626,183627,183627,183630,183630,183633,183640,183644,183648,183652,183652,183654,183660,183660,183661,183662,183662,183662,183664,183667,183668,183669,183674,183674,183674,183676,183676,183676,183676,183676,183676,183676,183676,183676,183680,183685,183686,183686,183690,183691,183694,183695,183702,183711,183714,183715,183722,183736,183736,183746,183751,183759,183768,183768,183771,183778,183780,183784,183791,183792,183795,183796,183799,183812,183816,183816,183826,183826,183832,183832,183832,183834,183835,183837,183838,183845,183849,183850,183853,183859,183863,183864,183870,183874,183877,183880,183884,183886,183893,183896,183898,183904,183906,183920,183921,183923,183925,183925,183926,183929,183930,183930,183931,183931,183931,183931,183931,183931,183936,183944,183944,183946,183946,183946,183950,183952,183952,183953,183953,183953,183959,183973,183975,183976,183976,183976,183976,183976,183986,183988,183990,183992,183994,183994,184000,184001,184001,184001,184001,184009,184009,184011,184018,184018,184023,184027,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184029,184031,184033,184035,184035,184035,184035,184038,184038,184038,184040,184043,184044,184047,184052,184052,184053,184053,184058,184058,184058,184059,184061,184062,184070,184071,184071,184071,184071,184071,184072,184074,184077,184077,184079,184079,184080,184080,184080,184080,184080,184086,184086,184086,184086,184086,184086,184088,184093,184093,184093,184094,184094,184098,184098,184100,184109,184111,184111,184111,184111,184111,184111,184111,184111,184111,184111,184111,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184121,184122,184122,184122,184122,184123,184123,184123,184123,184123,184123,184123,184123,184123,184124,184124,184124,184124,184125,184125,184125,184125,184126,184127,184127,184128,184128,184129,184129,184133,184134,184138,184141,184142,184143,184148,184152,184154,184156,184156,184156,184156,184156,184156,184156,184156,184156,184156,184156,184156,184156,184156,184159,184164,184164,184164,184164,184164,184166,184168,184168,184168,184168,184168,184168,184169,184180,184181,184182,184183,184183,184183,184185,184185,184187,184187,184187,184187,184187,184188,184189,184189,184191,184192,184192,184192,184195,184195,184195,184195,184195,184197,184198,184198,184198,184200,184201,184201,184202,184204,184205,184205,184206,184206,184211,184212,184214,184216,184220,184220,184221,184223,184226,184226,184227,184232,184232,184232,184232,184232,184232,184232,184232,184232,184232,184232,184232,184232,184232,184232,184243,184248,184248,184248,184253,184254,184255,184255,184255,184255,184255,184258,184259,184259,184260,184261,184263,184263,184270,184273,184276,184276,184278,184278,184278,184279,184279,184280,184280,184280,184280,184280,184281,184282,184282,184283,184284,184284,184284,184284,184285,184285,184287,184293,184293,184299,184301,184302,184302,184302,184311,184319,184319,184319,184320,184320,184320,184320,184323,184324,184324,184324,184327,184327,184327,184327,184327,184327,184327,184330,184334,184338,184338,184340,184340,184340,184340,184342,184343,184343,184344,184344,184349,184353,184353,184355,184356,184356,184356,184356,184356,184357,184359,184366,184366,184370,184375,184376,184377,184377,184380,184382,184384,184384,184386,184388,184389,184391,184393,184393,184393,184394,184397,184398,184398,184398,184399,184401,184403,184403,184403,184403,184403,184403,184403,184405,184406,184412,184413,184418,184418,184419,184421,184421,184421,184424,184424,184425,184425,184432,184432,184438,184440,184441,184441,184441,184441,184441,184442,184443,184444,184444,184444,184447,184447,184451,184451,184451,184457,184457,184458,184465,184465,184474,184477,184485,184489,184489,184497,184497,184501,184501,184501,184501,184503,184507,184507,184511,184511,184511,184511,184521,184522,184524,184527,184534,184536,184538,184539,184540,184545,184545,184548,184548,184550,184550,184562,184562,184562,184562,184562,184562,184562,184562,184562,184566,184566,184566,184566,184566,184566,184566,184566,184567,184567,184567,184568,184569,184569,184569,184569,184573,184573,184573,184573,184573,184576,184576,184576,184577,184584,184584,184592,184597,184599,184601,184609,184615,184617,184620,184629,184636,184636,184642,184642,184642,184646,184649,184649,184651,184651,184653,184653,184654,184659,184659,184664,184666,184667,184681,184688,184690,184698,184712,184713,184713,184715,184722,184730,184733,184737,184739,184739,184739,184739,184741,184742,184744,184745,184745,184745,184745,184751,184751,184751,184751,184756,184756,184762,184765,184767,184767,184768,184769,184769,184777,184789,184791,184794,184795,184795,184795,184795,184795,184795,184798,184798,184798,184798,184798,184798,184799,184806,184807,184811,184811,184812,184812,184813,184813,184815,184816,184817,184821,184822,184823,184823,184823,184823,184823,184824,184833,184834,184834,184837,184838,184854,184857,184859,184859,184859,184860,184870,184876,184877,184877,184880,184882,184884,184884,184884,184890,184894,184894,184894,184894,184894,184894,184898,184898,184899,184899,184900,184900,184901,184907,184911,184911,184918,184920,184920,184920,184922,184931,184931,184936,184939,184939,184941,184945,184945,184948,184948,184948,184948,184948,184948,184948,184949,184954,184954,184954,184955,184961,184961,184965,184965,184966,184966,184966,184966,184967,184972,184972,184973,184973,184973,184973,184973,184975,184978,184979,184980,184982,184987,184987,184987,184987,184987,184989,184989,184989,184990,184991,184991,184994,184994,184995,184995,184995,184995,184996,184996,185000,185000,185000,185003,185012,185015,185016,185017,185018,185021,185021,185021,185021,185021,185021,185021,185021,185021,185021,185021,185021,185021,185021,185021,185021,185022,185022,185022,185022,185022,185024,185024,185024,185024,185024,185025,185025,185025,185025,185025,185025,185025,185025,185025,185027,185027,185028,185030,185030,185030,185030,185030,185030,185030,185030,185032,185035,185036,185038,185041,185041,185041,185044,185046,185052,185057,185058,185064,185064,185065,185073,185077,185077,185077,185077,185077,185077,185077,185081,185081,185082,185086,185093,185093,185095,185095,185104,185108,185116,185117,185118,185125,185126,185126,185132,185135,185141,185142,185143,185149,185151,185156,185156,185156,185157,185157,185163,185165,185173,185175,185178,185180,185184,185186,185187,185187,185191,185200,185203,185208,185217,185217,185219,185225,185234,185235,185239,185252,185259,185265,185265,185271,185275,185278,185278,185278,185278,185279,185279,185279,185280,185280,185282,185286,185286,185287,185287,185298,185301,185304,185307,185308,185310,185312,185312,185317,185319,185320,185320,185323,185329,185331,185332,185335,185335,185335,185338,185338,185342,185342,185342,185342,185342,185342,185342,185342,185342,185342,185342,185342,185343,185343,185343,185343,185347,185347,185347,185353,185353,185356,185357,185358,185363,185368,185368,185369,185371,185372,185372,185372,185372,185373,185373,185376,185376,185379,185379,185380,185380,185380,185399,185399,185399,185399,185403,185404,185404,185404,185407,185411,185418,185422,185424,185426,185432,185433,185435,185442,185445,185445,185448,185452,185456,185464,185472,185472,185474,185475,185478,185479,185487,185497,185500,185500,185500,185500,185500,185500,185500,185500,185502,185504,185507,185510,185524,185525,185526,185532,185532,185533,185540,185541,185542,185542,185546,185546,185546,185546,185546,185550,185552,185554,185557,185560,185564,185565,185567,185572,185575,185576,185577,185580,185585,185586,185587,185590,185592,185595,185596,185597,185598,185598,185600,185602,185608,185615,185616,185621,185622,185630,185630,185630,185632,185633,185634,185635,185636,185636,185636,185636,185636,185636,185636,185636,185636,185636,185636,185640,185641,185641,185641,185643,185643,185647,185650,185650,185650,185653,185655,185655,185655,185655,185655,185655,185655,185655,185655,185655,185655,185657,185657,185663,185664,185664,185664,185664,185669,185669,185669,185671,185679,185692,185693,185695,185699,185709,185711,185719,185719,185723,185727,185727,185727,185729,185729,185734,185737,185745,185746,185746,185752,185759,185762,185765,185766,185768,185768,185776,185776,185778,185780,185781,185782,185789,185794,185796,185805,185807,185814,185814,185814,185814,185814,185814,185824,185829,185831,185831,185834,185834,185842,185843,185847,185847,185847,185849,185857,185857,185858,185858,185858,185860,185866,185868,185871,185877,185877,185878,185880,185885,185885,185885,185887,185887,185887,185887,185888,185893,185899,185900,185901,185908,185913,185922,185922,185923,185924,185925,185930,185931,185938,185939,185939,185939,185939,185939,185939,185939,185939,185939,185939,185939,185939,185939,185939,185939,185939,185943,185948,185949,185953,185953,185953,185953,185953,185957,185957,185961,185962,185966,185966,185967,185967,185967,185969,185972,185972,185977,185977,185978,185979,185979,185980,185981,185981,185983,185983,185986,185996,185998,186000,186004,186004,186005,186008,186010,186014,186014,186015,186018,186024,186033,186037,186037,186037,186037,186037,186037,186037,186037,186037,186041,186042,186043,186046,186047,186048,186049,186050,186054,186054,186054,186054,186055,186057,186057,186057,186057,186057,186057,186068,186068,186069,186069,186069,186076,186078,186087,186090,186091,186092,186094,186096,186097,186098,186098,186100,186101,186115,186118,186118,186118,186118,186118,186118,186119,186122,186122,186122,186123,186123,186125,186126,186128,186128,186129,186131,186132,186133,186138,186138,186143,186143,186144,186147,186148,186148,186148,186148,186151,186152,186158,186162,186164,186174,186174,186174,186178,186185,186187,186187,186188,186189,186194,186194,186201,186213,186213,186213,186214,186216,186218,186218,186218,186218,186218,186218,186218,186221,186221,186222,186223,186223,186223,186223,186223,186223,186223,186223,186229,186233,186235,186236,186241,186242,186245,186250,186250,186253,186256,186256,186256,186261,186261,186270,186270,186270,186271,186274,186281,186282,186289,186290,186290,186298,186302,186302,186302,186311,186313,186313,186313,186320,186320,186320,186323,186323,186324,186326,186327,186327,186327,186327,186329,186331,186332,186333,186333,186336,186348,186350,186353,186356,186356,186366,186373,186378,186379,186380,186392,186392,186395,186400,186407,186408,186413,186416,186416,186416,186416,186416,186416,186416,186416,186416,186416,186419,186419,186419,186422,186422,186422,186422,186422,186422,186422,186423,186426,186427,186434,186442,186442,186443,186443,186445,186446,186451,186454,186456,186456,186457,186457,186457,186463,186464,186467,186467,186469,186469,186469,186469,186470,186472,186475,186477,186480,186482,186482,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186487,186488,186490,186491,186496,186498,186505,186505,186513,186514,186519,186520,186520,186520,186520,186522,186522,186524,186525,186525,186527,186527,186527,186529,186529,186536,186537,186539,186539,186542,186543,186544,186544,186544,186544,186544,186550,186550,186553,186553,186556,186559,186563,186566,186567,186567,186572,186578,186578,186580,186583,186585,186586,186589,186590,186591,186594,186599,186599,186599,186602,186602,186603,186604,186604,186611,186613,186613,186613,186618,186618,186618,186620,186620,186620,186620,186622,186629,186634,186634,186636,186642,186642,186643,186643,186643,186643,186643,186643,186643,186643,186643,186643,186643,186643,186643,186643,186643,186643,186648,186651,186652,186654,186654,186655,186655,186655,186655,186656,186656,186656,186656,186656,186656,186657,186657,186657,186657,186657,186659,186661,186662,186663,186663,186663,186663,186664,186664,186665,186666,186666,186666,186666,186666,186666,186666,186668,186668,186670,186672,186673,186673,186673,186673,186673,186673,186674,186675,186676,186677,186677,186678,186679,186680,186680,186682,186683,186683,186683,186683,186683,186683,186683,186684,186684,186684,186686,186686,186687,186687,186688,186688,186688,186688,186688,186691,186692,186693,186694,186696,186696,186696,186697,186697,186698,186699,186699,186699,186701,186702,186702,186702,186702,186702,186702,186703,186703,186703,186703,186703,186703,186703,186703,186704,186704,186704,186704,186704,186704,186704,186705,186705,186705,186705,186706,186706,186706,186706,186706,186707,186707,186707,186709,186710,186710,186710,186711,186711,186711,186711,186713,186713,186713,186713,186714,186715,186718,186718,186719,186721,186721,186732,186732,186733,186736,186737,186739,186740,186740,186743,186744,186745,186745,186745,186745,186746,186747,186747,186747,186747,186747,186749,186752,186752,186753,186757,186758,186759,186761,186764,186764,186767,186769,186771,186772,186772,186772,186773,186773,186778,186791,186798,186801,186809,186809,186809,186809,186809,186809,186810,186818,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186826,186834,186834,186834,186846,186846,186851,186858,186876,186879,186886,186887,186887,186887,186890,186893,186896,186896,186896,186900,186902,186902,186903,186918,186921,186922,186926,186926,186931,186931,186931,186931,186931,186933,186933,186933,186933,186933,186933,186933,186933,186933,186934,186934,186934,186935,186935,186937,186937,186938,186938,186940,186942,186943,186946,186946,186946,186946,186946,186953,186961,186963,186964,186965,186966,186980,186985,186991,186991,186991,186991,186991,186991,186991,186991,186992,186992,186994,186995,186996,186996,186996,186996,186996,187000,187006,187011,187014,187016,187024,187032,187032,187033,187036,187036,187036,187036,187036,187036,187036,187036,187041,187047,187047,187048,187052,187056,187058,187060,187060,187060,187062,187062,187062,187062,187063,187075,187083,187092,187096,187097,187098,187099,187099,187100,187104,187106,187110,187110,187110,187110,187110,187110,187110,187110,187110,187111,187114,187114,187122,187122,187130,187131,187133,187134,187134,187138,187138,187138,187144,187149,187163,187163,187181,187182,187183,187186,187189,187194,187194,187194,187199,187199,187200,187200,187201,187202,187205,187209,187212,187214,187225,187232,187240,187240,187240,187240,187245,187247,187249,187249,187254,187254,187266,187271,187274,187274,187274,187277,187277,187281,187283,187286,187286,187288,187289,187289,187291,187291,187292,187292,187292,187295,187295,187295,187297,187298,187298,187300,187301,187301,187302,187307,187309,187309,187313,187314,187316,187316,187316,187316,187318,187322,187322,187324,187326,187328,187329,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187342,187344,187344,187345,187346,187346,187346,187346,187346,187346,187346,187346,187346,187346,187346,187346,187346,187346,187346,187346,187358,187359,187359,187361,187362,187364,187364,187366,187374,187375,187375,187381,187382,187405,187416,187420,187425,187426,187434,187435,187439,187440,187446,187449,187453,187458,187458,187466,187475,187476,187476,187477,187477,187478,187478,187488,187488,187488,187488,187488,187489,187497,187498,187503,187504,187507,187517,187519,187519,187520,187520,187520,187521,187521,187521,187521,187524,187525,187525,187525,187528,187528,187528,187529,187530,187530,187530,187531,187531,187533,187534,187534,187534,187534,187534,187535,187535,187535,187535,187536,187536,187536,187536,187537,187538,187538,187538,187538,187538,187538,187539,187540,187540,187540,187540,187540,187540,187540,187541,187542,187542,187542,187543,187544,187544,187544,187544,187547,187547,187547,187547,187548,187548,187549,187550,187564,187569,187569,187572,187573,187579,187579,187580,187587,187590,187591,187604,187604,187604,187605,187607,187616,187616,187617,187620,187621,187628,187629,187629,187629,187631,187635,187643,187644,187644,187644,187644,187644,187644,187644,187644,187644,187644,187644,187644,187644,187644,187645,187646,187647,187648,187648,187648,187648,187648,187648,187649,187650,187650,187650,187651,187651,187653,187653,187653,187653,187654,187657,187657,187660,187660,187667,187671,187671,187671,187671,187675,187675,187675,187675,187675,187675,187675,187675,187675,187675,187675,187676,187677,187678,187679,187679,187679,187682,187683,187683,187686,187691,187693,187695,187695,187695,187695,187695,187695,187695,187695,187696,187696,187697,187697,187701,187703,187714,187715,187718,187719,187719,187725,187725,187725,187727,187727,187727,187727,187727,187727,187727,187729,187730,187732,187732,187743,187745,187746,187746,187746,187746,187746,187751,187753,187753,187753,187753,187753,187753,187753,187753,187753,187755,187755,187755,187762,187765,187767,187767,187769,187771,187774,187776,187777,187781,187781,187781,187781,187783,187783,187784,187784,187785,187785,187785,187785,187785,187785,187785,187785,187785,187787,187788,187788,187789,187789,187789,187789,187789,187789,187789,187790,187791,187792,187792,187793,187794,187794,187795,187795,187796,187798,187798,187798,187798,187798,187799,187799,187799,187802,187808,187811,187813,187817,187818,187819,187821,187823,187834,187836,187842,187844,187844,187844,187846,187848,187848,187848,187848,187848,187854,187854,187857,187858,187860,187861,187861,187861,187861,187862,187863,187863,187866,187866,187869,187871,187871,187872,187872,187873,187875,187875,187878,187880,187880,187880,187886,187888,187888,187890,187890,187892,187892,187892,187893,187893,187893,187893,187895,187895,187895,187895,187895,187895,187903,187905,187905,187905,187907,187907,187907,187909,187913,187914,187914,187914,187915,187916,187916,187916,187916,187916,187916,187916,187916,187916,187916,187916,187916,187916,187916,187916,187917,187917,187917,187917,187917,187917,187918,187918,187918,187918,187920,187922,187922,187922,187922,187922,187922,187922,187922,187927,187930,187931,187933,187933,187936,187937,187938,187938,187943,187945,187945,187945,187949,187950,187950,187952,187956,187956,187957,187961,187964,187964,187964,187966,187966,187966,187966,187967,187968,187969,187969,187969,187970,187972,187975,187975,187977,187978,187978,187978,187978,187978,187978,187978,187978,187978,187979,187981,187981,187981,187982,187982,187982,187984,187985,187986,187986,187986,187986,187986,187988,187992,187992,187995,187995,187996,187998,188003,188003,188005,188005,188005,188006,188006,188009,188011,188013,188013,188013,188015,188015,188017,188018,188020,188021,188021,188021,188021,188021,188021,188021,188021,188021,188021,188022,188023,188023,188024,188024,188024,188024,188024,188025,188025,188025,188025,188025,188027,188027,188027,188038,188038,188040,188040,188040,188040,188040,188040,188042,188042,188042,188042,188043,188043,188044,188046,188046,188046,188046,188046,188046,188048,188048,188049,188049,188051,188053,188053,188053,188057,188058,188060,188062,188062,188062,188062,188062,188062,188062,188062,188064,188064,188064,188066,188066,188066,188071,188071,188072,188074,188074,188075,188078,188079,188079,188079,188079,188079,188079,188079,188079,188079,188083,188084,188084,188085,188086,188089,188091,188091,188091,188095,188095,188096,188100,188105,188107,188107,188115,188115,188116,188117,188118,188119,188123,188135,188138,188143,188146,188146,188146,188146,188146,188147,188147,188149,188153,188153,188154,188159,188160,188161,188161,188161,188161,188166,188168,188173,188179,188185,188185,188185,188185,188186,188187,188188,188189,188189,188194,188194,188196,188196,188196,188196,188197,188202,188202,188204,188204,188205,188205,188205,188205,188211,188211,188212,188212,188212,188213,188213,188213,188214,188220,188222,188222,188225,188230,188234,188234,188234,188234,188234,188236,188236,188242,188242,188245,188245,188249,188251,188251,188253,188253,188254,188256,188256,188256,188256,188256,188256,188262,188269,188269,188272,188283,188290,188295,188296,188297,188302,188304,188306,188307,188307,188309,188309,188312,188312,188315,188319,188320,188322,188331,188340,188340,188341,188347,188354,188354,188356,188356,188356,188356,188357,188358,188358,188359,188362,188363,188370,188372,188372,188376,188378,188378,188380,188380,188380,188380,188380,188380,188380,188382,188383,188385,188385,188385,188385,188387,188392,188392,188393,188393,188394,188394,188395,188395,188395,188395,188395,188395,188395,188395,188395,188395,188395,188395,188395,188395,188395,188395,188396,188396,188397,188398,188399,188399,188400,188403,188403,188408,188409,188409,188409,188412,188415,188420,188423,188424,188429,188433,188438,188438,188440,188440,188441,188441,188442,188442,188444,188445,188447,188451,188451,188451,188451,188451,188451,188452,188454,188454,188455,188455,188456,188457,188459,188460,188460,188460,188460,188460,188461,188462,188464,188464,188466,188467,188468,188469,188470,188474,188476,188479,188479,188479,188479,188479,188480,188480,188480,188480,188482,188482,188484,188484,188484,188484,188484,188493,188493,188495,188495,188495,188496,188497,188497,188497,188497,188498,188499,188500,188500,188501,188502,188503,188506,188506,188512,188512,188512,188515,188515,188518,188522,188522,188522,188522,188523,188526,188533,188533,188534,188534,188535,188535,188535,188535,188535,188536,188536,188536,188536,188536,188536,188536,188536,188537,188537,188537,188537,188537,188538,188538,188540,188541,188544,188546,188546,188546,188546,188546,188547,188550,188550,188550,188550,188553,188555,188555,188555,188555,188555,188555,188555,188555,188555,188558,188560,188560,188561,188562,188562,188562,188562,188562,188563,188566,188566,188567,188568,188568,188568,188569,188570,188570,188570,188570,188574,188578,188578,188579,188579,188580,188581,188581,188581,188582,188582,188584,188584,188587,188588,188588,188588,188588,188588,188592,188594,188594,188594,188595,188596,188596,188604,188604,188604,188604,188604,188604,188604,188604,188605,188605,188607,188609,188611,188611,188612,188612,188612,188616,188617,188618,188620,188621,188626,188626,188626,188627,188627,188639,188646,188646,188647,188648,188648,188648,188652,188653,188657,188657,188660,188660,188692,188692,188692,188700,188704,188704,188704,188704,188704,188713,188713,188715,188715,188715,188715,188718,188721,188721,188722,188722,188729,188729,188729,188730,188730,188730,188734,188735,188737,188737,188737,188737,188737,188737,188737,188740,188740,188740,188741,188742,188742,188748,188753,188753,188753,188755,188755,188761,188766,188770,188775,188777,188787,188793,188793,188797,188797,188800,188806,188806,188813,188814,188817,188823,188824,188826,188827,188827,188828,188833,188833,188835,188835,188835,188835,188837,188838,188841,188843,188843,188843,188843,188843,188844,188844,188845,188846,188846,188848,188849,188849,188849,188849,188850,188852,188852,188854,188854,188856,188859,188860,188861,188861,188861,188865,188865,188865,188865,188865,188865,188865,188865,188865,188866,188866,188866,188866,188867,188867,188867,188867,188870,188870,188870,188874,188875,188878,188878,188878,188880,188880,188883,188884,188884,188884,188884,188884,188887,188890,188895,188895,188895,188896,188900,188901,188901,188906,188907,188907,188907,188907,188907,188916,188917,188917,188917,188920,188926,188930,188930,188930,188931,188931,188931,188931,188931,188934,188935,188936,188942,188943,188943,188944,188948,188948,188955,188955,188956,188957,188957,188957,188957,188957,188957,188957,188957,188959,188963,188965,188976,188976,188976,188976,188976,188976,188976,188976,188976,188976,188976,188976,188976,188977,188977,188977,188978,188979,188981,188981,188982,188986,188988,188988,188988,188988,188988,188988,188988,188989,188989,188989,188990,188990,188990,188990,188998,188999,188999,188999,189004,189004,189004,189006,189010,189010,189010,189010,189010,189010,189011,189011,189011,189012,189013,189014,189022,189031,189033,189037,189037,189042,189047,189048,189059,189070,189073,189081,189085,189087,189088,189088,189094,189107,189113,189114,189124,189124,189126,189126,189129,189129,189133,189133,189134,189134,189134,189134,189135,189135,189136,189137,189137,189138,189138,189138,189138,189138,189139,189139,189144,189145,189146,189146,189146,189146,189147,189147,189147,189150,189152,189152,189154,189156,189156,189157,189159,189159,189159,189159,189159,189159,189160,189160,189160,189160,189162,189162,189164,189166,189169,189170,189170,189170,189176,189177,189177,189178,189178,189178,189178,189178,189178,189178,189178,189178,189179,189182,189186,189186,189186,189186,189189,189189,189190,189190,189192,189194,189194,189195,189195,189198,189207,189207,189207,189208,189208,189208,189208,189208,189208,189208,189211,189211,189211,189213,189215,189219,189219,189225,189226,189226,189227,189241,189246,189252,189258,189258,189258,189258,189263,189265,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189268,189269,189269,189269,189269,189269,189271,189273,189273,189273,189276,189277,189278,189288,189288,189288,189288,189288,189288,189288,189288,189288,189288,189288,189288,189292,189292,189292,189292,189295,189303,189304,189304,189304,189313,189313,189319,189320,189325,189326,189326,189326,189331,189331,189331,189332,189334,189335,189335,189338,189338,189338,189339,189341,189342,189347,189348,189350,189352,189354,189354,189354,189355,189356,189358,189359,189359,189367,189368,189368,189369,189369,189377,189377,189377,189377,189381,189381,189381,189381,189381,189381,189387,189387,189388,189389,189400,189404,189410,189410,189423,189428,189431,189435,189437,189437,189440,189440,189442,189445,189445,189446,189446,189452,189454,189455,189455,189457,189457,189461,189461,189461,189466,189466,189467,189470,189471,189471,189471,189472,189472,189473,189473,189473,189473,189473,189473,189474,189474,189476,189476,189477,189477,189484,189486,189487,189490,189491,189494,189494,189495,189495,189495,189498,189505,189510,189510,189512,189516,189516,189516,189516,189519,189519,189519,189519,189519,189520,189520,189522,189525,189526,189526,189530,189530,189530,189530,189530,189530,189534,189540,189540,189540,189543,189551,189551,189552,189557,189557,189557,189557,189557,189560,189560,189561,189561,189561,189561,189561,189563,189563,189564,189564,189564,189566,189586,189586,189593,189604,189605,189610,189611,189613,189616,189629,189633,189633,189640,189640,189640,189653,189653,189654,189654,189655,189658,189661,189661,189661,189661,189664,189664,189664,189665,189668,189668,189668,189668,189671,189674,189674,189675,189675,189675,189675,189675,189675,189676,189678,189680,189680,189682,189683,189683,189683,189683,189683,189683,189683,189685,189695,189696,189699,189704,189707,189708,189715,189715,189720,189724,189725,189726,189729,189730,189731,189731,189733,189735,189735,189737,189739,189740,189740,189740,189740,189740,189741,189741,189744,189746,189746,189746,189746,189747,189748,189750,189753,189753,189753,189753,189753,189753,189753,189753,189754,189754,189756,189756,189759,189761,189761,189761,189761,189761,189761,189761,189761,189761,189761,189762,189762,189762,189762,189762,189762,189764,189767,189770,189772,189772,189781,189781,189781,189781,189781,189781,189781,189781,189783,189787,189787,189787,189787,189787,189787,189787,189787,189787,189791,189791,189791,189793,189794,189794,189794,189796,189796,189796,189804,189808,189809,189809,189809,189819,189820,189821,189824,189824,189824,189824,189830,189830,189830,189830,189830,189830,189830,189831,189831,189833,189833,189833,189833,189833,189833,189834,189835,189837,189842,189847,189847,189854,189861,189862,189863,189865,189874,189875,189876,189876,189883,189885,189887,189888,189888,189889,189896,189899,189903,189904,189908,189909,189912,189919,189919,189919,189919,189925,189927,189927,189927,189927,189927,189927,189927,189927,189927,189928,189930,189930,189936,189943,189943,189943,189943,189943,189943,189948,189948,189948,189948,189948,189948,189949,189953,189953,189957,189957,189963,189964,189965,189965,189970,189971,189972,189972,189972,189976,189976,189976,189976,189976,189976,189976,189976,189976,189976,189976,189979,189979,189979,189979,189979,189981,189987,189987,189988,189990,189994,189996,190001,190001,190004,190007,190007,190007,190009,190009,190011,190013,190014,190014,190014,190014,190016,190016,190016,190023,190025,190029,190031,190037,190038,190041,190041,190041,190041,190041,190051,190053,190054,190055,190057,190057,190057,190057,190059,190059,190059,190059,190059,190067,190070,190073,190077,190078,190082,190083,190085,190086,190090,190090,190092,190093,190093,190093,190094,190094,190097,190097,190097,190098,190099,190100,190100,190100,190100,190100,190101,190101,190103,190103,190103,190103,190103,190105,190105,190110,190112,190112,190112,190115,190122,190123,190125,190127,190129,190131,190131,190134,190134,190135,190140,190141,190143,190143,190147,190150,190151,190152,190153,190156,190158,190164,190165,190165,190181,190181,190183,190183,190183,190193,190204,190204,190219,190220,190236,190237,190242,190242,190243,190249,190249,190253,190261,190277,190285,190285,190289,190290,190291,190292,190292,190296,190302,190305,190305,190305,190310,190310,190310,190310,190313,190314,190316,190321,190333,190333,190335,190335,190345,190347,190347,190348,190349,190350,190351,190355,190362,190365,190369,190369,190369,190370,190371,190371,190373,190375,190378,190390,190391,190391,190395,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190396,190399,190401,190410,190410,190410,190410,190410,190410,190432,190434,190439,190455,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190458,190463,190463,190463,190463,190463,190466,190469,190469,190472,190472,190477,190477,190481,190481,190486,190486,190488,190488,190489,190492,190493,190493,190497,190497,190499,190503,190504,190505,190505,190505,190508,190509,190512,190513,190515,190519,190520,190522,190522,190529,190530,190531,190531,190532,190532,190532,190532,190532,190535,190535,190539,190539,190539,190539,190543,190545,190548,190548,190548,190549,190555,190558,190573,190573,190573,190573,190574,190574,190576,190577,190578,190578,190580,190580,190580,190580,190581,190581,190587,190587,190587,190587,190589,190589,190591,190591,190592,190592,190592,190593,190593,190593,190593,190600,190600,190600,190600,190600,190600,190600,190600,190600,190603,190603,190603,190603,190603,190603,190603,190603,190604,190604,190604,190604,190604,190604,190604,190604,190604,190604,190604,190604,190604,190605,190605,190605,190605,190605,190605,190605,190605,190605,190606,190607,190607,190608,190608,190608,190608,190608,190609,190609,190612,190612,190612,190613,190613,190620,190620,190620,190620,190620,190620,190621,190621,190625,190626,190627,190627,190633,190636,190636,190636,190636,190636,190636,190636,190636,190636,190638,190639,190639,190639,190639,190639,190639,190640,190640,190644,190645,190645,190648,190650,190650,190651,190651,190653,190658,190658,190660,190660,190660,190661,190661,190664,190665,190667,190667,190667,190667,190667,190667,190667,190667,190669,190681,190681,190683,190685,190687,190687,190699,190699,190700,190700,190702,190704,190708,190711,190713,190714,190717,190717,190717,190719,190719,190719,190719,190719,190720,190722,190725,190725,190726,190735,190738,190741,190744,190748,190749,190750,190751,190751,190752,190752,190755,190755,190756,190757,190758,190760,190760,190760,190760,190760,190761,190761,190762,190762,190763,190764,190764,190764,190766,190766,190768,190771,190772,190772,190772,190772,190772,190772,190775,190776,190776,190776,190776,190776,190776,190779,190781,190784,190784,190786,190790,190790,190790,190790,190791,190791,190791,190791,190800,190804,190809,190810,190814,190815,190823,190823,190836,190836,190837,190842,190842,190844,190845,190846,190846,190846,190846,190847,190848,190848,190849,190849,190853,190856,190856,190856,190858,190862,190863,190864,190865,190865,190866,190867,190868,190870,190871,190871,190872,190873,190874,190875,190878,190880,190880,190881,190882,190883,190883,190883,190883,190883,190883,190883,190884,190885,190885,190885,190885,190885,190885,190886,190886,190887,190894,190895,190895,190895,190897,190897,190897,190902,190907,190910,190910,190911,190913,190913,190913,190913,190913,190914,190914,190923,190928,190928,190928,190932,190942,190945,190946,190948,190953,190956,190956,190962,190968,190969,190975,190975,190976,190977,190977,190978,190990,190990,190990,190990,190990,190993,190993,190994,190994,190995,190995,190996,190996,190996,190996,190996,191003,191003,191005,191005,191012,191012,191021,191021,191025,191027,191028,191041,191042,191046,191049,191052,191053,191053,191058,191062,191069,191072,191085,191085,191085,191085,191085,191085,191086,191086,191086,191086,191098,191106,191111,191111,191120,191122,191125,191125,191125,191139,191140,191142,191146,191150,191151,191151,191151,191151,191151,191155,191156,191157,191160,191161,191161,191161,191161,191162,191162,191162,191163,191163,191163,191164,191164,191164,191165,191165,191166,191166,191169,191169,191169,191169,191172,191173,191173,191175,191175,191175,191176,191177,191177,191177,191177,191186,191186,191186,191186,191186,191186,191186,191186,191189,191189,191191,191202,191203,191215,191216,191216,191225,191234,191235,191235,191236,191237,191240,191241,191241,191242,191257,191261,191264,191264,191264,191275,191276,191277,191280,191281,191281,191281,191282,191284,191288,191290,191295,191302,191308,191308,191308,191309,191310,191313,191313,191313,191313,191316,191316,191316,191316,191316,191323,191323,191333,191333,191333,191333,191333,191333,191336,191340,191342,191344,191351,191351,191352,191352,191355,191357,191359,191365,191368,191370,191370,191372,191372,191375,191379,191379,191379,191389,191390,191390,191390,191392,191393,191401,191402,191409,191414,191419,191419,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191421,191422,191422,191422,191422,191422,191422,191422,191423,191423,191425,191425,191425,191428,191428,191428,191428,191429,191429,191429,191429,191430,191431,191431,191431,191433,191434,191436,191437,191437,191437,191438,191438,191440,191440,191440,191440,191440,191440,191440,191440,191440,191441,191443,191443,191443,191443,191445,191446,191446,191447,191449,191449,191449,191450,191450,191453,191453,191453,191453,191453,191453,191454,191454,191454,191456,191456,191459,191460,191461,191461,191461,191462,191466,191466,191466,191467,191467,191467,191468,191469,191469,191471,191471,191471,191472,191472,191474,191477,191479,191479,191479,191479,191479,191479,191479,191479,191479,191479,191481,191481,191481,191481,191481,191482,191482,191484,191484,191486,191488,191489,191489,191490,191490,191491,191491,191491,191491,191491,191491,191491,191491,191491,191495,191495,191495,191496,191496,191496,191496,191497,191497,191497,191497,191497,191497,191505,191506,191506,191506,191506,191506,191507,191507,191507,191507,191507,191511,191511,191512,191512,191513,191513,191513,191513,191514,191515,191515,191517,191521,191521,191525,191525,191525,191528,191530,191532,191532,191532,191532,191533,191533,191534,191536,191536,191536,191536,191536,191536,191536,191539,191542,191542,191542,191545,191545,191545,191545,191545,191546,191547,191548,191548,191549,191554,191554,191554,191556,191559,191559,191564,191566,191568,191572,191572,191572,191573,191574,191574,191574,191574,191574,191575,191576,191576,191577,191577,191578,191579,191586,191587,191587,191590,191590,191590,191596,191598,191598,191599,191599,191599,191599,191599,191599,191602,191603,191603,191605,191607,191609,191609,191610,191613,191613,191613,191619,191619,191623,191623,191627,191630,191631,191638,191638,191638,191638,191643,191648,191649,191649,191649,191650,191650,191650,191653,191654,191656,191657,191660,191661,191662,191662,191664,191667,191671,191674,191674,191674,191675,191678,191678,191678,191680,191680,191680,191680,191680,191680,191682,191685,191688,191689,191689,191689,191690,191690,191694,191695,191701,191701,191702,191703,191703,191703,191703,191703,191705,191707,191707,191707,191710,191712,191712,191712,191713,191716,191716,191719,191721,191721,191721,191730,191732,191735,191739,191740,191741,191742,191743,191749,191750,191751,191751,191756,191765,191766,191766,191766,191768,191770,191770,191777,191783,191786,191791,191806,191807,191807,191817,191820,191821,191829,191831,191835,191842,191847,191847,191850,191852,191853,191857,191866,191878,191878,191878,191878,191880,191880,191886,191886,191886,191886,191886,191886,191886,191892,191908,191912,191920,191920,191920,191920,191920,191920,191920,191920,191920,191920,191920,191920,191920,191921,191922,191923,191925,191926,191926,191926,191926,191926,191927,191927,191928,191931,191932,191932,191932,191932,191932,191932,191932,191933,191933,191933,191933,191933,191933,191933,191933,191934,191934,191943,191944,191944,191944,191944,191944,191947,191951,191959,191963,191971,191973,191973,191974,191974,191974,191976,191976,191976,191976,191976,191977,191977,191977,191978,191979,191979,191979,191981,191984,191986,191987,191987,191987,191991,191993,191995,191997,192010,192016,192016,192016,192016,192017,192028,192030,192034,192038,192038,192040,192043,192043,192044,192046,192054,192054,192061,192061,192061,192061,192061,192063,192069,192071,192078,192081,192081,192082,192082,192085,192086,192086,192086,192088,192098,192098,192101,192102,192102,192106,192109,192114,192121,192121,192133,192134,192144,192144,192144,192145,192165,192165,192165,192165,192167,192169,192173,192175,192178,192180,192185,192193,192200,192200,192200,192204,192210,192211,192211,192216,192220,192220,192223,192230,192231,192235,192236,192236,192246,192246,192246,192249,192249,192250,192254,192256,192266,192267,192268,192268,192282,192282,192282,192282,192282,192282,192282,192284,192284,192284,192284,192287,192287,192287,192290,192293,192294,192298,192299,192301,192303,192304,192308,192312,192312,192312,192312,192312,192312,192313,192313,192313,192314,192314,192314,192314,192314,192314,192316,192316,192323,192330,192331,192342,192350,192357,192357,192374,192382,192385,192385,192389,192392,192392,192393,192398,192401,192401,192401,192401,192401,192401,192404,192415,192418,192425,192427,192436,192446,192448,192448,192448,192451,192454,192465,192472,192476,192486,192486,192486,192486,192502,192502,192511,192511,192514,192520,192523,192523,192523,192536,192536,192536,192541,192541,192541,192550,192553,192553,192553,192553,192553,192553,192553,192555,192560,192560,192560,192563,192563,192563,192563,192563,192563,192563,192563,192563,192563,192567,192577,192577,192577,192582,192597,192598,192598,192598,192598,192605,192617,192620,192623,192638,192657,192662,192665,192665,192667,192667,192668,192681,192689,192689,192690,192691,192694,192698,192703,192710,192714,192718,192719,192720,192721,192729,192729,192729,192729,192729,192729,192729,192729,192729,192729,192737,192742,192743,192745,192747,192749,192749,192749,192751,192753,192753,192753,192753,192759,192759,192759,192759,192765,192780,192786,192790,192797,192797,192799,192811,192811,192816,192827,192830,192830,192830,192830,192830,192830,192830,192832,192833,192833,192834,192834,192834,192834,192837,192850,192851,192852,192852,192853,192853,192860,192860,192860,192862,192884,192893,192893,192898,192905,192907,192911,192912,192925,192929,192930,192936,192947,192950,192950,192950,192950,192952,192953,192955,192956,192965,192966,192967,192981,192988,192988,192993,193001,193004,193007,193009,193009,193009,193009,193011,193012,193012,193019,193021,193023,193023,193024,193024,193024,193029,193037,193041,193043,193043,193049,193052,193054,193054,193055,193067,193067,193067,193071,193077,193082,193087,193089,193091,193094,193096,193096,193113,193114,193120,193129,193133,193139,193139,193143,193145,193145,193145,193148,193162,193170,193170,193181,193181,193187,193187,193187,193187,193187,193187,193187,193187,193187,193187,193189,193191,193191,193200,193201,193201,193201,193201,193201,193215,193215,193217,193221,193223,193223,193230,193243,193243,193251,193256,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193265,193267,193267,193271,193286,193286,193294,193296,193299,193308,193312,193312,193312,193323,193327,193327,193329,193331,193333,193344,193349,193367,193367,193367,193370,193370,193373,193379,193382,193383,193383,193395,193395,193396,193396,193396,193396,193396,193396,193396,193396,193403,193407,193412,193412,193417,193420,193426,193426,193428,193445,193445,193452,193452,193468,193489,193489,193502,193502,193502,193503,193503,193505,193505,193509,193509,193514,193514,193529,193530,193531,193538,193541,193542,193547,193547,193547,193553,193555,193555,193591,193599,193599,193599,193599,193599,193601,193601,193601,193603,193606,193606,193607,193607,193607,193607,193610,193624,193625,193625,193629,193640,193640,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193659,193660,193660,193660,193660,193663,193663,193668,193670,193670,193674,193677,193677,193677,193684,193699,193709,193715,193718,193725,193725,193725,193725,193725,193725,193735,193735,193738,193744,193747,193747,193747,193749,193750,193750,193750,193752,193752,193755,193757,193770,193770,193770,193770,193770,193770,193770,193770,193770,193770,193770,193771,193772,193775,193776,193776,193776,193777,193777,193777,193778,193778,193779,193779,193782,193787,193787,193789,193792,193795,193797,193797,193797,193799,193799,193811,193814,193814,193814,193814,193816,193816,193817,193818,193818,193828,193828,193828,193828,193828,193832,193833,193833,193836,193836,193842,193872,193877,193878,193880,193880,193881,193881,193882,193887,193887,193887,193887,193887,193887,193887,193887,193888,193888,193888,193888,193888,193888,193888,193888,193894,193896,193898,193900,193903,193903,193903,193907,193911,193915,193922,193927,193933,193936,193940,193940,193941,193957,193958,193962,193973,193975,193981,193981,193985,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193988,193991,193992,193993,193994,193998,194003,194007,194007,194007,194010,194010,194012,194013,194014,194014,194015,194015,194015,194015,194016,194019,194019,194019,194022,194025,194025,194030,194032,194033,194033,194035,194036,194036,194036,194040,194040,194040,194040,194040,194040,194045,194046,194046,194048,194051,194051,194056,194059,194060,194073,194074,194074,194074,194084,194087,194089,194089,194089,194089,194090,194091,194093,194095,194095,194095,194100,194100,194106,194108,194108,194108,194110,194117,194119,194119,194119,194131,194131,194131,194131,194131,194133,194137,194146,194146,194147,194153,194153,194154,194155,194157,194157,194157,194164,194164,194168,194168,194168,194169,194180,194191,194207,194213,194216,194221,194221,194221,194223,194226,194226,194226,194231,194233,194236,194240,194240,194244,194244,194245,194245,194252,194263,194267,194271,194275,194281,194283,194283,194286,194286,194289,194289,194290,194298,194299,194303,194305,194307,194308,194311,194324,194326,194330,194331,194338,194347,194352,194353,194353,194354,194360,194363,194365,194367,194370,194378,194384,194397,194397,194402,194403,194406,194407,194411,194412,194412,194412,194418,194418,194426,194438,194451,194456,194467,194468,194472,194476,194476,194500,194500,194500,194500,194500,194500,194500,194502,194502,194502,194503,194503,194503,194503,194503,194503,194504,194505,194505,194506,194506,194515,194522,194523,194543,194545,194545,194545,194556,194564,194564,194572,194583,194586,194592,194595,194609,194623,194623,194625,194625,194625,194628,194637,194647,194647,194647,194650,194653,194658,194661,194665,194667,194671,194671,194671,194671,194671,194678,194681,194684,194684,194684,194685,194686,194688,194689,194690,194690,194691,194697,194700,194701,194715,194727,194733,194734,194737,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194739,194742,194746,194750,194752,194753,194753,194754,194758,194760,194762,194762,194762,194762,194762,194762,194762,194762,194762,194766,194767,194767,194767,194768,194770,194771,194771,194771,194781,194781,194781,194794,194802,194803,194804,194804,194807,194814,194814,194816,194820,194832,194832,194837,194844,194851,194858,194868,194868,194868,194869,194870,194876,194876,194882,194885,194896,194900,194902,194903,194908,194908,194910,194914,194914,194920,194924,194927,194929,194938,194946,194946,194948,194951,194953,194954,194954,194960,194963,194964,194969,194969,194969,194972,194977,194983,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194988,194995,194995,194995,195005,195015,195026,195026,195027,195028,195028,195029,195029,195030,195033,195033,195033,195033,195033,195044,195047,195049,195052,195052,195052,195053,195055,195056,195058,195059,195059,195059,195061,195061,195062,195064,195072,195082,195084,195084,195084,195084,195084,195084,195084,195084,195084,195093,195101,195107,195107,195112,195118,195122,195122,195126,195126,195133,195146,195147,195158,195158,195158,195158,195171,195172,195174,195178,195179,195179,195195,195198,195202,195207,195213,195217,195217,195217,195217,195222,195229,195242,195250,195256,195258,195258,195261,195261,195271,195274,195277,195277,195277,195278,195278,195278,195288,195300,195300,195300,195302,195309,195309,195311,195314,195314,195314,195316,195331,195332,195333,195342,195344,195345,195349,195353,195354,195357,195370,195376,195377,195378,195388,195388,195388,195389,195394,195394,195396,195396,195396,195400,195402,195402,195415,195416,195416,195416,195422,195428,195432,195435,195444,195444,195445,195456,195461,195464,195464,195467,195468,195468,195469,195469,195469,195470,195472,195473,195474,195476,195476,195476,195476,195476,195477,195483,195485,195489,195493,195498,195503,195504,195506,195506,195516,195516,195516,195519,195526,195527,195547,195549,195555,195555,195555,195575,195576,195577,195580,195580,195581,195581,195581,195581,195581,195581,195582,195584,195584,195584,195585,195586,195593,195594,195594,195594,195596,195596,195597,195598,195605,195609,195612,195613,195613,195613,195613,195613,195615,195618,195618,195622,195623,195629,195629,195632,195638,195640,195641,195643,195650,195650,195650,195650,195653,195655,195655,195656,195660,195665,195665,195667,195682,195682,195682,195682,195682,195682,195684,195686,195688,195688,195688,195688,195688,195688,195688,195688,195688,195688,195688,195688,195688,195688,195689,195690,195692,195693,195694,195695,195698,195698,195698,195703,195707,195707,195709,195717,195718,195727,195737,195737,195737,195757,195765,195771,195775,195786,195787,195798,195803,195803,195811,195825,195829,195833,195837,195844,195849,195861,195865,195892,195896,195898,195899,195912,195923,195924,195925,195938,195938,195938,195938,195938,195938,195940,195944,195947,195947,195947,195950,195961,195964,195964,195965,195966,195970,195971,195971,195973,195976,195977,195978,195981,195981,195984,195986,195987,195998,195998,196000,196000,196000,196001,196002,196012,196017,196017,196024,196026,196027,196030,196030,196042,196050,196051,196055,196073,196073,196076,196084,196085,196085,196104,196108,196109,196116,196123,196128,196136,196136,196136,196136,196141,196145,196145,196148,196148,196149,196150,196151,196164,196178,196191,196193,196193,196193,196194,196194,196196,196196,196196,196200,196201,196205,196205,196209,196210,196210,196210,196216,196217,196218,196221,196221,196222,196222,196222,196232,196233,196234,196234,196235,196238,196238,196239,196239,196239,196239,196239,196241,196241,196241,196242,196242,196242,196242,196243,196244,196244,196244,196244,196244,196247,196247,196247,196248,196250,196250,196250,196251,196251,196251,196251,196251,196252,196252,196252,196252,196252,196253,196253,196258,196258,196259,196260,196261,196261,196261,196261,196262,196263,196263,196266,196267,196268,196269,196270,196270,196271,196271,196271,196272,196273,196274,196275,196275,196275,196277,196278,196279,196279,196279,196281,196282,196282,196282,196282,196283,196283,196283,196283,196283,196286,196286,196286,196286,196288,196288,196288,196288,196288,196288,196290,196292,196292,196292,196292,196292,196292,196293,196293,196293,196293,196294,196294,196294,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196295,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196296,196297,196297,196297,196297,196297,196297,196297,196297,196297,196298,196298,196298,196298,196298,196298,196298,196299,196299,196299,196300,196300,196300,196300,196302,196302,196302,196302,196302,196302,196302,196302,196302,196303,196308,196308,196308,196308,196308,196308,196310,196310,196310,196311,196312,196312,196312,196312,196312,196312,196312,196312,196312,196312,196312,196312,196312,196312,196312,196313,196313,196313,196314,196315,196315,196315,196315,196315,196315,196315,196316,196316,196317,196317,196317,196317,196317,196317,196317,196317,196317,196317,196319,196319,196319,196319,196319,196319,196321,196321,196321,196321,196321,196321,196322,196322,196322,196322,196322,196322,196322,196322,196322,196322,196322,196322,196322,196322,196322,196322,196323,196323,196323,196323,196323,196323,196325,196325,196327,196327,196327,196327,196327,196329,196329,196329,196329,196329,196329,196334,196334,196334,196334,196335,196335,196337,196337,196337,196338,196339,196339,196339,196339,196339,196339,196339,196342,196343,196343,196344,196348,196348,196348,196352,196352,196353,196357,196359,196360,196363,196369,196371,196371,196372,196372,196376,196377,196378,196378,196381,196381,196384,196384,196384,196385,196387,196387,196387,196389,196390,196390,196390,196390,196392,196394,196395,196395,196395,196395,196395,196395,196395,196396,196397,196398,196400,196401,196401,196414,196414,196414,196414,196417,196418,196418,196418,196418,196418,196418,196419,196423,196425,196425,196425,196425,196425,196427,196427,196427,196427,196427,196427,196427,196427,196427,196427,196427,196428,196428,196430,196430,196431,196431,196431,196431,196431,196431,196431,196431,196432,196432,196432,196433,196433,196433,196433,196433,196433,196433,196433,196435,196435,196435,196436,196437,196438,196438,196438,196439,196439,196442,196442,196443,196443,196445,196448,196448,196450,196450,196451,196451,196453,196453,196453,196453,196463,196468,196477,196480,196480,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196481,196483,196483,196483,196487,196487,196489,196490,196490,196493,196494,196494,196494,196495,196495,196495,196497,196498,196500,196501,196501,196501,196510,196510,196510,196510,196510,196511,196513,196515,196515,196515,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196517,196518,196518,196518,196519,196522,196525,196525,196525,196525,196526,196526,196526,196527,196527,196527,196527,196527,196527,196527,196534,196543,196543,196543,196543,196543,196543,196543,196544,196544,196547,196547,196550,196551,196551,196552,196553,196555,196555,196555,196555,196557,196558,196559,196559,196559,196560,196563,196563,196563,196566,196566,196566,196567,196567,196567,196568,196575,196577,196578,196578,196578,196588,196593,196593,196598,196598,196600,196606,196609,196610,196614,196614,196614,196614,196614,196614,196614,196614,196614,196614,196614,196617,196617,196620,196621,196621,196625,196626,196628,196631,196632,196632,196634,196642,196642,196643,196645,196650,196661,196662,196663,196664,196666,196667,196669,196670,196670,196687,196690,196693,196693,196693,196693,196693,196693,196694,196697,196700,196700,196705,196707,196710,196718,196719,196719,196719,196720,196721,196722,196724,196729,196730,196731,196732,196732,196732,196734,196734,196738,196741,196744,196744,196745,196746,196748,196752,196752,196752,196752,196754,196755,196755,196755,196755,196757,196757,196771,196779,196783,196786,196786,196786,196786,196786,196790,196790,196800,196806,196808,196811,196812,196816,196818,196828,196834,196834,196834,196834,196838,196844,196846,196849,196850,196852,196853,196858,196858,196875,196875,196876,196876,196876,196886,196888,196893,196893,196897,196913,196914,196914,196914,196916,196916,196916,196938,196939,196957,196958,196960,196963,196968,196969,196969,196985,196988,196989,196990,196991,196991,196992,196992,196992,196995,196995,196995,196995,196995,196998,196999,197002,197006,197008,197008,197008,197008,197008,197008,197008,197008,197008,197008,197009,197009,197014,197015,197024,197024,197024,197024,197032,197037,197041,197048,197048,197053,197054,197054,197054,197054,197057,197058,197065,197065,197065,197067,197067,197068,197073,197073,197074,197077,197077,197079,197080,197082,197092,197099,197104,197105,197112,197112,197112,197126,197135,197136,197146,197146,197147,197157,197158,197158,197158,197158,197158,197158,197160,197166,197167,197167,197186,197186,197186,197186,197189,197191,197193,197194,197197,197199,197199,197202,197203,197207,197207,197211,197237,197245,197248,197249,197259,197269,197269,197269,197282,197295,197301,197301,197317,197317,197326,197336,197336,197337,197340,197350,197350,197350,197350,197351,197351,197351,197360,197364,197364,197365,197373,197375,197375,197375,197376,197382,197383,197383,197383,197383,197383,197383,197383,197383,197383,197383,197383,197383,197383,197383,197383,197387,197390,197410,197415,197417,197417,197421,197424,197427,197427,197427,197427,197431,197431,197431,197431,197432,197436,197436,197438,197439,197440,197443,197443,197443,197444,197448,197452,197453,197455,197455,197455,197455,197457,197465,197471,197471,197475,197476,197476,197481,197481,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197482,197484,197485,197485,197489,197490,197491,197491,197493,197501,197506,197509,197513,197513,197513,197513,197513,197513,197521,197521,197523,197525,197533,197535,197535,197535,197535,197535,197535,197535,197538,197540,197541,197553,197556,197563,197563,197563,197566,197566,197570,197570,197571,197576,197576,197576,197578,197584,197592,197592,197592,197593,197593,197593,197593,197593,197595,197598,197600,197605,197613,197613,197613,197613,197622,197636,197636,197641,197641,197641,197641,197641,197641,197641,197641,197641,197641,197641,197646,197649,197650,197651,197652,197652,197652,197654,197654,197654,197654,197655,197658,197662,197662,197662,197664,197665,197666,197667,197667,197667,197667,197667,197667,197667,197667,197667,197669,197670,197674,197674,197674,197676,197676,197698,197704,197714,197714,197715,197715,197715,197715,197715,197715,197715,197715,197719,197719,197722,197727,197746,197753,197764,197775,197781,197789,197790,197793,197793,197793,197793,197793,197793,197793,197793,197797,197800,197801,197801,197801,197801,197801,197802,197802,197807,197811,197811,197811,197811,197811,197815,197815,197815,197817,197824,197824,197824,197824,197824,197824,197824,197824,197825,197827,197827,197827,197827,197827,197827,197828,197829,197835,197858,197861,197869,197872,197872,197872,197877,197880,197882,197882,197882,197884,197884,197885,197885,197886,197889,197889,197890,197893,197901,197904,197907,197907,197907,197911,197912,197912,197912,197914,197914,197919,197922,197923,197923,197924,197924,197924,197924,197928,197928,197933,197938,197938,197941,197944,197956,197956,197956,197959,197963,197965,197972,197973,197973,197981,197994,198000,198000,198006,198006,198007,198014,198019,198019,198023,198026,198027,198032,198034,198034,198034,198034,198034,198034,198035,198035,198037,198038,198038,198038,198038,198039,198039,198039,198039,198039,198039,198039,198039,198039,198041,198041,198041,198041,198041,198041,198043,198043,198043,198044,198048,198048,198049,198049,198049,198049,198049,198054,198056,198057,198066,198074,198077,198085,198085,198085,198085,198087,198089,198091,198097,198107,198111,198111,198111,198111,198112,198128,198130,198131,198136,198151,198159,198162,198170,198170,198173,198175,198175,198178,198178,198178,198178,198190,198190,198192,198202,198202,198204,198215,198218,198218,198220,198220,198220,198223,198223,198223,198225,198227,198227,198231,198233,198235,198236,198236,198240,198240,198242,198244,198244,198244,198246,198248,198249,198249,198251,198257,198271,198271,198271,198271,198276,198282,198282,198283,198284,198285,198286,198286,198287,198287,198288,198292,198295,198295,198297,198297,198300,198303,198304,198305,198307,198320,198324,198324,198337,198338,198339,198339,198342,198342,198348,198348,198349,198357,198363,198368,198370,198371,198373,198374,198379,198379,198379,198379,198385,198389,198389,198391,198391,198391,198393,198393,198393,198394,198394,198394,198397,198399,198399,198399,198403,198403,198403,198403,198403,198403,198403,198406,198406,198407,198407,198407,198407,198407,198409,198409,198409,198409,198409,198410,198412,198412,198412,198412,198412,198412,198412,198412,198413,198413,198413,198413,198414,198414,198416,198416,198417,198417,198417,198417,198417,198417,198417,198422,198422,198424,198426,198435,198435,198438,198444,198446,198446,198449,198456,198462,198462,198469,198471,198472,198472,198473,198473,198473,198473,198488,198498,198499,198507,198507,198507,198507,198507,198510,198510,198510,198510,198510,198514,198514,198515,198515,198515,198515,198518,198519,198523,198524,198524,198524,198530,198530,198530,198530,198533,198534,198534,198534,198534,198534,198534,198534,198535,198540,198545,198552,198555,198557,198562,198565,198565,198572,198572,198572,198593,198594,198599,198608,198609,198614,198614,198615,198621,198621,198622,198622,198631,198642,198642,198644,198645,198646,198647,198648,198648,198651,198653,198657,198663,198663,198663,198669,198669,198674,198674,198674,198674,198674,198674,198677,198677,198677,198678,198681,198681,198681,198682,198685,198692,198692,198692,198692,198692,198698,198699,198699,198699,198699,198699,198699,198701,198701,198701,198705,198705,198705,198707,198714,198715,198715,198716,198719,198719,198722,198724,198730,198731,198743,198749,198750,198750,198750,198775,198780,198781,198783,198783,198798,198798,198798,198800,198801,198801,198801,198801,198801,198803,198803,198811,198813,198821,198825,198825,198825,198825,198826,198826,198827,198828,198832,198832,198832,198832,198832,198832,198832,198832,198832,198832,198832,198833,198834,198834,198835,198835,198850,198850,198856,198857,198858,198858,198858,198862,198862,198864,198864,198867,198868,198870,198874,198874,198875,198877,198877,198877,198877,198878,198882,198886,198896,198898,198909,198909,198914,198914,198914,198914,198914,198914,198914,198914,198914,198921,198922,198922,198922,198922,198923,198926,198930,198930,198934,198942,198942,198946,198956,198956,198957,198958,198959,198960,198960,198960,198960,198960,198960,198960,198960,198960,198960,198961,198964,198967,198967,198968,198974,198975,198976,198985,198997,198997,198997,199014,199029,199032,199043,199043,199043,199043,199047,199047,199053,199053,199056,199056,199058,199061,199065,199069,199070,199070,199084,199088,199089,199089,199089,199091,199091,199091,199094,199098,199099,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199100,199103,199104,199104,199107,199107,199107,199108,199109,199111,199117,199119,199119,199119,199121,199122,199123,199124,199126,199127,199133,199134,199135,199147,199148,199156,199158,199166,199166,199173,199177,199180,199181,199181,199187,199190,199193,199194,199197,199200,199209,199213,199217,199223,199224,199226,199231,199239,199239,199245,199245,199245,199252,199254,199261,199261,199261,199261,199261,199261,199261,199261,199261,199261,199264,199264,199264,199273,199276,199277,199280,199284,199321,199323,199337,199343,199343,199343,199343,199344,199346,199346,199346,199346,199346,199346,199346,199347,199349,199350,199351,199352,199353,199353,199353,199353,199354,199356,199358,199360,199366,199371,199374,199389,199389,199392,199392,199396,199397,199400,199403,199412,199412,199415,199416,199418,199419,199419,199419,199422,199423,199425,199425,199436,199447,199447,199456,199470,199473,199478,199484,199487,199487,199487,199493,199498,199501,199508,199510,199510,199510,199510,199514,199531,199531,199531,199531,199531,199531,199531,199531,199531,199531,199538,199540,199543,199550,199551,199552,199552,199552,199552,199553,199553,199553,199553,199554,199554,199558,199558,199558,199558,199563,199575,199576,199579,199579,199579,199579,199587,199587,199591,199594,199594,199609,199609,199613,199614,199614,199615,199616,199618,199618,199618,199619,199619,199620,199620,199620,199620,199620,199620,199621,199621,199624,199625,199625,199628,199628,199629,199629,199630,199644,199644,199645,199646,199646,199653,199654,199657,199658,199658,199659,199659,199659,199659,199659,199662,199662,199662,199662,199664,199667,199670,199673,199673,199677,199681,199681,199682,199682,199684,199686,199686,199728,199729,199729,199730,199730,199731,199731,199731,199738,199738,199738,199739,199739,199740,199742,199744,199744,199744,199744,199746,199752,199754,199756,199757,199757,199759,199759,199759,199759,199759,199764,199765,199786,199786,199786,199789,199789,199790,199797,199799,199799,199800,199800,199801,199801,199802,199804,199806,199813,199814,199815,199815,199815,199815,199815,199815,199817,199817,199818,199820,199820,199822,199822,199826,199833,199833,199833,199836,199842,199850,199852,199852,199852,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199857,199860,199860,199865,199865,199866,199871,199874,199876,199876,199879,199881,199881,199883,199883,199883,199883,199883,199883,199883,199888,199889,199889,199890,199891,199895,199899,199899,199900,199904,199904,199904,199905,199905,199906,199907,199909,199910,199912,199915,199916,199918,199921,199921,199923,199924,199924,199924,199924,199924,199926,199927,199929,199929,199931,199931,199932,199937,199939,199939,199940,199940,199940,199940,199941,199941,199941,199941,199941,199941,199944,199944,199944,199944,199944,199948,199948,199948,199948,199949,199949,199950,199952,199952,199952,199952,199953,199954,199955,199958,199961,199962,199964,199967,199967,199967,199967,199967,199967,199967,199967,199967,199967,199967,199968,199968,199968,199970,199971,199971,199971,199971,199971,199973,199973,199973,199975,199975,199975,199975,199977,199977,199980,199980,199983,199983,199983,199983,199984,199985,199988,199989,199992,199994,199995,199998,199998,199998,200000,200000,200003,200004,200004,200004,200005,200005,200006,200008,200008,200008,200009,200009,200012,200016,200017,200020,200021,200021,200021,200026,200027,200030,200032,200033,200034,200040,200042,200042,200043,200050,200056,200057,200058,200064,200064,200066,200066,200066,200066,200066,200066,200066,200074,200076,200077,200079,200079,200079,200079,200079,200081,200081,200083,200083,200084,200085,200087,200087,200087,200087,200088,200090,200090,200092,200092,200092,200092,200096,200097,200112,200113,200117,200117,200117,200117,200117,200117,200117,200117,200117,200122,200125,200125,200129,200129,200129,200129,200129,200129,200129,200131,200131,200133,200134,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200141,200142,200150,200150,200150,200150,200153,200153,200154,200155,200156,200157,200160,200160,200162,200165,200166,200167,200167,200168,200169,200171,200181,200182,200184,200186,200191,200192,200192,200200,200200,200200,200200,200200,200202,200202,200203,200203,200203,200206,200208,200209,200209,200210,200212,200212,200218,200219,200225,200228,200231,200234,200239,200244,200246,200246,200246,200250,200250,200250,200250,200251,200255,200255,200256,200256,200256,200257,200257,200257,200258,200259,200259,200260,200264,200264,200265,200265,200265,200265,200267,200267,200267,200272,200272,200273,200292,200299,200301,200303,200303,200303,200304,200304,200304,200305,200305,200305,200305,200305,200305,200305,200307,200307,200307,200307,200307,200307,200308,200317,200323,200325,200327,200328,200329,200329,200329,200334,200334,200337,200341,200342,200342,200348,200352,200352,200352,200352,200352,200352,200353,200353,200355,200356,200356,200356,200361,200363,200363,200363,200364,200364,200364,200364,200366,200366,200366,200366,200366,200367,200368,200371,200371,200371,200374,200377,200384,200385,200385,200392,200392,200408,200408,200408,200408,200412,200414,200425,200438,200441,200443,200451,200457,200457,200457,200458,200458,200459,200459,200460,200461,200461,200464,200466,200471,200472,200474,200479,200480,200481,200483,200484,200484,200485,200495,200496,200496,200496,200496,200496,200503,200504,200508,200508,200511,200512,200513,200515,200517,200517,200517,200517,200517,200517,200519,200521,200521,200521,200524,200525,200526,200526,200529,200531,200535,200535,200536,200537,200538,200538,200538,200538,200538,200539,200539,200539,200542,200542,200545,200547,200547,200548,200548,200548,200548,200548,200551,200552,200552,200552,200552,200552,200555,200557,200557,200559,200560,200560,200561,200563,200563,200569,200572,200578,200578,200578,200578,200581,200587,200589,200589,200594,200594,200596,200597,200600,200602,200604,200610,200611,200611,200611,200612,200612,200616,200618,200618,200626,200628,200630,200630,200630,200630,200630,200632,200639,200640,200648,200649,200658,200658,200670,200677,200694,200694,200700,200701,200708,200708,200708,200720,200720,200724,200732,200732,200732,200744,200745,200746,200756,200758,200758,200764,200766,200771,200773,200773,200778,200780,200782,200782,200782,200782,200782,200784,200784,200784,200790,200800,200801,200801,200804,200809,200809,200809,200812,200816,200824,200830,200832,200833,200839,200839,200850,200851,200854,200862,200866,200867,200867,200872,200876,200881,200892,200892,200892,200892,200896,200896,200901,200904,200904,200905,200905,200905,200907,200909,200916,200917,200919,200919,200920,200927,200927,200931,200939,200941,200941,200945,200945,200946,200960,200960,200962,200964,200967,200967,200972,200978,200978,200981,200986,200993,201019,201020,201020,201020,201021,201025,201031,201032,201032,201032,201034,201036,201037,201049,201050,201051,201051,201051,201051,201051,201051,201051,201063,201064,201065,201065,201072,201073,201076,201076,201076,201078,201078,201083,201087,201090,201090,201096,201097,201101,201101,201102,201103,201115,201115,201115,201115,201115,201115,201115,201119,201122,201122,201126,201138,201151,201152,201153,201153,201160,201160,201163,201167,201173,201191,201202,201202,201211,201211,201211,201211,201211,201211,201211,201211,201211,201224,201231,201239,201242,201242,201249,201252,201252,201252,201253,201254,201255,201257,201263,201269,201270,201292,201292,201307,201307,201307,201307,201307,201307,201308,201312,201322,201322,201326,201326,201326,201326,201326,201326,201326,201326,201326,201326,201326,201326,201333,201341,201351,201358,201362,201363,201366,201366,201370,201372,201377,201381,201383,201386,201386,201391,201399,201404,201404,201404,201405,201407,201411,201415,201421,201421,201429,201429,201437,201437,201437,201437,201437,201437,201437,201437,201437,201437,201437,201437,201437,201437,201446,201446,201446,201449,201453,201453,201455,201464,201466,201467,201467,201471,201471,201471,201471,201474,201477,201477,201478,201478,201479,201494,201494,201505,201515,201525,201526,201526,201527,201529,201529,201530,201530,201531,201533,201553,201555,201557,201564,201595,201595,201607,201621,201626,201626,201632,201632,201633,201634,201634,201634,201635,201635,201636,201638,201638,201639,201639,201641,201649,201650,201651,201652,201652,201655,201664,201668,201668,201668,201671,201674,201675,201675,201680,201680,201680,201680,201683,201683,201688,201688,201689,201695,201696,201696,201704,201713,201715,201715,201715,201715,201721,201722,201723,201726,201733,201736,201748,201748,201748,201748,201748,201748,201748,201748,201749,201753,201758,201762,201762,201770,201771,201775,201775,201783,201783,201783,201783,201784,201785,201785,201788,201790,201791,201794,201794,201794,201794,201797,201802,201802,201802,201810,201810,201811,201814,201816,201816,201816,201819,201822,201828,201828,201828,201833,201834,201845,201845,201847,201850,201850,201850,201852,201853,201855,201855,201855,201861,201867,201871,201888,201890,201891,201894,201894,201913,201914,201914,201914,201914,201914,201914,201914,201916,201918,201923,201923,201923,201925,201942,201944,201947,201950,201950,201953,201954,201956,201956,201956,201959,201962,201962,201978,201980,201984,201984,201989,201995,201995,202000,202013,202017,202023,202025,202028,202037,202050,202051,202054,202054,202056,202056,202058,202077,202079,202083,202084,202088,202092,202093,202099,202108,202120,202128,202128,202139,202141,202146,202146,202148,202150,202153,202155,202158,202160,202176,202176,202176,202176,202178,202178,202179,202180,202181,202189,202192,202197,202198,202199,202202,202206,202206,202207,202207,202210,202210,202210,202212,202212,202213,202214,202220,202220,202223,202230,202230,202230,202230,202230,202230,202230,202236,202236,202236,202237,202237,202237,202237,202243,202245,202246,202249,202252,202253,202253,202255,202256,202257,202261,202268,202268,202280,202280,202281,202281,202281,202281,202281,202290,202290,202296,202313,202324,202332,202337,202355,202355,202355,202369,202374,202378,202391,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202396,202409,202410,202427,202429,202430,202431,202443,202443,202451,202451,202451,202451,202453,202454,202455,202455,202455,202455,202456,202456,202457,202457,202459,202459,202460,202460,202461,202461,202461,202462,202467,202467,202467,202471,202475,202480,202480,202482,202483,202483,202503,202504,202506,202508,202526,202526,202531,202538,202538,202538,202538,202538,202554,202559,202559,202564,202565,202574,202575,202576,202578,202581,202581,202584,202586,202586,202586,202586,202586,202586,202586,202589,202592,202599,202600,202601,202610,202610,202610,202611,202611,202612,202624,202624,202624,202624,202629,202630,202630,202633,202633,202633,202633,202633,202633,202633,202634,202634,202634,202636,202644,202651,202655,202655,202655,202676,202676,202681,202681,202681,202681,202686,202689,202691,202697,202700,202700,202700,202700,202700,202703,202708,202708,202715,202729,202732,202734,202734,202736,202737,202738,202738,202738,202739,202739,202739,202739,202739,202740,202740,202740,202740,202741,202742,202742,202743,202744,202744,202745,202746,202746,202746,202746,202746,202746,202746,202746,202747,202747,202747,202747,202747,202751,202751,202751,202751,202752,202752,202752,202752,202752,202755,202757,202761,202762,202764,202767,202769,202777,202777,202780,202780,202787,202789,202789,202795,202795,202810,202813,202813,202813,202813,202813,202815,202827,202830,202832,202832,202832,202848,202848,202848,202850,202850,202850,202850,202850,202850,202850,202850,202850,202850,202850,202850,202850,202852,202852,202852,202853,202853,202853,202853,202853,202853,202854,202854,202854,202855,202855,202855,202856,202856,202858,202858,202859,202859,202859,202861,202861,202864,202867,202869,202869,202871,202871,202872,202875,202877,202883,202890,202891,202891,202891,202892,202894,202903,202903,202906,202906,202906,202909,202910,202913,202916,202924,202926,202931,202932,202936,202938,202938,202938,202940,202945,202948,202948,202950,202951,202953,202954,202954,202955,202957,202960,202960,202964,202964,202964,202967,202967,202968,202968,202968,202968,202968,202973,202974,202974,202976,202980,202980,202981,202981,202981,202981,202981,202982,202982,202982,202983,202984,202984,202986,202987,202987,202987,202987,202987,202987,202987,202987,202987,202988,202988,202990,202990,202991,202992,202992,202992,202992,202993,202994,202996,202997,202998,202998,202998,202998,202998,202998,202998,202998,203004,203007,203009,203009,203009,203010,203011,203011,203013,203013,203016,203030,203031,203034,203036,203047,203049,203050,203051,203051,203053,203053,203053,203053,203056,203056,203057,203057,203057,203058,203061,203063,203063,203064,203067,203068,203069,203070,203080,203083,203086,203088,203097,203097,203097,203097,203099,203099,203100,203103,203105,203112,203121,203121,203121,203127,203128,203128,203130,203130,203135,203136,203138,203138,203138,203138,203138,203138,203139,203140,203141,203141,203142,203142,203144,203144,203146,203151,203152,203161,203161,203161,203172,203175,203180,203183,203183,203185,203187,203189,203189,203191,203195,203205,203213,203213,203213,203216,203220,203223,203223,203223,203223,203223,203223,203223,203225,203225,203230,203231,203233,203234,203237,203237,203237,203237,203237,203238,203238,203238,203239,203239,203239,203239,203240,203240,203240,203242,203243,203244,203246,203246,203247,203247,203249,203251,203253,203255,203256,203258,203263,203263,203263,203263,203266,203266,203268,203268,203268,203268,203268,203268,203269,203269,203276,203279,203279,203279,203286,203287,203287,203289,203291,203293,203299,203299,203300,203300,203301,203301,203301,203302,203306,203309,203309,203315,203315,203315,203317,203317,203317,203319,203323,203323,203323,203326,203326,203329,203333,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203335,203338,203339,203341,203347,203347,203347,203347,203351,203352,203352,203352,203352,203352,203354,203354,203355,203356,203356,203356,203357,203357,203357,203363,203364,203364,203364,203364,203364,203364,203364,203364,203365,203368,203368,203369,203369,203369,203372,203372,203372,203372,203372,203372,203373,203375,203377,203378,203378,203381,203381,203384,203384,203384,203384,203384,203385,203385,203386,203387,203388,203388,203390,203393,203394,203396,203397,203399,203400,203402,203402,203402,203402,203402,203404,203407,203417,203423,203423,203431,203438,203438,203438,203438,203438,203443,203443,203443,203444,203456,203457,203458,203464,203467,203467,203476,203477,203483,203484,203486,203487,203487,203487,203499,203501,203506,203506,203508,203509,203509,203512,203512,203515,203518,203520,203523,203527,203531,203532,203532,203532,203532,203533,203533,203533,203534,203538,203538,203538,203538,203539,203539,203542,203542,203543,203544,203544,203544,203547,203547,203550,203550,203550,203550,203550,203552,203554,203557,203558,203565,203574,203574,203574,203593,203600,203600,203601,203603,203603,203603,203603,203607,203607,203612,203612,203613,203615,203621,203626,203626,203629,203629,203637,203637,203640,203640,203640,203640,203640,203640,203640,203640,203640,203640,203642,203646,203648,203651,203652,203656,203656,203656,203656,203664,203664,203672,203682,203683,203683,203683,203689,203703,203704,203707,203713,203715,203725,203727,203729,203732,203741,203744,203744,203745,203750,203759,203760,203760,203761,203761,203764,203765,203765,203767,203767,203768,203768,203770,203778,203778,203778,203778,203782,203782,203782,203782,203782,203782,203782,203782,203782,203784,203793,203795,203795,203795,203795,203796,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203797,203798,203801,203804,203804,203804,203810,203813,203815,203817,203819,203819,203825,203826,203826,203829,203833,203836,203837,203840,203844,203854,203854,203854,203854,203854,203859,203859,203865,203870,203870,203883,203893,203897,203897,203897,203902,203903,203909,203909,203912,203917,203917,203917,203921,203921,203921,203930,203930,203930,203930,203930,203931,203933,203940,203946,203948,203948,203948,203950,203962,203964,203964,203964,203969,203971,203971,203972,203972,203972,203980,203982,203988,203988,203988,203996,203998,204001,204004,204014,204019,204023,204035,204037,204037,204043,204049,204052,204056,204059,204059,204062,204066,204067,204067,204070,204072,204072,204072,204074,204074,204075,204076,204077,204079,204080,204080,204081,204081,204084,204084,204084,204084,204087,204088,204091,204110,204113,204114,204120,204127,204131,204134,204140,204144,204144,204144,204146,204147,204148,204152,204156,204156,204159,204160,204171,204173,204181,204193,204198,204206,204209,204218,204219,204219,204222,204222,204224,204227,204229,204231,204238,204242,204248,204251,204254,204255,204256,204269,204270,204271,204271,204271,204272,204272,204274,204276,204276,204279,204279,204281,204286,204295,204295,204298,204298,204298,204299,204307,204316,204316,204317,204320,204321,204321,204322,204329,204329,204330,204341,204342,204351,204351,204351,204351,204351,204353,204354,204354,204354,204354,204354,204354,204357,204367,204370,204376,204377,204377,204388,204392,204396,204403,204411,204414,204417,204420,204420,204420,204422,204425,204426,204427,204429,204430,204434,204434,204434,204437,204439,204441,204441,204447,204449,204449,204450,204452,204453,204453,204454,204458,204458,204458,204458,204460,204463,204464,204465,204468,204473,204473,204473,204474,204477,204477,204479,204482,204488,204491,204491,204491,204497,204503,204510,204513,204513,204519,204519,204519,204525,204529,204532,204538,204549,204550,204552,204554,204554,204554,204554,204556,204559,204560,204561,204561,204561,204563,204565,204579,204581,204582,204585,204587,204587,204592,204595,204596,204596,204599,204602,204608,204610,204614,204614,204614,204616,204620,204620,204620,204620,204631,204631,204634,204639,204643,204643,204643,204643,204644,204646,204651,204651,204652,204659,204661,204661,204662,204662,204665,204665,204668,204668,204668,204676,204680,204697,204700,204700,204700,204710,204710,204710,204710,204712,204719,204722,204724,204724,204724,204726,204728,204731,204739,204742,204745,204746,204750,204752,204752,204755,204759,204768,204770,204770,204773,204781,204784,204784,204784,204787,204787,204787,204787,204787,204795,204795,204796,204801,204807,204808,204810,204811,204817,204832,204833,204835,204847,204848,204852,204852,204854,204859,204865,204865,204865,204865,204871,204872,204879,204886,204893,204893,204895,204904,204906,204908,204911,204911,204911,204913,204913,204919,204919,204919,204919,204919,204923,204927,204930,204930,204930,204930,204931,204931,204931,204931,204931,204931,204931,204938,204941,204944,204946,204948,204949,204953,204953,204955,204956,204956,204961,204963,204963,204966,204966,204966,204969,204970,204973,204973,204979,204990,204994,204994,205003,205007,205011,205011,205012,205014,205025,205025,205025,205025,205026,205032,205034,205048,205049,205051,205052,205052,205052,205052,205052,205056,205058,205058,205067,205069,205072,205074,205081,205085,205085,205085,205086,205095,205097,205123,205123,205123,205125,205132,205136,205146,205147,205149,205160,205160,205169,205171,205171,205171,205171,205171,205174,205174,205185,205186,205192,205197,205199,205201,205224,205224,205227,205243,205244,205245,205245,205245,205245,205250,205250,205250,205252,205264,205271,205272,205272,205272,205274,205280,205280,205280,205280,205280,205280,205283,205284,205284,205284,205287,205287,205287,205287,205288,205298,205300,205301,205306,205306,205306,205306,205306,205307,205308,205309,205309,205309,205309,205312,205312,205314,205315,205316,205319,205321,205322,205333,205340,205340,205340,205340,205340,205342,205351,205351,205354,205354,205354,205355,205355,205359,205361,205368,205369,205372,205373,205381,205382,205382,205384,205387,205388,205399,205405,205409,205412,205415,205417,205417,205417,205417,205417,205421,205421,205421,205421,205422,205428,205429,205433,205439,205442,205445,205445,205451,205458,205459,205461,205469,205472,205473,205475,205477,205482,205483,205487,205487,205497,205497,205499,205501,205502,205504,205504,205505,205507,205510,205513,205529,205530,205546,205551,205553,205553,205556,205556,205559,205562,205570,205583,205583,205583,205608,205609,205614,205618,205621,205621,205622,205622,205627,205627,205631,205631,205634,205635,205635,205635,205637,205640,205642,205651,205657,205657,205658,205667,205668,205668,205668,205670,205672,205673,205673,205675,205677,205682,205687,205688,205691,205710,205717,205720,205722,205722,205722,205732,205734,205740,205750,205750,205750,205750,205756,205756,205759,205761,205761,205761,205763,205763,205766,205772,205775,205775,205775,205777,205777,205777,205784,205784,205784,205785,205787,205791,205791,205791,205791,205791,205791,205793,205796,205808,205825,205825,205825,205827,205827,205827,205827,205827,205827,205827,205827,205827,205827,205827,205829,205831,205839,205840,205842,205845,205850,205851,205860,205875,205875,205876,205882,205883,205889,205899,205901,205914,205921,205925,205927,205934,205937,205937,205937,205948,205950,205950,205953,205955,205955,205955,205955,205955,205956,205960,205960,205960,205968,205972,205974,205975,205982,205984,205984,205984,205984,205984,205996,205997,205997,205998,206002,206003,206005,206006,206007,206008,206010,206012,206023,206029,206029,206029,206031,206031,206040,206041,206045,206050,206057,206057,206058,206058,206058,206058,206058,206058,206063,206063,206067,206070,206070,206070,206070,206073,206078,206082,206084,206090,206090,206090,206095,206102,206105,206107,206107,206109,206110,206111,206127,206127,206127,206127,206128,206134,206136,206136,206136,206136,206136,206136,206136,206136,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206141,206146,206153,206153,206156,206159,206160,206165,206171,206171,206171,206172,206174,206176,206176,206177,206178,206211,206211,206211,206224,206227,206239,206249,206257,206282,206282,206283,206287,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206293,206294,206294,206294,206313,206320,206324,206324,206326,206326,206328,206334,206334,206335,206347,206347,206347,206347,206347,206351,206351,206351,206351,206351,206352,206352,206352,206355,206355,206355,206355,206355,206355,206366,206368,206368,206372,206373,206373,206373,206378,206384,206385,206385,206390,206392,206402,206402,206413,206417,206417,206417,206425,206425,206429,206441,206442,206444,206444,206446,206449,206449,206454,206461,206461,206461,206461,206461,206461,206461,206461,206461,206461,206468,206472,206473,206473,206475,206481,206484,206484,206484,206484,206485,206485,206485,206485,206485,206495,206500,206500,206500,206500,206500,206510,206510,206510,206510,206520,206524,206524,206524,206524,206530,206530,206530,206530,206530,206534,206536,206537,206537,206541,206546,206569,206569,206569,206572,206572,206572,206576,206577,206583,206583,206583,206583,206584,206584,206584,206584,206586,206586,206586,206590,206597,206597,206598,206603,206611,206629,206634,206634,206634,206634,206634,206636,206643,206645,206645,206648,206648,206652,206654,206654,206654,206661,206677,206678,206681,206681,206685,206686,206689,206692,206696,206697,206706,206711,206713,206724,206747,206757,206759,206763,206764,206767,206769,206776,206778,206778,206778,206825,206826,206828,206836,206851,206855,206856,206856,206856,206856,206871,206882,206882,206882,206882,206883,206889,206898,206898,206921,206931,206931,206934,206934,206941,206948,206948,206957,206959,206960,206960,206963,206970,206970,206973,206973,206973,206976,206978,206978,206978,206981,206981,206981,206981,206982,206982,206985,206985,206985,206986,206989,207000,207006,207009,207010,207010,207012,207014,207014,207018,207020,207021,207023,207028,207033,207052,207055,207059,207062,207066,207074,207074,207075,207075,207075,207086,207090,207107,207110,207110,207110,207110,207110,207110,207112,207114,207116,207118,207128,207135,207143,207155,207155,207155,207155,207155,207155,207155,207155,207155,207157,207157,207168,207168,207169,207170,207175,207181,207204,207214,207226,207226,207226,207226,207230,207242,207242,207242,207243,207243,207243,207243,207243,207243,207243,207243,207243,207243,207243,207243,207243,207243,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207244,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207245,207246,207246,207246,207246,207246,207246,207246,207247,207247,207247,207248,207248,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207249,207250,207250,207250,207250,207250,207251,207251,207251,207251,207251,207251,207251,207252,207252,207252,207252,207252,207252,207252,207253,207253,207254,207255,207257,207259,207259,207259,207259,207259,207259,207259,207259,207259,207260,207260,207260,207260,207260,207261,207263,207263,207263,207264,207264,207264,207264,207264,207264,207264,207264,207267,207271,207271,207272,207272,207272,207272,207274,207274,207274,207274,207274,207279,207279,207279,207281,207281,207281,207281,207283,207284,207284,207284,207285,207287,207287,207287,207287,207287,207288,207292,207292,207292,207292,207292,207293,207293,207295,207296,207296,207301,207301,207301,207304,207306,207308,207308,207308,207311,207312,207312,207312,207314,207314,207314,207314,207314,207314,207314,207314,207314,207314,207314,207315,207315,207315,207316,207317,207317,207324,207326,207327,207327,207328,207334,207334,207334,207336,207339,207340,207340,207343,207347,207347,207348,207349,207349,207350,207351,207351,207354,207355,207355,207356,207356,207356,207358,207359,207359,207359,207359,207359,207359,207360,207361,207362,207362,207364,207366,207366,207366,207366,207366,207366,207366,207366,207368,207370,207370,207375,207375,207375,207375,207377,207377,207382,207382,207387,207387,207399,207399,207405,207414,207418,207420,207422,207425,207425,207427,207427,207427,207428,207428,207428,207428,207429,207429,207432,207432,207433,207435,207435,207435,207436,207441,207441,207442,207443,207445,207445,207445,207445,207445,207446,207446,207446,207450,207452,207452,207452,207454,207454,207460,207462,207464,207468,207470,207470,207476,207478,207480,207485,207492,207500,207501,207501,207501,207501,207503,207510,207510,207510,207510,207514,207515,207523,207528,207528,207528,207528,207530,207538,207538,207542,207542,207542,207542,207551,207553,207554,207554,207554,207559,207559,207560,207561,207562,207564,207564,207565,207575,207575,207583,207583,207590,207591,207594,207594,207597,207611,207612,207613,207613,207615,207615,207619,207620,207626,207631,207632,207632,207632,207633,207633,207633,207633,207633,207633,207633,207633,207633,207633,207633,207635,207635,207636,207642,207642,207642,207644,207647,207648,207648,207650,207651,207655,207656,207656,207657,207658,207663,207666,207666,207667,207667,207667,207672,207682,207682,207689,207690,207697,207697,207716,207716,207716,207716,207718,207720,207724,207725,207725,207725,207725,207726,207728,207729,207729,207729,207732,207734,207740,207746,207755,207758,207758,207758,207760,207762,207766,207770,207770,207771,207771,207771,207771,207771,207775,207775,207775,207782,207784,207785,207786,207788,207788,207788,207788,207791,207791,207792,207792,207792,207795,207797,207806,207807,207809,207811,207811,207816,207819,207822,207823,207828,207828,207828,207831,207833,207836,207837,207842,207848,207849,207849,207851,207856,207857,207857,207857,207857,207857,207857,207857,207857,207858,207858,207862,207862,207863,207863,207864,207868,207869,207869,207870,207870,207872,207872,207875,207878,207882,207887,207888,207891,207894,207896,207897,207914,207915,207926,207928,207928,207928,207930,207931,207931,207933,207933,207934,207935,207935,207937,207938,207944,207948,207949,207949,207949,207955,207955,207962,207963,207971,207973,207977,207984,207987,207992,207993,207993,207993,207994,207994,207994,207994,207994,207994,207997,207997,207997,207997,207997,207998,208000,208023,208028,208028,208028,208030,208030,208034,208041,208042,208046,208054,208057,208058,208083,208083,208083,208083,208095,208095,208121,208121,208123,208137,208137,208137,208137,208137,208137,208137,208137,208137,208137,208137,208153,208153,208157,208157,208157,208162,208162,208163,208166,208171,208173,208183,208183,208183,208185,208185,208185,208185,208186,208186,208188,208188,208190,208190,208198,208205,208210,208211,208221,208221,208221,208225,208225,208226,208230,208235,208235,208235,208237,208241,208241,208248,208250,208251,208251,208251,208258,208260,208262,208274,208276,208279,208281,208281,208285,208291,208311,208313,208318,208319,208322,208327,208328,208333,208335,208344,208344,208344,208351,208360,208362,208366,208366,208385,208385,208389,208397,208401,208403,208403,208403,208403,208408,208416,208421,208421,208421,208421,208421,208423,208423,208424,208424,208426,208428,208440,208443,208443,208447,208447,208447,208447,208447,208447,208447,208447,208447,208447,208447,208449,208449,208449,208451,208451,208451,208451,208451,208451,208451,208451,208452,208452,208452,208454,208470,208473,208475,208475,208485,208494,208494,208495,208495,208503,208512,208520,208528,208531,208547,208553,208553,208554,208555,208555,208560,208560,208560,208562,208564,208579,208579,208583,208586,208596,208636,208636,208636,208637,208639,208646,208647,208648,208649,208649,208654,208654,208654,208654,208654,208662,208670,208670,208671,208673,208673,208673,208675,208676,208682,208682,208684,208687,208689,208691,208692,208694,208703,208706,208706,208706,208716,208716,208719,208719,208747,208754,208759,208759,208759,208766,208766,208767,208768,208776,208776,208781,208782,208782,208786,208807,208807,208807,208818,208822,208846,208849,208850,208856,208856,208856,208858,208861,208864,208865,208867,208867,208871,208873,208874,208874,208882,208888,208890,208890,208892,208906,208907,208914,208914,208914,208914,208915,208923,208923,208924,208929,208935,208936,208936,208940,208943,208948,208948,208948,208948,208958,208958,208960,208960,208961,208961,208967,208968,208972,208981,208986,208987,208989,208990,208993,208999,209000,209002,209009,209013,209016,209026,209032,209034,209038,209038,209038,209038,209047,209055,209055,209055,209055,209059,209064,209067,209067,209068,209069,209072,209076,209078,209081,209093,209095,209098,209101,209104,209106,209108,209108,209108,209108,209109,209109,209113,209113,209113,209115,209117,209120,209120,209126,209131,209132,209135,209140,209152,209160,209165,209178,209187,209188,209199,209205,209208,209210,209211,209222,209228,209229,209231,209234,209236,209236,209241,209244,209245,209245,209246,209246,209246,209247,209247,209249,209249,209249,209250,209253,209254,209254,209255,209258,209258,209258,209258,209258,209258,209260,209261,209269,209283,209283,209293,209295,209299,209299,209307,209318,209322,209325,209325,209333,209333,209333,209333,209333,209333,209333,209333,209333,209336,209337,209338,209338,209355,209357,209371,209380,209382,209392,209396,209396,209403,209408,209411,209411,209411,209412,209414,209418,209418,209418,209418,209418,209418,209429,209429,209429,209431,209432,209433,209435,209450,209457,209459,209472,209482,209482,209482,209482,209482,209482,209482,209482,209484,209485,209497,209501,209504,209506,209506,209507,209512,209514,209514,209515,209517,209519,209519,209523,209524,209539,209547,209553,209553,209553,209553,209556,209557,209561,209563,209563,209563,209563,209563,209563,209563,209563,209563,209563,209563,209563,209563,209563,209565,209568,209577,209577,209580,209580,209580,209581,209582,209584,209585,209588,209588,209591,209591,209592,209594,209594,209598,209606,209607,209614,209614,209615,209615,209615,209615,209615,209626,209626,209631,209631,209636,209640,209644,209647,209650,209650,209664,209678,209683,209683,209683,209683,209690,209702,209708,209708,209712,209714,209715,209716,209723,209724,209727,209736,209754,209758,209758,209762,209769,209770,209773,209773,209776,209777,209777,209777,209791,209792,209793,209793,209793,209795,209795,209798,209801,209804,209806,209823,209825,209845,209845,209850,209850,209852,209852,209853,209854,209854,209855,209861,209872,209875,209875,209875,209886,209886,209887,209887,209887,209887,209890,209893,209893,209893,209893,209893,209893,209893,209893,209904,209905,209911,209920,209921,209921,209922,209924,209927,209933,209934,209935,209935,209936,209936,209941,209941,209944,209944,209952,209952,209953,209954,209959,209960,209970,209978,209989,209993,210007,210011,210015,210017,210026,210028,210038,210040,210041,210043,210046,210046,210048,210049,210057,210060,210062,210064,210064,210064,210066,210069,210072,210072,210072,210073,210073,210075,210090,210094,210097,210101,210113,210120,210139,210139,210139,210139,210139,210139,210139,210140,210141,210150,210150,210165,210167,210171,210172,210173,210176,210179,210180,210188,210188,210188,210188,210188,210188,210188,210188,210191,210191,210191,210191,210193,210193,210193,210193,210199,210208,210210,210212,210213,210213,210214,210214,210214,210218,210222,210223,210226,210233,210235,210237,210241,210244,210245,210245,210247,210248,210248,210254,210255,210257,210257,210258,210258,210259,210259,210259,210260,210260,210263,210266,210266,210266,210268,210268,210276,210279,210280,210280,210280,210282,210282,210286,210288,210288,210288,210288,210289,210289,210291,210292,210292,210292,210292,210292,210294,210294,210302,210305,210305,210308,210309,210310,210312,210312,210312,210312,210317,210317,210317,210317,210317,210319,210328,210328,210332,210332,210333,210335,210336,210338,210338,210338,210338,210341,210341,210341,210342,210342,210344,210347,210350,210350,210350,210353,210353,210359,210364,210367,210368,210371,210373,210375,210375,210378,210381,210386,210386,210389,210389,210389,210391,210391,210391,210391,210394,210396,210397,210397,210399,210400,210402,210406,210411,210411,210413,210415,210417,210424,210424,210427,210427,210430,210430,210436,210436,210436,210436,210441,210441,210441,210445,210445,210445,210445,210447,210447,210448,210450,210450,210451,210452,210452,210452,210452,210454,210456,210456,210463,210463,210464,210465,210472,210473,210473,210474,210479,210479,210479,210492,210501,210501,210501,210501,210501,210507,210507,210507,210511,210515,210518,210518,210523,210524,210525,210528,210528,210528,210528,210528,210535,210540,210541,210544,210550,210552,210552,210552,210552,210553,210554,210554,210556,210557,210557,210557,210558,210560,210562,210563,210566,210566,210575,210578,210581,210584,210592,210593,210595,210597,210603,210607,210608,210614,210614,210614,210614,210614,210617,210617,210628,210628,210628,210631,210632,210632,210632,210639,210640,210640,210643,210643,210644,210644,210644,210644,210644,210644,210645,210645,210645,210645,210645,210648,210648,210655,210656,210657,210658,210658,210659,210663,210663,210663,210663,210663,210663,210671,210671,210671,210674,210674,210674,210674,210679,210683,210685,210686,210686,210686,210687,210688,210688,210695,210695,210695,210695,210695,210697,210697,210697,210697,210697,210697,210697,210697,210698,210698,210700,210702,210711,210711,210718,210727,210728,210728,210728,210737,210739,210739,210739,210740,210740,210740,210742,210743,210743,210743,210743,210743,210744,210746,210746,210750,210750,210750,210750,210750,210751,210751,210751,210760,210770,210780,210792,210794,210796,210797,210798,210799,210799,210801,210807,210807,210807,210807,210807,210810,210811,210811,210811,210814,210814,210814,210814,210821,210826,210826,210826,210826,210831,210831,210831,210831,210831,210831,210840,210840,210840,210840,210840,210840,210844,210844,210846,210846,210853,210853,210854,210854,210858,210858,210858,210858,210858,210860,210862,210862,210878,210879,210879,210883,210884,210884,210884,210885,210892,210895,210897,210897,210900,210900,210901,210901,210903,210904,210907,210917,210921,210921,210924,210924,210928,210931,210931,210931,210933,210940,210940,210946,210946,210946,210946,210946,210946,210952,210966,210969,210973,210975,210976,210976,210979,210985,210987,210987,210987,210988,210988,210988,210988,210988,210988,210988,210988,210989,210991,210991,210991,210991,210999,211007,211008,211011,211011,211014,211019,211027,211031,211031,211037,211038,211038,211038,211051,211051,211056,211056,211056,211057,211057,211057,211057,211057,211057,211057,211057,211057,211057,211057,211058,211058,211065,211069,211087,211091,211100,211100,211100,211106,211107,211109,211111,211111,211111,211123,211129,211131,211133,211133,211136,211138,211142,211143,211147,211150,211152,211152,211152,211154,211156,211156,211156,211162,211172,211175,211180,211180,211183,211183,211183,211183,211189,211197,211211,211231,211236,211242,211242,211242,211242,211245,211251,211256,211257,211257,211269,211271,211271,211283,211286,211286,211289,211289,211289,211289,211289,211295,211299,211301,211302,211302,211307,211307,211307,211311,211311,211311,211321,211321,211321,211325,211329,211330,211332,211332,211339,211339,211339,211341,211341,211346,211348,211348,211348,211348,211348,211348,211353,211353,211353,211354,211355,211355,211355,211355,211358,211359,211361,211365,211365,211367,211367,211367,211367,211367,211367,211367,211367,211369,211370,211372,211373,211373,211376,211380,211380,211383,211385,211391,211409,211411,211412,211412,211412,211412,211412,211412,211412,211412,211412,211413,211415,211415,211421,211424,211425,211433,211434,211434,211434,211434,211434,211435,211435,211435,211444,211454,211463,211463,211466,211480,211480,211480,211493,211494,211494,211494,211494,211494,211495,211496,211500,211501,211506,211510,211518,211520,211520,211530,211531,211531,211531,211544,211545,211546,211547,211548,211548,211548,211549,211552,211556,211556,211556,211556,211556,211556,211556,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211558,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211559,211560,211560,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211561,211562,211562,211562,211564,211564,211564,211564,211564,211564,211564,211564,211565,211565,211566,211566,211567,211568,211568,211568,211568,211568,211568,211572,211573,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211574,211575,211575,211576,211576,211578,211578,211579,211579,211582,211583,211585,211586,211586,211586,211586,211586,211586,211587,211589,211589,211589,211590,211590,211592,211592,211592,211592,211592,211592,211593,211595,211595,211596,211597,211599,211599,211600,211600,211601,211601,211602,211602,211602,211603,211603,211603,211605,211608,211608,211608,211610,211612,211612,211614,211614,211615,211615,211615,211615,211617,211617,211618,211629,211630,211630,211630,211630,211630,211630,211631,211631,211632,211632,211634,211634,211635,211635,211635,211635,211636,211636,211638,211638,211639,211639,211641,211642,211642,211644,211647,211650,211650,211651,211652,211652,211652,211654,211654,211656,211657,211662,211662,211662,211666,211666,211666,211666,211669,211670,211671,211671,211675,211681,211682,211682,211682,211683,211684,211685,211685,211685,211687,211687,211687,211687,211688,211688,211691,211693,211694,211697,211701,211702,211704,211705,211706,211707,211708,211708,211708,211709,211709,211711,211711,211711,211714,211714,211714,211716,211717,211717,211718,211718,211719,211719,211719,211719,211719,211719,211720,211721,211721,211722,211724,211725,211732,211732,211738,211738,211744,211751,211752,211752,211754,211754,211754,211756,211757,211757,211757,211757,211757,211760,211760,211761,211761,211761,211761,211762,211766,211767,211770,211772,211772,211772,211772,211772,211782,211785,211789,211790,211791,211793,211798,211798,211799,211799,211801,211809,211809,211821,211821,211828,211828,211831,211835,211839,211840,211840,211840,211840,211841,211842,211842,211842,211842,211843,211843,211843,211849,211850,211850,211852,211852,211853,211858,211858,211860,211861,211862,211863,211863,211866,211872,211879,211882,211882,211882,211882,211882,211886,211886,211886,211886,211896,211896,211896,211897,211897,211898,211898,211900,211900,211900,211906,211907,211911,211911,211911,211912,211912,211914,211915,211918,211919,211919,211924,211924,211924,211924,211924,211925,211925,211925,211925,211925,211929,211929,211929,211929,211930,211930,211930,211930,211930,211930,211931,211933,211936,211938,211938,211938,211938,211942,211942,211942,211942,211952,211952,211952,211952,211952,211952,211952,211952,211952,211952,211953,211953,211956,211956,211956,211958,211958,211963,211964,211965,211965,211966,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211971,211972,211975,211981,211982,211982,211982,211997,212001,212001,212007,212007,212008,212008,212011,212011,212011,212011,212013,212018,212019,212020,212020,212022,212023,212024,212024,212029,212030,212033,212034,212035,212041,212042,212045,212045,212046,212046,212046,212047,212052,212052,212053,212053,212054,212054,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212055,212057,212057,212057,212057,212057,212057,212057,212058,212058,212065,212065,212065,212065,212066,212069,212072,212073,212073,212073,212074,212074,212074,212074,212074,212074,212076,212077,212077,212079,212080,212080,212080,212080,212080,212080,212081,212084,212084,212087,212087,212092,212093,212094,212094,212095,212096,212102,212102,212102,212103,212103,212103,212105,212107,212108,212108,212115,212118,212118,212118,212124,212136,212136,212137,212142,212142,212148,212148,212148,212148,212148,212148,212148,212151,212151,212157,212158,212158,212159,212159,212160,212160,212161,212161,212161,212161,212163,212166,212173,212173,212173,212173,212174,212174,212174,212174,212175,212176,212178,212178,212180,212181,212187,212188,212188,212188,212188,212188,212188,212191,212193,212194,212194,212194,212194,212194,212194,212195,212195,212195,212195,212195,212200,212205,212210,212210,212210,212210,212211,212211,212211,212211,212213,212219,212224,212228,212231,212233,212233,212233,212234,212235,212235,212238,212239,212239,212239,212239,212239,212239,212241,212242,212242,212242,212242,212243,212243,212243,212243,212245,212245,212245,212247,212247,212248,212249,212251,212251,212251,212252,212256,212256,212256,212256,212259,212259,212259,212259,212259,212260,212260,212260,212263,212265,212266,212266,212266,212266,212269,212270,212272,212273,212274,212276,212280,212284,212284,212284,212284,212288,212290,212290,212291,212294,212298,212299,212299,212306,212306,212306,212306,212306,212306,212306,212306,212306,212307,212309,212309,212311,212311,212311,212311,212311,212311,212315,212315,212320,212321,212322,212326,212326,212336,212355,212355,212356,212357,212357,212357,212360,212360,212360,212360,212370,212373,212373,212375,212384,212384,212390,212398,212406,212420,212420,212428,212430,212430,212430,212430,212430,212431,212436,212441,212441,212441,212441,212449,212450,212455,212455,212455,212455,212455,212455,212455,212455,212455,212455,212455,212458,212458,212459,212462,212473,212473,212476,212476,212476,212486,212498,212502,212502,212511,212511,212513,212513,212513,212514,212517,212518,212518,212518,212518,212518,212518,212520,212522,212524,212524,212528,212531,212533,212534,212538,212539,212539,212539,212539,212539,212540,212542,212548,212548,212551,212552,212552,212556,212558,212558,212566,212566,212571,212572,212572,212572,212574,212575,212575,212576,212577,212577,212577,212577,212577,212578,212583,212583,212583,212583,212583,212583,212585,212585,212586,212588,212589,212590,212590,212590,212591,212592,212597,212599,212599,212599,212599,212601,212603,212605,212606,212606,212608,212608,212608,212611,212611,212613,212613,212621,212621,212622,212622,212623,212623,212626,212627,212628,212630,212630,212645,212645,212647,212647,212647,212649,212652,212657,212657,212659,212668,212673,212673,212673,212684,212684,212685,212685,212685,212687,212688,212689,212689,212697,212699,212702,212704,212711,212711,212711,212711,212714,212717,212718,212719,212720,212743,212743,212743,212746,212748,212750,212754,212759,212759,212760,212761,212761,212761,212761,212761,212761,212763,212763,212763,212764,212769,212786,212790,212790,212794,212794,212794,212802,212802,212803,212805,212805,212811,212811,212811,212812,212812,212812,212812,212812,212812,212812,212812,212815,212815,212820,212820,212820,212820,212820,212824,212824,212824,212826,212829,212829,212832,212834,212834,212838,212838,212839,212839,212839,212839,212841,212841,212841,212841,212841,212841,212843,212843,212847,212849,212851,212851,212852,212853,212854,212854,212854,212854,212854,212855,212856,212856,212856,212858,212859,212859,212859,212861,212863,212863,212866,212866,212866,212866,212866,212866,212866,212866,212866,212867,212867,212870,212870,212870,212871,212872,212882,212885,212889,212889,212889,212889,212889,212889,212891,212891,212892,212892,212892,212892,212892,212892,212892,212894,212894,212894,212895,212895,212895,212895,212895,212895,212896,212899,212899,212899,212899,212900,212900,212900,212901,212901,212901,212901,212903,212905,212905,212905,212905,212905,212905,212905,212905,212906,212906,212908,212909,212913,212914,212914,212914,212915,212918,212918,212918,212920,212922,212922,212922,212922,212922,212922,212922,212923,212923,212924,212924,212924,212924,212925,212926,212928,212930,212931,212933,212933,212942,212942,212947,212950,212950,212951,212951,212952,212954,212958,212961,212973,212975,212975,212975,212979,212979,212979,212980,212980,212984,212990,212993,212997,213003,213004,213010,213010,213013,213013,213017,213020,213020,213021,213023,213025,213025,213028,213028,213028,213028,213029,213033,213035,213035,213038,213039,213043,213045,213045,213046,213057,213057,213057,213066,213066,213066,213068,213072,213074,213082,213082,213082,213083,213083,213083,213083,213083,213083,213083,213083,213083,213083,213083,213083,213086,213087,213088,213089,213089,213091,213096,213099,213102,213102,213112,213119,213119,213124,213127,213130,213139,213139,213147,213150,213152,213152,213152,213156,213163,213165,213166,213167,213167,213168,213169,213173,213174,213176,213180,213183,213183,213183,213183,213190,213190,213190,213191,213191,213193,213193,213201,213201,213201,213202,213202,213203,213207,213207,213207,213207,213207,213207,213208,213208,213211,213211,213211,213212,213212,213215,213217,213218,213218,213219,213221,213221,213221,213224,213225,213226,213226,213226,213226,213226,213226,213229,213229,213229,213243,213244,213244,213244,213248,213250,213251,213252,213254,213254,213255,213255,213257,213260,213262,213262,213265,213265,213269,213271,213272,213272,213272,213277,213281,213281,213282,213282,213282,213282,213282,213284,213285,213286,213287,213289,213292,213292,213293,213293,213295,213304,213306,213307,213311,213315,213316,213319,213319,213319,213319,213322,213322,213323,213325,213325,213327,213327,213327,213328,213334,213334,213337,213337,213339,213339,213339,213342,213342,213342,213342,213343,213345,213349,213354,213356,213357,213359,213359,213370,213371,213373,213376,213378,213380,213382,213385,213386,213386,213386,213386,213386,213391,213392,213392,213395,213411,213411,213411,213412,213412,213416,213416,213416,213417,213418,213436,213439,213440,213440,213440,213447,213451,213451,213452,213452,213462,213466,213466,213466,213471,213471,213473,213473,213479,213480,213481,213481,213485,213493,213495,213499,213500,213505,213506,213507,213507,213507,213508,213511,213511,213511,213512,213512,213512,213519,213523,213527,213529,213529,213529,213529,213529,213529,213533,213533,213544,213545,213546,213546,213546,213547,213547,213547,213548,213548,213548,213549,213551,213552,213552,213552,213554,213555,213555,213556,213556,213556,213558,213559,213561,213562,213564,213566,213566,213567,213567,213567,213571,213571,213577,213579,213582,213583,213583,213589,213589,213589,213590,213596,213596,213608,213609,213613,213616,213616,213616,213616,213630,213630,213631,213631,213631,213631,213631,213631,213631,213631,213642,213644,213646,213650,213660,213667,213671,213671,213672,213673,213677,213686,213686,213686,213686,213686,213688,213690,213690,213690,213702,213711,213711,213712,213712,213712,213712,213712,213716,213728,213729,213730,213732,213732,213732,213732,213732,213736,213738,213738,213741,213746,213746,213747,213747,213747,213747,213753,213753,213753,213753,213753,213753,213753,213753,213753,213756,213757,213758,213759,213766,213766,213766,213769,213769,213769,213770,213771,213773,213773,213774,213779,213781,213781,213781,213782,213784,213785,213786,213787,213789,213799,213801,213806,213808,213810,213818,213828,213828,213841,213841,213842,213843,213843,213843,213844,213850,213850,213852,213852,213853,213857,213860,213860,213869,213871,213871,213871,213871,213871,213871,213871,213871,213871,213871,213872,213873,213873,213873,213877,213879,213879,213882,213884,213895,213895,213899,213901,213903,213913,213913,213913,213913,213913,213914,213916,213917,213924,213926,213928,213942,213942,213943,213943,213943,213946,213954,213957,213957,213957,213960,213960,213960,213961,213961,213961,213976,213976,213979,213982,213985,213986,213987,213999,213999,213999,214000,214002,214003,214003,214003,214011,214014,214017,214024,214031,214034,214039,214039,214051,214051,214056,214066,214069,214073,214082,214084,214091,214091,214091,214092,214096,214101,214104,214105,214105,214105,214106,214107,214111,214111,214111,214111,214111,214112,214112,214112,214112,214112,214112,214116,214117,214124,214128,214131,214140,214145,214154,214154,214154,214158,214158,214161,214161,214161,214161,214161,214163,214165,214165,214166,214173,214173,214173,214173,214174,214176,214176,214176,214179,214179,214179,214179,214179,214180,214180,214183,214187,214187,214187,214187,214189,214189,214189,214190,214190,214190,214190,214190,214190,214191,214191,214191,214191,214191,214191,214191,214191,214191,214191,214192,214192,214192,214192,214192,214192,214192,214192,214192,214192,214192,214192,214193,214193,214193,214193,214194,214195,214196,214196,214196,214196,214197,214197,214200,214200,214200,214200,214202,214202,214202,214202,214202,214202,214203,214203,214203,214205,214206,214207,214207,214207,214209,214209,214209,214209,214211,214211,214213,214215,214217,214217,214217,214218,214218,214221,214221,214225,214225,214225,214225,214225,214225,214227,214227,214227,214233,214233,214235,214239,214239,214239,214240,214240,214240,214240,214240,214242,214242,214242,214242,214243,214243,214245,214246,214246,214247,214249,214254,214254,214257,214258,214258,214258,214258,214258,214259,214260,214260,214260,214261,214261,214261,214264,214264,214264,214264,214264,214271,214271,214271,214271,214271,214271,214272,214274,214275,214275,214275,214275,214278,214281,214281,214283,214283,214283,214284,214286,214286,214289,214290,214291,214291,214291,214292,214293,214296,214307,214307,214308,214308,214311,214311,214312,214314,214314,214324,214328,214328,214328,214328,214328,214328,214328,214328,214328,214328,214329,214332,214333,214334,214335,214336,214338,214339,214341,214343,214344,214348,214348,214352,214352,214352,214352,214353,214354,214355,214358,214362,214363,214365,214365,214365,214365,214366,214368,214373,214379,214384,214384,214394,214399,214399,214401,214408,214408,214408,214409,214411,214414,214417,214419,214419,214419,214425,214433,214437,214438,214439,214445,214445,214445,214449,214452,214452,214453,214456,214457,214460,214462,214467,214467,214468,214468,214469,214472,214473,214476,214478,214479,214483,214485,214486,214489,214491,214491,214491,214491,214491,214491,214492,214493,214495,214496,214496,214496,214497,214497,214497,214497,214497,214497,214497,214500,214501,214501,214501,214501,214501,214501,214501,214505,214509,214514,214515,214517,214518,214520,214521,214521,214521,214521,214521,214521,214521,214521,214522,214522,214522,214526,214527,214530,214532,214533,214533,214536,214538,214538,214538,214539,214539,214539,214541,214541,214541,214542,214542,214545,214545,214545,214547,214549,214549,214549,214549,214553,214554,214554,214554,214554,214554,214554,214555,214557,214558,214558,214560,214560,214560,214560,214560,214568,214570,214571,214576,214580,214581,214584,214585,214585,214585,214585,214587,214591,214591,214597,214598,214607,214611,214612,214612,214614,214617,214617,214619,214620,214622,214623,214625,214628,214629,214631,214639,214639,214639,214640,214642,214644,214645,214651,214651,214651,214652,214655,214655,214655,214656,214656,214656,214656,214657,214657,214658,214658,214658,214658,214658,214658,214661,214667,214667,214667,214667,214667,214667,214668,214668,214674,214676,214676,214679,214679,214681,214681,214681,214681,214683,214683,214688,214690,214693,214697,214697,214697,214698,214698,214698,214698,214698,214698,214698,214698,214700,214701,214701,214702,214704,214706,214709,214711,214711,214717,214717,214718,214719,214719,214719,214719,214719,214719,214719,214719,214719,214719,214727,214730,214733,214741,214741,214743,214751,214754,214754,214754,214756,214756,214756,214756,214756,214756,214756,214756,214756,214756,214756,214756,214757,214758,214763,214763,214766,214771,214773,214773,214773,214774,214783,214783,214783,214787,214788,214790,214790,214790,214791,214792,214794,214795,214796,214799,214799,214799,214799,214801,214801,214801,214801,214801,214803,214803,214803,214803,214803,214808,214808,214809,214812,214812,214812,214812,214812,214812,214813,214813,214813,214813,214813,214813,214813,214813,214813,214813,214813,214813,214816,214816,214817,214817,214820,214820,214820,214820,214824,214825,214826,214828,214830,214830,214831,214831,214831,214831,214832,214832,214832,214834,214834,214837,214837,214837,214837,214838,214838,214838,214838,214838,214839,214839,214841,214841,214841,214841,214843,214843,214844,214844,214844,214845,214848,214850,214851,214853,214854,214854,214854,214854,214856,214857,214858,214859,214859,214859,214859,214859,214861,214861,214866,214866,214866,214867,214867,214869,214869,214869,214870,214874,214876,214876,214876,214877,214877,214877,214882,214886,214886,214886,214891,214892,214892,214894,214894,214894,214895,214897,214897,214897,214897,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214898,214904,214905,214908,214908,214911,214918,214920,214921,214922,214924,214928,214935,214938,214938,214940,214945,214946,214946,214947,214951,214951,214952,214952,214956,214956,214959,214960,214962,214962,214983,214985,214985,214985,214988,214988,214988,214988,214989,214990,214990,214990,214990,214991,214992,214992,214996,214997,214997,214998,214998,215001,215001,215001,215001,215001,215001,215003,215003,215005,215005,215005,215005,215006,215006,215007,215007,215007,215008,215008,215008,215012,215013,215013,215013,215014,215014,215015,215015,215015,215015,215016,215024,215025,215025,215025,215026,215026,215026,215026,215026,215026,215026,215026,215026,215026,215032,215037,215037,215042,215047,215047,215049,215050,215050,215050,215050,215059,215063,215064,215068,215069,215070,215070,215073,215073,215074,215079,215083,215087,215091,215093,215095,215095,215095,215099,215099,215101,215101,215102,215102,215103,215103,215103,215103,215105,215108,215110,215110,215110,215111,215120,215120,215132,215132,215132,215147,215149,215150,215153,215153,215153,215154,215156,215162,215166,215168,215169,215175,215175,215175,215175,215176,215178,215178,215183,215184,215186,215195,215195,215196,215197,215197,215200,215201,215201,215202,215203,215203,215203,215204,215206,215207,215207,215207,215208,215209,215209,215211,215217,215217,215217,215235,215235,215235,215235,215239,215239,215241,215241,215242,215243,215243,215244,215247,215252,215252,215252,215252,215258,215260,215266,215266,215270,215271,215272,215273,215274,215274,215274,215274,215276,215276,215277,215277,215277,215277,215277,215277,215278,215285,215285,215285,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215287,215296,215296,215297,215297,215297,215299,215300,215300,215304,215304,215304,215306,215306,215307,215312,215313,215313,215315,215316,215316,215316,215316,215319,215319,215319,215319,215320,215321,215325,215331,215338,215339,215345,215345,215345,215351,215351,215351,215352,215352,215353,215355,215356,215356,215357,215360,215360,215362,215367,215367,215367,215367,215368,215373,215373,215373,215376,215376,215376,215376,215376,215376,215380,215380,215381,215381,215381,215382,215384,215384,215388,215389,215390,215396,215400,215418,215418,215428,215441,215441,215441,215441,215442,215443,215444,215451,215454,215456,215457,215457,215464,215464,215475,215482,215482,215482,215483,215483,215483,215486,215486,215486,215486,215486,215487,215487,215487,215487,215487,215489,215494,215494,215494,215494,215496,215496,215497,215497,215497,215497,215498,215498,215499,215499,215499,215500,215502,215504,215506,215509,215509,215511,215511,215514,215514,215514,215514,215514,215514,215516,215516,215522,215522,215522,215522,215522,215531,215552,215552,215553,215553,215553,215556,215562,215562,215567,215567,215567,215573,215573,215573,215573,215574,215575,215582,215582,215582,215585,215585,215592,215592,215592,215592,215592,215592,215592,215592,215592,215592,215594,215602,215602,215602,215602,215602,215607,215607,215607,215607,215611,215617,215620,215625,215625,215627,215628,215628,215629,215632,215632,215639,215639,215639,215639,215641,215641,215644,215646,215646,215646,215649,215651,215652,215652,215658,215658,215658,215662,215662,215663,215666,215666,215670,215671,215672,215672,215672,215672,215675,215675,215678,215678,215678,215678,215678,215679,215679,215679,215679,215679,215680,215680,215680,215680,215680,215682,215683,215684,215690,215690,215691,215693,215695,215695,215698,215699,215705,215707,215718,215719,215719,215720,215720,215729,215732,215733,215733,215733,215735,215736,215740,215740,215740,215740,215742,215746,215752,215753,215753,215766,215776,215778,215780,215782,215786,215789,215792,215793,215796,215798,215803,215811,215811,215816,215817,215817,215817,215817,215817,215817,215819,215819,215819,215820,215820,215820,215820,215821,215822,215822,215822,215828,215831,215833,215834,215837,215838,215838,215839,215840,215842,215845,215846,215848,215848,215849,215849,215849,215850,215850,215850,215850,215850,215850,215850,215850,215850,215850,215850,215850,215850,215850,215852,215852,215857,215861,215864,215864,215864,215864,215866,215867,215868,215868,215868,215873,215873,215876,215876,215881,215882,215884,215884,215887,215891,215893,215895,215895,215895,215895,215895,215895,215896,215899,215899,215903,215904,215906,215906,215911,215911,215911,215916,215916,215919,215922,215922,215922,215922,215927,215930,215932,215932,215933,215933,215937,215937,215939,215942,215947,215948,215948,215948,215952,215952,215956,215956,215956,215957,215960,215960,215960,215960,215960,215960,215965,215965,215965,215970,215972,215972,215973,215973,215973,215974,215974,215975,215975,215975,215978,215978,215984,215986,215986,215986,215986,215987,215989,215989,215989,215989,215989,215989,215989,215989,215990,215990,215990,215990,215990,215990,215991,215994,215994,215994,215995,215996,215996,215997,215997,215997,215999,216002,216003,216003,216003,216003,216007,216007,216010,216012,216016,216020,216020,216029,216031,216031,216036,216042,216045,216048,216057,216060,216060,216066,216070,216073,216075,216075,216076,216085,216086,216089,216090,216091,216094,216100,216102,216102,216103,216103,216112,216118,216120,216133,216133,216138,216145,216150,216151,216151,216153,216153,216153,216153,216153,216153,216153,216156,216158,216158,216158,216158,216159,216160,216160,216160,216164,216164,216164,216166,216166,216166,216166,216166,216167,216169,216173,216174,216179,216181,216181,216184,216184,216184,216184,216185,216185,216185,216187,216187,216189,216190,216190,216192,216192,216192,216192,216192,216195,216197,216198,216199,216201,216201,216203,216206,216211,216212,216213,216218,216218,216218,216218,216218,216218,216222,216222,216222,216222,216222,216222,216233,216233,216233,216233,216233,216233,216238,216253,216253,216253,216256,216259,216259,216266,216270,216270,216270,216271,216271,216272,216272,216272,216283,216283,216292,216295,216299,216299,216300,216303,216304,216306,216310,216311,216314,216321,216321,216322,216322,216322,216323,216324,216324,216328,216328,216328,216328,216328,216328,216329,216329,216329,216330,216330,216330,216330,216330,216331,216331,216332,216336,216338,216338,216338,216342,216342,216342,216343,216343,216346,216348,216348,216348,216348,216353,216357,216371,216384,216384,216384,216386,216386,216386,216387,216387,216387,216387,216388,216397,216399,216401,216402,216403,216408,216408,216408,216408,216408,216408,216408,216408,216415,216431,216436,216438,216445,216449,216454,216455,216455,216455,216455,216455,216455,216455,216455,216455,216455,216456,216456,216456,216456,216456,216456,216456,216456,216456,216456,216456,216457,216458,216462,216464,216464,216465,216465,216465,216466,216466,216466,216467,216467,216467,216467,216467,216468,216468,216468,216468,216471,216476,216476,216476,216476,216476,216479,216482,216488,216488,216488,216492,216498,216499,216501,216502,216503,216503,216505,216505,216505,216506,216508,216508,216508,216508,216508,216508,216513,216513,216513,216513,216516,216518,216518,216518,216518,216519,216519,216522,216522,216527,216530,216532,216533,216533,216534,216534,216534,216534,216535,216536,216536,216538,216538,216538,216539,216539,216540,216542,216542,216542,216546,216546,216548,216551,216551,216552,216552,216552,216552,216554,216556,216556,216556,216556,216556,216556,216557,216558,216559,216563,216564,216569,216569,216571,216573,216573,216574,216574,216574,216574,216577,216579,216580,216580,216582,216582,216582,216583,216583,216583,216584,216584,216589,216589,216591,216592,216597,216600,216606,216606,216606,216606,216606,216606,216606,216608,216611,216613,216616,216616,216617,216617,216617,216617,216617,216620,216620,216620,216620,216622,216622,216622,216622,216622,216622,216622,216622,216622,216622,216622,216624,216627,216627,216628,216629,216630,216631,216633,216633,216633,216636,216636,216636,216636,216641,216641,216641,216644,216644,216644,216647,216649,216650,216650,216650,216650,216655,216655,216665,216665,216665,216666,216679,216686,216686,216686,216686,216688,216688,216696,216696,216696,216696,216696,216696,216696,216696,216696,216704,216705,216712,216715,216715,216715,216719,216720,216724,216724,216724,216727,216732,216734,216739,216739,216739,216739,216739,216742,216742,216743,216749,216751,216751,216753,216755,216755,216755,216766,216776,216782,216782,216782,216782,216785,216786,216788,216789,216796,216796,216796,216801,216801,216802,216804,216806,216806,216808,216811,216811,216811,216812,216813,216820,216822,216822,216825,216826,216834,216836,216836,216836,216837,216837,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216840,216844,216844,216851,216852,216857,216858,216868,216868,216871,216873,216873,216878,216879,216885,216885,216888,216888,216891,216893,216893,216895,216897,216897,216897,216897,216902,216902,216903,216903,216903,216903,216905,216905,216905,216908,216908,216910,216910,216910,216910,216910,216910,216910,216910,216913,216913,216916,216916,216916,216917,216917,216917,216918,216918,216918,216923,216923,216924,216924,216925,216925,216925,216925,216925,216925,216926,216928,216929,216929,216929,216929,216929,216930,216932,216936,216937,216937,216938,216942,216942,216942,216944,216944,216944,216944,216944,216949,216952,216954,216954,216954,216954,216954,216954,216955,216955,216959,216959,216959,216959,216960,216960,216961,216961,216963,216964,216964,216964,216964,216964,216965,216965,216966,216966,216969,216970,216971,216972,216972,216972,216972,216972,216973,216978,216978,216978,216978,216979,216979,216986,216987,216993,216999,217001,217007,217012,217013,217013,217015,217025,217027,217027,217030,217033,217033,217034,217034,217034,217034,217034,217034,217037,217037,217038,217038,217039,217039,217039,217041,217042,217043,217043,217043,217043,217043,217043,217044,217044,217045,217045,217046,217046,217046,217047,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217049,217050,217050,217050,217050,217050,217050,217050,217051,217051,217051,217053,217054,217054,217055,217055,217056,217058,217058,217059,217059,217060,217060,217060,217062,217062,217062,217064,217066,217068,217072,217082,217084,217084,217085,217086,217088,217098,217100,217100,217100,217100,217100,217107,217108,217111,217111,217111,217114,217119,217128,217128,217129,217135,217138,217143,217152,217157,217157,217157,217159,217159,217163,217163,217163,217170,217170,217173,217173,217173,217175,217183,217183,217185,217185,217186,217203,217205,217205,217205,217208,217210,217211,217211,217211,217211,217213,217213,217213,217213,217214,217222,217222,217231,217241,217241,217241,217243,217243,217243,217248,217248,217257,217261,217261,217264,217266,217280,217295,217295,217308,217311,217311,217314,217314,217315,217315,217316,217316,217316,217316,217316,217319,217323,217325,217328,217329,217330,217339,217339,217339,217346,217348,217350,217351,217352,217360,217361,217361,217363,217366,217366,217366,217366,217366,217367,217367,217368,217368,217369,217369,217369,217370,217370,217371,217376,217378,217379,217380,217380,217381,217381,217382,217384,217384,217384,217384,217384,217388,217389,217391,217391,217391,217391,217395,217395,217396,217399,217399,217399,217399,217399,217399,217399,217401,217406,217406,217406,217407,217410,217411,217412,217412,217414,217418,217419,217423,217423,217423,217424,217424,217425,217426,217426,217428,217430,217431,217432,217437,217437,217438,217438,217441,217441,217441,217441,217441,217441,217441,217442,217442,217442,217443,217443,217444,217444,217444,217446,217447,217447,217447,217447,217450,217450,217451,217452,217452,217454,217454,217457,217457,217457,217457,217459,217459,217459,217459,217459,217459,217459,217459,217462,217462,217464,217464,217464,217465,217465,217465,217465,217465,217465,217465,217466,217466,217467,217471,217472,217472,217472,217478,217479,217483,217483,217483,217483,217483,217484,217485,217487,217491,217492,217493,217493,217493,217494,217494,217494,217494,217494,217494,217498,217500,217501,217505,217506,217508,217508,217510,217523,217528,217529,217529,217530,217532,217539,217539,217540,217541,217542,217542,217542,217544,217544,217544,217544,217544,217544,217545,217545,217545,217545,217545,217545,217545,217545,217545,217546,217548,217549,217555,217555,217557,217558,217558,217560,217560,217562,217562,217562,217568,217569,217569,217571,217571,217571,217573,217573,217573,217577,217579,217580,217583,217583,217585,217585,217585,217590,217591,217591,217591,217591,217591,217593,217593,217594,217601,217611,217611,217611,217611,217611,217611,217614,217621,217621,217622,217623,217623,217623,217623,217623,217624,217625,217626,217626,217627,217627,217627,217627,217628,217628,217628,217632,217639,217639,217639,217639,217646,217646,217647,217650,217650,217652,217652,217653,217657,217657,217658,217658,217658,217666,217677,217685,217685,217685,217687,217699,217699,217710,217710,217710,217710,217710,217710,217711,217711,217711,217714,217714,217718,217718,217723,217723,217723,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217726,217730,217738,217744,217744,217744,217744,217744,217746,217746,217749,217750,217754,217754,217754,217756,217756,217757,217757,217757,217759,217768,217771,217771,217772,217772,217773,217775,217776,217776,217776,217782,217785,217785,217790,217790,217790,217794,217798,217798,217798,217798,217806,217807,217809,217809,217809,217812,217818,217823,217825,217825,217825,217825,217825,217825,217825,217825,217825,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217828,217829,217829,217829,217829,217830,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217831,217834,217834,217834,217834,217834,217834,217834,217834,217834,217834,217834,217834,217834,217835,217835,217835,217836,217836,217836,217836,217836,217836,217836,217836,217836,217837,217837,217837,217838,217838,217838,217840,217840,217841,217842,217842,217842,217843,217843,217843,217843,217844,217844,217844,217844,217844,217845,217845,217845,217845,217845,217845,217845,217845,217848,217848,217848,217848,217848,217848,217848,217849,217849,217849,217849,217849,217849,217849,217850,217851,217851,217851,217852,217853,217854,217854,217855,217855,217856,217856,217856,217857,217857,217857,217857,217858,217860,217861,217861,217861,217862,217862,217862,217862,217862,217862,217862,217862,217862,217862,217862,217862,217862,217862,217862,217864,217866,217866,217866,217866,217866,217866,217866,217866,217866,217866,217866,217866,217866,217866,217867,217867,217867,217868,217868,217868,217869,217871,217872,217873,217876,217876,217877,217877,217877,217877,217877,217877,217877,217877,217877,217878,217879,217879,217880,217880,217880,217880,217880,217881,217881,217881,217882,217882,217882,217883,217883,217883,217884,217884,217884,217884,217885,217887,217887,217887,217887,217887,217887,217888,217890,217891,217891,217891,217891,217891,217891,217891,217892,217893,217893,217893,217893,217893,217895,217895,217895,217895,217895,217895,217898,217898,217898,217899,217899,217902,217902,217903,217904,217904,217905,217905,217905,217905,217905,217905,217906,217906,217906,217908,217908,217908,217908,217909,217911,217911,217911,217911,217913,217913,217914,217915,217915,217915,217917,217920,217920,217920,217920,217920,217920,217921,217921,217921,217922,217922,217924,217924,217924,217924,217924,217925,217925,217925,217925,217925,217927,217928,217930,217930,217932,217934,217937,217937,217937,217938,217938,217939,217939,217939,217939,217939,217939,217939,217939,217939,217939,217939,217939,217940,217940,217940,217940,217940,217943,217944,217945,217945,217945,217945,217946,217947,217948,217949,217951,217951,217951,217951,217951,217951,217951,217952,217955,217955,217955,217956,217956,217956,217956,217956,217957,217957,217958,217959,217963,217964,217965,217966,217969,217971,217971,217971,217971,217971,217971,217971,217971,217971,217971,217971,217971,217971,217972,217972,217972,217973,217973,217973,217974,217979,217980,217980,217980,217980,217980,217983,217983,217983,217984,217984,217984,217984,217985,217986,217986,217988,217988,217988,217989,217990,217991,217991,217993,217993,217993,217993,217994,217994,217994,217994,217994,217994,217994,217994,217994,217995,217995,217995,217995,217996,217997,217997,217997,217997,217997,217997,217997,217998,217998,217998,217998,217998,218000,218000,218002,218002,218002,218003,218003,218004,218006,218006,218006,218007,218008,218008,218008,218009,218009,218011,218011,218012,218015,218015,218015,218015,218016,218017,218024,218028,218030,218032,218033,218033,218034,218034,218037,218037,218039,218040,218040,218040,218040,218040,218040,218040,218041,218041,218043,218043,218044,218051,218052,218055,218056,218058,218058,218061,218062,218063,218064,218067,218068,218071,218071,218071,218071,218075,218075,218078,218082,218082,218082,218086,218086,218086,218086,218086,218086,218087,218087,218087,218087,218087,218088,218090,218090,218090,218090,218091,218092,218093,218095,218097,218097,218099,218099,218100,218100,218100,218100,218105,218108,218111,218111,218111,218111,218113,218116,218120,218120,218120,218123,218125,218125,218126,218131,218131,218131,218131,218131,218134,218134,218135,218137,218137,218142,218142,218142,218144,218152,218155,218159,218160,218162,218162,218167,218168,218169,218169,218169,218169,218171,218171,218173,218175,218181,218189,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218190,218198,218200,218206,218218,218218,218228,218234,218234,218237,218237,218247,218252,218252,218252,218252,218252,218252,218258,218260,218270,218270,218276,218276,218285,218287,218291,218294,218295,218308,218310,218312,218317,218317,218320,218321,218323,218323,218324,218324,218325,218330,218333,218333,218333,218337,218339,218342,218345,218359,218361,218361,218374,218374,218374,218375,218375,218375,218375,218375,218375,218376,218376,218380,218382,218385,218385,218385,218385,218385,218387,218387,218387,218390,218390,218390,218390,218390,218392,218395,218395,218395,218397,218398,218403,218403,218403,218403,218404,218406,218410,218413,218414,218416,218418,218424,218429,218433,218439,218444,218447,218457,218461,218461,218461,218463,218466,218470,218470,218470,218471,218472,218473,218473,218473,218477,218477,218478,218487,218487,218491,218497,218504,218512,218517,218532,218536,218544,218544,218544,218555,218556,218556,218558,218561,218563,218569,218573,218590,218594,218597,218599,218599,218601,218610,218617,218617,218622,218625,218626,218636,218637,218638,218639,218645,218649,218649,218652,218652,218658,218658,218658,218663,218663,218676,218676,218676,218676,218684,218685,218685,218685,218689,218689,218689,218689,218689,218689,218689,218689,218689,218692,218693,218695,218696,218698,218702,218703,218725,218738,218738,218738,218738,218738,218738,218738,218744,218749,218750,218752,218754,218757,218757,218757,218758,218761,218761,218761,218761,218761,218765,218765,218765,218765,218765,218765,218766,218778,218780,218786,218791,218791,218791,218791,218797,218805,218806,218808,218809,218813,218813,218814,218817,218817,218834,218838,218838,218838,218838,218838,218838,218839,218839,218839,218853,218856,218868,218870,218871,218871,218871,218880,218882,218884,218884,218885,218885,218885,218885,218885,218887,218890,218890,218891,218891,218891,218891,218891,218891,218892,218892,218896,218898,218898,218899,218899,218899,218904,218904,218906,218912,218915,218916,218916,218921,218924,218924,218924,218924,218924,218924,218924,218924,218924,218924,218924,218926,218927,218927,218927,218927,218928,218931,218933,218933,218933,218934,218934,218941,218946,218946,218946,218946,218946,218955,218955,218957,218957,218960,218963,218964,218966,218966,218967,218967,218967,218967,218970,218973,218973,218973,218977,218977,218979,218981,218982,218985,218985,218989,218990,218990,218991,218995,218995,218995,218999,219000,219003,219009,219009,219011,219013,219017,219017,219018,219020,219021,219021,219022,219022,219028,219029,219032,219032,219032,219032,219032,219035,219035,219037,219037,219037,219039,219040,219040,219042,219044,219044,219044,219044,219044,219044,219044,219044,219044,219047,219048,219049,219049,219053,219053,219053,219053,219053,219053,219053,219058,219058,219058,219058,219058,219059,219059,219062,219062,219062,219064,219064,219064,219065,219065,219065,219066,219071,219072,219073,219073,219073,219076,219076,219076,219078,219078,219080,219080,219080,219080,219080,219082,219082,219082,219083,219083,219083,219086,219086,219086,219089,219090,219093,219093,219094,219094,219095,219096,219096,219096,219096,219096,219097,219097,219097,219097,219097,219097,219101,219101,219103,219104,219104,219104,219104,219105,219105,219106,219107,219107,219109,219109,219110,219110,219110,219112,219112,219114,219115,219115,219116,219118,219118,219118,219118,219118,219118,219118,219118,219118,219119,219119,219120,219120,219121,219122,219122,219124,219124,219124,219124,219125,219125,219125,219126,219126,219127,219127,219128,219128,219129,219129,219131,219132,219134,219136,219136,219137,219137,219137,219140,219143,219143,219144,219145,219146,219147,219149,219149,219149,219152,219152,219152,219153,219153,219153,219153,219153,219154,219154,219154,219155,219155,219155,219155,219156,219156,219156,219156,219156,219156,219156,219156,219157,219157,219157,219157,219159,219159,219159,219159,219160,219160,219161,219162,219163,219163,219168,219169,219171,219172,219174,219176,219177,219177,219177,219178,219178,219182,219183,219184,219185,219186,219188,219191,219195,219196,219197,219197,219201,219201,219201,219201,219202,219203,219203,219204,219204,219205,219205,219205,219205,219205,219206,219206,219206,219206,219207,219208,219208,219208,219208,219209,219209,219209,219209,219209,219209,219210,219211,219211,219214,219214,219214,219214,219214,219214,219214,219214,219215,219215,219215,219215,219217,219217,219219,219221,219223,219223,219225,219226,219226,219226,219226,219227,219227,219227,219227,219229,219229,219229,219229,219229,219230,219235,219235,219235,219236,219238,219239,219242,219243,219243,219243,219245,219246,219247,219247,219249,219254,219255,219255,219255,219255,219255,219255,219255,219255,219255,219255,219255,219255,219255,219255,219255,219255,219256,219256,219256,219256,219256,219256,219256,219256,219256,219256,219257,219257,219258,219259,219259,219259,219259,219259,219259,219259,219262,219262,219262,219262,219262,219262,219263,219264,219269,219271,219271,219271,219271,219271,219273,219276,219276,219276,219280,219280,219280,219280,219280,219280,219280,219280,219280,219280,219281,219283,219284,219287,219289,219289,219292,219292,219292,219295,219296,219297,219300,219301,219301,219301,219301,219302,219302,219302,219303,219303,219303,219303,219303,219306,219307,219308,219311,219311,219311,219311,219313,219313,219313,219313,219313,219313,219313,219320,219320,219320,219320,219320,219323,219323,219323,219323,219323,219327,219327,219328,219328,219330,219330,219331,219331,219334,219335,219337,219338,219340,219343,219343,219343,219343,219343,219347,219347,219347,219347,219347,219347,219347,219349,219349,219349,219351,219352,219352,219357,219358,219359,219360,219360,219360,219367,219368,219371,219372,219372,219375,219375,219376,219377,219379,219380,219380,219381,219383,219384,219384,219388,219391,219395,219398,219401,219404,219405,219406,219406,219414,219414,219414,219414,219414,219414,219414,219414,219414,219414,219414,219415,219415,219417,219417,219422,219422,219422,219426,219426,219426,219426,219426,219426,219429,219435,219435,219435,219435,219435,219438,219439,219440,219440,219440,219444,219447,219448,219449,219451,219459,219459,219459,219460,219462,219464,219464,219464,219465,219465,219469,219469,219471,219471,219473,219473,219473,219473,219473,219473,219473,219477,219478,219478,219480,219480,219480,219480,219484,219486,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219487,219489,219489,219491,219491,219491,219491,219491,219493,219495,219498,219501,219501,219501,219502,219502,219503,219503,219503,219503,219503,219504,219506,219508,219511,219514,219514,219518,219519,219519,219519,219519,219519,219519,219519,219519,219519,219519,219528,219528,219528,219532,219532,219534,219534,219534,219534,219540,219541,219541,219541,219541,219541,219541,219543,219543,219545,219546,219550,219550,219558,219558,219558,219558,219561,219563,219565,219565,219565,219565,219565,219565,219565,219566,219566,219569,219579,219580,219580,219581,219581,219581,219581,219581,219581,219581,219581,219585,219585,219588,219596,219596,219597,219597,219597,219597,219601,219610,219610,219610,219613,219613,219616,219621,219621,219621,219624,219624,219626,219626,219626,219629,219629,219629,219633,219636,219636,219636,219638,219639,219647,219647,219647,219647,219647,219647,219647,219647,219648,219648,219649,219650,219650,219651,219651,219651,219652,219652,219657,219658,219658,219660,219660,219660,219660,219660,219661,219661,219661,219661,219661,219661,219661,219665,219667,219668,219679,219683,219683,219684,219684,219684,219684,219684,219684,219684,219684,219684,219685,219685,219689,219693,219696,219711,219711,219711,219713,219714,219719,219719,219719,219719,219719,219719,219719,219719,219719,219721,219724,219737,219739,219741,219744,219746,219752,219752,219754,219756,219757,219757,219759,219761,219767,219769,219772,219785,219786,219794,219799,219806,219812,219817,219817,219817,219817,219820,219820,219820,219823,219823,219823,219823,219823,219830,219840,219840,219849,219851,219853,219853,219854,219855,219855,219861,219861,219861,219862,219865,219867,219872,219872,219872,219879,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219880,219881,219881,219881,219881,219881,219881,219881,219881,219881,219881,219882,219882,219882,219882,219882,219882,219882,219882,219882,219882,219882,219882,219882,219883,219883,219884,219884,219884,219884,219885,219885,219885,219885,219885,219885,219885,219885,219885,219885,219885,219885,219885,219886,219886,219886,219886,219886,219886,219886,219886,219886,219886,219886,219886,219887,219887,219887,219887,219887,219887,219887,219887,219887,219887,219887,219887,219887,219887,219887,219888,219888,219888,219888,219888,219889,219890,219890,219891,219893,219894,219894,219894,219894,219894,219896,219896,219900,219900,219901,219901,219901,219901,219901,219902,219902,219902,219903,219903,219903,219904,219904,219904,219904,219905,219905,219905,219905,219905,219905,219907,219907,219907,219907,219907,219907,219909,219909,219910,219910,219910,219910,219910,219910,219911,219911,219911,219911,219912,219913,219913,219913,219914,219914,219915,219915,219915,219916,219918,219919,219919,219919,219919,219919,219919,219919,219921,219921,219923,219925,219925,219925,219928,219933,219934,219937,219938,219938,219939,219939,219939,219941,219941,219941,219944,219946,219946,219950,219951,219951,219951,219951,219951,219951,219953,219953,219953,219953,219953,219953,219953,219953,219953,219953,219954,219954,219954,219954,219956,219958,219959,219964,219965,219968,219969,219969,219970,219971,219971,219972,219972,219983,219983,219987,219987,219987,219989,219994,219994,219996,219996,219998,219998,220000,220000,220003,220003,220006,220007,220009,220011,220014,220014,220014,220014,220014,220014,220015,220015,220015,220015,220015,220015,220015,220016,220016,220016,220021,220023,220024,220024,220025,220025,220027,220027,220027,220027,220027,220027,220028,220028,220028,220029,220030,220030,220034,220036,220036,220036,220037,220037,220039,220040,220043,220044,220044,220044,220044,220045,220051,220051,220051,220051,220051,220051,220051,220051,220051,220052,220052,220052,220052,220052,220053,220054,220054,220055,220055,220056,220056,220056,220057,220058,220060,220060,220063,220063,220063,220063,220063,220063,220063,220065,220070,220073,220083,220085,220085,220085,220085,220085,220085,220085,220085,220085,220085,220085,220086,220086,220088,220089,220091,220091,220092,220092,220093,220093,220093,220094,220096,220098,220098,220099,220099,220100,220102,220102,220106,220107,220107,220107,220108,220108,220108,220110,220111,220111,220113,220113,220120,220120,220120,220120,220120,220120,220120,220124,220124,220127,220129,220134,220134,220134,220140,220140,220144,220145,220145,220149,220151,220151,220151,220151,220155,220155,220155,220155,220155,220155,220155,220155,220155,220155,220160,220160,220160,220167,220167,220167,220168,220168,220168,220168,220173,220173,220173,220174,220176,220176,220177,220184,220184,220184,220184,220184,220185,220185,220192,220194,220209,220209,220215,220218,220223,220226,220226,220229,220229,220229,220229,220229,220229,220229,220233,220233,220233,220234,220235,220235,220235,220243,220243,220248,220251,220252,220252,220252,220253,220253,220255,220256,220256,220256,220256,220258,220260,220266,220267,220267,220271,220272,220272,220272,220272,220272,220272,220272,220272,220272,220272,220274,220274,220274,220274,220275,220286,220286,220290,220290,220291,220295,220296,220296,220299,220299,220301,220301,220302,220302,220307,220307,220311,220318,220324,220326,220326,220326,220326,220327,220330,220330,220330,220330,220332,220332,220337,220339,220339,220344,220346,220347,220347,220347,220347,220348,220348,220349,220350,220351,220351,220351,220351,220354,220354,220354,220354,220355,220356,220358,220358,220358,220358,220358,220358,220359,220359,220360,220361,220362,220363,220365,220365,220366,220366,220366,220366,220366,220368,220371,220372,220372,220372,220375,220375,220375,220375,220375,220375,220375,220375,220375,220376,220376,220377,220379,220379,220379,220379,220379,220380,220381,220381,220381,220381,220383,220384,220385,220385,220385,220386,220387,220387,220388,220389,220389,220389,220391,220393,220393,220396,220398,220398,220398,220399,220399,220399,220399,220399,220399,220399,220399,220399,220399,220399,220399,220400,220400,220402,220402,220403,220403,220404,220404,220404,220405,220405,220406,220406,220407,220407,220407,220407,220408,220410,220410,220410,220410,220411,220411,220412,220413,220413,220413,220413,220413,220416,220416,220416,220417,220417,220418,220418,220418,220419,220419,220419,220419,220419,220420,220420,220420,220420,220420,220420,220421,220423,220424,220425,220425,220425,220426,220426,220426,220428,220429,220431,220431,220431,220432,220432,220432,220432,220432,220435,220435,220435,220435,220443,220443,220449,220449,220449,220452,220452,220453,220454,220454,220454,220454,220456,220459,220462,220462,220462,220464,220465,220468,220468,220470,220470,220470,220470,220471,220473,220475,220475,220481,220483,220483,220483,220484,220484,220484,220485,220485,220485,220486,220486,220486,220486,220486,220490,220491,220492,220492,220492,220493,220493,220493,220493,220494,220494,220498,220498,220498,220498,220498,220498,220498,220498,220498,220498,220499,220499,220500,220500,220501,220501,220504,220504,220505,220505,220507,220508,220508,220509,220509,220509,220511,220511,220512,220512,220512,220512,220513,220514,220514,220516,220516,220516,220521,220521,220522,220522,220522,220524,220525,220526,220526,220526,220526,220528,220529,220529,220529,220529,220532,220533,220533,220533,220534,220534,220534,220534,220540,220540,220540,220540,220541,220541,220541,220541,220543,220543,220543,220543,220543,220544,220544,220545,220545,220545,220545,220545,220545,220545,220546,220547,220548,220548,220548,220551,220551,220552,220553,220553,220553,220553,220553,220553,220554,220557,220557,220557,220557,220559,220559,220559,220559,220559,220559,220560,220560,220560,220561,220561,220561,220561,220562,220565,220565,220565,220565,220565,220566,220566,220566,220566,220567,220567,220567,220567,220567,220567,220567,220569,220570,220570,220572,220572,220572,220576,220577,220577,220577,220577,220581,220582,220582,220583,220583,220583,220583,220585,220585,220587,220587,220587,220587,220587,220589,220590,220591,220593,220593,220595,220595,220595,220595,220595,220596,220596,220598,220598,220600,220600,220600,220600,220600,220600,220601,220604,220605,220606,220607,220607,220607,220607,220607,220607,220607,220607,220608,220609,220609,220611,220611,220611,220613,220613,220615,220615,220615,220616,220616,220616,220616,220616,220616,220616,220617,220617,220617,220617,220617,220618,220620,220626,220628,220628,220628,220634,220642,220647,220647,220647,220648,220650,220650,220651,220651,220651,220657,220658,220662,220662,220662,220662,220662,220662,220662,220662,220662,220663,220663,220663,220666,220666,220666,220667,220667,220667,220667,220667,220667,220668,220668,220668,220668,220669,220670,220671,220673,220674,220674,220681,220681,220681,220681,220682,220683,220683,220683,220683,220683,220694,220700,220700,220700,220700,220700,220704,220705,220705,220705,220705,220706,220706,220706,220706,220706,220708,220708,220714,220717,220721,220726,220727,220728,220728,220728,220731,220731,220731,220731,220731,220732,220734,220741,220742,220742,220742,220742,220743,220747,220747,220749,220749,220754,220754,220754,220754,220755,220755,220755,220755,220757,220758,220760,220760,220762,220762,220762,220762,220762,220763,220763,220763,220764,220764,220764,220764,220764,220764,220764,220764,220764,220764,220764,220764,220766,220767,220771,220771,220772,220772,220772,220772,220772,220772,220772,220773,220773,220773,220774,220776,220777,220777,220777,220777,220778,220778,220779,220779,220779,220781,220781,220781,220785,220785,220785,220785,220785,220785,220785,220785,220785,220790,220791,220792,220792,220797,220797,220799,220799,220799,220802,220804,220806,220813,220820,220828,220830,220830,220830,220841,220841,220843,220843,220843,220845,220846,220849,220849,220849,220849,220849,220849,220849,220849,220852,220853,220860,220861,220862,220862,220862,220862,220862,220862,220864,220864,220868,220869,220869,220869,220869,220869,220870,220871,220872,220872,220873,220874,220875,220875,220876,220879,220879,220880,220880,220881,220881,220881,220882,220884,220884,220886,220890,220890,220893,220893,220893,220893,220896,220897,220897,220898,220901,220903,220904,220904,220907,220908,220908,220911,220913,220915,220922,220922,220930,220931,220939,220939,220939,220945,220945,220946,220947,220949,220952,220952,220952,220955,220957,220957,220957,220963,220963,220963,220966,220966,220970,220970,220970,220971,220971,220973,220984,220984,220988,220999,220999,221003,221005,221006,221008,221011,221011,221011,221015,221015,221017,221017,221017,221022,221023,221025,221029,221029,221029,221031,221035,221038,221039,221042,221046,221048,221048,221048,221052,221052,221052,221056,221057,221057,221057,221059,221059,221061,221061,221061,221062,221064,221065,221066,221066,221069,221070,221072,221073,221073,221076,221076,221079,221082,221082,221083,221083,221084,221084,221084,221084,221084,221084,221084,221084,221084,221084,221085,221085,221085,221086,221090,221091,221091,221091,221091,221091,221091,221091,221091,221091,221091,221091,221091,221091,221091,221091,221094,221094,221094,221094,221094,221099,221100,221100,221102,221102,221106,221106,221113,221114,221116,221116,221116,221117,221117,221117,221117,221117,221120,221120,221120,221121,221122,221122,221122,221124,221124,221124,221130,221130,221135,221135,221143,221144,221148,221148,221148,221148,221158,221161,221161,221161,221163,221163,221164,221164,221166,221166,221166,221166,221166,221166,221166,221166,221166,221166,221167,221168,221170,221170,221170,221175,221183,221186,221186,221186,221186,221187,221187,221187,221196,221199,221199,221199,221203,221211,221211,221211,221214,221221,221221,221222,221225,221226,221229,221229,221229,221230,221232,221233,221236,221239,221239,221239,221242,221244,221248,221251,221251,221251,221252,221252,221256,221257,221261,221264,221264,221264,221264,221264,221264,221265,221266,221268,221268,221268,221270,221271,221271,221272,221272,221273,221279,221280,221284,221284,221284,221284,221287,221290,221291,221291,221291,221291,221293,221294,221294,221294,221295,221295,221297,221298,221299,221300,221300,221300,221300,221300,221300,221300,221301,221301,221301,221301,221301,221301,221301,221301,221303,221305,221306,221306,221306,221307,221307,221307,221307,221311,221313,221319,221322,221325,221326,221326,221328,221331,221332,221334,221336,221340,221343,221347,221350,221351,221351,221352,221352,221352,221352,221357,221358,221359,221359,221359,221359,221359,221359,221359,221359,221359,221360,221360,221360,221360,221360,221361,221361,221361,221362,221362,221363,221363,221363,221363,221364,221365,221365,221365,221367,221367,221371,221371,221372,221373,221373,221373,221373,221373,221374,221375,221377,221379,221380,221380,221380,221381,221382,221383,221383,221385,221385,221385,221386,221386,221386,221386,221386,221386,221389,221390,221391,221391,221392,221392,221393,221395,221395,221395,221395,221396,221396,221397,221397,221397,221397,221398,221398,221399,221400,221400,221400,221401,221403,221404,221407,221407,221407,221409,221410,221410,221412,221412,221412,221413,221413,221414,221415,221417,221418,221419,221420,221422,221422,221422,221425,221426,221431,221431,221436,221436,221436,221439,221439,221443,221443,221447,221447,221449,221450,221451,221451,221454,221455,221455,221455,221460,221460,221464,221465,221465,221466,221472,221480,221483,221483,221483,221483,221483,221483,221483,221483,221483,221483,221484,221484,221484,221492,221492,221492,221493,221497,221500,221502,221512,221512,221512,221521,221528,221529,221529,221529,221531,221533,221533,221533,221533,221533,221533,221534,221535,221535,221535,221535,221535,221535,221535,221537,221539,221549,221556,221556,221556,221557,221560,221560,221560,221560,221564,221565,221565,221566,221566,221566,221566,221567,221568,221568,221568,221568,221575,221575,221576,221584,221584,221585,221585,221587,221588,221589,221597,221597,221597,221597,221597,221597,221602,221603,221604,221604,221606,221606,221606,221606,221606,221606,221608,221608,221609,221609,221609,221609,221611,221611,221612,221612,221612,221613,221613,221613,221615,221615,221615,221615,221616,221621,221621,221625,221625,221625,221629,221630,221630,221630,221631,221631,221631,221631,221631,221633,221633,221633,221633,221633,221633,221633,221633,221638,221639,221641,221641,221642,221642,221645,221645,221645,221645,221646,221646,221647,221649,221649,221649,221649,221649,221649,221649,221649,221649,221650,221652,221652,221657,221657,221657,221659,221669,221670,221671,221672,221672,221672,221677,221677,221677,221677,221680,221680,221680,221682,221683,221683,221685,221685,221686,221686,221694,221694,221698,221698,221698,221698,221698,221700,221701,221705,221706,221708,221708,221709,221709,221709,221709,221709,221710,221712,221713,221713,221713,221714,221715,221715,221715,221715,221715,221715,221715,221716,221716,221716,221716,221718,221718,221719,221720,221720,221720,221720,221721,221722,221722,221722,221724,221724,221727,221730,221731,221733,221734,221743,221744,221744,221746,221746,221746,221746,221747,221747,221747,221748,221749,221750,221751,221751,221751,221751,221754,221754,221755,221755,221757,221758,221759,221761,221761,221764,221764,221764,221764,221768,221768,221769,221769,221769,221771,221773,221782,221782,221782,221784,221787,221790,221790,221790,221794,221797,221801,221803,221805,221806,221809,221815,221820,221830,221830,221830,221837,221837,221837,221838,221838,221839,221846,221850,221853,221854,221855,221855,221856,221857,221859,221859,221859,221863,221864,221864,221867,221867,221867,221877,221879,221880,221887,221895,221901,221907,221910,221924,221924,221925,221927,221927,221927,221927,221927,221927,221927,221927,221927,221927,221929,221929,221931,221936,221936,221936,221937,221951,221951,221951,221951,221951,221951,221951,221952,221952,221955,221957,221957,221958,221958,221958,221958,221958,221958,221958,221958,221958,221958,221959,221960,221961,221961,221964,221966,221966,221966,221967,221967,221967,221967,221967,221969,221969,221970,221973,221974,221977,221978,221978,221986,221993,221993,221994,221994,221996,222008,222011,222011,222012,222012,222018,222018,222019,222019,222023,222023,222023,222026,222032,222032,222034,222035,222035,222035,222037,222038,222043,222044,222045,222047,222052,222055,222055,222055,222056,222061,222061,222061,222061,222061,222061,222066,222068,222070,222075,222075,222076,222076,222076,222076,222078,222082,222082,222084,222085,222085,222088,222089,222091,222091,222091,222091,222093,222095,222104,222106,222112,222113,222113,222117,222121,222122,222123,222123,222129,222129,222129,222129,222130,222136,222138,222142,222142,222147,222152,222154,222158,222158,222160,222161,222161,222163,222164,222165,222169,222169,222177,222177,222179,222180,222181,222183,222190,222196,222198,222198,222198,222198,222198,222198,222198,222198,222198,222201,222201,222201,222201,222202,222204,222205,222206,222206,222206,222209,222210,222210,222210,222211,222211,222212,222212,222212,222212,222213,222215,222215,222215,222215,222217,222219,222221,222223,222225,222225,222226,222235,222235,222235,222235,222235,222235,222236,222240,222240,222241,222246,222246,222247,222248,222251,222253,222254,222257,222263,222264,222277,222281,222281,222288,222289,222291,222291,222297,222298,222313,222317,222317,222317,222317,222317,222317,222317,222318,222320,222325,222325,222325,222328,222328,222328,222329,222334,222334,222337,222340,222342,222358,222360,222362,222368,222369,222380,222381,222396,222396,222396,222396,222402,222402,222402,222402,222402,222402,222402,222402,222402,222403,222404,222407,222407,222408,222408,222409,222409,222417,222421,222422,222425,222429,222432,222433,222433,222433,222433,222441,222443,222452,222460,222462,222462,222462,222462,222463,222464,222465,222465,222465,222465,222469,222469,222469,222471,222472,222474,222477,222477,222482,222482,222493,222493,222493,222499,222505,222508,222510,222515,222517,222519,222521,222526,222528,222530,222531,222533,222533,222533,222535,222539,222545,222565,222565,222565,222567,222569,222569,222569,222571,222572,222579,222581,222581,222582,222582,222582,222582,222582,222582,222582,222582,222582,222586,222586,222592,222607,222607,222612,222612,222614,222618,222619,222619,222619,222619,222619,222619,222626,222630,222637,222638,222640,222640,222641,222641,222641,222642,222642,222642,222642,222646,222649,222651,222653,222653,222654,222654,222660,222663,222666,222667,222675,222680,222682,222682,222684,222684,222686,222687,222690,222690,222690,222690,222690,222690,222690,222690,222690,222690,222690,222690,222690,222690,222690,222690,222692,222692,222693,222693,222693,222693,222693,222693,222697,222697,222700,222700,222700,222700,222701,222701,222701,222701,222701,222701,222701,222701,222701,222702,222702,222702,222706,222706,222706,222708,222709,222709,222711,222714,222715,222715,222715,222715,222715,222715,222715,222715,222722,222722,222722,222722,222723,222728,222729,222730,222730,222731,222731,222731,222731,222731,222732,222732,222732,222732,222732,222732,222733,222734,222734,222734,222734,222734,222734,222734,222734,222737,222737,222737,222737,222742,222752,222753,222755,222755,222755,222755,222755,222759,222759,222759,222759,222759,222762,222768,222779,222781,222781,222782,222782,222783,222783,222783,222788,222788,222789,222789,222792,222793,222793,222794,222794,222794,222794,222796,222796,222798,222798,222801,222802,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222810,222811,222812,222813,222814,222814,222814,222816,222819,222819,222819,222819,222820,222820,222820,222829,222832,222832,222835,222839,222845,222846,222846,222852,222852,222855,222855,222858,222858,222862,222862,222862,222873,222874,222885,222889,222890,222896,222896,222900,222905,222908,222914,222914,222914,222915,222919,222927,222927,222927,222929,222939,222940,222940,222941,222943,222947,222947,222949,222950,222953,222957,222957,222961,222961,222964,222964,222967,222973,222973,222974,222975,222975,222990,222992,222996,222996,222998,223001,223002,223002,223009,223011,223012,223013,223013,223013,223013,223014,223021,223022,223025,223026,223026,223026,223029,223029,223029,223029,223033,223039,223042,223044,223044,223045,223046,223046,223047,223048,223048,223049,223049,223049,223049,223050,223053,223057,223069,223071,223073,223074,223080,223081,223082,223082,223082,223085,223085,223091,223097,223097,223097,223100,223100,223100,223100,223100,223100,223102,223102,223105,223112,223121,223121,223121,223121,223123,223125,223126,223127,223127,223127,223127,223127,223127,223130,223130,223137,223138,223138,223138,223138,223138,223138,223138,223138,223138,223138,223138,223138,223138,223138,223138,223138,223143,223143,223146,223147,223150,223153,223157,223157,223158,223158,223159,223165,223166,223167,223168,223169,223169,223169,223171,223171,223171,223171,223171,223173,223173,223173,223173,223175,223175,223176,223178,223178,223179,223179,223179,223179,223181,223182,223184,223187,223191,223200,223200,223203,223204,223204,223204,223207,223209,223210,223210,223210,223210,223210,223211,223211,223211,223211,223211,223214,223214,223214,223214,223214,223214,223214,223215,223215,223215,223215,223217,223217,223217,223217,223217,223217,223220,223222,223222,223224,223224,223224,223225,223225,223225,223228,223228,223228,223228,223228,223228,223228,223230,223231,223231,223233,223234,223235,223235,223235,223235,223235,223239,223239,223239,223240,223240,223240,223240,223241,223241,223241,223241,223241,223241,223242,223242,223242,223243,223243,223243,223243,223243,223243,223252,223254,223255,223256,223260,223269,223272,223272,223272,223272,223273,223273,223275,223277,223277,223278,223278,223278,223279,223280,223281,223283,223283,223284,223285,223285,223285,223285,223285,223285,223285,223285,223285,223285,223286,223286,223286,223286,223286,223286,223286,223286,223286,223286,223286,223286,223286,223286,223286,223286,223288,223288,223289,223289,223289,223290,223290,223290,223290,223292,223295,223297,223297,223298,223298,223298,223299,223300,223301,223302,223302,223302,223302,223302,223303,223303,223303,223303,223303,223304,223304,223304,223304,223304,223310,223311,223311,223311,223312,223313,223313,223314,223314,223314,223316,223316,223319,223319,223319,223319,223320,223322,223322,223322,223323,223323,223323,223323,223323,223324,223325,223325,223325,223328,223328,223329,223329,223329,223330,223330,223330,223331,223334,223337,223343,223347,223353,223357,223360,223361,223362,223366,223369,223371,223374,223374,223381,223384,223385,223393,223404,223406,223414,223414,223414,223414,223414,223414,223414,223414,223414,223414,223414,223414,223414,223415,223419,223421,223422,223422,223422,223423,223430,223431,223431,223432,223432,223436,223440,223440,223440,223442,223442,223443,223443,223443,223444,223444,223447,223447,223447,223447,223447,223447,223447,223447,223447,223447,223447,223448,223449,223449,223450,223462,223462,223462,223462,223462,223462,223462,223462,223465,223467,223468,223471,223471,223473,223474,223474,223474,223474,223475,223476,223480,223483,223493,223497,223497,223499,223499,223505,223505,223506,223506,223506,223507,223510,223514,223518,223520,223520,223520,223528,223531,223532,223535,223536,223541,223544,223545,223555,223555,223555,223555,223555,223555,223555,223556,223558,223559,223559,223559,223559,223559,223560,223560,223560,223560,223560,223561,223566,223568,223568,223568,223568,223568,223572,223573,223579,223580,223581,223581,223581,223581,223581,223581,223581,223581,223581,223581,223582,223584,223586,223587,223587,223590,223590,223590,223593,223593,223593,223593,223593,223593,223593,223597,223597,223600,223602,223603,223603,223604,223607,223608,223615,223620,223620,223622,223622,223625,223627,223630,223632,223632,223632,223636,223638,223642,223642,223643,223643,223644,223644,223644,223645,223646,223647,223647,223647,223648,223649,223653,223657,223659,223660,223661,223661,223661,223664,223670,223670,223671,223671,223672,223673,223676,223679,223682,223682,223682,223682,223682,223683,223684,223684,223687,223691,223692,223694,223708,223712,223721,223722,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223723,223732,223734,223737,223739,223739,223739,223743,223743,223745,223745,223746,223747,223751,223751,223752,223752,223753,223753,223753,223754,223754,223754,223754,223755,223755,223755,223755,223755,223755,223755,223756,223757,223757,223757,223757,223757,223757,223758,223758,223758,223759,223759,223759,223759,223759,223759,223759,223760,223760,223760,223760,223760,223760,223760,223760,223761,223761,223761,223761,223761,223761,223762,223762,223762,223762,223762,223762,223762,223762,223762,223762,223765,223766,223769,223771,223773,223773,223774,223775,223775,223777,223777,223778,223778,223780,223780,223781,223781,223782,223785,223786,223789,223789,223789,223793,223793,223794,223795,223799,223799,223799,223802,223803,223803,223803,223803,223804,223805,223805,223807,223807,223807,223807,223807,223807,223813,223813,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223814,223815,223816,223816,223817,223818,223818,223822,223827,223827,223833,223833,223838,223838,223838,223841,223842,223842,223843,223846,223846,223846,223850,223850,223850,223852,223857,223858,223858,223858,223859,223869,223874,223874,223874,223875,223875,223878,223886,223887,223887,223887,223889,223891,223891,223896,223904,223905,223905,223907,223907,223910,223913,223913,223914,223915,223915,223925,223927,223930,223933,223933,223934,223934,223934,223936,223937,223940,223941,223942,223948,223952,223955,223961,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223962,223966,223968,223969,223973,223973,223973,223973,223975,223975,223975,223976,223977,223977,223977,223977,223978,223979,223984,223984,223988,223988,223989,223990,223990,223990,223996,223997,224003,224003,224003,224006,224009,224009,224009,224010,224015,224015,224015,224015,224015,224015,224016,224016,224017,224020,224023,224026,224033,224033,224033,224033,224033,224033,224035,224050,224054,224055,224056,224058,224060,224062,224064,224064,224068,224073,224078,224078,224078,224081,224081,224081,224081,224082,224084,224085,224085,224085,224085,224085,224086,224087,224088,224088,224090,224092,224092,224092,224095,224097,224097,224097,224098,224100,224102,224102,224103,224104,224108,224110,224110,224110,224111,224111,224111,224111,224112,224113,224113,224113,224115,224120,224124,224128,224141,224142,224153,224155,224159,224165,224168,224172,224174,224175,224183,224183,224183,224186,224189,224190,224190,224191,224198,224199,224199,224199,224199,224199,224202,224202,224203,224207,224212,224214,224218,224218,224218,224220,224221,224221,224224,224225,224233,224233,224233,224236,224237,224237,224237,224241,224244,224247,224247,224247,224250,224250,224250,224250,224250,224250,224250,224250,224257,224258,224260,224261,224262,224262,224263,224265,224265,224267,224267,224268,224270,224271,224272,224273,224275,224275,224279,224282,224282,224283,224286,224286,224286,224286,224294,224298,224298,224302,224302,224302,224302,224303,224304,224304,224308,224315,224320,224328,224332,224333,224335,224337,224342,224348,224349,224350,224350,224350,224350,224355,224355,224356,224358,224358,224362,224362,224365,224365,224365,224367,224368,224368,224368,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224369,224370,224373,224374,224377,224393,224393,224393,224396,224396,224396,224402,224402,224402,224415,224415,224415,224415,224415,224415,224422,224422,224427,224427,224431,224431,224434,224434,224434,224434,224435,224436,224437,224437,224438,224438,224438,224438,224438,224438,224438,224441,224441,224446,224446,224447,224448,224450,224454,224458,224458,224458,224458,224459,224459,224460,224460,224460,224460,224460,224462,224462,224466,224467,224475,224475,224476,224478,224482,224487,224491,224492,224494,224499,224507,224508,224508,224511,224511,224522,224534,224534,224534,224540,224551,224551,224551,224558,224562,224563,224563,224566,224566,224569,224569,224570,224570,224570,224575,224579,224581,224581,224581,224581,224589,224589,224601,224602,224602,224606,224606,224606,224612,224612,224615,224615,224615,224615,224615,224621,224634,224650,224653,224654,224655,224661,224662,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224665,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224666,224671,224672,224672,224675,224675,224675,224677,224677,224677,224677,224680,224683,224683,224692,224692,224695,224695,224695,224700,224700,224700,224700,224705,224706,224717,224717,224717,224717,224717,224730,224734,224736,224745,224746,224746,224753,224753,224753,224755,224755,224755,224755,224756,224757,224759,224768,224779,224779,224779,224779,224784,224785,224786,224786,224786,224786,224786,224786,224786,224786,224786,224786,224786,224787,224788,224789,224789,224789,224789,224790,224791,224793,224793,224797,224808,224809,224809,224811,224811,224814,224826,224826,224826,224827,224827,224827,224829,224830,224830,224831,224831,224831,224832,224848,224855,224859,224861,224861,224867,224871,224878,224883,224883,224903,224908,224908,224916,224919,224921,224930,224938,224943,224947,224959,224959,224961,224972,224980,224980,224980,224980,224981,224981,224991,224991,225000,225000,225002,225005,225006,225007,225008,225023,225025,225025,225025,225046,225049,225059,225061,225062,225062,225063,225063,225066,225067,225069,225069,225074,225075,225075,225075,225084,225084,225086,225090,225090,225098,225098,225099,225099,225099,225102,225104,225105,225106,225108,225108,225109,225110,225110,225110,225112,225112,225112,225113,225113,225113,225114,225118,225118,225118,225118,225118,225118,225118,225118,225118,225121,225128,225131,225131,225132,225132,225132,225132,225136,225139,225142,225146,225146,225147,225148,225153,225157,225157,225161,225162,225162,225162,225179,225206,225214,225214,225214,225221,225224,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225225,225230,225238,225238,225238,225240,225240,225245,225247,225247,225248,225248,225248,225249,225250,225251,225256,225256,225256,225256,225258,225258,225258,225258,225261,225261,225267,225269,225271,225271,225275,225276,225276,225276,225276,225277,225281,225281,225281,225284,225284,225284,225285,225285,225290,225290,225293,225293,225293,225293,225293,225294,225294,225296,225297,225299,225304,225304,225305,225306,225308,225310,225310,225310,225312,225312,225312,225313,225313,225316,225316,225321,225331,225331,225331,225331,225331,225331,225331,225331,225331,225334,225338,225338,225338,225342,225345,225345,225346,225366,225367,225379,225384,225392,225400,225400,225400,225406,225408,225413,225413,225413,225414,225415,225415,225418,225425,225425,225425,225425,225425,225427,225427,225443,225458,225462,225462,225468,225469,225477,225488,225489,225489,225494,225496,225500,225504,225506,225512,225515,225520,225520,225523,225532,225533,225538,225540,225543,225547,225548,225550,225551,225551,225553,225554,225554,225554,225554,225554,225555,225557,225557,225559,225559,225560,225560,225560,225560,225560,225560,225562,225562,225562,225564,225566,225566,225566,225566,225566,225566,225567,225567,225573,225575,225575,225575,225575,225575,225575,225585,225590,225590,225590,225590,225590,225590,225590,225595,225598,225598,225598,225598,225604,225604,225604,225606,225606,225606,225606,225611,225611,225611,225611,225616,225616,225617,225636,225638,225638,225651,225655,225655,225659,225659,225662,225662,225662,225662,225662,225662,225663,225663,225668,225673,225677,225679,225680,225692,225701,225711,225713,225718,225718,225723,225729,225748,225753,225761,225763,225765,225765,225765,225765,225767,225767,225767,225768,225768,225768,225770,225771,225772,225772,225774,225774,225774,225776,225776,225781,225781,225781,225782,225784,225784,225784,225784,225784,225784,225784,225784,225784,225785,225786,225787,225787,225787,225788,225788,225795,225795,225797,225798,225798,225798,225801,225803,225803,225808,225812,225815,225820,225820,225823,225830,225830,225830,225830,225835,225848,225848,225850,225855,225862,225863,225863,225865,225866,225866,225866,225866,225866,225866,225866,225866,225866,225866,225866,225866,225867,225867,225869,225869,225869,225869,225870,225870,225871,225877,225883,225884,225885,225888,225891,225892,225892,225895,225903,225907,225909,225910,225913,225915,225915,225916,225916,225916,225916,225916,225916,225919,225926,225927,225936,225946,225949,225949,225952,225955,225963,225975,225975,225975,225975,225975,225975,225975,225975,225975,225975,225975,225975,225975,225975,225975,225976,225976,225976,225979,225980,225980,225981,225989,225989,225989,225989,225991,225992,225997,225997,225998,226001,226020,226020,226025,226026,226026,226031,226033,226033,226034,226040,226046,226048,226054,226060,226060,226060,226061,226064,226064,226064,226064,226064,226064,226064,226064,226064,226064,226066,226067,226067,226067,226067,226067,226067,226069,226069,226069,226070,226070,226070,226072,226073,226078,226078,226080,226080,226083,226084,226084,226086,226089,226089,226095,226100,226111,226112,226112,226112,226123,226141,226144,226144,226144,226146,226146,226154,226154,226155,226170,226174,226175,226175,226175,226175,226175,226179,226183,226187,226187,226190,226190,226191,226191,226192,226195,226197,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226199,226206,226206,226206,226222,226222,226222,226225,226225,226225,226232,226238,226238,226238,226238,226238,226243,226244,226248,226252,226254,226257,226257,226257,226257,226258,226260,226260,226260,226260,226260,226262,226264,226264,226267,226267,226273,226276,226276,226277,226277,226278,226278,226278,226279,226279,226279,226279,226279,226281,226281,226282,226282,226282,226282,226282,226282,226283,226283,226284,226284,226284,226284,226287,226287,226292,226293,226294,226294,226295,226305,226308,226312,226312,226312,226312,226312,226312,226312,226312,226312,226312,226313,226314,226314,226314,226319,226320,226324,226324,226324,226324,226324,226324,226329,226332,226332,226334,226336,226337,226338,226339,226341,226341,226344,226344,226344,226344,226345,226346,226348,226352,226352,226352,226352,226352,226353,226353,226353,226356,226363,226365,226366,226368,226368,226369,226369,226378,226378,226391,226401,226403,226409,226412,226417,226418,226420,226421,226421,226423,226429,226433,226435,226439,226439,226439,226445,226445,226446,226446,226453,226456,226458,226458,226463,226464,226466,226466,226466,226467,226467,226468,226491,226495,226495,226495,226496,226497,226502,226506,226517,226517,226517,226519,226523,226524,226524,226524,226524,226524,226524,226526,226528,226536,226536,226536,226536,226536,226539,226539,226539,226541,226548,226550,226565,226565,226565,226573,226574,226574,226580,226595,226595,226597,226597,226602,226609,226614,226630,226630,226632,226637,226638,226645,226647,226648,226652,226653,226653,226656,226662,226681,226681,226681,226681,226681,226681,226681,226681,226698,226701,226704,226705,226705,226705,226705,226709,226709,226709,226709,226709,226709,226709,226709,226715,226720,226728,226737,226741,226742,226747,226753,226762,226763,226763,226764,226766,226766,226768,226768,226768,226768,226772,226775,226778,226782,226794,226794,226799,226801,226805,226806,226806,226813,226817,226822,226829,226831,226832,226836,226840,226841,226843,226848,226852,226854,226862,226862,226862,226862,226866,226867,226873,226876,226881,226881,226883,226885,226892,226893,226893,226918,226918,226918,226918,226931,226945,226949,226949,226958,226959,226964,226969,226969,226975,226979,226981,226997,227001,227002,227003,227015,227015,227027,227027,227034,227034,227036,227036,227039,227041,227044,227045,227052,227052,227052,227052,227052,227052,227052,227052,227055,227056,227057,227058,227058,227058,227074,227075,227075,227075,227075,227075,227075,227075,227075,227079,227084,227084,227092,227092,227095,227100,227100,227100,227104,227107,227110,227110,227112,227113,227113,227115,227115,227116,227117,227120,227122,227122,227124,227124,227124,227124,227124,227124,227125,227130,227135,227137,227139,227145,227153,227163,227163,227167,227167,227167,227167,227167,227167,227167,227167,227167,227167,227167,227168,227168,227168,227168,227168,227168,227168,227168,227168,227168,227170,227170,227170,227170,227171,227171,227171,227172,227172,227172,227172,227173,227173,227174,227174,227175,227177,227178,227181,227182,227182,227182,227182,227182,227182,227183,227183,227183,227183,227183,227183,227183,227184,227185,227186,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227187,227189,227190,227190,227190,227190,227190,227190,227190,227190,227190,227190,227191,227191,227191,227193,227201,227201,227201,227201,227203,227203,227203,227203,227207,227214,227214,227214,227215,227226,227229,227231,227234,227241,227241,227241,227246,227249,227253,227253,227254,227257,227258,227267,227269,227272,227275,227275,227275,227279,227279,227279,227279,227282,227284,227287,227288,227292,227294,227295,227295,227304,227308,227308,227308,227308,227313,227313,227313,227313,227313,227317,227318,227319,227321,227322,227323,227326,227329,227330,227340,227343,227346,227347,227347,227348,227359,227359,227359,227364,227364,227365,227379,227384,227393,227395,227395,227399,227402,227408,227408,227408,227428,227432,227434,227437,227445,227445,227446,227447,227450,227456,227459,227464,227464,227465,227468,227469,227472,227473,227473,227473,227473,227473,227478,227478,227478,227481,227494,227498,227506,227510,227510,227512,227512,227512,227512,227512,227512,227513,227515,227515,227516,227536,227541,227548,227549,227549,227550,227557,227557,227560,227565,227568,227573,227577,227584,227586,227587,227587,227587,227588,227588,227588,227588,227588,227599,227599,227607,227612,227613,227616,227622,227625,227635,227640,227649,227652,227652,227652,227652,227652,227652,227655,227659,227659,227659,227659,227662,227663,227665,227668,227675,227675,227675,227675,227675,227677,227680,227680,227680,227680,227682,227684,227692,227692,227698,227701,227701,227701,227701,227704,227705,227705,227706,227707,227711,227716,227727,227734,227741,227741,227751,227755,227756,227756,227756,227764,227767,227767,227767,227772,227775,227782,227794,227798,227806,227807,227817,227818,227820,227832,227841,227845,227851,227870,227877,227878,227891,227892,227892,227892,227895,227897,227897,227897,227924,227925,227930,227932,227932,227939,227946,227946,227951,227965,227965,227974,227974,227974,227981,227981,227981,227994,227994,228027,228033,228033,228039,228039,228049,228049,228049,228049,228060,228061,228061,228064,228064,228064,228064,228070,228070,228070,228074,228075,228075,228076,228078,228078,228082,228082,228088,228092,228094,228094,228101,228109,228111,228111,228111,228112,228120,228124,228130,228146,228149,228158,228167,228170,228170,228170,228177,228178,228180,228180,228182,228182,228185,228194,228202,228210,228210,228220,228220,228222,228234,228235,228248,228251,228259,228270,228274,228279,228283,228285,228289,228295,228295,228295,228298,228305,228305,228309,228309,228310,228312,228312,228314,228316,228319,228319,228320,228320,228320,228320,228322,228323,228325,228326,228326,228330,228331,228333,228343,228343,228343,228343,228343,228343,228343,228343,228351,228353,228353,228353,228355,228356,228361,228363,228363,228363,228363,228384,228385,228385,228385,228386,228394,228396,228396,228399,228399,228401,228405,228408,228409,228419,228422,228432,228445,228447,228448,228461,228461,228461,228464,228465,228467,228467,228467,228467,228472,228478,228482,228482,228485,228485,228485,228485,228486,228487,228487,228487,228487,228487,228487,228490,228490,228491,228491,228495,228503,228506,228506,228509,228514,228514,228519,228526,228530,228532,228540,228544,228553,228558,228561,228563,228565,228568,228579,228585,228591,228594,228594,228611,228624,228626,228626,228626,228626,228626,228626,228626,228626,228640,228652,228655,228657,228661,228666,228672,228679,228682,228683,228689,228698,228699,228701,228704,228705,228705,228707,228715,228719,228722,228731,228732,228732,228733,228734,228734,228734,228738,228749,228757,228775,228776,228776,228779,228780,228780,228780,228780,228781,228781,228796,228799,228804,228807,228807,228807,228809,228818,228819,228819,228820,228822,228826,228826,228828,228829,228831,228832,228833,228834,228836,228836,228840,228840,228841,228845,228845,228849,228851,228851,228852,228853,228860,228865,228874,228883,228884,228899,228909,228909,228925,228928,228933,228934,228937,228948,228950,228959,228967,228973,228973,228975,228975,228978,228978,228978,228987,228987,228995,228997,229001,229005,229005,229005,229005,229005,229005,229005,229005,229005,229008,229009,229009,229009,229009,229009,229009,229009,229009,229014,229015,229016,229017,229017,229027,229027,229027,229027,229029,229031,229039,229039,229040,229056,229058,229065,229071,229083,229083,229089,229097,229104,229105,229107,229108,229108,229108,229108,229109,229109,229110,229110,229110,229111,229111,229113,229113,229113,229114,229116,229119,229128,229140,229140,229143,229143,229143,229146,229150,229151,229152,229153,229153,229160,229165,229168,229168,229168,229168,229169,229177,229179,229180,229180,229180,229182,229184,229186,229187,229195,229201,229201,229201,229214,229216,229223,229225,229225,229225,229225,229226,229228,229228,229232,229233,229233,229235,229236,229238,229241,229243,229250,229255,229255,229255,229256,229257,229261,229261,229263,229275,229280,229282,229282,229286,229290,229316,229321,229333,229333,229344,229344,229344,229344,229354,229359,229362,229365,229375,229375,229380,229380,229380,229380,229382,229393,229397,229397,229397,229399,229402,229402,229405,229408,229413,229415,229416,229420,229420,229426,229427,229428,229430,229433,229436,229441,229446,229446,229447,229449,229452,229458,229462,229462,229465,229465,229466,229466,229466,229466,229475,229477,229484,229486,229487,229493,229509,229511,229513,229515,229523,229530,229536,229536,229536,229537,229538,229541,229543,229543,229543,229543,229544,229544,229544,229544,229544,229544,229545,229546,229546,229546,229546,229549,229550,229554,229556,229558,229570,229573,229576,229576,229576,229579,229581,229594,229594,229594,229598,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229609,229612,229614,229614,229614,229614,229615,229615,229615,229615,229615,229615,229615,229616,229616,229616,229616,229616,229616,229617,229617,229617,229617,229618,229618,229618,229618,229620,229620,229623,229623,229623,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229625,229628,229629,229629,229629,229629,229631,229631,229631,229631,229631,229631,229633,229635,229637,229637,229637,229638,229639,229645,229647,229647,229649,229650,229651,229651,229651,229651,229651,229651,229651,229651,229651,229651,229652,229652,229654,229654,229655,229656,229656,229656,229657,229657,229657,229657,229657,229657,229659,229660,229660,229660,229660,229660,229660,229660,229661,229661,229662,229663,229663,229664,229666,229666,229667,229668,229669,229669,229670,229672,229674,229675,229675,229677,229678,229684,229684,229684,229684,229685,229690,229690,229693,229698,229698,229701,229703,229704,229704,229704,229704,229704,229704,229705,229705,229705,229705,229705,229709,229710,229711,229711,229712,229712,229712,229712,229712,229712,229713,229715,229715,229715,229715,229715,229715,229715,229716,229717,229718,229718,229720,229721,229721,229725,229725,229725,229725,229725,229725,229726,229726,229727,229727,229731,229735,229736,229742,229743,229748,229748,229751,229752,229752,229753,229756,229756,229756,229757,229757,229757,229759,229762,229765,229765,229765,229769,229770,229770,229770,229770,229770,229770,229771,229773,229773,229773,229774,229775,229776,229777,229780,229780,229782,229782,229782,229786,229786,229788,229796,229796,229797,229803,229811,229814,229815,229816,229816,229820,229820,229820,229830,229832,229836,229842,229844,229845,229854,229854,229857,229863,229868,229873,229873,229873,229873,229873,229877,229877,229877,229877,229877,229884,229885,229885,229887,229887,229887,229887,229892,229893,229895,229896,229899,229899,229900,229901,229908,229909,229909,229913,229925,229925,229925,229925,229928,229931,229937,229954,229955,229956,229959,229962,229968,229972,229977,229984,229985,229985,229985,229985,229985,229985,229985,229985,229985,229985,229985,229991,229996,229996,229996,229996,229996,229998,230000,230003,230003,230003,230003,230003,230003,230004,230005,230006,230007,230010,230010,230010,230010,230010,230011,230011,230011,230021,230021,230021,230021,230022,230022,230022,230022,230022,230022,230024,230032,230032,230032,230032,230035,230046,230049,230056,230058,230062,230063,230067,230068,230085,230093,230095,230096,230101,230104,230110,230127,230127,230127,230127,230128,230128,230128,230146,230154,230158,230158,230158,230166,230172,230174,230180,230183,230190,230190,230191,230194,230194,230194,230194,230197,230198,230209,230210,230211,230214,230215,230215,230217,230226,230226,230229,230233,230256,230258,230260,230260,230267,230267,230267,230270,230275,230277,230287,230287,230292,230296,230296,230296,230297,230298,230299,230310,230314,230321,230334,230345,230351,230351,230351,230362,230364,230365,230365,230365,230370,230370,230378,230380,230385,230387,230390,230395,230395,230395,230395,230395,230396,230396,230396,230396,230397,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230401,230407,230408,230408,230408,230408,230411,230414,230414,230414,230415,230415,230416,230417,230418,230418,230420,230420,230423,230424,230425,230435,230444,230448,230448,230464,230471,230472,230487,230488,230496,230500,230504,230506,230507,230507,230507,230507,230512,230513,230515,230520,230520,230520,230520,230521,230535,230535,230536,230536,230544,230550,230550,230560,230560,230564,230564,230564,230567,230567,230569,230569,230569,230569,230569,230572,230573,230573,230573,230583,230587,230591,230605,230612,230615,230616,230616,230619,230621,230622,230626,230626,230626,230632,230633,230633,230636,230637,230637,230644,230647,230655,230655,230655,230655,230655,230655,230655,230658,230667,230679,230703,230703,230703,230708,230709,230711,230712,230727,230734,230736,230736,230736,230736,230736,230737,230740,230745,230746,230746,230747,230750,230750,230756,230756,230756,230756,230757,230757,230757,230757,230757,230759,230760,230760,230760,230760,230761,230761,230762,230764,230764,230764,230764,230764,230764,230765,230766,230767,230767,230773,230773,230775,230776,230778,230778,230781,230782,230784,230787,230795,230801,230806,230808,230811,230824,230824,230824,230828,230828,230831,230833,230841,230849,230851,230853,230859,230861,230861,230861,230861,230863,230867,230867,230869,230871,230875,230875,230876,230876,230878,230878,230878,230880,230880,230880,230880,230880,230885,230885,230885,230885,230885,230885,230885,230885,230886,230890,230890,230895,230895,230896,230899,230904,230910,230916,230916,230916,230916,230916,230916,230920,230921,230924,230932,230939,230944,230944,230944,230944,230944,230945,230945,230945,230945,230945,230946,230951,230952,230956,230958,230959,230959,230959,230959,230959,230959,230959,230959,230960,230960,230960,230960,230963,230982,230982,230982,230984,230984,230991,230992,230992,230994,230995,230998,231003,231004,231004,231004,231004,231004,231004,231004,231004,231005,231012,231013,231016,231016,231034,231039,231041,231047,231052,231056,231056,231056,231060,231061,231063,231067,231069,231073,231075,231077,231080,231086,231087,231090,231090,231092,231093,231095,231095,231098,231105,231105,231111,231118,231123,231123,231125,231125,231133,231143,231145,231146,231146,231149,231155,231155,231155,231155,231155,231155,231156,231157,231161,231163,231164,231173,231178,231205,231209,231211,231216,231217,231219,231219,231219,231219,231219,231219,231219,231219,231219,231219,231219,231219,231227,231227,231228,231232,231239,231243,231243,231243,231254,231254,231254,231254,231255,231255,231255,231255,231255,231257,231260,231262,231262,231262,231262,231262,231268,231268,231269,231269,231269,231269,231269,231269,231269,231273,231275,231279,231286,231287,231296,231296,231301,231306,231309,231310,231311,231313,231319,231319,231319,231322,231322,231322,231325,231325,231325,231325,231325,231325,231325,231325,231325,231325,231325,231326,231328,231334,231334,231334,231343,231343,231343,231343,231343,231344,231344,231344,231344,231344,231346,231346,231346,231346,231346,231348,231353,231353,231353,231353,231355,231355,231355,231355,231355,231355,231356,231356,231356,231356,231356,231358,231358,231359,231359,231359,231359,231361,231363,231364,231369,231370,231371,231371,231373,231373,231376,231379,231380,231382,231382,231382,231382,231382,231383,231395,231401,231401,231404,231404,231405,231405,231405,231405,231406,231407,231407,231408,231408,231408,231408,231408,231408,231408,231408,231409,231409,231410,231412,231413,231413,231415,231415,231415,231415,231416,231416,231417,231417,231420,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231422,231433,231433,231433,231433,231434,231436,231443,231451,231452,231458,231458,231459,231463,231465,231465,231474,231477,231480,231482,231484,231486,231490,231495,231495,231495,231495,231495,231495,231496,231496,231496,231498,231505,231509,231514,231516,231533,231537,231540,231547,231547,231554,231560,231561,231563,231565,231571,231574,231576,231579,231580,231580,231580,231595,231595,231595,231597,231597,231597,231597,231597,231597,231605,231606,231608,231608,231610,231610,231610,231610,231610,231610,231610,231610,231610,231610,231610,231610,231611,231612,231612,231612,231612,231612,231612,231612,231612,231612,231612,231612,231612,231612,231612,231612,231614,231618,231619,231621,231621,231624,231625,231626,231626,231626,231626,231626,231629,231630,231633,231633,231633,231633,231635,231636,231636,231638,231643,231645,231646,231648,231648,231651,231652,231652,231652,231657,231665,231676,231678,231678,231679,231679,231686,231686,231686,231689,231692,231693,231695,231696,231699,231699,231703,231706,231710,231710,231710,231710,231713,231714,231717,231719,231720,231720,231724,231725,231727,231727,231727,231727,231728,231729,231730,231730,231730,231730,231730,231730,231732,231732,231732,231732,231733,231733,231733,231733,231733,231733,231733,231736,231736,231738,231738,231738,231738,231738,231738,231738,231740,231740,231740,231740,231742,231742,231742,231742,231743,231743,231743,231745,231747,231747,231747,231747,231749,231750,231750,231750,231750,231751,231754,231757,231761,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231762,231763,231764,231765,231765,231769,231769,231775,231776,231778,231781,231783,231787,231789,231789,231789,231790,231790,231790,231790,231790,231790,231790,231790,231791,231791,231791,231791,231792,231795,231795,231796,231798,231800,231803,231804,231805,231806,231807,231809,231809,231809,231809,231809,231809,231812,231812,231813,231817,231822,231824,231826,231826,231826,231826,231826,231826,231826,231826,231826,231826,231826,231826,231827,231828,231830,231831,231835,231839,231842,231842,231845,231849,231849,231856,231856,231857,231857,231857,231857,231857,231857,231857,231857,231857,231858,231860,231860,231862,231862,231862,231863,231866,231867,231867,231870,231871,231871,231871,231872,231873,231873,231873,231873,231873,231873,231873,231876,231877,231877,231878,231878,231878,231879,231881,231883,231886,231886,231890,231890,231890,231891,231891,231892,231895,231895,231895,231898,231901,231903,231903,231904,231905,231905,231906,231906,231907,231908,231908,231912,231912,231914,231914,231914,231914,231914,231914,231914,231915,231915,231915,231916,231916,231916,231916,231917,231919,231919,231919,231924,231925,231925,231926,231926,231926,231927,231929,231931,231931,231931,231931,231935,231936,231940,231941,231944,231946,231946,231947,231948,231949,231955,231955,231958,231959,231961,231962,231962,231965,231965,231966,231966,231969,231969,231969,231969,231969,231973,231974,231974,231974,231974,231974,231975,231975,231976,231976,231976,231976,231977,231977,231977,231977,231977,231980,231980,231980,231981,231981,231981,231981,231981,231981,231981,231983,231984,231990,231993,231993,231996,231996,231997,231997,231997,231997,231997,231998,231998,231998,231999,232001,232001,232001,232001,232002,232002,232004,232004,232004,232004,232004,232012,232012,232013,232019,232022,232022,232024,232025,232032,232033,232035,232035,232037,232039,232042,232042,232043,232044,232046,232046,232047,232047,232047,232048,232052,232055,232059,232059,232062,232064,232064,232065,232066,232066,232066,232066,232068,232068,232068,232069,232069,232069,232072,232072,232072,232074,232075,232075,232076,232076,232076,232079,232079,232079,232079,232079,232081,232081,232081,232087,232091,232091,232093,232093,232093,232093,232094,232094,232094,232095,232097,232101,232104,232106,232106,232107,232107,232107,232107,232107,232107,232107,232107,232109,232114,232114,232116,232116,232117,232117,232118,232118,232119,232121,232121,232126,232126,232126,232126,232126,232126,232126,232126,232126,232128,232128,232130,232139,232145,232145,232145,232145,232145,232145,232145,232145,232145,232145,232145,232145,232145,232145,232145,232145,232147,232147,232154,232157,232160,232160,232160,232160,232164,232165,232170,232171,232173,232174,232175,232175,232176,232180,232180,232180,232181,232184,232186,232187,232187,232187,232188,232188,232188,232188,232188,232188,232188,232189,232191,232191,232191,232191,232191,232191,232191,232191,232193,232195,232195,232198,232202,232202,232202,232202,232204,232204,232205,232205,232205,232206,232206,232206,232207,232207,232207,232207,232208,232209,232209,232209,232209,232209,232209,232213,232214,232214,232214,232215,232215,232217,232217,232217,232217,232217,232228,232228,232228,232228,232228,232228,232228,232228,232228,232228,232229,232230,232232,232233,232233,232234,232236,232237,232238,232238,232238,232238,232239,232239,232239,232239,232241,232241,232241,232243,232243,232243,232245,232245,232245,232247,232248,232249,232250,232257,232259,232259,232259,232259,232259,232260,232260,232260,232260,232260,232260,232260,232260,232260,232262,232262,232264,232264,232266,232266,232268,232270,232270,232271,232271,232271,232271,232271,232272,232273,232274,232274,232276,232277,232278,232278,232278,232285,232285,232287,232288,232293,232294,232295,232295,232296,232296,232299,232299,232299,232303,232304,232304,232304,232306,232308,232308,232313,232315,232317,232317,232317,232318,232318,232318,232320,232321,232325,232327,232328,232330,232331,232333,232333,232335,232335,232335,232336,232336,232337,232337,232338,232340,232340,232341,232341,232342,232342,232342,232342,232342,232342,232343,232343,232345,232345,232345,232347,232347,232347,232347,232350,232350,232350,232354,232354,232355,232355,232357,232357,232358,232358,232358,232358,232360,232362,232362,232366,232366,232368,232368,232371,232371,232372,232373,232373,232373,232373,232375,232375,232377,232378,232378,232380,232380,232380,232380,232380,232380,232382,232382,232382,232382,232382,232382,232385,232389,232389,232391,232393,232393,232395,232395,232395,232399,232399,232399,232400,232400,232400,232400,232414,232425,232425,232425,232425,232425,232425,232425,232426,232428,232430,232431,232431,232431,232432,232432,232432,232433,232436,232436,232436,232441,232447,232447,232450,232452,232452,232452,232452,232454,232457,232459,232459,232461,232464,232464,232467,232469,232470,232470,232471,232471,232471,232474,232475,232476,232478,232480,232482,232482,232486,232492,232492,232492,232494,232497,232499,232504,232504,232507,232513,232513,232517,232518,232519,232521,232521,232526,232536,232541,232561,232573,232574,232574,232577,232580,232580,232584,232605,232605,232605,232606,232620,232625,232625,232635,232637,232637,232643,232646,232646,232651,232666,232666,232666,232689,232692,232692,232692,232692,232692,232692,232692,232692,232692,232694,232696,232697,232701,232709,232727,232727,232728,232730,232730,232730,232730,232732,232732,232732,232733,232733,232733,232733,232735,232735,232735,232741,232745,232745,232745,232745,232747,232751,232754,232754,232754,232754,232757,232764,232766,232766,232766,232767,232772,232774,232775,232783,232786,232786,232789,232790,232793,232797,232798,232798,232798,232802,232803,232803,232803,232804,232804,232804,232814,232816,232818,232820,232821,232823,232826,232826,232827,232829,232829,232829,232829,232834,232836,232837,232837,232838,232839,232840,232841,232844,232844,232844,232844,232847,232850,232852,232856,232857,232857,232857,232858,232858,232860,232861,232861,232861,232862,232864,232864,232864,232864,232864,232865,232865,232865,232865,232865,232865,232865,232865,232866,232866,232866,232867,232867,232867,232867,232867,232868,232868,232868,232868,232868,232870,232872,232874,232875,232875,232878,232879,232879,232879,232880,232889,232889,232889,232889,232890,232890,232892,232895,232900,232900,232900,232903,232904,232905,232905,232908,232908,232909,232915,232915,232918,232921,232930,232931,232931,232931,232933,232933,232933,232937,232937,232937,232938,232945,232945,232945,232945,232945,232950,232952,232960,232966,232966,232966,232966,232966,232966,232966,232967,232975,232981,232981,232985,232991,232993,232993,232994,232995,232995,232999,233013,233013,233016,233016,233023,233026,233026,233045,233048,233054,233055,233062,233072,233073,233074,233075,233075,233076,233080,233082,233083,233083,233083,233083,233095,233099,233099,233105,233111,233111,233113,233113,233113,233114,233116,233116,233119,233120,233124,233126,233127,233138,233139,233140,233140,233140,233151,233161,233161,233164,233177,233180,233180,233180,233180,233180,233180,233180,233183,233194,233195,233197,233199,233199,233199,233199,233199,233199,233200,233200,233200,233202,233202,233205,233205,233205,233206,233213,233224,233225,233225,233235,233235,233235,233237,233239,233239,233242,233245,233245,233247,233248,233248,233250,233250,233250,233250,233251,233256,233263,233266,233267,233268,233268,233270,233270,233270,233272,233274,233274,233276,233276,233277,233277,233277,233277,233281,233283,233283,233286,233286,233288,233290,233293,233294,233294,233294,233294,233295,233297,233297,233301,233301,233302,233303,233303,233318,233326,233329,233337,233343,233352,233352,233358,233363,233363,233363,233365,233371,233377,233379,233382,233382,233382,233382,233382,233382,233382,233382,233382,233388,233402,233403,233403,233406,233412,233414,233414,233415,233415,233416,233417,233418,233441,233458,233472,233472,233472,233473,233473,233474,233474,233474,233479,233484,233489,233494,233497,233499,233505,233505,233514,233515,233522,233522,233522,233533,233534,233539,233546,233548,233548,233549,233550,233550,233550,233550,233550,233550,233551,233551,233552,233554,233554,233556,233559,233564,233567,233567,233567,233569,233577,233577,233578,233585,233587,233588,233590,233590,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233593,233599,233601,233605,233605,233606,233606,233606,233606,233606,233616,233616,233616,233616,233616,233616,233616,233616,233616,233618,233618,233625,233625,233630,233631,233631,233632,233636,233638,233641,233643,233645,233651,233658,233658,233658,233658,233661,233661,233663,233663,233663,233666,233668,233668,233669,233677,233679,233679,233679,233679,233680,233681,233681,233681,233682,233689,233689,233691,233691,233691,233694,233694,233698,233699,233703,233703,233705,233712,233712,233712,233713,233714,233714,233714,233714,233714,233721,233722,233722,233722,233723,233723,233723,233723,233724,233724,233724,233724,233724,233724,233724,233724,233724,233724,233724,233725,233725,233726,233726,233726,233726,233726,233726,233726,233726,233726,233726,233728,233729,233729,233729,233731,233731,233731,233732,233734,233734,233734,233735,233740,233747,233747,233749,233755,233763,233766,233769,233769,233772,233772,233772,233772,233772,233773,233774,233778,233779,233779,233790,233793,233798,233799,233803,233804,233804,233807,233812,233812,233812,233815,233815,233825,233828,233828,233828,233829,233831,233831,233832,233835,233837,233838,233838,233846,233847,233848,233848,233848,233856,233863,233865,233872,233872,233873,233873,233873,233873,233878,233879,233881,233881,233881,233882,233893,233893,233893,233893,233893,233893,233897,233897,233897,233897,233897,233897,233898,233898,233898,233898,233898,233898,233905,233905,233905,233906,233907,233911,233912,233915,233918,233919,233922,233922,233922,233926,233934,233935,233940,233947,233947,233948,233948,233955,233958,233958,233959,233963,233965,233966,233969,233973,233982,233984,233988,233988,233988,233991,233991,233994,233998,233998,233998,233998,234002,234004,234004,234010,234010,234010,234014,234019,234020,234030,234034,234039,234051,234051,234051,234051,234051,234069,234072,234075,234075,234079,234081,234083,234083,234090,234093,234095,234098,234102,234105,234105,234105,234109,234109,234109,234111,234114,234122,234122,234134,234137,234138,234140,234147,234147,234147,234155,234157,234157,234159,234166,234166,234167,234167,234168,234168,234168,234172,234177,234178,234183,234185,234185,234185,234185,234185,234191,234191,234194,234195,234195,234197,234200,234216,234220,234225,234225,234225,234225,234236,234244,234250,234250,234256,234258,234258,234258,234260,234260,234260,234260,234261,234263,234266,234270,234283,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234297,234304,234307,234310,234310,234310,234311,234311,234312,234314,234320,234322,234323,234325,234332,234337,234346,234346,234346,234351,234357,234357,234357,234357,234361,234361,234361,234362,234379,234382,234385,234388,234388,234388,234388,234388,234388,234389,234391,234391,234391,234391,234391,234391,234391,234391,234394,234394,234405,234405,234408,234412,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234425,234433,234444,234445,234446,234446,234460,234460,234460,234464,234466,234466,234466,234466,234467,234467,234469,234469,234476,234478,234483,234483,234483,234483,234490,234492,234492,234493,234494,234494,234494,234494,234494,234499,234508,234511,234511,234516,234518,234519,234521,234526,234526,234526,234526,234526,234526,234526,234526,234526,234526,234526,234530,234531,234533,234538,234543,234549,234551,234556,234562,234566,234566,234567,234575,234580,234585,234592,234593,234595,234600,234604,234604,234604,234605,234611,234615,234615,234627,234636,234637,234637,234642,234646,234647,234651,234653,234653,234655,234655,234660,234660,234660,234662,234663,234665,234667,234668,234677,234679,234683,234686,234686,234691,234691,234693,234693,234696,234697,234703,234711,234711,234711,234712,234712,234716,234726,234734,234734,234734,234734,234734,234737,234745,234753,234753,234753,234758,234761,234761,234766,234769,234771,234771,234774,234774,234774,234786,234809,234816,234827,234831,234832,234841,234841,234841,234843,234851,234858,234862,234862,234865,234866,234866,234869,234880,234880,234880,234883,234883,234883,234886,234887,234892,234903,234906,234914,234920,234922,234923,234923,234924,234924,234927,234927,234928,234931,234931,234932,234938,234940,234940,234941,234942,234942,234943,234944,234944,234944,234945,234945,234945,234945,234946,234946,234946,234946,234947,234948,234948,234948,234952,234953,234954,234958,234958,234958,234959,234963,234969,234975,234980,234980,234983,234983,234985,234991,234991,235004,235007,235009,235012,235019,235023,235027,235037,235040,235044,235044,235044,235047,235052,235052,235062,235062,235064,235064,235067,235067,235070,235072,235076,235076,235077,235078,235078,235078,235078,235078,235078,235078,235078,235081,235081,235082,235082,235083,235083,235092,235093,235093,235104,235108,235112,235115,235121,235122,235123,235126,235128,235129,235129,235129,235129,235129,235130,235130,235132,235132,235135,235149,235156,235157,235157,235160,235160,235161,235167,235167,235169,235175,235178,235188,235188,235189,235189,235189,235190,235190,235190,235190,235190,235190,235190,235191,235192,235205,235216,235220,235226,235233,235234,235236,235242,235245,235255,235256,235258,235259,235261,235261,235261,235261,235261,235261,235261,235261,235266,235276,235276,235276,235286,235288,235288,235290,235292,235292,235294,235297,235316,235316,235360,235362,235363,235365,235365,235365,235365,235369,235373,235373,235376,235385,235402,235404,235404,235404,235419,235419,235426,235432,235432,235440,235448,235449,235449,235449,235449,235449,235449,235449,235449,235450,235451,235452,235452,235452,235452,235452,235452,235452,235454,235454,235455,235459,235460,235461,235461,235465,235465,235465,235465,235467,235467,235468,235468,235468,235468,235468,235475,235477,235477,235477,235477,235479,235480,235489,235489,235489,235489,235491,235492,235492,235492,235495,235495,235495,235495,235500,235500,235500,235500,235500,235500,235500,235500,235500,235503,235503,235505,235505,235506,235509,235511,235512,235512,235512,235513,235513,235513,235514,235514,235515,235516,235517,235524,235525,235526,235527,235527,235533,235539,235541,235541,235545,235551,235551,235554,235554,235557,235557,235558,235559,235559,235560,235562,235565,235579,235579,235579,235582,235582,235582,235583,235583,235585,235591,235594,235596,235596,235596,235603,235612,235612,235613,235623,235626,235629,235634,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235636,235639,235639,235639,235639,235639,235640,235649,235650,235651,235654,235657,235661,235680,235680,235680,235680,235686,235688,235690,235690,235695,235717,235728,235748,235748,235769,235781,235793,235793,235795,235795,235795,235795,235817,235817,235817,235817,235817,235817,235817,235817,235824,235824,235824,235826,235828,235835,235835,235842,235843,235844,235848,235849,235849,235849,235849,235861,235864,235864,235864,235864,235865,235867,235870,235871,235872,235874,235874,235874,235874,235874,235875,235876,235876,235876,235876,235876,235876,235876,235876,235878,235878,235878,235878,235879,235879,235880,235882,235882,235882,235884,235884,235884,235893,235894,235894,235894,235894,235896,235896,235896,235896,235896,235897,235897,235897,235897,235898,235898,235899,235906,235906,235906,235906,235908,235908,235910,235912,235927,235929,235930,235930,235930,235934,235934,235934,235934,235934,235938,235938,235938,235938,235938,235939,235940,235942,235948,235948,235948,235948,235948,235948,235948,235949,235950,235950,235950,235950,235950,235951,235954,235954,235954,235954,235956,235956,235961,235961,235961,235961,235961,235962,235963,235963,235963,235963,235963,235963,235963,235963,235963,235963,235964,235964,235964,235964,235967,235967,235968,235969,235972,235972,235972,235972,235972,235974,235974,235980,235981,235982,235982,235984,235985,235985,235993,235993,235993,235993,235993,235993,235993,235993,235993,235996,236005,236008,236011,236013,236015,236017,236018,236029,236029,236030,236034,236034,236036,236037,236044,236045,236046,236046,236046,236048,236050,236050,236051,236055,236057,236061,236070,236070,236071,236078,236078,236085,236087,236087,236087,236087,236090,236101,236102,236107,236109,236109,236109,236113,236113,236114,236114,236114,236116,236120,236151,236152,236166,236167,236170,236175,236175,236178,236192,236200,236200,236200,236203,236207,236208,236221,236227,236233,236235,236235,236235,236238,236240,236242,236248,236248,236248,236248,236248,236253,236255,236265,236266,236284,236285,236285,236285,236285,236285,236292,236292,236292,236294,236296,236296,236297,236297,236299,236300,236301,236305,236305,236305,236305,236305,236310,236311,236311,236313,236313,236313,236323,236327,236330,236332,236332,236332,236339,236339,236339,236339,236339,236339,236339,236339,236339,236339,236339,236339,236339,236339,236340,236340,236348,236357,236358,236362,236362,236369,236375,236376,236377,236377,236379,236386,236389,236393,236393,236394,236394,236394,236396,236402,236402,236402,236403,236404,236413,236413,236415,236415,236415,236416,236417,236423,236423,236425,236425,236425,236425,236426,236443,236445,236462,236466,236466,236466,236466,236468,236470,236470,236472,236472,236473,236473,236480,236488,236488,236488,236495,236500,236500,236501,236501,236506,236512,236517,236517,236517,236517,236517,236521,236521,236521,236521,236525,236527,236531,236533,236536,236536,236536,236536,236536,236536,236537,236546,236549,236549,236551,236552,236557,236557,236563,236566,236572,236574,236574,236575,236575,236575,236578,236578,236578,236579,236583,236593,236599,236599,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236603,236604,236604,236605,236605,236605,236605,236605,236605,236605,236605,236605,236605,236608,236610,236610,236614,236617,236617,236617,236617,236617,236617,236617,236620,236620,236623,236624,236624,236624,236626,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236627,236628,236630,236630,236630,236630,236631,236632,236632,236632,236635,236636,236636,236637,236637,236638,236638,236638,236641,236641,236641,236641,236641,236641,236642,236642,236644,236644,236644,236644,236644,236650,236650,236650,236651,236651,236651,236651,236651,236651,236651,236651,236651,236651,236651,236651,236651,236651,236651,236651,236653,236657,236658,236659,236660,236665,236665,236665,236666,236668,236670,236670,236674,236676,236676,236676,236676,236676,236677,236679,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236680,236681,236681,236682,236682,236682,236683,236683,236683,236683,236683,236683,236684,236684,236684,236684,236685,236685,236686,236686,236686,236686,236686,236687,236687,236688,236688,236688,236690,236690,236690,236690,236690,236691,236691,236691,236692,236692,236692,236694,236694,236694,236694,236695,236695,236695,236696,236696,236696,236696,236696,236697,236698,236699,236699,236699,236699,236699,236699,236699,236699,236699,236699,236701,236701,236703,236703,236703,236703,236703,236703,236703,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236707,236708,236708,236709,236709,236709,236709,236709,236709,236709,236710,236710,236710,236710,236710,236710,236710,236710,236710,236712,236712,236713,236713,236713,236714,236714,236714,236714,236715,236716,236716,236717,236717,236718,236718,236718,236718,236719,236721,236722,236722,236722,236722,236722,236722,236722,236723,236723,236723,236723,236727,236729,236730,236730,236730,236733,236733,236734,236736,236736,236736,236736,236736,236736,236737,236737,236738,236739,236740,236740,236741,236742,236743,236743,236749,236750,236751,236753,236754,236754,236754,236756,236757,236757,236757,236757,236757,236758,236758,236759,236760,236760,236765,236766,236766,236769,236769,236776,236785,236785,236785,236785,236787,236788,236788,236789,236789,236791,236791,236795,236796,236797,236797,236797,236797,236799,236799,236799,236799,236799,236799,236801,236803,236803,236804,236807,236807,236808,236811,236811,236811,236811,236811,236812,236822,236827,236828,236828,236828,236828,236828,236828,236828,236828,236834,236836,236840,236842,236847,236852,236853,236859,236860,236861,236861,236863,236864,236864,236864,236864,236864,236865,236868,236869,236869,236870,236870,236871,236872,236875,236876,236878,236881,236882,236882,236884,236885,236885,236886,236898,236899,236899,236899,236902,236903,236904,236904,236906,236906,236906,236907,236907,236907,236907,236908,236908,236909,236912,236915,236919,236919,236925,236927,236929,236929,236929,236929,236931,236937,236937,236944,236944,236946,236947,236947,236951,236951,236951,236951,236951,236953,236954,236954,236955,236965,236969,236969,236969,236970,236970,236971,236972,236972,236973,236974,236974,236977,236977,236980,236980,236981,236992,236998,237003,237003,237004,237004,237006,237006,237006,237006,237006,237006,237006,237006,237006,237006,237006,237006,237007,237014,237023,237023,237023,237023,237023,237026,237028,237034,237034,237034,237034,237034,237034,237037,237037,237039,237045,237046,237048,237049,237058,237058,237058,237058,237058,237058,237058,237058,237058,237058,237058,237058,237061,237065,237066,237069,237069,237071,237073,237073,237085,237089,237089,237090,237093,237095,237098,237104,237118,237118,237118,237118,237118,237118,237118,237120,237126,237129,237129,237129,237129,237129,237129,237129,237132,237132,237135,237135,237149,237149,237154,237165,237165,237166,237169,237170,237171,237171,237172,237172,237173,237173,237177,237180,237183,237194,237194,237195,237200,237201,237201,237203,237203,237204,237222,237225,237227,237228,237229,237233,237233,237233,237233,237241,237241,237242,237242,237243,237249,237252,237252,237252,237252,237256,237260,237260,237260,237260,237260,237260,237260,237260,237260,237261,237261,237261,237261,237261,237261,237261,237261,237261,237262,237262,237262,237262,237262,237262,237263,237263,237263,237263,237263,237263,237263,237264,237264,237264,237264,237264,237264,237264,237264,237264,237265,237265,237265,237266,237267,237267,237267,237267,237267,237268,237268,237268,237269,237269,237269,237269,237269,237270,237270,237271,237274,237275,237276,237276,237276,237277,237277,237280,237283,237284,237284,237285,237286,237286,237286,237286,237290,237291,237295,237295,237295,237295,237295,237295,237295,237295,237295,237295,237295,237295,237302,237302,237302,237302,237302,237308,237310,237310,237310,237311,237312,237313,237314,237317,237318,237319,237325,237340,237340,237340,237340,237340,237341,237346,237347,237348,237348,237348,237353,237362,237365,237376,237388,237390,237392,237392,237392,237392,237392,237392,237392,237393,237393,237393,237402,237411,237411,237411,237417,237417,237424,237429,237432,237433,237437,237437,237437,237439,237445,237453,237453,237455,237456,237459,237459,237461,237465,237466,237466,237466,237470,237476,237488,237491,237498,237503,237503,237513,237518,237519,237519,237520,237527,237527,237527,237528,237529,237532,237539,237539,237541,237546,237547,237549,237551,237551,237551,237551,237554,237558,237560,237560,237564,237579,237579,237583,237586,237599,237600,237602,237602,237603,237611,237611,237611,237613,237613,237613,237624,237624,237624,237624,237624,237630,237630,237630,237630,237630,237631,237639,237639,237639,237639,237639,237639,237643,237644,237644,237645,237646,237650,237650,237651,237654,237655,237659,237659,237661,237661,237662,237663,237663,237663,237663,237663,237663,237663,237667,237667,237667,237667,237667,237668,237670,237670,237675,237675,237679,237679,237680,237682,237682,237682,237682,237689,237691,237691,237691,237691,237693,237693,237698,237705,237705,237705,237705,237708,237708,237709,237709,237709,237709,237720,237720,237720,237720,237720,237720,237720,237722,237724,237724,237724,237728,237731,237736,237742,237742,237742,237742,237742,237742,237742,237751,237751,237751,237751,237751,237751,237760,237760,237765,237765,237768,237769,237775,237775,237779,237782,237783,237784,237784,237785,237793,237794,237797,237799,237799,237802,237809,237811,237812,237812,237817,237818,237820,237827,237846,237849,237849,237849,237854,237858,237865,237874,237888,237890,237891,237891,237891,237893,237893,237913,237921,237921,237926,237934,237937,237952,237956,237958,237958,237959,237959,237959,237959,237959,237966,237973,237973,237974,237980,237987,237987,237992,238002,238002,238003,238006,238008,238010,238011,238011,238011,238011,238013,238015,238029,238029,238047,238052,238054,238057,238057,238057,238057,238062,238062,238071,238071,238073,238074,238074,238074,238074,238075,238075,238092,238093,238093,238094,238094,238099,238100,238100,238101,238101,238103,238103,238104,238105,238107,238113,238113,238117,238118,238125,238132,238133,238147,238152,238152,238155,238155,238159,238161,238161,238164,238166,238167,238175,238178,238178,238178,238182,238183,238196,238199,238210,238210,238213,238213,238213,238213,238213,238214,238218,238218,238219,238228,238228,238230,238230,238237,238237,238239,238242,238247,238248,238249,238249,238250,238250,238253,238253,238253,238254,238256,238266,238280,238281,238302,238302,238304,238308,238308,238321,238324,238324,238324,238324,238327,238330,238331,238341,238344,238345,238347,238350,238350,238355,238355,238355,238355,238356,238358,238366,238366,238366,238368,238372,238372,238379,238379,238385,238385,238385,238393,238393,238398,238401,238417,238426,238427,238428,238429,238429,238429,238429,238430,238433,238433,238435,238435,238437,238439,238439,238454,238454,238458,238470,238470,238470,238470,238477,238492,238494,238503,238508,238508,238512,238515,238516,238518,238525,238525,238525,238531,238531,238533,238533,238537,238537,238537,238542,238548,238549,238556,238560,238565,238565,238589,238595,238595,238595,238595,238599,238600,238600,238603,238607,238608,238608,238620,238632,238632,238636,238637,238638,238645,238647,238647,238654,238658,238662,238666,238669,238672,238674,238682,238692,238695,238704,238706,238717,238720,238723,238723,238723,238724,238724,238724,238724,238724,238725,238725,238725,238727,238728,238728,238730,238730,238732,238732,238737,238738,238738,238738,238738,238738,238740,238740,238740,238740,238740,238740,238740,238740,238740,238740,238740,238745,238748,238749,238755,238757,238758,238758,238770,238775,238781,238786,238791,238793,238793,238795,238796,238796,238796,238797,238797,238800,238801,238804,238805,238806,238811,238811,238811,238824,238827,238832,238837,238845,238845,238845,238846,238846,238852,238854,238867,238867,238876,238877,238877,238877,238877,238877,238877,238877,238877,238877,238877,238886,238896,238896,238899,238906,238910,238910,238910,238911,238916,238921,238925,238935,238935,238938,238938,238938,238950,238958,238958,238963,238965,238965,238966,238966,238966,238967,238967,238970,238970,238971,238972,238973,238973,238973,238975,238976,238977,238978,238979,238983,238983,238983,238983,238983,238986,238988,238988,238989,238993,238997,239005,239005,239005,239005,239008,239008,239010,239030,239030,239033,239040,239043,239043,239043,239047,239054,239057,239059,239059,239061,239068,239068,239074,239085,239088,239088,239092,239095,239095,239095,239103,239104,239109,239111,239118,239121,239123,239125,239127,239128,239130,239131,239131,239131,239134,239138,239141,239143,239144,239145,239145,239147,239148,239148,239149,239150,239150,239151,239153,239153,239163,239165,239165,239165,239165,239168,239168,239170,239172,239177,239179,239188,239192,239192,239201,239202,239204,239211,239212,239213,239213,239213,239213,239213,239213,239213,239213,239213,239213,239213,239213,239214,239214,239214,239221,239224,239224,239226,239226,239229,239232,239232,239232,239232,239238,239242,239243,239244,239245,239246,239246,239246,239254,239268,239273,239280,239282,239284,239286,239290,239291,239296,239300,239309,239316,239324,239325,239334,239334,239343,239343,239343,239346,239350,239351,239351,239355,239357,239357,239357,239361,239363,239366,239374,239374,239375,239379,239382,239385,239387,239387,239401,239402,239402,239402,239402,239405,239412,239416,239417,239419,239424,239430,239433,239435,239436,239442,239451,239454,239456,239459,239463,239467,239468,239469,239469,239473,239473,239473,239478,239483,239484,239497,239498,239498,239509,239513,239517,239517,239517,239524,239525,239527,239527,239528,239528,239529,239531,239534,239536,239546,239547,239555,239558,239562,239571,239572,239574,239577,239580,239583,239589,239598,239599,239602,239602,239604,239605,239616,239628,239633,239633,239634,239637,239637,239637,239638,239640,239647,239647,239650,239651,239653,239654,239659,239665,239674,239677,239677,239678,239686,239687,239695,239695,239701,239713,239714,239717,239718,239720,239720,239732,239732,239734,239734,239734,239734,239734,239734,239739,239743,239745,239750,239755,239757,239757,239757,239757,239757,239757,239757,239757,239757,239757,239757,239757,239757,239758,239760,239760,239765,239771,239776,239780,239781,239781,239781,239781,239792,239792,239793,239794,239797,239797,239797,239799,239803,239804,239809,239809,239809,239812,239813,239817,239826,239834,239835,239840,239842,239851,239854,239860,239860,239862,239863,239869,239869,239871,239872,239874,239874,239878,239878,239878,239878,239878,239878,239880,239885,239885,239885,239887,239888,239889,239889,239889,239891,239898,239901,239906,239907,239907,239907,239907,239912,239912,239920,239931,239938,239944,239944,239950,239951,239951,239951,239958,239958,239958,239958,239960,239961,239963,239963,239963,239963,239963,239963,239965,239965,239966,239967,239968,239969,239969,239969,239984,239985,239985,239986,239988,239988,239992,239992,239992,239994,239996,239996,239997,240000,240000,240004,240005,240005,240005,240005,240005,240005,240006,240006,240006,240008,240008,240009,240009,240010,240010,240010,240011,240011,240012,240019,240029,240045,240045,240046,240050,240050,240050,240050,240053,240053,240054,240054,240054,240054,240054,240054,240055,240055,240057,240059,240062,240064,240065,240065,240068,240068,240068,240072,240076,240076,240079,240079,240082,240085,240085,240085,240085,240085,240085,240085,240085,240085,240087,240089,240089,240090,240092,240092,240092,240095,240096,240097,240097,240097,240097,240101,240101,240116,240132,240135,240135,240135,240135,240148,240151,240151,240155,240158,240161,240164,240165,240172,240172,240172,240172,240172,240172,240172,240177,240177,240177,240177,240186,240187,240189,240194,240195,240195,240195,240211,240212,240213,240214,240219,240219,240219,240219,240220,240223,240223,240234,240234,240234,240239,240245,240246,240258,240258,240258,240258,240258,240258,240258,240258,240258,240258,240258,240267,240278,240281,240285,240286,240287,240287,240287,240293,240294,240295,240305,240309,240313,240314,240316,240321,240324,240324,240324,240324,240325,240325,240325,240325,240326,240326,240326,240326,240329,240330,240330,240330,240330,240330,240330,240330,240330,240330,240330,240330,240330,240332,240333,240335,240335,240336,240338,240338,240347,240347,240348,240348,240348,240348,240350,240350,240352,240352,240358,240359,240359,240362,240367,240372,240375,240375,240376,240376,240381,240384,240389,240393,240395,240397,240397,240404,240406,240412,240417,240420,240420,240427,240429,240436,240442,240446,240448,240454,240454,240457,240459,240459,240460,240462,240462,240463,240464,240465,240470,240474,240474,240474,240474,240474,240474,240477,240484,240486,240487,240489,240496,240497,240499,240500,240500,240500,240500,240504,240514,240515,240517,240521,240538,240538,240538,240538,240542,240549,240558,240558,240573,240575,240575,240578,240580,240595,240615,240628,240631,240639,240663,240663,240663,240663,240663,240673,240673,240677,240686,240688,240697,240697,240699,240707,240707,240707,240709,240709,240716,240723,240724,240737,240737,240737,240740,240740,240740,240740,240744,240749,240749,240749,240749,240753,240753,240753,240760,240761,240765,240765,240781,240784,240785,240795,240795,240796,240798,240806,240810,240816,240821,240826,240834,240834,240838,240838,240839,240841,240841,240841,240847,240847,240847,240849,240849,240851,240851,240851,240853,240859,240859,240859,240859,240859,240863,240863,240863,240863,240880,240888,240892,240893,240895,240908,240927,240938,240946,240949,240959,240962,240970,240971,240971,240971,240989,240989,240989,240989,240991,240991,240999,241000,241000,241000,241000,241000,241000,241000,241000,241003,241005,241005,241005,241005,241005,241006,241009,241009,241012,241016,241019,241022,241022,241024,241029,241033,241046,241047,241047,241056,241066,241069,241071,241074,241077,241078,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241088,241089,241092,241092,241092,241092,241093,241093,241094,241096,241096,241096,241101,241101,241101,241101,241102,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241103,241104,241104,241104,241104,241104,241105,241105,241105,241105,241105,241106,241106,241106,241110,241110,241110,241110,241110,241110,241110,241112,241114,241114,241114,241115,241115,241116,241116,241118,241120,241120,241120,241124,241124,241124,241124,241124,241125,241125,241125,241125,241125,241126,241126,241126,241126,241128,241129,241129,241129,241130,241133,241133,241133,241139,241139,241140,241141,241146,241146,241147,241148,241148,241149,241149,241149,241149,241153,241154,241156,241156,241159,241159,241160,241161,241163,241168,241168,241168,241168,241168,241168,241168,241168,241168,241168,241168,241168,241170,241173,241174,241175,241181,241205,241210,241217,241220,241220,241224,241231,241231,241237,241237,241243,241246,241248,241249,241249,241252,241260,241260,241266,241268,241268,241268,241268,241269,241269,241270,241275,241277,241277,241278,241279,241280,241280,241280,241281,241281,241281,241281,241282,241282,241282,241282,241282,241283,241288,241291,241295,241299,241304,241304,241305,241306,241309,241314,241317,241317,241320,241328,241337,241338,241338,241348,241353,241354,241356,241359,241367,241367,241367,241369,241372,241373,241373,241377,241380,241381,241382,241385,241387,241387,241389,241394,241395,241403,241404,241405,241405,241410,241413,241413,241413,241415,241415,241415,241415,241415,241415,241415,241415,241415,241415,241426,241426,241426,241426,241426,241426,241426,241426,241426,241426,241426,241433,241441,241442,241443,241446,241446,241447,241447,241447,241447,241447,241447,241447,241449,241455,241462,241464,241464,241466,241471,241471,241474,241476,241480,241483,241484,241488,241493,241495,241499,241500,241508,241508,241513,241513,241527,241527,241532,241533,241534,241536,241538,241540,241545,241550,241550,241550,241558,241558,241558,241558,241565,241565,241568,241580,241584,241584,241584,241584,241596,241596,241596,241596,241602,241610,241613,241613,241614,241614,241625,241625,241625,241625,241627,241627,241627,241632,241634,241637,241639,241640,241645,241645,241646,241647,241648,241665,241668,241672,241674,241682,241686,241686,241690,241690,241693,241693,241694,241694,241694,241694,241694,241694,241694,241694,241696,241696,241697,241697,241701,241701,241704,241720,241721,241727,241744,241752,241754,241766,241769,241772,241772,241774,241774,241788,241788,241789,241790,241790,241795,241795,241797,241803,241803,241803,241808,241810,241810,241810,241810,241810,241816,241817,241821,241823,241823,241823,241823,241829,241829,241830,241830,241839,241847,241857,241857,241857,241857,241860,241860,241860,241862,241862,241868,241874,241875,241882,241883,241905,241909,241915,241915,241915,241923,241923,241923,241924,241928,241928,241935,241935,241937,241938,241939,241939,241943,241943,241950,241955,241955,241956,241961,241966,241971,241971,241974,241974,241974,241974,241974,241977,241982,241986,241986,241986,241987,241999,242004,242004,242004,242010,242011,242011,242025,242025,242026,242028,242043,242054,242056,242061,242061,242070,242073,242074,242078,242100,242100,242100,242100,242100,242101,242104,242108,242108,242108,242108,242113,242117,242123,242123,242125,242125,242125,242129,242129,242129,242130,242130,242132,242132,242137,242137,242137,242143,242149,242157,242173,242186,242186,242188,242189,242189,242196,242196,242196,242201,242201,242225,242231,242240,242241,242241,242241,242241,242241,242241,242244,242244,242246,242246,242246,242252,242255,242255,242255,242255,242255,242255,242255,242259,242261,242261,242264,242271,242277,242281,242281,242281,242282,242282,242282,242294,242299,242299,242311,242315,242317,242320,242325,242325,242329,242330,242330,242330,242330,242330,242330,242330,242332,242332,242332,242336,242340,242341,242345,242346,242353,242353,242353,242354,242355,242359,242367,242370,242374,242377,242378,242386,242389,242389,242389,242389,242390,242390,242390,242394,242394,242394,242394,242394,242394,242394,242395,242398,242398,242398,242400,242400,242400,242400,242403,242403,242404,242415,242415,242418,242418,242418,242418,242422,242424,242428,242437,242440,242440,242440,242441,242441,242445,242456,242468,242468,242468,242480,242481,242484,242485,242490,242496,242502,242502,242502,242504,242511,242514,242517,242517,242522,242525,242529,242533,242544,242549,242549,242552,242568,242571,242572,242572,242581,242581,242581,242586,242588,242589,242596,242596,242596,242598,242598,242603,242603,242603,242604,242611,242613,242619,242625,242645,242645,242645,242645,242654,242657,242672,242680,242680,242681,242682,242685,242685,242693,242694,242694,242695,242696,242708,242708,242708,242719,242719,242719,242721,242721,242731,242755,242757,242757,242757,242763,242763,242764,242764,242764,242764,242764,242779,242780,242780,242782,242782,242785,242785,242785,242785,242796,242798,242801,242803,242808,242815,242827,242828,242845,242845,242851,242851,242861,242865,242880,242883,242884,242884,242884,242893,242893,242903,242913,242928,242930,242936,242936,242945,242945,242949,242952,242954,242958,242959,242959,242979,243011,243011,243011,243011,243011,243011,243012,243012,243013,243013,243013,243013,243013,243013,243013,243014,243014,243014,243014,243014,243014,243014,243016,243016,243017,243024,243024,243024,243036,243037,243037,243047,243052,243058,243068,243068,243069,243069,243069,243069,243069,243069,243069,243071,243078,243079,243079,243095,243101,243102,243102,243102,243102,243102,243102,243115,243126,243127,243136,243140,243143,243143,243143,243143,243144,243151,243152,243152,243153,243154,243155,243165,243166,243168,243169,243180,243180,243183,243185,243185,243185,243185,243185,243190,243196,243201,243201,243213,243231,243233,243234,243235,243236,243241,243245,243245,243254,243254,243258,243260,243260,243268,243268,243273,243280,243295,243307,243309,243310,243312,243314,243315,243319,243327,243328,243344,243346,243359,243373,243373,243383,243401,243401,243402,243402,243403,243403,243403,243403,243404,243404,243404,243404,243404,243404,243405,243405,243405,243405,243406,243406,243406,243406,243407,243407,243407,243407,243408,243408,243409,243409,243410,243410,243411,243411,243416,243431,243433,243437,243437,243450,243453,243456,243456,243456,243460,243460,243465,243465,243465,243472,243481,243481,243491,243492,243497,243499,243504,243526,243533,243533,243533,243541,243541,243541,243541,243541,243544,243546,243546,243547,243553,243554,243554,243556,243558,243562,243566,243566,243566,243566,243566,243566,243578,243583,243602,243610,243613,243615,243625,243625,243625,243625,243625,243627,243630,243630,243631,243635,243638,243645,243648,243649,243650,243656,243658,243658,243662,243665,243665,243666,243672,243680,243682,243682,243682,243685,243689,243689,243693,243693,243697,243699,243707,243707,243707,243707,243707,243707,243709,243709,243710,243710,243710,243710,243710,243710,243711,243711,243711,243712,243712,243712,243712,243713,243714,243714,243717,243717,243717,243717,243717,243717,243723,243723,243724,243724,243724,243724,243727,243727,243733,243743,243746,243746,243749,243752,243754,243754,243754,243755,243755,243755,243758,243760,243760,243764,243765,243771,243771,243771,243776,243776,243776,243777,243777,243777,243777,243778,243780,243781,243786,243789,243789,243793,243794,243795,243795,243795,243798,243802,243802,243803,243803,243809,243810,243810,243810,243810,243810,243817,243817,243817,243817,243817,243822,243823,243827,243827,243831,243837,243853,243856,243866,243866,243868,243868,243871,243874,243874,243899,243906,243906,243906,243906,243906,243906,243906,243906,243906,243906,243906,243906,243908,243909,243916,243916,243917,243917,243917,243917,243923,243926,243926,243937,243950,243959,243962,243964,243971,243972,243972,243972,243975,243975,243977,243983,243997,243999,244002,244014,244014,244014,244019,244019,244020,244023,244023,244032,244032,244044,244046,244048,244048,244048,244048,244048,244052,244052,244052,244053,244053,244055,244061,244065,244071,244074,244080,244085,244090,244093,244098,244100,244102,244102,244107,244122,244122,244125,244131,244134,244134,244134,244134,244135,244135,244135,244136,244139,244143,244147,244147,244160,244160,244162,244163,244166,244168,244168,244169,244170,244178,244179,244179,244181,244182,244187,244187,244187,244193,244199,244202,244204,244204,244210,244219,244222,244234,244241,244243,244243,244243,244243,244244,244244,244249,244249,244249,244261,244263,244265,244275,244278,244282,244286,244287,244293,244293,244295,244301,244305,244307,244307,244307,244319,244319,244332,244336,244340,244350,244353,244357,244357,244376,244379,244379,244379,244379,244379,244379,244379,244381,244401,244405,244419,244419,244419,244419,244423,244427,244427,244427,244428,244429,244430,244430,244430,244433,244435,244438,244440,244447,244447,244451,244453,244454,244454,244454,244456,244456,244456,244457,244457,244465,244465,244465,244465,244465,244466,244470,244472,244473,244473,244473,244473,244478,244479,244481,244481,244484,244485,244486,244486,244486,244489,244495,244498,244508,244510,244510,244512,244515,244516,244542,244549,244549,244550,244550,244554,244557,244557,244559,244560,244574,244579,244580,244582,244582,244582,244586,244596,244600,244600,244600,244602,244607,244609,244612,244616,244619,244619,244623,244623,244623,244624,244636,244649,244650,244661,244661,244661,244669,244676,244676,244676,244676,244677,244677,244685,244690,244690,244692,244694,244695,244697,244697,244698,244698,244701,244701,244706,244712,244718,244724,244724,244726,244726,244726,244726,244731,244731,244737,244738,244748,244751,244754,244756,244763,244763,244769,244786,244791,244791,244791,244792,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244804,244811,244811,244824,244825,244829,244831,244839,244844,244848,244849,244850,244851,244851,244851,244852,244852,244853,244860,244861,244861,244861,244863,244864,244864,244868,244869,244870,244871,244874,244874,244875,244881,244897,244898,244903,244903,244904,244906,244913,244925,244926,244928,244939,244940,244940,244940,244944,244947,244951,244951,244951,244951,244951,244951,244959,244962,244962,244962,244962,244964,244969,244969,244969,244969,244972,244986,244992,244995,244997,244999,245000,245007,245007,245020,245022,245028,245028,245049,245049,245049,245049,245049,245057,245063,245063,245067,245071,245071,245071,245072,245072,245072,245073,245076,245077,245081,245085,245090,245091,245092,245095,245096,245097,245101,245101,245101,245107,245111,245112,245117,245125,245125,245140,245140,245140,245140,245142,245145,245167,245191,245192,245194,245197,245204,245207,245217,245220,245223,245227,245235,245236,245237,245238,245242,245242,245242,245248,245248,245257,245265,245292,245297,245298,245301,245305,245307,245314,245321,245326,245333,245333,245333,245339,245345,245347,245349,245353,245353,245353,245354,245368,245368,245368,245393,245393,245395,245395,245402,245405,245411,245413,245414,245424,245424,245446,245446,245446,245446,245447,245451,245451,245451,245456,245456,245459,245472,245476,245476,245479,245482,245483,245483,245483,245483,245483,245485,245487,245493,245494,245494,245494,245494,245502,245509,245512,245515,245522,245547,245557,245562,245564,245564,245564,245564,245564,245564,245564,245581,245585,245589,245589,245589,245589,245589,245589,245589,245590,245591,245591,245591,245591,245595,245595,245595,245602,245604,245608,245608,245609,245623,245636,245641,245662,245664,245665,245670,245676,245681,245681,245681,245682,245686,245692,245692,245694,245696,245697,245700,245702,245704,245704,245708,245708,245708,245708,245708,245717,245722,245728,245734,245734,245738,245738,245738,245741,245742,245752,245752,245768,245779,245780,245781,245784,245788,245790,245792,245795,245797,245799,245801,245803,245807,245823,245824,245824,245824,245824,245832,245836,245852,245857,245857,245857,245857,245858,245864,245864,245869,245877,245878,245881,245881,245881,245885,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245886,245889,245889,245889,245889,245889,245889,245889,245890,245891,245896,245897,245901,245903,245904,245910,245910,245914,245914,245917,245918,245918,245919,245925,245925,245929,245929,245931,245934,245934,245936,245939,245939,245939,245944,245955,245955,245962,245963,245968,245976,245977,245978,245978,245984,245986,246006,246007,246009,246009,246009,246016,246016,246020,246021,246021,246021,246030,246030,246030,246030,246042,246042,246044,246059,246067,246067,246067,246077,246078,246087,246087,246087,246087,246087,246087,246087,246093,246095,246095,246095,246095,246098,246098,246103,246108,246109,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246123,246125,246125,246134,246135,246135,246137,246137,246140,246141,246143,246143,246143,246143,246143,246143,246143,246143,246143,246143,246143,246143,246143,246144,246144,246144,246144,246144,246144,246144,246144,246144,246144,246144,246144,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246146,246150,246151,246151,246151,246151,246151,246151,246151,246152,246153,246158,246158,246159,246161,246162,246162,246163,246163,246163,246163,246163,246164,246164,246164,246164,246164,246164,246164,246164,246164,246165,246166,246166,246166,246166,246166,246167,246167,246167,246168,246168,246168,246168,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246169,246171,246171,246173,246173,246174,246175,246175,246175,246175,246175,246175,246175,246175,246175,246176,246176,246178,246178,246181,246181,246181,246181,246181,246181,246182,246183,246183,246183,246183,246183,246184,246184,246184,246186,246187,246188,246190,246191,246191,246191,246191,246191,246192,246194,246194,246195,246195,246196,246196,246196,246197,246197,246197,246198,246201,246201,246202,246203,246203,246205,246205,246205,246206,246213,246215,246215,246217,246221,246222,246222,246222,246222,246222,246222,246228,246230,246230,246230,246232,246232,246232,246233,246234,246238,246240,246240,246240,246240,246242,246244,246247,246247,246249,246249,246254,246255,246255,246255,246255,246255,246255,246255,246258,246259,246259,246261,246263,246263,246263,246263,246266,246266,246266,246266,246266,246269,246269,246275,246275,246275,246277,246278,246278,246287,246295,246298,246301,246306,246315,246323,246328,246329,246331,246331,246331,246337,246337,246337,246337,246341,246341,246341,246341,246341,246341,246341,246343,246343,246343,246343,246345,246346,246349,246357,246362,246362,246367,246370,246370,246382,246385,246386,246386,246388,246388,246393,246397,246397,246404,246404,246404,246411,246415,246420,246420,246420,246420,246421,246421,246421,246421,246421,246421,246429,246434,246439,246447,246447,246447,246451,246459,246459,246460,246460,246460,246463,246464,246464,246464,246465,246469,246469,246469,246470,246473,246476,246477,246478,246478,246478,246482,246485,246492,246505,246513,246514,246515,246515,246519,246519,246524,246526,246530,246531,246533,246533,246534,246538,246545,246547,246552,246552,246552,246555,246557,246557,246557,246558,246558,246558,246564,246567,246567,246568,246568,246568,246568,246568,246571,246571,246571,246571,246571,246571,246571,246572,246573,246573,246573,246573,246573,246573,246574,246576,246577,246580,246580,246583,246589,246589,246591,246591,246597,246599,246599,246601,246602,246603,246604,246607,246611,246613,246618,246618,246621,246627,246633,246636,246638,246643,246643,246644,246651,246656,246663,246670,246675,246675,246680,246681,246686,246695,246695,246699,246703,246710,246724,246724,246729,246749,246749,246769,246774,246774,246774,246774,246774,246774,246774,246774,246774,246774,246774,246779,246786,246792,246794,246795,246795,246795,246803,246803,246807,246822,246822,246822,246822,246823,246824,246826,246827,246834,246834,246834,246834,246834,246839,246852,246853,246867,246868,246868,246868,246890,246896,246905,246912,246919,246919,246923,246928,246928,246928,246934,246949,246954,246957,246963,246963,246964,246964,246964,246969,246972,246982,246983,246987,246994,246995,246996,247004,247005,247005,247006,247006,247006,247006,247006,247006,247006,247006,247006,247007,247009,247010,247011,247011,247012,247016,247021,247021,247021,247021,247021,247021,247021,247033,247033,247034,247035,247041,247041,247041,247041,247048,247048,247049,247060,247060,247060,247060,247063,247064,247076,247079,247088,247092,247092,247093,247095,247102,247105,247108,247113,247113,247114,247114,247114,247115,247127,247129,247129,247131,247131,247132,247138,247141,247143,247143,247147,247149,247152,247152,247153,247159,247160,247171,247179,247180,247180,247180,247184,247195,247195,247197,247202,247203,247212,247221,247230,247230,247246,247248,247250,247250,247268,247284,247304,247322,247328,247332,247332,247332,247333,247345,247345,247345,247348,247370,247370,247372,247372,247373,247376,247376,247380,247384,247396,247409,247412,247413,247413,247418,247420,247421,247421,247429,247434,247438,247438,247442,247442,247442,247442,247449,247479,247483,247485,247487,247490,247491,247491,247491,247496,247502,247508,247508,247512,247517,247517,247518,247519,247521,247521,247524,247524,247524,247524,247524,247524,247525,247525,247525,247525,247529,247531,247533,247554,247566,247567,247580,247581,247583,247586,247589,247593,247600,247601,247601,247601,247612,247617,247621,247622,247626,247628,247639,247640,247687,247687,247695,247695,247697,247698,247705,247710,247715,247715,247715,247723,247726,247732,247738,247738,247741,247747,247749,247755,247756,247762,247762,247762,247765,247770,247777,247777,247777,247780,247780,247780,247780,247780,247780,247780,247780,247780,247789,247792,247792,247799,247801,247803,247806,247807,247816,247829,247830,247830,247830,247830,247838,247838,247848,247849,247851,247851,247858,247863,247869,247871,247875,247876,247876,247876,247876,247876,247876,247876,247876,247876,247876,247876,247881,247882,247882,247882,247885,247886,247895,247899,247900,247901,247901,247903,247904,247904,247904,247904,247911,247916,247916,247917,247919,247924,247924,247944,247945,247946,247946,247950,247950,247950,247950,247950,247950,247950,247950,247951,247951,247953,247953,247953,247953,247953,247953,247953,247955,247968,247969,247971,247971,247971,247971,247971,247972,247973,247977,247977,247977,247978,247980,247981,247984,247985,247988,247988,247998,247998,247999,247999,247999,248004,248007,248024,248026,248029,248029,248031,248033,248033,248048,248053,248057,248073,248073,248073,248073,248073,248073,248073,248073,248077,248080,248080,248081,248083,248083,248084,248084,248084,248084,248084,248085,248089,248091,248091,248091,248095,248096,248102,248106,248106,248107,248117,248119,248127,248133,248134,248134,248134,248138,248148,248166,248169,248171,248171,248178,248178,248179,248180,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248181,248184,248187,248187,248187,248188,248192,248192,248197,248199,248203,248204,248209,248222,248232,248232,248235,248238,248240,248242,248244,248245,248245,248245,248245,248248,248249,248249,248253,248253,248258,248261,248261,248264,248269,248273,248276,248276,248276,248276,248290,248290,248294,248296,248306,248306,248307,248307,248307,248307,248307,248307,248310,248310,248310,248310,248310,248310,248310,248311,248311,248311,248311,248311,248313,248313,248313,248313,248317,248317,248325,248325,248325,248325,248330,248330,248340,248344,248348,248350,248352,248352,248352,248353,248353,248353,248353,248357,248362,248362,248362,248362,248362,248363,248366,248368,248368,248374,248374,248377,248381,248381,248381,248386,248387,248391,248393,248393,248394,248394,248394,248397,248400,248400,248400,248403,248404,248409,248409,248409,248412,248416,248424,248424,248424,248424,248425,248425,248426,248428,248428,248429,248429,248430,248439,248440,248450,248453,248453,248453,248453,248455,248455,248464,248467,248471,248472,248473,248473,248475,248475,248475,248478,248480,248489,248493,248493,248494,248503,248512,248514,248516,248516,248520,248520,248520,248520,248520,248520,248520,248523,248523,248523,248523,248523,248523,248523,248523,248523,248524,248524,248524,248524,248524,248525,248526,248526,248526,248529,248529,248529,248529,248529,248529,248529,248531,248531,248532,248532,248534,248535,248538,248543,248543,248544,248544,248545,248546,248548,248548,248548,248548,248553,248554,248554,248557,248559,248565,248565,248565,248567,248567,248573,248580,248580,248588,248591,248591,248591,248591,248598,248599,248600,248600,248603,248605,248606,248606,248606,248606,248614,248621,248623,248627,248629,248636,248636,248636,248641,248642,248642,248649,248660,248660,248660,248665,248667,248669,248672,248673,248673,248673,248673,248673,248675,248685,248685,248689,248689,248689,248691,248693,248693,248693,248693,248695,248695,248696,248704,248713,248720,248735,248735,248735,248736,248737,248739,248741,248746,248747,248752,248752,248761,248762,248763,248764,248766,248767,248767,248767,248768,248771,248776,248784,248785,248802,248815,248815,248821,248821,248826,248830,248834,248838,248838,248853,248857,248860,248862,248867,248870,248878,248878,248882,248900,248902,248903,248903,248913,248918,248924,248937,248949,248956,248959,248964,248964,248967,248967,248967,248967,248967,248967,248970,248970,248971,248973,248973,248977,248978,248983,248986,248986,248986,248999,249001,249002,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249005,249010,249011,249020,249023,249030,249036,249040,249047,249060,249063,249077,249077,249077,249077,249077,249077,249080,249080,249080,249080,249080,249082,249083,249083,249090,249090,249092,249092,249093,249093,249093,249094,249094,249094,249094,249094,249094,249094,249097,249101,249101,249101,249101,249101,249101,249101,249101,249108,249112,249112,249112,249114,249116,249124,249129,249129,249129,249129,249129,249131,249133,249134,249135,249137,249139,249139,249140,249142,249144,249146,249147,249148,249148,249148,249151,249151,249151,249153,249156,249157,249157,249158,249168,249168,249168,249168,249168,249168,249168,249169,249193,249194,249194,249204,249206,249209,249209,249211,249216,249216,249216,249216,249222,249235,249235,249247,249247,249247,249247,249248,249248,249248,249248,249248,249248,249248,249248,249248,249248,249248,249248,249248,249252,249253,249253,249259,249268,249268,249268,249268,249268,249285,249287,249287,249291,249292,249293,249297,249311,249311,249321,249321,249321,249321,249321,249321,249321,249321,249326,249328,249331,249333,249333,249333,249333,249337,249337,249337,249337,249337,249351,249362,249367,249369,249371,249372,249372,249372,249373,249373,249373,249373,249374,249376,249377,249377,249380,249384,249386,249390,249394,249394,249404,249406,249407,249414,249414,249416,249416,249420,249422,249426,249426,249429,249430,249432,249432,249444,249447,249447,249450,249451,249454,249458,249462,249463,249474,249474,249474,249475,249475,249475,249475,249475,249476,249476,249476,249476,249477,249478,249492,249497,249499,249499,249500,249513,249513,249513,249517,249519,249522,249528,249536,249536,249541,249541,249546,249548,249548,249550,249555,249569,249569,249569,249569,249574,249574,249574,249574,249578,249579,249586,249586,249593,249595,249601,249601,249601,249601,249604,249604,249604,249608,249608,249620,249623,249636,249636,249636,249638,249638,249645,249655,249657,249657,249657,249658,249658,249658,249658,249658,249658,249658,249662,249662,249663,249669,249669,249685,249685,249697,249699,249699,249702,249707,249707,249724,249724,249728,249729,249732,249732,249733,249734,249736,249736,249742,249749,249749,249767,249768,249770,249770,249770,249776,249777,249777,249782,249787,249788,249788,249788,249793,249794,249809,249814,249818,249827,249830,249833,249833,249839,249853,249864,249864,249866,249866,249877,249882,249893,249904,249904,249918,249918,249918,249923,249949,249958,249960,249961,249965,249965,249965,249970,249970,249974,249975,249977,249977,249980,249985,249985,249987,249991,250002,250005,250008,250020,250025,250030,250030,250030,250031,250031,250031,250035,250035,250036,250038,250043,250043,250045,250049,250049,250049,250052,250055,250055,250070,250076,250077,250079,250082,250083,250085,250085,250087,250088,250093,250093,250093,250093,250095,250116,250123,250130,250131,250132,250135,250136,250136,250137,250146,250146,250146,250147,250147,250147,250154,250158,250158,250158,250159,250160,250160,250160,250160,250161,250161,250161,250164,250165,250177,250177,250178,250189,250194,250198,250202,250204,250220,250223,250230,250241,250251,250256,250257,250258,250259,250259,250265,250268,250268,250271,250276,250279,250280,250284,250284,250287,250288,250288,250296,250299,250299,250300,250301,250302,250302,250309,250315,250325,250331,250332,250332,250332,250334,250337,250338,250351,250353,250359,250359,250359,250359,250362,250362,250369,250372,250372,250372,250376,250377,250379,250386,250386,250386,250399,250399,250406,250428,250447,250452,250452,250452,250455,250455,250472,250472,250472,250472,250472,250473,250475,250476,250476,250483,250484,250486,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250488,250496,250497,250497,250497,250503,250503,250508,250512,250512,250513,250513,250524,250524,250524,250524,250524,250524,250529,250534,250539,250540,250547,250549,250550,250552,250552,250561,250568,250571,250573,250573,250574,250576,250576,250585,250595,250605,250606,250613,250613,250613,250613,250613,250615,250617,250617,250617,250619,250628,250628,250633,250644,250644,250654,250654,250654,250671,250679,250680,250680,250706,250708,250711,250712,250715,250715,250724,250743,250747,250749,250768,250783,250784,250786,250786,250786,250796,250796,250802,250804,250804,250813,250813,250821,250821,250834,250837,250837,250837,250837,250837,250838,250838,250841,250859,250863,250866,250872,250874,250877,250889,250893,250893,250894,250898,250904,250904,250906,250907,250908,250915,250915,250916,250920,250920,250920,250922,250922,250922,250922,250923,250924,250924,250932,250935,250935,250935,250935,250935,250935,250935,250938,250938,250938,250940,250940,250942,250944,250944,250945,250946,250948,250962,250962,250971,250975,250975,250975,250975,250975,250977,250977,250980,250991,250992,250997,250999,250999,251018,251021,251025,251025,251040,251049,251049,251056,251062,251065,251067,251067,251069,251070,251074,251078,251082,251082,251082,251086,251089,251089,251091,251092,251092,251093,251093,251093,251094,251098,251099,251104,251105,251108,251116,251116,251116,251116,251117,251118,251120,251120,251120,251120,251120,251122,251128,251134,251137,251142,251142,251142,251142,251142,251142,251142,251144,251147,251149,251151,251154,251154,251161,251162,251167,251169,251186,251187,251189,251190,251191,251191,251191,251191,251203,251212,251212,251218,251220,251225,251225,251225,251231,251241,251242,251244,251246,251248,251254,251267,251273,251273,251279,251279,251279,251282,251282,251283,251285,251285,251295,251297,251297,251297,251297,251297,251300,251300,251300,251301,251301,251301,251304,251317,251318,251318,251318,251322,251329,251332,251334,251340,251346,251351,251353,251353,251354,251355,251363,251364,251370,251371,251374,251377,251381,251381,251391,251392,251394,251406,251412,251417,251418,251418,251418,251428,251432,251435,251440,251441,251444,251452,251456,251458,251459,251459,251463,251469,251475,251475,251485,251485,251485,251490,251494,251497,251497,251497,251498,251499,251527,251528,251530,251531,251542,251542,251543,251550,251550,251550,251550,251556,251570,251570,251571,251574,251574,251575,251577,251578,251580,251584,251584,251591,251591,251591,251603,251604,251621,251626,251626,251626,251626,251629,251629,251633,251635,251645,251646,251648,251655,251657,251659,251662,251665,251665,251669,251675,251676,251677,251677,251677,251681,251681,251681,251681,251683,251693,251693,251693,251693,251693,251694,251694,251694,251695,251695,251697,251697,251697,251705,251705,251706,251706,251708,251708,251708,251710,251713,251714,251718,251721,251723,251723,251729,251748,251748,251748,251750,251750,251750,251750,251752,251752,251753,251758,251763,251771,251776,251779,251784,251790,251793,251793,251801,251802,251803,251804,251804,251806,251806,251814,251819,251832,251832,251832,251834,251837,251838,251844,251852,251852,251852,251852,251852,251852,251852,251852,251852,251852,251852,251852,251852,251852,251859,251859,251861,251866,251866,251866,251866,251866,251866,251866,251866,251866,251866,251866,251866,251866,251866,251868,251873,251876,251883,251901,251905,251906,251908,251915,251915,251922,251923,251924,251924,251924,251924,251924,251924,251924,251924,251924,251924,251924,251924,251927,251927,251939,251939,251939,251939,251940,251945,251950,251952,251953,251957,251957,251957,251961,251961,251961,251961,251962,251967,251967,251967,251967,251967,251967,251967,251967,251967,251969,251977,251982,251982,251986,251988,251988,251988,251988,251988,251988,251988,251988,251992,251993,251996,251996,251997,251997,251997,251997,251999,251999,252000,252000,252002,252003,252004,252004,252007,252007,252010,252011,252012,252014,252014,252014,252014,252014,252014,252019,252019,252023,252028,252032,252039,252039,252039,252039,252042,252046,252046,252046,252048,252052,252057,252058,252062,252068,252076,252077,252077,252077,252077,252080,252080,252081,252081,252081,252081,252081,252082,252086,252086,252090,252090,252099,252105,252106,252117,252118,252135,252135,252136,252136,252138,252141,252141,252145,252145,252149,252151,252153,252153,252161,252161,252163,252164,252169,252169,252170,252170,252171,252172,252175,252175,252178,252179,252180,252180,252181,252188,252191,252194,252204,252205,252207,252223,252223,252232,252235,252236,252245,252245,252245,252255,252261,252270,252270,252280,252292,252294,252301,252308,252330,252331,252333,252333,252333,252333,252343,252367,252368,252369,252371,252372,252372,252387,252395,252397,252397,252400,252400,252400,252400,252400,252400,252400,252400,252400,252400,252401,252401,252401,252411,252413,252414,252414,252418,252420,252422,252422,252422,252422,252422,252422,252422,252422,252422,252433,252433,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252434,252438,252439,252439,252439,252439,252439,252439,252439,252439,252439,252439,252442,252443,252443,252444,252444,252444,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252445,252446,252447,252447,252448,252449,252450,252471,252473,252473,252473,252473,252473,252473,252473,252473,252473,252474,252475,252481,252482,252485,252485,252485,252493,252508,252509,252510,252511,252513,252515,252515,252516,252516,252516,252517,252519,252519,252519,252519,252519,252519,252520,252520,252521,252521,252521,252521,252521,252521,252521,252521,252522,252522,252523,252523,252523,252523,252523,252523,252523,252523,252524,252524,252524,252525,252525,252527,252527,252528,252529,252529,252530,252532,252532,252534,252536,252537,252538,252539,252540,252540,252540,252540,252540,252540,252540,252540,252540,252540,252540,252540,252540,252540,252540,252540,252541,252541,252541,252541,252541,252541,252541,252541,252541,252541,252541,252541,252541,252541,252541,252541,252542,252543,252545,252545,252545,252545,252545,252545,252545,252547,252548,252550,252550,252557,252564,252564,252564,252564,252564,252564,252564,252564,252564,252564,252564,252579,252582,252589,252593,252603,252605,252614,252616,252625,252626,252628,252628,252628,252628,252628,252630,252635,252637,252637,252641,252643,252643,252644,252648,252651,252659,252663,252665,252671,252672,252673,252682,252684,252684,252684,252687,252687,252687,252687,252696,252698,252712,252716,252719,252719,252719,252719,252721,252721,252731,252738,252741,252744,252748,252750,252753,252754,252754,252760,252775,252775,252791,252794,252794,252794,252794,252796,252797,252802,252803,252811,252811,252811,252811,252811,252811,252811,252811,252811,252811,252811,252811,252821,252825,252827,252830,252833,252835,252835,252837,252842,252843,252843,252843,252844,252848,252848,252848,252851,252853,252860,252860,252861,252863,252873,252874,252874,252874,252874,252874,252882,252882,252885,252900,252900,252918,252918,252928,252930,252937,252939,252939,252945,252947,252948,252948,252948,252956,252956,252962,252962,252966,252966,252981,252993,253005,253024,253032,253032,253040,253040,253044,253048,253052,253053,253054,253054,253057,253068,253068,253068,253068,253068,253068,253068,253068,253069,253073,253074,253075,253075,253078,253085,253087,253090,253105,253108,253119,253120,253124,253131,253131,253132,253132,253132,253132,253132,253132,253132,253133,253135,253139,253143,253143,253152,253158,253165,253169,253175,253175,253178,253181,253181,253182,253182,253182,253182,253187,253189,253189,253191,253192,253194,253198,253200,253209,253222,253222,253223,253226,253226,253234,253234,253238,253238,253242,253242,253243,253243,253243,253243,253250,253250,253251,253251,253252,253256,253259,253260,253270,253271,253272,253273,253273,253281,253281,253281,253286,253292,253295,253297,253297,253297,253297,253299,253299,253306,253308,253309,253311,253312,253312,253312,253312,253312,253312,253312,253314,253314,253314,253314,253314,253314,253319,253319,253319,253319,253319,253320,253320,253320,253320,253320,253320,253320,253320,253321,253321,253321,253321,253321,253323,253323,253323,253324,253325,253325,253326,253326,253339,253341,253343,253349,253349,253351,253352,253369,253371,253389,253393,253401,253416,253418,253421,253421,253423,253431,253435,253435,253435,253436,253436,253436,253438,253438,253438,253438,253439,253439,253439,253439,253439,253439,253439,253442,253446,253451,253453,253453,253453,253453,253454,253454,253455,253455,253455,253455,253455,253459,253459,253459,253464,253465,253465,253476,253479,253480,253486,253488,253488,253489,253489,253492,253492,253494,253494,253494,253495,253496,253507,253511,253514,253515,253515,253517,253517,253518,253518,253519,253520,253522,253526,253530,253534,253534,253534,253536,253536,253542,253546,253548,253548,253548,253553,253558,253562,253564,253564,253564,253564,253564,253564,253565,253566,253566,253567,253567,253567,253567,253568,253569,253570,253570,253570,253570,253585,253588,253588,253591,253591,253593,253595,253595,253595,253597,253597,253597,253599,253599,253599,253599,253599,253601,253608,253609,253610,253614,253618,253623,253623,253627,253627,253630,253630,253632,253633,253633,253634,253634,253634,253634,253634,253635,253635,253636,253638,253640,253646,253646,253655,253657,253657,253658,253659,253659,253663,253671,253677,253679,253679,253681,253692,253699,253699,253699,253699,253699,253700,253700,253700,253700,253702,253702,253702,253705,253710,253714,253717,253718,253722,253725,253731,253732,253754,253767,253767,253767,253772,253776,253777,253777,253777,253777,253787,253799,253805,253805,253805,253818,253818,253835,253840,253846,253846,253852,253858,253858,253868,253869,253874,253874,253874,253874,253874,253874,253874,253874,253874,253876,253878,253880,253884,253886,253889,253889,253896,253896,253896,253896,253896,253896,253896,253896,253910,253911,253913,253916,253917,253917,253922,253925,253927,253928,253936,253936,253936,253936,253939,253940,253940,253942,253947,253950,253951,253952,253952,253956,253956,253961,253966,253967,253976,253976,253977,253978,253987,253988,253988,253988,253995,254001,254005,254005,254005,254005,254005,254007,254015,254015,254015,254015,254015,254015,254015,254017,254025,254028,254030,254033,254036,254038,254038,254039,254041,254041,254043,254048,254049,254052,254054,254061,254066,254067,254069,254070,254075,254080,254080,254081,254081,254083,254083,254083,254083,254083,254084,254086,254088,254090,254091,254092,254096,254100,254106,254107,254109,254110,254113,254113,254117,254123,254124,254126,254131,254131,254131,254131,254133,254134,254134,254136,254139,254140,254140,254140,254141,254141,254141,254142,254143,254143,254144,254144,254144,254144,254144,254144,254144,254144,254144,254144,254145,254145,254147,254148,254148,254148,254148,254150,254150,254150,254150,254151,254151,254156,254156,254158,254162,254162,254162,254162,254162,254162,254163,254163,254170,254172,254174,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254175,254177,254184,254186,254186,254193,254194,254196,254199,254204,254206,254209,254214,254219,254220,254221,254222,254224,254224,254225,254226,254235,254238,254239,254241,254242,254243,254244,254244,254244,254244,254244,254244,254244,254244,254244,254244,254244,254244,254244,254245,254251,254252,254255,254268,254270,254270,254270,254270,254270,254270,254270,254270,254270,254270,254270,254272,254273,254275,254275,254276,254278,254278,254278,254278,254278,254278,254278,254278,254278,254278,254278,254288,254290,254293,254298,254298,254298,254298,254298,254298,254298,254302,254302,254302,254303,254303,254311,254312,254312,254313,254314,254315,254323,254329,254329,254332,254332,254334,254338,254340,254340,254344,254347,254349,254351,254352,254352,254353,254364,254364,254365,254367,254367,254373,254373,254376,254384,254390,254390,254390,254391,254393,254393,254395,254398,254398,254398,254408,254414,254414,254415,254418,254418,254421,254421,254421,254422,254423,254424,254427,254431,254431,254433,254435,254435,254443,254443,254444,254449,254450,254452,254453,254455,254455,254457,254458,254461,254462,254462,254463,254468,254468,254468,254471,254474,254476,254478,254479,254480,254482,254486,254490,254493,254493,254494,254495,254495,254496,254497,254497,254497,254497,254503,254506,254508,254508,254508,254509,254509,254513,254519,254520,254521,254521,254522,254522,254523,254528,254528,254528,254531,254534,254534,254534,254536,254541,254547,254551,254555,254556,254559,254566,254566,254569,254570,254579,254580,254580,254580,254580,254583,254593,254598,254599,254603,254607,254608,254616,254620,254622,254628,254632,254632,254635,254642,254652,254655,254656,254657,254657,254657,254659,254664,254666,254666,254670,254676,254676,254676,254676,254676,254676,254676,254676,254676,254676,254678,254679,254682,254690,254697,254705,254715,254721,254722,254723,254727,254731,254733,254738,254741,254747,254758,254758,254758,254758,254760,254762,254762,254773,254773,254773,254778,254792,254793,254794,254794,254794,254794,254795,254796,254798,254799,254804,254805,254805,254806,254806,254806,254806,254806,254806,254806,254810,254826,254830,254831,254836,254836,254836,254840,254840,254840,254840,254841,254854,254860,254862,254862,254862,254865,254867,254870,254877,254882,254884,254888,254889,254891,254891,254891,254894,254905,254905,254905,254905,254905,254905,254905,254905,254907,254910,254914,254914,254915,254916,254916,254930,254944,254944,254950,254959,254969,254975,254976,254983,254989,254992,254994,254995,255005,255005,255005,255005,255005,255005,255005,255005,255013,255015,255020,255022,255022,255022,255022,255022,255022,255022,255030,255033,255033,255034,255035,255036,255037,255054,255060,255063,255063,255063,255063,255063,255065,255067,255070,255079,255080,255088,255089,255094,255095,255099,255103,255103,255103,255103,255108,255108,255108,255112,255113,255118,255126,255138,255138,255141,255145,255151,255159,255159,255159,255159,255159,255159,255159,255159,255159,255159,255159,255159,255159,255159,255159,255159,255160,255171,255195,255197,255199,255202,255205,255205,255208,255209,255209,255209,255209,255209,255209,255209,255209,255218,255218,255219,255223,255223,255226,255227,255229,255230,255230,255230,255230,255230,255230,255230,255231,255232,255232,255232,255238,255242,255243,255245,255263,255265,255274,255275,255275,255278,255283,255283,255283,255295,255295,255298,255300,255306,255309,255310,255321,255322,255322,255322,255329,255330,255330,255330,255337,255338,255342,255342,255342,255342,255355,255355,255356,255361,255361,255365,255368,255368,255370,255372,255378,255378,255382,255386,255386,255386,255393,255396,255396,255397,255397,255401,255408,255408,255411,255421,255423,255434,255434,255448,255458,255460,255471,255471,255471,255472,255481,255483,255488,255493,255494,255494,255494,255496,255497,255500,255501,255504,255505,255510,255511,255535,255539,255545,255548,255556,255558,255558,255563,255567,255574,255580,255583,255585,255588,255588,255589,255589,255589,255589,255589,255589,255590,255595,255603,255606,255610,255610,255613,255613,255615,255615,255615,255615,255615,255615,255615,255615,255615,255629,255634,255634,255643,255644,255656,255660,255661,255661,255663,255679,255682,255683,255691,255691,255691,255691,255697,255703,255703,255703,255704,255704,255704,255711,255712,255720,255725,255726,255726,255726,255728,255735,255736,255743,255749,255753,255758,255767,255768,255768,255777,255812,255818,255818,255818,255819,255819,255819,255819,255819,255820,255826,255826,255826,255826,255826,255827,255827,255827,255835,255843,255846,255848,255848,255848,255848,255848,255848,255848,255854,255854,255854,255858,255871,255877,255884,255899,255915,255915,255923,255938,255942,255954,255955,255955,255955,255957,255962,255962,255968,255968,255969,255969,255971,255971,255971,255972,255977,255985,255985,255985,255987,255992,255998,256006,256009,256011,256016,256016,256019,256034,256037,256037,256049,256050,256053,256060,256061,256064,256064,256065,256071,256082,256089,256094,256102,256107,256110,256110,256110,256110,256110,256111,256114,256114,256116,256120,256120,256133,256134,256139,256141,256141,256146,256149,256149,256154,256159,256166,256168,256179,256182,256183,256186,256190,256197,256197,256197,256204,256204,256212,256212,256212,256213,256213,256228,256229,256233,256236,256237,256237,256240,256251,256255,256262,256270,256278,256288,256290,256296,256296,256297,256316,256316,256321,256321,256324,256324,256324,256327,256327,256327,256328,256328,256328,256328,256328,256333,256352,256352,256352,256366,256366,256366,256370,256373,256373,256374,256374,256374,256374,256375,256375,256375,256377,256379,256379,256380,256380,256381,256386,256387,256392,256392,256417,256418,256424,256429,256433,256435,256440,256443,256449,256450,256450,256450,256450,256454,256455,256458,256462,256463,256466,256470,256473,256475,256488,256500,256514,256514,256514,256517,256522,256522,256530,256530,256533,256539,256550,256551,256551,256551,256553,256556,256556,256556,256559,256560,256560,256560,256564,256574,256574,256574,256577,256582,256583,256595,256608,256613,256617,256630,256643,256645,256649,256653,256662,256668,256670,256674,256674,256679,256683,256683,256683,256683,256683,256683,256683,256683,256683,256683,256683,256683,256683,256683,256684,256684,256685,256685,256687,256687,256688,256690,256690,256690,256691,256691,256701,256701,256702,256703,256705,256705,256705,256706,256710,256710,256713,256717,256718,256718,256718,256718,256727,256735,256735,256743,256743,256743,256744,256747,256759,256769,256784,256784,256784,256784,256785,256791,256793,256793,256812,256812,256812,256813,256813,256813,256813,256813,256813,256813,256813,256813,256813,256815,256815,256817,256820,256831,256834,256834,256834,256837,256839,256839,256840,256841,256844,256844,256844,256844,256846,256847,256847,256848,256856,256857,256861,256863,256863,256863,256864,256865,256870,256875,256875,256875,256876,256882,256887,256887,256887,256888,256893,256893,256894,256901,256906,256912,256921,256922,256922,256926,256926,256929,256937,256938,256943,256943,256943,256943,256944,256945,256955,256965,256965,256965,256965,256965,256968,256972,256979,256982,256986,256986,256986,257001,257008,257015,257017,257018,257026,257026,257026,257030,257032,257037,257038,257038,257038,257038,257038,257040,257046,257050,257063,257073,257077,257079,257084,257087,257093,257096,257118,257118,257118,257123,257127,257127,257133,257140,257143,257144,257144,257152,257152,257154,257158,257158,257158,257160,257160,257161,257161,257166,257170,257173,257175,257175,257175,257176,257182,257184,257187,257189,257195,257195,257204,257204,257205,257223,257223,257229,257239,257242,257244,257247,257253,257263,257268,257268,257268,257269,257269,257281,257283,257284,257284,257284,257284,257284,257284,257284,257284,257284,257284,257289,257295,257295,257300,257300,257307,257308,257315,257315,257318,257318,257318,257318,257318,257318,257319,257325,257328,257328,257332,257341,257343,257344,257350,257350,257351,257351,257351,257358,257360,257361,257361,257361,257361,257362,257363,257363,257365,257365,257370,257372,257372,257374,257381,257381,257381,257386,257399,257399,257399,257409,257410,257410,257418,257422,257424,257424,257424,257438,257441,257441,257447,257453,257453,257453,257453,257453,257454,257456,257456,257456,257457,257457,257457,257457,257457,257457,257459,257459,257459,257459,257459,257459,257459,257459,257459,257461,257461,257466,257468,257470,257473,257473,257473,257473,257473,257474,257479,257479,257479,257479,257479,257486,257490,257490,257490,257490,257495,257500,257508,257510,257523,257529,257529,257529,257535,257535,257542,257543,257544,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257555,257568,257569,257572,257572,257577,257577,257577,257577,257580,257580,257580,257585,257587,257590,257608,257614,257632,257632,257635,257641,257643,257644,257644,257644,257646,257651,257653,257658,257660,257670,257671,257671,257676,257678,257678,257678,257680,257680,257690,257690,257690,257698,257698,257703,257706,257706,257708,257708,257708,257708,257714,257715,257715,257715,257715,257715,257715,257717,257717,257717,257718,257727,257729,257730,257738,257740,257740,257740,257740,257744,257744,257744,257748,257749,257749,257749,257749,257749,257750,257752,257755,257756,257759,257760,257761,257763,257765,257772,257773,257773,257773,257774,257779,257782,257799,257799,257801,257802,257815,257843,257843,257843,257843,257843,257848,257848,257848,257848,257860,257860,257867,257869,257869,257872,257872,257877,257879,257880,257884,257913,257918,257926,257927,257929,257931,257931,257938,257939,257949,257950,257952,257952,257952,257952,257952,257952,257952,257952,257952,257952,257952,257953,257957,257957,257957,257964,257969,257969,257969,257969,257976,257977,257981,257982,257982,257982,257985,257994,257999,258000,258006,258020,258020,258023,258030,258034,258037,258037,258042,258053,258056,258056,258056,258057,258066,258068,258068,258076,258080,258081,258084,258091,258114,258115,258115,258116,258121,258121,258137,258142,258144,258148,258150,258150,258159,258162,258165,258165,258165,258187,258189,258190,258190,258192,258192,258192,258197,258197,258197,258202,258207,258210,258216,258216,258218,258219,258224,258224,258224,258236,258242,258247,258248,258254,258254,258254,258255,258257,258259,258259,258259,258259,258267,258267,258267,258267,258267,258267,258267,258267,258267,258269,258269,258269,258280,258283,258283,258283,258286,258297,258312,258312,258321,258329,258332,258342,258343,258343,258352,258352,258354,258357,258369,258385,258385,258390,258390,258396,258396,258396,258396,258408,258408,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258409,258410,258410,258410,258410,258410,258410,258410,258410,258410,258410,258410,258411,258411,258411,258411,258411,258411,258411,258411,258412,258412,258412,258412,258412,258413,258413,258413,258413,258413,258415,258416,258418,258421,258421,258421,258421,258421,258422,258422,258427,258428,258429,258429,258430,258434,258434,258435,258435,258435,258436,258436,258436,258437,258437,258439,258440,258440,258440,258440,258440,258440,258441,258441,258441,258441,258441,258441,258441,258441,258442,258442,258442,258442,258442,258443,258443,258443,258444,258444,258444,258444,258444,258444,258445,258445,258445,258445,258445,258445,258445,258445,258445,258445,258446,258446,258446,258446,258446,258446,258446,258446,258446,258446,258446,258446,258451,258452,258452,258452,258453,258454,258458,258459,258459,258460,258461,258463,258463,258463,258466,258467,258468,258469,258474,258474,258478,258479,258481,258481,258481,258481,258486,258486,258486,258486,258486,258491,258492,258497,258499,258507,258507,258507,258509,258509,258512,258512,258512,258512,258512,258513,258515,258519,258519,258520,258520,258524,258525,258529,258529,258530,258534,258536,258537,258537,258537,258537,258554,258554,258554,258556,258557,258557,258562,258569,258576,258578,258578,258582,258591,258598,258598,258603,258603,258604,258606,258611,258614,258614,258617,258617,258617,258618,258619,258632,258633,258634,258637,258638,258638,258643,258643,258643,258647,258648,258653,258656,258658,258659,258659,258661,258661,258675,258679,258679,258680,258701,258713,258715,258715,258715,258715,258715,258716,258723,258724,258726,258741,258742,258745,258746,258749,258754,258756,258757,258757,258757,258760,258765,258766,258766,258769,258772,258772,258785,258787,258788,258788,258788,258797,258798,258798,258798,258806,258806,258806,258810,258811,258826,258829,258831,258836,258843,258843,258844,258848,258851,258851,258851,258851,258851,258861,258864,258865,258865,258873,258876,258876,258881,258896,258896,258902,258910,258910,258920,258920,258920,258920,258925,258927,258931,258932,258932,258934,258941,258941,258943,258954,258954,258962,258964,258965,258965,258966,258982,258982,258990,258993,258993,258996,259001,259009,259009,259016,259019,259019,259021,259022,259027,259032,259035,259037,259037,259037,259042,259047,259051,259051,259051,259051,259052,259054,259054,259057,259057,259057,259060,259067,259075,259077,259077,259077,259077,259077,259077,259077,259090,259090,259093,259095,259106,259109,259113,259114,259114,259120,259120,259120,259120,259123,259123,259125,259127,259127,259127,259129,259129,259129,259129,259129,259136,259138,259139,259139,259139,259139,259139,259149,259152,259153,259153,259155,259159,259160,259160,259169,259169,259177,259178,259179,259182,259196,259208,259209,259210,259210,259210,259214,259216,259225,259234,259234,259245,259250,259254,259254,259259,259259,259262,259269,259273,259274,259277,259278,259278,259278,259280,259280,259283,259283,259284,259287,259287,259287,259288,259297,259297,259297,259297,259299,259299,259299,259299,259299,259301,259302,259323,259324,259327,259327,259329,259333,259333,259333,259339,259341,259341,259341,259344,259345,259352,259353,259355,259357,259358,259359,259367,259367,259374,259374,259379,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259380,259388,259389,259394,259395,259403,259413,259413,259414,259417,259417,259418,259419,259436,259436,259438,259440,259446,259446,259448,259448,259448,259449,259449,259450,259451,259451,259451,259455,259457,259459,259463,259466,259466,259466,259466,259467,259467,259476,259483,259495,259498,259499,259523,259539,259540,259544,259545,259545,259551,259552,259564,259574,259574,259596,259600,259600,259600,259602,259602,259602,259603,259608,259608,259608,259608,259611,259611,259616,259617,259620,259620,259620,259621,259626,259631,259631,259631,259637,259639,259642,259642,259644,259646,259651,259652,259658,259667,259668,259668,259668,259670,259673,259674,259689,259696,259696,259696,259702,259704,259714,259722,259723,259726,259738,259738,259749,259753,259754,259762,259768,259768,259772,259772,259779,259786,259796,259804,259814,259819,259820,259822,259822,259827,259830,259830,259831,259835,259837,259837,259841,259847,259847,259847,259853,259853,259854,259866,259868,259869,259883,259883,259885,259886,259887,259889,259889,259895,259895,259895,259895,259895,259895,259895,259895,259895,259895,259901,259901,259902,259903,259903,259906,259907,259909,259909,259914,259914,259914,259918,259918,259919,259931,259934,259945,259946,259946,259953,259958,259965,259966,259967,259970,259970,259970,259970,259974,259974,259978,259978,259978,259979,259987,259990,259992,259992,259992,259992,259992,259992,259992,259992,259992,259992,259992,259992,259995,259997,259997,259999,260002,260002,260002,260007,260009,260009,260013,260029,260037,260037,260037,260047,260048,260051,260051,260055,260055,260055,260068,260068,260070,260074,260077,260077,260077,260078,260079,260083,260084,260090,260092,260105,260107,260114,260114,260117,260121,260121,260121,260123,260127,260127,260130,260134,260134,260138,260138,260140,260140,260140,260143,260143,260146,260146,260152,260156,260161,260164,260168,260169,260169,260177,260185,260189,260192,260192,260192,260192,260192,260192,260192,260196,260197,260197,260198,260198,260198,260198,260198,260198,260198,260198,260200,260205,260207,260210,260210,260210,260210,260218,260218,260218,260218,260219,260222,260223,260223,260223,260226,260229,260230,260230,260230,260230,260230,260230,260231,260232,260235,260235,260242,260247,260247,260247,260247,260248,260250,260250,260253,260253,260268,260268,260272,260275,260276,260278,260279,260279,260280,260280,260280,260286,260287,260287,260290,260292,260292,260296,260296,260299,260301,260312,260313,260315,260319,260319,260326,260330,260330,260331,260331,260332,260334,260334,260340,260340,260340,260340,260340,260341,260341,260342,260346,260346,260346,260353,260357,260365,260367,260367,260367,260367,260369,260370,260371,260372,260373,260377,260377,260379,260381,260381,260381,260383,260397,260403,260404,260404,260408,260408,260409,260411,260411,260413,260413,260416,260416,260417,260417,260417,260417,260419,260424,260430,260430,260435,260437,260455,260456,260457,260468,260470,260475,260475,260475,260475,260478,260478,260478,260478,260484,260486,260487,260488,260498,260502,260504,260505,260505,260508,260508,260508,260508,260508,260508,260508,260510,260510,260524,260526,260536,260536,260536,260541,260556,260560,260561,260561,260564,260569,260569,260569,260576,260581,260586,260596,260603,260603,260603,260603,260603,260603,260610,260613,260613,260620,260620,260620,260620,260620,260621,260621,260621,260621,260631,260632,260652,260654,260656,260660,260660,260660,260672,260678,260682,260683,260683,260688,260688,260696,260698,260703,260712,260715,260717,260723,260725,260725,260726,260729,260734,260734,260754,260760,260778,260779,260781,260782,260787,260800,260810,260812,260812,260816,260816,260816,260816,260816,260822,260824,260824,260824,260824,260824,260824,260824,260824,260824,260825,260832,260840,260845,260846,260846,260849,260860,260866,260873,260876,260878,260887,260891,260897,260901,260901,260901,260901,260901,260914,260917,260920,260928,260936,260936,260941,260953,260957,260969,260970,260986,260989,260996,260996,260997,261000,261012,261023,261023,261023,261027,261030,261036,261036,261036,261037,261048,261048,261054,261056,261060,261060,261060,261063,261064,261065,261073,261075,261078,261078,261090,261092,261093,261112,261120,261120,261120,261120,261120,261120,261120,261120,261129,261130,261130,261131,261132,261138,261139,261150,261152,261154,261169,261169,261170,261174,261174,261184,261189,261190,261191,261193,261193,261194,261199,261199,261200,261204,261207,261207,261207,261208,261209,261211,261216,261217,261221,261221,261224,261231,261248,261255,261255,261255,261255,261255,261255,261258,261258,261261,261261,261261,261261,261262,261264,261272,261272,261272,261272,261277,261278,261278,261280,261282,261289,261290,261290,261290,261290,261291,261298,261303,261303,261312,261315,261315,261315,261315,261315,261315,261316,261319,261322,261323,261325,261327,261327,261328,261328,261328,261328,261338,261346,261379,261386,261386,261388,261389,261393,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261396,261397,261398,261399,261402,261402,261405,261405,261405,261405,261405,261405,261405,261406,261407,261409,261409,261409,261412,261413,261414,261414,261414,261417,261417,261417,261418,261418,261418,261420,261420,261420,261420,261420,261421,261421,261422,261422,261423,261423,261423,261425,261425,261431,261442,261442,261443,261443,261443,261444,261447,261449,261449,261450,261452,261452,261452,261452,261452,261452,261452,261452,261452,261453,261453,261453,261453,261453,261454,261457,261462,261463,261463,261464,261467,261474,261474,261474,261477,261477,261477,261486,261490,261501,261501,261501,261513,261515,261516,261516,261517,261519,261520,261521,261523,261524,261524,261528,261528,261528,261531,261531,261532,261539,261547,261565,261565,261565,261565,261565,261565,261576,261576,261576,261576,261576,261576,261578,261578,261579,261587,261588,261589,261589,261589,261589,261589,261589,261596,261597,261597,261599,261607,261607,261607,261608,261608,261609,261609,261611,261619,261621,261621,261621,261627,261630,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261631,261633,261656,261663,261663,261667,261672,261673,261673,261673,261673,261673,261673,261673,261673,261676,261677,261677,261679,261679,261679,261686,261687,261690,261700,261701,261701,261706,261714,261721,261734,261739,261755,261766,261769,261771,261774,261783,261783,261783,261783,261783,261783,261783,261783,261791,261795,261798,261807,261812,261819,261819,261819,261819,261819,261831,261843,261848,261850,261850,261850,261866,261871,261883,261888,261888,261888,261888,261889,261892,261899,261899,261900,261901,261901,261901,261901,261901,261903,261904,261904,261907,261907,261907,261907,261913,261920,261920,261920,261923,261924,261927,261931,261936,261941,261942,261947,261953,261958,261960,261966,261966,261966,261966,261966,261970,261970,261971,261971,261971,261974,261977,261979,261980,261982,261982,261982,261982,261982,261984,261984,261984,261984,261984,261984,261984,261984,261987,261991,261991,261991,261991,261992,261992,261992,261996,261996,261996,262002,262007,262008,262013,262013,262019,262019,262028,262047,262053,262053,262055,262055,262055,262057,262062,262069,262072,262073,262075,262076,262076,262079,262082,262086,262091,262099,262100,262100,262107,262107,262119,262119,262119,262119,262119,262124,262124,262124,262124,262124,262124,262124,262125,262138,262143,262143,262143,262148,262148,262156,262156,262159,262160,262167,262180,262186,262187,262191,262191,262191,262209,262209,262209,262210,262218,262219,262220,262220,262220,262220,262221,262221,262222,262229,262233,262243,262249,262250,262252,262253,262253,262253,262255,262255,262259,262272,262272,262274,262277,262277,262282,262282,262286,262288,262294,262294,262294,262294,262294,262294,262296,262301,262306,262307,262307,262316,262316,262316,262316,262318,262318,262322,262322,262322,262322,262322,262322,262322,262322,262322,262322,262322,262322,262322,262322,262322,262322,262323,262323,262323,262325,262327,262327,262327,262328,262331,262341,262341,262341,262365,262366,262366,262369,262371,262374,262378,262381,262383,262395,262395,262395,262395,262397,262397,262397,262397,262402,262403,262411,262412,262427,262431,262436,262438,262461,262468,262468,262469,262470,262482,262484,262485,262485,262485,262494,262494,262494,262501,262515,262515,262516,262520,262527,262533,262534,262537,262540,262541,262559,262560,262560,262560,262566,262567,262568,262573,262573,262581,262582,262582,262594,262594,262595,262595,262595,262595,262607,262612,262613,262620,262621,262623,262625,262629,262634,262646,262648,262648,262648,262649,262653,262654,262656,262659,262660,262661,262664,262664,262669,262672,262678,262678,262704,262706,262706,262718,262718,262724,262725,262727,262727,262727,262727,262727,262727,262727,262727,262742,262742,262742,262744,262744,262745,262747,262750,262752,262758,262763,262764,262766,262770,262770,262773,262775,262780,262781,262787,262787,262808,262808,262811,262811,262811,262811,262811,262811,262811,262811,262811,262811,262811,262817,262817,262817,262818,262819,262823,262824,262824,262832,262832,262832,262832,262834,262837,262837,262838,262838,262838,262838,262838,262838,262844,262846,262846,262849,262849,262849,262850,262851,262851,262851,262856,262856,262856,262856,262858,262858,262858,262860,262860,262861,262863,262865,262865,262865,262868,262873,262873,262884,262888,262888,262891,262892,262893,262896,262900,262914,262920,262922,262924,262924,262924,262937,262945,262945,262972,262978,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262982,262984,262989,262991,262991,262991,262991,262991,262994,262994,262997,263003,263007,263012,263012,263012,263014,263015,263016,263026,263042,263049,263051,263051,263056,263060,263060,263061,263064,263076,263081,263082,263086,263086,263091,263091,263093,263093,263094,263094,263102,263109,263113,263113,263113,263125,263125,263130,263132,263140,263142,263143,263145,263148,263152,263154,263167,263167,263172,263172,263175,263179,263179,263179,263179,263181,263194,263203,263203,263210,263215,263223,263223,263232,263240,263240,263240,263240,263240,263245,263247,263249,263249,263249,263250,263251,263251,263251,263251,263251,263251,263251,263251,263251,263251,263251,263251,263251,263252,263271,263273,263273,263273,263273,263274,263274,263278,263281,263281,263286,263296,263296,263296,263296,263303,263306,263318,263318,263318,263321,263332,263335,263339,263339,263339,263339,263342,263342,263343,263351,263351,263355,263355,263355,263358,263372,263372,263372,263376,263376,263376,263378,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263383,263384,263388,263400,263400,263402,263402,263402,263406,263406,263406,263409,263419,263432,263432,263432,263437,263438,263440,263452,263452,263452,263454,263460,263460,263460,263460,263462,263464,263468,263471,263472,263474,263484,263484,263484,263484,263484,263485,263485,263490,263490,263494,263495,263495,263502,263503
\ No newline at end of file
diff --git a/RoaringBitmap/src/test/resources/testdata/testIssue260.txt b/roaringbitmap/src/test/resources/testdata/testIssue260.txt
similarity index 100%
rename from RoaringBitmap/src/test/resources/testdata/testIssue260.txt
rename to roaringbitmap/src/test/resources/testdata/testIssue260.txt
diff --git a/RoaringBitmap/style/eclipse-java-google-style.xml b/roaringbitmap/style/eclipse-java-google-style.xml
similarity index 100%
rename from RoaringBitmap/style/eclipse-java-google-style.xml
rename to roaringbitmap/style/eclipse-java-google-style.xml
diff --git a/RoaringBitmap/style/roaring_google_checks.xml b/roaringbitmap/style/roaring_google_checks.xml
similarity index 100%
rename from RoaringBitmap/style/roaring_google_checks.xml
rename to roaringbitmap/style/roaring_google_checks.xml
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 915e323ce..58ae10f92 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,5 +1,5 @@
 include(
-        "RoaringBitmap",
+        "roaringbitmap",
         "bsi",
         "fuzz-tests",
         "jmh",
diff --git a/simplebenchmark/build.gradle.kts b/simplebenchmark/build.gradle.kts
index 1e9fe497a..94c880484 100644
--- a/simplebenchmark/build.gradle.kts
+++ b/simplebenchmark/build.gradle.kts
@@ -1,5 +1,5 @@
 dependencies {
-    implementation(project(":RoaringBitmap"))
+    implementation(project(":roaringbitmap"))
 }
 
 tasks {
diff --git a/simplebenchmark/src/main/java/simplebenchmark.java b/simplebenchmark/src/main/java/simplebenchmark.java
index 810e94f3a..d87280acd 100644
--- a/simplebenchmark/src/main/java/simplebenchmark.java
+++ b/simplebenchmark/src/main/java/simplebenchmark.java
@@ -1,266 +1,270 @@
-
-import java.io.*;
-import java.net.*;
-import java.text.*;
-import java.util.*;
-import java.util.zip.*;
-import org.roaringbitmap.*;
-import org.roaringbitmap.buffer.*;
+import org.roaringbitmap.RoaringBitmap;
+import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
+import org.roaringbitmap.buffer.MutableRoaringBitmap;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
 
 public class simplebenchmark {
 
-    public static final String CENSUS_INCOME = "census-income";
-    public static final String CENSUS1881 = "census1881";
-    public static final String DIMENSION_008 = "dimension_008";
-    public static final String DIMENSION_003 = "dimension_003";
-    public static final String DIMENSION_033 = "dimension_033";
-    public static final String USCENSUS2000 = "uscensus2000";
-    public static final String WEATHER_SEPT_85 = "weather_sept_85";
-    public static final String WIKILEAKS_NOQUOTES = "wikileaks-noquotes";
-    public static final String CENSUS_INCOME_SRT = "census-income_srt";
-    public static final String CENSUS1881_SRT = "census1881_srt";
-    public static final String WEATHER_SEPT_85_SRT = "weather_sept_85_srt";
-    public static final String WIKILEAKS_NOQUOTES_SRT = "wikileaks-noquotes_srt";
-    public static int rep = 100;
-    static List toBitmaps(ZipRealDataRetriever zip)  throws IOException, URISyntaxException {
-        ArrayList answer = new ArrayList();
-        for(int[] data : zip.fetchBitPositions()) {
-            RoaringBitmap r = RoaringBitmap.bitmapOf(data);
-            r.runOptimize();
-            answer.add(r);
-        }
-        return answer;
+  public static final String CENSUS_INCOME = "census-income";
+  public static final String CENSUS1881 = "census1881";
+  public static final String DIMENSION_008 = "dimension_008";
+  public static final String DIMENSION_003 = "dimension_003";
+  public static final String DIMENSION_033 = "dimension_033";
+  public static final String USCENSUS2000 = "uscensus2000";
+  public static final String WEATHER_SEPT_85 = "weather_sept_85";
+  public static final String WIKILEAKS_NOQUOTES = "wikileaks-noquotes";
+  public static final String CENSUS_INCOME_SRT = "census-income_srt";
+  public static final String CENSUS1881_SRT = "census1881_srt";
+  public static final String WEATHER_SEPT_85_SRT = "weather_sept_85_srt";
+  public static final String WIKILEAKS_NOQUOTES_SRT = "wikileaks-noquotes_srt";
+  public static int rep = 100;
+
+  static List toBitmaps(ZipRealDataRetriever zip)
+      throws IOException, URISyntaxException {
+    ArrayList answer = new ArrayList();
+    for (int[] data : zip.fetchBitPositions()) {
+      RoaringBitmap r = RoaringBitmap.bitmapOf(data);
+      r.runOptimize();
+      answer.add(r);
     }
-    static List toBufferBitmaps(ZipRealDataRetriever zip)  throws IOException, URISyntaxException {
-        ArrayList answer = new ArrayList();
-        for(int[] data : zip.fetchBitPositions()) {
-            MutableRoaringBitmap r = MutableRoaringBitmap.bitmapOf(data);
-            r.runOptimize();
-            answer.add(r);
-        }
-        return answer;
+    return answer;
+  }
+
+  static List toBufferBitmaps(ZipRealDataRetriever zip)
+      throws IOException, URISyntaxException {
+    ArrayList answer = new ArrayList();
+    for (int[] data : zip.fetchBitPositions()) {
+      MutableRoaringBitmap r = MutableRoaringBitmap.bitmapOf(data);
+      r.runOptimize();
+      answer.add(r);
     }
+    return answer;
+  }
 
-    static int universeSize(ZipRealDataRetriever zip)  throws IOException, URISyntaxException {
-        int answer = 0;
-        for(int[] data : zip.fetchBitPositions()) {
-            if(data[data.length - 1] > answer) answer = data[data.length - 1];
-        }
-        return answer;
+  static int universeSize(ZipRealDataRetriever zip) throws IOException, URISyntaxException {
+    int answer = 0;
+    for (int[] data : zip.fetchBitPositions()) {
+      if (data[data.length - 1] > answer) answer = data[data.length - 1];
     }
-
-    public static void benchmark(ZipRealDataRetriever zip)  throws IOException,URISyntaxException {
-        int maxvalue = universeSize(zip);
-        // bitspervalue nanotimefor2by2and nanotimefor2by2or nanotimeforwideor nanotimeforcontains (first normal then buffer)
-        System.out.print(String.format("%1$-25s", zip.getName())+"\t\t");
-        List bitmaps = toBitmaps(zip);
-        display(bitmaps,maxvalue);
-        //
-        System.out.print("\t");
-        List bufferbitmaps = toBufferBitmaps(zip);
-        bufferdisplay(bufferbitmaps,maxvalue);
-        System.out.println();
-
-
+    return answer;
+  }
+
+  public static void benchmark(ZipRealDataRetriever zip) throws IOException, URISyntaxException {
+    int maxvalue = universeSize(zip);
+    // bitspervalue nanotimefor2by2and nanotimefor2by2or nanotimeforwideor nanotimeforcontains
+    // (first normal then buffer)
+    System.out.print(String.format("%1$-25s", zip.getName()) + "\t\t");
+    List bitmaps = toBitmaps(zip);
+    display(bitmaps, maxvalue);
+    //
+    System.out.print("\t");
+    List bufferbitmaps = toBufferBitmaps(zip);
+    bufferdisplay(bufferbitmaps, maxvalue);
+    System.out.println();
+  }
+
+  static void display(List bitmaps, int maxvalue) {
+    long totalcard = 0;
+    long totalbytes = 0;
+    DecimalFormat dfbitsperval = new DecimalFormat("0.00");
+
+    for (RoaringBitmap r : bitmaps) {
+      totalcard += r.getCardinality();
+      totalbytes += r.getSizeInBytes();
     }
 
-    static void display(List bitmaps, int maxvalue) {
-        long totalcard = 0;
-        long totalbytes = 0;
-        DecimalFormat dfbitsperval = new DecimalFormat("0.00");
-
-        for(RoaringBitmap r : bitmaps) {
-            totalcard += r.getCardinality();
-            totalbytes += r.getSizeInBytes();
-        }
-
-        List timings = timings(bitmaps,maxvalue);
-        for(int repeat = 0; repeat < rep; ++ repeat) {
-            List newtime = timings(bitmaps,maxvalue);
-            for(int i = 0 ; i < newtime.size() ; ++i) {
-                if(newtime.get(i) < timings.get(i)) timings.set(i,newtime.get(i));
-            }
-        }
-
-        System.out.print(String.format("%1$-10s",dfbitsperval.format(totalbytes * 8.0 / totalcard)));
-        System.out.flush();
-        for(long time : timings) {
-            System.out.print(String.format("%1$10s",time));
-        }
-
+    List timings = timings(bitmaps, maxvalue);
+    for (int repeat = 0; repeat < rep; ++repeat) {
+      List newtime = timings(bitmaps, maxvalue);
+      for (int i = 0; i < newtime.size(); ++i) {
+        if (newtime.get(i) < timings.get(i)) timings.set(i, newtime.get(i));
+      }
     }
-    static void bufferdisplay(List bitmaps, int maxvalue) {
-        long totalcard = 0;
-        long totalbytes = 0;
-        DecimalFormat dfbitsperval = new DecimalFormat("0.00");
-
-        for(ImmutableRoaringBitmap r : bitmaps) {
-            totalcard += r.getCardinality();
-            totalbytes += r.getSizeInBytes();
-        }
-
-        List timings = buffertimings(bitmaps,maxvalue);
-        for(int repeat = 0; repeat < rep; ++ repeat) {
-            List newtime = buffertimings(bitmaps,maxvalue);
-            for(int i = 0 ; i < newtime.size() ; ++i) {
-                if(newtime.get(i) < timings.get(i)) timings.set(i,newtime.get(i));
-            }
-        }
-
-        for(long time : timings) {
-            System.out.print(String.format("%1$10s",time));
-        }
 
+    System.out.print(String.format("%1$-10s", dfbitsperval.format(totalbytes * 8.0 / totalcard)));
+    System.out.flush();
+    for (long time : timings) {
+      System.out.print(String.format("%1$10s", time));
     }
+  }
 
-    static ArrayList timings(List bitmaps, int maxvalue) {
-        long successive_and = 0;
-        long successive_or = 0;
-        long total_or = 0;
-        long start, stop;
-        ArrayList timings = new ArrayList();
-
-        start = System.nanoTime();
-        for (int i = 0; i < bitmaps.size() - 1; ++i) {
-            successive_and += RoaringBitmap.and(bitmaps.get(i),bitmaps.get(i + 1)).getCardinality();
-        }
-        if(successive_and == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-        timings.add(stop - start);
-
-        start = System.nanoTime();
-        for (int i = 0; i < bitmaps.size() - 1; ++i) {
-            successive_or += RoaringBitmap.or(bitmaps.get(i),bitmaps.get(i + 1)).getCardinality();
-        }
-        if(successive_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-
-        timings.add(stop - start);
-
-        start = System.nanoTime();
-        total_or = RoaringBitmap.or(bitmaps.iterator()).getCardinality();
-        if(total_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-        timings.add(stop - start);
-        int quartcount = 0;
-        start = System.nanoTime();
-        for(RoaringBitmap rb : bitmaps) {
-            if(rb.contains(maxvalue / 4 )) ++ quartcount;
-            if(rb.contains(maxvalue / 2 )) ++ quartcount;
-            if(rb.contains(3 * maxvalue / 4 )) ++ quartcount;
-        }
-        if(quartcount == 0) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-        timings.add(stop - start);
-        return timings;
+  static void bufferdisplay(List bitmaps, int maxvalue) {
+    long totalcard = 0;
+    long totalbytes = 0;
+    DecimalFormat dfbitsperval = new DecimalFormat("0.00");
 
+    for (ImmutableRoaringBitmap r : bitmaps) {
+      totalcard += r.getCardinality();
+      totalbytes += r.getSizeInBytes();
     }
 
-    static ArrayList buffertimings(List bitmaps, int maxvalue) {
-        long successive_and = 0;
-        long successive_or = 0;
-        long total_or = 0;
-        long start, stop;
-        ArrayList timings = new ArrayList();
-
-        start = System.nanoTime();
-        for (int i = 0; i < bitmaps.size() - 1; ++i) {
-            successive_and += ImmutableRoaringBitmap.and(bitmaps.get(i),bitmaps.get(i + 1)).getCardinality();
-        }
-        if(successive_and == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-        timings.add(stop - start);
-
-        start = System.nanoTime();
-        for (int i = 0; i < bitmaps.size() - 1; ++i) {
-            successive_or += ImmutableRoaringBitmap.or(bitmaps.get(i),bitmaps.get(i + 1)).getCardinality();
-        }
-        if(successive_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-        timings.add(stop - start);
-
-        start = System.nanoTime();
-        total_or = ImmutableRoaringBitmap.or(bitmaps.iterator()).getCardinality();
-        if(total_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-        timings.add(stop - start);
-        int quartcount = 0;
-        start = System.nanoTime();
-        for(ImmutableRoaringBitmap rb : bitmaps) {
-            if(rb.contains(maxvalue / 4 )) ++ quartcount;
-            if(rb.contains(maxvalue / 2 )) ++ quartcount;
-            if(rb.contains(3 * maxvalue / 4 )) ++ quartcount;
-        }
-        if(quartcount == 0) System.out.println(); // to defeat clever compilers
-        stop = System.nanoTime();
-        timings.add(stop - start);
-        return timings;
-
+    List timings = buffertimings(bitmaps, maxvalue);
+    for (int repeat = 0; repeat < rep; ++repeat) {
+      List newtime = buffertimings(bitmaps, maxvalue);
+      for (int i = 0; i < newtime.size(); ++i) {
+        if (newtime.get(i) < timings.get(i)) timings.set(i, newtime.get(i));
+      }
     }
 
+    for (long time : timings) {
+      System.out.print(String.format("%1$10s", time));
+    }
+  }
+
+  static ArrayList timings(List bitmaps, int maxvalue) {
+    long successive_and = 0;
+    long successive_or = 0;
+    long total_or = 0;
+    long start, stop;
+    ArrayList timings = new ArrayList();
+
+    start = System.nanoTime();
+    for (int i = 0; i < bitmaps.size() - 1; ++i) {
+      successive_and += RoaringBitmap.and(bitmaps.get(i), bitmaps.get(i + 1)).getCardinality();
+    }
+    if (successive_and == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+    timings.add(stop - start);
 
-
-
-    public static void main(String[] args)  throws IOException, URISyntaxException {
-        if(args.length != 1) {
-            System.out.println("You need to provide exactly one parameter.");
-            System.out.println("E.g., java simplebenchmark ../real-roaring-dataset/src/main/resources/real-roaring-dataset/census1881.zip");
-            return;
-        }
-        try {
-            benchmark(new ZipRealDataRetriever(args[0]));
-        } catch(FileNotFoundException  fnf) {
-            System.err.println("I can't find the file "+ args[0]);
-        }
+    start = System.nanoTime();
+    for (int i = 0; i < bitmaps.size() - 1; ++i) {
+      successive_or += RoaringBitmap.or(bitmaps.get(i), bitmaps.get(i + 1)).getCardinality();
+    }
+    if (successive_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+
+    timings.add(stop - start);
+
+    start = System.nanoTime();
+    total_or = RoaringBitmap.or(bitmaps.iterator()).getCardinality();
+    if (total_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+    timings.add(stop - start);
+    int quartcount = 0;
+    start = System.nanoTime();
+    for (RoaringBitmap rb : bitmaps) {
+      if (rb.contains(maxvalue / 4)) ++quartcount;
+      if (rb.contains(maxvalue / 2)) ++quartcount;
+      if (rb.contains(3 * maxvalue / 4)) ++quartcount;
+    }
+    if (quartcount == 0) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+    timings.add(stop - start);
+    return timings;
+  }
+
+  static ArrayList buffertimings(List bitmaps, int maxvalue) {
+    long successive_and = 0;
+    long successive_or = 0;
+    long total_or = 0;
+    long start, stop;
+    ArrayList timings = new ArrayList();
+
+    start = System.nanoTime();
+    for (int i = 0; i < bitmaps.size() - 1; ++i) {
+      successive_and +=
+          ImmutableRoaringBitmap.and(bitmaps.get(i), bitmaps.get(i + 1)).getCardinality();
     }
+    if (successive_and == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+    timings.add(stop - start);
+
+    start = System.nanoTime();
+    for (int i = 0; i < bitmaps.size() - 1; ++i) {
+      successive_or +=
+          ImmutableRoaringBitmap.or(bitmaps.get(i), bitmaps.get(i + 1)).getCardinality();
+    }
+    if (successive_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+    timings.add(stop - start);
+
+    start = System.nanoTime();
+    total_or = ImmutableRoaringBitmap.or(bitmaps.iterator()).getCardinality();
+    if (total_or == 0xFFFFFFFF) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+    timings.add(stop - start);
+    int quartcount = 0;
+    start = System.nanoTime();
+    for (ImmutableRoaringBitmap rb : bitmaps) {
+      if (rb.contains(maxvalue / 4)) ++quartcount;
+      if (rb.contains(maxvalue / 2)) ++quartcount;
+      if (rb.contains(3 * maxvalue / 4)) ++quartcount;
+    }
+    if (quartcount == 0) System.out.println(); // to defeat clever compilers
+    stop = System.nanoTime();
+    timings.add(stop - start);
+    return timings;
+  }
+
+  public static void main(String[] args) throws IOException, URISyntaxException {
+    if (args.length != 1) {
+      System.out.println("You need to provide exactly one parameter.");
+      System.out.println(
+          "E.g., java simplebenchmark"
+              + " ../real-roaring-dataset/src/main/resources/real-roaring-dataset/census1881.zip");
+      return;
+    }
+    try {
+      benchmark(new ZipRealDataRetriever(args[0]));
+    } catch (FileNotFoundException fnf) {
+      System.err.println("I can't find the file " + args[0]);
+    }
+  }
 }
 
-
 class ZipRealDataRetriever {
 
-    private final String dataset;
+  private final String dataset;
 
-    public ZipRealDataRetriever(String dataset) throws IOException, URISyntaxException {
-        this.dataset = dataset;
-    }
+  public ZipRealDataRetriever(String dataset) throws IOException, URISyntaxException {
+    this.dataset = dataset;
+  }
 
-    public List fetchBitPositions() throws IOException {
-        List bitPositions = new ArrayList<>();
-
-        try (
-            final ZipInputStream zis = getResourceAsStream();
-            final BufferedReader buf = new BufferedReader(new InputStreamReader(zis));
-        ) {
-
-
-        while (true) {
-            ZipEntry nextEntry = zis.getNextEntry();
-            if (nextEntry == null) {
-            break;
-            }
-
-            try {
-            String oneLine = buf.readLine(); // a single, perhaps very long, line
-            String[] positions = oneLine.split(",");
-            int[] ans = new int[positions.length];
-            for (int i = 0; i < positions.length; i++) {
-                ans[i] = Integer.parseInt(positions[i]);
-            }
-            bitPositions.add(ans);
-            } catch (IOException e) {
-            throw new RuntimeException(e);
-            }
-        }
+  public List fetchBitPositions() throws IOException {
+    List bitPositions = new ArrayList<>();
+
+    try (final ZipInputStream zis = getResourceAsStream();
+        final BufferedReader buf = new BufferedReader(new InputStreamReader(zis)); ) {
+
+      while (true) {
+        ZipEntry nextEntry = zis.getNextEntry();
+        if (nextEntry == null) {
+          break;
         }
-        return bitPositions;
-    }
 
-    public String getName() {
-        return new File(dataset).getName();
+        try {
+          String oneLine = buf.readLine(); // a single, perhaps very long, line
+          String[] positions = oneLine.split(",");
+          int[] ans = new int[positions.length];
+          for (int i = 0; i < positions.length; i++) {
+            ans[i] = Integer.parseInt(positions[i]);
+          }
+          bitPositions.add(ans);
+        } catch (IOException e) {
+          throw new RuntimeException(e);
+        }
+      }
     }
+    return bitPositions;
+  }
 
-    private ZipInputStream getResourceAsStream() throws FileNotFoundException {
-        return new ZipInputStream(new FileInputStream(dataset));
-    }
+  public String getName() {
+    return new File(dataset).getName();
+  }
 
+  private ZipInputStream getResourceAsStream() throws FileNotFoundException {
+    return new ZipInputStream(new FileInputStream(dataset));
+  }
 }