Files
MentOS/mentos/inc/klib/list_head.h
T
Enrico Fraccaroli (Galfurian) 1b2bc49d41 Update license and remove unused files.
2022-01-27 15:12:36 -05:00

172 lines
5.4 KiB
C

/// @file list_head.h
/// @brief
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "stddef.h"
/// @brief Structure used to implement the list_head data structure.
typedef struct list_head {
/// @brief The previous element.
struct list_head *prev;
/// @brief The subsequent element.
struct list_head *next;
} list_head;
/// @brief Get the struct for this entry.
/// @param ptr The &list_head pointer.
/// @param type The type of the struct this is embedded in.
/// @param member The name of the list_head within the struct.
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/// @brief Iterates over a list.
/// @param pos The &list_head to use as a loop cursor.
/// @param head The head for your list.
#define list_for_each(pos, head) \
for ((pos) = (head)->next; (pos) != (head); (pos) = (pos)->next)
/// @brief Iterates over a list backwards.
/// @param pos The &list_head to use as a loop cursor.
/// @param head The head for your list.
#define list_for_each_prev(pos, head) \
for ((pos) = (head)->prev; (pos) != (head); (pos) = (pos)->prev)
/// @brief Iterates over a list safe against removal of list entry.
/// @param pos The &list_head to use as a loop cursor.
/// @param store Another &list_head to use as temporary storage.
/// @param head The head for your list.
#define list_for_each_safe(pos, store, head) \
for ((pos) = (head)->next, (store) = (pos)->next; (pos) != (head); \
(pos) = (store), (store) = (pos)->next)
/// @brief Iterates over a list.
/// @param pos The &list_head to use as a loop cursor.
/// @param head The head for your list.
#define list_for_each_decl(pos, head) \
for (list_head * (pos) = (head)->next; (pos) != (head); (pos) = (pos)->next)
/// @brief Initializes the list_head.
/// @param head The head for your list.
#define list_head_init(head) (head)->next = (head)->prev = (head)
/// @brief Initializes the list_head.
/// @param head The head for your list.
#define list_head_size(head) \
({ \
unsigned __list_head_size = 0; \
list_for_each_decl(it, head) __list_head_size += 1; \
__list_head_size; \
})
/// @brief Insert element l2 after l1.
static inline void list_head_insert_after(list_head *l1, list_head *l2)
{
// [La]->l1 La<-[l1]->Lb <-[l2]-> l1<-[Lb]
list_head *l1_next = l1->next;
// [La]->l1 La<-[l1]->l2 <-[l2]-> l1<-[Lb]
l1->next = l2;
// [La]->l1 La<-[l1]->l2 l1<-[l2]-> l1<-[Lb]
l2->prev = l1;
// [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l1<-[Lb]
l2->next = l1_next;
// [La]->l1 La<-[l1]->l2 l1<-[l2]->Lb l2<-[Lb]
l1_next->prev = l2;
}
/// @brief Insert element l2 before l1.
static inline void list_head_insert_before(list_head *l1, list_head *l2)
{
// [La]->l1 [l2] La<-[l1]->Lb l1<-[Lb]
list_head *l1_prev = l1->prev;
// [La]->l2 [l2] La<-[l1]->Lb l1<-[Lb]
l1_prev->next = l2;
// [La]->l2 La<-[l2] La<-[l1]->Lb l1<-[Lb]
l2->prev = l1_prev;
// [La]->l2 La<-[l2]->l1 La<-[l1]->Lb l1<-[Lb]
l2->next = l1;
// [La]->l2 La<-[l2]->l1 l2<-[l1]->Lb l1<-[Lb]
l1->prev = l2;
}
/// @brief Remove l from the list.
/// @param l The element to remove.
static inline void list_head_del(list_head *l)
{
// [La]->l La<-[l]->Lb l<-[Lb]
// [La]->Lb La<-[l]->Lb l<-[Lb]
l->prev->next = l->next;
// [La]->Lb La<-[l]->Lb La<-[Lb]
l->next->prev = l->prev;
// [La]->Lb l<-[l]->l La<-[Lb]
l->next = l->prev = l;
}
/// @brief Tests whether the given list is empty.
/// @param head The list to check.
/// @return 1 if empty, 0 otherwise.
static inline int list_head_empty(list_head const *head)
{
return head->next == head;
}
/// Insert a new entry between two known consecutive entries.
static inline void __list_add(list_head *new, list_head *prev, list_head *next)
{
// [prev]-> <-[new]-> <-[next]
// [prev]-> <-[new]-> new<-[next]
next->prev = new;
// [prev]-> <-[new]->next new<-[next]
new->next = next;
// [prev]-> prev<-[new]->next new<-[next]
new->prev = prev;
// [prev]->new prev<-[new]->next new<-[next]
prev->next = new;
}
/// @brief Insert element l2 before l1.
static inline void list_head_add(list_head *new, list_head *head)
{
__list_add(new, head, head->next);
}
/// @brief Insert element l2 before l1.
static inline void list_head_add_tail(list_head *new, list_head *head)
{
__list_add(new, head->prev, head);
}
/// @brief Removes an element from the list pointer, it's used when we have a possibly
/// null list pointer and want to pop an element from it
static inline list_head *list_head_pop(list_head *listp)
{
if (list_head_empty(listp))
return NULL;
list_head *value = listp->next;
list_head_del(listp->next);
return value;
}
static inline list_head *list_head_front(list_head *listp)
{
return listp->next;
}
/// Merges the elements of l2, into the elements of l1.
static inline void list_head_merge(list_head *l1, list_head *l2)
{
l1->prev->next = l2->next;
l2->next->prev = l1->prev;
l2->prev->next = l1;
l1->prev = l2->prev;
// Initialize the second list.
list_head_init(l2);
}