-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathpacked_vector.hpp
118 lines (95 loc) · 3.1 KB
/
packed_vector.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#pragma once
#include "common.hpp"
namespace emphf {
template <typename MemoryModel>
class packed_vector {
template <typename T>
using vector = typename MemoryModel::template vector<T>;
public:
packed_vector()
: m_size(0)
, m_k(0)
, m_mask(~0ULL)
, m_bits()
{}
packed_vector(MemoryModel& mm, uint64_t k, uint64_t n = 0)
: m_size(0)
, m_k(k)
, m_mask(m_k == 64 ? ~0ULL : ~(~0ULL << m_k))
, m_bits(mm.make_vector(uninitialized_uint64()))
{
resize(n);
}
void resize(uint64_t n)
{
// can only grow, for now
assert(n >= size());
m_size = n;
m_bits.resize((m_size * m_k + 63) / 64);
}
size_t size() const
{
return m_size;
}
void set(uint64_t i, uint64_t val)
{
assert(i < size());
assert(m_k == 64 || (val >> m_k) == 0);
uint64_t pos = i * m_k;
uint64_t word_pos = pos / 64;
uint64_t offset_pos = pos % 64;
m_bits[word_pos] &= ~(m_mask << offset_pos);
m_bits[word_pos] |= val << offset_pos;
uint64_t stored = 64 - offset_pos;
if (stored < m_k) {
m_bits[word_pos + 1] &= ~(m_mask >> stored);
m_bits[word_pos + 1] |= val >> stored;
}
}
uint64_t operator[](uint64_t i) const
{
assert(i < size());
uint64_t pos = i * m_k;
uint64_t word_pos = pos / 64;
uint64_t offset_pos = pos % 64;
uint64_t val = m_bits[word_pos] >> offset_pos;
uint64_t read = 64 - offset_pos;
if (read < m_k) {
val |= m_bits[word_pos + 1] << read;
}
val &= m_mask;
return val;
}
void swap(packed_vector& other)
{
std::swap(m_size, other.m_size);
std::swap(m_k, other.m_k);
std::swap(m_mask, other.m_mask);
m_bits.swap(other.m_bits);
}
void save(std::ostream& os) const
{
os.write(reinterpret_cast<char const*>(&m_size), sizeof(m_size));
os.write(reinterpret_cast<char const*>(&m_k), sizeof(m_k));
os.write(reinterpret_cast<char const*>(m_bits.data()),
(std::streamsize)(sizeof(m_bits[0]) * m_bits.size()));
}
void load(std::istream& is)
{
is.read(reinterpret_cast<char*>(&m_size), sizeof(m_size));
is.read(reinterpret_cast<char*>(&m_k), sizeof(m_k));
m_bits.resize((m_size * m_k + 63) / 64);
is.read(reinterpret_cast<char*>(m_bits.data()),
(std::streamsize)(sizeof(m_bits[0]) * m_bits.size()));
}
vector<uint64_t> const& data() const
{
return m_bits;
}
protected:
uint64_t m_size;
uint64_t m_k;
uint64_t m_mask;
vector<uninitialized_uint64> m_bits;
};
}