diff --git a/include/ircd/m/events.h b/include/ircd/m/events.h index 5d0deed9f..316393afc 100644 --- a/include/ircd/m/events.h +++ b/include/ircd/m/events.h @@ -13,16 +13,23 @@ namespace ircd::m::events { + struct range; using id_closure_bool = std::function; using closure_bool = std::function; - // counts up from start - bool for_each(const event::idx &start, const id_closure_bool &); - bool for_each(const event::idx &start, const closure_bool &); - bool for_each(const event::idx &start, const event_filter &, const closure_bool &); - - // -1 starts at newest event; counts down - bool rfor_each(const event::idx &start, const id_closure_bool &); - bool rfor_each(const event::idx &start, const closure_bool &); - bool rfor_each(const event::idx &start, const event_filter &, const closure_bool &); + bool for_each(const range &, const id_closure_bool &); + bool for_each(const range &, const closure_bool &); + bool for_each(const range &, const event_filter &, const closure_bool &); } + +/// Range to start (inclusive) and stop (exclusive). If start is greater than +/// stop a reverse iteration will occur. -1 (or unsigned max value) can be used +/// to start or stop at the end. 0 can be used to start or stop at the beginning. +/// +struct ircd::m::events::range +:std::pair +{ + range(const event::idx &start, const event::idx &stop = -1) + :std::pair{start, stop} + {} +}; diff --git a/ircd/m/m.cc b/ircd/m/m.cc index 0dd9a29b8..74f6719dd 100644 --- a/ircd/m/m.cc +++ b/ircd/m/m.cc @@ -1611,86 +1611,7 @@ ircd::m::node::room::room(const m::node &node) // bool -ircd::m::events::rfor_each(const event::idx &start, - const event_filter &filter, - const closure_bool &closure) -{ - auto limit - { - json::get<"limit"_>(filter)?: 32L - }; - - return rfor_each(start, [&filter, &closure, &limit] - (const event::idx &event_idx, const m::event &event) - -> bool - { - if(!match(filter, event)) - return true; - - if(!closure(event_idx, event)) - return false; - - return --limit; - }); -} - -bool -ircd::m::events::rfor_each(const event::idx &start, - const closure_bool &closure) -{ - event::fetch event; - return rfor_each(start, id_closure_bool{[&event, &closure] - (const event::idx &event_idx, const event::id &event_id) - { - if(!seek(event, event_idx, std::nothrow)) - return true; - - return closure(event_idx, event); - }}); -} - -bool -ircd::m::events::rfor_each(const event::idx &start, - const id_closure_bool &closure) -{ - static const db::gopts opts - { - db::get::NO_CACHE - }; - - static constexpr auto column_idx - { - json::indexof() - }; - - auto &column - { - dbs::event_column.at(column_idx) - }; - - if(start == uint64_t(-1)) - { - for(auto it(column.rbegin(opts)); it; ++it) - if(!closure(byte_view(it->first), it->second)) - return false; - - return true; - } - - auto it - { - column.lower_bound(byte_view(start), opts) - }; - - for(; it; --it) - if(!closure(byte_view(it->first), it->second)) - return false; - - return true; -} - -bool -ircd::m::events::for_each(const event::idx &start, +ircd::m::events::for_each(const range &range, const event_filter &filter, const closure_bool &closure) { @@ -1699,7 +1620,7 @@ ircd::m::events::for_each(const event::idx &start, json::get<"limit"_>(filter)?: 32L }; - return for_each(start, [&filter, &closure, &limit] + return for_each(range, [&filter, &closure, &limit] (const event::idx &event_idx, const m::event &event) -> bool { @@ -1714,11 +1635,11 @@ ircd::m::events::for_each(const event::idx &start, } bool -ircd::m::events::for_each(const event::idx &start, +ircd::m::events::for_each(const range &range, const closure_bool &closure) { event::fetch event; - return for_each(start, id_closure_bool{[&event, &closure] + return for_each(range, id_closure_bool{[&event, &closure] (const event::idx &event_idx, const event::id &event_id) { if(!seek(event, event_idx, std::nothrow)) @@ -1729,7 +1650,7 @@ ircd::m::events::for_each(const event::idx &start, } bool -ircd::m::events::for_each(const event::idx &start, +ircd::m::events::for_each(const range &range, const id_closure_bool &closure) { static const db::gopts opts @@ -1747,16 +1668,51 @@ ircd::m::events::for_each(const event::idx &start, dbs::event_column.at(column_idx) }; - auto it + const auto &start{range.first}; + const auto &stop{range.second}; + const bool ascending { - start > 0? - column.lower_bound(byte_view(start), opts): - column.begin(opts) + start < stop }; - for(; it; ++it) - if(!closure(byte_view(it->first), it->second)) + auto it + { + column.lower_bound(byte_view(start), opts) + }; + + // Branch to use a reverse iterator from the end + if(!ascending && !it) + { + for(auto it(column.rbegin(opts)); it; ++it) + { + const event::idx &event_idx + { + byte_view(it->first) + }; + + if(event_idx <= stop) + break; + + if(!closure(event_idx, it->second)) + return false; + } + } + else for(; it; ascending? ++it : --it) + { + const event::idx &event_idx + { + byte_view(it->first) + }; + + if(ascending && event_idx >= stop) + break; + + if(!ascending && event_idx <= stop) + break; + + if(!closure(event_idx, it->second)) return false; + } return true; } diff --git a/modules/console.cc b/modules/console.cc index 624301c7d..a7252b0a9 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -5249,36 +5249,39 @@ console_cmd__events(opt &out, const string_view &line) { const params param{line, " ", { - "start", "[dir]", "[limit]" + "start", "stop" }}; - const uint64_t start + const int64_t start { - param.at(0, uint64_t(-1)) + param.at("start", -1) }; - const char &dir + const int64_t stop { - param.at(1, "b"_sv).at(0) + param.at("stop", start == -1? 0 : -1) }; size_t limit { - param.at(2, 32) + stop == 0 || stop == -1? + 32: + std::numeric_limits::max() }; const auto closure{[&out, &limit] (const m::event::idx &seq, const m::event &event) { - out << seq << " " << pretty_oneline(event) << std::endl;; - return --limit; + out << seq << " " << pretty_oneline(event) << std::endl; + return --limit > 0; }}; - if(dir == 'f') - m::events::for_each(start, closure); - else - m::events::rfor_each(start, closure); + const m::events::range range + { + uint64_t(start), uint64_t(stop) + }; + m::events::for_each(range, closure); return true; } @@ -5300,7 +5303,7 @@ console_cmd__events__filter(opt &out, const string_view &line) param.at(1) }; - m::events::rfor_each(start, filter, [&out] + m::events::for_each({start, 0}, filter, [&out] (const m::event::idx &seq, const m::event &event) { out << seq << " " << pretty_oneline(event) << std::endl;;