บิตแมปคำรามแบบพกพาใน C (และ C++) พร้อมการสนับสนุนอย่างเต็มที่สำหรับคอมไพเลอร์ที่คุณชื่นชอบ (GNU GCC, เสียงดังกราวของ LLVM, Visual Studio, Apple Xcode, Intel oneAPI) รวมอยู่ในรายการซอฟต์แวร์โอเพ่นซอร์ส C ที่ยอดเยี่ยม
บิตเซ็ตหรือที่เรียกว่าบิตแมป มักใช้เป็นโครงสร้างข้อมูลที่รวดเร็ว น่าเสียดายที่พวกเขาใช้หน่วยความจำมากเกินไป เพื่อชดเชย เรามักใช้บิตแมปที่ถูกบีบอัด
บิตแมปคำรามเป็นบิตแมปที่ถูกบีบอัด ซึ่งมีแนวโน้มที่จะมีประสิทธิภาพเหนือกว่าบิตแมปที่ถูกบีบอัดทั่วไป เช่น WAH, EWAH หรือ Concise ถูกใช้โดยระบบหลักๆ หลายแห่ง เช่น Apache Lucene และระบบอนุพันธ์ เช่น Solr และ Elasticsearch, Druid ของ Metamarkets, LinkedIn Pinot, Netflix Atlas, Apache Spark, OpenSearchServer, Cloud Torrent, Whoosh, InfluxDB, Pilosa, Bleve, Microsoft Visual Studio Team บริการ (VSTS) และ Apache Kylin ของ eBay ไลบรารี CRoaring ถูกใช้ในหลายระบบ เช่น Apache Doris, ClickHouse, Redpanda และ StarRocks Google Procella ซึ่งเป็น YouTube SQL Engine ใช้บิตแมป Roaring สำหรับการจัดทำดัชนี
เราเผยแพร่บทความที่ผ่านการตรวจสอบโดยผู้ทรงคุณวุฒิเกี่ยวกับการออกแบบและการประเมินผลห้องสมุดนี้:
บิตแมปคำรามทำงานได้ดีในแอปพลิเคชันที่สำคัญมากมาย:
ใช้ Roaring เพื่อบีบอัดบิตแมปทุกครั้งที่เป็นไปได้ อย่าใช้วิธีการบีบอัดบิตแมปอื่น ๆ (Wang et al., SIGMOD 2017)
มีข้อกำหนดรูปแบบต่อเนื่องสำหรับการทำงานร่วมกันระหว่างการใช้งาน ดังนั้นจึงเป็นไปได้ที่จะทำให้บิตแมปคำรามเป็นอนุกรมจาก C++, อ่านใน Java, แก้ไข, ทำให้เป็นอันดับกลับมา และอ่านใน Go และ Python
เป้าหมายหลักของ CRoaring คือการนำเสนอการใช้งานระดับต่ำที่มีประสิทธิภาพสูงซึ่งใช้ประโยชน์จากฮาร์ดแวร์ล่าสุดได้อย่างเต็มที่ บิตแมปคำรามมีอยู่แล้วบนแพลตฟอร์มที่หลากหลายผ่านการใช้งาน Java, Go, Rust... CRoaring เป็นไลบรารีที่พยายามบรรลุประสิทธิภาพที่เหนือกว่าโดยอยู่ใกล้กับฮาร์ดแวร์ใหม่ล่าสุด
(c) 2016-... ผู้เขียน CRoaring
แทบไม่มีใครสามารถเข้าถึงระบบยักษ์ใหญ่ที่แท้จริงได้ อย่างไรก็ตาม เราสนับสนุนระบบ big-endian เช่น IBM s390x ผ่านโปรแกรมจำลอง --- ยกเว้น IO serialization ซึ่งได้รับการสนับสนุนบนระบบ little-endian เท่านั้น (ดูปัญหา 423)
ไลบรารี CRoaring สามารถรวมเป็นไฟล์ต้นฉบับเดียวซึ่งช่วยให้รวมเข้ากับโครงการอื่นได้ง่ายขึ้น ยิ่งไปกว่านั้น ด้วยการทำให้สามารถคอมไพล์โค้ดที่สำคัญทั้งหมดลงในหน่วยการคอมไพล์เดียว จึงสามารถปรับปรุงประสิทธิภาพได้ สำหรับเหตุผล โปรดดูเอกสารประกอบ SQLite หรือรายการ Wikipedia ที่เกี่ยวข้อง ผู้ใช้ที่เลือกเส้นทางนี้ ไม่จำเป็นต้องพึ่งพาระบบบิลด์ของ CRoaring (อิงจาก CMake)
เรานำเสนอไฟล์แบบรวมเป็นส่วนหนึ่งของแต่ละรุ่น
ผู้ใช้ Linux หรือ macOS อาจปฏิบัติตามคำแนะนำต่อไปนี้หากติดตั้งคอมไพเลอร์ C หรือ C++ ล่าสุดและมียูทิลิตี้มาตรฐาน ( wget
)
wget https://github.com/RoaringBitmap/CRoaring/releases/download/v2.1.0/roaring.c
wget https://github.com/RoaringBitmap/CRoaring/releases/download/v2.1.0/roaring.h
wget https://github.com/RoaringBitmap/CRoaring/releases/download/v2.1.0/roaring.hh
demo.c
โดยมีเนื้อหาดังนี้: #include
#include
#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 = %dn" , ( 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 ;
}
demo.cpp
โดยมีเนื้อหาดังนี้: # 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 ;
}
cc -o demo demo.c
c++ -std=c++11 -o demopp demo.cpp
./demo
cardinality = 900
1000
./demopp
cardinality = 900
cardinality = 900
หากคุณชอบ CMake และ CPM คุณสามารถเพิ่มเพียงไม่กี่บรรทัดในไฟล์ CMakeLists.txt
ของคุณเพื่อรับ CRoaring
release ดูการสาธิต CPM ของเราสำหรับรายละเอียดเพิ่มเติม
cmake_minimum_required ( VERSION 3.10)
project (roaring_demo
LANGUAGES CXX C
)
set (CMAKE_CXX_STANDARD 17)
set (CMAKE_C_STANDARD 11)
add_executable (hello hello.cpp)
# You can add CPM.cmake like so:
# mkdir -p cmake
# wget -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake
include (cmake/CPM.cmake)
CPMAddPackage(
NAME roaring
GITHUB_REPOSITORY "RoaringBitmap/CRoaring"
GIT_TAG v2.0.4
OPTIONS "BUILD_TESTING OFF"
)
target_link_libraries (hello roaring::roaring)
หากคุณชอบ CMake คุณสามารถเพิ่มเพียงไม่กี่บรรทัดในไฟล์ CMakeLists.txt
ของคุณเพื่อรับ CRoaring
release ดูการสาธิตของเราสำหรับรายละเอียดเพิ่มเติม
หากคุณติดตั้งไลบรารี CRoaring ในเครื่อง คุณอาจใช้กับฟังก์ชัน find_package
ของ CMake ได้ดังในตัวอย่างนี้:
cmake_minimum_required ( VERSION 3.15)
project (test_roaring_install VERSION 0.1.0 LANGUAGES CXX C)
set (CMAKE_CXX_STANDARD 11)
set (CMAKE_CXX_STANDARD_REQUIRED ON )
set (CMAKE_C_STANDARD 11)
set (CMAKE_C_STANDARD_REQUIRED ON )
find_package (roaring REQUIRED)
file (WRITE main.cpp "
#include
#include " roaring/roaring.hh "
int main() {
roaring::Roaring r1;
for (uint32_t i = 100; i < 1000; i++) {
r1.add(i);
}
std::cout << " cardinality = " << r1.cardinality() << std::endl;
return 0;
}" )
add_executable (repro main.cpp)
target_link_libraries (repro PUBLIC roaring::roaring)
หากต้องการสร้างไฟล์ที่รวมเข้าด้วยกันด้วยตนเอง คุณสามารถเรียกใช้สคริปต์ทุบตี...
./amalgamation.sh
หากคุณต้องการเอาต์พุตแบบไม่มีการโต้ตอบ คุณสามารถใช้คำสั่งต่อไปนี้เพื่อเปลี่ยนเส้นทาง stdout
:
./amalgamation.sh > /dev/null
(Bash Shells เป็นมาตรฐานสำหรับ Linux และ macOS Bash Shells มีให้ใช้งานภายใต้ Windows โดยเป็นส่วนหนึ่งของ GitHub Desktop ภายใต้ชื่อ Git Shell
ดังนั้น หากคุณได้โคลนพื้นที่เก็บข้อมูล CRoaring
GitHub จากภายใน GitHub Desktop คุณสามารถคลิกขวาที่ CRoaring
ให้เลือก Git Shell
จากนั้นป้อนคำสั่งด้านบน)
ไม่จำเป็นต้องเรียกใช้สคริปต์ในไดเร็กทอรี CRoaring คุณสามารถเรียกใช้จากไดเร็กทอรีใดก็ได้ที่คุณต้องการให้เขียนไฟล์การควบรวม
มันจะสร้างไฟล์สามไฟล์สำหรับผู้ใช้ C: roaring.h
, roaring.c
และ amalgamation_demo.c
... เช่นเดียวกับคำแนะนำสั้น ๆ ไฟล์ amalgamation_demo.c
เป็นตัวอย่างสั้นๆ ในขณะที่ roaring.h
และ roaring.c
เป็นไฟล์ "รวมกัน" (รวมถึงไฟล์ต้นฉบับและส่วนหัวทั้งหมดสำหรับโปรเจ็กต์) ซึ่งหมายความว่าคุณสามารถคัดลอกไฟล์ roaring.h
และ roaring.c
ลงในโปรเจ็กต์ของคุณได้เลย และเตรียมตัวให้พร้อม! ไม่ต้องสร้างห้องสมุด! ดูไฟล์ amalgamation_demo.c
พบอินเทอร์เฟซ C ในไฟล์
เรายังมีอินเทอร์เฟซ C++:
ผู้ใช้บางรายต้องจัดการกับข้อมูลปริมาณมาก อาจเป็นสิ่งสำคัญสำหรับผู้ใช้เหล่านี้ที่จะต้องทราบถึงฟังก์ชัน addMany
(C++) roaring_bitmap_or_many
(C) เนื่องจากจะเพิ่มค่าเป็นชุดได้เร็วกว่าและประหยัดมาก นอกจากนี้ การเรียกฟังก์ชัน runOptimize
(C++) หรือ roaring_bitmap_run_optimize
(C) เป็นระยะๆ อาจช่วยได้
เรามี Microbenchmarks ที่สร้างด้วย Google Benchmarks ภายใต้ Linux หรือ macOS คุณสามารถเรียกใช้ได้ดังต่อไปนี้:
cmake -B build -D ENABLE_ROARING_MICROBENCHMARKS=ON
cmake --build build
./build/microbenchmarks/bench
ตามค่าเริ่มต้น เครื่องมือวัดประสิทธิภาพจะเลือกชุดข้อมูลหนึ่งชุด (เช่น CRoaring/benchmarks/realdata/census1881
) เรามีชุดข้อมูลหลายชุด และคุณสามารถเลือกชุดอื่นได้:
./build/microbenchmarks/bench benchmarks/realdata/wikileaks-noquotes
คุณสามารถปิดการใช้งานฟังก์ชันบางอย่างเพื่อวัตถุประสงค์ในการเปรียบเทียบได้ ตัวอย่างเช่น สมมติว่าคุณมีโปรเซสเซอร์ x64 คุณสามารถเปรียบเทียบโค้ดที่ไม่มี AVX-512 ได้ แม้ว่าทั้งโปรเซสเซอร์และคอมไพเลอร์ของคุณจะรองรับก็ตาม:
cmake -B buildnoavx512 -D ROARING_DISABLE_AVX512=ON -D ENABLE_ROARING_MICROBENCHMARKS=ON
cmake --build buildnoavx512
./buildnoavx512/microbenchmarks/bench
คุณสามารถวัดประสิทธิภาพโดยไม่ต้องใช้ AVX หรือ AVX-512 ได้เช่นกัน:
cmake -B buildnoavx -D ROARING_DISABLE_AVX=ON -D ENABLE_ROARING_MICROBENCHMARKS=ON
cmake --build buildnoavx
./buildnoavx/microbenchmarks/bench
สำหรับผู้ใช้ทั่วไป CRoaring จะใช้ตัวจัดสรรเริ่มต้นโดยไม่มีรหัสเพิ่มเติม แต่ขอเกี่ยวหน่วยความจำส่วนกลางก็มีให้สำหรับผู้ที่ต้องการตัวจัดสรรหน่วยความจำแบบกำหนดเอง นี่คือตัวอย่าง:
#include
int main (){
// define with your own memory hook
roaring_memory_t my_hook { my_malloc , my_free ...};
// initialize global memory hook
roaring_init_memory_hook ( my_hook );
// write you code here
...
}
โดยค่าเริ่มต้นเราใช้:
static roaring_memory_t global_memory_hook = {
. malloc = malloc ,
. realloc = realloc ,
. calloc = calloc ,
. free = free ,
. aligned_malloc = roaring_bitmap_aligned_malloc ,
. aligned_free = roaring_bitmap_aligned_free ,
};
เราต้องการให้ฟังก์ชัน free
/ aligned_free
เป็นไปตามแบบแผน C โดยที่ free(NULL)
/ aligned_free(NULL)
ไม่มีผลกระทบ
ตัวอย่างนี้ถือว่า CRoaring ถูกสร้างขึ้นและคุณกำลังเชื่อมโยงกับไลบรารีที่เกี่ยวข้อง ตามค่าเริ่มต้น CRoaring จะติดตั้งไฟล์ส่วนหัวในไดเรกทอรี roaring
หากคุณกำลังทำงานจากสคริปต์การรวม คุณสามารถเพิ่มบรรทัด #include "roaring.c"
หากคุณไม่ได้เชื่อมโยงกับไลบรารี CRoaring ที่สร้างไว้ล่วงหน้า และแทนที่ #include
ด้วย #include "roaring.h"
.
#include
#include
#include
#include
bool roaring_iterator_sumall ( uint32_t value , void * param ) {
* ( uint32_t * ) param += value ;
return true; // iterate till the end
}
int main () {
// create a new empty bitmap
roaring_bitmap_t * r1 = roaring_bitmap_create ();
// then we can add values
for ( uint32_t i = 100 ; i < 1000 ; i ++ ) roaring_bitmap_add ( r1 , i );
// check whether a value is contained
assert ( roaring_bitmap_contains ( r1 , 500 ));
// compute how many bits there are:
uint32_t cardinality = roaring_bitmap_get_cardinality ( r1 );
printf ( "Cardinality = %d n" , cardinality );
// if your bitmaps have long runs, you can compress them by calling
// run_optimize
uint32_t expectedsizebasic = roaring_bitmap_portable_size_in_bytes ( r1 );
roaring_bitmap_run_optimize ( r1 );
uint32_t expectedsizerun = roaring_bitmap_portable_size_in_bytes ( r1 );
printf ( "size before run optimize %d bytes, and after %d bytesn" ,
expectedsizebasic , expectedsizerun );
// create a new bitmap containing the values {1,2,3,5,6}
roaring_bitmap_t * r2 = roaring_bitmap_from ( 1 , 2 , 3 , 5 , 6 );
roaring_bitmap_printf ( r2 ); // print it
// we can also create a bitmap from a pointer to 32-bit integers
uint32_t somevalues [] = { 2 , 3 , 4 };
roaring_bitmap_t * r3 = roaring_bitmap_of_ptr ( 3 , somevalues );
// we can also go in reverse and go from arrays to bitmaps
uint64_t card1 = roaring_bitmap_get_cardinality ( r1 );
uint32_t * arr1 = ( uint32_t * ) malloc ( card1 * sizeof ( uint32_t ));
assert ( arr1 != NULL );
roaring_bitmap_to_uint32_array ( r1 , arr1 );
roaring_bitmap_t * r1f = roaring_bitmap_of_ptr ( card1 , arr1 );
free ( arr1 );
assert ( roaring_bitmap_equals ( r1 , r1f )); // what we recover is equal
roaring_bitmap_free ( r1f );
// we can go from arrays to bitmaps from "offset" by "limit"
size_t offset = 100 ;
size_t limit = 1000 ;
uint32_t * arr3 = ( uint32_t * ) malloc ( limit * sizeof ( uint32_t ));
assert ( arr3 != NULL );
roaring_bitmap_range_uint32_array ( r1 , offset , limit , arr3 );
free ( arr3 );
// we can copy and compare bitmaps
roaring_bitmap_t * z = roaring_bitmap_copy ( r3 );
assert ( roaring_bitmap_equals ( r3 , z )); // what we recover is equal
roaring_bitmap_free ( z );
// we can compute union two-by-two
roaring_bitmap_t * r1_2_3 = roaring_bitmap_or ( r1 , r2 );
roaring_bitmap_or_inplace ( r1_2_3 , r3 );
// we can compute a big union
const roaring_bitmap_t * allmybitmaps [] = { r1 , r2 , r3 };
roaring_bitmap_t * bigunion = roaring_bitmap_or_many ( 3 , allmybitmaps );
assert (
roaring_bitmap_equals ( r1_2_3 , bigunion )); // what we recover is equal
// can also do the big union with a heap
roaring_bitmap_t * bigunionheap =
roaring_bitmap_or_many_heap ( 3 , allmybitmaps );
assert ( roaring_bitmap_equals ( r1_2_3 , bigunionheap ));
roaring_bitmap_free ( r1_2_3 );
roaring_bitmap_free ( bigunion );
roaring_bitmap_free ( bigunionheap );
// we can compute intersection two-by-two
roaring_bitmap_t * i1_2 = roaring_bitmap_and ( r1 , r2 );
roaring_bitmap_free ( i1_2 );
// we can write a bitmap to a pointer and recover it later
uint32_t expectedsize = roaring_bitmap_portable_size_in_bytes ( r1 );
char * serializedbytes = malloc ( expectedsize );
// When serializing data to a file, we recommend that you also use
// checksums so that, at deserialization, you can be confident
// that you are recovering the correct data.
roaring_bitmap_portable_serialize ( r1 , serializedbytes );
// Note: it is expected that the input follows the specification
// https://github.com/RoaringBitmap/RoaringFormatSpec
// otherwise the result may be unusable.
// The 'roaring_bitmap_portable_deserialize_safe' function will not read
// beyond expectedsize bytes.
// We also recommend that you use checksums to check that serialized data corresponds
// to the serialized bitmap. The CRoaring library does not provide checksumming.
roaring_bitmap_t * t = roaring_bitmap_portable_deserialize_safe ( serializedbytes , expectedsize );
if ( t == NULL ) { return EXIT_FAILURE ; }
const char * reason = NULL ;
// If your input came from an untrusted source, then you need to validate the
// resulting bitmap. Failing to do so could lead to undefined behavior, crashes and so forth.
if (! roaring_bitmap_internal_validate ( t , & reason )) {
return EXIT_FAILURE ;
}
// At this point, the bitmap is safe.
assert ( roaring_bitmap_equals ( r1 , t )); // what we recover is equal
roaring_bitmap_free ( t );
// we can also check whether there is a bitmap at a memory location without
// reading it
size_t sizeofbitmap =
roaring_bitmap_portable_deserialize_size ( serializedbytes , expectedsize );
assert ( sizeofbitmap ==
expectedsize ); // sizeofbitmap would be zero if no bitmap were found
// We can also read the bitmap "safely" by specifying a byte size limit.
// The 'roaring_bitmap_portable_deserialize_safe' function will not read
// beyond expectedsize bytes.
// We also recommend that you use checksums to check that serialized data corresponds
// to the serialized bitmap. The CRoaring library does not provide checksumming.
t = roaring_bitmap_portable_deserialize_safe ( serializedbytes , expectedsize );
if ( t == NULL ) {
printf ( "Problem during deserialization.n" );
// We could clear any memory and close any file here.
return EXIT_FAILURE ;
}
// We can validate the bitmap we recovered to make sure it is proper.
// If the data came from an untrusted source, you should call
// roaring_bitmap_internal_validate.
const char * reason_failure = NULL ;
if (! roaring_bitmap_internal_validate ( t , & reason_failure )) {
printf ( "safely deserialized invalid bitmap: %sn" , reason_failure );
// We could clear any memory and close any file here.
return EXIT_FAILURE ;
}
assert ( roaring_bitmap_equals ( r1 , t )); // what we recover is equal
roaring_bitmap_free ( t );
free ( serializedbytes );
// we can iterate over all values using custom functions
uint32_t counter = 0 ;
roaring_iterate ( r1 , roaring_iterator_sumall , & counter );
// we can also create iterator structs
counter = 0 ;
roaring_uint32_iterator_t * i = roaring_iterator_create ( r1 );
while ( i -> has_value ) {
counter ++ ; // could use i->current_value
roaring_uint32_iterator_advance ( i );
}
// you can skip over values and move the iterator with
// roaring_uint32_iterator_move_equalorlarger(i,someintvalue)
roaring_uint32_iterator_free ( i );
// roaring_bitmap_get_cardinality(r1) == counter
// for greater speed, you can iterate over the data in bulk
i = roaring_iterator_create ( r1 );
uint32_t buffer [ 256 ];
while ( 1 ) {
uint32_t ret = roaring_uint32_iterator_read ( i , buffer , 256 );
for ( uint32_t j = 0 ; j < ret ; j ++ ) {
counter += buffer [ j ];
}
if ( ret < 256 ) {
break ;
}
}
roaring_uint32_iterator_free ( i );
roaring_bitmap_free ( r1 );
roaring_bitmap_free ( r2 );
roaring_bitmap_free ( r3 );
return EXIT_SUCCESS ;
}
นอกจากนี้เรายังสนับสนุนบิตแมปที่บีบอัด 64 บิตที่มีประสิทธิภาพใน C:
roaring64_bitmap_t *r2 = roaring64_bitmap_create();
for ( uint64_t i = 100 ; i < 1000 ; i++) roaring64_bitmap_add(r2, i);
printf ( " cardinality (64-bit) = %d n " , ( int ) roaring64_bitmap_get_cardinality(r2));
roaring64_bitmap_free (r2);
API นั้นคล้ายคลึงกับบิตแมป 32 บิตทั่วไป โปรดดูไฟล์ส่วนหัว roaring64.h
(เปรียบเทียบกับ roaring.h
)
เราสนับสนุนบิตเซ็ตแบบแผน (ไม่บีบอัด) โดยเป็นส่วนหนึ่งของไลบรารี
ตัวอย่างง่ายๆ:
bitset_t * b = bitset_create ();
bitset_set ( b , 10 );
bitset_get ( b , 10 ); // returns true
bitset_free ( b ); // frees memory
ตัวอย่างขั้นสูงเพิ่มเติม:
bitset_t * b = bitset_create ();
for ( int k = 0 ; k < 1000 ; ++ k ) {
bitset_set ( b , 3 * k );
}
// We have bitset_count(b) == 1000.
// We have bitset_get(b, 3) is true
// You can iterate through the values:
size_t k = 0 ;
for ( size_t i = 0 ; bitset_next_set_bit ( b , & i ); i ++ ) {
// You will have i == k
k += 3 ;
}
// We support a wide range of operations on two bitsets such as
// bitset_inplace_symmetric_difference(b1,b2);
// bitset_inplace_symmetric_difference(b1,b2);
// bitset_inplace_difference(b1,b2);// should make no difference
// bitset_inplace_union(b1,b2);
// bitset_inplace_intersection(b1,b2);
// bitsets_disjoint
// bitsets_intersect
ในบางกรณี คุณอาจต้องการแปลงบิตแมป Roaring ให้เป็นบิตเซ็ตธรรมดา (ไม่มีการบีบอัด) แท้จริงแล้ว บิตเซ็ตมีข้อดี เช่น ประสิทธิภาพการสืบค้นที่สูงกว่าในบางกรณี รหัสต่อไปนี้แสดงวิธีที่คุณสามารถทำได้:
roaring_bitmap_t * r1 = roaring_bitmap_create ();
for ( uint32_t i = 100 ; i < 100000 ; i += 1 + ( i % 5 )) {
roaring_bitmap_add ( r1 , i );
}
for ( uint32_t i = 100000 ; i < 500000 ; i += 100 ) {
roaring_bitmap_add ( r1 , i );
}
roaring_bitmap_add_range ( r1 , 500000 , 600000 );
bitset_t * bitset = bitset_create ();
bool success = roaring_bitmap_to_bitset ( r1 , bitset );
assert ( success ); // could fail due to memory allocation.
assert ( bitset_count ( bitset ) == roaring_bitmap_get_cardinality ( r1 ));
// You can then query the bitset:
for ( uint32_t i = 100 ; i < 100000 ; i += 1 + ( i % 5 )) {
assert ( bitset_get ( bitset , i ));
}
for ( uint32_t i = 100000 ; i < 500000 ; i += 100 ) {
assert ( bitset_get ( bitset , i ));
}
// you must free the memory:
bitset_free ( bitset );
roaring_bitmap_free ( r1 );
คุณควรทราบว่าบิตเซ็ตแบบแผน ( bitset_t *
) อาจใช้หน่วยความจำมากกว่าบิตแมป Roaring ในบางกรณี คุณควรเรียกใช้การวัดประสิทธิภาพเพื่อพิจารณาว่าการแปลงเป็นบิตเซ็ตมีประโยชน์ด้านประสิทธิภาพในกรณีของคุณหรือไม่
ตัวอย่างนี้ถือว่า CRoaring ถูกสร้างขึ้นและคุณกำลังเชื่อมโยงกับไลบรารีที่เกี่ยวข้อง ตามค่าเริ่มต้น CRoaring จะติดตั้งไฟล์ส่วนหัวในไดเรกทอรี roaring
ดังนั้นคุณอาจต้องแทนที่ #include "roaring.hh"
ด้วย #include
หากคุณกำลังทำงานจากสคริปต์การควบรวม คุณสามารถเพิ่มบรรทัด #include "roaring.c"
หากคุณไม่ได้เชื่อมโยงกับไลบรารีที่สร้างไว้ล่วงหน้าของ CRoaring
# include < iostream >
# include " roaring.hh "
using namespace roaring ;
int main () {
Roaring r1;
for ( uint32_t i = 100 ; i < 1000 ; i++) {
r1. add (i);
}
// check whether a value is contained
assert (r1. contains ( 500 ));
// compute how many bits there are:
uint32_t cardinality = r1. cardinality ();
// if your bitmaps have long runs, you can compress them by calling
// run_optimize
uint32_t size = r1. getSizeInBytes ();
r1. runOptimize ();
// you can enable "copy-on-write" for fast and shallow copies
r1. setCopyOnWrite ( true );
uint32_t compact_size = r1. getSizeInBytes ();
std::cout << " size before run optimize " << size << " bytes, and after "
<< compact_size << " bytes. " << std::endl;
// create a new bitmap with varargs
Roaring r2 = Roaring::bitmapOf ( 5 , 1 , 2 , 3 , 5 , 6 );
r2. printf ();
printf ( " n " );
// create a new bitmap with initializer list
Roaring r2i = Roaring::bitmapOfList ({ 1 , 2 , 3 , 5 , 6 });
assert (r2i == r2);
// we can also create a bitmap from a pointer to 32-bit integers
const uint32_t values[] = { 2 , 3 , 4 };
Roaring r3 ( 3 , values);
// we can also go in reverse and go from arrays to bitmaps
uint64_t card1 = r1. cardinality ();
uint32_t *arr1 = new uint32_t [card1];
r1. toUint32Array (arr1);
Roaring r1f (card1, arr1);
delete[] arr1;
// bitmaps shall be equal
assert (r1 == r1f);
// we can copy and compare bitmaps
Roaring z (r3);
assert (r3 == z);
// we can compute union two-by-two
Roaring r1_2_3 = r1 | r2;
r1_2_3 |= r3;
// we can compute a big union
const Roaring *allmybitmaps[] = {&r1, &r2, &r3};
Roaring bigunion = Roaring::fastunion ( 3 , allmybitmaps);
assert (r1_2_3 == bigunion);
// we can compute intersection two-by-two
Roaring i1_2 = r1 & r2;
// we can write a bitmap to a pointer and recover it later
uint32_t expectedsize = r1. getSizeInBytes ();
char *serializedbytes = new char [expectedsize];
r1. write (serializedbytes);
// readSafe will not overflow, but the resulting bitmap
// is only valid and usable if the input follows the
// Roaring specification: https://github.com/RoaringBitmap/RoaringFormatSpec/
Roaring t = Roaring::readSafe (serializedbytes, expectedsize);
assert (r1 == t);
delete[] serializedbytes;
// we can iterate over all values using custom functions
uint32_t counter = 0 ;
r1.iterate(
[]( uint32_t value, void *param) {
*( uint32_t *)param += value;
return true ;
},
&counter);
// we can also iterate the C++ way
counter = 0 ;
for (Roaring::const_iterator i = t. begin (); i != t. end (); i++) {
++counter;
}
// counter == t.cardinality()
// we can move iterators to skip values
const uint32_t manyvalues[] = { 2 , 3 , 4 , 7 , 8 };
Roaring rogue ( 5 , manyvalues);
Roaring::const_iterator j = rogue. begin ();
j. equalorlarger ( 4 ); // *j == 4
return EXIT_SUCCESS;
}
CRoaring เป็นไปตามเวิร์กโฟลว์ cmake มาตรฐาน เริ่มต้นจากไดเร็กทอรีรากของโครงการ (CRoaring) คุณสามารถทำ:
mkdir -p build
cd build
cmake ..
cmake --build .
# follow by 'ctest' if you want to test.
# you can also type 'make install' to install the library on your system
# C header files typically get installed to /usr/local/include/roaring
# whereas C++ header files get installed to /usr/local/include/roaring
(คุณสามารถแทนที่ไดเร็กทอรี build
ด้วยชื่อไดเร็กทอรีอื่นได้) ตามค่าเริ่มต้น การทดสอบทั้งหมดถูกสร้างขึ้นบนทุกแพลตฟอร์ม หากต้องการข้ามการสร้างและรันการทดสอบ ให้เพิ่ม -DENABLE_ROARING_TESTS=OFF
ลงในบรรทัดคำสั่ง
เช่นเดียวกับโปรเจ็กต์ cmake
ทั้งหมด คุณสามารถระบุคอมไพเลอร์ที่คุณต้องการใช้โดยการเพิ่ม (ตัวอย่าง) -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
เข้ากับบรรทัดรับคำสั่ง cmake
หากคุณใช้ clang หรือ gcc และคุณทราบสถาปัตยกรรมเป้าหมายของคุณ คุณสามารถตั้งค่าสถาปัตยกรรมได้โดยการระบุ -DROARING_ARCH=arch
ตัวอย่างเช่น หากคุณมีเซิร์ฟเวอร์จำนวนมาก แต่เซิร์ฟเวอร์ที่เก่าแก่ที่สุดใช้สถาปัตยกรรม Intel haswell
คุณสามารถระบุ - DROARING_ARCH=haswell
ในกรณีเช่นนี้ ไบนารีที่สร้างขึ้นจะได้รับการปรับให้เหมาะสมสำหรับโปรเซสเซอร์ที่มีคุณลักษณะของกระบวนการแฮสเวลล์ และอาจไม่สามารถทำงานบนสถาปัตยกรรมรุ่นเก่าได้ คุณสามารถค้นหารายการค่าสถาปัตยกรรมที่ถูกต้องได้โดยพิมพ์ man gcc
mkdir -p build_haswell
cd build_haswell
cmake -DROARING_ARCH=haswell ..
cmake --build .
สำหรับการเปิดตัวแก้ไขข้อบกพร่อง เริ่มต้นจากไดเร็กทอรีรากของโครงการ (CRoaring) ให้ลอง
mkdir -p debug
cd debug
cmake -DCMAKE_BUILD_TYPE=Debug -DROARING_SANITIZE=ON ..
ctest
หากต้องการตรวจสอบว่าโค้ดของคุณเป็นไปตามแบบแผน (ตรวจสอบให้แน่ใจว่าได้ติดตั้ง clang-format
):
./tools/clang-format-check.sh
หากต้องการฟอร์แมตโค้ดของคุณใหม่ตามแบบแผน (ตรวจสอบให้แน่ใจว่าได้ติดตั้ง clang-format
):
./tools/clang-format.sh
เรากำลังสมมติว่าคุณมีพีซี Windows ทั่วไปที่มี Visual Studio 2015 เป็นอย่างน้อยและโปรเซสเซอร์ x64
หากต้องการสร้างด้วย Visual Studio 2015 เป็นอย่างน้อยจากบรรทัดคำสั่ง:
cmake
พร้อมใช้งานจากบรรทัดคำสั่งVisualStudio
CRoaring
ในรายการพื้นที่เก็บข้อมูล GitHub ของคุณ แล้วเลือก Open in Git Shell
จากนั้นพิมพ์ cd VisualStudio
ในเชลล์ที่สร้างขึ้นใหม่cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..
ในเชลล์ขณะอยู่ในที่เก็บ VisualStudio
(หรืออีกทางหนึ่ง หากคุณต้องการสร้างไลบรารีแบบสแตติก คุณอาจใช้บรรทัดคำสั่ง cmake -DCMAKE_GENERATOR_PLATFORM=x64 -DROARING_BUILD_STATIC=ON ..
.)RoaringBitmap.sln
) เปิดไฟล์นี้ใน Visual Studio ตอนนี้คุณควรจะสามารถสร้างโปรเจ็กต์และดำเนินการทดสอบได้แล้ว ตัวอย่างเช่น ในหน้าต่าง Solution Explorer
(มีให้จากเมนู View
) ให้คลิกขวาที่ ALL_BUILD
และเลือก Build
หากต้องการทดสอบโค้ด ยังอยู่ในหน้าต่าง Solution Explorer
ให้เลือก RUN_TESTS
และเลือก Build
วิธีสร้างด้วย Visual Studio 2017 เป็นอย่างน้อยโดยตรงใน IDE:
Visual C++ tools for CMake
เมื่อติดตั้งปริมาณงานการพัฒนา C++ ภายใน Visual StudioFile > Open > Folder...
เพื่อเปิดโฟลเดอร์ CRoaringCMakeLists.txt
ในไดเร็กทอรีพาเรนต์ภายใน Solution Explorer
และเลือก Build
เพื่อสร้างโปรเจ็กต์Select Startup Item...
และเลือกการทดสอบรายการใดรายการหนึ่ง รันการทดสอบโดยกดปุ่มทางด้านซ้ายของเมนูแบบเลื่อนลงเรามีการเพิ่มประสิทธิภาพเฉพาะสำหรับ AVX2 และ AVX-512 ในโค้ด และจะมีการเปิดแบบไดนามิกตามฮาร์ดแวร์ที่ตรวจพบในขณะรันไทม์
conan
) คุณสามารถติดตั้งไบนารีที่สร้างไว้ล่วงหน้าสำหรับ roaring
หรือสร้างจากแหล่งที่มาโดยใช้ Conan ใช้คำสั่งต่อไปนี้เพื่อติดตั้งเวอร์ชันล่าสุด:
conan install --requires="roaring/[*]" --build=missing
สำหรับคำแนะนำโดยละเอียดเกี่ยวกับวิธีใช้ Conan โปรดดูเอกสารประกอบของ Conan
สูตรโคนัน roaring
ได้รับการปรับปรุงให้ทันสมัยโดยผู้ดูแลโคนันและผู้ร่วมให้ข้อมูลในชุมชน หากเวอร์ชันล้าสมัย โปรดสร้างปัญหาหรือดึงคำขอบนที่เก็บ ConanCenterIndex
vcpkg
บน Windows, Linux และ macOS) ผู้ใช้ vcpkg บน Windows, Linux และ macOS สามารถดาวน์โหลดและติดตั้ง roaring
ด้วยคำสั่งเดียวจากเชลล์ที่พวกเขาชื่นชอบ
บน Linux และ macOS:
$ ./vcpkg install roaring
จะสร้างและติดตั้ง roaring
เป็นไลบรารีแบบคงที่
บน Windows (64 บิต):
.vcpkg.exe install roaring:x64-windows
จะสร้างและติดตั้ง roaring
เป็นไลบรารีที่ใช้ร่วมกัน
.vcpkg.exe install roaring:x64-windows-static
จะสร้างและติดตั้ง roaring
เป็นไลบรารีแบบคงที่
คำสั่งเหล่านี้จะพิมพ์คำแนะนำเกี่ยวกับวิธีการใช้ไลบรารีจากโครงการ MSBuild หรือ CMake
หากคุณพบว่าเวอร์ชันของ roaring
ที่มาพร้อมกับ vcpkg
นั้นล้าสมัย คุณสามารถรายงานไปยังชุมชน vcpkg
ได้โดยการส่งปัญหาหรือโดยการสร้าง PR
รหัส AVX2 ของเราไม่ได้ใช้ตัวเลขทศนิยมหรือการคูณ ดังนั้นจึงไม่ต้องควบคุมความถี่เทอร์โบบนโปรเซสเซอร์ Intel แบบหลายคอร์
รหัส AVX-512 ของเราเปิดใช้งานได้บนฮาร์ดแวร์ล่าสุดเท่านั้น (Intel Ice Lake หรือดีกว่าและ AMD Zen 4) ซึ่งไม่พบการควบคุมความถี่เฉพาะ SIMD
เช่นเดียวกับ ตัวอย่างเช่น คอนเทนเนอร์ STL ไลบรารี CRoaring ไม่มีการสนับสนุนเธรดในตัว ดังนั้นเมื่อใดก็ตามที่คุณแก้ไขบิตแมปในเธรดหนึ่ง จึงไม่ปลอดภัยที่จะสอบถามบิตแมปนั้นในเธรดอื่น อย่างไรก็ตาม คุณสามารถคัดลอกบิตแมปได้อย่างปลอดภัยและใช้ทั้งสองสำเนาได้