xo-arena: + const_iterator support for DValueHashMap
This commit is contained in:
parent
2edfb56530
commit
f16e701a40
4 changed files with 124 additions and 31 deletions
|
|
@ -50,7 +50,9 @@ namespace xo {
|
||||||
using store_type = detail::HashMapStore<Key, Value>;
|
using store_type = detail::HashMapStore<Key, Value>;
|
||||||
using insert_value_type = std::pair<value_type *, bool>;
|
using insert_value_type = std::pair<value_type *, bool>;
|
||||||
using iterator = detail::DArenaHashMapIterator<Key, Value>;
|
using iterator = detail::DArenaHashMapIterator<Key, Value>;
|
||||||
|
using const_iterator = detail::DArenaHashMapConstIterator<Key, Value>;
|
||||||
|
|
||||||
|
public:
|
||||||
/** create hash map **/
|
/** create hash map **/
|
||||||
DArenaHashMap(size_type hint_max_capacity,
|
DArenaHashMap(size_type hint_max_capacity,
|
||||||
bool debug_flag = false);
|
bool debug_flag = false);
|
||||||
|
|
@ -71,28 +73,14 @@ namespace xo {
|
||||||
**/
|
**/
|
||||||
bool verify_ok(verify_policy p = verify_policy::throw_only()) const;
|
bool verify_ok(verify_policy p = verify_policy::throw_only()) const;
|
||||||
|
|
||||||
iterator begin() {
|
const_iterator cbegin() const { return this->_begin_aux(); }
|
||||||
if (this->empty()) [[unlikely]] {
|
const_iterator cend() const { return this->_end_aux(); }
|
||||||
return this->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator ix(&(store_.control_[c_control_stub]),
|
const_iterator begin() const { return this->_begin_aux(); }
|
||||||
&(store_.slots_[0]));
|
const_iterator end() const { return this->_end_aux(); }
|
||||||
|
|
||||||
if (ix._at_slot_sentinel()) {
|
iterator begin() { return _promote_iterator(_begin_aux()); }
|
||||||
/* advance to first occupied position in table */
|
iterator end() { return _promote_iterator(_end_aux()); }
|
||||||
++ix;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ix;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator end() {
|
|
||||||
iterator ix(&(store_.control_[c_control_stub + store_.capacity()]),
|
|
||||||
&(store_.slots_[store_.capacity()]));
|
|
||||||
|
|
||||||
return ix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** insert @p kv_pair into hash map.
|
/** insert @p kv_pair into hash map.
|
||||||
* Replaces any previous value stored under the same key.
|
* Replaces any previous value stored under the same key.
|
||||||
|
|
@ -117,12 +105,46 @@ namespace xo {
|
||||||
/** find element with key @p key.
|
/** find element with key @p key.
|
||||||
* @return iterator to element if found, end() otherwise
|
* @return iterator to element if found, end() otherwise
|
||||||
**/
|
**/
|
||||||
iterator find(const key_type & key);
|
const_iterator find(const key_type & key) const { return _find(key); }
|
||||||
|
iterator find(const key_type & key) { return _promote_iterator(_find(key)); }
|
||||||
|
|
||||||
/** establish kv pair for @p key in this table; return address of value part **/
|
/** establish kv pair for @p key in this table; return address of value part **/
|
||||||
mapped_type & operator[](const key_type & key);
|
mapped_type & operator[](const key_type & key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
iterator _promote_iterator(const_iterator ix) {
|
||||||
|
return iterator(const_cast<uint8_t *>(ix._ctrl()),
|
||||||
|
const_cast<value_type *>(ix._pos()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator _begin_aux() const {
|
||||||
|
if (this->empty()) [[unlikely]] {
|
||||||
|
return this->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator ix(&(store_.control_[c_control_stub]),
|
||||||
|
&(store_.slots_[0]));
|
||||||
|
|
||||||
|
if (ix._at_slot_sentinel()) {
|
||||||
|
/* advance to first occupied position in table */
|
||||||
|
++ix;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ix;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator _end_aux() const {
|
||||||
|
const_iterator ix(&(store_.control_[c_control_stub + store_.capacity()]),
|
||||||
|
&(store_.slots_[store_.capacity()]));
|
||||||
|
|
||||||
|
return ix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** search hash map on key @p key, return iterator to table member.
|
||||||
|
* return end-iterator if @p key not found
|
||||||
|
**/
|
||||||
|
const_iterator _find(const key_type & key) const;
|
||||||
|
|
||||||
/** insert @p kv_pair,
|
/** insert @p kv_pair,
|
||||||
* where key hashes to @p hash_value, into @p *store
|
* where key hashes to @p hash_value, into @p *store
|
||||||
**/
|
**/
|
||||||
|
|
@ -416,12 +438,12 @@ namespace xo {
|
||||||
typename Hash,
|
typename Hash,
|
||||||
typename Equal>
|
typename Equal>
|
||||||
auto
|
auto
|
||||||
DArenaHashMap<Key, Value, Hash, Equal>::find(const key_type & key) -> iterator
|
DArenaHashMap<Key, Value, Hash, Equal>::_find(const key_type & key) const -> const_iterator
|
||||||
{
|
{
|
||||||
size_type N = store_.capacity();
|
size_type N = store_.capacity();
|
||||||
|
|
||||||
if (N == 0) [[unlikely]] {
|
if (N == 0) [[unlikely]] {
|
||||||
return this->end();
|
return this->cend();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type h = hash_(key);
|
size_type h = hash_(key);
|
||||||
|
|
@ -443,8 +465,8 @@ namespace xo {
|
||||||
auto & slot = store_.slots_[slot_ix];
|
auto & slot = store_.slots_[slot_ix];
|
||||||
|
|
||||||
if (equal_(slot.first, key)) {
|
if (equal_(slot.first, key)) {
|
||||||
return iterator(&(store_.control_[c_control_stub + slot_ix]),
|
return const_iterator(&(store_.control_[c_control_stub + slot_ix]),
|
||||||
&slot);
|
&slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
m &= (m - 1);
|
m &= (m - 1);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ namespace xo {
|
||||||
std::array<uint8_t, DArenaHashMapUtil::c_group_size> ctrl_;
|
std::array<uint8_t, DArenaHashMapUtil::c_group_size> ctrl_;
|
||||||
|
|
||||||
/** Require: lo is aligned on c_group_size (probably 16 bytes) **/
|
/** Require: lo is aligned on c_group_size (probably 16 bytes) **/
|
||||||
explicit ControlGroup(uint8_t * lo) {
|
explicit ControlGroup(const uint8_t * lo) {
|
||||||
::memcpy(ctrl_.data(), lo, DArenaHashMapUtil::c_group_size);
|
::memcpy(ctrl_.data(), lo, DArenaHashMapUtil::c_group_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ namespace xo {
|
||||||
value_type & operator*() const { return *pos_; }
|
value_type & operator*() const { return *pos_; }
|
||||||
value_type * operator->() const { return pos_; }
|
value_type * operator->() const { return pos_; }
|
||||||
|
|
||||||
|
uint8_t * _ctrl() const { return ctrl_; }
|
||||||
|
value_type * _pos() const { return pos_; }
|
||||||
|
|
||||||
/** true iff iterator at sentinel position (not dereferencable state !) **/
|
/** true iff iterator at sentinel position (not dereferencable state !) **/
|
||||||
bool _at_slot_sentinel() const { return is_sentinel(*ctrl_) && (*ctrl_ != c_iterator_bookend); }
|
bool _at_slot_sentinel() const { return is_sentinel(*ctrl_) && (*ctrl_ != c_iterator_bookend); }
|
||||||
|
|
||||||
|
|
@ -36,8 +39,8 @@ namespace xo {
|
||||||
|
|
||||||
DArenaHashMapIterator & operator++() {
|
DArenaHashMapIterator & operator++() {
|
||||||
do {
|
do {
|
||||||
++ctrl_;
|
++(this->ctrl_);
|
||||||
++pos_;
|
++(this->pos_);
|
||||||
|
|
||||||
/** end condition: iterator ends at last non-wrapped position.
|
/** end condition: iterator ends at last non-wrapped position.
|
||||||
* relyin on bookend sentinel values at known offset from 'wrap' section
|
* relyin on bookend sentinel values at known offset from 'wrap' section
|
||||||
|
|
@ -62,8 +65,8 @@ namespace xo {
|
||||||
* precedes control byte for first slot
|
* precedes control byte for first slot
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
--ctrl_;
|
--(this->ctrl_);
|
||||||
--pos_;
|
--(this->pos_);
|
||||||
} while (is_sentinel(*ctrl_)
|
} while (is_sentinel(*ctrl_)
|
||||||
&& (*ctrl_ != c_iterator_bookend));
|
&& (*ctrl_ != c_iterator_bookend));
|
||||||
|
|
||||||
|
|
@ -75,6 +78,74 @@ namespace xo {
|
||||||
value_type * pos_ = nullptr;
|
value_type * pos_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Key,
|
||||||
|
typename Value>
|
||||||
|
struct DArenaHashMapConstIterator : public DArenaHashMapUtil {
|
||||||
|
using value_type = std::pair<const Key, Value>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DArenaHashMapConstIterator(const uint8_t * c, const value_type * p)
|
||||||
|
: ctrl_{c}, pos_{p} {}
|
||||||
|
|
||||||
|
const value_type & operator*() const { return *pos_; }
|
||||||
|
const value_type * operator->() const { return pos_; }
|
||||||
|
|
||||||
|
const uint8_t * _ctrl() const { return ctrl_; }
|
||||||
|
const value_type * _pos() const { return pos_; }
|
||||||
|
|
||||||
|
/** true iff iterator at sentinel position (not dereferencable state !) **/
|
||||||
|
bool _at_slot_sentinel() const {
|
||||||
|
return is_sentinel(*ctrl_) && (*ctrl_ != c_iterator_bookend);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const DArenaHashMapConstIterator & x) const {
|
||||||
|
return this->pos_ == x.pos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const DArenaHashMapConstIterator & x) const {
|
||||||
|
return this->pos_ != x.pos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DArenaHashMapConstIterator & operator++() {
|
||||||
|
do {
|
||||||
|
++(this->ctrl_);
|
||||||
|
++(this->pos_);
|
||||||
|
|
||||||
|
/** end condition: iterator ends at last non-wrapped position.
|
||||||
|
* relyin on bookend sentinel values at known offset from 'wrap' section
|
||||||
|
*
|
||||||
|
* ctrl_ ctrl_ + c_group_size
|
||||||
|
* | |
|
||||||
|
* v v
|
||||||
|
* <----------------- control_size(n_slot) ---------------->
|
||||||
|
* <-stub-> <----------- n_slot ----------> <group> <-stub->
|
||||||
|
* +--------+-------------------------------+-------+--------+
|
||||||
|
* | 0xF0 | empty / data / tombstone | wrap | 0xF0 |
|
||||||
|
* +--------+-------------------------------+-------+--------+
|
||||||
|
**/
|
||||||
|
} while (is_sentinel(*ctrl_)
|
||||||
|
&& (*(ctrl_ + c_group_size) != c_iterator_bookend));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DArenaHashMapConstIterator & operator--() {
|
||||||
|
/* simpler than forward iteration, since bookend immediately
|
||||||
|
* precedes control byte for first slot
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
--(this->ctrl_);
|
||||||
|
--(this->pos_);
|
||||||
|
} while (is_sentinel(*ctrl_)
|
||||||
|
&& (*ctrl_ != c_iterator_bookend));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t * ctrl_ = nullptr;
|
||||||
|
const value_type * pos_ = nullptr;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} /*namespace map*/
|
} /*namespace map*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** load control group for slot range [ix .. ix+c_group_size) **/
|
/** load control group for slot range [ix .. ix+c_group_size) **/
|
||||||
group_type _load_group(size_type ix) {
|
group_type _load_group(size_type ix) const {
|
||||||
return group_type(&(control_[ix + c_control_stub]));
|
return group_type(&(control_[ix + c_control_stub]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue