-
Notifications
You must be signed in to change notification settings - Fork 284
Expand file tree
/
Copy pathtag_map.cpp
More file actions
173 lines (139 loc) · 4.34 KB
/
Copy pathtag_map.cpp
File metadata and controls
173 lines (139 loc) · 4.34 KB
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "tag_map.h"
#include <boost/functional/hash.hpp>
#include <iostream>
TagMap::TagMap() {
keys.resize(16);
key2value.resize(16);
values.resize(16);
}
void TagMap::reset() {
for (int i = 0; i < 16; i++) {
keys[i].clear();
key2value[i].clear();
values[i].clear();
}
}
bool TagMap::empty() const {
for (int i = 0; i < keys.size(); i++)
if (keys[i].size() > 0)
return false;
return true;
}
const std::size_t hashString(const std::string& str) {
// This is a pretty crappy hash function in terms of bit
// avalanching and distribution of output values.
//
// But it's very good in terms of speed, which turns out
// to be the important measure.
std::size_t hash = str.size();
if (hash >= 4)
hash ^= *(uint32_t*)str.data();
return hash;
}
const std::size_t hashString(const char* str, size_t size) {
// This is a pretty crappy hash function in terms of bit
// avalanching and distribution of output values.
//
// But it's very good in terms of speed, which turns out
// to be the important measure.
std::size_t hash = size;
if (hash >= 4)
hash ^= *(uint32_t*)str;
return hash;
}
uint32_t TagMap::ensureString(
std::vector<std::vector<const protozero::data_view*>>& vector,
const protozero::data_view& value
) {
std::size_t hash = hashString(value.data(), value.size());
const uint16_t shard = hash % vector.size();
for (int i = 0; i < vector[shard].size(); i++)
if (*(vector[shard][i]) == value)
return shard << 16 | i;
vector[shard].push_back(&value);
return shard << 16 | (vector[shard].size() - 1);
}
void TagMap::addTag(const protozero::data_view& key, const protozero::data_view& value) {
uint32_t valueLoc = ensureString(values, value);
uint32_t keyLoc = ensureString(keys, key);
const uint16_t shard = keyLoc >> 16;
const uint16_t pos = keyLoc;
if (key2value[shard].size() <= pos) {
key2value[shard].resize(pos + 1);
}
key2value[shard][pos] = valueLoc;
}
int64_t TagMap::getKey(const char* key, size_t size) const {
// Return -1 if key not found, else return its keyLoc.
std::size_t hash = hashString(key, size);
const uint16_t shard = hash % keys.size();
for (int i = 0; i < keys[shard].size(); i++) {
const protozero::data_view& candidate = *keys[shard][i];
if (candidate.size() != size)
continue;
if (memcmp(candidate.data(), key, size) == 0)
return shard << 16 | i;
}
return -1;
}
int64_t TagMap::getValue(const char* value, size_t size) const {
// Return -1 if value not found, else return its valueLoc.
std::size_t hash = hashString(value, size);
const uint16_t shard = hash % values.size();
for (int i = 0; i < values[shard].size(); i++) {
const protozero::data_view& candidate = *values[shard][i];
if (candidate.size() != size)
continue;
if (memcmp(candidate.data(), value, size) == 0)
return shard << 16 | i;
}
return -1;
}
const protozero::data_view* TagMap::getValueFromKey(uint32_t keyLoc) const {
const uint32_t valueLoc = key2value[keyLoc >> 16][keyLoc & 0xFFFF];
return values[valueLoc >> 16][valueLoc & 0xFFFF];
}
const protozero::data_view* TagMap::getValue(uint32_t valueLoc) const {
return values[valueLoc >> 16][valueLoc & 0xFFFF];
}
boost::container::flat_map<std::string, std::string> TagMap::exportToBoostMap() const {
boost::container::flat_map<std::string, std::string> rv;
for (int i = 0; i < keys.size(); i++) {
for (int j = 0; j < keys[i].size(); j++) {
uint32_t valueLoc = key2value[i][j];
auto key = *keys[i][j];
auto value = *values[valueLoc >> 16][valueLoc & 0xFFFF];
rv[std::string(key.data(), key.size())] = std::string(value.data(), value.size());
}
}
return rv;
}
TagMap::Iterator TagMap::begin() const {
size_t shard = 0;
while(keys.size() > shard && keys[shard].size() == 0)
shard++;
return Iterator{*this, shard, 0};
}
TagMap::Iterator TagMap::end() const {
return Iterator{*this, keys.size(), 0};
}
bool TagMap::Iterator::operator!=(const Iterator& other) const {
return other.shard != shard || other.offset != offset;
}
void TagMap::Iterator::operator++() {
++offset;
if (offset >= map.keys[shard].size()) {
offset = 0;
shard++;
// Advance to the next non-empty shard.
while(map.keys.size() > shard && map.keys[shard].size() == 0)
shard++;
}
}
Tag TagMap::Iterator::operator*() const {
const uint32_t valueLoc = map.key2value[shard][offset];
return Tag{
*map.keys[shard][offset],
*map.getValue(valueLoc)
};
}