libostd/octa/map.h

176 lines
5.2 KiB
C
Raw Normal View History

2015-06-14 03:46:46 +02:00
/* Associative array for OctaSTD. Implemented as a hash table.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
#ifndef OCTA_MAP_H
#define OCTA_MAP_H
#include "octa/types.h"
#include "octa/utility.h"
#include "octa/memory.h"
#include "octa/functional.h"
2015-06-15 03:22:10 +02:00
#include "octa/initializer_list.h"
2015-06-14 03:46:46 +02:00
#include "octa/internal/hashtable.h"
namespace octa {
namespace detail {
template<typename K, typename T> struct MapBase {
2015-06-14 05:32:01 +02:00
using Element = octa::Pair<const K, T>;
2015-06-14 03:46:46 +02:00
static inline const K &get_key(Element &e) {
return e.first;
}
static inline T &get_data(Element &e) {
return e.second;
}
template<typename U>
static inline void set_key(Element &e, U &&key) {
2015-06-14 03:46:46 +02:00
e.first.~K();
new ((K *)&e.first) K(octa::forward<U>(key));
2015-06-14 03:46:46 +02:00
}
2015-06-15 01:18:08 +02:00
static inline void swap_elem(Element &a, Element &b) {
octa::swap(*((K *)&a.first), *((K *)&b.first));
octa::swap(*((T *)&a.second), *((T *)&b.second));
}
2015-06-14 03:46:46 +02:00
};
}
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 Map {
private:
using Base = octa::detail::Hashtable<
octa::detail::MapBase<K, T>, octa::Pair<const K, T>, K, T, H, C, A
>;
Base p_table;
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>;
2015-06-14 05:32:01 +02:00
using Range = octa::HashRange<octa::Pair<const K, T>>;
using ConstRange = octa::HashRange<const octa::Pair<const K, T>>;
2015-06-14 03:46:46 +02:00
using Allocator = A;
explicit Map(octa::Size size, const H &hf = H(),
const C &eqf = C(), const A &alloc = A()
): p_table(size, hf, eqf, alloc) {}
2015-06-14 03:46:46 +02:00
2015-06-15 03:22:10 +02:00
Map(): Map(octa::Size(1 << 10)) {}
explicit Map(const A &alloc): Map(octa::Size(1 << 10), H(), C(), alloc) {}
2015-06-15 02:35:37 +02:00
Map(octa::Size size, const A &alloc): Map(size, H(), C(), alloc) {}
Map(octa::Size size, const H &hf, const A &alloc): Map(size, hf, C(), alloc) {}
2015-06-15 02:35:37 +02:00
2015-06-15 03:22:10 +02:00
template<typename R>
Map(R range, octa::Size size = 1 << 10, 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, hf, eqf, alloc) {
2015-06-15 03:22:10 +02:00
for (; !range.empty(); range.pop_front())
emplace(range.front());
}
template<typename R>
Map(R range, octa::Size size, const A &alloc)
: Map(range, size, H(), C(), alloc) {}
2015-06-15 03:22:10 +02:00
template<typename R>
Map(R range, octa::Size size, const H &hf, const A &alloc)
: Map(range, size, hf, C(), alloc) {}
2015-06-15 03:22:10 +02:00
Map(octa::InitializerList<Value> init, octa::Size size = 1 << 10,
const H &hf = H(), const C &eqf = C(), const A &alloc = A()
): Map(octa::each(init), size, hf, eqf, alloc) {}
2015-06-15 03:22:10 +02:00
Map(octa::InitializerList<Value> init, octa::Size size, const A &alloc)
: Map(octa::each(init), size, H(), C(), alloc) {}
2015-06-15 03:22:10 +02:00
Map(octa::InitializerList<Value> init, octa::Size size, const H &hf,
const A &alloc
): Map(octa::each(init), size, hf, C(), alloc) {}
2015-06-15 03:22:10 +02:00
2015-06-14 04:38:08 +02:00
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(); }
2015-06-14 03:46:46 +02:00
2015-06-14 04:38:08 +02:00
octa::Size bucket_count() const { return p_table.bucket_count(); }
octa::Size max_bucket_count() const { return p_table.max_bucket_count(); }
2015-06-14 03:46:46 +02:00
void clear() { p_table.clear(); }
A get_allocator() const {
return p_table.get_challoc();
}
T &at(const K &key) {
return *p_table.access(key);
}
const T &at(const K &key) const {
return *p_table.access(key);
}
T &operator[](const K &key) {
octa::Size h;
T *v = p_table.access_base(key, h);
if (v) return *v;
return p_table.insert(h, key);
}
T &operator[](K &&key) {
octa::Size h;
T *v = p_table.access_base(key, h);
if (v) return *v;
return p_table.insert(h, octa::move(key));
}
2015-06-14 03:46:46 +02:00
2015-06-15 03:09:53 +02:00
template<typename ...Args>
octa::Pair<Range, bool> emplace(Args &&...args) {
return p_table.emplace(octa::forward<Args>(args)...);
}
2015-06-14 04:38:08 +02:00
octa::Size erase(const K &key) {
if (p_table.remove(key)) return 1;
return 0;
}
float load_factor() const { return p_table.load_factor(); }
2015-06-14 04:43:11 +02:00
float max_load_factor() const { return p_table.max_load_factor(); }
void max_load_factor(float lf) { p_table.max_load_factor(lf); }
2015-06-14 04:38:08 +02:00
2015-06-15 01:18:08 +02:00
void rehash(octa::Size count) {
p_table.rehash(count);
}
void reserve(octa::Size count) {
p_table.reserve(count);
}
2015-06-14 05:32:01 +02:00
Range each() { return p_table.each(); }
ConstRange each() const { return p_table.each(); }
ConstRange ceach() const { return p_table.ceach(); }
2015-06-14 03:46:46 +02:00
void swap(Map &v) {
octa::swap(p_table, v.p_table);
}
};
} /* namespace detail */
#endif