mirror of
https://github.com/slendidev/lunar.git
synced 2026-01-30 16:28:58 +02:00
288 lines
5.7 KiB
C++
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
|