<html><head></head><body>pos is an l-value, not necessarily a variable. If you look at existing array macros usages, quite often the l-values for array and size are not variables, so I don't think we should make that assumption.<br><br><div class="gmail_quote">Le 13 juin 2018 12:45:19 GMT+03:00, Steve Lhomme <robux4@ycbcr.xyz> 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 2018-06-13 11:24 AM, Romain Vimont wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"> On Tue, Jun 12, 2018 at 09:27:04PM +0300, Rémi Denis-Courmont wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;"> ---<br>   include/vlc_list.h | 261 +++++++++++++++++++++++++++++++++++++++++++++<br>   src/Makefile.am    |   1 +<br>   2 files changed, 262 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..b334c075c2<br> --- /dev/null<br> +++ b/include/vlc_list.h<br> @@ -0,0 +1,261 @@<br> +/******************************************************************************<br> + * vlc_list.h<br> + ******************************************************************************<br> + * Copyright © 2018 Rémi Denis-Courmont<br> + *<br> + * This program is free software; you can redistribute it and/or modify it<br> + * under the terms of the GNU Lesser General Public License as published by<br> + * the Free Software Foundation; either version 2.1 of the License, or<br> + * (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 License<br> + * along with this program; if not, write to the Free Software Foundation,<br> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.<br> + *****************************************************************************/<br> +<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 directly.<br> + */<br> +static inline void vlc_list_add_internal(struct vlc_list *restrict node,<br> +                                         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> +    const struct vlc_list *head;<br> +    struct vlc_list *current;<br> +    struct vlc_list *next;<br> +};<br> +<br> +static inline<br> +struct vlc_list_it vlc_list_it_start(const struct vlc_list *head)<br> +{<br> +    struct vlc_list *first = head->next;<br> +<br> +    return (struct vlc_list_it){ head, first, first->next };<br> +}<br> +<br> +static inline bool vlc_list_it_continue(const struct vlc_list_it *restrict it)<br> +{<br> +    return it->current != it->head;<br> +}<br> +<br> +static inline void vlc_list_it_next(struct vlc_list_it *restrict it)<br> +{<br> +    struct vlc_list *next = it->next;<br> +<br> +    it->current = next;<br> +    it->next = next->next;<br> +}<br> +<br> +/**<br> + * List iteration macro.<br> + *<br> + * This macro iterates over all elements (excluding the head) of a list,<br> + * in order from the first to the last.<br> + *<br> + * For each iteration, it sets the cursor variable to the current element.<br> + *<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> +    for (struct vlc_list_it it = vlc_list_it_start(head); \<br></blockquote> I see the intention to avoid the declaration on the caller-side, but it<br> feels weird to require a parameter for which the caller should mostly<br> pass a random string (which does not conflict with any existing variable<br> name).<br></blockquote><br>Since pos is already a variable that avoids shadowing, can't we use <br>pos##some_suffix internally ? (which a proper STRINGIFY macro)<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;"><br> But I think there is no perfect solution.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;"> +         vlc_list_it_continue(&it) \<br> +          && ((p) = vlc_list_entry(it.current, type, member), true); \<br></blockquote> Nice :)<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;"> +         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 type<br> + */<br> +#define vlc_list_entry(ptr, type, member) container_of(ptr, type, member)<br></blockquote> Should include <vlc_common.h> for container_of()?<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;"> +<br> +static inline void *vlc_list_first_or_null(const struct vlc_list *head,<br> +                                           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 *head,<br> +                                          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, member)))<br> +<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, member)))<br> +<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><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>