template<typename K, typename V, typename H = std::hash<K>, typename P = std::equal_to<K>> class hash_set {
struct item {
std::pair<const K, V> data;
std::size_t cached_hash;
};
std::list<item> data;
H hash;
P predicate;
static const auto items_per_bucket = 5; // Arbitrary- determine by profile if performance undesirable
public:
struct iterator {
typename std::list<item>::iterator it;
std::pair<const K, V>& operator*() { return it->data; }
std::pair<const K, V>* operator->() { return &it->data; }
iterator operator++(int) {
auto ret(*this);
++it;
return ret;
}
iterator& operator++() {
++it;
return *this;
}
iterator operator--(int) {
auto ret(*this);
--it;
return ret;
}
iterator& operator--() {
--it;
return *this;
}
};
iterator begin() { return iterator { data.begin() }; }
iterator end() { return iterator { data.end() }; }
std::size_t size() const { return data.size(); }
void clear() { data.clear(); buckets.clear(); }
private:
std::vector<std::vector<iterator>> buckets;
void insert_into_buckets(iterator it) {
if (buckets.size() == 0)
rehash(10); // Arbitrary- determine by profile if performance undesirable
auto&& bucket = buckets[it->cached_hash % buckets.size()];
if (bucket.size() >= items_per_bucket)
rehash(buckets.size() * 2);
buckets[it->cached_hash % buckets.size()].push_back(it);
}
public:
void rehash(std::size_t size) {
auto oldbuckets = std::move(buckets);
buckets.resize(size);
for(auto&& iterators : oldbuckets) {
for(auto&& i : iterators) {
insert_into_buckets(i);
}
}
}
std::pair<iterator, bool> insert(K k, V v) {
auto it = find(k);
if (it == end()) {
std::size_t val = hash(k);
data.push_back(item { { std::move(k), std::move(v) }, val });
try {
insert_into_buckets(--data.end());
} catch(...) {
data.pop_back();
throw;
}
return { --data.end(), true };
}
return { it, false };
}
template<typename AK> iterator find(AK&& k, H h = H(), P p = P()) {
return find(std::forward<AK>(k), h, p);
}
template<typename AK, typename AH> iterator find(AK&& k, AH&& h = AH(), P p = P()) {
return find(std::forward<AK>(k), std::forward<AH>(h), p);
}
template<typename AK, typename AH, typename AP> iterator find(AK&& k, AH&& h = AH(), AP&& p = AP()) {
auto&& bucket = buckets[h(k) % buckets.size()];
for(auto it : bucket) {
if (p(k, it->data.first))
return it;
}
return end();
}
template<typename AK> iterator erase(AK&& k, H h = H(), P p = P()) {
return erase(find(std::forward<AK>(k), h, p));
}
template<typename AK, typename AH> iterator erase(AK&& k, AH&& h = AH(), P p = P()) {
return erase(find(std::forward<AK>(k), std::forward<AH>(h), p));
}
template<typename AK, typename AH, typename AP> iterator erase(AK&& k, AH&& h = AH(), AP&& p = AP()) {
return erase(find(std::forward<AK>(k), std::forward<AH>(h), std:forward<AP>(p)));
}
iterator erase(iterator it) {
auto&& bucket = buckets[it->cached_hash % buckets.size()];
for(int i = 0; i < bucket.size(); i++) {
if (bucket[i] == it) {
bucket.erase(bucket.begin() + i);
return data.erase(it.it);
}
}
return end();
}
template<typename AK> V& operator[](AK&& ak) {
auto it = find(std::forward<AK>(ak));
if (it == end())
return insert(ak, V()).first->data.second;
return it->data.second;
}
};
dGVtcGxhdGU8dHlwZW5hbWUgSywgdHlwZW5hbWUgViwgdHlwZW5hbWUgSCA9IHN0ZDo6aGFzaDxLPiwgdHlwZW5hbWUgUCA9IHN0ZDo6ZXF1YWxfdG88Sz4+IGNsYXNzIGhhc2hfc2V0IHsKICAgIHN0cnVjdCBpdGVtIHsKICAgICAgICBzdGQ6OnBhaXI8Y29uc3QgSywgVj4gZGF0YTsKICAgICAgICBzdGQ6OnNpemVfdCBjYWNoZWRfaGFzaDsKICAgIH07CiAgICBzdGQ6Omxpc3Q8aXRlbT4gZGF0YTsKICAgIEggaGFzaDsKICAgIFAgcHJlZGljYXRlOwogICAgc3RhdGljIGNvbnN0IGF1dG8gaXRlbXNfcGVyX2J1Y2tldCA9IDU7IC8vIEFyYml0cmFyeS0gZGV0ZXJtaW5lIGJ5IHByb2ZpbGUgaWYgcGVyZm9ybWFuY2UgdW5kZXNpcmFibGUKcHVibGljOgoKICAgIHN0cnVjdCBpdGVyYXRvciB7CiAgICAgICAgdHlwZW5hbWUgc3RkOjpsaXN0PGl0ZW0+OjppdGVyYXRvciBpdDsKICAgICAgICBzdGQ6OnBhaXI8Y29uc3QgSywgVj4mIG9wZXJhdG9yKigpIHsgcmV0dXJuIGl0LT5kYXRhOyB9CiAgICAgICAgc3RkOjpwYWlyPGNvbnN0IEssIFY+KiBvcGVyYXRvci0+KCkgeyByZXR1cm4gJml0LT5kYXRhOyB9CgogICAgICAgIGl0ZXJhdG9yIG9wZXJhdG9yKysoaW50KSB7CiAgICAgICAgICAgIGF1dG8gcmV0KCp0aGlzKTsKICAgICAgICAgICAgKytpdDsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9CiAgICAgICAgaXRlcmF0b3ImIG9wZXJhdG9yKysoKSB7CiAgICAgICAgICAgICsraXQ7CiAgICAgICAgICAgIHJldHVybiAqdGhpczsKICAgICAgICB9CiAgICAgICAgaXRlcmF0b3Igb3BlcmF0b3ItLShpbnQpIHsKICAgICAgICAgICAgYXV0byByZXQoKnRoaXMpOwogICAgICAgICAgICAtLWl0OwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0KICAgICAgICBpdGVyYXRvciYgb3BlcmF0b3ItLSgpIHsKICAgICAgICAgICAgLS1pdDsKICAgICAgICAgICAgcmV0dXJuICp0aGlzOwogICAgICAgIH0KCiAgICB9OwoKICAgIGl0ZXJhdG9yIGJlZ2luKCkgeyByZXR1cm4gaXRlcmF0b3IgeyBkYXRhLmJlZ2luKCkgfTsgfQogICAgaXRlcmF0b3IgZW5kKCkgeyByZXR1cm4gaXRlcmF0b3IgeyBkYXRhLmVuZCgpIH07IH0KICAgIHN0ZDo6c2l6ZV90IHNpemUoKSBjb25zdCB7IHJldHVybiBkYXRhLnNpemUoKTsgfQogICAgdm9pZCBjbGVhcigpIHsgZGF0YS5jbGVhcigpOyBidWNrZXRzLmNsZWFyKCk7IH0KCnByaXZhdGU6CiAgICBzdGQ6OnZlY3RvcjxzdGQ6OnZlY3RvcjxpdGVyYXRvcj4+IGJ1Y2tldHM7CgogICAgdm9pZCBpbnNlcnRfaW50b19idWNrZXRzKGl0ZXJhdG9yIGl0KSB7CiAgICAgICAgaWYgKGJ1Y2tldHMuc2l6ZSgpID09IDApCiAgICAgICAgICAgIHJlaGFzaCgxMCk7IC8vIEFyYml0cmFyeS0gZGV0ZXJtaW5lIGJ5IHByb2ZpbGUgaWYgcGVyZm9ybWFuY2UgdW5kZXNpcmFibGUKICAgICAgICBhdXRvJiYgYnVja2V0ID0gYnVja2V0c1tpdC0+Y2FjaGVkX2hhc2ggJSBidWNrZXRzLnNpemUoKV07CiAgICAgICAgaWYgKGJ1Y2tldC5zaXplKCkgPj0gaXRlbXNfcGVyX2J1Y2tldCkKICAgICAgICAgICAgcmVoYXNoKGJ1Y2tldHMuc2l6ZSgpICogMik7CiAgICAgICAgYnVja2V0c1tpdC0+Y2FjaGVkX2hhc2ggJSBidWNrZXRzLnNpemUoKV0ucHVzaF9iYWNrKGl0KTsKICAgIH0KcHVibGljOgogICAgdm9pZCByZWhhc2goc3RkOjpzaXplX3Qgc2l6ZSkgewogICAgICAgIGF1dG8gb2xkYnVja2V0cyA9IHN0ZDo6bW92ZShidWNrZXRzKTsKICAgICAgICBidWNrZXRzLnJlc2l6ZShzaXplKTsKICAgICAgICBmb3IoYXV0byYmIGl0ZXJhdG9ycyA6IG9sZGJ1Y2tldHMpIHsKICAgICAgICAgICAgZm9yKGF1dG8mJiBpIDogaXRlcmF0b3JzKSB7CiAgICAgICAgICAgICAgICBpbnNlcnRfaW50b19idWNrZXRzKGkpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIHN0ZDo6cGFpcjxpdGVyYXRvciwgYm9vbD4gaW5zZXJ0KEsgaywgViB2KSB7CiAgICAgICAgYXV0byBpdCA9IGZpbmQoayk7CiAgICAgICAgaWYgKGl0ID09IGVuZCgpKSB7CiAgICAgICAgICAgIHN0ZDo6c2l6ZV90IHZhbCA9IGhhc2goayk7CiAgICAgICAgICAgIGRhdGEucHVzaF9iYWNrKGl0ZW0geyB7IHN0ZDo6bW92ZShrKSwgc3RkOjptb3ZlKHYpIH0sIHZhbCB9KTsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIGluc2VydF9pbnRvX2J1Y2tldHMoLS1kYXRhLmVuZCgpKTsKICAgICAgICAgICAgfSBjYXRjaCguLi4pIHsKICAgICAgICAgICAgICAgIGRhdGEucG9wX2JhY2soKTsKICAgICAgICAgICAgICAgIHRocm93OwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB7IC0tZGF0YS5lbmQoKSwgdHJ1ZSB9OwogICAgICAgIH0KICAgICAgICByZXR1cm4geyBpdCwgZmFsc2UgfTsKICAgIH0KICAgIAogICAgdGVtcGxhdGU8dHlwZW5hbWUgQUs+IGl0ZXJhdG9yIGZpbmQoQUsmJiBrLCBIIGggPSBIKCksIFAgcCA9IFAoKSkgewogICAgICAgIHJldHVybiBmaW5kKHN0ZDo6Zm9yd2FyZDxBSz4oayksIGgsIHApOwogICAgfQogICAgdGVtcGxhdGU8dHlwZW5hbWUgQUssIHR5cGVuYW1lIEFIPiBpdGVyYXRvciBmaW5kKEFLJiYgaywgQUgmJiBoID0gQUgoKSwgUCBwID0gUCgpKSB7CiAgICAgICAgcmV0dXJuIGZpbmQoc3RkOjpmb3J3YXJkPEFLPihrKSwgc3RkOjpmb3J3YXJkPEFIPihoKSwgcCk7CiAgICB9CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBBSywgdHlwZW5hbWUgQUgsIHR5cGVuYW1lIEFQPiBpdGVyYXRvciBmaW5kKEFLJiYgaywgQUgmJiBoID0gQUgoKSwgQVAmJiBwID0gQVAoKSkgewogICAgICAgIGF1dG8mJiBidWNrZXQgPSBidWNrZXRzW2goaykgJSBidWNrZXRzLnNpemUoKV07CiAgICAgICAgZm9yKGF1dG8gaXQgOiBidWNrZXQpIHsKICAgICAgICAgICAgaWYgKHAoaywgaXQtPmRhdGEuZmlyc3QpKQogICAgICAgICAgICAgICAgcmV0dXJuIGl0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gZW5kKCk7CiAgICB9CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBBSz4gaXRlcmF0b3IgZXJhc2UoQUsmJiBrLCBIIGggPSBIKCksIFAgcCA9IFAoKSkgewogICAgICAgIHJldHVybiBlcmFzZShmaW5kKHN0ZDo6Zm9yd2FyZDxBSz4oayksIGgsIHApKTsKICAgIH0KICAgIHRlbXBsYXRlPHR5cGVuYW1lIEFLLCB0eXBlbmFtZSBBSD4gaXRlcmF0b3IgZXJhc2UoQUsmJiBrLCBBSCYmIGggPSBBSCgpLCBQIHAgPSBQKCkpIHsKICAgICAgICByZXR1cm4gZXJhc2UoZmluZChzdGQ6OmZvcndhcmQ8QUs+KGspLCBzdGQ6OmZvcndhcmQ8QUg+KGgpLCBwKSk7CiAgICB9CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBBSywgdHlwZW5hbWUgQUgsIHR5cGVuYW1lIEFQPiBpdGVyYXRvciBlcmFzZShBSyYmIGssIEFIJiYgaCA9IEFIKCksIEFQJiYgcCA9IEFQKCkpIHsKICAgICAgICByZXR1cm4gZXJhc2UoZmluZChzdGQ6OmZvcndhcmQ8QUs+KGspLCBzdGQ6OmZvcndhcmQ8QUg+KGgpLCBzdGQ6Zm9yd2FyZDxBUD4ocCkpKTsKICAgIH0KICAgIGl0ZXJhdG9yIGVyYXNlKGl0ZXJhdG9yIGl0KSB7CiAgICAgICAgYXV0byYmIGJ1Y2tldCA9IGJ1Y2tldHNbaXQtPmNhY2hlZF9oYXNoICUgYnVja2V0cy5zaXplKCldOwogICAgICAgIGZvcihpbnQgaSA9IDA7IGkgPCBidWNrZXQuc2l6ZSgpOyBpKyspIHsKICAgICAgICAgICAgaWYgKGJ1Y2tldFtpXSA9PSBpdCkgewogICAgICAgICAgICAgICAgYnVja2V0LmVyYXNlKGJ1Y2tldC5iZWdpbigpICsgaSk7CiAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5lcmFzZShpdC5pdCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIGVuZCgpOwogICAgfQogICAgdGVtcGxhdGU8dHlwZW5hbWUgQUs+IFYmIG9wZXJhdG9yW10oQUsmJiBhaykgewogICAgICAgIGF1dG8gaXQgPSBmaW5kKHN0ZDo6Zm9yd2FyZDxBSz4oYWspKTsKICAgICAgICBpZiAoaXQgPT0gZW5kKCkpCiAgICAgICAgICAgIHJldHVybiBpbnNlcnQoYWssIFYoKSkuZmlyc3QtPmRhdGEuc2Vjb25kOwogICAgICAgIHJldHVybiBpdC0+ZGF0YS5zZWNvbmQ7CiAgICB9Cn07