croaring-ffi-1.0: src/Data/Bitmap/Roaring/FFI/Bitmap64.hs
{-# LANGUAGE CApiFFI #-}
{-| Raw bindings to @roaring/roaring64.h@ for 64-bit Roaring bitmaps, @roaring64_bitmap_t@.
Each binding is the C function without its @roaring64_bitmap_@ prefix, camelCased.
The @_safe@ loader only bounds how far it reads, so it is named 'portableDeserializeBounded' here.
'portableDeserializeValidated' also runs 'internalValidate'.
Use it for bytes from outside the program.
Handles carry no ownership.
Release the bitmaps that C returns with 'free' or 'finalizerFree'.
A bitmap is not synchronised.
Concurrent use needs external locking.
-}
module Data.Bitmap.Roaring.FFI.Bitmap64
( Bitmap64 (..)
, create
, free
, finalizerFree
, with
, fromRange
, ofPtr
, moveFromRoaring32
, copy
, overwrite
, clear
, add
, addChecked
, addMany
, addBulk
, addRange
, addRangeClosed
, remove
, removeChecked
, removeMany
, removeBulk
, removeRange
, removeRangeClosed
, contains
, containsBulk
, containsRange
, containsRangeClosed
, getCardinality
, rangeCardinality
, rangeClosedCardinality
, isEmpty
, minimum
, maximum
, select
, rank
, getIndex
, equals
, isSubset
, isStrictSubset
, intersect
, intersectWithRange
, jaccardIndex
, and
, andInplace
, andCardinality
, or
, orInplace
, orCardinality
, xor
, xorInplace
, xorCardinality
, andnot
, andnotInplace
, andnotCardinality
, flip
, flipClosed
, flipInplace
, flipClosedInplace
, addOffsetSigned
, addOffset
, subOffset
, toUint64Array
, runOptimize
, removeRunCompression
, shrinkToFit
, statistics
, getStatistics
, internalValidate
, portableSizeInBytes
, portableSerialize
, portableDeserializeBounded
, portableDeserializeValidated
, portableDeserializeSize
, portableDeserializeFrozen
, frozenSizeInBytes
, frozenSerialize
, frozenView
, withPortableFrozen
, withFrozenView
, iterate
, iterateWith
) where
import Prelude hiding (and, flip, iterate, maximum, minimum, or)
import Control.Exception (bracket)
import Data.Bitmap.Roaring.FFI.Bitmap (Bitmap (..), Callback64, wrapCallback64)
import Data.Bitmap.Roaring.FFI.Bitmap64.BulkContext (BulkContext (..))
import Data.Bitmap.Roaring.FFI.Bitmap64.Statistics (Statistics)
import Data.Bitmap.Roaring.FFI.Callback qualified as Callback
import Data.Bitmap.Roaring.FFI.NullHandle qualified as NullHandle
import Data.Word (Word64)
import Foreign.C.ConstPtr (ConstPtr (..))
import Foreign.C.Types (CChar, CSize (..))
import Foreign.ForeignPtr (FinalizerPtr)
import Foreign.Marshal.Alloc (alloca)
import Foreign.Ptr (FunPtr, Ptr, nullPtr)
import Foreign.Storable (Storable, peek)
-- | @roaring64_bitmap_t@. Its 'Storable' instance stores the pointer itself.
newtype Bitmap64 = Bitmap64 (Ptr Bitmap64)
deriving (Eq, Ord, Show, Storable)
-- | @roaring64_bitmap_create@: NULL on allocation failure.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_create"
create :: IO Bitmap64
-- | @roaring64_bitmap_free@: also releases read-only views.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_free"
free :: Bitmap64 -> IO ()
-- | @&roaring64_bitmap_free@
foreign import capi unsafe "roaring/roaring64.h &roaring64_bitmap_free"
finalizerFree :: FinalizerPtr Bitmap64
-- | Frees the bitmap when the action ends. Throws t'NullHandle.NullHandle' if the constructor returns NULL.
with :: IO Bitmap64 -> (Bitmap64 -> IO a) -> IO a
with = NullHandle.bracket "Data.Bitmap.Roaring.FFI.Bitmap64.with" free
{-# INLINE with #-}
-- | @roaring64_bitmap_from_range@: @[min, max)@ every @step@ from @min@. NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_from_range"
fromRange :: Word64 -> Word64 -> Word64 -> IO Bitmap64
-- | @roaring64_bitmap_of_ptr@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_of_ptr"
ofPtr :: CSize -> Ptr Word64 -> IO Bitmap64
-- | @roaring64_bitmap_move_from_roaring32@: empties the 32-bit bitmap, which still has to be freed.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_move_from_roaring32"
moveFromRoaring32 :: Bitmap -> IO Bitmap64
-- | @roaring64_bitmap_copy@: NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_copy"
copy :: Bitmap64 -> IO Bitmap64
-- | @roaring64_bitmap_overwrite@: the two may be the same bitmap.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_overwrite"
overwrite :: Bitmap64 -> Bitmap64 -> IO ()
-- | @roaring64_bitmap_clear@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_clear"
clear :: Bitmap64 -> IO ()
-- | @roaring64_bitmap_add@
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_add"
add :: Bitmap64 -> Word64 -> IO ()
-- | @roaring64_bitmap_add_checked@: 'True' if the value was absent.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_add_checked"
addChecked :: Bitmap64 -> Word64 -> IO Bool
-- | @roaring64_bitmap_add_many@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_add_many"
addMany :: Bitmap64 -> CSize -> Ptr Word64 -> IO ()
-- | @roaring64_bitmap_add_bulk@: see "Data.Bitmap.Roaring.FFI.Bitmap64.BulkContext" for the context's rules.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_add_bulk"
addBulk :: Bitmap64 -> BulkContext -> Word64 -> IO ()
-- | @roaring64_bitmap_add_range@: @[min, max)@.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_add_range"
addRange :: Bitmap64 -> Word64 -> Word64 -> IO ()
-- | @roaring64_bitmap_add_range_closed@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_add_range_closed"
addRangeClosed :: Bitmap64 -> Word64 -> Word64 -> IO ()
-- | @roaring64_bitmap_remove@
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_remove"
remove :: Bitmap64 -> Word64 -> IO ()
-- | @roaring64_bitmap_remove_checked@: 'True' if the value was present.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_remove_checked"
removeChecked :: Bitmap64 -> Word64 -> IO Bool
-- | @roaring64_bitmap_remove_many@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_remove_many"
removeMany :: Bitmap64 -> CSize -> Ptr Word64 -> IO ()
-- | @roaring64_bitmap_remove_bulk@: see "Data.Bitmap.Roaring.FFI.Bitmap64.BulkContext" for the context's rules.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_remove_bulk"
removeBulk :: Bitmap64 -> BulkContext -> Word64 -> IO ()
-- | @roaring64_bitmap_remove_range@: @[min, max)@.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_remove_range"
removeRange :: Bitmap64 -> Word64 -> Word64 -> IO ()
-- | @roaring64_bitmap_remove_range_closed@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_remove_range_closed"
removeRangeClosed :: Bitmap64 -> Word64 -> Word64 -> IO ()
-- | @roaring64_bitmap_contains@
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_contains"
contains :: Bitmap64 -> Word64 -> IO Bool
-- | @roaring64_bitmap_contains_bulk@: see "Data.Bitmap.Roaring.FFI.Bitmap64.BulkContext" for the context's rules.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_contains_bulk"
containsBulk :: Bitmap64 -> BulkContext -> Word64 -> IO Bool
-- | @roaring64_bitmap_contains_range@: @[min, max)@.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_contains_range"
containsRange :: Bitmap64 -> Word64 -> Word64 -> IO Bool
-- | @roaring64_bitmap_contains_range_closed@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_contains_range_closed"
containsRangeClosed :: Bitmap64 -> Word64 -> Word64 -> IO Bool
-- | @roaring64_bitmap_get_cardinality@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_get_cardinality"
getCardinality :: Bitmap64 -> IO Word64
-- | @roaring64_bitmap_range_cardinality@: @[min, max)@.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_range_cardinality"
rangeCardinality :: Bitmap64 -> Word64 -> Word64 -> IO Word64
-- | @roaring64_bitmap_range_closed_cardinality@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_range_closed_cardinality"
rangeClosedCardinality :: Bitmap64 -> Word64 -> Word64 -> IO Word64
-- | @roaring64_bitmap_is_empty@
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_is_empty"
isEmpty :: Bitmap64 -> IO Bool
-- | @roaring64_bitmap_minimum@: @UINT64_MAX@ when empty.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_minimum"
minimum :: Bitmap64 -> IO Word64
-- | @roaring64_bitmap_maximum@: 0 when empty.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_maximum"
maximum :: Bitmap64 -> IO Word64
-- | @roaring64_bitmap_select@: the rank is 0-based. 'False' when it is not below the cardinality.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_select"
select :: Bitmap64 -> Word64 -> Ptr Word64 -> IO Bool
-- | @roaring64_bitmap_rank@: the number of values less than or equal to the given one.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_rank"
rank :: Bitmap64 -> Word64 -> IO Word64
-- | @roaring64_bitmap_get_index@: the index is 0-based. 'False' when the value is absent.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_get_index"
getIndex :: Bitmap64 -> Word64 -> Ptr Word64 -> IO Bool
-- | @roaring64_bitmap_equals@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_equals"
equals :: Bitmap64 -> Bitmap64 -> IO Bool
-- | @roaring64_bitmap_is_subset@: whether the first is a subset of the second.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_is_subset"
isSubset :: Bitmap64 -> Bitmap64 -> IO Bool
-- | @roaring64_bitmap_is_strict_subset@: whether the first is a strict subset of the second.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_is_strict_subset"
isStrictSubset :: Bitmap64 -> Bitmap64 -> IO Bool
-- | @roaring64_bitmap_intersect@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_intersect"
intersect :: Bitmap64 -> Bitmap64 -> IO Bool
-- | @roaring64_bitmap_intersect_with_range@: @[min, max)@.
foreign import capi unsafe "roaring/roaring64.h roaring64_bitmap_intersect_with_range"
intersectWithRange :: Bitmap64 -> Word64 -> Word64 -> IO Bool
-- | @roaring64_bitmap_jaccard_index@: NaN when both are empty.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_jaccard_index"
jaccardIndex :: Bitmap64 -> Bitmap64 -> IO Double
-- | @roaring64_bitmap_and@: NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_and"
and :: Bitmap64 -> Bitmap64 -> IO Bitmap64
-- | @roaring64_bitmap_and_inplace@: the two may be the same bitmap.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_and_inplace"
andInplace :: Bitmap64 -> Bitmap64 -> IO ()
-- | @roaring64_bitmap_and_cardinality@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_and_cardinality"
andCardinality :: Bitmap64 -> Bitmap64 -> IO Word64
-- | @roaring64_bitmap_or@: NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_or"
or :: Bitmap64 -> Bitmap64 -> IO Bitmap64
-- | @roaring64_bitmap_or_inplace@: passing the same bitmap twice leaves it unchanged.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_or_inplace"
orInplace :: Bitmap64 -> Bitmap64 -> IO ()
-- | @roaring64_bitmap_or_cardinality@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_or_cardinality"
orCardinality :: Bitmap64 -> Bitmap64 -> IO Word64
-- | @roaring64_bitmap_xor@: NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_xor"
xor :: Bitmap64 -> Bitmap64 -> IO Bitmap64
-- | @roaring64_bitmap_xor_inplace@: passing the same bitmap twice clears it.
xorInplace :: Bitmap64 -> Bitmap64 -> IO ()
xorInplace target other
| target == other = clear target
| otherwise = xorInplaceDistinct target other
{-# INLINE xorInplace #-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_xor_inplace"
xorInplaceDistinct :: Bitmap64 -> Bitmap64 -> IO ()
-- | @roaring64_bitmap_xor_cardinality@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_xor_cardinality"
xorCardinality :: Bitmap64 -> Bitmap64 -> IO Word64
-- | @roaring64_bitmap_andnot@: first minus second. NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_andnot"
andnot :: Bitmap64 -> Bitmap64 -> IO Bitmap64
-- | @roaring64_bitmap_andnot_inplace@: first minus second. Passing the same bitmap twice clears it.
andnotInplace :: Bitmap64 -> Bitmap64 -> IO ()
andnotInplace target other
| target == other = clear target
| otherwise = andnotInplaceDistinct target other
{-# INLINE andnotInplace #-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_andnot_inplace"
andnotInplaceDistinct :: Bitmap64 -> Bitmap64 -> IO ()
-- | @roaring64_bitmap_andnot_cardinality@: the size of first minus second.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_andnot_cardinality"
andnotCardinality :: Bitmap64 -> Bitmap64 -> IO Word64
-- | @roaring64_bitmap_flip@: @[min, max)@. NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_flip"
flip :: Bitmap64 -> Word64 -> Word64 -> IO Bitmap64
-- | @roaring64_bitmap_flip_closed@: NULL on failure.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_flip_closed"
flipClosed :: Bitmap64 -> Word64 -> Word64 -> IO Bitmap64
-- | @roaring64_bitmap_flip_inplace@: @[min, max)@.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_flip_inplace"
flipInplace :: Bitmap64 -> Word64 -> Word64 -> IO ()
-- | @roaring64_bitmap_flip_closed_inplace@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_flip_closed_inplace"
flipClosedInplace :: Bitmap64 -> Word64 -> Word64 -> IO ()
-- | @roaring64_bitmap_add_offset_signed@: shifts up when 'True', down when 'False'. Values leaving the 64-bit range are dropped.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_add_offset_signed"
addOffsetSigned :: Bitmap64 -> Bool -> Word64 -> IO Bitmap64
-- | @roaring64_bitmap_add_offset@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_add_offset"
addOffset :: Bitmap64 -> Word64 -> IO Bitmap64
-- | @roaring64_bitmap_sub_offset@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_sub_offset"
subOffset :: Bitmap64 -> Word64 -> IO Bitmap64
-- | @roaring64_bitmap_to_uint64_array@: the output must hold 'getCardinality' values.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_to_uint64_array"
toUint64Array :: Bitmap64 -> Ptr Word64 -> IO ()
{- | @roaring64_bitmap_run_optimize@: converts containers to or from runs, whichever is smaller.
'True' if the result has a run container.
Adding or removing single values never converts a run container to another kind.
Call it again after many such edits to recover the space.
-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_run_optimize"
runOptimize :: Bitmap64 -> IO Bool
-- | @roaring64_bitmap_remove_run_compression@: 'True' if anything changed.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_remove_run_compression"
removeRunCompression :: Bitmap64 -> IO Bool
-- | @roaring64_bitmap_shrink_to_fit@: returns the bytes freed.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_shrink_to_fit"
shrinkToFit :: Bitmap64 -> IO CSize
-- | @roaring64_bitmap_statistics@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_statistics"
statistics :: Bitmap64 -> Ptr Statistics -> IO ()
getStatistics :: Bitmap64 -> IO Statistics
getStatistics bitmap =
alloca $ \ptr -> do
statistics bitmap ptr
peek ptr
{- | @roaring64_bitmap_internal_validate@: checks the internal invariants.
'True' if the bitmap is consistent.
If a check fails and the pointer is not NULL, the pointer receives a static C string that names the first problem.
The caller does not free that string.
Unless the bytes are known to come from a serialised bitmap, the loaded bitmap must pass this before any other use.
-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_internal_validate"
internalValidate :: Bitmap64 -> Ptr (ConstPtr CChar) -> IO Bool
-- | @roaring64_bitmap_portable_size_in_bytes@
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_portable_size_in_bytes"
portableSizeInBytes :: Bitmap64 -> IO CSize
-- | @roaring64_bitmap_portable_serialize@: the buffer must hold 'portableSizeInBytes'.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_portable_serialize"
portableSerialize :: Bitmap64 -> Ptr CChar -> IO CSize
{- | @roaring64_bitmap_portable_deserialize_safe@: reads at most the given number of bytes.
NULL on failure.
Only the reads are bounded.
Bytes that did not come from a portable serialiser can still yield a broken bitmap.
Until 'internalValidate' accepts it, such a bitmap can give wrong answers, crash or corrupt memory.
-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_portable_deserialize_safe"
portableDeserializeBounded :: Ptr CChar -> CSize -> IO Bitmap64
{- | Runs 'portableDeserializeBounded', then 'internalValidate'.
'Nothing' when the bytes are truncated, malformed or fail validation.
After 'Nothing', there is nothing to free.
-}
portableDeserializeValidated :: Ptr CChar -> CSize -> IO (Maybe Bitmap64)
portableDeserializeValidated buffer limit = portableDeserializeBounded buffer limit >>= validated
validated :: Bitmap64 -> IO (Maybe Bitmap64)
validated bitmap
| bitmap == Bitmap64 nullPtr = pure Nothing
| otherwise = do
valid <- internalValidate bitmap nullPtr
if valid then pure $ Just bitmap else Nothing <$ free bitmap
-- | @roaring64_bitmap_portable_deserialize_size@: reads at most the given number of bytes. Returns 0 if no whole bitmap is found.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_portable_deserialize_size"
portableDeserializeSize :: Ptr CChar -> CSize -> IO CSize
{- | @roaring64_bitmap_portable_deserialize_frozen@: a read-only view into the portable-format buffer, reading at most the given number of bytes.
NULL on failure and on big-endian hosts.
Only the reads are bounded.
Bytes that did not come from a portable serialiser can still yield a bitmap that misbehaves until 'internalValidate' accepts it.
The buffer must stay alive and unmodified until 'free' releases the view.
The view must not be modified.
-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_portable_deserialize_frozen"
portableDeserializeFrozen :: Ptr CChar -> CSize -> IO Bitmap64
-- | @roaring64_bitmap_frozen_size_in_bytes@: call 'shrinkToFit' first.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_frozen_size_in_bytes"
frozenSizeInBytes :: Bitmap64 -> IO CSize
{- | @roaring64_bitmap_frozen_serialize@: the format mirrors the in-memory layout, so it depends on the CRoaring version and host endianness.
Call 'shrinkToFit' first.
The buffer must hold 'frozenSizeInBytes'.
-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_frozen_serialize"
frozenSerialize :: Bitmap64 -> Ptr CChar -> IO CSize
{- | @roaring64_bitmap_frozen_view@: a read-only bitmap viewing a 'frozenSerialize' buffer, reading at most the given number of bytes.
NULL on failure, including when the buffer is not 64-byte aligned.
Bytes that did not come from 'frozenSerialize' can yield a bitmap that misbehaves.
The buffer must stay alive and unmodified until 'free' releases the view.
The view must not be modified.
-}
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_frozen_view"
frozenView :: Ptr CChar -> CSize -> IO Bitmap64
{- | Validates a 'portableDeserializeFrozen' view, reading at most the given number of bytes, and frees it when the action ends.
'Nothing' when the bytes do not hold a valid bitmap, and on big-endian hosts.
The buffer must stay unmodified during the action.
The view must not be modified, and must not escape the action.
-}
withPortableFrozen :: Ptr CChar -> CSize -> (Bitmap64 -> IO a) -> IO (Maybe a)
withPortableFrozen buffer limit = viewing $ portableDeserializeFrozen buffer limit
{- | Validates a 'frozenView', reading at most the given number of bytes, and frees it when the action ends.
'Nothing' when the bytes do not hold a valid bitmap or the buffer is not 64-byte aligned.
The buffer must stay unmodified during the action.
The view must not be modified, and must not escape the action.
-}
withFrozenView :: Ptr CChar -> CSize -> (Bitmap64 -> IO a) -> IO (Maybe a)
withFrozenView buffer limit = viewing $ frozenView buffer limit
viewing :: IO Bitmap64 -> (Bitmap64 -> IO a) -> IO (Maybe a)
viewing construct action = bracket (construct >>= validated) (mapM_ free) $ traverse action
-- | @roaring64_bitmap_iterate@: 'True' if the callback never stopped the iteration.
foreign import capi safe "roaring/roaring64.h roaring64_bitmap_iterate"
iterate :: Bitmap64 -> FunPtr Callback64 -> Ptr () -> IO Bool
{- | Runs 'iterate' with a Haskell function.
'True' if the function never returned 'False'.
An exception from the function stops the iteration and is rethrown after it, instead of unwinding through C.
Each value costs a call into Haskell, about 100 ns.
For reading in bulk, 'Data.Bitmap.Roaring.FFI.Bitmap64.Iterator.read' is much faster.
-}
iterateWith :: Bitmap64 -> (Word64 -> IO Bool) -> IO Bool
iterateWith bitmap visit = Callback.with wrapCallback64 visit $ \callback -> iterate bitmap callback nullPtr