diff --git a/include/ircd/m/room.h b/include/ircd/m/room.h index e62950604..0a5277dbf 100644 --- a/include/ircd/m/room.h +++ b/include/ircd/m/room.h @@ -104,6 +104,7 @@ struct ircd::m::room struct state; struct members; struct origins; + struct head; using id = m::id::room; using alias = m::id::room_alias; @@ -342,6 +343,30 @@ struct ircd::m::room::origins {} }; +/// Interface to the room head +/// +/// This interface helps compute and represent aspects of the room graph, +/// specifically concerning the "head" or the "front" or the "top" of this +/// graph where events are either furthest from the m.room.create genesis, +/// or are yet unreferenced by another event. Usage of this interface is +/// fundamental when composing the references of a new event on the graph. +/// +struct ircd::m::room::head +{ + using closure = std::function; + using closure_bool = std::function; + + m::room room; + + bool for_each(const closure_bool &) const; + void for_each(const closure &) const; + size_t count() const; + + head(const m::room &room) + :room{room} + {} +}; + /// Tuple to represent fundamental room state singletons (state_key = "") /// /// This is not a complete representation of room state. Missing from here diff --git a/ircd/m/room.cc b/ircd/m/room.cc index aec801c42..95cfb7102 100644 --- a/ircd/m/room.cc +++ b/ircd/m/room.cc @@ -567,7 +567,7 @@ ircd::m::room::state::state(const m::room &room, room.event_id? event::id::buf{room.event_id}: opts.snapshot? - head(room_id): + m::head(room_id): event::id::buf{} } ,root_id @@ -1492,6 +1492,69 @@ const return false; } +// +// room::head +// + +size_t +ircd::m::room::head::count() +const +{ + size_t ret(0); + for_each([&ret] + (const event::idx &event_idx, const event::id &event_id) + { + ++ret; + }); + + return ret; +} + +void +ircd::m::room::head::for_each(const closure &closure) +const +{ + for_each(closure_bool{[&closure] + (const event::idx &event_idx, const event::id &event_id) + { + closure(event_idx, event_id); + return true; + }}); +} + +bool +ircd::m::room::head::for_each(const closure_bool &closure) +const +{ + auto &index + { + dbs::room_head + }; + + auto it + { + index.begin(room.room_id) + }; + + for(; it; ++it) + { + const event::id &event_id + { + dbs::room_head_key(it->first) + }; + + const event::idx &event_idx + { + byte_view{it->second} + }; + + if(!closure(event_idx, event_id)) + return false; + } + + return true; +} + // // room::state::tuple //