1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-21 06:53:01 +08:00
lvgl/lv_misc/lv_ll.c

361 lines
9.2 KiB
C
Raw Normal View History

2017-11-23 20:42:14 +01:00
/**
2017-11-24 17:48:47 +01:00
* @file lv_ll.c
2017-11-23 20:42:14 +01:00
* Handle linked lists.
2017-11-24 17:48:47 +01:00
* The nodes are dynamically allocated by the 'lv_mem' module,
2017-11-23 20:42:14 +01:00
*/
/*********************
* INCLUDES
*********************/
#include <stdint.h>
#include <string.h>
#include "lv_ll.h"
#include "lv_mem.h"
/*********************
* DEFINES
*********************/
2017-11-24 17:48:47 +01:00
#define LL_NODE_META_SIZE (sizeof(lv_ll_node_t*) + sizeof(lv_ll_node_t*))
2017-11-23 20:42:14 +01:00
#define LL_PREV_P_OFFSET(ll_p) (ll_p->n_size)
2017-11-24 17:48:47 +01:00
#define LL_NEXT_P_OFFSET(ll_p) (ll_p->n_size + sizeof(lv_ll_node_t*))
2017-11-23 20:42:14 +01:00
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
2017-11-24 17:48:47 +01:00
static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t* act, lv_ll_node_t* prev);
static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t* act, lv_ll_node_t* next);
2017-11-23 20:42:14 +01:00
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize linked list
* @param ll_dsc pointer to ll_dsc variable
* @param n_size the size of 1 node in bytes
*/
2017-11-24 17:48:47 +01:00
void lv_ll_init(lv_ll_t * ll_p, uint32_t n_size)
2017-11-23 20:42:14 +01:00
{
ll_p->head = NULL;
ll_p->tail = NULL;
if(n_size & 0x3) { /*Round up to 4*/
n_size &= ~0x3;
2017-11-23 20:42:14 +01:00
n_size += 4;
}
ll_p->n_size = n_size;
}
/**
* Add a new head to a linked list
* @param ll_p pointer to linked list
* @return pointer to the new head
*/
2017-11-24 17:48:47 +01:00
void * lv_ll_ins_head(lv_ll_t * ll_p)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
lv_ll_node_t* n_new;
2017-11-23 20:42:14 +01:00
2017-11-23 21:28:36 +01:00
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
2017-11-23 20:42:14 +01:00
if(n_new != NULL) {
node_set_prev(ll_p, n_new, NULL); /*No prev. before the new head*/
node_set_next(ll_p, n_new, ll_p->head); /*After new comes the old head*/
if(ll_p->head != NULL) { /*If there is old head then before it goes the new*/
node_set_prev(ll_p, ll_p->head, n_new);
}
ll_p->head = n_new; /*Set the new head in the dsc.*/
if(ll_p->tail == NULL) {/*If there is no tail (1. node) set the tail too*/
ll_p->tail = n_new;
}
}
return n_new;
}
2018-02-15 13:24:56 +01:00
/**
* Insert a new node in front of the n_act node
* @param ll_p pointer to linked list
* @param n_act pointer a node
* @return pointer to the new head
*/
void * lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act)
{
lv_ll_node_t* n_new;
lv_ll_node_t* n_prev;
if(NULL == ll_p || NULL == n_act) return NULL;
if(lv_ll_get_head(ll_p) == n_act) {
n_new = lv_ll_ins_head(ll_p);
}
else {
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
lv_mem_assert(n_new);
n_prev = lv_ll_get_prev(ll_p, n_act);
node_set_next(ll_p, n_prev, n_new);
node_set_prev(ll_p, n_new, n_prev);
node_set_prev(ll_p, n_act, n_new);
node_set_next(ll_p, n_new, n_act);
}
return n_new;
}
2017-11-23 20:42:14 +01:00
/**
* Add a new tail to a linked list
* @param ll_p pointer to linked list
* @return pointer to the new tail
*/
2017-11-24 17:48:47 +01:00
void * lv_ll_ins_tail(lv_ll_t * ll_p)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
lv_ll_node_t* n_new;
2017-11-23 20:42:14 +01:00
2017-11-23 21:28:36 +01:00
n_new = lv_mem_alloc(ll_p->n_size + LL_NODE_META_SIZE);
2017-11-23 20:42:14 +01:00
if(n_new != NULL) {
node_set_next(ll_p, n_new, NULL); /*No next after the new tail*/
node_set_prev(ll_p, n_new, ll_p->tail); /*The prev. before new is tho old tail*/
if(ll_p->tail != NULL) { /*If there is old tail then the new comes after it*/
node_set_next(ll_p, ll_p->tail, n_new);
}
ll_p->tail = n_new; /*Set the new tail in the dsc.*/
if(ll_p->head == NULL) { /*If there is no head (1. node) set the head too*/
ll_p->head = n_new;
}
}
return n_new;
}
/**
* Remove the node 'node_p' from 'll_p' linked list.
* It Dose not free the the memory of node.
* @param ll_p pointer to the linked list of 'node_p'
* @param node_p pointer to node in 'll_p' linked list
*/
2017-11-24 17:48:47 +01:00
void lv_ll_rem(lv_ll_t * ll_p, void * node_p)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
if(lv_ll_get_head(ll_p) == node_p) {
2017-11-23 20:42:14 +01:00
/*The new head will be the node after 'n_act'*/
2017-11-24 17:48:47 +01:00
ll_p->head = lv_ll_get_next(ll_p, node_p);
2017-11-23 20:42:14 +01:00
if(ll_p->head == NULL) {
ll_p->tail = NULL;
}
else {
node_set_prev(ll_p, ll_p->head, NULL);
}
}
2017-11-24 17:48:47 +01:00
else if(lv_ll_get_tail(ll_p) == node_p) {
2017-11-23 20:42:14 +01:00
/*The new tail will be the node before 'n_act'*/
2017-11-24 17:48:47 +01:00
ll_p->tail = lv_ll_get_prev(ll_p, node_p);
2017-11-23 20:42:14 +01:00
if(ll_p->tail == NULL) {
ll_p->head = NULL;
}
else {
node_set_next(ll_p, ll_p->tail, NULL);
}
}
else
{
2017-11-24 17:48:47 +01:00
lv_ll_node_t* n_prev = lv_ll_get_prev(ll_p, node_p);
lv_ll_node_t* n_next = lv_ll_get_next(ll_p, node_p);
2017-11-23 20:42:14 +01:00
node_set_next(ll_p, n_prev, n_next);
node_set_prev(ll_p, n_next, n_prev);
}
}
/**
2017-11-24 17:48:47 +01:00
* Remove and free all elements from a linked list. The list remain valid but become empty.
2017-11-23 20:42:14 +01:00
* @param ll_p pointer to linked list
*/
2017-11-24 17:48:47 +01:00
void lv_ll_clear(lv_ll_t * ll_p)
2017-11-23 20:42:14 +01:00
{
void * i;
void * i_next;
2017-11-24 17:48:47 +01:00
i = lv_ll_get_head(ll_p);
2017-11-23 20:42:14 +01:00
i_next = NULL;
while(i != NULL) {
2017-11-24 17:48:47 +01:00
i_next = lv_ll_get_next(ll_p, i);
2017-11-23 20:42:14 +01:00
2017-11-24 17:48:47 +01:00
lv_ll_rem(ll_p, i);
2017-11-23 21:28:36 +01:00
lv_mem_free(i);
2017-11-23 20:42:14 +01:00
i = i_next;
}
}
/**
* Move a node to a new linked list
* @param ll_ori_p pointer to the original (old) linked list
* @param ll_new_p pointer to the new linked list
* @param node pointer to a node
*/
2017-11-24 17:48:47 +01:00
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
lv_ll_rem(ll_ori_p, node);
2017-11-23 20:42:14 +01:00
/*Set node as head*/
node_set_prev(ll_new_p, node, NULL);
node_set_next(ll_new_p, node, ll_new_p->head);
if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/
node_set_prev(ll_new_p, ll_new_p->head, node);
}
ll_new_p->head = node; /*Set the new head in the dsc.*/
if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
ll_new_p->tail = node;
}
}
/**
* Return with head node of the linked list
* @param ll_p pointer to linked list
* @return pointer to the head of 'll_p'
*/
2017-11-24 17:48:47 +01:00
void * lv_ll_get_head(lv_ll_t * ll_p)
2017-11-23 20:42:14 +01:00
{
void * head = NULL;
if(ll_p != NULL) {
head = ll_p->head;
}
return head;
}
/**
* Return with tail node of the linked list
* @param ll_p pointer to linked list
* @return pointer to the head of 'll_p'
*/
2017-11-24 17:48:47 +01:00
void * lv_ll_get_tail(lv_ll_t * ll_p)
2017-11-23 20:42:14 +01:00
{
void * tail = NULL;
if(ll_p != NULL) {
tail = ll_p->tail;
}
return tail;
}
/**
* Return with the pointer of the next node after 'n_act'
* @param ll_p pointer to linked list
* @param n_act pointer a node
* @return pointer to the next node
*/
2017-11-24 17:48:47 +01:00
void * lv_ll_get_next(lv_ll_t * ll_p, void * n_act)
2017-11-23 20:42:14 +01:00
{
void * next = NULL;
if(ll_p != NULL) {
2017-11-24 17:48:47 +01:00
lv_ll_node_t* n_act_d = n_act;
2017-11-23 20:42:14 +01:00
memcpy(&next, n_act_d + LL_NEXT_P_OFFSET(ll_p), sizeof(void *));
}
return next;
}
/**
* Return with the pointer of the previous node after 'n_act'
* @param ll_p pointer to linked list
* @param n_act pointer a node
* @return pointer to the previous node
*/
2017-11-24 17:48:47 +01:00
void * lv_ll_get_prev(lv_ll_t * ll_p, void * n_act)
2017-11-23 20:42:14 +01:00
{
void * prev = NULL;
if(ll_p != NULL) {
2017-11-24 17:48:47 +01:00
lv_ll_node_t* n_act_d = n_act;
2017-11-23 20:42:14 +01:00
memcpy(&prev, n_act_d + LL_PREV_P_OFFSET(ll_p), sizeof(void *));
}
return prev;
}
2017-11-24 17:48:47 +01:00
void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p)
2017-11-23 20:42:14 +01:00
{
2017-12-02 20:43:50 +01:00
(void)(ll_p);
(void)(n1_p);
(void)(n2_p);
2017-11-24 17:48:47 +01:00
/*TODO*/
2017-11-23 20:42:14 +01:00
}
2018-04-18 13:23:19 +02:00
/**
* Move a nodw before an other node in the same linked list
* @param ll_p pointer to a linked list
* @param n_act pointer to node to move
* @param n_after pointer to a node which should be after `n_act`
*/
void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after)
{
if(n_act == n_after) return; /*Can't move before itself*/
if(n_after == NULL) {
void * n_before = lv_ll_get_tail(ll_p);
node_set_next(ll_p, n_before, n_act);
node_set_prev(ll_p, n_act, n_before);
node_set_next(ll_p, n_act, NULL);
ll_p->tail = n_act;
} else {
void * n_before = lv_ll_get_prev(ll_p, n_after);
/*Move the node between `n_before` and `n_after`*/
node_set_next(ll_p, n_before, n_act);
node_set_prev(ll_p, n_act, n_before);
node_set_prev(ll_p, n_after, n_act);
node_set_next(ll_p, n_act, n_after);
}
}
2017-11-23 20:42:14 +01:00
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Set the 'pervious node pointer' of a node
* @param ll_p pointer to linked list
* @param act pointer to a node which prev. node pointer should be set
* @param prev pointer to a node which should be the previous node before 'act'
*/
2017-11-24 17:48:47 +01:00
static void node_set_prev(lv_ll_t * ll_p, lv_ll_node_t* act, lv_ll_node_t* prev)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
memcpy(act + LL_PREV_P_OFFSET(ll_p), &prev, sizeof(lv_ll_node_t*));
2017-11-23 20:42:14 +01:00
}
/**
* Set the 'next node pointer' of a node
* @param ll_p pointer to linked list
* @param act pointer to a node which next node pointer should be set
* @param next pointer to a node which should be the next node before 'act'
*/
2017-11-24 17:48:47 +01:00
static void node_set_next(lv_ll_t * ll_p, lv_ll_node_t* act, lv_ll_node_t* next)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
memcpy(act + LL_NEXT_P_OFFSET(ll_p), &next, sizeof(lv_ll_node_t*));
2017-11-23 20:42:14 +01:00
}