Files
Cpp-in-Embedded-Systems/Chapter18/cib/libs/stdx/detail/list_common.hpp
Amar Mahmutbegovic 8634accda5 add Chapter18
2025-02-06 00:19:59 +01:00

124 lines
3.4 KiB
C++

#pragma once
#include <stdx/concepts.hpp>
#include <stdx/panic.hpp>
#include <type_traits>
#include <utility>
namespace stdx {
inline namespace v1 {
#if __cpp_concepts >= 201907L
namespace detail {
template <typename T>
concept base_single_linkable = requires(T node) {
{ node->next } -> same_as<T &>;
};
template <typename T>
concept base_double_linkable = base_single_linkable<T> and requires(T node) {
{ node->prev } -> same_as<T &>;
};
} // namespace detail
template <typename T>
concept single_linkable = requires(T *node) {
requires detail::base_single_linkable<
std::remove_cvref_t<decltype(node->next)>>;
};
template <typename T>
concept double_linkable = requires(T *node) {
requires detail::base_double_linkable<
std::remove_cvref_t<decltype(node->next)>>;
requires detail::base_double_linkable<
std::remove_cvref_t<decltype(node->prev)>>;
};
#define STDX_SINGLE_LINKABLE single_linkable
#define STDX_DOUBLE_LINKABLE double_linkable
#else
#define STDX_SINGLE_LINKABLE typename
#define STDX_DOUBLE_LINKABLE typename
#endif
namespace detail::detect {
template <typename T, typename = void> constexpr auto has_prev_pointer = false;
template <typename T>
constexpr auto
has_prev_pointer<T, std::void_t<decltype(std::declval<T>().prev)>> = true;
} // namespace detail::detect
namespace node_policy {
template <typename Node> class checked {
constexpr static auto valid_for_push(Node *node) -> bool {
if constexpr (detail::detect::has_prev_pointer<Node>) {
return node->prev == nullptr and node->next == nullptr;
} else {
return node->next == nullptr;
}
}
public:
template <typename L>
constexpr static auto push_front(L &list, Node *node) -> void {
if (not valid_for_push(node)) {
STDX_PANIC("bad list node!");
}
list.unchecked_push_front(node);
}
template <typename L>
constexpr static auto push_back(L &list, Node *node) -> void {
if (not valid_for_push(node)) {
STDX_PANIC("bad list node!");
}
list.unchecked_push_back(node);
}
template <typename L, typename It>
constexpr static auto insert(L &list, It it, Node *node) -> void {
if (not valid_for_push(node)) {
STDX_PANIC("bad list node!");
}
list.unchecked_insert(it, node);
}
constexpr static auto on_pop(Node *node) {
if constexpr (detail::detect::has_prev_pointer<Node>) {
node->prev = nullptr;
}
node->next = nullptr;
}
constexpr static auto on_clear(Node *head) {
while (head != nullptr) {
if constexpr (detail::detect::has_prev_pointer<Node>) {
head->prev = nullptr;
}
head = std::exchange(head->next, nullptr);
}
}
};
template <typename Node> struct unchecked {
template <typename L>
constexpr static auto push_front(L &list, Node *node) -> void {
list.unchecked_push_front(node);
}
template <typename L>
constexpr static auto push_back(L &list, Node *node) -> void {
list.unchecked_push_back(node);
}
template <typename L, typename It>
constexpr static auto insert(L &list, It it, Node *node) -> void {
list.unchecked_insert(it, node);
}
constexpr static auto on_pop(Node *) {}
constexpr static auto on_clear(Node *) {}
};
} // namespace node_policy
} // namespace v1
} // namespace stdx