Skip to content

Commit

Permalink
Minimal functional
Browse files Browse the repository at this point in the history
`set`, `reset`, and `test`.
  • Loading branch information
cubicYYY committed Aug 31, 2024
1 parent 730d273 commit 478a965
Show file tree
Hide file tree
Showing 22 changed files with 922 additions and 566 deletions.
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ IndentWidth: 4
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Attach
ColumnLimit: 80
ColumnLimit: 120
ContinuationIndentWidth: 4
IndentCaseLabels: true
AccessModifierOffset: -4
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
project(FlexibleRoaringBitmap)

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# Add subdirectories
Expand Down
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
# Flexible Roaring Bitmap

*Flexible Roaring Bitmap* is a variation of [Roaring Bitmap](), with a flexible interface based on templates.
**Work in Progress.**

*Flexible Roaring Bitmap* is a variation of [Roaring Bitmap](https://github.com/RoaringBitmap/CRoaring), with a flexible interface based on templates.

You can custom the index size, the container size and the underlying word size.

It is optimized for small containers: if only a single container is needed, no arrays will be used.
## Components

### Flexible Roaring Bitmap

Out-of-the-box bitmap for handling sparse bit maps.

- Minimizes memory usage.
- Structure: `BinSearchIndex -> Containers`, or `Single container` for small ones.

### Containers

- Bitmap: use bits to represent 0 & 1.
- Array: number indices.
- RLE: Run-Length Encoded array

### Index Layer

- BinSearchIndex
- RBTreeIndex (TODO)

## Usage

```bash
# Clone the repository
git clone ...
git clone https://github.com/cubicYYY/FlexibleRoaringBitmap.git
cd ./FlexibleRoaringBitmap

# Build examples
Expand All @@ -23,6 +43,4 @@ make -j
# Run examples
./example
# ...
```

**Work in Progress.**
```
21 changes: 18 additions & 3 deletions examples/example.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include <iostream>
#include <vector>

#include "froaring.h"

using namespace std;

int main() {
froaring::FlexibleRoaringBitmap<> a;

a.set(1);
a.set(100);
a.set(101);
Expand All @@ -15,11 +17,24 @@ int main() {
assert(!a.test(99));
assert(!a.test(102));
assert(!a.test(102));

a.set(102);
assert(a.test(102));
// a.reset(102);
// assert(!a.test(102));
assert(a.cardinality() == 4);

a.set(114514);
assert(a.test(114514));
assert(!a.test(114513));
assert(!a.test(114515));

a.reset(114514);
assert(!a.test(114514));
assert(!a.test(114513));
assert(!a.test(114515));

cout << a.count() << endl;
assert(a.count() == 4);
cout << (a == a) << endl;
cout << sizeof(a) << endl;
cout << sizeof(std::vector<int>) << endl;
cout << sizeof(size_t) << endl;
}
86 changes: 35 additions & 51 deletions lib/array_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
// FIXME: check all the memmove-s!
namespace froaring {
template <typename WordType, size_t DataBits>
class ArrayContainer {
class ArrayContainer : public froaring_container_t {
public:
using IndexOrNumType = froaring::can_fit_t<DataBits>;
using SizeType = froaring::can_fit_t<DataBits + 1>;

Expand All @@ -21,94 +22,80 @@ class ArrayContainer {
}
std::cout << std::endl;
}
static ArrayContainer* create(
SizeType capacity = ARRAY_CONTAINER_INIT_SIZE) {
size_t totalSize =
sizeof(ArrayContainer) + capacity * sizeof(IndexOrNumType);
void* memory = operator new(totalSize);
ArrayContainer* container = new (memory) ArrayContainer();
return container;

ArrayContainer(SizeType capacity = ARRAY_CONTAINER_INIT_CAPACITY, SizeType size = 0)
: capacity(capacity),
size(size),
vals(static_cast<IndexOrNumType*>(malloc(capacity * sizeof(IndexOrNumType)))) {
assert(vals && "Failed to allocate memory for ArrayContainer");
}

~ArrayContainer() { free(vals); }

ArrayContainer(const ArrayContainer&) = delete;
ArrayContainer& operator=(const ArrayContainer&) = delete;

void clear() { size = 0; }

static void set(ArrayContainer*& c, IndexOrNumType num) {
auto pos = (c->size ? c->lower_bound(num) : 0);
if (pos < c->size && c->vals[pos] == num) return;
void set(IndexOrNumType num) {
auto pos = (size ? lower_bound(num) : 0);
if (pos < size && vals[pos] == num) return;

if (c->size == c->capacity) expand(c);
if (size == capacity) expand();

std::memmove(&c->vals[pos + 1], &c->vals[pos],
(c->size - pos) *
sizeof(IndexOrNumType)); // TODO: Boost by combining
// memmove with expand()
std::memmove(&vals[pos + 1], &vals[pos],
(size - pos) * sizeof(IndexOrNumType)); // TODO: Boost by combining
// memmove with expand()

c->vals[pos] = num;
++c->size;
vals[pos] = num;
++size;
}

void reset(IndexOrNumType num) {
if (!size) return;
auto pos = lower_bound(num);
if (pos == size || vals[pos] != num) return;

std::memmove(&vals[pos], &vals[pos + 1],
(size - pos - 1) * sizeof(IndexOrNumType));
std::memmove(&vals[pos], &vals[pos + 1], (size - pos - 1) * sizeof(IndexOrNumType));
--size;
}

bool test(IndexOrNumType num) const {
if (!size) return false;
auto pos = lower_bound(num);
std::cout << "pos=" << int(pos) << " v[p]=" << int(vals[pos])
<< std::endl;
return pos < size && vals[pos] == num;
}

static bool test_and_set(ArrayContainer*& c, IndexOrNumType num) {
bool test_and_set(IndexOrNumType num) {
bool was_set;
IndexOrNumType pos;
if (!c->size) {
if (!size) {
was_set = false;
} else {
pos = c->lower_bound(num);
was_set = (pos < c->size && c->vals[pos] == num);
pos = lower_bound(num);
was_set = (pos < size && vals[pos] == num);
}

if (was_set) return false;

if (c->size == c->capacity) expand(c);
if (size == capacity) expand();

std::memmove(&c->vals[pos + 1], &c->vals[pos],
(c->size - pos) * sizeof(IndexOrNumType));
std::memmove(&vals[pos + 1], &vals[pos], (size - pos) * sizeof(IndexOrNumType));

c->vals[pos] = num;
++c->size;
vals[pos] = num;
++size;

return true;
}

SizeType cardinality() const { return size; }

private:
static void expand(ArrayContainer*& c) {
auto new_cap = c->capacity * 2;

size_t totalSize =
sizeof(ArrayContainer) + new_cap * sizeof(IndexOrNumType);
void* new_memory = operator new(totalSize);
ArrayContainer* new_container =
new (new_memory) ArrayContainer(new_cap, c->size);

std::memmove(&new_container->vals, &c->vals,
c->size * sizeof(IndexOrNumType));
c->~ArrayContainer();
operator delete(c);

c = new_container;
void expand() {
capacity *= 2;
void* new_memory = realloc(vals, capacity * sizeof(IndexOrNumType));
assert(new_memory && "Failed to reallocate memory for ArrayContainer");
vals = static_cast<IndexOrNumType*>(new_memory);
}

IndexOrNumType lower_bound(IndexOrNumType num) const {
Expand All @@ -126,12 +113,9 @@ class ArrayContainer {
return left;
}

ArrayContainer(SizeType capacity = ARRAY_CONTAINER_INIT_SIZE,
SizeType size = 0)
: capacity(capacity), size(size) {}

public:
SizeType capacity;
SizeType size;
IndexOrNumType vals[];
IndexOrNumType* vals;
};
} // namespace froaring
Loading

0 comments on commit 478a965

Please sign in to comment.