Skip to content

Commit

Permalink
Dynamic containers
Browse files Browse the repository at this point in the history
  • Loading branch information
cubicYYY committed Aug 29, 2024
1 parent e2949e5 commit 730d273
Show file tree
Hide file tree
Showing 9 changed files with 359 additions and 280 deletions.
3 changes: 1 addition & 2 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ BasedOnStyle: Google
IndentWidth: 4
TabWidth: 4
UseTab: Never
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Attach
ColumnLimit: 80
ContinuationIndentWidth: 4
IndentCaseLabels: true
AccessModifierOffset: -4
AllowShortIfStatementsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: Always
107 changes: 67 additions & 40 deletions lib/array_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,89 +11,112 @@
namespace froaring {
template <typename WordType, size_t DataBits>
class ArrayContainer {
using DataType = froaring::can_fit_t<DataBits>;
using IndexOrNumType = froaring::can_fit_t<DataBits>;
using SizeType = froaring::can_fit_t<DataBits + 1>;

public:
ArrayContainer() : capacity(ARRAY_CONTAINER_INIT_SIZE), size(0) {
vals = new DataType[capacity];
void debug_print() {
for (SizeType i = 0; i < size; ++i) {
std::cout << int(vals[i]) << " ";
}
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() { delete[] vals; }

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

void clear() { size = 0; }

void set(DataType num) {
auto pos = (size ? lower_bound(num) : 0);
if (pos < size && vals[pos] == num) return;
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;

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

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

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

void reset(DataType num) {
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(DataType));
(size - pos - 1) * sizeof(IndexOrNumType));
--size;
}

bool test(DataType num) const {
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;
}

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

if (was_set) return false;

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

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

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

return true;
}

DataType cardinality() const { return size; }
SizeType cardinality() const { return size; }

private:
void expand() {
capacity *= 2;
auto new_vals = new DataType[capacity];
std::memmove(new_vals, vals, size * sizeof(DataType));
delete[] vals;
vals = new_vals;
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;
}

DataType lower_bound(DataType num) const {
IndexOrNumType lower_bound(IndexOrNumType num) const {
assert(size && "Cannot find lower bound in an empty container");
DataType left = 0;
DataType right = size;
SizeType left = 0;
SizeType right = size;
while (left < right) {
DataType mid = left + (right - left) / 2;
SizeType mid = left + (right - left) / 2;
if (vals[mid] < num) {
left = mid + 1;
} else {
Expand All @@ -103,8 +126,12 @@ class ArrayContainer {
return left;
}

DataType* vals;
size_t capacity; // TODO: use less memory by using a smaller type
size_t size;
ArrayContainer(SizeType capacity = ARRAY_CONTAINER_INIT_SIZE,
SizeType size = 0)
: capacity(capacity), size(size) {}

SizeType capacity;
SizeType size;
IndexOrNumType vals[];
};
} // namespace froaring
27 changes: 17 additions & 10 deletions lib/bitmap_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,48 @@ class BitmapContainer {
static constexpr size_t TotalBits = (1 << DataBits);
static constexpr size_t WordCount =
(TotalBits + BitsPerWord - 1) / BitsPerWord; // ceiling
std::array<WordType, WordCount> bits;
using DataType = froaring::can_fit_t<DataBits>;

BitmapContainer() { bits.fill(0); }
using IndexOrNumType = froaring::can_fit_t<DataBits>;
using SizeType = froaring::can_fit_t<DataBits + 1>;

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

void clear() { std::memset(bits.data(), 0, WordCount * sizeof(WordType)); }

void set(DataType index) {
static BitmapContainer* create() {
BitmapContainer* container = new BitmapContainer();
return container;
}

void set(IndexOrNumType index) {
bits[index / BitsPerWord] |= (1 << (index % BitsPerWord));
}

bool test(DataType index) const {
bool test(IndexOrNumType index) const {
return bits[index / BitsPerWord] & (1 << (index % BitsPerWord));
}

bool test_and_set(DataType index) {
bool test_and_set(IndexOrNumType index) {
bool was_set = test(index);
if (was_set) return false;
set(index);
return true;
}

void reset(DataType index) {
void reset(IndexOrNumType index) {
bits[index / BitsPerWord] &= ~(1 << (index % BitsPerWord));
}

size_t cardinality() const {
size_t count = 0;
SizeType cardinality() const {
SizeType count = 0;
for (const auto& word : bits) {
count += __builtin_popcount(word);
}
return count;
}

private:
BitmapContainer() { memset(bits, 0, sizeof(bits)); }
WordType bits[WordCount];
};
} // namespace froaring
26 changes: 16 additions & 10 deletions lib/containers.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ class Containers {
ContainerEntry newEntry;
newEntry.containerIndex = index;
newEntry.containerType = CTy::Array;
newEntry.containerPtr = new ArrayContainer<WordType, DataBits>();
newEntry.containerPtr =
ArrayContainer<WordType, DataBits>::create();

containers.insert(it, newEntry);
it = getContainerPosByIndex(index);
Expand All @@ -145,21 +146,26 @@ class Containers {

// Now we found the corresponding container
switch (entry.containerType) {
case CTy::RLE:
static_cast<RLEContainer<WordType, DataBits>*>(
entry.containerPtr)
->set(data);
case CTy::RLE: {
auto rleptr = static_cast<RLEContainer<WordType, DataBits>*>(
entry.containerPtr);
RLEContainer<WordType, DataBits>::set(rleptr, data);
entry.containerPtr = (void*)rleptr;
break;
case CTy::Array:
static_cast<ArrayContainer<WordType, DataBits>*>(
entry.containerPtr)
->set(data);
}
case CTy::Array: {
auto aptr = static_cast<ArrayContainer<WordType, DataBits>*>(
entry.containerPtr);
ArrayContainer<WordType, DataBits>::set(aptr, data);
entry.containerPtr = (void*)aptr;
break;
case CTy::Bitmap:
}
case CTy::Bitmap: {
static_cast<BitmapContainer<WordType, DataBits>*>(
entry.containerPtr)
->set(data);
break;
}
default:
FROARING_UNREACHABLE
}
Expand Down
Loading

0 comments on commit 730d273

Please sign in to comment.