docs
This commit is contained in:
parent
ef7ac48e32
commit
4ebe555fac
271
src/sparsemap.c
271
src/sparsemap.c
|
@ -150,13 +150,20 @@ __sm_chunk_map_calc_vector_size(uint8_t b)
|
||||||
return (size_t)lookup[b];
|
return (size_t)lookup[b];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Returns the position of a sm_bitvec_t in m_data.
|
||||||
* Returns the position of a sm_bitvec_t in m_data.
|
*
|
||||||
|
* Each chunk has a set of bitvec that are sometimes abbreviated due to
|
||||||
|
* compression (e.g. when a bitvec is all zeros or ones there is no need
|
||||||
|
* to store anything, so no wasted space).
|
||||||
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param[in] bv The index of the vector to find in the chunk.
|
||||||
|
* @returns the position of a sm_bitvec_t in m_data
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_chunk_map_get_position(__sm_chunk_t *map, size_t bv)
|
__sm_chunk_map_get_position(__sm_chunk_t *map, size_t bv)
|
||||||
{
|
{
|
||||||
// handle 4 indices (1 byte) at a time
|
/* Handle 4 indices (1 byte) at a time. */
|
||||||
size_t num_bytes = bv / ((size_t)SM_FLAGS_PER_INDEX_BYTE * SM_BITS_PER_VECTOR);
|
size_t num_bytes = bv / ((size_t)SM_FLAGS_PER_INDEX_BYTE * SM_BITS_PER_VECTOR);
|
||||||
|
|
||||||
size_t position = 0;
|
size_t position = 0;
|
||||||
|
@ -176,8 +183,10 @@ __sm_chunk_map_get_position(__sm_chunk_t *map, size_t bv)
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Initialize __sm_chunk_t with provided data.
|
||||||
* Initialize __sm_chunk_t with provided data.
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param[in] data The memory to use within this chunk.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
__sm_chunk_map_init(__sm_chunk_t *map, uint8_t *data)
|
__sm_chunk_map_init(__sm_chunk_t *map, uint8_t *data)
|
||||||
|
@ -185,8 +194,10 @@ __sm_chunk_map_init(__sm_chunk_t *map, uint8_t *data)
|
||||||
map->m_data = (sm_bitvec_t *)data;
|
map->m_data = (sm_bitvec_t *)data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Examines the chunk to determine its current capacity.
|
||||||
* Returns the maximum capacity of this __sm_chunk_t.
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @returns the maximum capacity in bytes of this __sm_chunk_t
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_chunk_map_get_capacity(__sm_chunk_t *map)
|
__sm_chunk_map_get_capacity(__sm_chunk_t *map)
|
||||||
|
@ -208,8 +219,11 @@ __sm_chunk_map_get_capacity(__sm_chunk_t *map)
|
||||||
return capacity;
|
return capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Sets the capacity of this chunk.
|
||||||
* Sets the capacity.
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param[in] capacity The new capacity in bytes to assign to the chunk,
|
||||||
|
* must be less than SM_CHUNK_MAX_CAPACITY.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
__sm_chunk_map_set_capacity(__sm_chunk_t *map, size_t capacity)
|
__sm_chunk_map_set_capacity(__sm_chunk_t *map, size_t capacity)
|
||||||
|
@ -236,8 +250,10 @@ __sm_chunk_map_set_capacity(__sm_chunk_t *map, size_t capacity)
|
||||||
__sm_assert(__sm_chunk_map_get_capacity(map) == capacity);
|
__sm_assert(__sm_chunk_map_get_capacity(map) == capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Examines the chunk to determine if it is empty.
|
||||||
* Returns true if this __sm_chunk_t is empty.
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @returns true if this __sm_chunk_t is empty
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
__sm_chunk_map_is_empty(__sm_chunk_t *map)
|
__sm_chunk_map_is_empty(__sm_chunk_t *map)
|
||||||
|
@ -262,8 +278,10 @@ __sm_chunk_map_is_empty(__sm_chunk_t *map)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Examines the chunk to determine its size.
|
||||||
* Returns the size of the data buffer, in bytes.
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @returns the size of the data buffer, in bytes.
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_chunk_map_get_size(__sm_chunk_t *map)
|
__sm_chunk_map_get_size(__sm_chunk_t *map)
|
||||||
|
@ -279,8 +297,12 @@ __sm_chunk_map_get_size(__sm_chunk_t *map)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Examines the chunk at \b idx to determine that bit's state (set,
|
||||||
* Returns the value of a bit at index |idx|.
|
* or unset).
|
||||||
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param[in] idx The 0-based index into this chunk to examine.
|
||||||
|
* @returns the value of a bit at index \b idx
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
__sm_chunk_map_is_set(__sm_chunk_t *map, size_t idx)
|
__sm_chunk_map_is_set(__sm_chunk_t *map, size_t idx)
|
||||||
|
@ -308,14 +330,21 @@ __sm_chunk_map_is_set(__sm_chunk_t *map, size_t idx)
|
||||||
return (w & ((sm_bitvec_t)1 << (idx % SM_BITS_PER_VECTOR))) > 0;
|
return (w & ((sm_bitvec_t)1 << (idx % SM_BITS_PER_VECTOR))) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Assigns a state to a bit in the chunk (set or unset).
|
||||||
* Sets the value of a bit at index |idx|. Returns SM_NEEDS_TO_GROW,
|
|
||||||
* SM_NEEDS_TO_SHRINK, or SM_OK. Sets |position| to the position of the
|
|
||||||
* sm_bitvec_t which is inserted/deleted and |fill| - the value of the fill
|
|
||||||
* word (used when growing).
|
|
||||||
*
|
*
|
||||||
* Note, the caller MUST to perform the relevant actions and call set() again,
|
* Sets the value of a bit at index \b idx. Then updates position \b pos to the
|
||||||
* this time with |retried| = true.
|
* position of the sm_bitvec_t which is inserted/deleted and \b fill - the value
|
||||||
|
* of the fill word (used when growing).
|
||||||
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param[in] idx The 0-based index into this chunk to mutate.
|
||||||
|
* @param[in] value The new state for the \b idx'th bit.
|
||||||
|
* @param[in,out] pos The position of the sm_bitvec_t inserted/deleted within the chunk.
|
||||||
|
* @param[in,out] fill The value of the fill word (when growing).
|
||||||
|
* @param[in] retired When not retried, grow the map by a bitvec.
|
||||||
|
* @returns \b SM_NEEDS_TO_GROW, \b SM_NEEDS_TO_SHRINK, or \b SM_OK
|
||||||
|
* @note, the caller MUST to perform the relevant actions and call set() again,
|
||||||
|
* this time with \b retried = true.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
__sm_chunk_map_set(__sm_chunk_t *map, size_t idx, bool value, size_t *pos, sm_bitvec_t *fill, bool retried)
|
__sm_chunk_map_set(__sm_chunk_t *map, size_t idx, bool value, size_t *pos, sm_bitvec_t *fill, bool retried)
|
||||||
|
@ -394,13 +423,22 @@ __sm_chunk_map_set(__sm_chunk_t *map, size_t idx, bool value, size_t *pos, sm_bi
|
||||||
return SM_OK;
|
return SM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Finds the index of the \b n'th bit after \b offset bits with \b value.
|
||||||
* Returns the index of the offset'th set bit; sets |*pnew_n| to 0 if the
|
*
|
||||||
* offset'th bit was found in this __sm_chunk_t, or to the new, reduced
|
* Scans the chunk \b map until after \b offset bits (of any value) have
|
||||||
* value of |offset|.
|
* passed and then begins counting the bits that match \b value looking
|
||||||
|
* for the \b n'th bit. It may not be in this chunk, when it is offset is
|
||||||
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param[in] value Informs what we're seeking, a set or unset bit's position.
|
||||||
|
* @param offset[in,out] Sets \b offset to 0 if the n'th bit was found
|
||||||
|
* in this __sm_chunk_t, or reduced value of \b n bits observed the search up
|
||||||
|
* to a maximum of SM_BITS_PER_VECTOR.
|
||||||
|
* @returns the 0-based index of the n'th set bit when found, otherwise
|
||||||
|
* SM_BITS_PER_VECTOR
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_chunk_map_select(__sm_chunk_t *map, size_t offset, ssize_t *pnew_n, bool value)
|
__sm_chunk_map_select(__sm_chunk_t *map, size_t n, ssize_t *offset, bool value)
|
||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
register uint8_t *p;
|
register uint8_t *p;
|
||||||
|
@ -422,24 +460,24 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t offset, ssize_t *pnew_n, bool va
|
||||||
ret += SM_BITS_PER_VECTOR;
|
ret += SM_BITS_PER_VECTOR;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (offset > SM_BITS_PER_VECTOR) {
|
if (n > SM_BITS_PER_VECTOR) {
|
||||||
offset -= SM_BITS_PER_VECTOR;
|
n -= SM_BITS_PER_VECTOR;
|
||||||
ret += SM_BITS_PER_VECTOR;
|
ret += SM_BITS_PER_VECTOR;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*pnew_n = -1;
|
*offset = -1;
|
||||||
return ret + offset;
|
return ret + n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flags == SM_PAYLOAD_ONES) {
|
if (flags == SM_PAYLOAD_ONES) {
|
||||||
if (value == true) {
|
if (value == true) {
|
||||||
if (offset > SM_BITS_PER_VECTOR) {
|
if (n > SM_BITS_PER_VECTOR) {
|
||||||
offset -= SM_BITS_PER_VECTOR;
|
n -= SM_BITS_PER_VECTOR;
|
||||||
ret += SM_BITS_PER_VECTOR;
|
ret += SM_BITS_PER_VECTOR;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*pnew_n = -1;
|
*offset = -1;
|
||||||
return ret + offset;
|
return ret + n;
|
||||||
} else {
|
} else {
|
||||||
ret += SM_BITS_PER_VECTOR;
|
ret += SM_BITS_PER_VECTOR;
|
||||||
continue;
|
continue;
|
||||||
|
@ -450,20 +488,20 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t offset, ssize_t *pnew_n, bool va
|
||||||
for (int k = 0; k < SM_BITS_PER_VECTOR; k++) {
|
for (int k = 0; k < SM_BITS_PER_VECTOR; k++) {
|
||||||
if (value) {
|
if (value) {
|
||||||
if (w & ((sm_bitvec_t)1 << k)) {
|
if (w & ((sm_bitvec_t)1 << k)) {
|
||||||
if (offset == 0) {
|
if (n == 0) {
|
||||||
*pnew_n = -1;
|
*offset = -1;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
offset--;
|
n--;
|
||||||
}
|
}
|
||||||
ret++;
|
ret++;
|
||||||
} else {
|
} else {
|
||||||
if (!(w & ((sm_bitvec_t)1 << k))) {
|
if (!(w & ((sm_bitvec_t)1 << k))) {
|
||||||
if (offset == 0) {
|
if (n == 0) {
|
||||||
*pnew_n = -1;
|
*offset = -1;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
offset--;
|
n--;
|
||||||
}
|
}
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
|
@ -471,17 +509,35 @@ __sm_chunk_map_select(__sm_chunk_t *map, size_t offset, ssize_t *pnew_n, bool va
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*pnew_n = (ssize_t)offset;
|
*offset = (ssize_t)n;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void print_bits(char *name, uint64_t value); // GSB
|
extern void print_bits(char *name, uint64_t value); // GSB
|
||||||
|
|
||||||
/**
|
/** @brief Counts the bits matching \b value in the range [0, \b idx]
|
||||||
* Counts the set bits in the range [0, 'idx'] inclusive ignoring the first
|
* inclusive after ignoring the first \b offset bits in the chunk.
|
||||||
* '*offset' bits in this chunk. Modifies '*offset' decreasing it by the number
|
*
|
||||||
* of bits ignored during the search. The ranking (counting) will start after
|
* Scans the chunk \b map until after \b offset bits (of any value) have
|
||||||
* the '*offset' has been reached 0.
|
* passed and then begins counting the bits that match \b value. The
|
||||||
|
* result should never be greater than \b idx + 1 maxing out at
|
||||||
|
* SM_BITS_PER_VECTOR. A range of [0, 0] will count 1 bit at \b offset
|
||||||
|
* + 1 in this chunk. A range of [0, 9] will count 10 bits, starting
|
||||||
|
* with the 0th and ending with the 9th and return at most a count of
|
||||||
|
* 10.
|
||||||
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param offset[in,out] Decreases \b offset by the number of bits ignored,
|
||||||
|
* at most by SM_BITS_PER_VECTOR.
|
||||||
|
* @param[in] idx The ending value of the range (inclusive) to count.
|
||||||
|
* @param[out] pos The position of the last bit examined in this chunk, always
|
||||||
|
* <= SM_BITS_PER_VECTOR, used when counting unset bits that fall within this
|
||||||
|
* chunk's range but after the last set bit.
|
||||||
|
* @param[out] vec The last sm_bitvec_t, masked and shifted, so as to be able
|
||||||
|
* to examine the bits used in the last portion of the ranking as a way to
|
||||||
|
* skip forward during a #span() operation.
|
||||||
|
* @param[in] value Informs what we're seeking, set or unset bits.
|
||||||
|
* @returns the count of the bits matching \b value within the range.
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, size_t *pos, sm_bitvec_t *vec, bool value)
|
__sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, size_t *pos, sm_bitvec_t *vec, bool value)
|
||||||
|
@ -591,7 +647,7 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, size_t *pos,
|
||||||
}
|
}
|
||||||
int pc = popcountll(mw);
|
int pc = popcountll(mw);
|
||||||
ret += pc;
|
ret += pc;
|
||||||
*vec = mw >> *offset;
|
*vec = mw >> ((*offset > 63) ? 63 : *offset);
|
||||||
*offset = *offset > idx ? *offset - idx + 1 : 0;
|
*offset = *offset > idx ? *offset - idx + 1 : 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -601,9 +657,15 @@ __sm_chunk_map_rank(__sm_chunk_t *map, size_t *offset, size_t idx, size_t *pos,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Calls \b scanner with sm_bitmap_t for each vector in this chunk.
|
||||||
* Decompresses the whole bitmap; calls visitor's operator() for all bits
|
*
|
||||||
* Returns the number of (set) bits that were passed to the scanner
|
* Decompresses the whole chunk into separate bitmaps then calls visitor's
|
||||||
|
* \b #operator() function for all bits.
|
||||||
|
*
|
||||||
|
* @param[in] map The chunk in question.
|
||||||
|
* @param[in] start
|
||||||
|
* @param[in] scanner
|
||||||
|
* @returns the number of (set) bits that were passed to the scanner
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[], size_t), size_t skip)
|
__sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[], size_t), size_t skip)
|
||||||
|
@ -672,12 +734,10 @@ __sm_chunk_map_scan(__sm_chunk_t *map, sm_idx_t start, void (*scanner)(sm_idx_t[
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/** @brief Provides the number of chunks currently in the map.
|
||||||
* The following is the "Sparsemap" implementation, it uses Chunk Maps (above).
|
*
|
||||||
*/
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @returns the number of chunk maps in the sparsemap
|
||||||
/**
|
|
||||||
* Returns the number of chunk maps.
|
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_get_chunk_map_count(sparsemap_t *map)
|
__sm_get_chunk_map_count(sparsemap_t *map)
|
||||||
|
@ -685,8 +745,12 @@ __sm_get_chunk_map_count(sparsemap_t *map)
|
||||||
return *(uint32_t *)&map->m_data[0];
|
return *(uint32_t *)&map->m_data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Encapsulates the method to find the starting address of a chunk's
|
||||||
* Returns the data at the specified |offset|.
|
* data.
|
||||||
|
*
|
||||||
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @param[in] offset The offset in bytes for the desired chunk map.
|
||||||
|
* @returns the data for the specified \b offset
|
||||||
*/
|
*/
|
||||||
static inline uint8_t *
|
static inline uint8_t *
|
||||||
__sm_get_chunk_map_data(sparsemap_t *map, size_t offset)
|
__sm_get_chunk_map_data(sparsemap_t *map, size_t offset)
|
||||||
|
@ -694,13 +758,16 @@ __sm_get_chunk_map_data(sparsemap_t *map, size_t offset)
|
||||||
return &map->m_data[SM_SIZEOF_OVERHEAD + offset];
|
return &map->m_data[SM_SIZEOF_OVERHEAD + offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Encapsulates the method to find the address of the first unused byte
|
||||||
* Returns a pointer after the end of the used data.
|
* in \b m_data.
|
||||||
|
*
|
||||||
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @returns a pointer after the end of the used data
|
||||||
|
* @todo could this simply use m_data_used?
|
||||||
*/
|
*/
|
||||||
static uint8_t *
|
static uint8_t *
|
||||||
__sm_get_chunk_map_end(sparsemap_t *map)
|
__sm_get_chunk_map_end(sparsemap_t *map)
|
||||||
{
|
{
|
||||||
// TODO: could this simply use m_data_used?
|
|
||||||
uint8_t *p = __sm_get_chunk_map_data(map, 0);
|
uint8_t *p = __sm_get_chunk_map_data(map, 0);
|
||||||
size_t count = __sm_get_chunk_map_count(map);
|
size_t count = __sm_get_chunk_map_count(map);
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
@ -712,8 +779,10 @@ __sm_get_chunk_map_end(sparsemap_t *map)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Provides the byte size amount of \b m_data consumed.
|
||||||
* Returns the used size in the data buffer.
|
*
|
||||||
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @returns the used size in the data buffer
|
||||||
*/
|
*/
|
||||||
static size_t
|
static size_t
|
||||||
__sm_get_size_impl(sparsemap_t *map)
|
__sm_get_size_impl(sparsemap_t *map)
|
||||||
|
@ -731,8 +800,10 @@ __sm_get_size_impl(sparsemap_t *map)
|
||||||
return SM_SIZEOF_OVERHEAD + p - start;
|
return SM_SIZEOF_OVERHEAD + p - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Aligns to SM_BITS_PER_VECTOR a given index \b idx.
|
||||||
* Returns the aligned offset (aligned to sm_bitvec_t capacity).
|
*
|
||||||
|
* @param[in] idx The index to align.
|
||||||
|
* @returns the aligned offset (aligned to sm_bitvec_t capacity).
|
||||||
*/
|
*/
|
||||||
static sm_idx_t
|
static sm_idx_t
|
||||||
__sm_get_aligned_offset(size_t idx)
|
__sm_get_aligned_offset(size_t idx)
|
||||||
|
@ -741,10 +812,25 @@ __sm_get_aligned_offset(size_t idx)
|
||||||
return (idx / capacity) * capacity;
|
return (idx / capacity) * capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Aligns to SM_CHUNK_MAP_CAPACITY a given index \b idx.
|
||||||
* Returns the byte offset of a __sm_chunk_t in m_data.
|
*
|
||||||
|
* @param[in] idx The index to align.
|
||||||
|
* @returns the aligned offset (aligned to __sm_chunk_t capacity)
|
||||||
*/
|
*/
|
||||||
static ssize_t
|
static sm_idx_t
|
||||||
|
__sm_get_fully_aligned_offset(size_t idx)
|
||||||
|
{
|
||||||
|
const size_t capacity = SM_CHUNK_MAX_CAPACITY;
|
||||||
|
return (idx / capacity) * capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Provides the byte offset of a chunk map at index \b idx.
|
||||||
|
*
|
||||||
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @param[in] idx The index of the chunk map to locate.
|
||||||
|
* @returns the byte offset of a __sm_chunk_t in m_data.
|
||||||
|
*/
|
||||||
|
static size_t
|
||||||
__sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
|
__sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
|
||||||
{
|
{
|
||||||
size_t count = __sm_get_chunk_map_count(map);
|
size_t count = __sm_get_chunk_map_count(map);
|
||||||
|
@ -769,18 +855,10 @@ __sm_get_chunk_map_offset(sparsemap_t *map, sparsemap_idx_t idx)
|
||||||
return (ssize_t)(p - start);
|
return (ssize_t)(p - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Sets the number of __sm_chunk_t's.
|
||||||
* Returns the aligned offset (aligned to __sm_chunk_t capacity).
|
*
|
||||||
*/
|
* @param[in] map The sparsemap_t in question.
|
||||||
static sm_idx_t
|
* @param[in] new_count The new number of chunks in the map.
|
||||||
__sm_get_fully_aligned_offset(size_t idx)
|
|
||||||
{
|
|
||||||
const size_t capacity = SM_CHUNK_MAX_CAPACITY;
|
|
||||||
return (idx / capacity) * capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the number of __sm_chunk_t's.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
__sm_set_chunk_map_count(sparsemap_t *map, size_t new_count)
|
__sm_set_chunk_map_count(sparsemap_t *map, size_t new_count)
|
||||||
|
@ -788,8 +866,11 @@ __sm_set_chunk_map_count(sparsemap_t *map, size_t new_count)
|
||||||
*(uint32_t *)&map->m_data[0] = (uint32_t)new_count;
|
*(uint32_t *)&map->m_data[0] = (uint32_t)new_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Appends raw data at the end of used portion of \b m_data.
|
||||||
* Appends more data.
|
*
|
||||||
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @param[in] buffer The bytes to copy into \b m_data.
|
||||||
|
* @param[in] buffer_size The size of the byte array \b buffer to copy.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
__sm_append_data(sparsemap_t *map, uint8_t *buffer, size_t buffer_size)
|
__sm_append_data(sparsemap_t *map, uint8_t *buffer, size_t buffer_size)
|
||||||
|
@ -798,8 +879,12 @@ __sm_append_data(sparsemap_t *map, uint8_t *buffer, size_t buffer_size)
|
||||||
map->m_data_used += buffer_size;
|
map->m_data_used += buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Inserts data at \b offset in the middle of \b m_data.
|
||||||
* Inserts data somewhere in the middle of m_data.
|
*
|
||||||
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @param[in] offset The offset in bytes into \b m_data to place the buffer.
|
||||||
|
* @param[in] buffer The bytes to copy into \b m_data.
|
||||||
|
* @param[in] buffer_size The size of the byte array \b buffer to copy.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
__sm_insert_data(sparsemap_t *map, size_t offset, uint8_t *buffer, size_t buffer_size)
|
__sm_insert_data(sparsemap_t *map, size_t offset, uint8_t *buffer, size_t buffer_size)
|
||||||
|
@ -810,8 +895,11 @@ __sm_insert_data(sparsemap_t *map, size_t offset, uint8_t *buffer, size_t buffer
|
||||||
map->m_data_used += buffer_size;
|
map->m_data_used += buffer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Removes data from \b m_data.
|
||||||
* Removes data from m_data.
|
*
|
||||||
|
* @param[in] map The sparsemap_t in question.
|
||||||
|
* @param[in] offset The offset in bytes into \b m_data at which to excise data.
|
||||||
|
* @param[in] gap_size The size of the excision.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
__sm_remove_data(sparsemap_t *map, size_t offset, size_t gap_size)
|
__sm_remove_data(sparsemap_t *map, size_t offset, size_t gap_size)
|
||||||
|
@ -822,9 +910,11 @@ __sm_remove_data(sparsemap_t *map, size_t offset, size_t gap_size)
|
||||||
map->m_data_used -= gap_size;
|
map->m_data_used -= gap_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Clears the whole buffer
|
* The following is the "Sparsemap" implementation, it uses chunk maps (code above)
|
||||||
|
* and is the public API for this compressed bitmap representation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
sparsemap_clear(sparsemap_t *map)
|
sparsemap_clear(sparsemap_t *map)
|
||||||
{
|
{
|
||||||
|
@ -1127,8 +1217,7 @@ sparsemap_get_size(sparsemap_t *map)
|
||||||
{
|
{
|
||||||
if (map->m_data_used) {
|
if (map->m_data_used) {
|
||||||
__sm_when_diag({
|
__sm_when_diag({
|
||||||
size_t used = __sm_get_size_impl(map);
|
__sm_assert(map->m_data_used == __sm_get_size_impl(map));
|
||||||
__sm_assert(map->m_data_used == used);
|
|
||||||
});
|
});
|
||||||
return map->m_data_used;
|
return map->m_data_used;
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,7 +380,7 @@ sm_add_span(sparsemap_t *map, int map_size, int span_length)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (attempts);
|
} while (attempts);
|
||||||
for (int i = placed_at; i < placed_at + span_length; i++) {
|
for (sparsemap_idx_t i = placed_at; i < placed_at + span_length; i++) {
|
||||||
if (sparsemap_set(map, i, true) != i) {
|
if (sparsemap_set(map, i, true) != i) {
|
||||||
return placed_at; // TODO error?
|
return placed_at; // TODO error?
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue