|
#define | M0_TL_DESCR(name, ambient_type, link_field, link_magic_field, link_magic, head_magic) |
|
#define | m0_tlist_for(descr, head, obj) |
|
#define | m0_tlist_endfor ;(void)__tl; } while (0) |
|
#define | m0_tlist_forall(descr, var, head, ...) |
|
#define | M0_TL_DESCR_DECLARE(name, scope) scope const struct m0_tl_descr name ## _tl |
|
#define | M0_TL_DECLARE(name, scope, amb_type) |
|
#define | __AUN __attribute__((unused)) |
|
#define | M0_TL_DESCR_DEFINE(name, hname, scope, amb_type, amb_link_field, amb_magic_field, amb_magic, head_magic) |
|
#define | M0_TL_DEFINE(name, scope, amb_type) |
|
#define | m0_tl_for(name, head, obj) m0_tlist_for(& name ## _tl, head, obj) |
|
#define | m0_tl_endfor m0_tlist_endfor |
|
#define | m0_tl_teardown(name, head, obj) while (((obj) = name ## _tlist_pop(head)) != NULL) |
|
#define | m0_tl_forall(name, var, head, ...) |
|
#define | m0_tl_find(name, var, head, ...) |
|
#define | m0_tl_exists(name, var, head, ...) (!m0_tl_forall(name, var, head, !({ __VA_ARGS__ ; }))) |
|
|
static struct m0_list_link * | __link (const struct m0_tl_descr *d, const void *obj) |
|
static uint64_t | magic (const struct m0_tl_descr *d, const void *obj) |
|
static void * | amb (const struct m0_tl_descr *d, struct m0_list_link *link) |
|
M0_INTERNAL void | m0_tlist_init (const struct m0_tl_descr *d, struct m0_tl *list) |
|
M0_INTERNAL void | m0_tlist_fini (const struct m0_tl_descr *d, struct m0_tl *list) |
|
M0_INTERNAL void | m0_tlink_init (const struct m0_tl_descr *d, void *obj) |
|
M0_INTERNAL void | m0_tlink_init_at (const struct m0_tl_descr *d, void *obj, struct m0_tl *list) |
|
M0_INTERNAL void | m0_tlink_init_at_tail (const struct m0_tl_descr *d, void *obj, struct m0_tl *list) |
|
M0_INTERNAL void | m0_tlink_fini (const struct m0_tl_descr *d, void *obj) |
|
M0_INTERNAL void | m0_tlink_del_fini (const struct m0_tl_descr *d, void *obj) |
|
M0_INTERNAL bool | m0_tlist_is_empty (const struct m0_tl_descr *d, const struct m0_tl *list) |
|
M0_INTERNAL bool | m0_tlink_is_in (const struct m0_tl_descr *d, const void *obj) |
|
M0_INTERNAL bool | m0_tlist_contains (const struct m0_tl_descr *d, const struct m0_tl *list, const void *obj) |
|
M0_INTERNAL size_t | m0_tlist_length (const struct m0_tl_descr *d, const struct m0_tl *list) |
|
M0_INTERNAL void | m0_tlist_add (const struct m0_tl_descr *d, struct m0_tl *list, void *obj) |
|
M0_INTERNAL void | m0_tlist_add_tail (const struct m0_tl_descr *d, struct m0_tl *list, void *obj) |
|
M0_INTERNAL void | m0_tlist_add_after (const struct m0_tl_descr *d, void *obj, void *new) |
|
M0_INTERNAL void | m0_tlist_add_before (const struct m0_tl_descr *d, void *obj, void *new) |
|
M0_INTERNAL void | m0_tlist_del (const struct m0_tl_descr *d, void *obj) |
|
M0_INTERNAL void | m0_tlist_remove (const struct m0_tl_descr *d, void *obj) |
|
M0_INTERNAL void | m0_tlist_move (const struct m0_tl_descr *d, struct m0_tl *list, void *obj) |
|
M0_INTERNAL void | m0_tlist_move_tail (const struct m0_tl_descr *d, struct m0_tl *list, void *obj) |
|
void * | m0_tlist_head (const struct m0_tl_descr *d, const struct m0_tl *list) |
|
M0_INTERNAL void * | m0_tlist_pop (const struct m0_tl_descr *d, const struct m0_tl *list) |
|
M0_INTERNAL void * | m0_tlist_tail (const struct m0_tl_descr *d, const struct m0_tl *list) |
|
void * | m0_tlist_next (const struct m0_tl_descr *d, const struct m0_tl *list, const void *obj) |
|
M0_INTERNAL void * | m0_tlist_prev (const struct m0_tl_descr *d, const struct m0_tl *list, const void *obj) |
|
M0_INTERNAL bool | m0_tlist_invariant (const struct m0_tl_descr *d, const struct m0_tl *list) |
|
M0_INTERNAL bool | m0_tlist_invariant_ext (const struct m0_tl_descr *d, const struct m0_tl *list, bool(*check)(const void *, void *), void *datum) |
|
M0_INTERNAL bool | m0_tlink_invariant (const struct m0_tl_descr *d, const void *obj) |
|
struct m0_tl_descr | M0_XCA_DOMAIN (be) |
|
Typed list module provides a double-linked list implementation that eliminates some chores and sources of errors typical for the "raw" m0_list interface.
Typed list is implemented on top of m0_list and adds the following features:
- a "list descriptor" (m0_tl_descr) object holding information about this
list type, including its human readable name;
- "magic" numbers embedded in list header and list links and checked by
the code to catch corruptions;
- automatic conversion to and from list links and ambient objects they
are embedded to, obviating the need in container_of() and
m0_list_entry() calls. In fact, links (m0_tlink) are not mentioned in
tlist interface at all;
- gdb (7.0) pretty-printer for lists (not yet implemented).
tlist is a safe and more convenient alternative to m0_list. As a general rule, m0_list should be used only when performance is critical or some flexibility beyond what tlist provides (e.g., a cyclic list without a head object) is necessary.
Similarly to m0_list, tlist is a purely algorithmic module: it deals with neither concurrency nor liveness nor with any similar issues that its callers are supposed to handle.
To describe a typical tlist usage pattern, suppose that one wants a list of objects of type foo hanging off every object of type bar.
First, two things have to be done:
- "list link" has to be embedded in foo:
- then, a "list head" has to be embedded in bar:
- now, define a tlist type:
.td_head_magic = 0x666f6f6261726865
};
This defines the simplest form of tlist without magic checking in list links (the magic embedded in a list head is checked anyway). To add magic checking, place a magic field in foo:
...
...
};
...
.td_link_magic = 0x666f6f6261726c69
};
Magic field can be shared by multiple tlist links embedded in the same object and can be used for other sanity checking. An "outermost" finaliser function must clear the magic as its last step to catch use-after-fini errors.
Now, one can populate and manipulate foo-bar lists:
M0_ASSERT(m0_tl_contains(&foobar_list, &
B.b_list, &
F));
- Note
- Differently from m0_list, tlist heads and links must be initialised before use, even when first usage overwrites the entity completely. This allows stronger checking in tlist manipulation functions.
Type-safe macros.
M0_TL_DESCR_DECLARE(), M0_TL_DECLARE(), M0_TL_DESCR_DEFINE() and M0_TL_DEFINE() macros generate versions of tlist interface tailored for a particular use case.
4 separate macros are necessary for flexibility. They should be used in exactly one of the following ways for any given typed list:
- static tlist, used in a single module only: M0_TL_DEFINE() and
M0_TL_DESCR_DEFINE() with scope "static" in the module .c file;
- tlist exported from a module: M0_TL_DEFINE() and M0_TL_DESCR_DEFINE()
with scope "" in .c file and M0_TL_DESCR_DECLARE(), M0_TL_DECLARE()
with scope "extern" in .h file;
- tlist exported from a module as a collection of inline functions:
M0_TL_DESCR_DEFINE() in .c file and M0_TL_DESCR_DECLARE() with scope
"extern" followed by M0_TL_DEFINE() with scope "static inline" in .h
file.
Use m0_tl_for() and m0_tl_endfor() to iterate over lists generated by M0_TL_DECLARE() and M0_TL_DEFINE().
◆ __AUN
◆ M0_TL_DECLARE
#define M0_TL_DECLARE |
( |
|
name, |
|
|
|
scope, |
|
|
|
amb_type |
|
) |
| |
Declares a version of tlist interface with definitions adjusted to take parameters of a specified ambient type (rather than void) and to hide m0_tl_descr from signatures.
declares
static void foo_tlist_init(
struct m0_tl *
head);
static void foo_tlink_init(
struct foo *
amb);
static struct foo *foo_tlist_head(
const struct m0_tl *
list);
&c.
- See also
- M0_TL_DEFINE()
-
M0_TL_DESCR_DEFINE()
Definition at line 495 of file tlist.h.
◆ M0_TL_DEFINE
#define M0_TL_DEFINE |
( |
|
name, |
|
|
|
scope, |
|
|
|
amb_type |
|
) |
| |
Defines functions declared by M0_TL_DECLARE().
The definitions generated assume that tlist descriptor, defined by M0_TL_DESC_DEFINED() is in scope.
Definition at line 550 of file tlist.h.
◆ M0_TL_DESCR
#define M0_TL_DESCR |
( |
|
name, |
|
|
|
ambient_type, |
|
|
|
link_field, |
|
|
|
link_magic_field, |
|
|
|
link_magic, |
|
|
|
head_magic |
|
) |
| |
Value:{ \
.td_link_offset =
offsetof(ambient_type, link_field), \
.td_link_magic_offset =
offsetof(ambient_type, link_magic_field), \
.td_link_magic = link_magic, \
.td_head_magic = head_magic, \
.td_container_size = sizeof(ambient_type) \
uint64_t))
#define M0_FIELD_VALUE(type, field)
#define M0_HAS_TYPE(expr, type)
#define offsetof(typ, memb)
Definition at line 231 of file tlist.h.
◆ M0_TL_DESCR_DECLARE
◆ M0_TL_DESCR_DEFINE
#define M0_TL_DESCR_DEFINE |
( |
|
name, |
|
|
|
hname, |
|
|
|
scope, |
|
|
|
amb_type, |
|
|
|
amb_link_field, |
|
|
|
amb_magic_field, |
|
|
|
amb_magic, |
|
|
|
head_magic |
|
) |
| |
Value: amb_type, \
amb_link_field, \
amb_magic_field, \
amb_magic, \
head_magic)
#define M0_TL_DESCR(name, ambient_type, link_field, link_magic_field, link_magic, head_magic)
Defines a tlist descriptor (m0_tl_descr) for a particular ambient type.
Definition at line 535 of file tlist.h.
◆ m0_tl_endfor
◆ m0_tl_exists
Returns a disjunction (logical OR) of an expression, evaluated for each list element.
- See also
- m0_tl_forall()
Definition at line 774 of file tlist.h.
◆ m0_tl_find
#define m0_tl_find |
( |
|
name, |
|
|
|
var, |
|
|
|
head, |
|
|
|
... |
|
) |
| |
Value:({ \
if (({ __VA_ARGS__ ; })) \
break; \
var; \
})
static int head(struct m0_sm *mach)
#define m0_tl_for(name, head, obj)
Returns the list element that satisfies given condition. Returns NULL if no such element is found.
Example:
- See also
- m0_tl_forall()
Definition at line 757 of file tlist.h.
◆ m0_tl_for
◆ m0_tl_forall
#define m0_tl_forall |
( |
|
name, |
|
|
|
var, |
|
|
|
head, |
|
|
|
... |
|
) |
| |
Value:({ \
if (!({ __VA_ARGS__ ; })) \
break; \
})
static int head(struct m0_sm *mach)
#define m0_tl_for(name, head, obj)
Returns a conjunction (logical AND) of an expression evaluated for each list element.
Declares a variable named "var" of list ambient object type in a new scope and evaluates user-supplied expression (the last argument) with "var" iterated over successive list elements, while this expression returns true. Returns true iff the whole list was iterated over.
The list can be modified by the user-supplied expression.
This function is useful for invariant checking.
bool foo_invariant(
const struct foo *
f)
{
b->b_count > 0 && b->b_parent ==
f);
}
- See also
- m0_forall(), m0_tlist_forall(), m0_list_forall(), m0_list_entry_forall().
Definition at line 735 of file tlist.h.
◆ m0_tl_teardown
Empties the list, by taking the list head, assigning it to "obj" and removing it from the list, until the list is empty.
- Note
- this doesn't require terminating macro.
Definition at line 708 of file tlist.h.
◆ m0_tlist_endfor
#define m0_tlist_endfor ;(void)__tl; } while (0) |
◆ m0_tlist_for
#define m0_tlist_for |
( |
|
descr, |
|
|
|
head, |
|
|
|
obj |
|
) |
| |
Value:do { \
void *__tl; \
\
obj = __tl)
void * m0_tlist_head(const struct m0_tl_descr *d, const struct m0_tl *list)
static int head(struct m0_sm *mach)
void * m0_tlist_next(const struct m0_tl_descr *d, const struct m0_tl *list, const void *obj)
Iterates over elements of list of type , assigning them in order (from head to tail) to .
It is safe to delete the "current" object in the body of the loop or modify the portion of the list preceding the current element. It is not safe to modify the list after the current point.
m0_tlist_for() macro has a few points of technical interest:
- it introduces a scope to declare a temporary variable to hold the
pointer to a "next" list element. The undesirable result of this is
that the loop has to be terminated by the matching m0_tlist_endfor
macro, closing the hidden scope. An alternative would be to use C99
syntax for iterative statement, which allows a declaration in the
for-loop header. Unfortunately, even though C99 mode can be enforced
for compilation of linux kernel modules (by means of CFLAGS_MODULE),
the kernel doesn't compile correctly in this mode;
- "inventive" use of comma expression in the loop condition allows to
calculate next element only once and only when the current element is
not NULL.
- See also
- m0_tlist_endfor
Definition at line 435 of file tlist.h.
◆ m0_tlist_forall
#define m0_tlist_forall |
( |
|
descr, |
|
|
|
var, |
|
|
|
head, |
|
|
|
... |
|
) |
| |
◆ __link()
Returns the address of a link embedded in an ambient object.
Definition at line 281 of file tlist.c.
◆ amb()
Casts a link to its ambient object.
Definition at line 291 of file tlist.c.
◆ m0_tlink_del_fini()
M0_INTERNAL void m0_tlink_del_fini |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj |
|
) |
| |
◆ m0_tlink_fini()
M0_INTERNAL void m0_tlink_fini |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj |
|
) |
| |
◆ m0_tlink_init()
M0_INTERNAL void m0_tlink_init |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj |
|
) |
| |
◆ m0_tlink_init_at()
M0_INTERNAL void m0_tlink_init_at |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj, |
|
|
struct m0_tl * |
list |
|
) |
| |
◆ m0_tlink_init_at_tail()
M0_INTERNAL void m0_tlink_init_at_tail |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj, |
|
|
struct m0_tl * |
list |
|
) |
| |
◆ m0_tlink_invariant()
M0_INTERNAL bool m0_tlink_invariant |
( |
const struct m0_tl_descr * |
d, |
|
|
const void * |
obj |
|
) |
| |
◆ m0_tlink_is_in()
M0_INTERNAL bool m0_tlink_is_in |
( |
const struct m0_tl_descr * |
d, |
|
|
const void * |
obj |
|
) |
| |
◆ m0_tlist_add()
M0_INTERNAL void m0_tlist_add |
( |
const struct m0_tl_descr * |
d, |
|
|
struct m0_tl * |
list, |
|
|
void * |
obj |
|
) |
| |
Adds an element to the beginning of a list.
- Precondition
- !m0_tlink_is_in(d, obj)
- Postcondition
- m0_tlink_is_in(d, obj)
Definition at line 125 of file tlist.c.
◆ m0_tlist_add_after()
M0_INTERNAL void m0_tlist_add_after |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj, |
|
|
void * |
next |
|
) |
| |
Adds an element after another element of the list.
- Precondition
- !m0_tlink_is_in(d, next)
- Postcondition
- m0_tlink_is_in(d, next)
Definition at line 141 of file tlist.c.
◆ m0_tlist_add_before()
M0_INTERNAL void m0_tlist_add_before |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj, |
|
|
void * |
next |
|
) |
| |
Adds an element before another element of the list.
- Precondition
- !m0_tlink_is_in(d, next)
- Postcondition
- m0_tlink_is_in(d, next)
Definition at line 149 of file tlist.c.
◆ m0_tlist_add_tail()
M0_INTERNAL void m0_tlist_add_tail |
( |
const struct m0_tl_descr * |
d, |
|
|
struct m0_tl * |
list, |
|
|
void * |
obj |
|
) |
| |
Adds an element to the end of a list.
- Precondition
- !m0_tlink_is_in(d, obj)
- Postcondition
- m0_tlink_is_in(d, obj)
Definition at line 133 of file tlist.c.
◆ m0_tlist_contains()
M0_INTERNAL bool m0_tlist_contains |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list, |
|
|
const void * |
obj |
|
) |
| |
◆ m0_tlist_del()
M0_INTERNAL void m0_tlist_del |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj |
|
) |
| |
Deletes an element from the list.
- Precondition
- m0_tlink_is_in(d, obj)
- Postcondition
- !m0_tlink_is_in(d, obj)
Definition at line 157 of file tlist.c.
◆ m0_tlist_fini()
M0_INTERNAL void m0_tlist_fini |
( |
const struct m0_tl_descr * |
d, |
|
|
struct m0_tl * |
list |
|
) |
| |
◆ m0_tlist_head()
void * m0_tlist_head |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list |
|
) |
| |
Returns the first element of a list or NULL if the list is empty.
Definition at line 187 of file tlist.c.
◆ m0_tlist_init()
M0_INTERNAL void m0_tlist_init |
( |
const struct m0_tl_descr * |
d, |
|
|
struct m0_tl * |
list |
|
) |
| |
◆ m0_tlist_invariant()
M0_INTERNAL bool m0_tlist_invariant |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list |
|
) |
| |
◆ m0_tlist_invariant_ext()
M0_INTERNAL bool m0_tlist_invariant_ext |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list, |
|
|
bool(*)(const void *, void *) |
check, |
|
|
void * |
datum |
|
) |
| |
◆ m0_tlist_is_empty()
M0_INTERNAL bool m0_tlist_is_empty |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list |
|
) |
| |
◆ m0_tlist_length()
M0_INTERNAL size_t m0_tlist_length |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list |
|
) |
| |
◆ m0_tlist_move()
M0_INTERNAL void m0_tlist_move |
( |
const struct m0_tl_descr * |
d, |
|
|
struct m0_tl * |
list, |
|
|
void * |
obj |
|
) |
| |
Moves an element from a list to the head of (possibly the same) list.
- Precondition
- m0_tlink_is_in(d, obj)
- Postcondition
- m0_tlink_is_in(d, obj)
Definition at line 170 of file tlist.c.
◆ m0_tlist_move_tail()
M0_INTERNAL void m0_tlist_move_tail |
( |
const struct m0_tl_descr * |
d, |
|
|
struct m0_tl * |
list, |
|
|
void * |
obj |
|
) |
| |
Moves an element from a list to the tail of (possibly the same) list.
- Precondition
- m0_tlink_is_in(d, obj)
- Postcondition
- m0_tlink_is_in(d, obj)
Definition at line 179 of file tlist.c.
◆ m0_tlist_next()
void * m0_tlist_next |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list, |
|
|
const void * |
obj |
|
) |
| |
Returns the next element of a list or NULL if is the last element.
- Precondition
- m0_tlist_contains(d, list, obj)
Definition at line 218 of file tlist.c.
◆ m0_tlist_pop()
M0_INTERNAL void * m0_tlist_pop |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list |
|
) |
| |
Removes and returns the head the list or NULL.
Definition at line 197 of file tlist.c.
◆ m0_tlist_prev()
M0_INTERNAL void * m0_tlist_prev |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list, |
|
|
const void * |
obj |
|
) |
| |
Returns the previous element of a list or NULL if is the first element.
- Precondition
- m0_tlist_contains(d, list, obj)
Definition at line 227 of file tlist.c.
◆ m0_tlist_remove()
M0_INTERNAL void m0_tlist_remove |
( |
const struct m0_tl_descr * |
d, |
|
|
void * |
obj |
|
) |
| |
Deletes at element from the list, if it was there.
- Postcondition
- !m0_tlink_is_in(d, obj)
Definition at line 163 of file tlist.c.
◆ m0_tlist_tail()
M0_INTERNAL void * m0_tlist_tail |
( |
const struct m0_tl_descr * |
d, |
|
|
const struct m0_tl * |
list |
|
) |
| |
Returns the last element of a list or NULL if the list is empty.
Definition at line 207 of file tlist.c.
◆ M0_XCA_DOMAIN()
◆ magic()
static uint64_t magic |
( |
const struct m0_tl_descr * |
d, |
|
|
const void * |
obj |
|
) |
| |
|
static |
Returns the value of the magic field in an ambient object
Definition at line 286 of file tlist.c.
◆ t_head [1/2]
◆ t_head [2/2]
◆ t_link [1/2]
◆ t_link [2/2]
◆ t_magic [1/2]
Head magic. This is set to m0_tl::td_head_magic and verified by the list invariant.
Definition at line 256 of file tlist.h.
◆ t_magic [2/2]
Head magic. This is set to m0_tl::td_head_magic and verified by the list invariant.
Definition at line 296 of file tlist.h.
◆ td_container_size [1/2]
Size of the ambient object.
Definition at line 228 of file tlist.h.
◆ td_container_size [2/2]
Size of the ambient object.
Definition at line 315 of file tlist.h.
◆ td_head_magic [1/2]
◆ td_head_magic [2/2]
◆ td_link_magic [1/2]
Magic stored in an ambient object.
If this field is 0, link magic checking is disabled.
Definition at line 221 of file tlist.h.
◆ td_link_magic [2/2]
Magic stored in an ambient object.
If this field is 0, link magic checking is disabled.
Definition at line 308 of file tlist.h.
◆ td_link_magic_offset [1/2]
◆ td_link_magic_offset [2/2]
◆ td_link_offset [1/2]
Offset of list link (m0_tlink) in the ambient object.
Definition at line 208 of file tlist.h.
◆ td_link_offset [2/2]
Offset of list link (m0_tlink) in the ambient object.
Definition at line 295 of file tlist.h.
◆ td_name [1/2]
Human-readable list name, used for error messages.
Definition at line 206 of file tlist.h.
◆ td_name [2/2]
Human-readable list name, used for error messages.
Definition at line 293 of file tlist.h.