Skip to content

Commit

Permalink
cii: Add bit vector interface
Browse files Browse the repository at this point in the history
  • Loading branch information
XuShaohua committed Dec 7, 2023
1 parent 5600c0a commit 15a25c7
Show file tree
Hide file tree
Showing 3 changed files with 279 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cii/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(SOURCE_FILES
src/arith.c
src/assert.c
src/atom.c
src/bit.c
src/except.c
src/hash.c
src/list.c
Expand All @@ -25,6 +26,7 @@ set(HEADER_FILES
include/cii/arith.h
include/cii/assert.h
include/cii/atom.h
include/cii/bit.h
include/cii/except.h
include/cii/hash.h
include/cii/list.h
Expand Down
166 changes: 166 additions & 0 deletions cii/include/cii/bit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// Copyright (c) 2023 Xu Shaohua <[email protected]>. All rights reserved.
// Use of this source is governed by GNU General Public License
// that can be found in the LICENSE file.

#ifndef CII_BIT_H
#define CII_BIT_H

#include <stdbool.h>
#include <stddef.h>

typedef struct bit_s bit_t;

/**
* Create a bit vector with fixed |length| and sets all the bits to zero.
*
* @param length
* @return
*/
extern bit_t* bit_new(size_t length);

/**
* Get fixed length of a bit vector.
*
* @param set
* @return
*/
extern size_t bit_length(bit_t* set);

/**
* Returns number of bits with one values in a bit vector.
*
* @param set
* @return
*/
extern size_t bit_count_ones(bit_t* set);

/**
* Returns number of bits with zero values in a bit vector.
* @param set
* @return
*/
extern size_t bit_count_zeros(bit_t* set);

/**
* Deallocate and clear a bit vector.
*
* @param set
*/
extern void bit_free(bit_t** set);

/**
* Check bit at |index| is set or not.
*
* @param set
* @param index
* @return
*/
extern bool bit_get(bit_t* set, size_t index);

/**
* update bit value at |index| and returns old value.
*
* @param set
* @param index
* @param value
* @return
*/
extern bool bit_put(bit_t* set, size_t index, bool value);

/**
* Clear bits in range [start, end) in a bit vector.
*
* @param set
* @param start
* @param end
*/
extern void bit_clear(bit_t* set, size_t start, size_t end);

/**
* Set bits in range [start, end) in a bit vector.
*
* @param set
* @param start
* @param end
*/
extern void bit_set(bit_t* set, size_t start, size_t end);

/**
* Toggle bits in range [start, end) in a bit vector.
*
* @param set
* @param start
* @param end
*/
extern void bit_not(bit_t* set, size_t start, size_t end);

/**
* Check whether bit vector s is less than t.
*
* @param s
* @param t
* @return
*/
extern bool bit_less(bit_t* s, bit_t* t);

/**
* Check whether bit vector s equals to t.
*
* @param s
* @param t
* @return
*/
extern bool bit_equal(bit_t* s, bit_t* t);

/**
* Check whether bit vector s is less than or equal to t.
*
* @param s
* @param t
* @return
*/
extern bool bit_less_equal(bit_t* s, bit_t* t);

/**
* Calls |apply| for each bit in set.
* @param s
* @param apply
* @param user_data
*/
extern void bit_map(bit_t* s,
void(*apply)(size_t index, bool is_set, void* user_data),
void* user_data);

/**
* Returns the union of s and t, denoted s + t.
* @param s
* @param t
* @return
*/
extern bit_t* bit_union(bit_t* s, bit_t* t);

/**
* Returns the intersection of s and t, denoted s * t.
* @param s
* @param t
* @return
*/
extern bit_t* bit_inter(bit_t* s, bit_t* t);

/**
* Returns the difference of s and t, denoted s - t.
* @param s
* @param t
* @return
*/
extern bit_t* bit_minus(bit_t* s, bit_t* t);

/**
* Returns the symmetric difference of s and t, denoted s / t.
* @param s
* @param t
* @return
*/
extern bit_t* bit_diff(bit_t* s, bit_t* t);

#endif // CII_BIT_H
111 changes: 111 additions & 0 deletions cii/src/bit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (c) 2023 Xu Shaohua <[email protected]>. All rights reserved.
// Use of this source is governed by GNU General Public License
// that can be found in the LICENSE file.

#include "cii/bit.h"

#include <stdarg.h>
#include <string.h>
#include <stdint.h>

#include "cii/assert.h"
#include "cii/mem.h"

struct bit_s {
// The |length| field gives the number of bits in the vector.
size_t length;

// |bytes| points to at least [length / 8] bytes.
// The bits are accessed by indexing bytes.
uint8_t* bytes;
size_t* words;
};

// Bytes per word.
static size_t bpw() {
return 8 * sizeof(size_t);
}

// Computes the number of words needed for a bit vector of length bits.
static size_t num_words(size_t length) {
return ((length + bpw() - 1) & (~(bpw() - 1))) / bpw();
}

bit_t* bit_new(size_t length) {
bit_t* set;
NEW(set);
if (length > 0) {
set->words = CALLOC(num_words(length), sizeof(size_t));
} else {
set->words = NULL;
}
set->length = length;
set->bytes = (uint8_t*) set->words;

return set;
}

void bit_free(bit_t** set) {
assert(set != NULL && *set != NULL);
FREE((*set)->words);
FREE(*set);
}

size_t bit_length(bit_t* set) {
assert(set != NULL);
return set->length;
}

size_t bit_count_ones(bit_t* set) {
assert(set != NULL);
size_t length = 0;
const uint8_t kCount[] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4
};
const size_t n_words = num_words(set->length);
for (size_t i = 0; i < n_words; ++i) {
uint8_t c = set->bytes[i];
length += kCount[c & 0x0F] + kCount[c >> 4];
}

return length;
}

size_t bit_count_zeros(bit_t* set) {
assert(set != NULL);
return bit_length(set) - bit_count_ones(set);
}

static bool bit_get_bit(bit_t* set, size_t index) {
return (set->bytes[ index / 8] >> (index % 8)) & 1;
}

bool bit_get(bit_t* set, size_t index) {
assert(set != NULL);
assert(index < set->length);
return bit_get_bit(set, index);
}

bool bit_put(bit_t* set, size_t index, bool value) {
assert(set != NULL);
assert(index < set->length);
const bool prev = bit_get_bit(set, index);
if (value) {
set->bytes[index / 8] |= 1 << (index % 8);
} else {
set->bytes[index / 8] &= ~(1 << (index % 8));
}
return prev;
}

void bit_clear(bit_t* set, size_t start, size_t end) {

}

void bit_set(bit_t* set, size_t start, size_t end) {

}

void bit_not(bit_t* set, size_t start, size_t end) {

}

0 comments on commit 15a25c7

Please sign in to comment.