add octa::Multimap and octa::Multiset
parent
bbb5fbf224
commit
ea70d2e467
|
@ -313,25 +313,40 @@ namespace detail {
|
|||
return B::get_data(c->value);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
bool remove(const U &key) {
|
||||
template<bool multi, typename U>
|
||||
octa::Size remove(const U &key) {
|
||||
if (!p_len) return 0;
|
||||
octa::Size olen = p_len;
|
||||
octa::Size h = get_hash()(key) & (p_size - 1);
|
||||
Chain *c = p_data.first()[h];
|
||||
Chain **p = &c;
|
||||
Chain **p = &p_data.first()[h], *c = *p;
|
||||
while (c) {
|
||||
if (get_eq()(key, B::get_key(c->value))) {
|
||||
--p_len;
|
||||
*p = c->next;
|
||||
octa::allocator_destroy(get_alloc(), &c->value);
|
||||
octa::allocator_construct(get_alloc(), &c->value);
|
||||
c->next = p_unused;
|
||||
p_unused = c;
|
||||
--p_len;
|
||||
return true;
|
||||
octa::allocator_destroy(get_alloc(), &c->value);
|
||||
octa::allocator_construct(get_alloc(), &c->value);
|
||||
if (!multi) return 1;
|
||||
} else {
|
||||
p = &c->next;
|
||||
}
|
||||
c = c->next;
|
||||
p = &c;
|
||||
c = *p;
|
||||
}
|
||||
return false;
|
||||
return olen - p_len;
|
||||
}
|
||||
|
||||
template<bool multi, typename U>
|
||||
octa::Size count(const U &key) {
|
||||
if (!p_len) return 0;
|
||||
octa::Size h = get_hash()(key) & (p_size - 1);
|
||||
octa::Size ret = 0;
|
||||
for (Chain *c = p_data.first()[h]; c; c = c->next)
|
||||
if (get_eq()(key, B::get_key(c->value))) {
|
||||
++ret;
|
||||
if (!multi) break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void delete_chunks(Chunk *chunks) {
|
||||
|
@ -394,10 +409,20 @@ namespace detail {
|
|||
B::swap_elem(found->value, elem);
|
||||
}
|
||||
Chain **hch = p_data.first();
|
||||
auto ret = octa::make_pair(Range(hch + h + 1, hch + bucket_count(),
|
||||
return octa::make_pair(Range(hch + h + 1, hch + bucket_count(),
|
||||
found), ins);
|
||||
rehash_up();
|
||||
return octa::move(ret);
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
octa::Pair<Range, bool> emplace_multi(Args &&...args) {
|
||||
rehash_ahead(1);
|
||||
E elem(octa::forward<Args>(args)...);
|
||||
octa::Size h = get_hash()(B::get_key(elem)) & (p_size - 1);
|
||||
Chain *ch = insert(h);
|
||||
B::swap_elem(ch->value, elem);
|
||||
Chain **hch = p_data.first();
|
||||
return octa::make_pair(Range(hch + h + 1, hch + bucket_count(),
|
||||
ch), true);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
|
|
198
octa/map.h
198
octa/map.h
|
@ -212,15 +212,11 @@ public:
|
|||
}
|
||||
|
||||
octa::Size erase(const K &key) {
|
||||
if (p_table.remove(key)) return 1;
|
||||
return 0;
|
||||
return p_table.remove<false>(key);
|
||||
}
|
||||
|
||||
octa::Size count(const K &key) {
|
||||
octa::Size h;
|
||||
T *v = p_table.access_base(key, h);
|
||||
if (v) return 1;
|
||||
return 0;
|
||||
return p_table.count<false>(key);
|
||||
}
|
||||
|
||||
Range find(const K &key) { return p_table.find(key); }
|
||||
|
@ -251,6 +247,196 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename K, typename T,
|
||||
typename H = octa::ToHash<K>,
|
||||
typename C = octa::Equal<K>,
|
||||
typename A = octa::Allocator<octa::Pair<const K, T>>
|
||||
> struct Multimap {
|
||||
private:
|
||||
using Base = octa::detail::Hashtable<
|
||||
octa::detail::MapBase<K, T, A>, octa::Pair<const K, T>,
|
||||
K, T, H, C, A
|
||||
>;
|
||||
Base p_table;
|
||||
|
||||
template<typename R>
|
||||
octa::Size estimate_rsize(const R &range,
|
||||
octa::EnableIf<octa::IsFiniteRandomAccessRange<R>::value, bool> = true
|
||||
) {
|
||||
return range.size();
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
octa::Size estimate_rsize(const R &,
|
||||
octa::EnableIf<!octa::IsFiniteRandomAccessRange<R>::value, bool> = true
|
||||
) {
|
||||
/* we have no idea how big the range actually is */
|
||||
return 16;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
using Key = K;
|
||||
using Mapped = T;
|
||||
using Size = octa::Size;
|
||||
using Difference = octa::Ptrdiff;
|
||||
using Hasher = H;
|
||||
using KeyEqual = C;
|
||||
using Value = octa::Pair<const K, T>;
|
||||
using Reference = Value &;
|
||||
using Pointer = octa::AllocatorPointer<A>;
|
||||
using ConstPointer = octa::AllocatorConstPointer<A>;
|
||||
using Range = octa::HashRange<octa::Pair<const K, T>>;
|
||||
using ConstRange = octa::HashRange<const octa::Pair<const K, T>>;
|
||||
using LocalRange = octa::BucketRange<octa::Pair<const K, T>>;
|
||||
using ConstLocalRange = octa::BucketRange<const octa::Pair<const K, T>>;
|
||||
using Allocator = A;
|
||||
|
||||
explicit Multimap(octa::Size size, const H &hf = H(),
|
||||
const C &eqf = C(), const A &alloc = A()
|
||||
): p_table(size, hf, eqf, alloc) {}
|
||||
|
||||
Multimap(): Multimap(0) {}
|
||||
explicit Multimap(const A &alloc): Multimap(0, H(), C(), alloc) {}
|
||||
|
||||
Multimap(octa::Size size, const A &alloc):
|
||||
Multimap(size, H(), C(), alloc) {}
|
||||
Multimap(octa::Size size, const H &hf, const A &alloc):
|
||||
Multimap(size, hf, C(), alloc) {}
|
||||
|
||||
Multimap(const Multimap &m): p_table(m.p_table,
|
||||
octa::allocator_container_copy(m.p_table.get_alloc())) {}
|
||||
|
||||
Multimap(const Multimap &m, const A &alloc): p_table(m.p_table, alloc) {}
|
||||
|
||||
Multimap(Multimap &&m): p_table(octa::move(m.p_table)) {}
|
||||
Multimap(Multimap &&m, const A &alloc):
|
||||
p_table(octa::move(m.p_table), alloc) {}
|
||||
|
||||
template<typename R>
|
||||
Multimap(R range, octa::Size size = 0, const H &hf = H(),
|
||||
const C &eqf = C(), const A &alloc = A(),
|
||||
octa::EnableIf<
|
||||
octa::IsInputRange<R>::value &&
|
||||
octa::IsConvertible<RangeReference<R>, Value>::value,
|
||||
bool
|
||||
> = true
|
||||
): p_table(size ? size : estimate_rsize(range), hf, eqf, alloc) {
|
||||
for (; !range.empty(); range.pop_front())
|
||||
emplace(range.front());
|
||||
p_table.rehash_up();
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
Multimap(R range, octa::Size size, const A &alloc)
|
||||
: Multimap(range, size, H(), C(), alloc) {}
|
||||
|
||||
template<typename R>
|
||||
Multimap(R range, octa::Size size, const H &hf, const A &alloc)
|
||||
: Multimap(range, size, hf, C(), alloc) {}
|
||||
|
||||
Multimap(octa::InitializerList<Value> init, octa::Size size = 0,
|
||||
const H &hf = H(), const C &eqf = C(), const A &alloc = A()
|
||||
): Multimap(octa::each(init), size, hf, eqf, alloc) {}
|
||||
|
||||
Multimap(octa::InitializerList<Value> init, octa::Size size, const A &alloc)
|
||||
: Multimap(octa::each(init), size, H(), C(), alloc) {}
|
||||
|
||||
Multimap(octa::InitializerList<Value> init, octa::Size size, const H &hf,
|
||||
const A &alloc
|
||||
): Multimap(octa::each(init), size, hf, C(), alloc) {}
|
||||
|
||||
Multimap &operator=(const Multimap &m) {
|
||||
p_table = m.p_table;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Multimap &operator=(Multimap &&m) {
|
||||
p_table = octa::move(m.p_table);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
octa::EnableIf<
|
||||
octa::IsInputRange<R>::value &&
|
||||
octa::IsConvertible<RangeReference<R>, Value>::value,
|
||||
Multimap &
|
||||
> operator=(R range) {
|
||||
clear();
|
||||
p_table.reserve_at_least(estimate_rsize(range));
|
||||
for (; !range.empty(); range.pop_front())
|
||||
emplace(range.front());
|
||||
p_table.rehash_up();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Multimap &operator=(InitializerList<Value> il) {
|
||||
const Value *beg = il.begin(), *end = il.end();
|
||||
clear();
|
||||
p_table.reserve_at_least(end - beg);
|
||||
while (beg != end)
|
||||
emplace(*beg++);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const { return p_table.empty(); }
|
||||
octa::Size size() const { return p_table.size(); }
|
||||
octa::Size max_size() const { return p_table.max_size(); }
|
||||
|
||||
octa::Size bucket_count() const { return p_table.bucket_count(); }
|
||||
octa::Size max_bucket_count() const { return p_table.max_bucket_count(); }
|
||||
|
||||
octa::Size bucket(const K &key) const { return p_table.bucket(key); }
|
||||
octa::Size bucket_size(octa::Size n) const { return p_table.bucket_size(n); }
|
||||
|
||||
void clear() { p_table.clear(); }
|
||||
|
||||
A get_allocator() const {
|
||||
return p_table.get_alloc();
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
octa::Pair<Range, bool> emplace(Args &&...args) {
|
||||
return p_table.emplace_multi(octa::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
octa::Size erase(const K &key) {
|
||||
return p_table.remove<true>(key);
|
||||
}
|
||||
|
||||
octa::Size count(const K &key) {
|
||||
return p_table.count<true>(key);
|
||||
}
|
||||
|
||||
Range find(const K &key) { return p_table.find(key); }
|
||||
ConstRange find(const K &key) const { return p_table.find(key); }
|
||||
|
||||
float load_factor() const { return p_table.load_factor(); }
|
||||
float max_load_factor() const { return p_table.max_load_factor(); }
|
||||
void max_load_factor(float lf) { p_table.max_load_factor(lf); }
|
||||
|
||||
void rehash(octa::Size count) {
|
||||
p_table.rehash(count);
|
||||
}
|
||||
|
||||
void reserve(octa::Size count) {
|
||||
p_table.reserve(count);
|
||||
}
|
||||
|
||||
Range each() { return p_table.each(); }
|
||||
ConstRange each() const { return p_table.each(); }
|
||||
ConstRange ceach() const { return p_table.ceach(); }
|
||||
|
||||
LocalRange each(octa::Size n) { return p_table.each(n); }
|
||||
ConstLocalRange each(octa::Size n) const { return p_table.each(n); }
|
||||
ConstLocalRange ceach(octa::Size n) const { return p_table.each(n); }
|
||||
|
||||
void swap(Multimap &v) {
|
||||
octa::swap(p_table, v.p_table);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
#endif
|
196
octa/set.h
196
octa/set.h
|
@ -180,15 +180,11 @@ public:
|
|||
}
|
||||
|
||||
octa::Size erase(const T &key) {
|
||||
if (p_table.remove(key)) return 1;
|
||||
return 0;
|
||||
return p_table.remove<false>(key);
|
||||
}
|
||||
|
||||
octa::Size count(const T &key) {
|
||||
octa::Size h;
|
||||
T *v = p_table.access_base(key, h);
|
||||
if (v) return 1;
|
||||
return 0;
|
||||
return p_table.count<false>(key);
|
||||
}
|
||||
|
||||
Range find(const Key &key) { return p_table.find(key); }
|
||||
|
@ -219,6 +215,194 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename T,
|
||||
typename H = octa::ToHash<T>,
|
||||
typename C = octa::Equal<T>,
|
||||
typename A = octa::Allocator<T>
|
||||
> struct Multiset {
|
||||
private:
|
||||
using Base = octa::detail::Hashtable<
|
||||
octa::detail::SetBase<T, A>, T, T, T, H, C, A
|
||||
>;
|
||||
Base p_table;
|
||||
|
||||
template<typename R>
|
||||
octa::Size estimate_rsize(const R &range,
|
||||
octa::EnableIf<octa::IsFiniteRandomAccessRange<R>::value, bool> = true
|
||||
) {
|
||||
return range.size();
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
octa::Size estimate_rsize(const R &,
|
||||
octa::EnableIf<!octa::IsFiniteRandomAccessRange<R>::value, bool> = true
|
||||
) {
|
||||
/* we have no idea how big the range actually is */
|
||||
return 16;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
using Key = T;
|
||||
using Size = octa::Size;
|
||||
using Difference = octa::Ptrdiff;
|
||||
using Hasher = H;
|
||||
using KeyEqual = C;
|
||||
using Value = T;
|
||||
using Reference = Value &;
|
||||
using Pointer = octa::AllocatorPointer<A>;
|
||||
using ConstPointer = octa::AllocatorConstPointer<A>;
|
||||
using Range = octa::HashRange<T>;
|
||||
using ConstRange = octa::HashRange<const T>;
|
||||
using LocalRange = octa::BucketRange<T>;
|
||||
using ConstLocalRange = octa::BucketRange<const T>;
|
||||
using Allocator = A;
|
||||
|
||||
explicit Multiset(octa::Size size, const H &hf = H(),
|
||||
const C &eqf = C(), const A &alloc = A()
|
||||
): p_table(size, hf, eqf, alloc) {}
|
||||
|
||||
Multiset(): Multiset(0) {}
|
||||
explicit Multiset(const A &alloc): Multiset(0, H(), C(), alloc) {}
|
||||
|
||||
Multiset(octa::Size size, const A &alloc):
|
||||
Multiset(size, H(), C(), alloc) {}
|
||||
Multiset(octa::Size size, const H &hf, const A &alloc):
|
||||
Multiset(size, hf, C(), alloc) {}
|
||||
|
||||
Multiset(const Multiset &m): p_table(m.p_table,
|
||||
octa::allocator_container_copy(m.p_table.get_alloc())) {}
|
||||
|
||||
Multiset(const Multiset &m, const A &alloc): p_table(m.p_table, alloc) {}
|
||||
|
||||
Multiset(Multiset &&m): p_table(octa::move(m.p_table)) {}
|
||||
Multiset(Multiset &&m, const A &alloc):
|
||||
p_table(octa::move(m.p_table), alloc) {}
|
||||
|
||||
template<typename R>
|
||||
Multiset(R range, octa::Size size = 0, const H &hf = H(),
|
||||
const C &eqf = C(), const A &alloc = A(),
|
||||
octa::EnableIf<
|
||||
octa::IsInputRange<R>::value &&
|
||||
octa::IsConvertible<RangeReference<R>, Value>::value,
|
||||
bool
|
||||
> = true
|
||||
): p_table(size ? size : estimate_rsize(range), hf, eqf, alloc) {
|
||||
for (; !range.empty(); range.pop_front())
|
||||
emplace(range.front());
|
||||
p_table.rehash_up();
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
Multiset(R range, octa::Size size, const A &alloc)
|
||||
: Multiset(range, size, H(), C(), alloc) {}
|
||||
|
||||
template<typename R>
|
||||
Multiset(R range, octa::Size size, const H &hf, const A &alloc)
|
||||
: Multiset(range, size, hf, C(), alloc) {}
|
||||
|
||||
Multiset(octa::InitializerList<Value> init, octa::Size size = 0,
|
||||
const H &hf = H(), const C &eqf = C(), const A &alloc = A()
|
||||
): Multiset(octa::each(init), size, hf, eqf, alloc) {}
|
||||
|
||||
Multiset(octa::InitializerList<Value> init, octa::Size size, const A &alloc)
|
||||
: Multiset(octa::each(init), size, H(), C(), alloc) {}
|
||||
|
||||
Multiset(octa::InitializerList<Value> init, octa::Size size, const H &hf,
|
||||
const A &alloc
|
||||
): Multiset(octa::each(init), size, hf, C(), alloc) {}
|
||||
|
||||
Multiset &operator=(const Multiset &m) {
|
||||
p_table = m.p_table;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Multiset &operator=(Multiset &&m) {
|
||||
p_table = octa::move(m.p_table);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
octa::EnableIf<
|
||||
octa::IsInputRange<R>::value &&
|
||||
octa::IsConvertible<RangeReference<R>, Value>::value,
|
||||
Multiset &
|
||||
> operator=(R range) {
|
||||
clear();
|
||||
p_table.reserve_at_least(estimate_rsize(range));
|
||||
for (; !range.empty(); range.pop_front())
|
||||
emplace(range.front());
|
||||
p_table.rehash_up();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Multiset &operator=(InitializerList<Value> il) {
|
||||
const Value *beg = il.begin(), *end = il.end();
|
||||
clear();
|
||||
p_table.reserve_at_least(end - beg);
|
||||
while (beg != end)
|
||||
emplace(*beg++);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const { return p_table.empty(); }
|
||||
octa::Size size() const { return p_table.size(); }
|
||||
octa::Size max_size() const { return p_table.max_size(); }
|
||||
|
||||
octa::Size bucket_count() const { return p_table.bucket_count(); }
|
||||
octa::Size max_bucket_count() const { return p_table.max_bucket_count(); }
|
||||
|
||||
octa::Size bucket(const T &key) const { return p_table.bucket(key); }
|
||||
octa::Size bucket_size(octa::Size n) const { return p_table.bucket_size(n); }
|
||||
|
||||
void clear() { p_table.clear(); }
|
||||
|
||||
A get_allocator() const {
|
||||
return p_table.get_alloc();
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
octa::Pair<Range, bool> emplace(Args &&...args) {
|
||||
return p_table.emplace_multi(octa::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
octa::Size erase(const T &key) {
|
||||
return p_table.remove<true>(key);
|
||||
}
|
||||
|
||||
octa::Size count(const T &key) {
|
||||
return p_table.count<true>(key);
|
||||
}
|
||||
|
||||
Range find(const T &key) { return p_table.find(key); }
|
||||
ConstRange find(const T &key) const { return p_table.find(key); }
|
||||
|
||||
float load_factor() const { return p_table.load_factor(); }
|
||||
float max_load_factor() const { return p_table.max_load_factor(); }
|
||||
void max_load_factor(float lf) { p_table.max_load_factor(lf); }
|
||||
|
||||
void rehash(octa::Size count) {
|
||||
p_table.rehash(count);
|
||||
}
|
||||
|
||||
void reserve(octa::Size count) {
|
||||
p_table.reserve(count);
|
||||
}
|
||||
|
||||
Range each() { return p_table.each(); }
|
||||
ConstRange each() const { return p_table.each(); }
|
||||
ConstRange ceach() const { return p_table.ceach(); }
|
||||
|
||||
LocalRange each(octa::Size n) { return p_table.each(n); }
|
||||
ConstLocalRange each(octa::Size n) const { return p_table.each(n); }
|
||||
ConstLocalRange ceach(octa::Size n) const { return p_table.each(n); }
|
||||
|
||||
void swap(Multiset &v) {
|
||||
octa::swap(p_table, v.p_table);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue