diff --git a/README.md b/README.md index 3e8b3c1..43ff024 100644 --- a/README.md +++ b/README.md @@ -100,23 +100,31 @@ for i in bitmap { You can build using Swift Package Manager as follows: -```bash +```bash swift build --configuration release -$(swift build --configuration release --show-bin-path)/fun ``` +To find where the library is built, type the following +in your shell: +```bash + echo $(swift build --configuration release --show-bin-path) +``` + You can run tests using Swift Package Manager as follows: -```bash +```bash swift test ``` ### Interactive use ``` -$ swift build -Xcc -march=native --configuration release -$ swift -I .build/release -L .build/release -lSwiftRoaringDynamic +$ swift build --configuration release +$ swift repl -I .build/release -L .build/release -lSwiftRoaringDynamic 1> import SwiftRoaring 2> let bitmap = RoaringBitmap() 3> bitmap.add(1) + 4> for i in bitmap { + print(i) + } ``` ### Mailing list/discussion group diff --git a/Sources/CRoaring/include/roaring.h b/Sources/CRoaring/include/roaring.h index 69bfd55..3bab893 100644 --- a/Sources/CRoaring/include/roaring.h +++ b/Sources/CRoaring/include/roaring.h @@ -1,8 +1,12 @@ // !!! DO NOT EDIT - THIS IS AN AUTO-GENERATED FILE !!! -// Created by amalgamation.sh on Wed 8 Jun 2022 15:13:10 EDT +// Created by amalgamation.sh on 2022-11-11T14:36:13Z /* - * Copyright 2016-2020 The CRoaring authors + * The CRoaring project is under a dual license (Apache/MIT). + * Users of the library may choose one or the other license. + */ +/* + * Copyright 2016-2022 The CRoaring authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,16 +22,47 @@ * * SPDX-License-Identifier: Apache-2.0 */ +/* + * MIT License + * + * Copyright 2016-2022 The CRoaring authors + * + * Permission is hereby granted, free of charge, to any + * person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without + * limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice + * shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ /* begin file include/roaring/roaring_version.h */ // /include/roaring/roaring_version.h automatically generated by release.py, do not change by hand #ifndef ROARING_INCLUDE_ROARING_VERSION #define ROARING_INCLUDE_ROARING_VERSION -#define ROARING_VERSION "0.5.0" +#define ROARING_VERSION "0.7.3" enum { ROARING_VERSION_MAJOR = 0, - ROARING_VERSION_MINOR = 5, - ROARING_VERSION_REVISION = 0 + ROARING_VERSION_MINOR = 7, + ROARING_VERSION_REVISION = 3 }; #endif // ROARING_INCLUDE_ROARING_VERSION /* end file include/roaring/roaring_version.h */ @@ -394,9 +429,48 @@ void roaring_bitmap_andnot_inplace(roaring_bitmap_t *r1, */ void roaring_bitmap_free(const roaring_bitmap_t *r); +/** + * A bit of context usable with `roaring_bitmap_*_bulk()` functions + * + * Should be initialized with `{0}` (or `memset()` to all zeros). + * Callers should treat it as an opaque type. + * + * A context may only be used with a single bitmap + * (unless re-initialized to zero), and any modification to a bitmap + * (other than modifications performed with `_bulk()` functions with the context + * passed) will invalidate any contexts associated with that bitmap. + */ +typedef struct roaring_bulk_context_s { + ROARING_CONTAINER_T *container; + int idx; + uint16_t key; + uint8_t typecode; +} roaring_bulk_context_t; + +/** + * Add an item, using context from a previous insert for speed optimization. + * + * `context` will be used to store information between calls to make bulk + * operations faster. `*context` should be zero-initialized before the first + * call to this function. + * + * Modifying the bitmap in any way (other than `-bulk` suffixed functions) + * will invalidate the stored context, calling this function with a non-zero + * context after doing any modification invokes undefined behavior. + * + * In order to exploit this optimization, the caller should call this function + * with values with the same "key" (high 16 bits of the value) consecutively. + */ +void roaring_bitmap_add_bulk(roaring_bitmap_t *r, + roaring_bulk_context_t *context, uint32_t val); + /** * Add value n_args from pointer vals, faster than repeatedly calling * `roaring_bitmap_add()` + * + * In order to exploit this optimization, the caller should attempt to keep + * values with the same "key" (high 16 bits of the value) as consecutive + * elements in `vals` */ void roaring_bitmap_add_many(roaring_bitmap_t *r, size_t n_args, const uint32_t *vals); @@ -472,6 +546,25 @@ bool roaring_bitmap_contains_range(const roaring_bitmap_t *r, uint64_t range_start, uint64_t range_end); +/** + * Check if an items is present, using context from a previous insert for speed + * optimization. + * + * `context` will be used to store information between calls to make bulk + * operations faster. `*context` should be zero-initialized before the first + * call to this function. + * + * Modifying the bitmap in any way (other than `-bulk` suffixed functions) + * will invalidate the stored context, calling this function with a non-zero + * context after doing any modification invokes undefined behavior. + * + * In order to exploit this optimization, the caller should call this function + * with values with the same "key" (high 16 bits of the value) consecutively. + */ +bool roaring_bitmap_contains_bulk(const roaring_bitmap_t *r, + roaring_bulk_context_t *context, + uint32_t val); + /** * Get the cardinality of the bitmap (number of elements). */ @@ -951,7 +1044,6 @@ uint32_t roaring_read_uint32_iterator(roaring_uint32_iterator_t *it, using namespace ::roaring::api; #endif #endif - /* end file include/roaring/roaring.h */ /* begin file include/roaring/memory.h */ #ifndef INCLUDE_ROARING_MEMORY_H_ diff --git a/Sources/CRoaring/roaring.c b/Sources/CRoaring/roaring.c index 1548be3..b7e7b90 100644 --- a/Sources/CRoaring/roaring.c +++ b/Sources/CRoaring/roaring.c @@ -1,8 +1,12 @@ // !!! DO NOT EDIT - THIS IS AN AUTO-GENERATED FILE !!! -// Created by amalgamation.sh on Wed 8 Jun 2022 15:13:10 EDT +// Created by amalgamation.sh on 2022-11-11T14:36:13Z /* - * Copyright 2016-2020 The CRoaring authors + * The CRoaring project is under a dual license (Apache/MIT). + * Users of the library may choose one or the other license. + */ +/* + * Copyright 2016-2022 The CRoaring authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +22,37 @@ * * SPDX-License-Identifier: Apache-2.0 */ +/* + * MIT License + * + * Copyright 2016-2022 The CRoaring authors + * + * Permission is hereby granted, free of charge, to any + * person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without + * limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software + * is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice + * shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ #include "roaring.h" @@ -27,252 +62,48 @@ #endif #include "roaring.h" /* include public API definitions */ -/* begin file include/roaring/isadetection.h */ -/* From -https://github.com/endorno/pytorch/blob/master/torch/lib/TH/generic/simd/simd.h -Highly modified. - -Copyright (c) 2016- Facebook, Inc (Adam Paszke) -Copyright (c) 2014- Facebook, Inc (Soumith Chintala) -Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) -Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) -Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) -Copyright (c) 2011-2013 NYU (Clement Farabet) -Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, -Iain Melvin, Jason Weston) Copyright (c) 2006 Idiap Research Institute -(Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, -Samy Bengio, Johnny Mariethoz) - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories -America and IDIAP Research Institute nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef ROARING_ISADETECTION_H -#define ROARING_ISADETECTION_H - -#include -#include -#include -#if defined(_MSC_VER) -#include -#elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) -#include -#endif // defined(_MSC_VER) - - -enum croaring_instruction_set { - CROARING_DEFAULT = 0x0, - CROARING_NEON = 0x1, - CROARING_AVX2 = 0x4, - CROARING_SSE42 = 0x8, - CROARING_PCLMULQDQ = 0x10, - CROARING_BMI1 = 0x20, - CROARING_BMI2 = 0x40, - CROARING_ALTIVEC = 0x80, - CROARING_UNINITIALIZED = 0x8000 -}; - -#if defined(__PPC64__) - -static inline uint32_t dynamic_croaring_detect_supported_architectures() { - return CROARING_ALTIVEC; -} - -#elif defined(__arm__) || defined(__aarch64__) // incl. armel, armhf, arm64 - -#if defined(__ARM_NEON) - -static inline uint32_t dynamic_croaring_detect_supported_architectures() { - return CROARING_NEON; -} - -#else // ARM without NEON - -static inline uint32_t dynamic_croaring_detect_supported_architectures() { - return CROARING_DEFAULT; -} - -#endif - -#elif defined(__x86_64__) || defined(_M_AMD64) // x64 - - - - -static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, - uint32_t *edx) { - -#if defined(_MSC_VER) - int cpu_info[4]; - __cpuid(cpu_info, *eax); - *eax = cpu_info[0]; - *ebx = cpu_info[1]; - *ecx = cpu_info[2]; - *edx = cpu_info[3]; -#elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) - uint32_t level = *eax; - __get_cpuid(level, eax, ebx, ecx, edx); -#else - uint32_t a = *eax, b, c = *ecx, d; - __asm__("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); - *eax = a; - *ebx = b; - *ecx = c; - *edx = d; -#endif -} - -static inline uint32_t dynamic_croaring_detect_supported_architectures() { - uint32_t eax, ebx, ecx, edx; - uint32_t host_isa = 0x0; - // Can be found on Intel ISA Reference for CPUID - static uint32_t cpuid_avx2_bit = 1 << 5; ///< @private Bit 5 of EBX for EAX=0x7 - static uint32_t cpuid_bmi1_bit = 1 << 3; ///< @private bit 3 of EBX for EAX=0x7 - static uint32_t cpuid_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7 - static uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1 - static uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1 - // ECX for EAX=0x7 - eax = 0x7; - ecx = 0x0; - cpuid(&eax, &ebx, &ecx, &edx); - if (ebx & cpuid_avx2_bit) { - host_isa |= CROARING_AVX2; - } - if (ebx & cpuid_bmi1_bit) { - host_isa |= CROARING_BMI1; - } - - if (ebx & cpuid_bmi2_bit) { - host_isa |= CROARING_BMI2; - } - - // EBX for EAX=0x1 - eax = 0x1; - cpuid(&eax, &ebx, &ecx, &edx); - - if (ecx & cpuid_sse42_bit) { - host_isa |= CROARING_SSE42; - } - - if (ecx & cpuid_pclmulqdq_bit) { - host_isa |= CROARING_PCLMULQDQ; - } - - return host_isa; -} -#else // fallback - - -static inline uint32_t dynamic_croaring_detect_supported_architectures() { - return CROARING_DEFAULT; -} - - -#endif // end SIMD extension detection code - - -#if defined(__x86_64__) || defined(_M_AMD64) // x64 - -#if defined(__cplusplus) -#include -static inline uint32_t croaring_detect_supported_architectures() { - static std::atomic buffer{CROARING_UNINITIALIZED}; - if(buffer == CROARING_UNINITIALIZED) { - buffer = dynamic_croaring_detect_supported_architectures(); - } - return buffer; -} -#elif defined(_MSC_VER) && !defined(__clang__) -// Visual Studio does not support C11 atomics. -static inline uint32_t croaring_detect_supported_architectures() { - static int buffer = CROARING_UNINITIALIZED; - if(buffer == CROARING_UNINITIALIZED) { - buffer = dynamic_croaring_detect_supported_architectures(); - } - return buffer; -} -#else // defined(__cplusplus) and defined(_MSC_VER) && !defined(__clang__) -#include -static inline uint32_t croaring_detect_supported_architectures() { - static _Atomic int buffer = CROARING_UNINITIALIZED; - if(buffer == CROARING_UNINITIALIZED) { - buffer = dynamic_croaring_detect_supported_architectures(); - } - return buffer; -} -#endif // defined(_MSC_VER) && !defined(__clang__) - -#ifdef ROARING_DISABLE_AVX -static inline bool croaring_avx2() { - return false; -} -#elif defined(__AVX2__) -static inline bool croaring_avx2() { - return true; -} -#else -static inline bool croaring_avx2() { - return (croaring_detect_supported_architectures() & CROARING_AVX2) == CROARING_AVX2; -} -#endif - - -#else // defined(__x86_64__) || defined(_M_AMD64) // x64 - -static inline bool croaring_avx2() { - return false; -} - -static inline uint32_t croaring_detect_supported_architectures() { - // no runtime dispatch - return dynamic_croaring_detect_supported_architectures(); -} -#endif // defined(__x86_64__) || defined(_M_AMD64) // x64 - -#endif // ROARING_ISADETECTION_H -/* end file include/roaring/isadetection.h */ /* begin file include/roaring/portability.h */ /* * portability.h * */ + /** + * All macros should be prefixed with either CROARING or ROARING. + * The library uses both ROARING_... + * as well as CROAIRING_ as prefixes. The ROARING_ prefix is for + * macros that are provided by the build system or that are closely + * related to the format. The header macros may also use ROARING_. + * The CROARING_ prefix is for internal macros that a user is unlikely + * to ever interact with. + */ + #ifndef INCLUDE_PORTABILITY_H_ #define INCLUDE_PORTABILITY_H_ #ifndef _GNU_SOURCE -#define _GNU_SOURCE +#define _GNU_SOURCE 1 #endif // _GNU_SOURCE #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS 1 #endif // __STDC_FORMAT_MACROS +#ifdef _MSC_VER +#define CROARING_VISUAL_STUDIO 1 +/** + * We want to differentiate carefully between + * clang under visual studio and regular visual + * studio. + */ +#ifdef __clang__ +// clang under visual studio +#define CROARING_CLANG_VISUAL_STUDIO 1 +#else +// just regular visual studio (best guess) +#define CROARING_REGULAR_VISUAL_STUDIO 1 +#endif // __clang__ +#endif // _MSC_VER + #if !(defined(_POSIX_C_SOURCE)) || (_POSIX_C_SOURCE < 200809L) #define _POSIX_C_SOURCE 200809L #endif // !(defined(_POSIX_C_SOURCE)) || (_POSIX_C_SOURCE < 200809L) @@ -291,7 +122,7 @@ static inline uint32_t croaring_detect_supported_architectures() { extern "C" { // portability definitions are in global scope, not a namespace #endif -#if defined(_MSC_VER) && !defined(__clang__) && !defined(_WIN64) && !defined(ROARING_ACK_32BIT) +#if CROARING_REGULAR_VISUAL_STUDIO && !defined(_WIN64) && !defined(CROARING_ACK_32BIT) #pragma message( \ "You appear to be attempting a 32-bit build under Visual Studio. We recommend a 64-bit build instead.") #endif @@ -300,15 +131,15 @@ extern "C" { // portability definitions are in global scope, not a namespace #error This code assumes 64-bit long longs (by use of the GCC intrinsics). Your system is not currently supported. #endif -#if defined(_MSC_VER) +#if CROARING_REGULAR_VISUAL_STUDIO #define __restrict__ __restrict -#endif // defined(_MSC_VER +#endif // CROARING_REGULAR_VISUAL_STUDIO #if defined(__x86_64__) || defined(_M_X64) // we have an x64 processor -#define CROARING_IS_X64 +#define CROARING_IS_X64 1 #if defined(_MSC_VER) && (_MSC_VER < 1910) // Old visual studio systems won't support AVX2 well. @@ -321,14 +152,51 @@ extern "C" { // portability definitions are in global scope, not a namespace #undef CROARING_IS_X64 #endif -#ifdef ROARING_DISABLE_X64 +#ifdef CROARING_DISABLE_X64 #undef CROARING_IS_X64 #endif // we include the intrinsic header -#ifndef _MSC_VER +#if !CROARING_REGULAR_VISUAL_STUDIO /* Non-Microsoft C/C++-compatible compiler */ #include // on some recent GCC, this will declare posix_memalign -#endif // _MSC_VER + + + +#ifdef CROARING_CLANG_VISUAL_STUDIO + +/** + * You are not supposed, normally, to include these + * headers directly. Instead you should either include intrin.h + * or x86intrin.h. However, when compiling with clang + * under Windows (i.e., when _MSC_VER is set), these headers + * only get included *if* the corresponding features are detected + * from macros: + * e.g., if __AVX2__ is set... in turn, we normally set these + * macros by compiling against the corresponding architecture + * (e.g., arch:AVX2, -mavx2, etc.) which compiles the whole + * software with these advanced instructions. These headers would + * normally guard against such usage, but we carefully included + * (or ) before, so the headers + * are fooled. + */ +#include // for _blsr_u64 +#include // for __lzcnt64 +#include // for most things (AVX2, AVX512, _popcnt64) +#include +#include +#include +#include +#include +// unfortunately, we may not get _blsr_u64, but, thankfully, clang +// has it as a macro. +#ifndef _blsr_u64 +// we roll our own +#define _blsr_u64(n) ((n - 1) & n) +#endif // _blsr_u64 +#endif // SIMDJSON_CLANG_VISUAL_STUDIO + + +#endif // CROARING_REGULAR_VISUAL_STUDIO #endif // defined(__x86_64__) || defined(_M_X64) #if !defined(USENEON) && !defined(DISABLENEON) && defined(__ARM_NEON) @@ -338,14 +206,13 @@ extern "C" { // portability definitions are in global scope, not a namespace # include #endif -#ifndef _MSC_VER +#if !CROARING_REGULAR_VISUAL_STUDIO /* Non-Microsoft C/C++-compatible compiler, assumes that it supports inline * assembly */ -#define ROARING_INLINE_ASM +#define CROARING_INLINE_ASM 1 #endif // _MSC_VER - -#ifdef _MSC_VER +#if CROARING_REGULAR_VISUAL_STUDIO /* Microsoft C/C++-compatible compiler */ #include @@ -395,136 +262,378 @@ inline int __builtin_clzll(unsigned long long input_num) { const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ... const uint64_t h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3... - input_num -= (input_num >> 1) & m1; - input_num = (input_num & m2) + ((input_num >> 2) & m2); - input_num = (input_num + (input_num >> 4)) & m4; - return (input_num * h01) >> 56; -}*/ + input_num -= (input_num >> 1) & m1; + input_num = (input_num & m2) + ((input_num >> 2) & m2); + input_num = (input_num + (input_num >> 4)) & m4; + return (input_num * h01) >> 56; +}*/ + +/* Use #define so this is effective even under /Ob0 (no inline) */ +#define __builtin_unreachable() __assume(0) +#endif + +#endif + +#if CROARING_REGULAR_VISUAL_STUDIO +#define ALIGNED(x) __declspec(align(x)) +#elif defined(__GNUC__) || defined(__clang__) +#define ALIGNED(x) __attribute__((aligned(x))) +#else +#warning "Warning. Unrecognized compiler." +#define ALIGNED(x) +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define WARN_UNUSED __attribute__((warn_unused_result)) +#else +#define WARN_UNUSED +#endif + +#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) + +static inline int hammingbackup(uint64_t x) { + uint64_t c1 = UINT64_C(0x5555555555555555); + uint64_t c2 = UINT64_C(0x3333333333333333); + uint64_t c4 = UINT64_C(0x0F0F0F0F0F0F0F0F); + x -= (x >> 1) & c1; + x = (( x >> 2) & c2) + (x & c2); x=(x +(x>>4))&c4; + x *= UINT64_C(0x0101010101010101); + return x >> 56; +} + +static inline int hamming(uint64_t x) { +#if defined(_WIN64) && defined(CROARING_REGULAR_VISUAL_STUDIO) && CROARING_REGULAR_VISUAL_STUDIO +#ifdef _M_ARM64 + return hammingbackup(x); + // (int) _CountOneBits64(x); is unavailable +#else // _M_ARM64 + return (int) __popcnt64(x); +#endif // _M_ARM64 +#elif defined(_WIN32) && defined(CROARING_REGULAR_VISUAL_STUDIO) && CROARING_REGULAR_VISUAL_STUDIO +#ifdef _M_ARM + return hammingbackup(x); + // _CountOneBits is unavailable +#else // _M_ARM + return (int) __popcnt(( unsigned int)x) + (int) __popcnt(( unsigned int)(x>>32)); +#endif // _M_ARM +#else + return __builtin_popcountll(x); +#endif +} + +#ifndef UINT64_C +#define UINT64_C(c) (c##ULL) +#endif // UINT64_C + +#ifndef UINT32_C +#define UINT32_C(c) (c##UL) +#endif // UINT32_C + +#ifdef __cplusplus +} // extern "C" { +#endif // __cplusplus + + +// this is almost standard? +#undef STRINGIFY_IMPLEMENTATION_ +#undef STRINGIFY +#define STRINGIFY_IMPLEMENTATION_(a) #a +#define STRINGIFY(a) STRINGIFY_IMPLEMENTATION_(a) + +// Our fast kernels require 64-bit systems. +// +// On 32-bit x86, we lack 64-bit popcnt, lzcnt, blsr instructions. +// Furthermore, the number of SIMD registers is reduced. +// +// On 32-bit ARM, we would have smaller registers. +// +// The library should still have the fallback kernel. It is +// slower, but it should run everywhere. + +// +// Enable valid runtime implementations, and select CROARING_BUILTIN_IMPLEMENTATION +// + +// We are going to use runtime dispatch. +#ifdef CROARING_IS_X64 +#ifdef __clang__ +// clang does not have GCC push pop +// warning: clang attribute push can't be used within a namespace in clang up +// til 8.0 so CROARING_TARGET_REGION and CROARING_UNTARGET_REGION must be *outside* of a +// namespace. +#define CROARING_TARGET_REGION(T) \ + _Pragma(STRINGIFY( \ + clang attribute push(__attribute__((target(T))), apply_to = function))) +#define CROARING_UNTARGET_REGION _Pragma("clang attribute pop") +#elif defined(__GNUC__) +// GCC is easier +#define CROARING_TARGET_REGION(T) \ + _Pragma("GCC push_options") _Pragma(STRINGIFY(GCC target(T))) +#define CROARING_UNTARGET_REGION _Pragma("GCC pop_options") +#endif // clang then gcc + +#endif // CROARING_IS_X64 + +// Default target region macros don't do anything. +#ifndef CROARING_TARGET_REGION +#define CROARING_TARGET_REGION(T) +#define CROARING_UNTARGET_REGION +#endif + +#define CROARING_TARGET_AVX2 CROARING_TARGET_REGION("avx2,bmi,pclmul,lzcnt") + +#ifdef __AVX2__ +// No need for runtime dispatching. +// It is unnecessary and harmful to old clang to tag regions. +#undef CROARING_TARGET_AVX2 +#define CROARING_TARGET_AVX2 +#undef CROARING_UNTARGET_REGION +#define CROARING_UNTARGET_REGION +#endif + + +// We need portability.h to be included first, +// but we also always want isadetection.h to be +// included (right after). +// See https://github.com/RoaringBitmap/CRoaring/issues/394 +// There is no scenario where we want portability.h to +// be included, but not isadetection.h: the latter is a +// strict requirement. +#endif /* INCLUDE_PORTABILITY_H_ *//* end file include/roaring/portability.h */ +/* begin file include/roaring/isadetection.h */ +/* From +https://github.com/endorno/pytorch/blob/master/torch/lib/TH/generic/simd/simd.h +Highly modified. + +Copyright (c) 2016- Facebook, Inc (Adam Paszke) +Copyright (c) 2014- Facebook, Inc (Soumith Chintala) +Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) +Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) +Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) +Copyright (c) 2011-2013 NYU (Clement Farabet) +Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, +Iain Melvin, Jason Weston) Copyright (c) 2006 Idiap Research Institute +(Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, +Samy Bengio, Johnny Mariethoz) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories +America and IDIAP Research Institute nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ROARING_ISADETECTION_H +#define ROARING_ISADETECTION_H + +// isadetection.h does not define any macro (except for ROARING_ISADETECTION_H). + +#include +#include +#include + +// We need portability.h to be included first, see +// https://github.com/RoaringBitmap/CRoaring/issues/394 +#if CROARING_REGULAR_VISUAL_STUDIO +#include +#elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) +#include +#endif // CROARING_REGULAR_VISUAL_STUDIO + + +enum croaring_instruction_set { + CROARING_DEFAULT = 0x0, + CROARING_NEON = 0x1, + CROARING_AVX2 = 0x4, + CROARING_SSE42 = 0x8, + CROARING_PCLMULQDQ = 0x10, + CROARING_BMI1 = 0x20, + CROARING_BMI2 = 0x40, + CROARING_ALTIVEC = 0x80, + CROARING_UNINITIALIZED = 0x8000 +}; + +#if defined(__PPC64__) + +static inline uint32_t dynamic_croaring_detect_supported_architectures() { + return CROARING_ALTIVEC; +} + +#elif defined(__arm__) || defined(__aarch64__) // incl. armel, armhf, arm64 + +#if defined(__ARM_NEON) + +static inline uint32_t dynamic_croaring_detect_supported_architectures() { + return CROARING_NEON; +} + +#else // ARM without NEON + +static inline uint32_t dynamic_croaring_detect_supported_architectures() { + return CROARING_DEFAULT; +} -/* Use #define so this is effective even under /Ob0 (no inline) */ -#define __builtin_unreachable() __assume(0) #endif -#endif +#elif defined(__x86_64__) || defined(_M_AMD64) // x64 -#if defined(_MSC_VER) -#define ALIGNED(x) __declspec(align(x)) -#else -#if defined(__GNUC__) -#define ALIGNED(x) __attribute__((aligned(x))) -#endif -#endif -#ifdef __GNUC__ -#define WARN_UNUSED __attribute__((warn_unused_result)) -#else -#define WARN_UNUSED -#endif -#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) -static inline int hammingbackup(uint64_t x) { - uint64_t c1 = UINT64_C(0x5555555555555555); - uint64_t c2 = UINT64_C(0x3333333333333333); - uint64_t c4 = UINT64_C(0x0F0F0F0F0F0F0F0F); - x -= (x >> 1) & c1; - x = (( x >> 2) & c2) + (x & c2); x=(x +(x>>4))&c4; - x *= UINT64_C(0x0101010101010101); - return x >> 56; -} +static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx, + uint32_t *edx) { -static inline int hamming(uint64_t x) { -#if defined(_WIN64) && defined(_MSC_VER) && !defined(__clang__) -#ifdef _M_ARM64 - return hammingbackup(x); - // (int) _CountOneBits64(x); is unavailable -#else // _M_ARM64 - return (int) __popcnt64(x); -#endif // _M_ARM64 -#elif defined(_WIN32) && defined(_MSC_VER) && !defined(__clang__) -#ifdef _M_ARM - return hammingbackup(x); - // _CountOneBits is unavailable -#else // _M_ARM - return (int) __popcnt(( unsigned int)x) + (int) __popcnt(( unsigned int)(x>>32)); -#endif // _M_ARM +#if CROARING_REGULAR_VISUAL_STUDIO + int cpu_info[4]; + __cpuid(cpu_info, *eax); + *eax = cpu_info[0]; + *ebx = cpu_info[1]; + *ecx = cpu_info[2]; + *edx = cpu_info[3]; +#elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID) + uint32_t level = *eax; + __get_cpuid(level, eax, ebx, ecx, edx); #else - return __builtin_popcountll(x); + uint32_t a = *eax, b, c = *ecx, d; + __asm__("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d)); + *eax = a; + *ebx = b; + *ecx = c; + *edx = d; #endif } -#ifndef UINT64_C -#define UINT64_C(c) (c##ULL) -#endif // UINT64_C +static inline uint32_t dynamic_croaring_detect_supported_architectures() { + uint32_t eax, ebx, ecx, edx; + uint32_t host_isa = 0x0; + // Can be found on Intel ISA Reference for CPUID + static uint32_t cpuid_avx2_bit = 1 << 5; ///< @private Bit 5 of EBX for EAX=0x7 + static uint32_t cpuid_bmi1_bit = 1 << 3; ///< @private bit 3 of EBX for EAX=0x7 + static uint32_t cpuid_bmi2_bit = 1 << 8; ///< @private bit 8 of EBX for EAX=0x7 + static uint32_t cpuid_sse42_bit = 1 << 20; ///< @private bit 20 of ECX for EAX=0x1 + static uint32_t cpuid_pclmulqdq_bit = 1 << 1; ///< @private bit 1 of ECX for EAX=0x1 + // ECX for EAX=0x7 + eax = 0x7; + ecx = 0x0; + cpuid(&eax, &ebx, &ecx, &edx); + if (ebx & cpuid_avx2_bit) { + host_isa |= CROARING_AVX2; + } + if (ebx & cpuid_bmi1_bit) { + host_isa |= CROARING_BMI1; + } -#ifndef UINT32_C -#define UINT32_C(c) (c##UL) -#endif // UINT32_C + if (ebx & cpuid_bmi2_bit) { + host_isa |= CROARING_BMI2; + } -#ifdef __cplusplus -} // extern "C" { -#endif // __cplusplus + // EBX for EAX=0x1 + eax = 0x1; + cpuid(&eax, &ebx, &ecx, &edx); + if (ecx & cpuid_sse42_bit) { + host_isa |= CROARING_SSE42; + } -// this is almost standard? -#undef STRINGIFY_IMPLEMENTATION_ -#undef STRINGIFY -#define STRINGIFY_IMPLEMENTATION_(a) #a -#define STRINGIFY(a) STRINGIFY_IMPLEMENTATION_(a) + if (ecx & cpuid_pclmulqdq_bit) { + host_isa |= CROARING_PCLMULQDQ; + } -// Our fast kernels require 64-bit systems. -// -// On 32-bit x86, we lack 64-bit popcnt, lzcnt, blsr instructions. -// Furthermore, the number of SIMD registers is reduced. -// -// On 32-bit ARM, we would have smaller registers. -// -// The library should still have the fallback kernel. It is -// slower, but it should run everywhere. + return host_isa; +} +#else // fallback -// -// Enable valid runtime implementations, and select CROARING_BUILTIN_IMPLEMENTATION -// -// We are going to use runtime dispatch. -#ifdef CROARING_IS_X64 -#ifdef __clang__ -// clang does not have GCC push pop -// warning: clang attribute push can't be used within a namespace in clang up -// til 8.0 so CROARING_TARGET_REGION and CROARING_UNTARGET_REGION must be *outside* of a -// namespace. -#define CROARING_TARGET_REGION(T) \ - _Pragma(STRINGIFY( \ - clang attribute push(__attribute__((target(T))), apply_to = function))) -#define CROARING_UNTARGET_REGION _Pragma("clang attribute pop") -#elif defined(__GNUC__) -// GCC is easier -#define CROARING_TARGET_REGION(T) \ - _Pragma("GCC push_options") _Pragma(STRINGIFY(GCC target(T))) -#define CROARING_UNTARGET_REGION _Pragma("GCC pop_options") -#endif // clang then gcc +static inline uint32_t dynamic_croaring_detect_supported_architectures() { + return CROARING_DEFAULT; +} -#endif // CROARING_IS_X64 -// Default target region macros don't do anything. -#ifndef CROARING_TARGET_REGION -#define CROARING_TARGET_REGION(T) -#define CROARING_UNTARGET_REGION -#endif +#endif // end SIMD extension detection code -#define CROARING_TARGET_AVX2 CROARING_TARGET_REGION("avx2,bmi,pclmul,lzcnt") -#ifdef __AVX2__ -// No need for runtime dispatching. -// It is unnecessary and harmful to old clang to tag regions. -#undef CROARING_TARGET_AVX2 -#define CROARING_TARGET_AVX2 -#undef CROARING_UNTARGET_REGION -#define CROARING_UNTARGET_REGION +#if defined(__x86_64__) || defined(_M_AMD64) // x64 + +#if defined(__cplusplus) +static inline uint32_t croaring_detect_supported_architectures() { + // thread-safe as per the C++11 standard. + static uint32_t buffer = dynamic_croaring_detect_supported_architectures(); + return buffer; +} +#elif CROARING_VISUAL_STUDIO +// Visual Studio does not support C11 atomics. +static inline uint32_t croaring_detect_supported_architectures() { + static int buffer = CROARING_UNINITIALIZED; + if (buffer == CROARING_UNINITIALIZED) { + buffer = dynamic_croaring_detect_supported_architectures(); + } + return buffer; +} +#else // CROARING_VISUAL_STUDIO +#include +static inline uint32_t croaring_detect_supported_architectures() { + // we use an atomic for thread safety + static _Atomic uint32_t buffer = CROARING_UNINITIALIZED; + if (buffer == CROARING_UNINITIALIZED) { + // atomicity is sufficient + buffer = dynamic_croaring_detect_supported_architectures(); + } + return buffer; +} +#endif // CROARING_REGULAR_VISUAL_STUDIO + +#ifdef ROARING_DISABLE_AVX +static inline bool croaring_avx2() { + return false; +} +#elif defined(__AVX2__) +static inline bool croaring_avx2() { + return true; +} +#else +static inline bool croaring_avx2() { + return (croaring_detect_supported_architectures() & CROARING_AVX2) == CROARING_AVX2; +} #endif -#endif /* INCLUDE_PORTABILITY_H_ */ -/* end file include/roaring/portability.h */ + +#else // defined(__x86_64__) || defined(_M_AMD64) // x64 + +static inline bool croaring_avx2() { + return false; +} + +static inline uint32_t croaring_detect_supported_architectures() { + // no runtime dispatch + return dynamic_croaring_detect_supported_architectures(); +} +#endif // defined(__x86_64__) || defined(_M_AMD64) // x64 + +#endif // ROARING_ISADETECTION_H +/* end file include/roaring/isadetection.h */ /* begin file include/roaring/containers/perfparameters.h */ #ifndef PERFPARAMETERS_H_ #define PERFPARAMETERS_H_ @@ -637,10 +746,10 @@ typedef ROARING_CONTAINER_T container_t; * downcast; only a static_cast<> is needed. Define a macro for static casting * which helps make casts more visible, and catches problems at compile-time * when building the C sources in C++ mode: - * + * * void some_func(container_t **c, ...) { // double pointer, not single * array_container_t *ac1 = (array_container_t *)(c); // uncaught!! - * + * * array_container_t *ac2 = CAST(array_container_t *, c) // C++ errors * array_container_t *ac3 = CAST_array(c); // shorthand for #2, errors * } @@ -649,7 +758,7 @@ typedef ROARING_CONTAINER_T container_t; * needs a reinterpret_cast<>, which sacrifices safety...so a template is used * leveraging to make sure it's legal in the C++ build. */ -#ifdef __cplusplus +#ifdef __cplusplus #define CAST(type,value) static_cast(value) #define movable_CAST(type,value) movable_CAST_HELPER(value) @@ -938,7 +1047,7 @@ bool memequals(const void *s1, const void *s2, size_t n); extern "C" { namespace roaring { #endif -#if defined(ROARING_INLINE_ASM) +#if defined(CROARING_INLINE_ASM) #define CROARING_ASMBITMANIPOPTIMIZATION // optimization flag #define ASM_SHIFT_RIGHT(srcReg, bitsReg, destReg) \ @@ -1953,18 +2062,24 @@ void array_container_offset(const array_container_t *c, //* Check whether a range of values from range_start (included) to range_end (excluded) is present. */ static inline bool array_container_contains_range(const array_container_t *arr, uint32_t range_start, uint32_t range_end) { - + const int32_t range_count = range_end - range_start; const uint16_t rs_included = range_start; const uint16_t re_included = range_end - 1; - const uint16_t *carr = (const uint16_t *) arr->array; - - const int32_t start = advanceUntil(carr, -1, arr->cardinality, rs_included); - const int32_t end = advanceUntil(carr, start - 1, arr->cardinality, re_included); + // Empty range is always included + if (range_count <= 0) { + return true; + } + if (range_count > arr->cardinality) { + return false; + } - return (start < arr->cardinality) && (end < arr->cardinality) - && (((uint16_t)(end - start)) == re_included - rs_included) - && (carr[start] == rs_included) && (carr[end] == re_included); + const int32_t start = binarySearch(arr->array, arr->cardinality, rs_included); + // If this sorted array contains all items in the range: + // * the start item must be found + // * the last item in range range_count must exist, and be the expected end value + return (start >= 0) && (arr->cardinality >= start + range_count) && + (arr->array[start + range_count - 1] == re_included); } /* Returns the smallest value (assumes not empty) */ @@ -6681,7 +6796,9 @@ inline container_t *ra_get_container_at_index( /** * Retrieves the key at index i */ -uint16_t ra_get_key_at_index(const roaring_array_t *ra, uint16_t i); +inline uint16_t ra_get_key_at_index(const roaring_array_t *ra, uint16_t i) { + return ra->keys[i]; +} /** * Add a new key-value pair at index i @@ -6911,7 +7028,7 @@ extern "C" { namespace roaring { namespace misc { // useful for basic info (0) static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { -#ifdef ROARING_INLINE_ASM +#ifdef CROARING_INLINE_ASM __asm volatile("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "0"(*eax), "2"(*ecx)); @@ -6923,7 +7040,7 @@ static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, // The EAX register should be loaded with a value specifying what information to // return static inline void cpuinfo(int code, int *eax, int *ebx, int *ecx, int *edx) { -#ifdef ROARING_INLINE_ASM +#ifdef CROARING_INLINE_ASM __asm__ volatile("cpuid;" // call cpuid instruction : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) // output equal to "movl %%eax %1" @@ -9013,8 +9130,9 @@ static inline bool _avx2_memequals(const void *s1, const void *s2, size_t n) { } while (ptr1 < end8) { - uint64_t v1 = *((const uint64_t*)ptr1); - uint64_t v2 = *((const uint64_t*)ptr2); + uint64_t v1, v2; + memcpy(&v1,ptr1,sizeof(uint64_t)); + memcpy(&v2,ptr2,sizeof(uint64_t)); if (v1 != v2) { return false; } @@ -11869,10 +11987,11 @@ container_t *convert_to_bitset_or_array_container( for (int rlepos = 0; rlepos < rc->n_runs; ++rlepos) { uint16_t run_start = rc->runs[rlepos].value; uint16_t run_end = run_start + rc->runs[rlepos].length; - for (uint16_t run_value = run_start; run_value <= run_end; + for (uint16_t run_value = run_start; run_value < run_end; ++run_value) { answer->array[answer->cardinality++] = run_value; } + answer->array[answer->cardinality++] = run_end; } assert(card == answer->cardinality); *resulttype = ARRAY_CONTAINER_TYPE; @@ -15311,46 +15430,91 @@ bool roaring_bitmap_init_with_capacity(roaring_bitmap_t *r, uint32_t cap) { return ra_init_with_capacity(&r->high_low_container, cap); } +static inline void add_bulk_impl(roaring_bitmap_t *r, + roaring_bulk_context_t *context, + uint32_t val) { + uint16_t key = val >> 16; + if (context->container == NULL || context->key != key) { + uint8_t typecode; + int idx; + context->container = containerptr_roaring_bitmap_add( + r, val, &typecode, &idx); + context->typecode = typecode; + context->idx = idx; + context->key = key; + } else { + // no need to seek the container, it is at hand + // because we already have the container at hand, we can do the + // insertion directly, bypassing the roaring_bitmap_add call + uint8_t new_typecode; + container_t *container2 = container_add( + context->container, val & 0xFFFF, context->typecode, &new_typecode); + if (container2 != context->container) { + // rare instance when we need to change the container type + container_free(context->container, context->typecode); + ra_set_container_at_index(&r->high_low_container, context->idx, + container2, new_typecode); + context->typecode = new_typecode; + context->container = container2; + } + } +} void roaring_bitmap_add_many(roaring_bitmap_t *r, size_t n_args, const uint32_t *vals) { - container_t *container = NULL; // hold value of last container touched - uint8_t typecode = 0; // typecode of last container touched - uint32_t prev = 0; // previous valued inserted - size_t i = 0; // index of value - int containerindex = 0; - if (n_args == 0) return; uint32_t val; - memcpy(&val, vals + i, sizeof(val)); - container = - containerptr_roaring_bitmap_add(r, val, &typecode, &containerindex); - prev = val; - i++; - for (; i < n_args; i++) { - memcpy(&val, vals + i, sizeof(val)); - if (((prev ^ val) >> 16) == - 0) { // no need to seek the container, it is at hand - // because we already have the container at hand, we can do the - // insertion - // automatically, bypassing the roaring_bitmap_add call - uint8_t newtypecode = typecode; - container_t *container2 = - container_add(container, val & 0xFFFF, typecode, &newtypecode); - if (container2 != container) { // rare instance when we need to - // change the container type - container_free(container, typecode); - ra_set_container_at_index(&r->high_low_container, - containerindex, container2, - newtypecode); - typecode = newtypecode; - container = container2; - } - } else { - container = containerptr_roaring_bitmap_add(r, val, &typecode, - &containerindex); + const uint32_t *start = vals; + const uint32_t *end = vals + n_args; + const uint32_t *current_val = start; + + if (n_args == 0) { + return; + } + + uint8_t typecode; + int idx; + container_t *container; + val = *current_val; + container = containerptr_roaring_bitmap_add(r, val, &typecode, &idx); + roaring_bulk_context_t context = {container, idx, (uint16_t)(val >> 16), typecode}; + + for (; current_val != end; current_val++) { + memcpy(&val, current_val, sizeof(val)); + add_bulk_impl(r, &context, val); + } +} + +void roaring_bitmap_add_bulk(roaring_bitmap_t *r, + roaring_bulk_context_t *context, uint32_t val) { + add_bulk_impl(r, context, val); +} + +bool roaring_bitmap_contains_bulk(const roaring_bitmap_t *r, + roaring_bulk_context_t *context, + uint32_t val) +{ + uint16_t key = val >> 16; + if (context->container == NULL || context->key != key) { + int32_t start_idx = -1; + if (context->container != NULL && context->key < key) { + start_idx = context->idx; + } + int idx = ra_advance_until(&r->high_low_container, key, start_idx); + if (idx == ra_get_size(&r->high_low_container)) { + return false; + } + uint8_t typecode; + context->container = ra_get_container_at_index(&r->high_low_container, idx, &typecode); + context->typecode = typecode; + context->idx = idx; + context->key = ra_get_key_at_index(&r->high_low_container, idx); + // ra_advance_until finds the next key >= the target, we found a later container. + if (context->key != key) { + return false; } - prev = val; } + // context is now set up + return container_contains(context->container, val & 0xFFFF, context->typecode); } roaring_bitmap_t *roaring_bitmap_of_ptr(size_t n_args, const uint32_t *vals) { @@ -15363,11 +15527,12 @@ roaring_bitmap_t *roaring_bitmap_of(size_t n_args, ...) { // todo: could be greatly optimized but we do not expect this call to ever // include long lists roaring_bitmap_t *answer = roaring_bitmap_create(); + roaring_bulk_context_t context = {0}; va_list ap; va_start(ap, n_args); - for (size_t i = 1; i <= n_args; i++) { + for (size_t i = 0; i < n_args; i++) { uint32_t val = va_arg(ap, uint32_t); - roaring_bitmap_add(answer, val); + roaring_bitmap_add_bulk(answer, &context, val); } va_end(ap); return answer; @@ -16637,14 +16802,24 @@ size_t roaring_bitmap_portable_serialize(const roaring_bitmap_t *r, roaring_bitmap_t *roaring_bitmap_deserialize(const void *buf) { const char *bufaschar = (const char *)buf; - if (*(const unsigned char *)buf == CROARING_SERIALIZATION_ARRAY_UINT32) { + if (bufaschar[0] == CROARING_SERIALIZATION_ARRAY_UINT32) { /* This looks like a compressed set of uint32_t elements */ uint32_t card; memcpy(&card, bufaschar + 1, sizeof(uint32_t)); const uint32_t *elems = (const uint32_t *)(bufaschar + 1 + sizeof(uint32_t)); - - return roaring_bitmap_of_ptr(card, elems); + roaring_bitmap_t *bitmap = roaring_bitmap_create(); + if (bitmap == NULL) { + return NULL; + } + roaring_bulk_context_t context = {0}; + for (uint32_t i = 0; i < card; i++) { + // elems may not be aligned, read with memcpy + uint32_t elem; + memcpy(&elem, elems + i, sizeof(elem)); + roaring_bitmap_add_bulk(bitmap, &context, elem); + } + return bitmap; } else if (bufaschar[0] == CROARING_SERIALIZATION_CONTAINER) { return roaring_bitmap_portable_deserialize(bufaschar + 1); } else @@ -18048,7 +18223,7 @@ bool roaring_bitmap_contains_range(const roaring_bitmap_t *r, uint64_t range_sta int32_t is = ra_get_index(&r->high_low_container, hb_rs); int32_t ie = ra_get_index(&r->high_low_container, hb_re); ie = (ie < 0 ? -ie - 1 : ie); - if ((is < 0) || ((ie - is) != span)) { + if ((is < 0) || ((ie - is) != span) || ie >= hlc_sz) { return false; } const uint32_t lb_rs = range_start & 0xFFFF; @@ -18062,7 +18237,6 @@ bool roaring_bitmap_contains_range(const roaring_bitmap_t *r, uint64_t range_sta if (!container_contains_range(c, lb_rs, 1 << 16, type)) { return false; } - assert(ie < hlc_sz); // would indicate an algorithmic bug c = ra_get_container_at_index(&r->high_low_container, ie, &type); if (!container_contains_range(c, 0, lb_re, type)) { return false; @@ -18685,30 +18859,8 @@ extern inline container_t *ra_get_container_at_index( const roaring_array_t *ra, uint16_t i, uint8_t *typecode); -#ifdef ROARING_NOT_USED -container_t *ra_get_writable_container( - roaring_array_t *ra, uint16_t x, - uint8_t *typecode -){ - int i = binarySearch(ra->keys, (int32_t)ra->size, x); - if (i < 0) return NULL; - *typecode = ra->typecodes[i]; - return get_writable_copy_if_shared(ra->containers[i], typecode); -} - -container_t *ra_get_writable_container_at_index( - roaring_array_t *ra, uint16_t i, - uint8_t *typecode -){ - assert(i < ra->size); - *typecode = ra->typecodes[i]; - return get_writable_copy_if_shared(ra->containers[i], typecode); -} -#endif - -uint16_t ra_get_key_at_index(const roaring_array_t *ra, uint16_t i) { - return ra->keys[i]; -} +extern inline uint16_t ra_get_key_at_index(const roaring_array_t *ra, + uint16_t i); extern inline int32_t ra_get_index(const roaring_array_t *ra, uint16_t x);