diff --git a/include/xo/arena/DArenaHashMap.hpp b/include/xo/arena/DArenaHashMap.hpp index 43fe16f..1c5e4bd 100644 --- a/include/xo/arena/DArenaHashMap.hpp +++ b/include/xo/arena/DArenaHashMap.hpp @@ -379,6 +379,19 @@ namespace xo { return *this; } + DArenaHashMapIterator & operator--() { + /* simpler than forward iteration, since bookend immediately + * precedes control byte for first slot + */ + do { + --ctrl_; + --pos_; + } while (is_sentinel(*ctrl_) + && (*ctrl_ != c_iterator_bookend)); + + return *this; + } + private: uint8_t * ctrl_ = nullptr; value_type * pos_ = nullptr; diff --git a/utest/DArenaHashMap.test.cpp b/utest/DArenaHashMap.test.cpp index dc2562b..757cd39 100644 --- a/utest/DArenaHashMap.test.cpp +++ b/utest/DArenaHashMap.test.cpp @@ -207,6 +207,9 @@ namespace xo { ok_flag &= HashMapUtil::check_forward_iterator(0.0 /*dvalue*/, dbg_flag, hash_map); + /* regular forward iterator, but start at hash_map.end() and use operator-- */ + ok_flag &= HashMapUtil::check_backward_iterator(0.0 /*dvalue*/, + dbg_flag, hash_map); ok_flag &= HashMapUtil::random_lookups(0.0 /*dvalue*/, dbg_flag, &rgen, hash_map); diff --git a/utest/random_hash_ops.hpp b/utest/random_hash_ops.hpp index dd42c39..ef19c31 100644 --- a/utest/random_hash_ops.hpp +++ b/utest/random_hash_ops.hpp @@ -378,7 +378,7 @@ namespace utest { /* Require: * - hash has keys [0..n-1] where n=map size - * - tree value at key k is dvalue+10*k + * - hash value at key k is dvalue+10*k */ static bool check_forward_iterator(uint32_t dvalue, @@ -443,6 +443,73 @@ namespace utest { return ok_flag; } + /* Require: + * - hash has keys [0..n-1] where n=map size + * - hash value at key k is dvalue+10*k + */ + static bool + check_backward_iterator(uint32_t dvalue, + bool catch_flag, + HashMap & map) + { + catch_flag=true; + + using xo::scope; + using xo::xtag; + + /* -> flase if/when verification fails */ + bool ok_flag = true; + + std::size_t const n = map.size(); + + scope log(XO_DEBUG(catch_flag)); + + log && log("map with size n", xtag("n", n)); + + std::unordered_set keys; + + { + auto end_ix = map.end(); + + //log && log(xtag("end_ix", end_ix)); + + auto begin_ix = map.begin(); + auto ix = end_ix; + + if (ix == begin_ix) [[unlikely]] { + return ok_flag; + } + + while (ix != begin_ix) { + log && log("backward loop top", + xtag("n", n) + ); + + --ix; + + /* verify: keys in map are in [0 .. n) */ + REQUIRE_ORFAIL(ok_flag, catch_flag, 0 <= ix->first); + REQUIRE_ORFAIL(ok_flag, catch_flag, ix->first < n); + + log && log(xtag("ix->first", ix->first)); + + /* verify: keys in map are unique */ + REQUIRE_ORFAIL(ok_flag, catch_flag, !keys.contains(ix->first)); + keys.insert(ix->first); + + REQUIRE_ORFAIL(ok_flag, catch_flag, ix->second == dvalue + 10 * ix->first); + } + + /* should have visited exactly n locations */ + REQUIRE_ORFAIL(ok_flag, catch_flag, map.size() == keys.size()); + REQUIRE_ORFAIL(ok_flag, catch_flag, ix == begin_ix); + + //log && log(xtag("ix", ix), xtag("begin_ix", begin_ix)); + } + + return ok_flag; + } + #ifdef NOT_YET /* Require: * - tree has keys [0..n-1], where n=treẹsize()