Skip to content

Commit

Permalink
Contains and intersects
Browse files Browse the repository at this point in the history
And assignment operators
  • Loading branch information
cubicYYY committed Sep 29, 2024
1 parent 2d7f29f commit c3e7f23
Show file tree
Hide file tree
Showing 13 changed files with 916 additions and 18 deletions.
2 changes: 2 additions & 0 deletions include/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
#include "froaring_api/and_inplace.h"
#include "froaring_api/array_container.h"
#include "froaring_api/bitmap_container.h"
#include "froaring_api/contains.h"
#include "froaring_api/diff.h"
#include "froaring_api/diff_inplace.h"
#include "froaring_api/equal.h"
#include "froaring_api/intersects.h"
#include "froaring_api/mix_ops.h"
#include "froaring_api/or.h"
#include "froaring_api/or_inplace.h"
Expand Down
69 changes: 69 additions & 0 deletions include/binsearch_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <cstring>

#include "api.h"
#include "froaring_api/contains.h"

namespace froaring {

Expand Down Expand Up @@ -626,6 +627,74 @@ class BinsearchIndex : public froaring_container_t {
}
a->size = new_container_counts;
}

static bool intersects(const BinsearchIndex<WordType, IndexBits, DataBits>* a,
const BinsearchIndex<WordType, IndexBits, DataBits>* b) {
SizeType i = 0, j = 0;
while (true) {
while (a->containers[i].index < b->containers[j].index) {
SKIP_FIRST_COMPARE:
i++;
if (i == a->size) {
return false;
}
}
while (a->containers[i].index > b->containers[j].index) {
j++;
if (j == b->size) {
return false;
}
}
if (a->containers[i].index == b->containers[j].index) {
if (froaring_intersects<WordType, DataBits>(a->containers[i].ptr, b->containers[j].ptr,
a->containers[i].type, b->containers[j].type)) {
return true;
}
i++;
j++;
if (i == a->size || j == b->size) {
return false;
}
} else {
goto SKIP_FIRST_COMPARE;
}
}
FROARING_UNREACHABLE
}

static bool contains(const BinsearchIndex<WordType, IndexBits, DataBits>* a,
const BinsearchIndex<WordType, IndexBits, DataBits>* b) {
if (b->size == 0) {
return true;
}

if (a->size < b->size) {
return false;
}

size_t i = 0, j = 0;

while (i < a->size && j < b->size) {
if (a->containers[i].index == b->containers[j].index) {
if (!froaring_contains<WordType, DataBits>(a->containers[i].ptr, b->containers[j].ptr,
a->containers[i].type, b->containers[j].type)) {
return false;
}
i++;
j++;
} else if (b->containers[j].index > a->containers[i].index) {
i++;
} else {
return false;
}
}
if (j == b->size) {
return true;
} else {
return false;
}
}

SizeType advanceAndReleaseUntil(IndexType key, SizeType pos) {
while (pos < size && containers[pos].index < key) {
release_container<WordType, DataBits>(containers[pos].ptr, containers[pos].type);
Expand Down
138 changes: 136 additions & 2 deletions include/froaring.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "binsearch_index.h"
#include "froaring_api/array_container.h"
#include "froaring_api/bitmap_container.h"
#include "froaring_api/intersects.h"
#include "froaring_api/mix_ops.h"
#include "froaring_api/prelude.h"

namespace froaring {
Expand All @@ -37,8 +39,12 @@ class FlexibleRoaring {
using ArraySized = ArrayContainer<WordType, DataBits>;
using CTy = froaring::ContainerType; // handy local alias
using ContainerHandle = froaring::ContainerHandle<IndexType>;
using iterator = FlexibleRoaringIterator<WordType, IndexBits, DataBits>;
using const_iterator = const iterator;

static constexpr IndexType UNKNOWN_INDEX = 0;
static constexpr IndexType ANY_INDEX = 0;

friend FlexibleRoaringIterator<WordType, IndexBits, DataBits>;

public:
Expand Down Expand Up @@ -84,8 +90,8 @@ class FlexibleRoaring {
FROARING_UNREACHABLE
}
}
FlexibleRoaring(FlexibleRoaring&& other) = default;
FlexibleRoaring& operator=(FlexibleRoaring&& other) = default;

FlexibleRoaring(FlexibleRoaring&& other) { handle = other.handle; }

~FlexibleRoaring() {
if (!handle.ptr) {
Expand All @@ -98,6 +104,41 @@ class FlexibleRoaring {
}
}

FlexibleRoaring& operator=(FlexibleRoaring&& other) {
if (!handle.ptr) {
handle = std::move(other.handle);
other.handle.ptr = nullptr;
return *this;
}

if (handle.type == CTy::Containers) {
delete castToContainers(handle.ptr);
} else {
release_container<WordType, DataBits>(handle.ptr, handle.type);
}
handle = std::move(other.handle);
other.handle.ptr = nullptr;
return *this;
}

FlexibleRoaring& operator=(const FlexibleRoaring& other) {
if (!handle.ptr) {
if (handle.type == CTy::Containers) {
delete castToContainers(handle.ptr);
} else {
release_container<WordType, DataBits>(handle.ptr, handle.type);
}
}
handle.type = other.handle.type;
handle.index = other.handle.index;
if (other.handle.type == CTy::Containers) {
handle.ptr = new ContainersSized(*castToContainers(other.handle.ptr));
} else {
handle.ptr = duplicate_container<WordType, DataBits>(other.handle.ptr, other.handle.type);
}
return *this;
}

void debug_print() {
if (!is_inited()) {
std::cout << "NULL!" << std::endl;
Expand Down Expand Up @@ -129,6 +170,91 @@ class FlexibleRoaring {
}
}

const_iterator begin() const { return FlexibleRoaringIterator<WordType, IndexBits, DataBits>::begin(*this); }

const_iterator end() const { return FlexibleRoaringIterator<WordType, IndexBits, DataBits>::end(*this); }

bool contains(const FlexibleRoaring& other) const noexcept {
if (!other.is_inited()) {
return true;
}
if (!is_inited()) {
return false;
}
// Both containers
if (handle.type == CTy::Containers && other.handle.type == CTy::Containers) {
return ContainersSized::contains(castToContainers(handle.ptr), castToContainers(other.handle.ptr));
}

// One of them are containers:
if (handle.type == CTy::Containers) { // the other is a single container
// FIXME: We assume that no empty container in Containers. Is that true?
return false;
}
if (other.handle.type == CTy::Containers) { // this is a single container
const auto other_containers = castToContainers(other.handle.ptr);
const ContainerHandle& this_single = handle;
auto pos = other_containers->lower_bound(this_single.index);
if (pos == other_containers->size) {
return false;
}
if (other_containers->containers[pos].index != this_single.index) {
return false;
}
return froaring_contains<WordType, DataBits>(other_containers->containers[pos].ptr, this_single.ptr,
other_containers->containers[pos].type, this_single.type);
}

// Both are single container:
if (handle.index != other.handle.index) {
return false;
}
return froaring_contains<WordType, DataBits>(handle.ptr, other.handle.ptr, handle.type, other.handle.type);
}
bool intersects(const FlexibleRoaring& other) const noexcept {
if (!is_inited() || !other.is_inited()) {
return false;
}
// Both containers
if (handle.type == CTy::Containers && other.handle.type == CTy::Containers) {
return ContainersSized::intersects(castToContainers(handle.ptr), castToContainers(other.handle.ptr));
}

// One of them are containers:
if (handle.type == CTy::Containers) { // the other is a single container
const auto this_containers = castToContainers(handle.ptr);
const ContainerHandle& other_single = other.handle;
auto pos = this_containers->lower_bound(other_single.index);
if (pos == this_containers->size) {
return false;
}
const ContainerHandle& lhs = this_containers->containers[pos];
if (lhs.index != other_single.index) {
return false;
}
return froaring_intersects<WordType, DataBits>(lhs.ptr, other_single.ptr, lhs.type, other_single.type);
}
if (other.handle.type == CTy::Containers) { // this is a single container
const auto other_containers = castToContainers(other.handle.ptr);
const ContainerHandle& this_single = handle;
auto pos = other_containers->lower_bound(this_single.index);
if (pos == other_containers->size) {
return false;
}
if (other_containers->containers[pos].index != this_single.index) {
return false;
}
return froaring_intersects<WordType, DataBits>(other_containers->containers[pos].ptr, this_single.ptr,
other_containers->containers[pos].type, this_single.type);
}

// Both are single container:
if (handle.index != other.handle.index) {
return false;
}
return froaring_intersects<WordType, DataBits>(handle.ptr, other.handle.ptr, handle.type, other.handle.type);
}

void set(WordType num) {
can_fit_t<IndexBits> index;
can_fit_t<DataBits> data;
Expand Down Expand Up @@ -507,6 +633,14 @@ class FlexibleRoaring {
return *this;
}

void intersectWithComplement(const FlexibleRoaring& other) noexcept { *this -= other; }

/// @brief Overwrite current FlexibleRoaring with the result of lhs-rhs.
void intersectWithComplement(const FlexibleRoaring& lhs, const FlexibleRoaring& rhs) noexcept {
*this = lhs;
*this -= rhs;
}

FlexibleRoaring operator|(const FlexibleRoaring& other) const noexcept {
if (!is_inited()) {
return FlexibleRoaring<WordType, IndexBits, DataBits>(other);
Expand Down
9 changes: 8 additions & 1 deletion include/froaring_api/array_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ class ArrayContainer : public froaring_container_t {
this->capacity = new_cap;
}

private:
IndexOrNumType lower_bound(IndexOrNumType num) const {
if (size < UseLinearScanThreshold) {
for (SizeType i = 0; i < size; ++i) {
Expand All @@ -131,6 +130,14 @@ class ArrayContainer : public froaring_container_t {
return left;
}

SizeType advanceUntil(IndexOrNumType key, SizeType pos) const {
// TODO: use Gallop search
while (pos < size && vals[pos] < key) {
pos++;
}
return pos;
}

public:
SizeType capacity;
SizeType size;
Expand Down
36 changes: 35 additions & 1 deletion include/froaring_api/bitmap_container.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,40 @@ class BitmapContainer : public froaring_container_t {
std::memset(&words[start_word + 1], 0xFF, (end_word - start_word - 1) * sizeof(NumType));
}

bool any_range(NumType start, NumType end) const {
if (start >= end) {
return false;
}
const IndexType start_word = start / BitsPerWord;
const IndexType end_word = end / BitsPerWord;

if (start_word >= WordsCount) {
return false;
}
// All "1" from `start` to MSB
const WordType first_mask = ~((1ULL << (start & IndexInsideWordMask)) - 1);
// All "1" from LSB to `end`
const WordType last_mask =
((1ULL << ((end & IndexInsideWordMask))) - 1) ^ (1ULL << ((end & IndexInsideWordMask)));

if (start_word == end_word) {
if (words[start_word] & (first_mask & last_mask)) return true;
}

if (words[start_word] & first_mask) {
return true;
}
if (end_word < WordsCount && words[end_word] & last_mask) {
return true;
}
for (size_t i = start_word + 1; i < std::min((size_t)(end_word), WordsCount); ++i) {
if (words[i]) {
return true;
}
}
return false;
}

bool test(NumType index) const { return words[index / BitsPerWord] & ((WordType)1 << (index % BitsPerWord)); }

bool test_and_set(NumType index) {
Expand Down Expand Up @@ -117,7 +151,7 @@ class BitmapContainer : public froaring_container_t {
/// @param start inclusive.
/// @param end inclusive.
/// @return If [start, end] is fully contained in the container.
bool containesRange(NumType start, NumType end) const {
bool test_range(NumType start, NumType end) const {
if (start >= end) {
return true;
}
Expand Down
Loading

0 comments on commit c3e7f23

Please sign in to comment.