Next: bool, Previous: bit_buffer.write, Up: Top [Contents]
%--------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%--------------------------------------------------%
% Copyright (C) 2001-2002, 2004-2007, 2009-2011 The University of Melbourne
% Copyright (C) 2013-2018 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%--------------------------------------------------%
%
% File: bitmap.m.
% Main author: rafe, stayl.
% Stability: low.
%
% Efficient bitmap implementation.
%
% CAVEAT: the user is referred to the documentation in the header of array.m
% regarding programming with unique objects (the compiler does not
% currently recognise them, hence we are forced to use non-unique modes
% until the situation is rectified; this places a small burden on programmers
% to ensure the correctness of their code that would otherwise be assured
% by the compiler.)
%
%--------------------------------------------------%
%--------------------------------------------------%
:- module bitmap.
:- interface.
:- import_module bool.
:- import_module list.
%--------------------------------------------------%
% Type `bitmap' is equivalent to `array(bool)', but is implemented
% much more efficiently. Accessing bitmaps as if they were an array
% of eight bit bytes is especially efficient.
%
% See runtime/mercury_types.h for the definition of MR_BitmapPtr for
% use in foreign code.
%
% Comparison of bitmaps first compares the size. If the sizes are equal,
% then it compares each bit in turn, starting from bit zero.
%
:- type bitmap.
:- inst bitmap == ground.
:- inst uniq_bitmap == bitmap. % XXX should be unique
:- mode bitmap_di == in(uniq_bitmap). % XXX should be di
:- mode bitmap_uo == out(uniq_bitmap).
:- mode bitmap_ui == in(uniq_bitmap).
% The exception thrown for any error.
%
:- type bitmap_error
---> bitmap_error(string).
%--------------------------------------------------%
:- type bit_index == int.
:- type byte_index == int.
:- type num_bits == int.
:- type num_bytes == int.
% 8 bits stored in the least significant bits of the integer.
%
:- type byte == int.
% An integer interpreted as a vector of int.bits_per_int bits.
%
:- type word == int.
%--------------------------------------------------%
% init(N, B) creates a bitmap of size N (indexed 0 .. N-1)
% setting each bit if B = yes and clearing each bit if B = no.
% An exception is thrown if N is negative.
%
:- func init(num_bits::in, bool::in) = (bitmap::bitmap_uo) is det.
% A synonym for init(N, no).
%
:- func init(num_bits::in) = (bitmap::bitmap_uo) is det.
% Is the given bit number in range?
%
:- pred in_range(bitmap, bit_index).
% :- mode in_range(bitmap_ui, in) is semidet.
:- mode in_range(in, in) is semidet.
% Is the given byte number in range?
%
:- pred byte_in_range(bitmap, byte_index).
% :- mode byte_in_range(bitmap_ui, in) is semidet.
:- mode byte_in_range(in, in) is semidet.
% Return the number of bits in a bitmap.
%
:- func num_bits(bitmap) = num_bits.
% :- mode num_bits(bitmap_ui) = out is det.
:- mode num_bits(in) = out is det.
% Return the number of bytes in a bitmap, failing if the bitmap
% has a partial final byte.
%
:- func num_bytes(bitmap) = num_bytes.
% :- mode num_bytes(bitmap_ui) = out is semidet.
:- mode num_bytes(in) = out is semidet.
% As above, but throw an exception if the bitmap has a partial final byte.
%
:- func det_num_bytes(bitmap) = num_bytes.
% :- mode det_num_bytes(bitmap_ui) = out is det.
:- mode det_num_bytes(in) = out is det.
% Return the number of bits in a byte (always 8).
%
:- func bits_per_byte = int.
% is_empty(Bitmap):
% True iff Bitmap is a bitmap containing zero bits.
%
:- pred is_empty(bitmap).
%:- mode is_empty(bitmap_ui) is semidet.
:- mode is_empty(in) is semidet.
%--------------------------------------------------%
%
% Get or set the given bit.
% The unsafe versions do not check whether the bit is in range.
%
:- func get_bit(bitmap, bit_index) = bool.
% :- mode get_bit(bitmap_ui, in) = out is det.
:- mode get_bit(in, in) = out is det.
:- func bitmap ^ bit(bit_index) = bool.
% :- mode bitmap_ui ^ bit(in) = out is det.
:- mode in ^ bit(in) = out is det.
:- func unsafe_get_bit(bitmap, bit_index) = bool.
% :- mode unsafe_get_bit(bitmap_ui, in) = out is det.
:- mode unsafe_get_bit(in, in) = out is det.
:- func bitmap ^ unsafe_bit(bit_index) = bool.
% :- mode bitmap_ui ^ unsafe_bit(in) = out is det.
:- mode in ^ unsafe_bit(in) = out is det.
:- pred set_bit(bit_index, bool, bitmap, bitmap).
:- mode set_bit(in, in, bitmap_di, bitmap_uo) is det.
:- func (bitmap ^ bit(bit_index) := bool) = bitmap.
:- mode (bitmap_di ^ bit(in) := in) = bitmap_uo is det.
:- pred unsafe_set_bit(bit_index, bool, bitmap, bitmap).
:- mode unsafe_set_bit(in, in, bitmap_di, bitmap_uo) is det.
:- func (bitmap ^ unsafe_bit(bit_index) := bool) = bitmap.
:- mode (bitmap_di ^ unsafe_bit(in) := in) = bitmap_uo is det.
%--------------------------------------------------%
%
% Bitmap ^ bits(OffSet, NumBits) = Word.
% The low order bits of Word contain the NumBits bits of BitMap
% starting at OffSet.
% 0 =< NumBits =< int.bits_per_int.
%
:- func get_bits(bitmap, bit_index, num_bits) = word.
% :- mode get_bits(bitmap_ui, in, in) = out is det.
:- mode get_bits(in, in, in) = out is det.
:- func bitmap ^ bits(bit_index, num_bits) = word.
% :- mode bitmap_ui ^ bits(in, in) = out is det.
:- mode in ^ bits(in, in) = out is det.
:- func unsafe_get_bits(bitmap, bit_index, num_bits) = word.
% :- mode unsafe_get_bits(bitmap_ui, in, in) = out is det.
:- mode unsafe_get_bits(in, in, in) = out is det.
:- func bitmap ^ unsafe_bits(bit_index, num_bits) = word.
% :- mode bitmap_ui ^ unsafe_bits(in, in) = out is det.
:- mode in ^ unsafe_bits(in, in) = out is det.
:- pred set_bits(bit_index, num_bits, word, bitmap, bitmap).
:- mode set_bits(in, in, in, bitmap_di, bitmap_uo) is det.
:- func (bitmap ^ bits(bit_index, num_bits) := word) = bitmap.
:- mode (bitmap_di ^ bits(in, in) := in) = bitmap_uo is det.
:- pred unsafe_set_bits(bit_index, num_bits, word, bitmap, bitmap).
:- mode unsafe_set_bits(in, in, in, bitmap_di, bitmap_uo) is det.
:- func (bitmap ^ unsafe_bits(bit_index, num_bits) := word) = bitmap.
:- mode (bitmap_di ^ unsafe_bits(in, in) := in) = bitmap_uo
is det.
%--------------------------------------------------%
%
% BM ^ byte(ByteNumber)
% Get or set the given numbered byte (multiply ByteNumber by
% bits_per_byte to get the bit index of the start of the byte).
%
% The bits are stored in or taken from the least significant bits of an int.
% The safe versions will throw an exception if the given ByteNumber is out of
% bounds. Final partial bytes are out of bounds. The unsafe versions do not
% check whether the byte is in range.
%
:- func get_byte(bitmap, byte_index) = byte.
% :- mode get_byte(bitmap_ui, in) = out is det.
:- mode get_byte(in, in) = out is det.
:- func bitmap ^ byte(byte_index) = byte.
% :- mode bitmap_ui ^ byte(in) = out is det.
:- mode in ^ byte(in) = out is det.
:- func unsafe_get_byte(bitmap, byte_index) = byte.
% :- mode unsafe_get_byte(bitmap_ui, in) = out is det.
:- mode unsafe_get_byte(in, in) = out is det.
:- func bitmap ^ unsafe_byte(byte_index) = byte.
% :- mode bitmap_ui ^ unsafe_byte(in) = out is det.
:- mode in ^ unsafe_byte(in) = out is det.
:- pred set_byte(byte_index, byte, bitmap, bitmap).
:- mode set_byte(in, in, bitmap_di, bitmap_uo) is det.
:- func (bitmap ^ byte(byte_index) := byte) = bitmap.
:- mode (bitmap_di ^ byte(in) := in) = bitmap_uo is det.
:- pred unsafe_set_byte(byte_index, byte, bitmap, bitmap).
:- mode unsafe_set_byte(in, in, bitmap_di, bitmap_uo) is det.
:- func (bitmap ^ unsafe_byte(byte_index) := byte) = bitmap.
:- mode (bitmap_di ^ unsafe_byte(in) := in) = bitmap_uo is det.
%
% Versions of the above that set or take uint8 values instead of a byte stored
% in the least significant bits of an int.
%
:- func get_uint8(bitmap, byte_index) = uint8.
%:- mode get_uint8(bitmap_ui, in) = out is det.
:- mode get_uint8(in, in) = out is det.
:- func unsafe_get_uint8(bitmap, byte_index) = uint8.
%:- mode unsafe_get_uint8(bitmap_ui, in) = out is det.
:- mode unsafe_get_uint8(in, in) = out is det.
:- pred set_uint8(byte_index::in, uint8::in,
bitmap::bitmap_di, bitmap::bitmap_uo) is det.
:- pred unsafe_set_uint8(byte_index::in, uint8::in,
bitmap::bitmap_di, bitmap::bitmap_uo) is det.
%--------------------------------------------------%
% Flip the given bit.
%
:- func flip(bitmap, bit_index) = bitmap.
:- mode flip(bitmap_di, in) = bitmap_uo is det.
:- pred flip(bit_index, bitmap, bitmap).
:- mode flip(in, bitmap_di, bitmap_uo) is det.
%--------------------------------------------------%
%
% Variations that might be slightly more efficient by not
% converting bits to bool.
%
:- func set(bitmap, bit_index) = bitmap.
:- mode set(bitmap_di, in) = bitmap_uo is det.
:- pred set(bit_index, bitmap, bitmap).
:- mode set(in, bitmap_di, bitmap_uo) is det.
:- func clear(bitmap, bit_index) = bitmap.
:- mode clear(bitmap_di, in) = bitmap_uo is det.
:- pred clear(bit_index, bitmap, bitmap).
:- mode clear(in, bitmap_di, bitmap_uo) is det.
% is_set(BM, I) and is_clear(BM, I) succeed iff bit I in BM
% is set or clear respectively.
%
:- pred is_set(bitmap, bit_index).
% :- mode is_set(bitmap_ui, in) is semidet.
:- mode is_set(in, in) is semidet.
:- pred is_clear(bitmap, bit_index).
% :- mode is_clear(bitmap_ui, in) is semidet.
:- mode is_clear(in, in) is semidet.
%--------------------------------------------------%
%
% Unsafe versions of the above. If the index is out of range,
% then behaviour is undefined, and bad things are likely to happen.
%
:- func unsafe_flip(bitmap, bit_index) = bitmap.
:- mode unsafe_flip(bitmap_di, in) = bitmap_uo is det.
:- pred unsafe_flip(bit_index, bitmap, bitmap).
:- mode unsafe_flip(in, bitmap_di, bitmap_uo) is det.
:- func unsafe_set(bitmap, bit_index) = bitmap.
:- mode unsafe_set(bitmap_di, in) = bitmap_uo is det.
:- pred unsafe_set(bit_index, bitmap, bitmap).
:- mode unsafe_set(in, bitmap_di, bitmap_uo) is det.
:- func unsafe_clear(bitmap, bit_index) = bitmap.
:- mode unsafe_clear(bitmap_di, in) = bitmap_uo is det.
:- pred unsafe_clear(bit_index, bitmap, bitmap).
:- mode unsafe_clear(in, bitmap_di, bitmap_uo) is det.
:- pred unsafe_is_set(bitmap, bit_index).
% :- mode unsafe_is_set(bitmap_ui, in) is semidet.
:- mode unsafe_is_set(in, in) is semidet.
:- pred unsafe_is_clear(bitmap, bit_index).
% :- mode unsafe_is_clear(bitmap_ui, in) is semidet.
:- mode unsafe_is_clear(in, in) is semidet.
%--------------------------------------------------%
% Create a new copy of a bitmap.
%
:- func copy(bitmap) = bitmap.
% :- mode copy(bitmap_ui) = bitmap_uo is det.
:- mode copy(in) = bitmap_uo is det.
% resize(BM, N, B) resizes bitmap BM to have N bits; if N is smaller
% than the current number of bits in BM then the excess are discarded.
% If N is larger than the current number of bits in BM, then
% the new bits are set if B = yes and cleared if B = no.
%
:- func resize(bitmap, num_bits, bool) = bitmap.
:- mode resize(bitmap_di, in, in) = bitmap_uo is det.
% Shrink a bitmap without copying it into a smaller memory allocation.
%
:- func shrink_without_copying(bitmap, num_bits) = bitmap.
:- mode shrink_without_copying(bitmap_di, in) = bitmap_uo is det.
%--------------------------------------------------%
% Slice = slice(BM, StartIndex, NumBits)
%
% A bitmap slice represents the sub-range of a bitmap of NumBits bits
% starting at bit index StartIndex. Throws an exception if the slice
% is not within the bounds of the bitmap.
%
:- type slice.
:- func slice(bitmap, bit_index, num_bits) = slice.
% As above, but use byte indices.
%
:- func byte_slice(bitmap, byte_index, num_bytes) = slice.
% Access functions for slices.
%
:- func slice ^ slice_bitmap = bitmap.
:- func slice ^ slice_start_bit_index = bit_index.
:- func slice ^ slice_num_bits = num_bits.
% As above, but return byte indices, throwing an exception
% if the slice doesn't start and end on a byte boundary.
%
:- func slice ^ slice_start_byte_index = byte_index.
:- func slice ^ slice_num_bytes = num_bytes.
%--------------------------------------------------%
%
% Set operations; for binary operations the second argument is altered
% in all cases. The input bitmaps must have the same size.
%
:- func complement(bitmap) = bitmap.
:- mode complement(bitmap_di) = bitmap_uo is det.
:- func union(bitmap, bitmap) = bitmap.
% :- mode union(bitmap_ui, bitmap_di) = bitmap_uo is det.
:- mode union(in, bitmap_di) = bitmap_uo is det.
:- func intersect(bitmap, bitmap) = bitmap.
% :- mode intersect(bitmap_ui, bitmap_di) = bitmap_uo is det.
:- mode intersect(in, bitmap_di) = bitmap_uo is det.
:- func difference(bitmap, bitmap) = bitmap.
% :- mode difference(bitmap_ui, bitmap_di) = bitmap_uo is det.
:- mode difference(in, bitmap_di) = bitmap_uo is det.
:- func xor(bitmap, bitmap) = bitmap.
% :- mode xor(bitmap_ui, bitmap_di) = bitmap_uo is det.
:- mode xor(in, bitmap_di) = bitmap_uo is det.
%--------------------------------------------------%
% Condense a list of bitmaps into a single bitmap.
%
:- func append_list(list(bitmap)) = bitmap.
:- mode append_list(in) = bitmap_uo is det.
%--------------------------------------------------%
%
% Operations to copy part of a bitmap.
%
% copy_bits(SrcBM, SrcStartBit, DestBM, DestStartBit, NumBits)
%
% Overwrite NumBits bits in DestBM starting at DestStartBit with
% the NumBits bits starting at SrcStartBit in SrcBM.
%
:- func copy_bits(bitmap, bit_index, bitmap, bit_index, num_bits) = bitmap.
% :- mode copy_bits(bitmap_ui, in, bitmap_di, in, in) = bitmap_uo is det.
:- mode copy_bits(in, in, bitmap_di, in, in) = bitmap_uo is det.
% copy_bits_in_bitmap(BM, SrcStartBit, DestStartBit, NumBits)
%
% Overwrite NumBits bits starting at DestStartBit with the NumBits
% bits starting at SrcStartBit in the same bitmap.
%
:- func copy_bits_in_bitmap(bitmap, bit_index, bit_index, num_bits) = bitmap.
:- mode copy_bits_in_bitmap(bitmap_di, in, in, in) = bitmap_uo is det.
% copy_bytes(SrcBM, SrcStartByte, DestBM, DestStartByte, NumBytes)
%
% Overwrite NumBytes bytes in DestBM starting at DestStartByte with
% the NumBytes bytes starting at SrcStartByte in SrcBM.
%
:- func copy_bytes(bitmap, byte_index, bitmap, byte_index, num_bytes) = bitmap.
% :- mode copy_bytes(bitmap_ui, in, bitmap_di, in, in) = bitmap_uo is det.
:- mode copy_bytes(in, in, bitmap_di, in, in) = bitmap_uo is det.
% copy_bytes_in_bitmap(BM, SrcStartByte, DestStartByte, NumBytes)
%
% Overwrite NumBytes bytes starting at DestStartByte with the NumBytes
% bytes starting at SrcStartByte in the same bitmap.
%
:- func copy_bytes_in_bitmap(bitmap, byte_index,
byte_index, num_bytes) = bitmap.
:- mode copy_bytes_in_bitmap(bitmap_di, in, in, in) = bitmap_uo is det.
%--------------------------------------------------%
% Convert a bitmap to a string of the form "<length:hex digits>",
% e.g. "<24:10AFBD>".
%
:- func to_string(bitmap) = string.
% :- mode to_string(bitmap_ui) = out is det.
:- mode to_string(in) = out is det.
% Convert a string created by to_string back into a bitmap.
% Fails if the string is not of the form created by to_string.
%
:- func from_string(string) = bitmap.
:- mode from_string(in) = bitmap_uo is semidet.
% As above, but throws an exception instead of failing.
%
:- func det_from_string(string) = bitmap.
:- mode det_from_string(in) = bitmap_uo is det.
% Convert a bitmap to a string of `1' and `0' characters, where
% the bytes are separated by `.'.
%
:- func to_byte_string(bitmap) = string.
% :- mode to_byte_string(bitmap_ui) = out is det.
:- mode to_byte_string(in) = out is det.
%--------------------------------------------------%
% Compute a hash function for a bitmap.
%
:- func hash(bitmap) = int.
% :- mode hash(bitmap_ui) = out is det.
:- mode hash(in) = out is det.
%--------------------------------------------------%
%--------------------------------------------------%
Next: bool, Previous: bit_buffer.write, Up: Top [Contents]