Program Listing for File dllist.hpp

Return to documentation for file (ckpttncpp/dllist.hpp)

#pragma once

#include <cassert>
// #include <cstdint>
#include <utility> // import std::move()

// Forward declaration for begin() end()
template <typename T>
class dll_iterator;

#pragma pack(push, 1)
template <typename T>
class dllink
{
    friend dll_iterator<T>;

  private:
    dllink* next {this};
    dllink* prev {this};
  public:
    T data {};
    // Int key{}; /*!< key */

    constexpr explicit dllink(T data) noexcept
        : data {std::move(data)}
    {
        static_assert(sizeof(dllink) <= 24, "keep this class small");
    }

    constexpr dllink() = default;
    ~dllink() = default;
    dllink(const dllink&) = delete;                              // don't copy
    constexpr auto operator=(const dllink&) -> dllink& = delete; // don't assign
    constexpr dllink(dllink&&) noexcept = default;
    constexpr auto operator=(dllink&&) noexcept
        -> dllink& = default; // don't assign

    constexpr auto lock() noexcept -> void
    {
        this->next = nullptr;
    }

    [[nodiscard]] constexpr auto is_locked() const noexcept -> bool
    {
        return this->next == nullptr;
    }

    [[nodiscard]] constexpr auto is_empty() const noexcept -> bool
    {
        return this->next == this;
    }

    constexpr auto clear() noexcept -> void
    {
        this->next = this->prev = this;
    }

    constexpr auto detach() noexcept -> void
    {
        assert(!this->is_locked());
        const auto n = this->next;
        const auto p = this->prev;
        p->next = n;
        n->prev = p;
    }

    constexpr auto appendleft(dllink& node) noexcept -> void
    {
        node.next = this->next;
        this->next->prev = &node;
        this->next = &node;
        node.prev = this;
    }

    constexpr auto append(dllink& node) noexcept -> void
    {
        node.prev = this->prev;
        this->prev->next = &node;
        this->prev = &node;
        node.next = this;
    }

    constexpr auto popleft() noexcept -> dllink&
    {
        auto res = this->next;
        this->next = res->next;
        this->next->prev = this;
        return *res;
    }

    constexpr auto pop() noexcept -> dllink&
    {
        auto res = this->prev;
        this->prev = res->prev;
        this->prev->next = this;
        return *res;
    }

    // For iterator

    constexpr auto begin() noexcept -> dll_iterator<T>;

    constexpr auto end() noexcept -> dll_iterator<T>;

    // using coro_t = boost::coroutines2::coroutine<dllink&>;
    // using pull_t = typename coro_t::pull_type;

    // /**
    //  * @brief item generator
    //  *
    //  * @return pull_t
    //  */
    // auto items() noexcept -> pull_t
    // {
    //     auto func = [&](typename coro_t::push_type& yield) {
    //         auto cur = this->next;
    //         while (cur != this)
    //         {
    //             yield(*cur);
    //             cur = cur->next;
    //         }
    //     };
    //     return pull_t(func);
    // }
};
#pragma pack(pop)

template <typename T>
class dll_iterator
{
  private:
    dllink<T>* cur;
  public:
    constexpr explicit dll_iterator(dllink<T>* cur) noexcept
        : cur {cur}
    {
    }

    constexpr auto operator++() noexcept -> dll_iterator&
    {
        this->cur = this->cur->next;
        return *this;
    }

    constexpr auto operator*() noexcept -> dllink<T>&
    {
        return *this->cur;
    }

    friend auto operator==(
        const dll_iterator& lhs, const dll_iterator& rhs) noexcept -> bool
    {
        return lhs.cur == rhs.cur;
    }

    friend auto operator!=(
        const dll_iterator& lhs, const dll_iterator& rhs) noexcept -> bool
    {
        return !(lhs == rhs);
    }
};


template <typename T>
inline constexpr auto dllink<T>::begin() noexcept -> dll_iterator<T>
{
    return dll_iterator<T> {this->next};
}

template <typename T>
inline constexpr auto dllink<T>::end() noexcept -> dll_iterator<T>
{
    return dll_iterator<T> {this};
}