Static bitset with tests created.
Summary: After manual merge of dev. Merge branch 'dev' into separate_bitset Include bitset in template. Merge branch 'dev' into separate_bitset Reviewers: florijan, buda Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D97
This commit is contained in:
parent
971e006d13
commit
97aa4b92e1
99
src/data_structures/bitset/static_bitset.hpp
Normal file
99
src/data_structures/bitset/static_bitset.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "utils/assert.hpp"
|
||||
|
||||
/**
|
||||
* Bitset data structure with a number of bits provided in constructor.
|
||||
* @tparam TStore type of underlying bit storage: int32, int64, char, etc.
|
||||
*/
|
||||
template <typename TStore>
|
||||
class Bitset {
|
||||
public:
|
||||
/**
|
||||
* Create bitset.
|
||||
* @param sz size of bitset
|
||||
*/
|
||||
Bitset(size_t sz) : block_size_(8 * sizeof(TStore)) {
|
||||
if (sz % block_size_ != 0) sz += block_size_;
|
||||
blocks_.resize(sz / block_size_);
|
||||
}
|
||||
/**
|
||||
* Set bit to one.
|
||||
* @param idx position of bit.
|
||||
*/
|
||||
void Set(int idx) {
|
||||
debug_assert(idx >= 0, "Invalid bit location.");
|
||||
debug_assert(idx < static_cast<int64_t>(blocks_.size()) * block_size_,
|
||||
"Invalid bit location.");
|
||||
int bucket = idx / block_size_;
|
||||
blocks_[bucket] |= TStore(1) << idx % block_size_;
|
||||
}
|
||||
/**
|
||||
* Return bit at position.
|
||||
* @param idx position of bit.
|
||||
* @return 1/0.
|
||||
*/
|
||||
bool At(int idx) const {
|
||||
debug_assert(idx >= 0, "Invalid bit location.");
|
||||
debug_assert(idx < static_cast<int64_t>(blocks_.size()) * block_size_,
|
||||
"Invalid bit location.");
|
||||
int bucket = idx / block_size_;
|
||||
return (blocks_[bucket] >> (idx % block_size_)) & 1;
|
||||
}
|
||||
/**
|
||||
* Intersect two bitsets
|
||||
* @param other bitset.
|
||||
* @return intersection.
|
||||
*/
|
||||
Bitset<TStore> Intersect(const Bitset<TStore> &other) const {
|
||||
debug_assert(this->blocks_.size() == other.blocks_.size(),
|
||||
"Bitsets are not of equal size.");
|
||||
Bitset<TStore> ret(this->blocks_.size() * this->block_size_);
|
||||
for (int i = 0; i < (int)this->blocks_.size(); ++i) {
|
||||
ret.blocks_[i] = this->blocks_[i] & other.blocks_[i];
|
||||
continue;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Positions of bits set to 1.
|
||||
* @return positions of bits set to 1.
|
||||
*/
|
||||
std::vector<int> Ones() const {
|
||||
std::vector<int> ret;
|
||||
int ret_idx = 0;
|
||||
for (auto x : blocks_) {
|
||||
while (x) {
|
||||
auto pos = CountTrailingZeroes(x & -x);
|
||||
x -= x & -x;
|
||||
ret.push_back(ret_idx + pos);
|
||||
}
|
||||
ret_idx += block_size_;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Calculate number of trailing zeroes in a binary number, usually a power
|
||||
* of two.
|
||||
* @return number of trailing zeroes.
|
||||
*/
|
||||
size_t CountTrailingZeroes(TStore v) const {
|
||||
size_t ret = 0;
|
||||
while (v >> 32) ret += 32, v >>= 32;
|
||||
if (v >> 16) ret += 16, v >>= 16;
|
||||
if (v >> 8) ret += 8, v >>= 8;
|
||||
if (v >> 4) ret += 4, v >>= 4;
|
||||
if (v >> 2) ret += 2, v >>= 2;
|
||||
if (v >> 1) ret += 1, v >>= 1;
|
||||
return ret;
|
||||
}
|
||||
std::vector<TStore> blocks_;
|
||||
const size_t block_size_;
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "data_structures/bitset/static_bitset.hpp"
|
||||
#include "communication/bolt/v1/serialization/record_stream.hpp"
|
||||
#include "io/network/socket.hpp"
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "data_structures/bitset/static_bitset.hpp"
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "storage/edge_accessor.hpp"
|
||||
@ -25,95 +26,6 @@ using std::endl;
|
||||
// s1.score+s2.score+s3.score+s4.score ORDER BY
|
||||
// s1.score+s2.score+s3.score+s4.score DESC LIMIT 10
|
||||
|
||||
template <typename TStore>
|
||||
/**
|
||||
* Bitset data structure with a number of bits provided in constructor.
|
||||
* @tparam type of underlying bit storage: int32, int64, char, etc.
|
||||
*/
|
||||
class Bitset {
|
||||
public:
|
||||
/**
|
||||
* Create bitset.
|
||||
* @param sz size of bitset
|
||||
*/
|
||||
Bitset(size_t sz) : block_size_(8 * sizeof(TStore)) {
|
||||
if (sz % block_size_ != 0) sz += block_size_;
|
||||
blocks_.resize(sz / block_size_);
|
||||
}
|
||||
/**
|
||||
* Set bit to one.
|
||||
* @param idx position of bit.
|
||||
*/
|
||||
void Set(int idx) {
|
||||
debug_assert(idx < static_cast<int64_t>(blocks_.size()) * block_size_,
|
||||
"Invalid bit location.");
|
||||
int bucket = idx / block_size_;
|
||||
blocks_[bucket] |= TStore(1) << idx % block_size_;
|
||||
}
|
||||
/**
|
||||
* Return bit at position.
|
||||
* @param idx position of bit.
|
||||
* @return 1/0.
|
||||
*/
|
||||
bool At(int idx) const {
|
||||
debug_assert(idx < static_cast<int64_t>(blocks_.size()) * block_size_,
|
||||
"Invalid bit location.");
|
||||
int bucket = idx / block_size_;
|
||||
return (blocks_[bucket] >> (idx % block_size_)) & 1;
|
||||
}
|
||||
/**
|
||||
* Intersect two bitsets
|
||||
* @param other bitset.
|
||||
* @return intersection.
|
||||
*/
|
||||
Bitset<TStore> Intersect(const Bitset<TStore> &other) {
|
||||
debug_assert(this->blocks_.size() == other.blocks_.size(),
|
||||
"Bitsets are not of equal size.");
|
||||
Bitset<TStore> ret(this->blocks_.size() * this->block_size_);
|
||||
for (int i = 0; i < (int)this->blocks_.size(); ++i) {
|
||||
ret.blocks_[i] = this->blocks_[i] & other.blocks_[i];
|
||||
continue;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Positions of bits set to 1.
|
||||
* @return positions of bits set to 1.
|
||||
*/
|
||||
std::vector<int> Ones() const {
|
||||
std::vector<int> ret;
|
||||
int ret_idx = 0;
|
||||
for (auto x : blocks_) {
|
||||
while (x) {
|
||||
auto pos = CountTrailingZeroes(x & -x);
|
||||
x -= x & -x;
|
||||
ret.push_back(ret_idx + pos);
|
||||
}
|
||||
ret_idx += block_size_;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Calculate number of trailing zeroes in a binary number, usually a power
|
||||
* of two.
|
||||
* @return number of trailing zeroes.
|
||||
*/
|
||||
size_t CountTrailingZeroes(TStore v) const {
|
||||
size_t ret = 0;
|
||||
while (v >> 32) ret += 32, v >>= 32;
|
||||
if (v >> 16) ret += 16, v >>= 16;
|
||||
if (v >> 8) ret += 8, v >>= 8;
|
||||
if (v >> 4) ret += 4, v >>= 4;
|
||||
if (v >> 2) ret += 2, v >>= 2;
|
||||
if (v >> 1) ret += 1, v >>= 1;
|
||||
return ret;
|
||||
}
|
||||
std::vector<TStore> blocks_;
|
||||
const size_t block_size_;
|
||||
};
|
||||
|
||||
enum CliqueQuery { SCORE_AND_LIMIT, FIND_ALL };
|
||||
|
||||
bool run_general_query(GraphDbAccessor &db_accessor,
|
||||
|
@ -10,3 +10,4 @@ using Stream = bolt::RecordStream<io::network::Socket>;
|
||||
#include "../stream/print_record_stream.hpp"
|
||||
using Stream = PrintRecordStream;
|
||||
#endif
|
||||
#include "data_structures/bitset/static_bitset.hpp"
|
||||
|
80
tests/unit/static_bitset.cpp
Normal file
80
tests/unit/static_bitset.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include "data_structures/bitset/static_bitset.hpp"
|
||||
#include <gmock/gmock.h>
|
||||
#include <vector>
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using testing::UnorderedElementsAreArray;
|
||||
|
||||
TEST(StaticBitset, Intersection) {
|
||||
const int n = 50;
|
||||
Bitset<int64_t> bitset(n);
|
||||
Bitset<int64_t> bitset2(n);
|
||||
std::vector<int> V;
|
||||
std::vector<int> V2;
|
||||
for (int i = 0; i < n / 2; ++i) {
|
||||
const int pos = rand() % n;
|
||||
bitset.Set(pos);
|
||||
V.push_back(pos);
|
||||
}
|
||||
for (int i = 0; i < n / 2; ++i) {
|
||||
const int pos = rand() % n;
|
||||
bitset2.Set(pos);
|
||||
V2.push_back(pos);
|
||||
}
|
||||
Bitset<int64_t> intersected = bitset.Intersect(bitset);
|
||||
sort(V.begin(), V.end());
|
||||
V.resize(unique(V.begin(), V.end()) - V.begin());
|
||||
EXPECT_THAT(V, UnorderedElementsAreArray(intersected.Ones()));
|
||||
|
||||
sort(V2.begin(), V2.end());
|
||||
V2.resize(unique(V2.begin(), V2.end()) - V2.begin());
|
||||
|
||||
std::vector<int> V3;
|
||||
set_intersection(V.begin(), V.end(), V2.begin(), V2.end(), back_inserter(V3));
|
||||
Bitset<int64_t> intersected_two = bitset.Intersect(bitset2);
|
||||
EXPECT_THAT(V3, UnorderedElementsAreArray(intersected_two.Ones()));
|
||||
}
|
||||
|
||||
TEST(StaticBitset, BasicFunctionality) {
|
||||
const int n = 50;
|
||||
Bitset<int64_t> bitset(n);
|
||||
std::vector<int> V;
|
||||
for (int i = 0; i < n / 2; ++i) {
|
||||
const int pos = rand() % n;
|
||||
bitset.Set(pos);
|
||||
V.push_back(pos);
|
||||
}
|
||||
sort(V.begin(), V.end());
|
||||
V.resize(unique(V.begin(), V.end()) - V.begin());
|
||||
EXPECT_THAT(V, UnorderedElementsAreArray(bitset.Ones()));
|
||||
}
|
||||
|
||||
TEST(StaticBitset, SetAndReadBit) {
|
||||
const int n = 50;
|
||||
Bitset<char> bitset(n);
|
||||
bitset.Set(4);
|
||||
EXPECT_EQ(bitset.At(4), true);
|
||||
EXPECT_EQ(bitset.At(3), false);
|
||||
}
|
||||
|
||||
TEST(StaticBitset, SetOutOfRange) {
|
||||
const int n = 50;
|
||||
Bitset<char> bitset(n);
|
||||
EXPECT_DEATH(bitset.Set(-1), "Invalid bit location.");
|
||||
EXPECT_DEATH(bitset.Set(150), "Invalid bit location.");
|
||||
bitset.Set(49);
|
||||
}
|
||||
|
||||
TEST(StaticBitset, AtOutOfRange) {
|
||||
const int n = 50;
|
||||
Bitset<char> bitset(n);
|
||||
bitset.Set(33);
|
||||
EXPECT_DEATH(bitset.At(150), "Invalid bit location.");
|
||||
EXPECT_DEATH(bitset.At(-1), "Invalid bit location.");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in New Issue
Block a user