Files
lunar/src/wayland/List.h
2026-01-27 00:55:28 +02:00

288 lines
5.7 KiB
C++

#pragma once
#include <cstddef>
#include <iterator>
#include <wayland-server-core.h>
namespace Lunar::Wayland {
namespace detail {
template<typename T, wl_list T::*Member>
constexpr std::ptrdiff_t member_offset() noexcept
{
return reinterpret_cast<std::ptrdiff_t>(
&(reinterpret_cast<T const volatile *>(0)->*Member));
}
template<typename T, wl_list T::*Member>
inline T *container_of(wl_list *node) noexcept
{
auto *p { reinterpret_cast<std::byte *>(node)
- member_offset<T, Member>() };
return reinterpret_cast<T *>(p);
}
template<typename T, wl_list T::*Member>
inline T const *container_of(wl_list const *node) noexcept
{
auto *p { reinterpret_cast<std::byte const *>(node)
- member_offset<T, Member>() };
return reinterpret_cast<T const *>(p);
}
} // namespace detail
template<typename T, wl_list T::*Member> struct List {
struct Iterator {
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T *;
using reference = T &;
Iterator() = default;
Iterator(wl_list *cur, wl_list *head)
: m_cur(cur)
, m_head(head)
{
}
auto operator*() const -> reference
{
return *detail::container_of<T, Member>(m_cur);
}
auto operator->() const -> pointer
{
return detail::container_of<T, Member>(m_cur);
}
auto operator++() -> Iterator &
{
m_cur = m_cur->next;
return *this;
}
auto operator++(int) -> Iterator
{
auto t { *this };
++(*this);
return t;
}
auto operator--() -> Iterator &
{
m_cur = (m_cur == m_head) ? m_head->prev : m_cur->prev;
return *this;
}
auto operator--(int) -> Iterator
{
auto t { *this };
--(*this);
return t;
}
friend auto operator==(Iterator a, Iterator b) -> bool
{
return a.m_cur == b.m_cur;
}
friend auto operator!=(Iterator a, Iterator b) -> bool
{
return !(a == b);
}
private:
wl_list *m_cur { nullptr };
wl_list *m_head { nullptr };
};
struct ConstIterator {
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T const;
using difference_type = std::ptrdiff_t;
using pointer = T const *;
using reference = T const &;
ConstIterator() = default;
ConstIterator(wl_list const *cur, wl_list const *head)
: m_cur(cur)
, m_head(head)
{
}
auto operator*() const -> reference
{
return *detail::container_of<T, Member>(m_cur);
}
auto operator->() const -> pointer
{
return detail::container_of<T, Member>(m_cur);
}
auto operator++() -> ConstIterator &
{
m_cur = m_cur->next;
return *this;
}
auto operator++(int) -> ConstIterator
{
auto t { *this };
++(*this);
return t;
}
auto operator--() -> ConstIterator &
{
m_cur = (m_cur == m_head) ? m_head->prev : m_cur->prev;
return *this;
}
auto operator--(int) -> ConstIterator
{
auto t { *this };
--(*this);
return t;
}
friend auto operator==(ConstIterator a, ConstIterator b) -> bool
{
return a.m_cur == b.m_cur;
}
friend auto operator!=(ConstIterator a, ConstIterator b) -> bool
{
return !(a == b);
}
private:
wl_list const *m_cur { nullptr };
wl_list const *m_head { nullptr };
};
List()
: m_head {}
, m_external_head { nullptr }
, m_should_cleanup { true }
{
wl_list_init(&m_head);
}
explicit List(
wl_list *existing_head, bool should_cleanup = false, bool init = false)
: m_head {}
, m_external_head { existing_head }
, m_should_cleanup { should_cleanup }
{
if (init && m_external_head)
wl_list_init(m_external_head);
}
~List()
{
if (!m_should_cleanup)
return;
clear();
if (auto *h { head_ptr() }; h)
wl_list_init(h);
}
List(List const &) = delete;
auto operator=(List const &) -> List & = delete;
List(List &&other) noexcept { move_from(other); }
auto operator=(List &&other) noexcept -> List &
{
if (this != &other) {
this->~List();
move_from(other);
}
return *this;
}
inline auto c_ptr() -> wl_list * { return head_ptr(); }
inline auto c_ptr() const -> wl_list const * { return head_ptr(); }
auto empty() const noexcept -> bool { return wl_list_empty(head_ptr()); }
auto length() const noexcept -> int { return wl_list_length(head_ptr()); }
auto push_front(T *elem) noexcept -> void
{
wl_list_insert(head_ptr(), &(elem->*Member));
}
auto push_back(T *elem) noexcept -> void
{
auto *h { head_ptr() };
wl_list_insert(h->prev, &(elem->*Member));
}
auto remove(T *elem) noexcept -> void
{
wl_list_remove(&(elem->*Member));
wl_list_init(&(elem->*Member));
}
auto clear() noexcept -> void
{
auto *h { head_ptr() };
while (!wl_list_empty(h)) {
auto *node { h->next };
wl_list_remove(node);
wl_list_init(node);
}
}
auto begin() noexcept -> Iterator
{
auto *h { head_ptr() };
return Iterator(h->next, h);
}
auto end() noexcept -> Iterator
{
auto *h { head_ptr() };
return Iterator(h, h);
}
auto begin() const noexcept -> ConstIterator
{
auto const *h { head_ptr() };
return ConstIterator(h->next, h);
}
auto end() const noexcept -> ConstIterator
{
auto const *h { head_ptr() };
return ConstIterator(h, h);
}
private:
auto head_ptr() noexcept -> wl_list *
{
return m_external_head ? m_external_head : &m_head;
}
auto head_ptr() const noexcept -> wl_list const *
{
return m_external_head ? m_external_head : &m_head;
}
auto move_from(List &other) noexcept -> void
{
m_head = other.m_head;
m_external_head = other.m_external_head;
m_should_cleanup = other.m_should_cleanup;
other.m_external_head = nullptr;
other.m_should_cleanup = false;
wl_list_init(&other.m_head);
}
private:
wl_list m_head {};
wl_list *m_external_head { nullptr };
bool m_should_cleanup { true };
};
} // namespace Lunar::Wayland