Skip to content
Snippets Groups Projects
Commit 9cf27242 authored by solsta's avatar solsta
Browse files

Added pmemobj_list.h

parent bf9731e2
No related branches found
No related tags found
No related merge requests found
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright 2016-2020, Intel Corporation */
/*
* pmemobj_list.h -- macro definitions for persistent
* singly linked list and tail queue
*/
#ifndef PMEMOBJ_LISTS_H
#define PMEMOBJ_LISTS_H
#include <libpmemobj.h>
/*
* This file defines two types of persistent data structures:
* singly-linked lists and tail queue.
*
* All macros defined in this file must be used within libpmemobj
* transactional API. Following snippet presents example of usage:
*
* TX_BEGIN(pop) {
* POBJ_TAILQ_INIT(head);
* } TX_ONABORT {
* abort();
* } TX_END
*
* SLIST TAILQ
* _HEAD + +
* _ENTRY + +
* _INIT + +
* _EMPTY + +
* _FIRST + +
* _NEXT + +
* _PREV - +
* _LAST - +
* _FOREACH + +
* _FOREACH_REVERSE - +
* _INSERT_HEAD + +
* _INSERT_BEFORE - +
* _INSERT_AFTER + +
* _INSERT_TAIL - +
* _MOVE_ELEMENT_HEAD - +
* _MOVE_ELEMENT_TAIL - +
* _REMOVE_HEAD + -
* _REMOVE + +
* _REMOVE_FREE + +
* _SWAP_HEAD_TAIL - +
*/
/*
* Singly-linked List definitions.
*/
#define POBJ_SLIST_HEAD(name, type)\
struct name {\
TOID(type) pe_first;\
}
#define POBJ_SLIST_ENTRY(type)\
struct {\
TOID(type) pe_next;\
}
/*
* Singly-linked List access methods.
*/
#define POBJ_SLIST_EMPTY(head) (TOID_IS_NULL((head)->pe_first))
#define POBJ_SLIST_FIRST(head) ((head)->pe_first)
#define POBJ_SLIST_NEXT(elm, field) (D_RO(elm)->field.pe_next)
/*
* Singly-linked List functions.
*/
#define POBJ_SLIST_INIT(head) do {\
TX_ADD_DIRECT(&(head)->pe_first);\
TOID_ASSIGN((head)->pe_first, OID_NULL);\
} while (0)
#define POBJ_SLIST_INSERT_HEAD(head, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
TX_ADD_DIRECT(&elm_ptr->field.pe_next);\
elm_ptr->field.pe_next = (head)->pe_first;\
TX_SET_DIRECT(head, pe_first, elm);\
} while (0)
#define POBJ_SLIST_INSERT_AFTER(slistelm, elm, field) do {\
TOID_TYPEOF(slistelm) *slistelm_ptr = D_RW(slistelm);\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
TX_ADD_DIRECT(&elm_ptr->field.pe_next);\
elm_ptr->field.pe_next = slistelm_ptr->field.pe_next;\
TX_ADD_DIRECT(&slistelm_ptr->field.pe_next);\
slistelm_ptr->field.pe_next = elm;\
} while (0)
#define POBJ_SLIST_REMOVE_HEAD(head, field) do {\
TX_ADD_DIRECT(&(head)->pe_first);\
(head)->pe_first = D_RO((head)->pe_first)->field.pe_next;\
} while (0)
#define POBJ_SLIST_REMOVE(head, elm, field) do {\
if (TOID_EQUALS((head)->pe_first, elm)) {\
POBJ_SLIST_REMOVE_HEAD(head, field);\
} else {\
TOID_TYPEOF(elm) *curelm_ptr = D_RW((head)->pe_first);\
while (!TOID_EQUALS(curelm_ptr->field.pe_next, elm))\
curelm_ptr = D_RW(curelm_ptr->field.pe_next);\
TX_ADD_DIRECT(&curelm_ptr->field.pe_next);\
curelm_ptr->field.pe_next = D_RO(elm)->field.pe_next;\
}\
} while (0)
#define POBJ_SLIST_REMOVE_FREE(head, elm, field) do {\
POBJ_SLIST_REMOVE(head, elm, field);\
TX_FREE(elm);\
} while (0)
#define POBJ_SLIST_FOREACH(var, head, field)\
for ((var) = POBJ_SLIST_FIRST(head);\
!TOID_IS_NULL(var);\
var = POBJ_SLIST_NEXT(var, field))
/*
* Tail-queue definitions.
*/
#define POBJ_TAILQ_ENTRY(type)\
struct {\
TOID(type) pe_next;\
TOID(type) pe_prev;\
}
#define POBJ_TAILQ_HEAD(name, type)\
struct name {\
TOID(type) pe_first;\
TOID(type) pe_last;\
}
/*
* Tail-queue access methods.
*/
#define POBJ_TAILQ_FIRST(head) ((head)->pe_first)
#define POBJ_TAILQ_LAST(head) ((head)->pe_last)
#define POBJ_TAILQ_EMPTY(head) (TOID_IS_NULL((head)->pe_first))
#define POBJ_TAILQ_NEXT(elm, field) (D_RO(elm)->field.pe_next)
#define POBJ_TAILQ_PREV(elm, field) (D_RO(elm)->field.pe_prev)
/*
* Tail-queue List internal methods.
*/
#define _POBJ_SWAP_PTR(elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
TX_ADD_DIRECT(&elm_ptr->field);\
__typeof__(elm) temp = elm_ptr->field.pe_prev;\
elm_ptr->field.pe_prev = elm_ptr->field.pe_next;\
elm_ptr->field.pe_next = temp;\
} while (0)
/*
* Tail-queue functions.
*/
#define POBJ_TAILQ_SWAP_HEAD_TAIL(head, field) do {\
__typeof__((head)->pe_first) temp = (head)->pe_first;\
TX_ADD_DIRECT(head);\
(head)->pe_first = (head)->pe_last;\
(head)->pe_last = temp;\
} while (0)
#define POBJ_TAILQ_FOREACH(var, head, field)\
for ((var) = POBJ_TAILQ_FIRST(head);\
!TOID_IS_NULL(var);\
var = POBJ_TAILQ_NEXT(var, field))
#define POBJ_TAILQ_FOREACH_REVERSE(var, head, field)\
for ((var) = POBJ_TAILQ_LAST(head);\
!TOID_IS_NULL(var);\
var = POBJ_TAILQ_PREV(var, field))
#define POBJ_TAILQ_INIT(head) do {\
TX_ADD_FIELD_DIRECT(head, pe_first);\
TOID_ASSIGN((head)->pe_first, OID_NULL);\
TX_ADD_FIELD_DIRECT(head, pe_last);\
TOID_ASSIGN((head)->pe_last, OID_NULL);\
} while (0)
#define POBJ_TAILQ_INSERT_HEAD(head, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
if (TOID_IS_NULL((head)->pe_first)) {\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_prev = (head)->pe_first;\
elm_ptr->field.pe_next = (head)->pe_first;\
TX_ADD_DIRECT(head);\
(head)->pe_first = elm;\
(head)->pe_last = elm;\
} else {\
TOID_TYPEOF(elm) *first = D_RW((head)->pe_first);\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_next = (head)->pe_first;\
elm_ptr->field.pe_prev = first->field.pe_prev;\
TX_ADD_DIRECT(&first->field.pe_prev);\
first->field.pe_prev = elm;\
TX_SET_DIRECT(head, pe_first, elm);\
}\
} while (0)
#define POBJ_TAILQ_INSERT_TAIL(head, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
if (TOID_IS_NULL((head)->pe_last)) {\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_prev = (head)->pe_last;\
elm_ptr->field.pe_next = (head)->pe_last;\
TX_ADD_DIRECT(head);\
(head)->pe_first = elm;\
(head)->pe_last = elm;\
} else {\
TOID_TYPEOF(elm) *last = D_RW((head)->pe_last);\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_prev = (head)->pe_last;\
elm_ptr->field.pe_next = last->field.pe_next;\
TX_ADD_DIRECT(&last->field.pe_next);\
last->field.pe_next = elm;\
TX_SET_DIRECT(head, pe_last, elm);\
}\
} while (0)
#define POBJ_TAILQ_INSERT_AFTER(listelm, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
TOID_TYPEOF(listelm) *listelm_ptr = D_RW(listelm);\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_prev = listelm;\
elm_ptr->field.pe_next = listelm_ptr->field.pe_next;\
if (TOID_IS_NULL(listelm_ptr->field.pe_next)) {\
TX_SET_DIRECT(head, pe_last, elm);\
} else {\
TOID_TYPEOF(elm) *next = D_RW(listelm_ptr->field.pe_next);\
TX_ADD_DIRECT(&next->field.pe_prev);\
next->field.pe_prev = elm;\
}\
TX_ADD_DIRECT(&listelm_ptr->field.pe_next);\
listelm_ptr->field.pe_next = elm;\
} while (0)
#define POBJ_TAILQ_INSERT_BEFORE(listelm, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
TOID_TYPEOF(listelm) *listelm_ptr = D_RW(listelm);\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_next = listelm;\
elm_ptr->field.pe_prev = listelm_ptr->field.pe_prev;\
if (TOID_IS_NULL(listelm_ptr->field.pe_prev)) {\
TX_SET_DIRECT(head, pe_first, elm);\
} else {\
TOID_TYPEOF(elm) *prev = D_RW(listelm_ptr->field.pe_prev);\
TX_ADD_DIRECT(&prev->field.pe_next);\
prev->field.pe_next = elm; \
}\
TX_ADD_DIRECT(&listelm_ptr->field.pe_prev);\
listelm_ptr->field.pe_prev = elm;\
} while (0)
#define POBJ_TAILQ_REMOVE(head, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
if (TOID_IS_NULL(elm_ptr->field.pe_prev) &&\
TOID_IS_NULL(elm_ptr->field.pe_next)) {\
TX_ADD_DIRECT(head);\
(head)->pe_first = elm_ptr->field.pe_prev;\
(head)->pe_last = elm_ptr->field.pe_next;\
} else {\
if (TOID_IS_NULL(elm_ptr->field.pe_prev)) {\
TX_SET_DIRECT(head, pe_first, elm_ptr->field.pe_next);\
TOID_TYPEOF(elm) *next = D_RW(elm_ptr->field.pe_next);\
TX_ADD_DIRECT(&next->field.pe_prev);\
next->field.pe_prev = elm_ptr->field.pe_prev;\
} else {\
TOID_TYPEOF(elm) *prev = D_RW(elm_ptr->field.pe_prev);\
TX_ADD_DIRECT(&prev->field.pe_next);\
prev->field.pe_next = elm_ptr->field.pe_next;\
}\
if (TOID_IS_NULL(elm_ptr->field.pe_next)) {\
TX_SET_DIRECT(head, pe_last, elm_ptr->field.pe_prev);\
TOID_TYPEOF(elm) *prev = D_RW(elm_ptr->field.pe_prev);\
TX_ADD_DIRECT(&prev->field.pe_next);\
prev->field.pe_next = elm_ptr->field.pe_next;\
} else {\
TOID_TYPEOF(elm) *next = D_RW(elm_ptr->field.pe_next);\
TX_ADD_DIRECT(&next->field.pe_prev);\
next->field.pe_prev = elm_ptr->field.pe_prev;\
}\
}\
} while (0)
#define POBJ_TAILQ_REMOVE_FREE(head, elm, field) do {\
POBJ_TAILQ_REMOVE(head, elm, field);\
TX_FREE(elm);\
} while (0)
/*
* 2 cases: only two elements, the rest possibilities
* including that elm is the last one
*/
#define POBJ_TAILQ_MOVE_ELEMENT_HEAD(head, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
if (TOID_EQUALS((head)->pe_last, elm) &&\
TOID_EQUALS(D_RO((head)->pe_first)->field.pe_next, elm)) {\
_POBJ_SWAP_PTR(elm, field);\
_POBJ_SWAP_PTR((head)->pe_first, field);\
POBJ_TAILQ_SWAP_HEAD_TAIL(head, field);\
} else {\
TOID_TYPEOF(elm) *prev = D_RW(elm_ptr->field.pe_prev);\
TX_ADD_DIRECT(&prev->field.pe_next);\
prev->field.pe_next = elm_ptr->field.pe_next;\
if (TOID_EQUALS((head)->pe_last, elm)) {\
TX_SET_DIRECT(head, pe_last, elm_ptr->field.pe_prev);\
} else {\
TOID_TYPEOF(elm) *next = D_RW(elm_ptr->field.pe_next);\
TX_ADD_DIRECT(&next->field.pe_prev);\
next->field.pe_prev = elm_ptr->field.pe_prev;\
}\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_prev = D_RO((head)->pe_first)->field.pe_prev;\
elm_ptr->field.pe_next = (head)->pe_first;\
TOID_TYPEOF(elm) *first = D_RW((head)->pe_first);\
TX_ADD_DIRECT(&first->field.pe_prev);\
first->field.pe_prev = elm;\
TX_SET_DIRECT(head, pe_first, elm);\
}\
} while (0)
#define POBJ_TAILQ_MOVE_ELEMENT_TAIL(head, elm, field) do {\
TOID_TYPEOF(elm) *elm_ptr = D_RW(elm);\
if (TOID_EQUALS((head)->pe_first, elm) &&\
TOID_EQUALS(D_RO((head)->pe_last)->field.pe_prev, elm)) {\
_POBJ_SWAP_PTR(elm, field);\
_POBJ_SWAP_PTR((head)->pe_last, field);\
POBJ_TAILQ_SWAP_HEAD_TAIL(head, field);\
} else {\
TOID_TYPEOF(elm) *next = D_RW(elm_ptr->field.pe_next);\
TX_ADD_DIRECT(&next->field.pe_prev);\
next->field.pe_prev = elm_ptr->field.pe_prev;\
if (TOID_EQUALS((head)->pe_first, elm)) {\
TX_SET_DIRECT(head, pe_first, elm_ptr->field.pe_next);\
} else { \
TOID_TYPEOF(elm) *prev = D_RW(elm_ptr->field.pe_prev);\
TX_ADD_DIRECT(&prev->field.pe_next);\
prev->field.pe_next = elm_ptr->field.pe_next;\
}\
TX_ADD_DIRECT(&elm_ptr->field);\
elm_ptr->field.pe_prev = (head)->pe_last;\
elm_ptr->field.pe_next = D_RO((head)->pe_last)->field.pe_next;\
__typeof__(elm_ptr) last = D_RW((head)->pe_last);\
TX_ADD_DIRECT(&last->field.pe_next);\
last->field.pe_next = elm;\
TX_SET_DIRECT(head, pe_last, elm);\
} \
} while (0)
#endif /* PMEMOBJ_LISTS_H */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment