% \iffalse meta-comment
%
%% File: l3clist.dtx Copyright (C) 2004-2011 Frank Mittelbach,
%%                                 The LaTeX3 project
%%                             (C) 2012 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the "l3kernel bundle" (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX3 Project.
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
\RequirePackage{l3names}
\GetIdInfo$Id: l3clist.dtx 3460 2012-02-26 12:16:41Z will $
  {L3 Experimental comma separated lists}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3clist} package\\ Comma separated lists^^A
%   \thanks{This file describes v\ExplFileVersion,
%      last revised \ExplFileDate.}^^A
% }
%
% \author{^^A
%  The \LaTeX3 Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released \ExplFileDate}
%
% \maketitle
%
% \begin{documentation}
%
% Comma lists contain ordered data where items can be added to the left
% or right end of the list. The resulting ordered list can then
% be mapped over using \cs{clist_map_function:NN}. Several items can
% be added at once, and spaces are removed from both sides of each item
% on input. Hence,
% \begin{verbatim}
%   \clist_new:N \l_my_clist
%   \clist_put_left:Nn \l_my_clist { ~ a ~ , ~ {b} ~ }
%   \clist_put_right:Nn \l_my_clist { ~ { c ~ } , d }
% \end{verbatim}
% results in \cs{l_my_clist} containing |a,{b},{c~},d|.
% Comma lists cannot contain empty items, thus
% \begin{verbatim}
%   \clist_clear_new:N \l_my_clist
%   \clist_put_right:Nn \l_my_clist { , ~ , , }
%   \clist_if_empty:NTF \l_my_clist { true } { false }
% \end{verbatim}
% will leave \texttt{true} in the input stream. To include an item
% which contains a comma, or starts or ends with a space,
% surround it with braces.
%
% \section{Creating and initialising comma lists}
%
% \begin{function}{\clist_new:N, \clist_new:c}
%   \begin{syntax}
%     \cs{clist_new:N} \meta{comma list}
%   \end{syntax}
%   Creates a new \meta{comma list} or raises an error if the name is
%   already taken. The declaration is global. The \meta{comma list} will
%   initially contain no items.
% \end{function}
%
% \begin{function}
%   {\clist_clear:N, \clist_clear:c, \clist_gclear:N, \clist_gclear:c}
%   \begin{syntax}
%     \cs{clist_clear:N} \meta{comma list}
%   \end{syntax}
%   Clears all items from the \meta{comma list}.
% \end{function}
%
% \begin{function}
%   {
%     \clist_clear_new:N,  \clist_clear_new:c,
%     \clist_gclear_new:N, \clist_gclear_new:c
%   }
%   \begin{syntax}
%     \cs{clist_clear_new:N} \meta{comma list}
%   \end{syntax}
%   Ensures that the \meta{comma list} exists globally by applying
%   \cs{clsit_new:N} if necessary, then applies \cs{clist_(g)clear:N} to leave
%   the list empty.
% \end{function}
%
% \begin{function}
%   {
%     \clist_set_eq:NN,  \clist_set_eq:cN,
%     \clist_set_eq:Nc,  \clist_set_eq:cc,
%     \clist_gset_eq:NN, \clist_gset_eq:cN,
%     \clist_gset_eq:Nc, \clist_gset_eq:cc
%   }
%   \begin{syntax}
%     \cs{clist_set_eq:NN} \meta{comma list1} \meta{comma list2}
%   \end{syntax}
%   Sets the content of \meta{comma list1} equal to that of
%   \meta{comma list2}.
% \end{function}
%
% \begin{function}
%   {
%     \clist_concat:NNN,  \clist_concat:ccc,
%     \clist_gconcat:NNN, \clist_gconcat:ccc
%   }
%   \begin{syntax}
%     \cs{clist_concat:NNN} \meta{comma list1} \meta{comma list2} \meta{comma list3}
%   \end{syntax}
%   Concatenates the content of \meta{comma list2} and \meta{comma list3}
%   together and saves the result in \meta{comma list1}. The items in
%   \meta{comma list2} will be placed at the left side of the new comma list.
% \end{function}
%
% \section{Adding data to comma lists}
%
% \begin{function}[added = 2011-09-06]
%   {
%     \clist_set:Nn,  \clist_set:NV,
%     \clist_set:No,  \clist_set:Nx,
%     \clist_set:cn,  \clist_set:cV,
%     \clist_set:co,  \clist_set:cx,
%     \clist_gset:Nn, \clist_gset:NV,
%     \clist_gset:No, \clist_gset:Nx,
%     \clist_gset:cn, \clist_gset:cV,
%     \clist_gset:co, \clist_gset:cx
%   }
%   \begin{syntax}
%     \cs{clist_set:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}|
%   \end{syntax}
%   Sets \meta{comma list} to contain the \meta{items},
%   removing any previous content from the variable.
%   Spaces are removed from both sides of each item.
% \end{function}
%
% \begin{function}[updated = 2011-09-05]
%   {
%     \clist_put_left:Nn,  \clist_put_left:NV,
%     \clist_put_left:No,  \clist_put_left:Nx,
%     \clist_put_left:cn,  \clist_put_left:cV,
%     \clist_put_left:co,  \clist_put_left:cx,
%     \clist_gput_left:Nn, \clist_gput_left:NV,
%     \clist_gput_left:No, \clist_gput_left:Nx,
%     \clist_gput_left:cn, \clist_gput_left:cV,
%     \clist_gput_left:co, \clist_gput_left:cx
%   }
%   \begin{syntax}
%     \cs{clist_put_left:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}|
%   \end{syntax}
%   Appends the \meta{items} to the left of the \meta{comma list}.
%   Spaces are removed from both sides of each item.
% \end{function}
%
% \begin{function}[updated = 2011-09-05]
%   {
%     \clist_put_right:Nn,  \clist_put_right:NV,
%     \clist_put_right:No,  \clist_put_right:Nx,
%     \clist_put_right:cn,  \clist_put_right:cV,
%     \clist_put_right:co,  \clist_put_right:cx,
%     \clist_gput_right:Nn, \clist_gput_right:NV,
%     \clist_gput_right:No, \clist_gput_right:Nx,
%     \clist_gput_right:cn, \clist_gput_right:cV,
%     \clist_gput_right:co, \clist_gput_right:cx
%   }
%   \begin{syntax}
%     \cs{clist_put_right:Nn} \meta{comma list} |{|\meta{item1},\ldots{},\meta{item$_n$}|}|
%   \end{syntax}
%   Appends the \meta{items} to the right of the \meta{comma list}.
%   Spaces are removed from both sides of each item.
% \end{function}
%
% \section{Using comma lists}
%
% \begin{function}[EXP]{\clist_use:N, \clist_use:c}
%   \begin{syntax}
%     \cs{clist_use:N} \meta{comma list}
%   \end{syntax}
%   Places the \meta{comma list} directly into the input stream,
%   including the commas, thus treating it as a \meta{token list}.
% \end{function}
%
% \section{Modifying comma lists}
%
% While comma lists are normally used as ordered lists, it may be
% necessary to modify the content. The functions here may be used
% to update comma lists, while retaining the order of the unaffected
% entries.
%
% \begin{function}
%   {
%     \clist_remove_duplicates:N,  \clist_remove_duplicates:c,
%     \clist_gremove_duplicates:N, \clist_gremove_duplicates:c
%   }
%   \begin{syntax}
%     \cs{clist_remove_duplicates:N} \meta{comma list}
%   \end{syntax}
%   Removes duplicate items from the \meta{comma list}, leaving the
%   left most copy of each item in the \meta{comma list}.  The \meta{item}
%   comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}.
%   \begin{texnote}
%     This function iterates through every item in the \meta{comma list} and
%     does a comparison with the \meta{items} already checked. It is therefore
%     relatively slow with large comma lists.
%     Furthermore, it will not work if any of the items in the
%     \meta{comma list} contains |{|, |}|, or |#|
%     (assuming the usual \TeX{} category codes apply).
%   \end{texnote}
% \end{function}
%
% \begin{function}[updated = 2011-09-06]
%   {
%     \clist_remove_all:Nn,  \clist_remove_all:cn,
%     \clist_gremove_all:Nn, \clist_gremove_all:cn
%   }
%   \begin{syntax}
%     \cs{clist_remove_all:Nn} \meta{comma list} \Arg{item}
%   \end{syntax}
%   Removes every occurrence of \meta{item} from the \meta{comma list}.
%   The \meta{item} comparison takes place on a token basis, as for
%   \cs{tl_if_eq:nn(TF)}.
%   \begin{texnote}
%     The \meta{item} may not contain |{|, |}|, or |#|
%     (assuming the usual \TeX{} category codes apply).
%   \end{texnote}
% \end{function}
%
% \section{Comma list conditionals}
%
% \begin{function}[EXP,pTF]{\clist_if_empty:N, \clist_if_empty:c}
%   \begin{syntax}
%     \cs{clist_if_empty_p:N} \meta{comma list}
%     \cs{clist_if_empty:NTF} \meta{comma list} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the \meta{comma list} is empty (containing no items).
% \end{function}
%
% \begin{function}[EXP,pTF]
%   {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc}
%   \begin{syntax}
%     \cs{clist_if_eq_p:NN} \Arg{clist_1} \Arg{clist_2}
%     \cs{clist_if_eq:NNTF} \Arg{clist_1} \Arg{clist_2} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Compares the content of two \meta{comma lists} and
%   is logically \texttt{true} if the two contain the same list of
%   entries in the same order.
% \end{function}
%
% \begin{function}[updated = 2011-09-06, TF]
%   {
%      \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No,
%      \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co,
%      \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no
%   }
%   \begin{syntax}
%     \cs{clist_if_in:NnTF} \meta{comma list} \Arg{item} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the \meta{item} is present in the \meta{comma list}.
%   In the case of an \texttt{n}-type \meta{comma list},
%   spaces are stripped from each item, but braces are not removed.
%   Hence,
%   \begin{verbatim}
%     \clist_if_in:nnTF { a , {b}~ , {b} , c } { b } {true} {false}
%   \end{verbatim}
%   yields \texttt{false}.
%   \begin{texnote}
%     The \meta{item} may not contain |{|, |}|, or |#|
%     (assuming the usual \TeX{} category codes apply),
%     and should not contain |,| nor start or end with a space.
%   \end{texnote}
% \end{function}
%
% \section{Mapping to comma lists}
%
% The functions described in this section apply a specified function
% to each item of a comma list.
%
% When the comma list is given explicitly, as an \texttt{n}-type argument,
% spaces are trimmed around each item.
% If the result of trimming spaces is empty, the item is ignored.
% Otherwise, if the item is surrounded by braces, one set is removed,
% and the result is passed to the mapped function. Thus, if your
% comma list that is being mapped is \verb*|{a , {b }, ,{}, {c},}|
% then the arguments passed to the mapped function are
% `\verb*|a|', `\verb*|{b }|', an empty argument, and `\verb*|c|'.
%
% When the comma list is given as an \texttt{N}-type argument, spaces
% have already been trimmed on input, and items are simply stripped
% of one set of braces if any. This case is more efficient than using
% \texttt{n}-type comma lists.
%
% \begin{function}[rEXP]
%   {\clist_map_function:NN, \clist_map_function:cN, \clist_map_function:nN}
%   \begin{syntax}
%     \cs{clist_map_function:NN} \meta{comma list} \meta{function}
%   \end{syntax}
%   Applies \meta{function} to every \meta{item} stored in the
%   \meta{comma list}. The \meta{function} will receive one argument for
%   each iteration. The \meta{items} are returned from left to right.
%   The function \cs{clist_map_inline:Nn} is in general more efficient
%   than \cs{clist_map_function:NN}.
%   One mapping may be nested inside another.
% \end{function}
%
% \begin{function}
%   {\clist_map_inline:Nn, \clist_map_inline:cn, \clist_map_inline:nn}
%   \begin{syntax}
%     \cs{clist_map_inline:Nn} \meta{comma list} \Arg{inline function}
%   \end{syntax}
%   Applies \meta{inline function} to every \meta{item} stored
%   within the \meta{comma list}. The \meta{inline function} should
%   consist of code which will receive the \meta{item} as |#1|.
%   One in line mapping can be nested inside another. The \meta{items}
%   are returned from left to right.
% \end{function}
%
% \begin{function}
%   {\clist_map_variable:NNn, \clist_map_variable:cNn, \clist_map_variable:nNn}
%   \begin{syntax}
%     \cs{clist_map_variable:NNn} \meta{comma list} \meta{tl~var.} \Arg{function using tl~var.}
%   \end{syntax}
%   Stores each entry in the \meta{comma list} in turn in the
%   \meta{tl~var.}\ and applies the \meta{function using tl~var.}
%   The \meta{function} will usually consist of code making use of
%   the \meta{tl~var.}, but this is not enforced.  One variable
%   mapping can be nested inside another. The \meta{items}
%   are returned from left to right.
% \end{function}
%
% \begin{function}[rEXP]{\clist_map_break:}
%   \begin{syntax}
%     \cs{clist_map_break:}
%   \end{syntax}
%   Used to terminate a \cs{clist_map_\ldots} function before all
%   entries in the \meta{comma list} have been processed. This will
%   normally take place within a conditional statement, for example
%   \begin{verbatim}
%     \clist_map_inline:Nn \l_my_clist
%       {
%         \str_if_eq:nnTF { #1 } { bingo }
%           { \clist_map_break: }
%           {
%             % Do something useful
%           }
%       }
%   \end{verbatim}
%   Use outside of a \cs{clist_map_\ldots} scenario will lead to low
%   level \TeX{} errors.
%   \begin{texnote}
%     When the mapping is broken, additional tokens may be inserted by the
%     internal macro \cs{prg_break_point:n} before further items are taken
%     from the input stream. This will depend on the design of the mapping
%     function.
%   \end{texnote}
% \end{function}
%
% \begin{function}[rEXP]{\clist_map_break:n}
%   \begin{syntax}
%     \cs{clist_map_break:n} \Arg{tokens}
%   \end{syntax}
%   Used to terminate a \cs{clist_map_\ldots} function before all
%   entries in the \meta{comma list} have been processed, inserting
%   the \meta{tokens} after the mapping has ended. This will
%   normally take place within a conditional statement, for example
%   \begin{verbatim}
%     \clist_map_inline:Nn \l_my_clist
%       {
%         \str_if_eq:nnTF { #1 } { bingo }
%           { \clist_map_break:n { <tokens> } }
%           {
%             % Do something useful
%           }
%       }
%   \end{verbatim}
%   Use outside of a \cs{clist_map_\ldots} scenario will lead to low
%   level \TeX{} errors.
%   \begin{texnote}
%     When the mapping is broken, additional tokens may be inserted by the
%     internal macro \cs{prg_break_point:n} before the \meta{tokens} are
%     inserted into the input stream.
%     This will depend on the design of the mapping function.
%   \end{texnote}
% \end{function}
%
% \section{Comma lists as stacks}
%
% Comma lists can be used as stacks, where data is pushed to and popped
% from the top of the comma list. (The left of a comma list is the top, for
% performance reasons.) The stack functions for comma lists are not
% intended to be mixed with the general ordered data functions detailed
% in the previous section: a comma list should either be used as an
% ordered data type or as a stack, but not in both ways.
%
% \begin{function}{\clist_get:NN, \clist_get:cN}
%   \begin{syntax}
%     \cs{clist_get:NN} \meta{comma list} \meta{token list variable}
%   \end{syntax}
%   Stores the left-most item from a \meta{comma list} in the
%   \meta{token list variable} without removing it from the
%   \meta{comma list}. The \meta{token list variable} is assigned locally.
% \end{function}
%
% \begin{function}{\clist_get:NN, \clist_get:cN}
%   \begin{syntax}
%     \cs{clist_get:NN} \meta{comma list} \meta{token list variable}
%   \end{syntax}
%   Stores the right-most item from a \meta{comma list} in the
%   \meta{token list variable} without removing it from the
%   \meta{comma list}. The \meta{token list variable} is assigned locally.
% \end{function}
%
% \begin{function}[updated = 2011-09-06]{\clist_pop:NN, \clist_pop:cN}
%   \begin{syntax}
%     \cs{clist_pop:NN} \meta{comma list} \meta{token list variable}
%   \end{syntax}
%   Pops the left-most item from a \meta{comma list} into the
%   \meta{token list variable}, \emph{i.e.}~removes the item from the
%   comma list and stores it in the \meta{token list variable}.
%   Both of the variables are assigned locally.
% \end{function}
%
% \begin{function}{\clist_gpop:NN, \clist_gpop:cN}
%   \begin{syntax}
%     \cs{clist_gpop:NN} \meta{comma list} \meta{token list variable}
%   \end{syntax}
%   Pops the left-most item from a \meta{comma list} into the
%   \meta{token list variable}, \emph{i.e.}~removes the item from the
%   comma list and stores it in the \meta{token list variable}.
%   The \meta{comma list} is modified globally, while the assignment of
%   the \meta{token list variable} is local.
% \end{function}
%
% \begin{function}
%   {
%     \clist_push:Nn,  \clist_push:NV,  \clist_push:No,  \clist_push:Nx,
%     \clist_push:cn,  \clist_push:cV,  \clist_push:co,  \clist_push:cx,
%     \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx,
%     \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx
%   }
%   \begin{syntax}
%     \cs{clist_push:Nn} \meta{comma list} \Arg{items}
%   \end{syntax}
%   Adds the \Arg{items} to the top of the \meta{comma list}.
%   Spaces are removed from both sides of each item.
% \end{function}
%
% \section{Viewing comma lists}
%
% \begin{function}{\clist_show:N, \clist_show:c}
%   \begin{syntax}
%     \cs{clist_show:N} \meta{comma list}
%   \end{syntax}
%   Displays the entries in the \meta{comma list} in the terminal.
% \end{function}
%
% \begin{function}{\clist_show:n}
%   \begin{syntax}
%     \cs{clist_show:n} \Arg{tokens}
%   \end{syntax}
%   Displays the entries in the comma list in the terminal.
% \end{function}
%
% \section{Scratch comma lists}
%
% \begin{variable}[added = 2011-09-06]{\l_tmpa_clist, \l_tmpb_clist}
%   Scratch comma lists for local assignment. These are never used by
%   the kernel code, and so are safe for use with any \LaTeX3-defined
%   function. However, they may be overwritten by other non-kernel
%   code and so should only be used for short-term storage.
% \end{variable}
%
% \begin{variable}[added = 2011-09-06]{\g_tmpa_clist, \g_tmpb_clist}
%   Scratch comma lists for global assignment. These are never used by
%   the kernel code, and so are safe for use with any \LaTeX3-defined
%   function. However, they may be overwritten by other non-kernel
%   code and so should only be used for short-term storage.
% \end{variable}
%
% \section{Experimental comma list functions}
%
% This section contains functions which may or may not be retained, depending
% on how useful they are found to be.
%
% \begin{function}[added = 2011-06-25, updated = 2011-09-06, EXP]
%   {\clist_length:N, \clist_length:c, \clist_length:n}
%   \begin{syntax}
%     \cs{clist_length:N} \meta{comma list}
%   \end{syntax}
%   Leaves the number of items in the \meta{comma list} in the input
%   stream as an \meta{integer denotation}. The total number of items
%   in a \meta{comma list} will include those which are duplicates,
%   \emph{i.e.}~every item in a \meta{comma list} is unique.
% \end{function}
%
% \begin{function}[updated = 2012-01-08, EXP]
%   {\clist_item:Nn, \clist_item:cn, \clist_item:nn}
%   \begin{syntax}
%     \cs{clist_item:Nn} \meta{comma list} \Arg{integer expression}
%   \end{syntax}
%   Indexing items in the \meta{comma list} from $0$ at the top (left), this
%   function will evaluate the \meta{integer expression} and leave the
%   appropriate item from the comma list in the input stream. If the
%   \meta{integer expression} is negative, indexing occurs from the
%   bottom (right) of the comma list. When the \meta{integer expression}
%   is larger than the number of items in the \meta{comma list} (as
%   calculated by \cs{clist_length:N}) then the function will expand to
%   nothing.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the \meta{item}
%     will not expand further when appearing in an x-type
%     argument expansion.
%   \end{texnote}
% \end{function}
%
% \begin{function}[updated = 2011-08-31]
%   {
%     \clist_set_from_seq:NN,  \clist_set_from_seq:cN,
%     \clist_set_from_seq:Nc,  \clist_set_from_seq:cc,
%     \clist_gset_from_seq:NN, \clist_gset_from_seq:cN,
%     \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc
%   }
%   \begin{syntax}
%     \cs{clist_set_from_seq:NN} \meta{comma list} \meta{sequence}
%   \end{syntax}
%   Sets the \meta{comma list} to be equal to the content of the
%   \meta{sequence}.
%   Items which contain either spaces or commas are surrounded by braces.
% \end{function}
%
% \begin{function}[added = 2011-11-26]
%   {
%     \clist_const:Nn, \clist_const:Nx,
%     \clist_const:cn, \clist_const:cx
%   }
%   \begin{syntax}
%     \cs{clist_const:Nn} \meta{clist~var} \Arg{comma list}
%   \end{syntax}
%   Creates a new constant \meta{clist~var} or raises an error
%   if the name is already taken. The value of the
%   \meta{clist~var} will be set globally to the
%   \meta{comma list}.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2011-12-07]{\clist_if_empty:n}
%   \begin{syntax}
%     \cs{clist_if_empty_p:n} \Arg{comma list}
%     \cs{clist_if_empty:nTF} \Arg{comma list} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the \meta{comma list} is empty (containing no items).
%   The rules for space trimming are as for other \texttt{n}-type
%   comma-list functions, hence the comma list |{~,~,,~}| (without
%   outer braces) is empty, while |{~,{},}| (without outer braces)
%   contains one element, which happens to be empty: the comma-list
%   is not empty.
% \end{function}
%
% \section{Internal comma-list functions}
%
% \begin{function}[added = 2011-07-09, rEXP]{\clist_trim_spaces:n}
%   \begin{syntax}
%     \cs{clist_trim_spaces:n} \Arg{comma list}
%   \end{syntax}
%   Removes leading and trailing spaces from each \meta{item} in the
%   \meta{comma list}, leaving the resulting modified list in the
%   input stream. This is used by the functions which add data
%   into a comma list.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3clist} implementation}
%
% \TestFiles{m3clist002}
%
%    \begin{macrocode}
%<*initex|package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
\package_check_loaded_expl:
%</package>
%    \end{macrocode}
%
% \begin{variable}{\l_clist_internal_clist}
%   Scratch space for various internal uses. This comma list variable
%   cannot be declared as such because it comes before \cs{clist_new:N}
%    \begin{macrocode}
\tl_new:N \l_clist_internal_clist
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[aux]{\clist_tmp:w}
%   A temporary function for various purposes.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_tmp:w { }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Allocation and initialisation}
%
% \begin{macro}{\clist_new:N,\clist_new:c}
% \UnitTested
%   Internally, comma lists are just token lists.
%    \begin{macrocode}
\cs_new_eq:NN \clist_new:N \tl_new:N
\cs_new_eq:NN \clist_new:c \tl_new:c
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\clist_clear:N, \clist_clear:c}
% \UnitTested
% \begin{macro}{\clist_gclear:N, \clist_gclear:c}
% \UnitTested
%   Clearing comma lists is just the same as clearing token lists.
%    \begin{macrocode}
\cs_new_eq:NN \clist_clear:N  \tl_clear:N
\cs_new_eq:NN \clist_clear:c  \tl_clear:c
\cs_new_eq:NN \clist_gclear:N \tl_gclear:N
\cs_new_eq:NN \clist_gclear:c \tl_gclear:c
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_clear_new:N, \clist_clear_new:c}
% \UnitTested
% \begin{macro}{\clist_gclear_new:N, \clist_gclear_new:c}
% \UnitTested
%   Once again a copy from the token list functions.
%    \begin{macrocode}
\cs_new_eq:NN \clist_clear_new:N  \tl_clear_new:N
\cs_new_eq:NN \clist_clear_new:c  \tl_clear_new:c
\cs_new_eq:NN \clist_gclear_new:N \tl_gclear_new:N
\cs_new_eq:NN \clist_gclear_new:c \tl_gclear_new:c
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {\clist_set_eq:NN, \clist_set_eq:cN, \clist_set_eq:Nc, \clist_set_eq:cc}
% \UnitTested
% \begin{macro}
%   {
%     \clist_gset_eq:NN, \clist_gset_eq:cN,
%     \clist_gset_eq:Nc, \clist_gset_eq:cc
%   }
% \UnitTested
%   Once again, these are simple copies from the token list functions.
%    \begin{macrocode}
\cs_new_eq:NN \clist_set_eq:NN  \tl_set_eq:NN
\cs_new_eq:NN \clist_set_eq:Nc  \tl_set_eq:Nc
\cs_new_eq:NN \clist_set_eq:cN  \tl_set_eq:cN
\cs_new_eq:NN \clist_set_eq:cc  \tl_set_eq:cc
\cs_new_eq:NN \clist_gset_eq:NN \tl_gset_eq:NN
\cs_new_eq:NN \clist_gset_eq:Nc \tl_gset_eq:Nc
\cs_new_eq:NN \clist_gset_eq:cN \tl_gset_eq:cN
\cs_new_eq:NN \clist_gset_eq:cc \tl_gset_eq:cc
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_concat:NNN, \clist_concat:ccc}
% \UnitTested
% \begin{macro}{\clist_gconcat:NNN, \clist_gconcat:ccc}
% \UnitTested
% \begin{macro}[aux]{\clist_concat_aux:NNNN}
%   Concatenating sequences is not quite as easy as it seems, as
%   there needs to be the correct addition of a comma to the output. So
%   a little work to do.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \clist_concat:NNN
  { \clist_concat_aux:NNNN \tl_set:Nx }
\cs_new_protected_nopar:Npn \clist_gconcat:NNN
  { \clist_concat_aux:NNNN \tl_gset:Nx }
\cs_new_protected:Npn \clist_concat_aux:NNNN #1#2#3#4
  {
    #1 #2
      {
        \exp_not:o #3
        \clist_if_empty:NF #3 { \clist_if_empty:NF #4 { , } }
        \exp_not:o #4
      }
  }
\cs_generate_variant:Nn \clist_concat:NNN  { ccc }
\cs_generate_variant:Nn \clist_gconcat:NNN { ccc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Removing spaces around items}
%
% \begin{macro}[int,EXP]{\clist_trim_spaces_generic:nw}
% \begin{macro}[aux]{\clist_trim_spaces_generic_aux:w}
% \begin{macro}[aux]{\clist_trim_spaces_generic_aux_ii:nn}
%   Used as `\cs{clist_trim_spaces_generic:nw} \Arg{code}
%   \cs{q_mark} \meta{item} |,|' (including the comma).
%   This expands to the \meta{code}, followed by a brace group
%   containing the \meta{item}, with leading and trailing spaces removed.
%   The calling function is responsible for inserting \cs{q_mark}
%   in front of the \meta{item}, as well as testing for the end of the list.
%   See \cs{tl_trim_spaces:n} for a partial explanation of what
%   is happening here. We changed \cs{tl_trim_spaces_aux_iv:w}
%   into \cs{clist_trim_spaces_generic_aux:w} compared to
%   \cs{tl_trim_spaces:n}, and dropped a \cs{q_mark}, which is
%   already included in the argument |##2|.
%    \begin{macrocode}
\cs_set:Npn \clist_tmp:w #1
  {
    \cs_new:Npn \clist_trim_spaces_generic:nw ##1 ##2 ,
      {
        \tl_trim_spaces_aux_i:w
        ##2
        \q_nil
        \q_mark #1 { }
        \q_mark \tl_trim_spaces_aux_ii:w
        \tl_trim_spaces_aux_iii:w
        #1 \q_nil
        \clist_trim_spaces_generic_aux:w
        \q_stop
        {##1}
      }
  }
\clist_tmp:w {~}
\cs_new:Npn \clist_trim_spaces_generic_aux:w #1 \q_nil #2 \q_stop
  { \exp_args:No \clist_trim_spaces_generic_aux_ii:nn { \use_none:n #1 } }
\cs_new:Npn \clist_trim_spaces_generic_aux_ii:nn #1 #2 { #2 {#1} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int,rEXP]{\clist_trim_spaces:n}
% \begin{macro}[aux]{\clist_trim_spaces_aux:nn}
%   The first argument of \cs{clist_trim_spaces_aux:nn} is initially empty,
%   and later a comma, namely, as soon as we have added an item to the
%   resulting list. The auxiliary tests for the end of the list,
%   and also prevents empty arguments from finding their way into the
%   output.
%    \begin{macrocode}
\cs_new:Npn \clist_trim_spaces:n #1
  {
    \clist_trim_spaces_generic:nw
      { \clist_trim_spaces_aux:nn { } }
      \q_mark #1 ,
    \q_recursion_tail, \q_recursion_stop
  }
\cs_new:Npn \clist_trim_spaces_aux:nn #1 #2
  {
    \quark_if_recursion_tail_stop:n {#2}
    \tl_if_empty:nTF {#2}
      {
        \clist_trim_spaces_generic:nw
          { \clist_trim_spaces_aux:nn {#1} } \q_mark
      }
      {
        #1 \exp_not:n {#2}
        \clist_trim_spaces_generic:nw
          { \clist_trim_spaces_aux:nn { , } } \q_mark
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Adding data to comma lists}
%
% \begin{macro}
%   {
%     \clist_set:Nn, \clist_set:NV,
%     \clist_set:No, \clist_set:Nx,
%     \clist_set:cn, \clist_set:cV,
%     \clist_set:co, \clist_set:cx
%   }
% \begin{macro}
%   {
%     \clist_gset:Nn, \clist_gset:NV,
%     \clist_gset:No, \clist_gset:Nx,
%     \clist_gset:cn, \clist_gset:cV,
%     \clist_gset:co, \clist_gset:cx
%   }
%    \begin{macrocode}
\cs_new_protected:Npn \clist_set:Nn #1#2
  { \tl_set:Nx #1 { \clist_trim_spaces:n {#2} } }
\cs_new_protected:Npn \clist_gset:Nn #1#2
  { \tl_gset:Nx #1 { \clist_trim_spaces:n {#2} } }
\cs_generate_variant:Nn \clist_set:Nn  { NV , No , Nx , c , cV , co , cx }
\cs_generate_variant:Nn \clist_gset:Nn { NV , No , Nx , c , cV , co , cx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \clist_put_left:Nn, \clist_put_left:NV,
%     \clist_put_left:No, \clist_put_left:Nx,
%     \clist_put_left:cn, \clist_put_left:cV,
%     \clist_put_left:co, \clist_put_left:cx
%   }
% \UnitTested
% \begin{macro}
%   {
%     \clist_gput_left:Nn, \clist_gput_left:NV,
%     \clist_gput_left:No, \clist_gput_left:Nx,
%     \clist_gput_left:cn, \clist_gput_left:cV,
%     \clist_gput_left:co, \clist_gput_left:cx
%   }
% \UnitTested
% \begin{macro}[aux]{\clist_put_left_aux:NNNn}
%   Comma lists cannot hold empty values: there are therefore a couple
%   of sanity checks to avoid accumulating commas.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \clist_put_left:Nn
  { \clist_put_left_aux:NNNn \clist_concat:NNN \clist_set:Nn }
\cs_new_protected_nopar:Npn \clist_gput_left:Nn
  { \clist_put_left_aux:NNNn \clist_gconcat:NNN \clist_set:Nn }
\cs_new_protected:Npn \clist_put_left_aux:NNNn #1#2#3#4
  {
    #2 \l_clist_internal_clist {#4}
    #1 #3 \l_clist_internal_clist #3
  }
\cs_generate_variant:Nn \clist_put_left:Nn  {     NV , No , Nx }
\cs_generate_variant:Nn \clist_put_left:Nn  { c , cV , co , cx }
\cs_generate_variant:Nn \clist_gput_left:Nn {     NV , No , Nx }
\cs_generate_variant:Nn \clist_gput_left:Nn { c , cV , co , cx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \clist_put_right:Nn, \clist_put_right:NV,
%     \clist_put_right:No, \clist_put_right:Nx,
%     \clist_put_right:cn, \clist_put_right:cV,
%     \clist_put_right:co, \clist_put_right:cx
%   }
% \UnitTested
% \begin{macro}
%   {
%     \clist_gput_right:Nn, \clist_gput_right:NV,
%     \clist_gput_right:No, \clist_gput_right:Nx,
%     \clist_gput_right:cn, \clist_gput_right:cV,
%     \clist_gput_right:co, \clist_gput_right:cx
%   }
% \UnitTested
% \begin{macro}[aux]{\clist_put_right_aux:NNNn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \clist_put_right:Nn
  { \clist_put_right_aux:NNNn \clist_concat:NNN \clist_set:Nn }
\cs_new_protected_nopar:Npn \clist_gput_right:Nn
  { \clist_put_right_aux:NNNn \clist_gconcat:NNN \clist_gset:Nn }
\cs_new_protected:Npn \clist_put_right_aux:NNNn #1#2#3#4
  {
    #2 \l_clist_internal_clist {#4}
    #1 #3 #3 \l_clist_internal_clist
  }
\cs_generate_variant:Nn \clist_put_right:Nn  {     NV , No , Nx }
\cs_generate_variant:Nn \clist_put_right:Nn  { c , cV , co , cx }
\cs_generate_variant:Nn \clist_gput_right:Nn {     NV , No , Nx }
\cs_generate_variant:Nn \clist_gput_right:Nn { c , cV , co , cx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Comma lists as stacks}
%
% \begin{macro}{\clist_get:NN, \clist_get:cN}
% \UnitTested
% \begin{macro}[aux]{\clist_get_aux:wN}
%   Getting an item from the left of a comma list is pretty easy: just
%   trim off the first item using the comma.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_get:NN #1#2
  { \exp_after:wN \clist_get_aux:wN #1 , \q_stop #2 }
\cs_new_protected:Npn \clist_get_aux:wN #1 , #2 \q_stop #3
  { \tl_set:Nn #3 {#1} }
\cs_generate_variant:Nn \clist_get:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_pop:NN, \clist_pop:cN}
% \UnitTested
% \begin{macro}{\clist_gpop:NN, \clist_gpop:cN}
% \UnitTested
% \begin{macro}[aux]
%   {\clist_pop_aux:NNN, \clist_pop_aux:NwNNN, \clist_pop_aux:wNN}
%   The aim here is to get the popped item as |#1| in the auxiliary, with
%   |#2| containing either the remainder of the list \emph{or} \cs{q_nil}
%   if there were insufficient items. That keeps the number of auxiliary
%   functions down.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \clist_pop:NN
  { \clist_pop_aux:NNN \tl_set:Nf }
\cs_new_protected_nopar:Npn \clist_gpop:NN
  { \clist_pop_aux:NNN \tl_gset:Nf }
\cs_new_protected:Npn \clist_pop_aux:NNN #1#2#3
  {
    \exp_after:wN \clist_pop_aux:wNNN #2 , \q_nil \q_stop #1#2#3
  }
\cs_new_protected:Npn \clist_pop_aux:wNNN #1 , #2 \q_stop #3#4#5
  {
    \tl_set:Nn #5 {#1}
    \quark_if_nil:nTF {#2}
      { #3 #4 { } }
      { #3 #4 { \clist_pop_aux:w \exp_stop_f: #2 } }
  }
\cs_new_protected:Npn \clist_pop_aux:w #1 , \q_nil {#1}
\cs_generate_variant:Nn \clist_pop:NN  { c }
\cs_generate_variant:Nn \clist_gpop:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{
%   \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx,
%   \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx
% }
% \UnitTested
% \begin{macro}{
%   \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx,
%   \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx
% }
% \UnitTested
%   Pushing to a sequence is the same as adding on the left.
%    \begin{macrocode}
\cs_new_eq:NN \clist_push:Nn  \clist_put_left:Nn
\cs_new_eq:NN \clist_push:NV  \clist_put_left:NV
\cs_new_eq:NN \clist_push:No  \clist_put_left:No
\cs_new_eq:NN \clist_push:Nx  \clist_put_left:Nx
\cs_new_eq:NN \clist_push:cn  \clist_put_left:cn
\cs_new_eq:NN \clist_push:cV  \clist_put_left:cV
\cs_new_eq:NN \clist_push:co  \clist_put_left:co
\cs_new_eq:NN \clist_push:cx  \clist_put_left:cx
\cs_new_eq:NN \clist_gpush:Nn \clist_gput_left:Nn
\cs_new_eq:NN \clist_gpush:NV \clist_gput_left:NV
\cs_new_eq:NN \clist_gpush:No \clist_gput_left:No
\cs_new_eq:NN \clist_gpush:Nx \clist_gput_left:Nx
\cs_new_eq:NN \clist_gpush:cn \clist_gput_left:cn
\cs_new_eq:NN \clist_gpush:cV \clist_gput_left:cV
\cs_new_eq:NN \clist_gpush:co \clist_gput_left:co
\cs_new_eq:NN \clist_gpush:cx \clist_gput_left:cx
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Using comma lists}
%
% \begin{macro}{\clist_use:N, \clist_use:c}
% \UnitTested
%   The approach is the same as for \cs{tl_use:N}.
%    \begin{macrocode}
\cs_new_eq:NN \clist_use:N \tl_use:N
\cs_new_eq:NN \clist_use:c \tl_use:c
%    \end{macrocode}
% \end{macro}
%
% \subsection{Modifying comma lists}
%
% \begin{variable}{\l_clist_internal_remove_clist}
%   An internal comma list for the removal routines.
%    \begin{macrocode}
\clist_new:N \l_clist_internal_remove_clist
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\clist_remove_duplicates:N, \clist_remove_duplicates:c}
% \UnitTested
% \begin{macro}{\clist_gremove_duplicates:N, \clist_gremove_duplicates:c}
% \UnitTested
% \begin{macro}[aux]{\clist_remove_duplicates_aux:NN}
%   Removing duplicates means making a new list then copying it.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_remove_duplicates:N
  { \clist_remove_duplicates_aux:NN \clist_set_eq:NN }
\cs_new_protected:Npn \clist_gremove_duplicates:N
  { \clist_remove_duplicates_aux:NN \clist_gset_eq:NN }
\cs_new_protected:Npn \clist_remove_duplicates_aux:NN #1#2
  {
    \clist_clear:N \l_clist_internal_remove_clist
    \clist_map_inline:Nn #2
      {
        \clist_if_in:NnF \l_clist_internal_remove_clist {##1}
          { \clist_put_right:Nn \l_clist_internal_remove_clist {##1} }
      }
    #1 #2 \l_clist_internal_remove_clist
  }
\cs_generate_variant:Nn \clist_remove_duplicates:N  { c }
\cs_generate_variant:Nn \clist_gremove_duplicates:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_remove_all:Nn, \clist_remove_all:cn}
% \UnitTested
% \begin{macro}{\clist_gremove_all:Nn, \clist_gremove_all:cn}
% \UnitTested
% \begin{macro}[aux]{\clist_remove_all_aux:NNn}
% \begin{macro}[aux]{\clist_remove_all_aux:w}
% \begin{macro}[aux]{\clist_remove_all_aux:}
%   The method used here is very similar to \cs{tl_replace_all:Nnn}.
%   Build a function delimited by the \meta{item} that should be removed,
%   surrounded with commas, and call that function followed by
%   the expanded comma list, and another copy of the \meta{item}.
%   The loop is controlled by the argument grabbed by
%   \cs{clist_remove_all_aux:w}: when the item was found,
%   the \cs{q_mark} delimiter used is the one inserted by
%   \cs{clist_tmp:w}, and \cs{use_none_delimit_by_q_stop:w}
%   is deleted. At the end, the final \meta{item} is
%   grabbed, and the argument of \cs{clist_tmp:w} contains
%   \cs{q_mark}: in that case, \cs{clist_remove_all_aux:w}
%   removes the second \cs{q_mark} (inserted by \cs{clist_tmp:w}),
%   and lets \cs{use_none_delimit_by_q_stop:w} act.
%
%   No brace is lost because items are always grabbed with a leading comma.
%   The result of the first assignment has an extra leading comma,
%   which we remove in a second assignment.
%   Two exceptions: if the clist lost all of its elements, the result
%   is empty, and we shouldn't remove anything; if the clist started up
%   empty, the first step happens to turn it into a single comma, and
%   the second step removes it.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_remove_all:Nn
  { \clist_remove_all_aux:NNn \tl_set:Nx }
\cs_new_protected:Npn \clist_gremove_all:Nn
  { \clist_remove_all_aux:NNn \tl_gset:Nx }
\cs_new_protected:Npn \clist_remove_all_aux:NNn #1#2#3
  {
    \cs_set:Npn \clist_tmp:w ##1 , #3 ,
      {
        ##1
        , \q_mark , \use_none_delimit_by_q_stop:w ,
        \clist_remove_all_aux:
      }
    #1 #2
      {
        \exp_after:wN \clist_remove_all_aux:
        #2 , \q_mark , #3 , \q_stop
      }
    \clist_if_empty:NF #2
      {
        #1 #2
          {
            \exp_args:No \exp_not:o
              { \exp_after:wN \use_none:n #2 }
          }
      }
  }
\cs_new:Npn \clist_remove_all_aux:
  { \exp_after:wN \clist_remove_all_aux:w \clist_tmp:w , }
\cs_new:Npn \clist_remove_all_aux:w #1 , \q_mark , #2 , { \exp_not:n {#1} }
\cs_generate_variant:Nn \clist_remove_all:Nn  { c }
\cs_generate_variant:Nn \clist_gremove_all:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Comma list conditionals}
%
% \begin{macro}[pTF]{\clist_if_empty:N, \clist_if_empty:c}
% \UnitTested
%   Simple copies from the token list variable material.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \clist_if_empty:N \tl_if_empty:N { p , T , F , TF }
\prg_new_eq_conditional:NNn \clist_if_empty:c \tl_if_empty:c { p , T , F , TF }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]
%   {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc}
% \UnitTested
%   Simple copies from the token list variable material.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \clist_if_eq:NN \tl_if_eq:NN { p , T , F , TF }
\prg_new_eq_conditional:NNn \clist_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF }
\prg_new_eq_conditional:NNn \clist_if_eq:cN \tl_if_eq:cN { p , T , F , TF }
\prg_new_eq_conditional:NNn \clist_if_eq:cc \tl_if_eq:cc { p , T , F , TF }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[TF]
%   {
%     \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No,
%     \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co,
%     \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no
%   }
% \begin{macro}[aux]{\clist_if_in_return:nn}
% \UnitTested
%   See description of the \cs{tl_if_in:Nn} function for details.
%   We simply surround the comma list, and the item, with commas.
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 { T  , F , TF }
  {
    \exp_args:No \clist_if_in_return:nn #1 {#2}
  }
\prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 { T  , F , TF }
  {
    \clist_set:Nn \l_clist_internal_clist {#1}
    \exp_args:No \clist_if_in_return:nn \l_clist_internal_clist {#2}
  }
\cs_new_protected:Npn \clist_if_in_return:nn #1#2
  {
    \cs_set:Npn \clist_tmp:w ##1 ,#2, { }
    \tl_if_empty:oTF
      { \clist_tmp:w ,#1, {} {} ,#2, }
      { \prg_return_false: } { \prg_return_true: }
  }
\cs_generate_variant:Nn \clist_if_in:NnT  {     NV , No }
\cs_generate_variant:Nn \clist_if_in:NnT  { c , cV , co }
\cs_generate_variant:Nn \clist_if_in:NnF  {     NV , No }
\cs_generate_variant:Nn \clist_if_in:NnF  { c , cV , co }
\cs_generate_variant:Nn \clist_if_in:NnTF {     NV , No }
\cs_generate_variant:Nn \clist_if_in:NnTF { c , cV , co }
\cs_generate_variant:Nn \clist_if_in:nnT  {     nV , no }
\cs_generate_variant:Nn \clist_if_in:nnF  {     nV , no }
\cs_generate_variant:Nn \clist_if_in:nnTF {     nV , no }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Mapping to comma lists}
%
% \begin{macro}{\clist_map_function:NN, \clist_map_function:cN}
% \UnitTested
% \begin{macro}[aux]{\clist_map_function_aux:Nw}
%   If the variable is empty, the mapping is skipped (otherwise,
%   that comma-list would be seen as consisting of one empty item).
%   Then loop over the comma-list, grabbing one comma-delimited
%   item at a time. The end is marked by \cs{q_recursion_tail}.
%   The auxiliary function \cs{clist_map_function_aux:Nw} is used
%   directly in \cs{clist_map_inline:Nn}. Change with care.
%    \begin{macrocode}
\cs_new:Npn \clist_map_function:NN #1#2
  {
    \clist_if_empty:NF #1
      {
        \exp_last_unbraced:NNo \clist_map_function_aux:Nw #2 #1
          , \q_recursion_tail ,
        \prg_break_point:n { }
      }
  }
\cs_new:Npn \clist_map_function_aux:Nw #1#2 ,
  {
    \quark_if_recursion_tail_break:n {#2}
    #1 {#2}
    \clist_map_function_aux:Nw #1
  }
\cs_generate_variant:Nn \clist_map_function:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_map_function:nN}
% \UnitTested
% \begin{macro}[aux]{\clist_map_function_n_aux:Nn}
% \begin{macro}{\clist_map_aux_unbrace:Nw}
%   The \texttt{n}-type mapping function is a bit more awkward,
%   since spaces mustbe trimmed from each item.
%   Space trimming is again based on \cs{clist_trim_spaces_generic:nw}.
%   The auxiliary \cs{clist_map_function_n_aux:Nn} receives
%   as arguments the function, and the result of removing leading
%   and trailing spaces from the item which lies until the next comma.
%   Empty items are ignored, then one level of braces is removed
%   by \cs{clist_map_aux_unbrace:Nw}.
%    \begin{macrocode}
\cs_new:Npn \clist_map_function:nN #1#2
  {
    \clist_trim_spaces_generic:nw { \clist_map_function_n_aux:Nn #2 }
    \q_mark #1, \q_recursion_tail,
    \prg_break_point:n { }
  }
\cs_new:Npn \clist_map_function_n_aux:Nn #1 #2
  {
    \quark_if_recursion_tail_break:n {#2}
    \tl_if_empty:nF {#2} { \clist_map_aux_unbrace:Nw #1 #2, }
    \clist_trim_spaces_generic:nw { \clist_map_function_n_aux:Nn #1 }
    \q_mark
  }
\cs_new:Npn \clist_map_aux_unbrace:Nw #1 #2, { #1 {#2} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_map_inline:Nn, \clist_map_inline:cn}
% \UnitTested
% \begin{macro}{\clist_map_inline:nn}
% \UnitTested
%   Inline mapping is done by creating a suitable function
%   \enquote{on the fly}: this is done globally to avoid
%   any issues with \TeX{}'s groups.  We use a different
%   function for each level of nesting.
%
%   Since the mapping is non-expandable,  we can perform
%   the space-trimming  needed by the \texttt{n} version
%   simply  by storing the comma-list in a variable.  We
%   don't need  a different comma-list  for each nesting
%   level: the comma-list is expanded before the mapping
%   starts.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_map_inline:Nn #1#2
  {
    \clist_if_empty:NF #1
      {
        \int_gincr:N \g_prg_map_int
        \cs_gset:cpn { clist_map_ \int_use:N \g_prg_map_int :n } ##1 {#2}
        \exp_last_unbraced:Nco \clist_map_function_aux:Nw
          { clist_map_ \int_use:N \g_prg_map_int :n }
          #1 , \q_recursion_tail ,
        \prg_break_point:n { \int_gdecr:N \g_prg_map_int }
      }
  }
\cs_new_protected:Npn \clist_map_inline:nn #1
  {
    \clist_set:Nn \l_clist_internal_clist {#1}
    \clist_map_inline:Nn \l_clist_internal_clist
  }
\cs_generate_variant:Nn \clist_map_inline:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_map_variable:NNn, \clist_map_variable:cNn}
% \UnitTested
% \begin{macro}{\clist_map_variable:nNn}
% \begin{macro}[aux]{\clist_map_variable_aux:Nnw}
%   As for other comma-list mappings, filter out the case of
%   an empty list. Same approach as \cs{clist_map_function:Nn},
%   additionally we store each item in the given variable.
%   As for inline mappings, space trimming for the \texttt{n}
%   variant is done by storing the comma list in a variable.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_map_variable:NNn #1#2#3
  {
    \clist_if_empty:NF #1
      {
        \exp_args:Nno \use:nn
          { \clist_map_variable_aux:Nnw #2 {#3} }
          #1
          , \q_recursion_tail , \q_recursion_stop
        \prg_break_point:n { }
      }
  }
\cs_new_protected:Npn \clist_map_variable:nNn #1
  {
    \clist_set:Nn \l_clist_internal_clist {#1}
    \clist_map_variable:NNn \l_clist_internal_clist
  }
\cs_new_protected:Npn \clist_map_variable_aux:Nnw #1#2#3,
  {
    \tl_set:Nn #1 {#3}
    \quark_if_recursion_tail_stop:N #1
    \use:n {#2}
    \clist_map_variable_aux:Nnw #1 {#2}
  }
\cs_generate_variant:Nn \clist_map_variable:NNn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_map_break:}
% \begin{macro}{\clist_map_break:n}
%   The break statements are simply copies.
%    \begin{macrocode}
\cs_new_eq:NN \clist_map_break:  \prg_map_break:
\cs_new_eq:NN \clist_map_break:n \prg_map_break:n
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Viewing comma lists}
%
% \begin{macro}{\clist_show:N, \clist_show:c}
% \begin{macro}{\clist_show:n}
%   Apply the general \cs{msg_aux_show:Nnx}. In the case
%   of an \texttt{n}-type comma-list, first store it
%   in a scratch variable, then show that variable,
%   omitting its name from the $4$-th argument.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_show:N #1
  {
    \msg_aux_show:Nnx
      #1
      { clist }
      { \clist_map_function:NN #1 \msg_aux_show:n }
  }
\cs_new_protected:Npn \clist_show:n #1
  {
    \clist_set:Nn \l_clist_internal_clist {#1}
    \msg_aux_show:Nnx
      \l_clist_internal_clist
      { clist }
      { \clist_map_function:NN \l_clist_internal_clist \msg_aux_show:n }
  }
\cs_generate_variant:Nn \clist_show:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Scratch comma lists}
%
% \begin{variable}{\l_tmpa_clist, \l_tmpb_clist}
% \begin{variable}{\g_tmpa_clist, \g_tmpb_clist}
%   Temporary comma list variables.
%    \begin{macrocode}
\clist_new:N \l_tmpa_clist
\clist_new:N \l_tmpb_clist
\clist_new:N \g_tmpa_clist
\clist_new:N \g_tmpb_clist
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \subsection{Experimental functions}
%
% \begin{macro}{\clist_length:N, \clist_length:c}
% \begin{macro}{\clist_length:n}
% \begin{macro}[aux]{\clist_length_aux:w}
%   Counting the items in a comma list is done using the same approach as for
%   other length functions: turn each entry into a \texttt{+1} then use
%   integer evaluation to actually do the mathematics.
%   In the case of an \texttt{n}-type comma-list, we could of course use
%   \cs{clist_map_function:nN}, but that is very slow, because it carefully
%   removes spaces. Instead, we loop manually, and skip blank items
%   (but not |{}|, hence the extra spaces).
%    \begin{macrocode}
\cs_new:Npn \clist_length:N #1
  {
    \int_eval:n
      {
        0
        \clist_map_function:NN #1 \clist_length_aux:n
      }
  }
\cs_new:Npn \clist_length_aux:n #1 { +1 }
\cs_new:Npx \clist_length:n #1
  {
    \exp_not:N \int_eval:n
      {
        0
        \exp_not:N \clist_length_n_aux:w \c_space_tl
        #1 \exp_not:n { , \q_recursion_tail , \q_recursion_stop }
      }
  }
\cs_new:Npx \clist_length_n_aux:w #1 ,
  {
    \exp_not:n { \exp_args:Nf \quark_if_recursion_tail_stop:n } {#1}
    \exp_not:N \tl_if_blank:nF {#1} { + \c_one }
    \exp_not:N \clist_length_n_aux:w \c_space_tl
  }
\cs_generate_variant:Nn \clist_length:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_item:Nn, \clist_item:cn}
% \begin{macro}[aux]{\clist_item_aux:nnNn}
% \begin{macro}[aux]{\clist_item_N_loop:nw}
%   To avoid needing to test the end of the list at each step,
%   we first compute the \meta{length} of the list. If the item number
%   is less than $-\meta{length}$ or more than $\meta{length}-1$,
%   the result is empty. If it is negative, but not less than $-\meta{length}$,
%   add the \meta{length} to the item number before performing the loop.
%   The loop itself is very simple, return the item if the counter
%   reached zero, otherwise, decrease the counter and repeat.
%    \begin{macrocode}
\cs_new:Npn \clist_item:Nn #1#2
  {
    \exp_args:Nfo \clist_item_aux:nnNn
      { \clist_length:N #1 }
      #1
      \clist_item_N_loop:nw
      {#2}
  }
\cs_new:Npn \clist_item_aux:nnNn #1#2#3#4
  {
    \int_compare:nNnTF {#4} < \c_zero
      {
        \int_compare:nNnTF {#4} < { - #1 }
          { \use_none_delimit_by_q_stop:w }
          { \exp_args:Nf #3 { \int_eval:n { #4 + #1 } } }
      }
      {
        \int_compare:nNnTF {#4} < {#1}
          { #3 {#4} }
          { \use_none_delimit_by_q_stop:w }
      }
    #2, \q_stop
  }
\cs_new:Npn \clist_item_N_loop:nw #1 #2,
  {
    \int_compare:nNnTF {#1} = \c_zero
      { \use_i_delimit_by_q_stop:nw { \exp_not:n {#2} } }
      { \exp_args:Nf \clist_item_N_loop:nw { \int_eval:n { #1 - 1 } } }
  }
\cs_generate_variant:Nn \clist_item:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_item:nn}
% \begin{macro}[aux]{
%     \clist_item_n_aux:nw,
%     \clist_item_n_loop:nw,
%     \clist_item_n_end:n,
%     \clist_item_n_strip:w}
%   This starts in the same way as \cs{clist_item:Nn} by checking the length
%   of the comma list. The final item should be space-trimmed before being
%   brace-stripped, hence we insert a couple of odd-looking
%   \cs{prg_do_nothing:} to avoid losing braces. Blank items are ignored.
%    \begin{macrocode}
\cs_new:Npn \clist_item:nn #1#2
  {
    \exp_args:Nf \clist_item_aux:nnNn
      { \clist_length:n {#1} }
      {#1}
      \clist_item_n_aux:nw
      {#2}
  }
\cs_new:Npn \clist_item_n_aux:nw #1
  { \clist_item_n_loop:nw {#1} \prg_do_nothing: }
\cs_new:Npn \clist_item_n_loop:nw #1 #2,
  {
    \exp_args:No \tl_if_blank:nTF {#2}
      { \clist_item_n_loop:nw {#1} \prg_do_nothing: }
      {
        \int_compare:nNnTF {#1} = \c_zero
          { \exp_args:No \clist_item_n_end:n {#2} }
          {
            \exp_args:Nf \clist_item_n_loop:nw
              { \int_eval:n { #1 - 1 } }
              \prg_do_nothing:
          }
      }
  }
\cs_new:Npn \clist_item_n_end:n #1 #2 \q_stop
  {
    \exp_after:wN \exp_after:wN \exp_after:wN \clist_item_n_strip:w
    \tl_trim_spaces:n {#1} ,
  }
\cs_new:Npn \clist_item_n_strip:w #1 , { \exp_not:n {#1} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \clist_set_from_seq:NN, \clist_set_from_seq:cN,
%     \clist_set_from_seq:Nc, \clist_set_from_seq:cc
%   }
% \UnitTested
% \begin{macro}
%   {
%     \clist_gset_from_seq:NN, \clist_gset_from_seq:cN,
%     \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc
%   }
% \UnitTested
% \begin{macro}[aux]{\clist_set_from_seq_aux:NNNN}
% \begin{macro}[aux]{\clist_wrap_item:n}
%   Setting a comma list from a comma-separated list is done using a simple
%   mapping. We wrap most items with \cs{exp_not:n}, and a comma. Items which
%   contain a comma or a space are surrounded by an extra set of braces. The
%   first comma must be removed, except in the case of an empty comma-list.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_set_from_seq:NN
  { \clist_set_from_seq_aux:NNNN \clist_clear:N  \tl_set:Nx  }
\cs_new_protected:Npn \clist_gset_from_seq:NN
  { \clist_set_from_seq_aux:NNNN \clist_gclear:N \tl_gset:Nx }
\cs_new_protected:Npn \clist_set_from_seq_aux:NNNN #1#2#3#4
  {
    \seq_if_empty:NTF #4
      { #1 #3 }
      {
        #2 #3
          {
            \exp_last_unbraced:Nf \use_none:n
              { \seq_map_function:NN #4 \clist_wrap_item:n }
          }
      }
  }
\cs_new:Npn \clist_wrap_item:n #1
  {
    ,
    \tl_if_empty:oTF { \clist_set_from_seq_aux:w #1 ~ , #1 ~ }
      { \exp_not:n   {#1}   }
      { \exp_not:n { {#1} } }
  }
\cs_new:Npn \clist_set_from_seq_aux:w #1 , #2 ~ { }
\cs_generate_variant:Nn \clist_set_from_seq:NN  {     Nc }
\cs_generate_variant:Nn \clist_set_from_seq:NN  { c , cc }
\cs_generate_variant:Nn \clist_gset_from_seq:NN {     Nc }
\cs_generate_variant:Nn \clist_gset_from_seq:NN { c , cc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \clist_const:Nn, \clist_const:cn,
%     \clist_const:Nx, \clist_const:cx
%   }
%   Creating and initializing a constant comma list is done in a way
%   similar to \cs{clist_set:Nn} and \cs{clist_gset:Nn}, being careful
%   to strip spaces.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_const:Nn #1#2
  { \tl_const:Nx #1 { \clist_trim_spaces:n {#2} } }
\cs_generate_variant:Nn \clist_const:Nn { c , Nx , cx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP, pTF]{\clist_if_empty:n}
% \begin{macro}[aux, EXP]{\clist_if_empty_n_aux:w}
% \begin{macro}[aux, EXP]{\clist_if_empty_n_aux:wNw}
%   As usual, we insert a token (here |?|) before grabbing
%   any argument: this avoids losing braces. The argument
%   of \cs{tl_if_empty:oTF} is empty if |#1| is |?| followed
%   by blank spaces (besides, this particular variant of
%   the emptyness test is optimized). If the item of the
%   comma list is blank, grab the next one. As soon as one
%   item is non-blank, exit: the second auxiliary will grab
%   \cs{prg_return_false:} as |#2|, unless every item in
%   the comma list was blank and the loop actually got broken
%   by the trailing |\q_mark \prg_return_false:| item.
%    \begin{macrocode}
\prg_new_conditional:Npnn \clist_if_empty:n #1 { p , T , F , TF }
  {
    \clist_if_empty_n_aux:w ? #1
    , \q_mark \prg_return_false:
    , \q_mark \prg_return_true:
    \q_stop
  }
\cs_new:Npn \clist_if_empty_n_aux:w #1 ,
  {
    \tl_if_empty:oTF { \use_none:nn #1 ? }
      { \clist_if_empty_n_aux:w ? }
      { \clist_if_empty_n_aux:wNw }
  }
\cs_new:Npn \clist_if_empty_n_aux:wNw #1 \q_mark #2#3 \q_stop {#2}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Deprecated interfaces}
%
% Deprecated on 2011-05-27, for removal by 2011-08-31.
%
% \begin{macro}{\clist_top:NN, \clist_top:cN}
% \UnitTested
%   These are old stack functions.
%    \begin{macrocode}
%<*deprecated>
\cs_new_eq:NN \clist_top:NN \clist_get:NN
\cs_new_eq:NN \clist_top:cN \clist_get:cN
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\clist_remove_element:Nn,\clist_gremove_element:Nn}
% \UnitTested
%   An older name for \cs{clist_remove_all:Nn}.
%    \begin{macrocode}
%<*deprecated>
\cs_new_eq:NN \clist_remove_element:Nn  \clist_remove_all:Nn
\cs_new_eq:NN \clist_gremove_element:Nn \clist_gremove_all:Nn
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\clist_display:N, \clist_display:c}
%   An older name for \cs{clist_show:N}.
%    \begin{macrocode}
%<*deprecated>
\cs_new_eq:NN \clist_display:N \clist_show:N
\cs_new_eq:NN \clist_display:c \clist_show:c
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
% Deprecated on 2011-09-05, for removal by 2011-12-31.
%
% \begin{macro}
%   {
%     \clist_trim_spaces:N, \clist_trim_spaces:c,
%     \clist_gtrim_spaces:N, \clist_gtrim_spaces:c
%   }
%   Since clist items are now always stripped from their surrounding
%   spaces, it is redundant to provide these functions.
%   The \cs{clist_trim_spaces:n} function is now internal,
%   deprecated for use outside the kernel.
%    \begin{macrocode}
%<*deprecated>
\cs_new_protected:Npn \clist_trim_spaces:N  #1 { \clist_set:No  #1 {#1} }
\cs_new_protected:Npn \clist_gtrim_spaces:N #1 { \clist_gset:No #1 {#1} }
\cs_generate_variant:Nn \clist_trim_spaces:N  { c }
\cs_generate_variant:Nn \clist_gtrim_spaces:N { c }
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
