CRoaring
4.2.1
Roaring bitmaps in C (and C++)
|
Portable Roaring bitmaps in C (and C++) with full support for your favorite compiler (GNU GCC, LLVM's clang, Visual Studio, Apple Xcode, Intel oneAPI). Included in the Awesome C list of open source C software.
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.
Roaring bitmaps are compressed bitmaps which tend to outperform conventional compressed bitmaps such as WAH, EWAH or Concise. They are used by several major systems such as Apache Lucene and derivative systems such as Solr and Elasticsearch, Metamarkets' Druid, LinkedIn Pinot, Netflix Atlas, Apache Spark, OpenSearchServer, Cloud Torrent, Whoosh, InfluxDB, Pilosa, Bleve, Microsoft Visual Studio Team Services (VSTS), and eBay's Apache Kylin. The CRoaring library is used in several systems such as Apache Doris, ClickHouse, Redpanda, and StarRocks. The YouTube SQL Engine, Google Procella, uses Roaring bitmaps for indexing.
We published a peer-reviewed article on the design and evaluation of this library:
Roaring bitmaps are found to work well in many important applications:
Use Roaring for bitmap compression whenever possible. Do not use other bitmap compression methods (Wang et al., SIGMOD 2017)
There is a serialized format specification for interoperability between implementations. Hence, it is possible to serialize a Roaring Bitmap from C++, read it in Java, modify it, serialize it back and read it in Go and Python.
The primary goal of the CRoaring is to provide a high performance low-level implementation that fully take advantage of the latest hardware. Roaring bitmaps are already available on a variety of platform through Java, Go, Rust... implementations. CRoaring is a library that seeks to achieve superior performance by staying close to the latest hardware.
(c) 2016-... The CRoaring authors.
Hardly anyone has access to an actual big-endian system. Nevertheless, We support big-endian systems such as IBM s390x through emulators—except for IO serialization which is only supported on little-endian systems (see issue 423).
The CRoaring library can be amalgamated into a single source file that makes it easier for integration into other projects. Moreover, by making it possible to compile all the critical code into one compilation unit, it can improve the performance. For the rationale, please see the SQLite documentation, or the corresponding Wikipedia entry. Users who choose this route, do not need to rely on CRoaring's build system (based on CMake).
We offer amalgamated files as part of each release.
Linux or macOS users might follow the following instructions if they have a recent C or C++ compiler installed and a standard utility (wget
).
Create a new file named
demo.c<tt>with this content: ``C #include <stdio.h> #include <stdlib.h> #include "roaring.c" int main() { roaring_bitmap_t *r1 = roaring_bitmap_create(); for (uint32_t i = 100; i < 1000; i++) roaring_bitmap_add(r1, i); printf("cardinality = %d\n", (int) roaring_bitmap_get_cardinality(r1)); roaring_bitmap_free(r1);
bitset_t *b = bitset_create(); for (int k = 0; k < 1000; ++k) { bitset_set(b, 3 * k); } printf("%zu \n", bitset_count(b)); bitset_free(b); return EXIT_SUCCESS; } ``
Create a new file named
demo.cpp<tt>with this content: ``C++ #include <iostream> #include "roaring.hh" // the amalgamated roaring.hh includes roaring64map.hh #include "roaring.c" int main() { roaring::Roaring r1; for (uint32_t i = 100; i < 1000; i++) { r1.add(i); } std::cout << "cardinality = " << r1.cardinality() << std::endl;
roaring::Roaring64Map r2; for (uint64_t i = 18000000000000000100ull; i < 18000000000000001000ull; i++) { r2.add(i); } std::cout << "cardinality = " << r2.cardinality() << std::endl; return 0; } ```
3.
./demo
`` cardinality = 900 1000 `` 4.
./demopp
`` cardinality = 900 cardinality = 900 ```If you like CMake and CPM, you can add just a few lines in your CMakeLists.txt
file to grab a CRoaring
release. See our CPM demonstration for further details.
If you like CMake, you can add just a few lines in your CMakeLists.txt
file to grab a CRoaring
release. See our demonstration for further details.
If you installed the CRoaring library locally, you may use it with CMake's find_package
function as in this example:
To generate the amalgamated files yourself, you can invoke a bash script...
If you prefer a silent output, you can use the following command to redirect stdout
:
(Bash shells are standard under Linux and macOS. Bash shells are available under Windows as part of the GitHub Desktop under the name Git Shell
. So if you have cloned the CRoaring
GitHub repository from within the GitHub Desktop, you can right-click on CRoaring
, select Git Shell
and then enter the above commands.)
It is not necessary to invoke the script in the CRoaring directory. You can invoke it from any directory where you want the amalgamation files to be written.
It will generate three files for C users: roaring.h
, roaring.c
and amalgamation_demo.c
... as well as some brief instructions. The amalgamation_demo.c
file is a short example, whereas roaring.h
and roaring.c
are "amalgamated" files (including all source and header files for the project). This means that you can simply copy the files roaring.h
and roaring.c
into your project and be ready to go! No need to produce a library! See the amalgamation_demo.c
file.
The C interface is found in the files
We also have a C++ interface:
Some users have to deal with large volumes of data. It may be important for these users to be aware of the addMany
(C++) roaring_bitmap_or_many
(C) functions as it is much faster and economical to add values in batches when possible. Furthermore, calling periodically the runOptimize
(C++) or roaring_bitmap_run_optimize
(C) functions may help.
We have microbenchmarks constructed with the Google Benchmarks. Under Linux or macOS, you may run them as follows:
By default, the benchmark tools picks one data set (e.g., CRoaring/benchmarks/realdata/census1881
). We have several data sets and you may pick others:
You may disable some functionality for the purpose of benchmarking. For example, assuming you have an x64 processor, you could benchmark the code without AVX-512 even if both your processor and compiler supports it:
You can benchmark without AVX or AVX-512 as well:
For general users, CRoaring would apply default allocator without extra codes. But global memory hook is also provided for those who want a custom memory allocator. Here is an example:
By default we use:
We require that the free
/aligned_free
functions follow the C convention where free(NULL)
/aligned_free(NULL)
have no effect.
This example assumes that CRoaring has been build and that you are linking against the corresponding library. By default, CRoaring will install its header files in a roaring
directory. If you are working from the amalgamation script, you may add the line #include "roaring.c"
if you are not linking against a prebuilt CRoaring library and replace #include <roaring/roaring.h>
by #include "roaring.h"
.
We also support efficient 64-bit compressed bitmaps in C:
The API is similar to the conventional 32-bit bitmaps. Please see the header file roaring64.h
(compare with roaring.h
).
We support convention bitsets (uncompressed) as part of the library.
Simple example:
More advanced example:
In some instances, you may want to convert a Roaring bitmap into a conventional (uncompressed) bitset. Indeed, bitsets have advantages such as higher query performances in some cases. The following code illustrates how you may do so:
You should be aware that a convention bitset (bitset_t *
) may use much more memory than a Roaring bitmap in some cases. You should run benchmarks to determine whether the conversion to a bitset has performance benefits in your case.
This example assumes that CRoaring has been build and that you are linking against the corresponding library. By default, CRoaring will install its header files in a roaring
directory so you may need to replace #include "roaring.hh"
by #include <roaring/roaring.hh>
. If you are working from the amalgamation script, you may add the line #include "roaring.c"
if you are not linking against a CRoaring prebuilt library.
CRoaring follows the standard cmake workflow. Starting from the root directory of the project (CRoaring), you can do:
(You can replace the build
directory with any other directory name.) By default all tests are built on all platforms, to skip building and running tests add -DENABLE_ROARING_TESTS=OFF
to the command line.
As with all cmake
projects, you can specify the compilers you wish to use by adding (for example) -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
to the cmake
command line.
If you are using clang or gcc and you know your target architecture, you can set the architecture by specifying -DROARING_ARCH=arch
. For example, if you have many server but the oldest server is running the Intel haswell
architecture, you can specify -DROARING_ARCH=haswell
. In such cases, the produced binary will be optimized for processors having the characteristics of a haswell process and may not run on older architectures. You can find out the list of valid architecture values by typing man gcc
.
For a debug release, starting from the root directory of the project (CRoaring), try
To check that your code abides by the style convention (make sure that clang-format
is installed):
To reformat your code according to the style convention (make sure that clang-format
is installed):
We are assuming that you have a common Windows PC with at least Visual Studio 2015, and an x64 processor.
To build with at least Visual Studio 2015 from the command line:
cmake
be made available from the command line.VisualStudio
.CRoaring
in your GitHub repository list, and select Open in Git Shell
, then type cd VisualStudio
in the newly created shell.cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..
in the shell while in the VisualStudio
repository. (Alternatively, if you want to build a static library, you may use the command line cmake -DCMAKE_GENERATOR_PLATFORM=x64 -DROARING_BUILD_STATIC=ON ..
.)RoaringBitmap.sln
). Open this file in Visual Studio. You should now be able to build the project and run the tests. For example, in the Solution Explorer
window (available from the View
menu), right-click ALL_BUILD
and select Build
. To test the code, still in the Solution Explorer
window, select RUN_TESTS
and select Build
.To build with at least Visual Studio 2017 directly in the IDE:
Visual C++ tools for CMake
optional component when installing the C++ Development Workload within Visual Studio.File > Open > Folder...
to open the CRoaring folder.CMakeLists.txt
in the parent directory within Solution Explorer
and select Build
to build the project.Select Startup Item...
menu and choose one of the tests. Run the test by pressing the button to the left of the dropdown.We have optimizations specific to AVX2 and AVX-512 in the code, and they are turned dynamically based on the detected hardware at runtime.
You can install pre-built binaries for roaring
or build it from source using Conan. Use the following command to install latest version:
For detailed instructions on how to use Conan, please refer to the Conan documentation.
The roaring
Conan recipe is kept up to date by Conan maintainers and community contributors. If the version is out of date, please create an issue or pull request on the ConanCenterIndex repository.
vcpkg users on Windows, Linux and macOS can download and install roaring
with one single command from their favorite shell.
On Linux and macOS:
will build and install roaring
as a static library.
On Windows (64-bit):
will build and install roaring
as a shared library.
will build and install roaring
as a static library.
These commands will also print out instructions on how to use the library from MSBuild or CMake-based projects.
If you find the version of roaring
shipped with vcpkg
is out-of-date, feel free to report it to vcpkg
community either by submiting an issue or by creating a PR.
Our AVX2 code does not use floating-point numbers or multiplications, so it is not subject to turbo frequency throttling on many-core Intel processors.
Our AVX-512 code is only enabled on recent hardware (Intel Ice Lake or better and AMD Zen 4) where SIMD-specific frequency throttling is not observed.
Like, for example, STL containers, the CRoaring library has no built-in thread support. Thus whenever you modify a bitmap in one thread, it is unsafe to query it in others. However, you can safely copy a bitmap and use both copies in concurrently.
If you use "copy-on-write" (default to disabled), then you should pass copies to the different threads. They will create shared containers, and for shared containers, we use reference counting with an atomic counter.
To summarize:
Thus the following pattern where you copy bitmaps and pass them to different threads is safe with or without COW:
Suppose you want to compute the union (OR) of many bitmaps. How do you proceed? There are many different strategies.
You can use roaring_bitmap_or_many(bitmapcount, bitmaps)
or roaring_bitmap_or_many_heap(bitmapcount, bitmaps)
or you may even roll your own aggregation:
All of them will work but they have different performance characteristics. The roaring_bitmap_or_many_heap
should probably only be used if, after benchmarking, you find that it is faster by a good margin: it uses more memory.
The roaring_bitmap_or_many
is meant as a good default. It works by trying to delay work as much as possible. However, because it delays computations, it also does not optimize the format as the computation runs. It might thus fail to see some useful pattern in the data such as long consecutive values.
The approach based on repeated calls to roaring_bitmap_or_inplace
is also fine, and might even be faster in some cases. You can expect it to be faster if, after a few calls, you get long sequences of consecutive values in the answer. That is, if the final answer is all integers in the range [0,1000000), and this is apparent quickly, then the later roaring_bitmap_or_inplace
will be very fast.
You should benchmark these alternatives on your own data to decide what is best.
Tom Cornebize wrote a Python wrapper available at https://github.com/Ezibenroc/PyRoaringBitMap Installing it is as easy as typing...
Salvatore Previti wrote a Node/JavaScript wrapper available at https://github.com/SalvatorePreviti/roaring-node Installing it is as easy as typing...
Jérémie Piotte wrote a Swift wrapper.
Brandon Smith wrote a C# wrapper available at https://github.com/RogueException/CRoaring.Net (works for Windows and Linux under x64 processors)
There is a Go (golang) wrapper available at https://github.com/RoaringBitmap/gocroaring
Saulius Grigaliunas wrote a Rust wrapper available at https://github.com/saulius/croaring-rs
Yuce Tekol wrote a D wrapper available at https://github.com/yuce/droaring
Antonio Guilherme Ferreira Viggiano wrote a Redis Module available at https://github.com/aviggiano/redis-roaring
Justin Whear wrote a Zig wrapper available at https://github.com/jwhear/roaring-zig
https://groups.google.com/forum/#!forum/roaring-bitmaps
When contributing a change to the project, please run tools/clang-format.sh
after making any changes. A github action runs on all PRs to ensure formatting is consistent with this.