<html><head></head><body>I am storing the head so that the head expression is expansion-safe. In practice, the compiler should be able to optimize it away. Likewise, it should be able to optimize the constant offset away.<br>
<br>
Point is that an iterator is unavoidable in the general case. With that in mind, I'd rather leverage the iterator to make the code as safe as possible.<br>
<br>
I already replaced goal with head to make the iteration safe against removal.<br><br><div class="gmail_quote">Le 11 juin 2018 11:11:42 GMT+03:00, Romain Vimont <rom1v@videolabs.io> a écrit :<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<pre class="k9mail">On Mon, Jun 11, 2018 at 12:15:49AM +0300, Rémi Denis-Courmont wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"> The iterator must be named so.  And if it needs a name, it must be unique. Otherwise shadowing will occur, e.g. with nested loops.<br> <br> So I cannot fathom how to avoid the iterator name parameter. The kernel also needs an explicit parameter for iterator, at least in the "safe" variants.<br></blockquote><br>It needs an additional parameter in the safe variant, but IIUC, your<br>implementation is equivalent to the unsafe one (not safe against removal<br>while iterating).<br><br>You cannot avoid naming the iterator if you use one, but I think you can<br>avoid using an iterator at all (I mean, a separate structure like<br>vlc_list_it, by using "head" as a "goal")<br><br>Something like this (inspired by the linux implementation, not heavily<br>tested and to be factorized):<br><br>    #define vlc_list_foreach(p, head, type, member) \<br>        for( p = (type *)(((char *)(head)->next) - offsetof(type, member)); \<br>             &(p)->member != (head); \<br>             p = (type *)(((char *)(p)->member.next) - offsetof(type, member)))<br><br>Is something missing with this approach?<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"> Note that the kernel list macros depend on GCC extension, notably typeof, so they are not directly applicable.<br></blockquote><br>OK for type/typeof.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"> <br> Le 10 juin 2018 23:45:53 GMT+03:00, Romain Vimont <rom1v@videolabs.io> a écrit :<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">On Sun, Jun 10, 2018 at 09:59:48PM +0300, Rémi Denis-Courmont wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> ---<br>  include/vlc_list.h | 263<br></blockquote>+++++++++++++++++++++++++++++++++++++++++++++<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;">  src/Makefile.am    |   1 +<br>  2 files changed, 264 insertions(+)<br>  create mode 100644 include/vlc_list.h<br> <br> diff --git a/include/vlc_list.h b/include/vlc_list.h<br> new file mode 100644<br> index 0000000000..0c6684c375<br> --- /dev/null<br> +++ b/include/vlc_list.h<br> @@ -0,0 +1,263 @@</blockquote><br>+/******************************************************************************<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * vlc_list.h<br> +<br></blockquote>******************************************************************************<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * Copyright © 2018 Rémi Denis-Courmont<br> + *<br> + * This program is free software; you can redistribute it and/or<br></blockquote>modify it<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * under the terms of the GNU Lesser General Public License as<br></blockquote>published by<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * the Free Software Foundation; either version 2.1 of the License,<br></blockquote>or<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * (at your option) any later version.<br> + *<br> + * This program is distributed in the hope that it will be useful,<br> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br> + * GNU Lesser General Public License for more details.<br> + *<br> + * You should have received a copy of the GNU Lesser General Public<br></blockquote>License<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * along with this program; if not, write to the Free Software<br></blockquote>Foundation,<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.<br> +<br></blockquote>*****************************************************************************/<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +<br> +#ifndef VLC_LIST_H<br> +# define VLC_LIST_H 1<br> +<br> +# include <stdbool.h><br> +# include <stddef.h><br> +<br> +/**<br> + * \defgroup list Linked lists<br> + * \ingroup cext<br> + * @{<br> + * \file<br> + * This provides convenience helpers for linked lists.<br> + */<br> +<br> +/**<br> + * Doubly-linked list node.<br> + *<br> + * This data structure provides a doubly-linked list node.<br> + * It must be embedded in each member of a list as a node proper.<br> + * It also serves as a list head in the object containing the list.<br> + */<br> +struct vlc_list<br> +{<br> +    struct vlc_list *prev;<br> +    struct vlc_list *next;<br> +};<br> +<br> +/**<br> + * Initializes an empty list head.<br> + */<br> +static inline void vlc_list_init(struct vlc_list *restrict head)<br> +{<br> +    head->prev = head;<br> +    head->next = head;<br> +}<br> +<br> +/**<br> + * Adds an element in a list.<br> + *<br> + * \note This is a common internal function. Do not call this<br></blockquote>directly.<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + */<br> +static inline void vlc_list_add_internal(struct vlc_list *restrict<br></blockquote>node,<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +                                         struct vlc_list *prev,<br> +                                         struct vlc_list *next)<br> +{<br> +    node->prev = prev;<br> +    node->next = next;<br> +    prev->next = node;<br> +    next->prev = node;<br> +}<br> +<br> +/**<br> + * Prepends an element into a list.<br> + *<br> + * \param node Node of the element to prepend to the list [OUT].<br> + * \param head Head of the list to be prepended.<br> + */<br> +static inline void vlc_list_prepend(struct vlc_list *restrict node,<br> +                                    struct vlc_list *head)<br> +{<br> +    vlc_list_add_internal(node, head, head->next);<br> +}<br> +<br> +/**<br> + * Appends an element into a list.<br> + *<br> + * \param node Node of the element to append to the list [OUT].<br> + * \param head Head of the list to be append.<br> + */<br> +static inline void vlc_list_append(struct vlc_list *restrict node,<br> +                                   struct vlc_list *head)<br> +{<br> +    vlc_list_add_internal(node, head->prev, head);<br> +}<br> +<br> +/**<br> + * Removes an element from a list.<br> + *<br> + * \param node Node of the element to remove from a list.<br> + * \warning The element must be inside a list.<br> + * Otherwise the behaviour is undefined.<br> + */<br> +static inline void vlc_list_remove(struct vlc_list *restrict node)<br> +{<br> +    struct vlc_list *prev = node->prev;<br> +    struct vlc_list *next = node->next;<br> +<br> +    prev->next = next;<br> +    next->prev = prev;<br> +}<br> +<br> +/**<br> + * Checks if a list is empty.<br> + *<br> + * \param head Head of the list to be checked [IN].<br> + *<br> + * \retval false The list is not empty.<br> + * \retval true The list is empty.<br> + *<br> + * \note Obviously the list must have been initialized.<br> + * Otherwise, the behaviour is undefined.<br> + */<br> +static inline bool vlc_list_is_empty(const struct vlc_list *head)<br> +{<br> +    return head->next == head;<br> +}<br> +<br> +/**<br> + * Checks if an element is first in a list.<br> + *<br> + * \param node List node of the element [IN].<br> + * \param head Head of the list to be checked [IN].<br> + *<br> + * \retval false The element is not first (or is in another list).<br> + * \retval true The element is first.<br> + */<br> +static inline bool vlc_list_is_first(const struct vlc_list *node,<br> +                                    const struct vlc_list *head)<br> +{<br> +    return node->prev == head;<br> +}<br> +<br> +/**<br> + * Checks if an element is last in a list.<br> + *<br> + * \param node List node of the element [IN].<br> + * \param head Head of the list to be checked [IN].<br> + *<br> + * \retval false The element is not last (or is in another list).<br> + * \retval true The element is last.<br> + */<br> +static inline bool vlc_list_is_last(const struct vlc_list *node,<br> +                                    const struct vlc_list *head)<br> +{<br> +    return node->next == head;<br> +}<br> +<br> +/**<br> + * List iterator.<br> + */<br> +struct vlc_list_it<br> +{<br> +    struct vlc_list *goal;<br> +    struct vlc_list *next;<br> +    ptrdiff_t node_offset;<br> +};<br> +<br> +static inline void *vlc_list_it_start(struct vlc_list_it *restrict<br></blockquote>it,<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +                                      struct vlc_list *head, size_t<br></blockquote>offset)<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +{<br> +    struct vlc_list *first = head->next;<br> +<br> +    it->goal = first;<br> +    it->next = first->next;<br> +    it->node_offset = -offset;<br> +    return ((char *)first) + it->node_offset;<br> +}<br> +<br> +static inline bool vlc_list_it_done(const struct vlc_list_it<br></blockquote>*restrict it)<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +{<br> +    return it->next == it->goal;<br> +}<br> +<br> +static inline void *vlc_list_it_next(struct vlc_list_it *restrict<br></blockquote>it)<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +{<br> +    struct vlc_list *next = it->next;<br> +<br> +    it->next = it->next->next;<br> +    return ((char *)next) + it->node_offset;<br> +}<br> +<br> +/**<br> + * List iteration macro.<br> + *<br> + * This macro iterates over all elements (excluding the head) of a<br></blockquote>list,<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + * in order from the first to the last.<br> + *<br> + * For each iteration, it sets the cursor variable to the current<br></blockquote>element.<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + *<br> + * \param pos Cursor variable.<br> + * \param it Storage space fo list iterator internal data.<br> + * \param head Head of the list to iterate [IN].<br> + * \param type Data type of list elements.<br> + * \param member Identifier of the member of the data type<br> + *               serving as list node.<br> + * \note It it safe to delete the current item while iterating.<br> + * It is however <b>not</b> safe to delete another item.<br> + */<br> +#define vlc_list_foreach(p, it, head, type, member) \<br></blockquote><br>Couldn't it be simplified so that the caller need not provide "it" nor<br>"type"? (like list_for_each_entry() in linux)<br><br><https://elixir.bootlin.com/linux/v4.17/source/include/linux/list.h#L457><br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +    for (p = (type *)vlc_list_it_start(&(it), head, offsetof (type,<br></blockquote>member)); \<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +         !vlc_list_it_done(&(it)); \<br> +         p = (type *)vlc_list_it_next(&(it)))<br> +<br> +/**<br> + * Converts a list node pointer to an element pointer.<br> + *<br> + * \param ptr list node pointer<br> + * \param type list data element type name<br> + * \param member list node member within the data element compound<br></blockquote>type<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> + */<br> +#define vlc_list_entry(ptr, type, member) container_of(ptr, type,<br></blockquote>member)<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +<br> +static inline void *vlc_list_first_or_null(const struct vlc_list<br></blockquote>*head,<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +                                           size_t offset)<br> +{<br> +    if (vlc_list_is_empty(head))<br> +        return NULL;<br> +    return ((char *)(head->next)) - offset;<br> +}<br> +<br> +static inline void *vlc_list_last_or_null(const struct vlc_list<br></blockquote>*head,<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +                                          size_t offset)<br> +{<br> +    if (vlc_list_is_empty(head))<br> +        return NULL;<br> +    return ((char *)(head->prev)) - offset;<br> +}<br> +<br> +/**<br> + * Gets the first element.<br> + *<br> + * \param head Head of list whose last element to get [IN].<br> + *<br> + * \return the first entry in a list or NULL if empty.<br> + */<br> +#define vlc_list_first_entry_or_null(head, type, member) \<br> +        ((type *)vlc_list_first_or_null(head, offsetof (type,<br></blockquote>member)))<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +<br> +/**<br> + * Gets the last element.<br> + *<br> + * \param head Head of list whose last element to get [IN].<br> + *<br> + * \return the last entry in a list or NULL if empty.<br> + */<br> +#define vlc_list_last_entry_or_null(head, type, member) \<br> +        ((type *)vlc_list_last_or_null(head, offsetof (type,<br></blockquote>member)))<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #8ae234; padding-left: 1ex;"> +<br> +/** \todo Merging lists, splitting lists. */<br> +<br> +/** @} */<br> +<br> +#endif /* VLC_LIST_H */<br> diff --git a/src/Makefile.am b/src/Makefile.am<br> index a13a3147d0..56552deab2 100644<br> --- a/src/Makefile.am<br> +++ b/src/Makefile.am<br> @@ -60,6 +60,7 @@ pluginsinclude_HEADERS = \<br>       ../include/vlc_input_item.h \<br>         ../include/vlc_interface.h \<br>          ../include/vlc_keystore.h \<br> + ../include/vlc_list.h \<br>       ../include/vlc_md5.h \<br>        ../include/vlc_messages.h \<br>   ../include/vlc_meta.h \<br> -- <br> 2.17.1<br> <br><hr><br> vlc-devel mailing list<br> To unsubscribe or modify your subscription options:<br> <a href="https://mailman.videolan.org/listinfo/vlc-devel">https://mailman.videolan.org/listinfo/vlc-devel</a><br></blockquote><hr><br>vlc-devel mailing list<br>To unsubscribe or modify your subscription options:<br><a href="https://mailman.videolan.org/listinfo/vlc-devel">https://mailman.videolan.org/listinfo/vlc-devel</a><br></blockquote> <br> -- <br> Envoyé de mon appareil Android avec Courriel K-9 Mail. Veuillez excuser ma brièveté.<br></blockquote><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"><hr><br> vlc-devel mailing list<br> To unsubscribe or modify your subscription options:<br> <a href="https://mailman.videolan.org/listinfo/vlc-devel">https://mailman.videolan.org/listinfo/vlc-devel</a><br></blockquote><br><hr><br>vlc-devel mailing list<br>To unsubscribe or modify your subscription options:<br><a href="https://mailman.videolan.org/listinfo/vlc-devel">https://mailman.videolan.org/listinfo/vlc-devel</a></pre></blockquote></div><br>
-- <br>
Envoyé de mon appareil Android avec Courriel K-9 Mail. Veuillez excuser ma brièveté.</body></html>