% \iffalse meta-comment
%
%% File: l3seq.dtx
%
% Copyright (C) 1990-2026 The LaTeX 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
%
%    https://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 development version of the bundle can be found at
%
%    https://github.com/latex3/latex3
%
% for those people who are interested.
%
%<*driver>
\documentclass[full,kernel]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3seq} module\\ Sequences and stacks^^A
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released 2026-08-10}
%
% \maketitle
%
% \begin{documentation}
%
% \LaTeX3 implements a \enquote{sequence} data type, which contain
% an ordered list of entries which may contain any \meta{balanced text}.
% It is possible to map functions to sequences such that the function
% is applied to every item in the sequence.
%
% Sequences are also used to implement stack functions in \LaTeX3. This
% is achieved using a number of dedicated stack functions.
%
% \section{Creating and initializing sequences}
%
% \begin{function}{\seq_new:N, \seq_new:c}
%   \begin{syntax}
%     \cs{seq_new:N} \meta{seq~var}
%   \end{syntax}
%   Creates a new \meta{seq~var} or raises an error if the name is
%   already taken. The declaration is global. The \meta{seq~var}
%   initially contains no items.
% \end{function}
%
% \begin{function}{\seq_clear:N, \seq_clear:c, \seq_gclear:N, \seq_gclear:c}
%   \begin{syntax}
%     \cs{seq_clear:N} \meta{seq~var}
%   \end{syntax}
%   Clears all items from the \meta{seq~var}.
% \end{function}
%
% \begin{function}
%   {\seq_clear_new:N, \seq_clear_new:c, \seq_gclear_new:N, \seq_gclear_new:c}
%   \begin{syntax}
%     \cs{seq_clear_new:N} \meta{seq~var}
%   \end{syntax}
%   Ensures that the \meta{seq~var} exists globally by applying
%   \cs{seq_new:N} if necessary, then applies
%   \cs[index=seq_clear:N]{seq_(g)clear:N} to leave
%   the \meta{seq~var} empty.
% \end{function}
%
% \begin{function}
%   {
%     \seq_set_eq:NN,  \seq_set_eq:cN,  \seq_set_eq:Nc,  \seq_set_eq:cc,
%     \seq_gset_eq:NN, \seq_gset_eq:cN, \seq_gset_eq:Nc, \seq_gset_eq:cc
%   }
%   \begin{syntax}
%     \cs{seq_set_eq:NN} \meta{seq~var_1} \meta{seq~var_2}
%   \end{syntax}
%   Sets the content of \meta{seq~var_1} equal to that of
%   \meta{seq~var_2}.
% \end{function}
%
% \begin{function}[added = 2014-07-17]
%   {
%     \seq_set_from_clist:NN,  \seq_set_from_clist:cN,
%     \seq_set_from_clist:Nc,  \seq_set_from_clist:cc,
%     \seq_gset_from_clist:NN, \seq_gset_from_clist:cN,
%     \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc,
%   }
%   \begin{syntax}
%     \cs{seq_set_from_clist:NN} \meta{seq~var} \meta{clist~var}
%   \end{syntax}
%   Converts the data in the \meta{clist~var} into a \meta{seq~var}:
%   the original \meta{clist~var} is unchanged.
% \end{function}
%
% \begin{function}[added = 2014-07-17]
%   {
%     \seq_set_from_clist:Nn,  \seq_set_from_clist:cn
%     \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn
%   }
%   \begin{syntax}
%     \cs{seq_set_from_clist:Nn} \meta{seq~var} \Arg{comma-list}
%   \end{syntax}
%   The \meta{seq~var} is set to contain the items in the \meta{comma list}.
% \end{function}
%
% \begin{function}[added = 2017-11-28]
%   {\seq_const_from_clist:Nn,  \seq_const_from_clist:cn}
%   \begin{syntax}
%     \cs{seq_const_from_clist:Nn} \meta{seq~var} \Arg{comma-list}
%   \end{syntax}
%   Creates a new constant \meta{seq~var} or raises an error if the name
%   is already taken. The \meta{seq~var} is set globally to contain the
%   items in the \meta{comma list}.
% \end{function}
%
% \begin{function}[added = 2011-08-15, updated = 2012-07-02]
%   {
%     \seq_set_split:Nnn ,
%     \seq_set_split:NVn , \seq_set_split:NnV , \seq_set_split:NVV ,
%     \seq_set_split:Nne , \seq_set_split:Nee ,
%     \seq_gset_split:Nnn,
%     \seq_gset_split:NVn , \seq_gset_split:NnV, \seq_gset_split:NVV,
%     \seq_gset_split:Nne , \seq_gset_split:Nee
%   }
%   \begin{syntax}
%     \cs{seq_set_split:Nnn} \meta{seq~var} \Arg{delimiter} \Arg{token list}
%   \end{syntax}
%   Splits the \meta{token list} into \meta{items} separated
%   by \meta{delimiter}, and assigns the result to the \meta{seq~var}.
%   Spaces on both sides of each \meta{item} are ignored,
%   then one set of outer braces is removed (if any);
%   this space trimming behavior is identical to that of
%   \pkg{l3clist} functions. Empty \meta{items} are preserved by
%   \cs{seq_set_split:Nnn}, and can be removed afterwards using
%   \cs{seq_remove_all:Nn} \meta{seq~var} |{}|.
%   The \meta{delimiter} may not contain |{|, |}| or |#|
%   (assuming \TeX{}'s normal category code régime).
%   If the \meta{delimiter} is empty, the \meta{token list} is split
%   into \meta{items} as described for \cs{tl_map_function:nN}.
%   See also \cs{seq_set_split_keep_spaces:Nnn}, which omits space stripping.
% \end{function}
%
% \begin{function}[added = 2021-03-24]
%   {
%     \seq_set_split_keep_spaces:Nnn , \seq_set_split_keep_spaces:NnV ,
%     \seq_gset_split_keep_spaces:Nnn, \seq_gset_split_keep_spaces:NnV
%   }
%   \begin{syntax}
%     \cs{seq_set_split_keep_spaces:Nnn} \meta{seq~var} \Arg{delimiter} \Arg{token list}
%   \end{syntax}
%   Splits the \meta{token list} into \meta{items} separated
%   by \meta{delimiter}, and assigns the result to the \meta{seq~var}.
%   One set of outer braces is removed (if any) but any surrounding spaces
%   are retained: any braces \emph{inside} one or more spaces are
%   therefore kept. Empty \meta{items} are preserved by
%   \cs{seq_set_split_keep_spaces:Nnn}, and can be removed afterwards using
%   \cs{seq_remove_all:Nn} \meta{seq~var} |{}|.
%   The \meta{delimiter} may not contain |{|, |}| or |#|
%   (assuming \TeX{}'s normal category code régime).
%   If the \meta{delimiter} is empty, the \meta{token list} is split
%   into \meta{items} as described for \cs{tl_map_function:nN}; note in this
%   case spaces will \emph{not} be preserved.
%   See also \cs{seq_set_split:Nnn}, which removes spaces around the delimiters.
% \end{function}
%
% \begin{function}[added = 2012-06-15]
%   {\seq_set_filter:NNn, \seq_gset_filter:NNn}
%   \begin{syntax}
%     \cs{seq_set_filter:NNn} \meta{seq~var_1} \meta{seq~var_2} \Arg{inline boolexpr}
%   \end{syntax}
%   Evaluates the \meta{inline boolexpr} for every \meta{item} stored
%   within the \meta{seq~var_2}. The \meta{inline boolexpr}
%   receives the \meta{item} as |#1|. The sequence of all \meta{items}
%   for which the \meta{inline boolexpr} evaluated to \texttt{true}
%   is assigned to \meta{seq~var_1}.
%   \begin{texnote}
%     Contrarily to other mapping functions, \cs{seq_map_break:} cannot
%     be used in this function, and would lead to low-level \TeX{} errors.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2024-12-08]
%   {
%     \seq_set_regex_extract_once:Nnn, \seq_set_regex_extract_once:cnn,
%     \seq_set_regex_extract_once:NNn, \seq_set_regex_extract_once:cNn,
%     \seq_gset_regex_extract_once:Nnn, \seq_gset_regex_extract_once:cnn,
%     \seq_gset_regex_extract_once:NNn, \seq_gset_regex_extract_once:cNn,
%   }
%   \begin{syntax}
%     \cs{seq_set_regex_extract_once:Nnn} \meta{seq~var} \Arg{regex} \Arg{token list}
%     \cs{seq_set_regex_extract_once:NNn} \meta{seq~var} \meta{regex~var} \Arg{token list}
%   \end{syntax}
%   Finds the first match of the \meta{regex} in the
%   \meta{token list}. If it exists, the match is stored as the first
%   item of the \meta{seq~var}, and further items are the contents of
%   capturing groups, in the order of their opening parenthesis.
%   If there is no match, the \meta{seq~var} is cleared.
%   Theses are alternative names for \cs{regex_extract_once:nnN} and friends,
%   with arguments re-ordered for \meta{seq~var} setting;
%   see \pkg{l3regex} chapter for more details of the \meta{regex}
%   format.
% \end{function}
%
% \begin{function}[added = 2024-12-08]
%   {
%     \seq_set_regex_extract_all:Nnn, \seq_set_regex_extract_all:cnn,
%     \seq_set_regex_extract_all:NNn, \seq_set_regex_extract_all:cNn,
%     \seq_gset_regex_extract_all:Nnn, \seq_gset_regex_extract_all:cnn,
%     \seq_gset_regex_extract_all:NNn, \seq_gset_regex_extract_all:cNn,
%   }
%   \begin{syntax}
%     \cs{seq_set_regex_extract_all:Nnn} \meta{seq~var} \Arg{regex} \Arg{token list}
%     \cs{seq_set_regex_extract_all:NNn} \meta{seq~var} \meta{regex~var} \Arg{token list}
%   \end{syntax}
%   Finds all matches of the \meta{regex} in the
%   \meta{token list}, and stores all the submatch information
%   in a single sequence (concatenating the results of
%   multiple \cs{seq_set_regex_extract_all:Nnn} calls).
%   If there is no match, the \meta{seq~var} is cleared.
%   Theses are alternative names for \cs{regex_extract_all:nnN} and friends,
%   with arguments re-ordered for \meta{seq~var} setting;
%   see \pkg{l3regex} chapter for more details of the \meta{regex}
%   format.
% \end{function}
%
% \begin{function}[added = 2024-12-08]
%   {
%     \seq_set_regex_split:Nnn, \seq_set_regex_split:cnn,
%     \seq_set_regex_split:NNn, \seq_set_regex_split:cNn,
%     \seq_gset_regex_split:Nnn, \seq_gset_regex_split:cnn,
%     \seq_gset_regex_split:NNn, \seq_gset_regex_split:cNn,
%   }
%   \begin{syntax}
%     \cs{seq_set_regex_split:Nnn} \meta{seq~var} \Arg{regex} \Arg{token list}
%     \cs{seq_set_regex_split:NNn} \meta{seq~var} \meta{regex~var} \Arg{token list}
%   \end{syntax}
%   Splits the \meta{token list} into a sequence of parts, delimited by
%   matches of the \meta{regular expression}. If the \meta{regular expression}
%   has capturing groups, then the token lists that they match are stored as
%   items of the sequence as well.
%   If no match is found the resulting \meta{seq~var} has the
%   \meta{token list} as its sole item. If the \meta{regular expression}
%   matches the empty token list, then the \meta{token list} is split
%   into single tokens.
%   For example, after
%   \begin{verbatim}
%     \seq_set_regex_split:Nnn \l_path_seq { / } { the/path/for/this/file.tex }
%   \end{verbatim}
%   the sequence |\l_path_seq| contains the items |{the}|, |{path}|,
%   |{for}|, |{this}|, and |{file.tex}|.
%   Theses are alternative names for \cs{regex_split:nnN} and friends,
%   with arguments re-ordered for \meta{seq~var} setting;
%   see \pkg{l3regex} chapter for more details of the \meta{regex}
%   format.
% \end{function}
%
% \begin{function}
%   {\seq_concat:NNN, \seq_concat:ccc, \seq_gconcat:NNN, \seq_gconcat:ccc}
%   \begin{syntax}
%     \cs{seq_concat:NNN} \meta{seq~var_1} \meta{seq~var_2} \meta{seq~var_3}
%   \end{syntax}
%   Concatenates the content of \meta{seq~var_2} and \meta{seq~var_3}
%   together and saves the result in \meta{seq~var_1}. The items in
%   \meta{seq~var_2} are placed at the left side of the new sequence.
% \end{function}
%
% \begin{function}[EXP, pTF, added=2012-03-03]
%   {\seq_if_exist:N, \seq_if_exist:c}
%   \begin{syntax}
%     \cs{seq_if_exist_p:N} \meta{seq~var}
%     \cs{seq_if_exist:NTF} \meta{seq~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests whether the \meta{seq~var} is currently defined.  This does not
%   check that the \meta{seq~var} really is a sequence variable.
% \end{function}
%
% \section{Appending data to sequences}
%
% \begin{function}{
%   \seq_put_left:Nn, \seq_put_left:NV, \seq_put_left:Nv, \seq_put_left:Ne,
%   \seq_put_left:No,
%   \seq_put_left:cn, \seq_put_left:cV, \seq_put_left:cv, \seq_put_left:ce,
%   \seq_put_left:co,
%   \seq_gput_left:Nn, \seq_gput_left:NV, \seq_gput_left:Nv, \seq_gput_left:Ne,
%   \seq_gput_left:No,
%   \seq_gput_left:cn, \seq_gput_left:cV, \seq_gput_left:cv, \seq_gput_left:ce,
%   \seq_gput_left:co
% }
%   \begin{syntax}
%     \cs{seq_put_left:Nn} \meta{seq~var} \Arg{item}
%   \end{syntax}
%   Appends the \meta{item} to the left of the \meta{seq~var}.
% \end{function}
%
% \begin{function}{
%   \seq_put_right:Nn, \seq_put_right:NV, \seq_put_right:Nv, \seq_put_right:Ne,
%   \seq_put_right:No,
%   \seq_put_right:cn, \seq_put_right:cV, \seq_put_right:cv, \seq_put_right:ce,
%   \seq_put_right:co,
%   \seq_gput_right:Nn, \seq_gput_right:NV, \seq_gput_right:Nv, \seq_gput_right:Ne,
%   \seq_gput_right:No,
%   \seq_gput_right:cn, \seq_gput_right:cV, \seq_gput_right:cv, \seq_gput_right:ce,
%   \seq_gput_right:co,
% }
%   \begin{syntax}
%     \cs{seq_put_right:Nn} \meta{seq~var} \Arg{item}
%   \end{syntax}
%   Appends the \meta{item} to the right of the \meta{seq~var}.
% \end{function}
%
% \section{Recovering items from sequences}
%
% Items can be recovered from either the left or the right of sequences.
% For implementation reasons, the actions at the left of the sequence are
% faster than those acting on the right. These functions all assign the
% recovered material locally, i.e., setting the
% \meta{tl~var} used with \cs{tl_set:Nn} and \emph{never}
% \cs{tl_gset:Nn}.
%
% \begin{function}[updated = 2012-05-14]{\seq_get_left:NN, \seq_get_left:cN}
%   \begin{syntax}
%     \cs{seq_get_left:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Stores the left-most item from a \meta{seq~var} in the
%   \meta{tl~var} without removing it from the
%   \meta{seq~var}. The \meta{tl~var} is assigned locally.
%   If \meta{seq~var} is empty the \meta{tl~var}
%   is set to the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[updated = 2012-05-19]{\seq_get_right:NN, \seq_get_right:cN}
%   \begin{syntax}
%     \cs{seq_get_right:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Stores the right-most item from a \meta{seq~var} in the
%   \meta{tl~var} without removing it from the
%   \meta{seq~var}. The \meta{tl~var} is assigned locally.
%   If \meta{seq~var} is empty the \meta{tl~var}
%   is set to the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[updated = 2012-05-14]{\seq_pop_left:NN, \seq_pop_left:cN}
%   \begin{syntax}
%     \cs{seq_pop_left:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Pops the left-most item from a \meta{seq~var} into the
%   \meta{tl~var}, i.e., removes the item from the
%   sequence and stores it in the \meta{tl~var}.
%   Both of the variables are assigned locally. If \meta{seq~var} is
%   empty the \meta{tl~var} is set to
%   the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[updated = 2012-05-14]{\seq_gpop_left:NN, \seq_gpop_left:cN}
%   \begin{syntax}
%     \cs{seq_gpop_left:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Pops the left-most item from a \meta{seq~var} into the
%   \meta{tl~var}, i.e., removes the item from the
%   sequence and stores it in the \meta{tl~var}.
%   The \meta{seq~var} is modified globally, while the assignment of
%   the \meta{tl~var} is local.
%   If \meta{seq~var} is empty the \meta{tl~var} is set to
%   the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[updated = 2012-05-19]{\seq_pop_right:NN, \seq_pop_right:cN}
%   \begin{syntax}
%     \cs{seq_pop_right:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Pops the right-most item from a \meta{seq~var} into the
%   \meta{tl~var}, i.e., removes the item from the
%   sequence and stores it in the \meta{tl~var}.
%   Both of the variables are assigned locally. If \meta{seq~var} is
%   empty the \meta{tl~var} is set to
%   the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[updated = 2012-05-19]{\seq_gpop_right:NN, \seq_gpop_right:cN}
%   \begin{syntax}
%     \cs{seq_gpop_right:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Pops the right-most item from a \meta{seq~var} into the
%   \meta{tl~var}, i.e., removes the item from the
%   sequence and stores it in the \meta{tl~var}.
%   The \meta{seq~var} is modified globally, while the assignment of
%   the \meta{tl~var} is local.
%   If \meta{seq~var} is empty the \meta{tl~var} is set to
%   the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[added = 2014-07-17, EXP]
%   {
%     \seq_item:Nn, \seq_item:NV, \seq_item:Ne,
%     \seq_item:cn, \seq_item:cV, \seq_item:ce
%   }
%   \begin{syntax}
%     \cs{seq_item:Nn} \meta{seq~var} \Arg{integer expression}
%   \end{syntax}
%   Indexing items in the \meta{seq~var} from~$1$ at the top (left), this
%   function evaluates the \meta{integer expression} and leaves the
%   appropriate item from the sequence in the input stream. If the
%   \meta{integer expression} is negative, indexing occurs from the
%   bottom (right) of the sequence. If the \meta{integer expression}
%   is larger than the number of items in the \meta{seq~var} (as
%   calculated by \cs{seq_count:N}) then the function expands to
%   nothing.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the \meta{item}
%     does not expand further when appearing in an \texttt{e}-type
%     or \texttt{x}-type argument expansion.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP, added = 2016-12-06]{\seq_rand_item:N, \seq_rand_item:c}
%   \begin{syntax}
%     \cs{seq_rand_item:N} \meta{seq~var}
%   \end{syntax}
%   Selects a pseudo-random item of the \meta{seq~var}.  If the
%   \meta{seq~var} is empty the result is empty.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the \meta{item}
%     does not expand further when appearing in an \texttt{e}-type
%     or \texttt{x}-type argument expansion.
%   \end{texnote}
% \end{function}
%
% \section{Recovering values from sequences with branching}
%
% The functions in this section combine tests for non-empty sequences
% with recovery of an item from the sequence. They offer increased readability
% and performance over separate testing and recovery phases.
%
% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]
%   {\seq_get_left:NN, \seq_get_left:cN}
%   \begin{syntax}
%     \cs{seq_get_left:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, stores the left-most item from the
%   \meta{seq~var}
%   in the \meta{tl~var} without removing it from the
%   \meta{seq~var}, then leaves the \meta{true code} in the input stream.
%   The \meta{tl~var} is assigned locally.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-19]
%   {\seq_get_right:NN, \seq_get_right:cN}
%   \begin{syntax}
%     \cs{seq_get_right:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, stores the right-most item from the
%   \meta{seq~var}
%   in the \meta{tl~var} without removing it from the
%   \meta{seq~var}, then leaves the \meta{true code} in the input stream.
%   The \meta{tl~var} is assigned locally.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]
%   {\seq_pop_left:NN, \seq_pop_left:cN}
%   \begin{syntax}
%     \cs{seq_pop_left:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, pops the left-most item from the
%   \meta{seq~var}
%   in the \meta{tl~var}, i.e., removes the item from the
%   \meta{seq~var}, then leaves the \meta{true code} in the input stream.
%   Both the \meta{seq~var} and the \meta{tl~var} are assigned
%   locally.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]
%   {\seq_gpop_left:NN, \seq_gpop_left:cN}
%   \begin{syntax}
%     \cs{seq_gpop_left:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, pops the left-most item from the \meta{seq~var}
%   in the \meta{tl~var}, i.e., removes the item from the
%   \meta{seq~var}, then leaves the \meta{true code} in the input stream.
%   The \meta{seq~var} is modified globally, while the \meta{tl~var}
%   is assigned locally.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-19]
%   {\seq_pop_right:NN, \seq_pop_right:cN}
%   \begin{syntax}
%     \cs{seq_pop_right:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, pops the right-most item from the \meta{seq~var}
%   in the \meta{tl~var}, i.e., removes the item from the
%   \meta{seq~var}, then leaves the \meta{true code} in the input stream.
%   Both the \meta{seq~var} and the \meta{tl~var} are assigned
%   locally.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-19]
%   {\seq_gpop_right:NN, \seq_gpop_right:cN}
%   \begin{syntax}
%     \cs{seq_gpop_right:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, pops the right-most item from the \meta{seq~var}
%   in the \meta{tl~var}, i.e., removes the item from the
%   \meta{seq~var}, then leaves the \meta{true code} in the input stream.
%   The \meta{seq~var} is modified globally, while the
%   \meta{tl~var} is assigned locally.
% \end{function}
%
% \section{Modifying sequences}
%
%  While sequences are normally used as ordered lists, it may be
%  necessary to modify the content. The functions here may be used
%  to update sequences, while retaining the order of the unaffected
%  entries.
%
% \begin{function}
%   {
%     \seq_remove_duplicates:N,  \seq_remove_duplicates:c,
%     \seq_gremove_duplicates:N, \seq_gremove_duplicates:c
%   }
%   \begin{syntax}
%     \cs{seq_remove_duplicates:N} \meta{seq~var}
%   \end{syntax}
%   Removes duplicate items from the \meta{seq~var}, leaving the
%   left most copy of each item in the \meta{seq~var}.  The \meta{item}
%   comparison takes place on a token basis, as for \cs{tl_if_eq:nnTF}.
%   \begin{texnote}
%     This function iterates through every item in the \meta{seq~var} and
%     does a comparison with the \meta{items} already checked. It is therefore
%     relatively slow with large sequences.
%   \end{texnote}
% \end{function}
%
% \begin{function}
%   {
%     \seq_remove_all:Nn,  \seq_remove_all:NV,  \seq_remove_all:Ne, 
%     \seq_remove_all:cn,  \seq_remove_all:cV,  \seq_remove_all:ce,
%     \seq_gremove_all:Nn, \seq_gremove_all:NV, \seq_gremove_all:Ne,
%     \seq_gremove_all:cn, \seq_gremove_all:cV, \seq_gremove_all:ce
%   }
%   \begin{syntax}
%     \cs{seq_remove_all:Nn} \meta{seq~var} \Arg{item}
%   \end{syntax}
%   Removes every occurrence of \meta{item} from the \meta{seq~var}.
%   The \meta{item} comparison takes place on a token basis, as for
%   \cs{tl_if_eq:nnTF}.
% \end{function}
%
% \begin{function}[added = 2021-04-29, noTF]
%   {\seq_set_item:Nnn, \seq_set_item:cnn, \seq_gset_item:Nnn, \seq_gset_item:cnn}
%   \begin{syntax}
%     \cs{seq_set_item:Nnn} \meta{seq~var} \Arg{int expr} \Arg{item}
%     \cs{seq_set_item:NnnTF} \meta{seq~var} \Arg{int expr} \Arg{item} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Removes the item of \meta{seq~var} at the position given by
%   evaluating the \meta{int expr} and replaces it by
%   \meta{item}.  Items are indexed from $1$ on the left/top of the
%   \meta{seq~var}, or from $-1$ on the right/bottom.  If the
%   \meta{int expr} is zero or is larger (in absolute value)
%   than the number of items in the sequence, the \meta{seq~var} is not
%   modified.  In these cases, \cs{seq_set_item:Nnn} raises an error
%   while \cs{seq_set_item:NnnTF} runs the \meta{false code}.  In cases
%   where the assignment was successful, \meta{true code} is run
%   afterwards.
% \end{function}
%
% \begin{function}[added = 2014-07-18]
%   {
%     \seq_reverse:N,  \seq_reverse:c,
%     \seq_greverse:N, \seq_greverse:c
%   }
%   \begin{syntax}
%     \cs{seq_reverse:N} \meta{seq~var}
%   \end{syntax}
%   Reverses the order of the items stored in the \meta{seq~var}.
% \end{function}
%
% \begin{function}[added = 2017-02-06]
%   {\seq_sort:Nn, \seq_sort:cn, \seq_gsort:Nn, \seq_gsort:cn}
%   \begin{syntax}
%     \cs{seq_sort:Nn} \meta{seq~var} \Arg{comparison code}
%   \end{syntax}
%   Sorts the items in the \meta{seq~var} according to the
%   \meta{comparison code}, and assigns the result to
%   \meta{seq~var}. The details of sorting comparison are
%   described in Section~\ref{sec:l3sort:mech}.
% \end{function}
%
% \begin{function}[added = 2018-04-29]
%   {\seq_shuffle:N, \seq_shuffle:c, \seq_gshuffle:N, \seq_gshuffle:c}
%   \begin{syntax}
%     \cs{seq_shuffle:N} \meta{seq~var}
%   \end{syntax}
%   Sets the \meta{seq~var} to the result of placing the items of the
%   \meta{seq~var} in a random order.  Each item is (roughly) as likely
%   to end up in any given position.
%   \begin{texnote}
%     For sequences with more than $13$ items or so, only a small
%     proportion of all possible permutations can be reached, because
%     the random seed \cs{sys_rand_seed:} only has $28$-bits.  The use
%     of \tn{toks} internally means that sequences with more than
%     $32767$ or $65535$ items (depending on the engine) cannot be
%     shuffled.
%   \end{texnote}
% \end{function}
%
% \section{Sequence conditionals}
%
% \begin{function}[EXP,pTF]{\seq_if_empty:N, \seq_if_empty:c}
%   \begin{syntax}
%     \cs{seq_if_empty_p:N} \meta{seq~var}
%     \cs{seq_if_empty:NTF} \meta{seq~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the \meta{seq~var} is empty (containing no items).
% \end{function}
%
% \begin{function}[TF]
%   {
%     \seq_if_in:Nn, \seq_if_in:NV, \seq_if_in:Nv,  \seq_if_in:Ne,
%     \seq_if_in:No,
%     \seq_if_in:cn, \seq_if_in:cV, \seq_if_in:cv, \seq_if_in:ce,
%     \seq_if_in:co,
%   }
%   \begin{syntax}
%     \cs{seq_if_in:NnTF} \meta{seq~var} \Arg{item} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the \meta{item} is present in the \meta{seq~var}.
% \end{function}
%
% \section{Mapping over sequences}
%
% All mappings are done at the current group level, i.e., any
% local assignments made by the \meta{function} or \meta{code} discussed
% below remain in effect after the loop.
%
% \begin{function}[rEXP, updated = 2012-06-29]
%   {\seq_map_function:NN, \seq_map_function:cN}
%   \begin{syntax}
%     \cs{seq_map_function:NN} \meta{seq~var} \meta{function}
%   \end{syntax}
%   Applies \meta{function} to every \meta{item} stored in the
%   \meta{seq~var}. The \meta{function} will receive one argument for
%   each iteration. The \meta{items} are returned from left to right.
%   To pass further arguments to the \meta{function}, see
%   \cs{seq_map_tokens:Nn}.
%   The function \cs{seq_map_inline:Nn} is faster than
%   \cs{seq_map_function:NN} for sequences with more than about~$10$
%   items.
% \end{function}
%
% \begin{function}[updated = 2012-06-29]
%   {\seq_map_inline:Nn, \seq_map_inline:cn}
%   \begin{syntax}
%     \cs{seq_map_inline:Nn} \meta{seq~var} \Arg{inline function}
%   \end{syntax}
%   Applies \meta{inline function} to every \meta{item} stored
%   within the \meta{seq~var}. The \meta{inline function} should
%   consist of code which will receive the \meta{item} as |#1|.
%   The \meta{items} are returned from left to right.
% \end{function}
%
% \begin{function}[rEXP, added = 2019-08-30]
%   {\seq_map_tokens:Nn, \seq_map_tokens:cn}
%   \begin{syntax}
%     \cs{seq_map_tokens:Nn} \meta{seq~var} \Arg{code}
%   \end{syntax}
%   Analogue of \cs{seq_map_function:NN} which maps several tokens
%   instead of a single function.  The \meta{code} receives each item in
%   the \meta{seq~var} as a trailing brace group. For instance,
%   \begin{verbatim}
%     \seq_map_tokens:Nn \l_my_seq { \prg_replicate:nn { 2 } }
%   \end{verbatim}
%   expands to twice each item in the \meta{seq~var}: for each item in
%   |\l_my_seq| the function \cs{prg_replicate:nn} receives |2| and
%   \meta{item} as its two arguments.  The function
%   \cs{seq_map_inline:Nn} is typically faster but it is not expandable.
% \end{function}
%
% \begin{function}[updated = 2012-06-29]
%   {
%     \seq_map_variable:NNn, \seq_map_variable:Ncn,
%     \seq_map_variable:cNn, \seq_map_variable:ccn
%   }
%   \begin{syntax}
%     \cs{seq_map_variable:NNn} \meta{seq~var} \meta{variable} \Arg{code}
%   \end{syntax}
%   Stores each \meta{item} of the \meta{seq~var} in turn in the (token
%   list) \meta{variable} and applies the \meta{code}.  The \meta{code}
%   will usually make use of the \meta{variable}, but this is not
%   enforced.  The assignments to the \meta{variable} are local.  Its
%   value after the loop is the last \meta{item} in the \meta{seq~var},
%   or its original value if the \meta{seq~var} is empty.  The
%   \meta{items} are returned from left to right.
% \end{function}
%
% \begin{function}[rEXP,added = 2018-05-03]{\seq_map_indexed_function:NN}
%   \begin{syntax}
%     \cs{seq_map_indexed_function:NN} \meta{seq~var} \meta{function}
%   \end{syntax}
%   Applies \meta{function} to every entry in the \meta{seq~var}.
%   The \meta{function} should have signature |:nn|.  It
%   receives two arguments for each iteration: the \meta{index} (namely
%   |1| for the first entry, then |2| and so on) and the \meta{item}.
% \end{function}
%
% \begin{function}[added = 2018-05-03]{\seq_map_indexed_inline:Nn}
%   \begin{syntax}
%     \cs{seq_map_indexed_inline:Nn} \meta{seq~var} \Arg{inline function}
%   \end{syntax}
%   Applies \meta{inline function} to every entry in the \meta{seq~var}.
%   The \meta{inline function} should consist of code which
%   receives the \meta{index} (namely |1| for the first entry, then |2|
%   and so on) as~|#1| and the \meta{item} as~|#2|.
% \end{function}
%
% \begin{function}[rEXP, added = 2023-05-10]
%   {
%     \seq_map_pairwise_function:NNN, \seq_map_pairwise_function:NcN,
%     \seq_map_pairwise_function:cNN, \seq_map_pairwise_function:ccN
%   }
%   \begin{syntax}
%     \cs{seq_map_pairwise_function:NNN} \meta{seq var_1} \meta{seq var_2} \meta{function}
%   \end{syntax}
%   Applies \meta{function} to every pair of items
%   \meta{seq var_1-item}--\meta{seq var_2-item} from the two sequences, returning
%   items from both sequences from left to right.   The \meta{function}
%   receives two \texttt{n}-type arguments for each iteration. The  mapping
%   terminates when
%   the end of either sequence is reached (i.e., whichever sequence has
%   fewer items determines how many iterations
%   occur).
% \end{function}
%
% \begin{function}[rEXP, updated = 2012-06-29]{\seq_map_break:}
%   \begin{syntax}
%     \cs{seq_map_break:}
%   \end{syntax}
%   Used to terminate a \cs[no-index]{seq_map_\ldots} function before all
%   entries in the \meta{seq~var} have been processed. This
%   normally takes place within a conditional statement, for example
%   \begin{verbatim}
%     \seq_map_inline:Nn \l_my_seq
%       {
%         \str_if_eq:nnTF { #1 } { bingo }
%           { \seq_map_break: }
%           {
%             % Do something useful
%           }
%       }
%   \end{verbatim}
%   Use outside of a \cs[no-index]{seq_map_\ldots} scenario leads to low
%   level \TeX{} errors.
%   \begin{texnote}
%     When the mapping is broken, additional tokens may be inserted
%     before further items are taken
%     from the input stream. This depends on the design of the mapping
%     function.
%   \end{texnote}
% \end{function}
%
% \begin{function}[rEXP, updated = 2012-06-29]{\seq_map_break:n}
%   \begin{syntax}
%     \cs{seq_map_break:n} \Arg{code}
%   \end{syntax}
%   Used to terminate a \cs[no-index]{seq_map_\ldots} function before all
%   entries in the \meta{seq~var} have been processed, inserting
%   the \meta{code} after the mapping has ended. This
%   normally takes place within a conditional statement, for example
%   \begin{verbatim}
%     \seq_map_inline:Nn \l_my_seq
%       {
%         \str_if_eq:nnTF { #1 } { bingo }
%           { \seq_map_break:n { <code> } }
%           {
%             % Do something useful
%           }
%       }
%   \end{verbatim}
%   Use outside of a \cs[no-index]{seq_map_\ldots} scenario leads to low
%   level \TeX{} errors.
%   \begin{texnote}
%     When the mapping is broken, additional tokens may be inserted
%     before the \meta{code} is
%     inserted into the input stream.
%     This depends on the design of the mapping function.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2011-12-22, updated = 2020-07-16]
%   {\seq_set_map:NNn, \seq_gset_map:NNn}
%   \begin{syntax}
%     \cs{seq_set_map:NNn} \meta{seq~var_1} \meta{seq~var_2} \Arg{inline function}
%   \end{syntax}
%   Applies \meta{inline function} to every \meta{item} stored
%   within the \meta{seq~var_2}. The \meta{inline function} should
%   consist of code which will receive the \meta{item} as |#1|.
%   The sequence resulting from applying \meta{inline function} to each
%   \meta{item} is assigned to \meta{seq~var_1}.
%   \begin{texnote}
%     Contrarily to other mapping functions, \cs{seq_map_break:} cannot
%     be used in this function, and would lead to low-level \TeX{} errors.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2020-07-16, updated = 2023-10-26]
%   {\seq_set_map_e:NNn, \seq_gset_map_e:NNn}
%   \begin{syntax}
%     \cs{seq_set_map_e:NNn} \meta{seq~var_1} \meta{seq~var_2} \Arg{inline function}
%   \end{syntax}
%   Applies \meta{inline function} to every \meta{item} stored
%   within the \meta{seq~var_2}. The \meta{inline function} should
%   consist of code which will receive the \meta{item} as |#1|.
%   The sequence resulting from \texttt{e}-expanding
%   \meta{inline function} applied to each \meta{item}
%   is assigned to \meta{seq~var_1}. As such, the code
%   in \meta{inline function} should be expandable.
%   \begin{texnote}
%     Contrarily to other mapping functions, \cs{seq_map_break:} cannot
%     be used in this function, and would lead to low-level \TeX{} errors.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP, added = 2012-07-13]{\seq_count:N, \seq_count:c}
%   \begin{syntax}
%     \cs{seq_count:N} \meta{seq~var}
%   \end{syntax}
%   Leaves the number of items in the \meta{seq~var} in the input
%   stream as an \meta{integer denotation}. The total number of items
%   in a \meta{seq~var} includes those which are empty and duplicates,
%   i.e., every item in a \meta{seq~var} is unique.
% \end{function}
%
% \section{Using the content of sequences directly}
%
% \begin{function}[EXP, added = 2013-05-26]{\seq_use:Nnnn, \seq_use:cnnn}
%   \begin{syntax}
%     \cs{seq_use:Nnnn} \meta{seq~var} \Arg{separator~between~two} \Arg{separator~between~more~than~two} \Arg{separator~between~final~two}
%   \end{syntax}
%   Places the contents of the \meta{seq~var} in the input stream, with
%   the appropriate \meta{separator} between the items.  Namely, if the
%   sequence has more than two items, the \meta{separator between more
%     than two} is placed between each pair of items except the last,
%   for which the \meta{separator between final two} is used.  If the
%   sequence has exactly two items, then they are placed in the input stream
%   separated by the \meta{separator between two}.  If the sequence has
%   a single item, it is placed in the input stream, and an empty sequence
%   produces no output.  An error is raised if the variable does
%   not exist or if it is invalid.
%
%   For example,
%   \begin{verbatim}
%     \seq_set_split:Nnn \l_tmpa_seq { | } { a | b | c | {de} | f }
%     \seq_use:Nnnn \l_tmpa_seq { ~and~ } { ,~ } { ,~and~ }
%   \end{verbatim}
%   inserts \enquote{\texttt{a, b, c, de, and f}} in the input
%   stream.  The first separator argument is not used in this case
%   because the sequence has more than $2$ items.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the \meta{items}
%     do not expand further when appearing in an \texttt{e}-type
%     or \texttt{x}-type argument expansion.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP, added = 2013-05-26]{\seq_use:Nn, \seq_use:cn}
%   \begin{syntax}
%     \cs{seq_use:Nn} \meta{seq~var} \Arg{separator}
%   \end{syntax}
%   Places the contents of the \meta{seq~var} in the input stream, with
%   the \meta{separator} between the items.  If the sequence has
%   a single item, it is placed in the input stream with no \meta{separator},
%   and an empty sequence produces no output.  An error is raised if
%   the variable does not exist or if it is invalid.
%
%   For example,
%   \begin{verbatim}
%     \seq_set_split:Nnn \l_tmpa_seq { | } { a | b | c | {de} | f }
%     \seq_use:Nn \l_tmpa_seq { ~and~ }
%   \end{verbatim}
%   inserts \enquote{\texttt{a and b and c and de and f}} in the input
%   stream.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the \meta{items}
%     do not expand further when appearing in an \texttt{e}-type
%     or \texttt{x}-type argument expansion.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP, added = 2025-06-09]{\seq_format:Nn, \seq_format:cn}
%   \begin{syntax}
%     \cs{seq_format:Nn} \meta{seq~var} \Arg{format specification}
%   \end{syntax}
%   Converts each item in the \meta{seq~var} as a token list to a string
%   according to the \meta{format specification}, and concatenates the results.
%   The details of the \meta{format specification} are described in
%   Section~\ref{sec:l3str-format:spec}.
% \end{function}
%
% \section{Sequences as stacks}
%
% Sequences can be used as stacks, where data is pushed to and popped
% from the top of the sequence. (The left of a sequence is the top, for
% performance reasons.) The stack functions for sequences are not
% intended to be mixed with the general ordered data functions detailed
% in the previous section: a sequence should either be used as an
% ordered data type or as a stack, but not in both ways.
%
% \begin{function}[updated = 2012-05-14]{\seq_get:NN, \seq_get:cN}
%   \begin{syntax}
%     \cs{seq_get:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Reads the top item from a \meta{seq~var} into the
%   \meta{tl~var} without removing it from the
%   \meta{seq~var}. The \meta{tl~var} is assigned locally.
%   If \meta{seq~var} is empty the \meta{tl~var} is set to
%   the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[updated = 2012-05-14]{\seq_pop:NN, \seq_pop:cN}
%   \begin{syntax}
%     \cs{seq_pop:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Pops the top item from a \meta{seq~var} into the
%   \meta{tl~var}. Both of the variables are assigned
%   locally. If \meta{seq~var} is empty the \meta{tl~var}
%   is set to the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[updated = 2012-05-14]{\seq_gpop:NN, \seq_gpop:cN}
%   \begin{syntax}
%     \cs{seq_gpop:NN} \meta{seq~var} \meta{tl~var}
%   \end{syntax}
%   Pops the top item from a \meta{seq~var} into the
%   \meta{tl~var}. The \meta{seq~var} is modified globally,
%   while the \meta{tl~var} is assigned locally. If
%   \meta{seq~var} is empty the \meta{tl~var} is set to
%   the special marker \cs{q_no_value}.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]{\seq_get:NN, \seq_get:cN}
%   \begin{syntax}
%     \cs{seq_get:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, stores the top item from a
%   \meta{seq~var} in the \meta{tl~var} without removing it from
%   the \meta{seq~var}. The \meta{tl~var} is assigned locally.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]{\seq_pop:NN, \seq_pop:cN}
%   \begin{syntax}
%     \cs{seq_pop:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, pops the top item from the
%   \meta{seq~var} in the \meta{tl~var}, i.e., removes the
%   item from the \meta{seq~var}. Both the \meta{seq~var} and the
%   \meta{tl~var} are assigned locally.
% \end{function}
%
% \begin{function}[TF, added = 2012-05-14, updated = 2012-05-19]{\seq_gpop:NN, \seq_gpop:cN}
%   \begin{syntax}
%     \cs{seq_gpop:NNTF} \meta{seq~var} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   If the \meta{seq~var} is empty, leaves the \meta{false code} in the
%   input stream.  The value of the \meta{tl~var} is
%   not defined in this case and should not be relied upon.  If the
%   \meta{seq~var} is non-empty, pops the top item from the \meta{seq~var}
%   in the \meta{tl~var}, i.e., removes the item from the
%   \meta{seq~var}. The \meta{seq~var} is modified globally, while the
%   \meta{tl~var} is assigned locally.
% \end{function}
%
% \begin{function}
%   {
%     \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:Ne,
%     \seq_push:No,
%     \seq_push:cn, \seq_push:cV, \seq_push:cv,  \seq_push:ce,
%     \seq_push:co,
%     \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv,  \seq_gpush:Ne,
%     \seq_gpush:No,
%     \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv,  \seq_gpush:ce,
%     \seq_gpush:co
%   }
%   \begin{syntax}
%     \cs{seq_push:Nn} \meta{seq~var} \Arg{item}
%   \end{syntax}
%   Adds the \Arg{item} to the top of the \meta{seq~var}.
% \end{function}
%
% \section{Sequences as sets}
%
% Sequences can also be used as sets, such that all of their items are
% distinct.  Usage of sequences as sets is not currently widespread,
% hence no specific set function is provided.  Instead, it is explained
% here how common set operations can be performed by combining several
% functions described in earlier sections.  When using sequences to
% implement sets, one should be careful not to rely on the order of
% items in the sequence representing the set.
%
% Sets should not contain several occurrences of a given item.  To make
% sure that a \meta{seq~var} only has distinct items, use
% \cs{seq_remove_duplicates:N} \meta{seq~var}.  This function
% is relatively slow, and to avoid performance issues one should only
% use it when necessary.
%
% Some operations on a set \meta{seq~var} are straightforward.  For
% instance, \cs{seq_count:N} \meta{seq~var} expands to the number of
% items, while \cs{seq_if_in:NnTF} \meta{seq~var} \Arg{item} tests if
% the \meta{item} is in the set.
%
% Adding an \meta{item} to a set \meta{seq~var} can be done by appending
% it to the \meta{seq~var} if it is not already in the \meta{seq~var}:
% \begin{quote}\ttfamily\parskip=0pt\obeylines
%   \cs{seq_if_in:NnF} \meta{seq~var} \Arg{item}
%   |  |\{ \cs{seq_put_right:Nn} \meta{seq~var} \Arg{item} \}
% \end{quote}
% Removing an \meta{item} from a set \meta{seq~var} can be done using
% \cs{seq_remove_all:Nn},
% \begin{quote}\ttfamily
%   \cs{seq_remove_all:Nn} \meta{seq~var} \Arg{item}
% \end{quote}
%
% The intersection of two sets \meta{seq~var_1} and \meta{seq~var_2} can
% be stored into \meta{seq~var_3} by collecting items of
% \meta{seq~var_1} which are in \meta{seq~var_2}.
% \begin{quote}\ttfamily\parskip=0pt\obeylines
%   \cs{seq_clear:N} \meta{seq~var_3}
%   \cs{seq_map_inline:Nn} \meta{seq~var_1}
%   |  |\{
%   |    |\cs{seq_if_in:NnT} \meta{seq~var_2} \{\#1\}
%   |      |\{ \cs{seq_put_right:Nn} \meta{seq~var_3} \{\#1\} \}
%   |  |\}
% \end{quote}
% The code as written here only works if \meta{seq~var_3} is different
% from the other two sequence variables.  To cover all cases, items
% should first be collected in a sequence
% |\l__|\meta{pkg}|_tmp_seq|, then \meta{seq~var_3} should be set
% equal to this internal sequence.  The same remark applies to other set
% functions.
%
% The union of two sets \meta{seq~var_1} and \meta{seq~var_2} can be
% stored into \meta{seq~var_3} through
% \begin{quote}\ttfamily
%   \cs{seq_concat:NNN} \meta{seq~var_3} \meta{seq~var_1} \meta{seq~var_2} \\
%   \cs{seq_remove_duplicates:N} \meta{seq~var_3}
% \end{quote}
% or by adding items to (a copy of) \meta{seq~var_1} one by one
% \begin{quote}\ttfamily\parskip=0pt\obeylines
%   \cs{seq_set_eq:NN} \meta{seq~var_3} \meta{seq~var_1}
%   \cs{seq_map_inline:Nn} \meta{seq~var_2}
%   |  |\{
%   |    |\cs{seq_if_in:NnF} \meta{seq~var_3} \{\#1\}
%   |      |\{ \cs{seq_put_right:Nn} \meta{seq~var_3} \{\#1\} \}
%   |  |\}
% \end{quote}
% The second approach is faster than the first when the \meta{seq~var_2}
% is short compared to \meta{seq~var_1}.
%
% The difference of two sets \meta{seq~var_1} and \meta{seq~var_2} can
% be stored into \meta{seq~var_3} by removing items of the
% \meta{seq~var_2} from (a copy of) the \meta{seq~var_1} one by one.
% \begin{quote}\ttfamily\parskip=0pt\obeylines
%   \cs{seq_set_eq:NN} \meta{seq~var_3} \meta{seq~var_1}
%   \cs{seq_map_inline:Nn} \meta{seq~var_2}
%   |  |\{ \cs{seq_remove_all:Nn} \meta{seq~var_3} \{\#1\} \}
% \end{quote}
%
% The symmetric difference of two sets \meta{seq~var_1} and
% \meta{seq~var_2} can be stored into \meta{seq~var_3} by computing the
% difference between \meta{seq~var_1} and \meta{seq~var_2} and storing
% the result as |\l__|\meta{pkg}|_tmp_seq|, then the difference
% between \meta{seq~var_2} and \meta{seq~var_1}, and finally
% concatenating the two differences to get the symmetric differences.
% \begin{quote}\ttfamily\parskip=0pt\obeylines
%   \cs{seq_set_eq:NN} |\l__|\meta{pkg}|_tmp_seq| \meta{seq~var_1}
%   \cs{seq_map_inline:Nn} \meta{seq~var_2}
%   |  |\{ \cs{seq_remove_all:Nn} |\l__|\meta{pkg}|_tmp_seq| \{\#1\} \}
%   \cs{seq_set_eq:NN} \meta{seq~var_3} \meta{seq~var_2}
%   \cs{seq_map_inline:Nn} \meta{seq~var_1}
%   |  |\{ \cs{seq_remove_all:Nn} \meta{seq~var_3} \{\#1\} \}
%   \cs{seq_concat:NNN} \meta{seq~var_3} \meta{seq~var_3} |\l__|\meta{pkg}|_tmp_seq|
% \end{quote}
%
% \section{Constant and scratch sequences}
%
% \begin{variable}[added = 2012-07-02]{\c_empty_seq}
%   Constant that is always empty.
% \end{variable}
%
% \begin{variable}[added = 2012-04-26]{\l_tmpa_seq, \l_tmpb_seq}
%   Scratch sequences 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 = 2012-04-26]{\g_tmpa_seq, \g_tmpb_seq}
%   Scratch sequences 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{Viewing sequences}
%
% \begin{function}[updated = 2021-04-29]{\seq_show:N, \seq_show:c}
%   \begin{syntax}
%     \cs{seq_show:N} \meta{seq~var}
%   \end{syntax}
%   Displays the entries in the \meta{seq~var} in the terminal.
% \end{function}
%
% \begin{function}[added = 2014-08-12, updated = 2021-04-29]{\seq_log:N, \seq_log:c}
%   \begin{syntax}
%     \cs{seq_log:N} \meta{seq~var}
%   \end{syntax}
%   Writes the entries in the \meta{seq~var} in the log file.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3seq} implementation}
%
% \TestFiles{m3seq002,m3seq003}
%
%    \begin{macrocode}
%<*code>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=seq>
%    \end{macrocode}
%
% A sequence is a control sequence whose top-level expansion is of the
% form \enquote{\cs{s_@@} \cs{@@_item:n} \marg{item_1} \ldots
%   \cs{@@_item:n} \marg{item_n}}, with a leading scan
% mark followed by $n$~items of the same form.  An
% earlier implementation used the structure \enquote{\cs{seq_elt:w}
%   \meta{item_1} \cs{seq_elt_end:} \ldots \cs{seq_elt:w} \meta{item_n}
%   \cs{seq_elt_end:}}.  This allowed rapid searching using a delimited
% function, but was not suitable for items containing |{|, |}| and |#|
% tokens, and also lead to the loss of surrounding braces around items
%
% \begin{function}[EXP]{\@@_item:n}
%   \begin{syntax}
%     \cs{@@_item:n} \Arg{item}
%   \end{syntax}
%   The internal token used to begin each sequence entry. If expanded
%   outside of a mapping or manipulation function, an error is
%   raised. The definition should always be set globally.
% \end{function}
%
% \begin{function}{\@@_push_item_def:n, \@@_push_item_def:e}
%   \begin{syntax}
%     \cs{@@_push_item_def:n} \Arg{code}
%   \end{syntax}
%   Saves the definition of \cs{@@_item:n} and redefines it to
%   accept one parameter and expand to \meta{code}. This function
%   should always be balanced by use of \cs{@@_pop_item_def:}.
% \end{function}
%
% \begin{function}{\@@_pop_item_def:}
%   \begin{syntax}
%     \cs{@@_pop_item_def:}
%   \end{syntax}
%   Restores the definition of \cs{@@_item:n} most recently saved by
%   \cs{@@_push_item_def:n}. This function should always be used in
%   a balanced pair with \cs{@@_push_item_def:n}.
% \end{function}
%
% \begin{variable}{\s_@@}
%   This private scan mark.
%    \begin{macrocode}
\scan_new:N \s_@@
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\s_@@_mark,\s_@@_stop}
%   Private scan marks.
%    \begin{macrocode}
\scan_new:N \s_@@_mark
\scan_new:N \s_@@_stop
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[EXP]{\@@_item:n}
%   The delimiter is always defined, but when used incorrectly simply
%   removes its argument and hits an undefined control sequence to
%   raise an error.
%    \begin{macrocode}
\cs_new:Npn \@@_item:n
  {
    \msg_expandable_error:nn { seq } { misused }
    \use_none:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_tmpa_tl, \l_@@_tmpb_tl}
%   Scratch space for various internal uses.
%    \begin{macrocode}
\tl_new:N \l_@@_tmpa_tl
\tl_new:N \l_@@_tmpb_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_tmp:w}
%   Scratch function for internal use.
%    \begin{macrocode}
\cs_new_eq:NN \@@_tmp:w ?
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\c_empty_seq}
%   A sequence with no item, following the structure mentioned above.
%    \begin{macrocode}
\tl_const:Nn \c_empty_seq { \s_@@ }
%    \end{macrocode}
% \end{variable}
%
% \subsection{Allocation and initialization}
%
% \begin{macro}{\seq_new:N, \seq_new:c}
% \UnitTested
%   Sequences are initialized to \cs{c_empty_seq}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_new:N #1
  {
    \__kernel_chk_if_free_cs:N #1
    \cs_gset_eq:NN #1 \c_empty_seq
  }
\cs_generate_variant:Nn \seq_new:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_clear:N, \seq_clear:c}
% \UnitTested
% \begin{macro}{\seq_gclear:N, \seq_gclear:c}
% \UnitTested
%   Clearing a sequence is similar to setting it equal to the empty one.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_clear:N  #1
  { \seq_set_eq:NN #1 \c_empty_seq }
\cs_generate_variant:Nn \seq_clear:N  { c }
\cs_new_protected:Npn \seq_gclear:N #1
  { \seq_gset_eq:NN #1 \c_empty_seq }
\cs_generate_variant:Nn \seq_gclear:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_clear_new:N, \seq_clear_new:c}
% \UnitTested
% \begin{macro}{\seq_gclear_new:N, \seq_gclear_new:c}
% \UnitTested
%   Once again we copy code from the token list functions.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_clear_new:N  #1
  { \seq_if_exist:NTF #1 { \seq_clear:N #1 } { \seq_new:N #1 } }
\cs_generate_variant:Nn \seq_clear_new:N  { c }
\cs_new_protected:Npn \seq_gclear_new:N #1
  { \seq_if_exist:NTF #1 { \seq_gclear:N #1 } { \seq_new:N #1 } }
\cs_generate_variant:Nn \seq_gclear_new:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_eq:NN, \seq_set_eq:cN, \seq_set_eq:Nc, \seq_set_eq:cc}
% \UnitTested
% \begin{macro}
%   {\seq_gset_eq:NN, \seq_gset_eq:cN, \seq_gset_eq:Nc, \seq_gset_eq:cc}
% \UnitTested
%   Copying a sequence is the same as copying the underlying token list.
%    \begin{macrocode}
\cs_new_eq:NN \seq_set_eq:NN  \tl_set_eq:NN
\cs_new_eq:NN \seq_set_eq:Nc  \tl_set_eq:Nc
\cs_new_eq:NN \seq_set_eq:cN  \tl_set_eq:cN
\cs_new_eq:NN \seq_set_eq:cc  \tl_set_eq:cc
\cs_new_eq:NN \seq_gset_eq:NN \tl_gset_eq:NN
\cs_new_eq:NN \seq_gset_eq:Nc \tl_gset_eq:Nc
\cs_new_eq:NN \seq_gset_eq:cN \tl_gset_eq:cN
\cs_new_eq:NN \seq_gset_eq:cc \tl_gset_eq:cc
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_set_from_clist:NN, \seq_set_from_clist:cN,
%     \seq_set_from_clist:Nc, \seq_set_from_clist:cc,
%     \seq_set_from_clist:Nn, \seq_set_from_clist:cn
%   }
% \begin{macro}
%   {
%     \seq_gset_from_clist:NN, \seq_gset_from_clist:cN,
%     \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc,
%     \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn
%   }
%   Setting a sequence from a comma-separated list is done using a simple
%   mapping.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_from_clist:NN #1#2
  {
    \__kernel_tl_set:Nx #1
      { \s_@@ \clist_map_function:NN #2 \@@_wrap_item:n }
  }
\cs_new_protected:Npn \seq_set_from_clist:Nn #1#2
  {
    \__kernel_tl_set:Nx #1
      { \s_@@ \clist_map_function:nN {#2} \@@_wrap_item:n }
  }
\cs_new_protected:Npn \seq_gset_from_clist:NN #1#2
  {
    \__kernel_tl_gset:Nx #1
      { \s_@@ \clist_map_function:NN #2 \@@_wrap_item:n }
  }
\cs_new_protected:Npn \seq_gset_from_clist:Nn #1#2
  {
    \__kernel_tl_gset:Nx #1
      { \s_@@ \clist_map_function:nN {#2} \@@_wrap_item:n }
  }
\cs_generate_variant:Nn \seq_set_from_clist:NN  {     Nc }
\cs_generate_variant:Nn \seq_set_from_clist:NN  { c , cc }
\cs_generate_variant:Nn \seq_set_from_clist:Nn  { c      }
\cs_generate_variant:Nn \seq_gset_from_clist:NN {     Nc }
\cs_generate_variant:Nn \seq_gset_from_clist:NN { c , cc }
\cs_generate_variant:Nn \seq_gset_from_clist:Nn { c      }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_const_from_clist:Nn, \seq_const_from_clist:cn}
%   Almost identical to \cs{seq_set_from_clist:Nn}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_const_from_clist:Nn #1#2
  {
    \tl_const:Ne #1
      { \s_@@ \clist_map_function:nN {#2} \@@_wrap_item:n }
  }
\cs_generate_variant:Nn \seq_const_from_clist:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_set_split:Nnn ,
%     \seq_set_split:NVn , \seq_set_split:NnV , \seq_set_split:NVV ,
%     \seq_set_split:Nne , \seq_set_split:Nee ,
%     \seq_set_split:Nnx , \seq_set_split:Nxx ,
%     \seq_gset_split:Nnn,
%     \seq_gset_split:NVn, \seq_gset_split:NnV, \seq_gset_split:NVV,
%     \seq_gset_split:Nne, \seq_gset_split:Nee,
%     \seq_gset_split:Nnx, \seq_gset_split:Nxx
%   }
% \begin{macro}
%   {
%     \seq_set_split_keep_spaces:Nnn , \seq_set_split_keep_spaces:NnV ,
%     \seq_gset_split_keep_spaces:Nnn, \seq_gset_split_keep_spaces:NnV
%   }
% \begin{macro}{\@@_set_split:NNnn}
% \begin{macro}
%   {
%     \@@_set_split:Nw, \@@_set_split:w,
%     \@@_set_split_end:
%   }
%   When the separator is empty, everything is very simple, just map
%   \cs{@@_wrap_item:n} through the items of the last argument.
%   For non-trivial separators, the goal is to split a given token list
%   at the marker, strip spaces from each item, and remove one set of
%   outer braces if after removing leading and trailing
%   spaces the item is enclosed within braces. After
%   \cs{tl_replace_all:Nnn}, the token list \cs{l_@@_tmpa_tl}
%   is a repetition of the pattern
%   \cs{@@_set_split:Nw} \cs{prg_do_nothing:}
%   \meta{item with spaces} \cs{@@_set_split_end:}.
%   Then, \texttt{x}-expansion causes \cs{@@_set_split:Nw}
%   to trim spaces, and leaves its result as
%   \cs{@@_set_split:w} \meta{trimmed item}
%   \cs{@@_set_split_end:}. This is then converted
%   to the \pkg{l3seq} internal structure by another
%   \texttt{x}-expansion. In the first step, we insert
%   \cs{prg_do_nothing:} to avoid losing braces too early:
%   that would cause space trimming to act within those
%   lost braces. The second step is solely there to strip
%   braces which are outermost after space trimming.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_split:Nnn
  { \@@_set_split:NNNnn \__kernel_tl_set:Nx \tl_trim_spaces:n }
\cs_new_protected:Npn \seq_gset_split:Nnn
  { \@@_set_split:NNNnn \__kernel_tl_gset:Nx \tl_trim_spaces:n }
\cs_new_protected:Npn \seq_set_split_keep_spaces:Nnn
  { \@@_set_split:NNNnn \__kernel_tl_set:Nx \exp_not:n }
\cs_new_protected:Npn \seq_gset_split_keep_spaces:Nnn
  { \@@_set_split:NNNnn \__kernel_tl_gset:Nx \exp_not:n }
\cs_new_protected:Npn \@@_set_split:NNNnn #1#2#3#4#5
  {
    \tl_if_empty:nTF {#4}
      {
        \tl_set:Nn \l_@@_tmpa_tl
          { \tl_map_function:nN {#5} \@@_wrap_item:n }
      }
      {
        \tl_set:Nn \l_@@_tmpa_tl
          {
            \@@_set_split:Nw #2 \prg_do_nothing:
            #5
            \@@_set_split_end:
          }
        \tl_replace_all:Nnn \l_@@_tmpa_tl {#4}
          {
            \@@_set_split_end:
            \@@_set_split:Nw #2 \prg_do_nothing:
          }
        \__kernel_tl_set:Nx \l_@@_tmpa_tl { \l_@@_tmpa_tl }
      }
    #1 #3 { \s_@@ \l_@@_tmpa_tl }
  }
\cs_new:Npn \@@_set_split:Nw #1#2 \@@_set_split_end:
  {
    \exp_not:N \@@_set_split:w
    \exp_args:No #1 {#2}
    \exp_not:N \@@_set_split_end:
  }
\cs_new:Npn \@@_set_split:w #1 \@@_set_split_end:
  { \@@_wrap_item:n {#1} }
\cs_generate_variant:Nn \seq_set_split:Nnn  { NV , NnV , NVV , Nne , Nee }
\cs_generate_variant:Nn \seq_set_split:Nnn  { Nnx , Nxx }
\cs_generate_variant:Nn \seq_gset_split:Nnn { NV , NnV , NVV , Nne , Nee }
\cs_generate_variant:Nn \seq_gset_split:Nnn { Nnx , Nxx }
\cs_generate_variant:Nn \seq_set_split_keep_spaces:Nnn  { NnV }
\cs_generate_variant:Nn \seq_gset_split_keep_spaces:Nnn { NnV }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_filter:NNn, \seq_gset_filter:NNn}
% \begin{macro}{\@@_set_filter:NNNn}
%   Similar to \cs{seq_map_inline:Nn}, without a
%   \cs{prg_break_point:} because the user's code
%   is performed within the evaluation of a boolean expression,
%   and skipping out of that would break horribly.
%   The \cs{@@_wrap_item:n} function inserts the relevant
%   \cs{@@_item:n} without expansion in the input stream,
%   hence in the \texttt{x}-expanding assignment.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_filter:NNn
  { \@@_set_filter:NNNn \__kernel_tl_set:Nx }
\cs_new_protected:Npn \seq_gset_filter:NNn
  { \@@_set_filter:NNNn \__kernel_tl_gset:Nx }
\cs_new_protected:Npn \@@_set_filter:NNNn #1#2#3#4
  {
    \@@_push_item_def:n { \bool_if:nT {#4} { \@@_wrap_item:n {##1} } }
    #1 #2 { #3 }
    \@@_pop_item_def:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_set_regex_extract_once:Nnn, \seq_set_regex_extract_once:cnn,
%     \seq_gset_regex_extract_once:Nnn, \seq_gset_regex_extract_once:cnn
%   }
% \begin{macro}
%   {
%     \seq_set_regex_extract_all:Nnn, \seq_set_regex_extract_all:cnn,
%     \seq_gset_regex_extract_all:Nnn, \seq_gset_regex_extract_all:cnn
%   }
% \begin{macro}
%   {
%     \seq_set_regex_extract_once:NNn, \seq_set_regex_extract_once:cNn,
%     \seq_gset_regex_extract_once:NNn, \seq_gset_regex_extract_once:cNn
%   }
% \begin{macro}
%   {
%     \seq_set_regex_extract_all:NNn, \seq_set_regex_extract_all:cNn,
%     \seq_gset_regex_extract_all:NNn, \seq_gset_regex_extract_all:cNn
%   }
% \begin{macro}
%   {
%     \seq_set_regex_split:Nnn, \seq_set_regex_split:cnn,
%     \seq_gset_regex_split:Nnn, \seq_gset_regex_split:cnn
%   }
% \begin{macro}
%   {
%     \seq_set_regex_split:NNn, \seq_set_regex_split:cNn,
%     \seq_gset_regex_split:NNn, \seq_gset_regex_split:cNn
%   }
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_regex_extract_once:Nnn #1#2#3
  { \regex_extract_once:nnN {#2} {#3} #1 }
\cs_generate_variant:Nn \seq_set_regex_extract_once:Nnn { c }
\cs_new_protected:Npn \seq_set_regex_extract_once:NNn #1#2#3
  { \regex_extract_once:NnN #2 {#3} #1 }
\cs_generate_variant:Nn \seq_set_regex_extract_once:NNn { c }
\cs_new_protected:Npn \seq_set_regex_extract_all:Nnn #1#2#3
  { \regex_extract_all:nnN {#2} {#3} #1 }
\cs_generate_variant:Nn \seq_set_regex_extract_all:Nnn { c }
\cs_new_protected:Npn \seq_set_regex_extract_all:NNn #1#2#3
  { \regex_extract_all:NnN #2 {#3} #1 }
\cs_generate_variant:Nn \seq_set_regex_extract_all:NNn { c }
\cs_new_protected:Npn \seq_set_regex_split:Nnn #1#2#3
  { \regex_split:nnN {#2} {#3} #1 }
\cs_generate_variant:Nn \seq_set_regex_split:Nnn { c }
\cs_new_protected:Npn \seq_set_regex_split:NNn #1#2#3
  { \regex_split:NnN #2 {#3} #1 }
\cs_generate_variant:Nn \seq_set_regex_split:NNn { c }
\group_begin:
  \cs_set_protected:Npn \@@_tmp:w #1#2#3
    {
      \cs_new_protected:cpe { seq_gset_regex_ #1 :N #2 n } ##1##2##3
        {
          \group_begin:
            \seq_set_eq:NN \exp_not:N \l_@@_tmp_seq ##1
            \exp_not:c { regex_ #1 :Nn #2 }
              #3 {##2} {##3} \exp_not:N \l_@@_tmp_seq
            \seq_gset_eq:NN ##1 \exp_not:N \l_@@_tmp_seq
          \group_end:
        }
      \cs_generate_variant:cn { seq_gset_regex_ #1 :N #2 n } { c }
    }
  \@@_tmp:w { extract_once } n { }
  \@@_tmp:w { extract_once } N \use:n
  \@@_tmp:w { extract_all } n { }
  \@@_tmp:w { extract_all } N \use:n
  \@@_tmp:w { split } n { }
  \@@_tmp:w { split } N \use:n
\group_end:
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_concat:NNN, \seq_concat:ccc}
% \UnitTested
% \begin{macro}{\seq_gconcat:NNN, \seq_gconcat:ccc}
% \UnitTested
%   When concatenating sequences, one must remove the leading \cs{s_@@}
%   of the second sequence.  The result starts with \cs{s_@@} (of the
%   first sequence), which stops \texttt{f}-expansion.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_concat:NNN #1#2#3
  { \tl_set:Nf #1 { \exp_after:wN \use_i:nn \exp_after:wN #2 #3 } }
\cs_new_protected:Npn \seq_gconcat:NNN #1#2#3
  { \tl_gset:Nf #1 { \exp_after:wN \use_i:nn \exp_after:wN #2 #3 } }
\cs_generate_variant:Nn \seq_concat:NNN  { ccc }
\cs_generate_variant:Nn \seq_gconcat:NNN { ccc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\seq_if_exist:N, \seq_if_exist:c}
%   Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \seq_if_exist:N \cs_if_exist:N
  { TF , T , F , p }
\prg_new_eq_conditional:NNn \seq_if_exist:c \cs_if_exist:c
  { TF , T , F , p }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Appending data to either end}
%
% \begin{macro}{
%   \seq_put_left:Nn, \seq_put_left:NV, \seq_put_left:Nv, \seq_put_left:Ne,
%   \seq_put_left:No, \seq_put_left:Nx,
%   \seq_put_left:cn, \seq_put_left:cV, \seq_put_left:cv,\seq_put_left:ce, 
%   \seq_put_left:co, \seq_put_left:cx
% }
% \UnitTested
% \begin{macro}{
%   \seq_gput_left:Nn, \seq_gput_left:NV, \seq_gput_left:Nv, \seq_gput_left:Ne,
%   \seq_gput_left:No, \seq_gput_left:Nx,
%   \seq_gput_left:cn, \seq_gput_left:cV, \seq_gput_left:cv, \seq_gput_left:ce,
%   \seq_gput_left:co, \seq_gput_left:cx
% }
% \begin{macro}[EXP]{\@@_put_left_aux:w}
%   When adding to the left of a sequence, remove \cs{s_@@}.  This is
%   done by \cs{@@_put_left_aux:w}, which also stops
%   \texttt{f}-expansion.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_put_left:Nn #1#2
  {
    \__kernel_tl_set:Nx #1
      {
        \exp_not:n { \s_@@ \@@_item:n {#2} }
        \exp_not:f { \exp_after:wN \@@_put_left_aux:w #1 }
      }
  }
\cs_new_protected:Npn \seq_gput_left:Nn #1#2
  {
    \__kernel_tl_gset:Nx #1
      {
        \exp_not:n { \s_@@ \@@_item:n {#2} }
        \exp_not:f { \exp_after:wN \@@_put_left_aux:w #1 }
      }
  }
\cs_new:Npn \@@_put_left_aux:w \s_@@ { \exp_stop_f: }
\cs_generate_variant:Nn \seq_put_left:Nn  {     NV , Nv , Ne , No , Nx }
\cs_generate_variant:Nn \seq_put_left:Nn  { c , cV , cv , ce , co ,cx }
\cs_generate_variant:Nn \seq_gput_left:Nn {     NV , Nv , Ne , No , Nx }
\cs_generate_variant:Nn \seq_gput_left:Nn { c , cV , cv , ce , co , cx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_put_right:Nn, \seq_put_right:NV, \seq_put_right:Nv, \seq_put_right:Ne,
%     \seq_put_right:No, \seq_put_right:Nx,
%     \seq_put_right:cn, \seq_put_right:cV, \seq_put_right:cv, \seq_put_right:cx,
%     \seq_put_right:co, \seq_put_right:cx
%   }
% \UnitTested
% \begin{macro}
%   {
%     \seq_gput_right:Nn, \seq_gput_right:NV, \seq_gput_right:Nv, \seq_gput_right:Ne,
%     \seq_gput_right:No, \seq_gput_right:Nx,
%     \seq_gput_right:cn, \seq_gput_right:cV, \seq_gput_right:cv, \seq_gput_right:ce,
%     \seq_gput_right:co, \seq_gput_right:cx
%   }
%   Since there is no trailing marker, adding an item to the right of a
%   sequence simply means wrapping it in \cs{@@_item:n}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_put_right:Nn #1#2
  { \tl_put_right:Nn #1 { \@@_item:n {#2} } }
\cs_new_protected:Npn \seq_gput_right:Nn #1#2
  { \tl_gput_right:Nn #1 { \@@_item:n {#2} } }
\cs_generate_variant:Nn \seq_put_right:Nn  {     NV , Nv , Ne , No , Nx }
\cs_generate_variant:Nn \seq_put_right:Nn  { c , cV , cv , ce , co , cx }
\cs_generate_variant:Nn \seq_gput_right:Nn {     NV , Nv , Ne , No , Nx }
\cs_generate_variant:Nn \seq_gput_right:Nn { c , cV , cv , ce , co , cx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Modifying sequences}
%
% \begin{macro}{\@@_wrap_item:n}
%   This function converts its argument to a proper sequence item
%   in an \texttt{e}- or \texttt{x}-expansion context.
%    \begin{macrocode}
\cs_new:Npn \@@_wrap_item:n #1 { \exp_not:n { \@@_item:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_tmp_seq}
%   An internal sequence for the removal routines.
%    \begin{macrocode}
\seq_new:N \l_@@_tmp_seq
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\seq_remove_duplicates:N, \seq_remove_duplicates:c}
% \UnitTested
% \begin{macro}{\seq_gremove_duplicates:N, \seq_gremove_duplicates:c}
% \UnitTested
% \begin{macro}{\@@_remove_duplicates:NN}
%   Removing duplicates means making a new list then copying it.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_remove_duplicates:N
  { \@@_remove_duplicates:NN \seq_set_eq:NN }
\cs_new_protected:Npn \seq_gremove_duplicates:N
  { \@@_remove_duplicates:NN \seq_gset_eq:NN }
\cs_new_protected:Npn \@@_remove_duplicates:NN #1#2
  {
    \seq_clear:N \l_@@_tmp_seq
    \seq_map_inline:Nn #2
      {
        \seq_if_in:NnF \l_@@_tmp_seq {##1}
          { \seq_put_right:Nn \l_@@_tmp_seq {##1} }
      }
    #1 #2 \l_@@_tmp_seq
  }
\cs_generate_variant:Nn \seq_remove_duplicates:N  { c }
\cs_generate_variant:Nn \seq_gremove_duplicates:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_remove_all:Nn, \seq_remove_all:NV, \seq_remove_all:Ne,
%     \seq_remove_all:Nx,
%     \seq_remove_all:cn, \seq_remove_all:cV, \seq_remove_all:ce,
%     \seq_remove_all:cx,
%   }
% \UnitTested
% \begin{macro}
%   {
%     \seq_gremove_all:Nn, \seq_gremove_all:NV, \seq_gremove_all:Ne,
%     \seq_gremove_all:Nx,
%     \seq_gremove_all:cn, \seq_gremove_all:cV, \seq_gremove_all:ce,
%     \seq_gremove_all:Nx
%   }
% \UnitTested
% \begin{macro}{\@@_remove_all_aux:NNn}
%   The idea of the code here is to avoid a relatively expensive addition of
%   items one at a time to an intermediate sequence.
%   The approach taken is therefore similar to
%   that in \cs{@@_pop_right:NNN}, using a \enquote{flexible}
%   \texttt{x}-type expansion to do most of the work. As \cs{tl_if_eq:nnT}
%   is not expandable, a two-part strategy is needed. First, the
%   \texttt{x}-type expansion uses \cs{str_if_eq:nnT} to find potential
%   matches. If one is found, the expansion is halted and the necessary
%   set up takes place to use the \cs{tl_if_eq:NNT} test. The \texttt{x}-type
%   is started again, including all of the items copied already. This
%   happens repeatedly until the entire sequence has been scanned. The code
%   is set up to avoid needing an intermediate scratch list: the lead-off
%   \texttt{x}-type expansion (|#1 #2 {#2}|) ensures that nothing is lost.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_remove_all:Nn
  { \@@_remove_all_aux:NNn \__kernel_tl_set:Nx }
\cs_new_protected:Npn \seq_gremove_all:Nn
  { \@@_remove_all_aux:NNn \__kernel_tl_gset:Nx }
\cs_new_protected:Npn \@@_remove_all_aux:NNn #1#2#3
  {
    \@@_push_item_def:n
      {
        \str_if_eq:nnT {##1} {#3}
          {
            \if_false: { \fi: }
            \tl_set:Nn \l_@@_tmpb_tl {##1}
            #1 #2
              { \if_false: } \fi:
                \exp_not:o {#2}
                \tl_if_eq:NNT \l_@@_tmpa_tl \l_@@_tmpb_tl
                  { \use_none:nn }
          }
        \@@_wrap_item:n {##1}
      }
    \tl_set:Nn \l_@@_tmpa_tl {#3}
    #1 #2 {#2}
    \@@_pop_item_def:
  }
\cs_generate_variant:Nn \seq_remove_all:Nn  { NV , Ne , c , cV , ce }
\cs_generate_variant:Nn \seq_remove_all:Nn  { Nx , cx }
\cs_generate_variant:Nn \seq_gremove_all:Nn { NV , Ne , c , cV , ce }
\cs_generate_variant:Nn \seq_gremove_all:Nn { Nx , cx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_int_eval:w}
%   Useful to more quickly go through items.
%    \begin{macrocode}
\cs_new_eq:NN \@@_int_eval:w \tex_numexpr:D
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[noTF]{\seq_set_item:Nnn, \seq_set_item:cnn, \seq_gset_item:Nnn, \seq_gset_item:cnn}
% \begin{macro}{\@@_set_item:NnnNN, \@@_set_item:nnNNNN, \@@_set_item_false:nnNNNN, \@@_set_item:nNnnNNNN}
% \begin{macro}[rEXP]{\@@_set_item:wn, \@@_set_item_end:w}
%   The conditionals are distinguished from the |Nnn| versions by the
%   last argument \cs{use_ii:nn} vs \cs{use_i:nn}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_item:Nnn #1#2#3
  { \@@_set_item:NnnNN #1 {#2} {#3} \__kernel_tl_set:Nx \use_i:nn }
\cs_new_protected:Npn \seq_gset_item:Nnn #1#2#3
  { \@@_set_item:NnnNN #1 {#2} {#3} \__kernel_tl_gset:Nx \use_i:nn }
\cs_generate_variant:Nn \seq_set_item:Nnn { c }
\cs_generate_variant:Nn \seq_gset_item:Nnn { c }
\prg_new_protected_conditional:Npnn \seq_set_item:Nnn #1#2#3 { TF , T , F }
  { \@@_set_item:NnnNN #1 {#2} {#3} \__kernel_tl_set:Nx \use_ii:nn }
\prg_new_protected_conditional:Npnn \seq_gset_item:Nnn #1#2#3 { TF , T , F }
  { \@@_set_item:NnnNN #1 {#2} {#3} \__kernel_tl_gset:Nx \use_ii:nn }
\prg_generate_conditional_variant:Nnn \seq_set_item:Nnn { c } { TF , T , F }
\prg_generate_conditional_variant:Nnn \seq_gset_item:Nnn { c } { TF , T , F }
%    \end{macrocode}
%   Save the item to be stored and evaluate the position and the sequence
%   length only once.  Then depending on the sign of the position, check
%   that it is not bigger than the length (in absolute value) nor zero.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_item:NnnNN #1#2#3
  {
    \tl_set:Nn \l_@@_tmpa_tl { \@@_item:n {#3} }
    \exp_args:Nff \@@_set_item:nnNNNN
      { \int_eval:n {#2} } { \seq_count:N #1 } #1 \use_none:nn
  }
\cs_new_protected:Npn \@@_set_item:nnNNNN #1#2
  {
    \int_compare:nNnTF {#1} > 0
      { \int_compare:nNnF {#1} > {#2} { \@@_set_item:nNnnNNNN { #1 - 1 } } }
      {
        \int_compare:nNnF {#1} < {-#2}
          {
            \int_compare:nNnF {#1} = 0
              { \@@_set_item:nNnnNNNN { #2 + #1 } }
          }
      }
    \@@_set_item_false:nnNNNN {#1} {#2}
  }
%    \end{macrocode}
%   If the position is not ok, \cs{@@_set_item_false:nnNNNN} calls an
%   error or returns \texttt{false} (depending on the \cs{use_i:nn} vs
%   \cs{use_ii:nn} argument mentioned above).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_item_false:nnNNNN #1#2#3#4#5#6
  {
    #6
      {
        \msg_error:nneee { seq } { item-too-large }
          { \token_to_str:N #3 } {#2} {#1}
      }
      { \prg_return_false: }
  }
%    \end{macrocode}
%   If the position is ok, \cs{@@_set_item:nNnnNNNN} makes the assignment
%   and returns \texttt{true} (in the case of conditionals).  Here |#1|
%   is an integer expression (position minus one), it needs to be
%   evaluated.  The sequence |#5| starts with \cs{s_@@} (even if empty),
%   which stops the integer expression and is absorbed by it.  The
%   \cs{if_meaning:w} test is slightly faster than an integer test (but
%   only works when testing against zero, hence the offset we chose in
%   the position).  When we are done skipping items, insert the saved
%   item \cs{l_@@_tmpa_tl}.  For |put| functions the last argument
%   of \cs{@@_set_item_end:w} is \cs{use_none:nn} and it absorbs the
%   item |#2| that we are removing: this is only useful for the |pop|
%   functions.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_item:nNnnNNNN #1#2#3#4#5#6#7#8
  {
    #7 #5
      {
        \s_@@
        \exp_after:wN \@@_set_item:wn
        \int_value:w \@@_int_eval:w #1
        #5 \s_@@_stop #6
      }
    #8 { } { \prg_return_true: }
  }
\cs_new:Npn \@@_set_item:wn #1 \@@_item:n #2
  {
    \if_meaning:w 0 #1 \@@_set_item_end:w \fi:
    \exp_not:n { \@@_item:n {#2} }
    \exp_after:wN \@@_set_item:wn
    \int_value:w \@@_int_eval:w #1 - 1 \s_@@
  }
\cs_new:Npn \@@_set_item_end:w #1 \exp_not:n #2 #3 \s_@@ #4 \s_@@_stop #5
  {
    #1
    \exp_not:o \l_@@_tmpa_tl
    \exp_not:n {#4}
    #5 #2
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {\seq_reverse:N, \seq_reverse:c, \seq_greverse:N, \seq_greverse:c}
% \begin{macro}{\@@_reverse:NN}
% \begin{macro}[EXP]{\@@_reverse_item:nwn}
%   Previously, \cs{seq_reverse:N} was coded by collecting the items
%   in reverse order after an \cs{exp_stop_f:} marker.
%   \begin{verbatim}
%     \cs_new_protected:Npn \seq_reverse:N #1
%       {
%         \cs_set_eq:NN \@@_item:n \@@_reverse_item:nw
%         \tl_set:Nf #2 { #2 \exp_stop_f: }
%       }
%     \cs_new:Npn \@@_reverse_item:nw #1 #2 \exp_stop_f:
%       {
%         #2 \exp_stop_f:
%         \@@_item:n {#1}
%       }
%   \end{verbatim}
%   At first, this seems optimal, since we can forget about each item
%   as soon as it is placed after \cs{exp_stop_f:}. Unfortunately,
%   \TeX{}'s usual tail recursion does not take place in this case:
%   since the following \cs{@@_reverse_item:nw} only reads
%   tokens until \cs{exp_stop_f:}, and never reads the
%   |\@@_item:n {#1}| left by the previous call, \TeX{} cannot
%   remove that previous call from the stack, and in particular
%   must retain the various macro parameters in memory, until the
%   end of the replacement text is reached. The stack is thus
%   only flushed after all the \cs{@@_reverse_item:nw} are
%   expanded. Keeping track of the arguments of all those calls
%   uses up a memory quadratic in the length of the sequence.
%   \TeX{} can then not cope with more than a few thousand items.
%
%   Instead, we collect the items in the argument
%   of \cs{exp_not:n}. The previous calls are cleanly removed
%   from the stack, and the memory consumption becomes linear.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_reverse:N
  { \@@_reverse:NN \__kernel_tl_set:Nx }
\cs_new_protected:Npn \seq_greverse:N
  { \@@_reverse:NN \__kernel_tl_gset:Nx }
\cs_new_protected:Npn \@@_reverse:NN #1 #2
  {
    \cs_set_eq:NN \@@_tmp:w \@@_item:n
    \cs_set_eq:NN \@@_item:n \@@_reverse_item:nwn
    #1 #2 { #2 \exp_not:n { } }
    \cs_set_eq:NN \@@_item:n \@@_tmp:w
  }
\cs_new:Npn \@@_reverse_item:nwn #1 #2 \exp_not:n #3
  {
    #2
    \exp_not:n { \@@_item:n {#1} #3 }
  }
\cs_generate_variant:Nn \seq_reverse:N  { c }
\cs_generate_variant:Nn \seq_greverse:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_sort:Nn, \seq_sort:cn, \seq_gsort:Nn, \seq_gsort:cn}
%   Implemented in \pkg{l3sort}.
% \end{macro}
%
% \subsection{Sequence conditionals}
%
% \begin{macro}[pTF]{\seq_if_empty:N, \seq_if_empty:c}
% \UnitTested
%   Similar to token lists, we compare with the empty sequence.
%    \begin{macrocode}
\prg_new_conditional:Npnn \seq_if_empty:N #1 { p , T , F , TF }
  {
    \if_meaning:w #1 \c_empty_seq
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
\prg_generate_conditional_variant:Nnn \seq_if_empty:N
  { c } { p , T , F , TF }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_shuffle:N, \seq_shuffle:c, \seq_gshuffle:N, \seq_gshuffle:c}
% \begin{macro}{\@@_shuffle:NN}
% \begin{macro}{\@@_shuffle_item:n}
% \begin{variable}{\g_@@_tmp_seq}
%   We apply the Fisher--Yates shuffle, storing items in \tn{toks}
%   registers.  We use the primitive \cs{tex_uniformdeviate:D} for
%   speed reasons.  Its non-uniformity is of order its argument divided
%   by $2^{28}$, not too bad for small lists.  For sequences with more
%   than $13$ elements there are more possible permutations than
%   possible seeds ($13!>2^{28}$) so the question of uniformity is
%   somewhat moot. The integer variables are declared in \pkg{l3int}:
%   load-order issues.
%    \begin{macrocode}
\seq_new:N \g_@@_tmp_seq
\cs_new_protected:Npn \seq_shuffle:N { \@@_shuffle:NN \seq_set_eq:NN }
\cs_new_protected:Npn \seq_gshuffle:N { \@@_shuffle:NN \seq_gset_eq:NN }
\cs_new_protected:Npn \@@_shuffle:NN #1#2
  {
    \int_compare:nNnTF { \seq_count:N #2 } > \c_max_register_int
      {
        \msg_error:nne { seq } { shuffle-too-large }
          { \token_to_str:N #2 }
      }
      {
        \group_begin:
          \int_zero:N \l_@@_tmpa_int
          \@@_push_item_def:
          \cs_gset_eq:NN \@@_item:n \@@_shuffle_item:n
          #2
          \@@_pop_item_def:
          \seq_gclear:N \g_@@_tmp_seq
          \int_step_inline:nn \l_@@_tmpa_int
            {
              \seq_gput_right:Ne \g_@@_tmp_seq
                { \tex_the:D \tex_toks:D ##1 }
            }
        \group_end:
        #1 #2 \g_@@_tmp_seq
        \seq_gclear:N \g_@@_tmp_seq
    }
  }
\cs_new_protected:Npn \@@_shuffle_item:n
  {
    \int_incr:N \l_@@_tmpa_int
    \int_set:Nn \l_@@_tmpb_int
      { 1 + \tex_uniformdeviate:D \l_@@_tmpa_int }
    \tex_toks:D \l_@@_tmpa_int
      = \tex_toks:D \l_@@_tmpb_int
    \tex_toks:D \l_@@_tmpb_int
  }
\cs_generate_variant:Nn \seq_shuffle:N { c }
\cs_generate_variant:Nn \seq_gshuffle:N { c }
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[TF]
%   {
%     \seq_if_in:Nn, \seq_if_in:NV, \seq_if_in:Nv, \seq_if_in:Ne,
%     \seq_if_in:No, \seq_if_in:Nx,
%     \seq_if_in:cn, \seq_if_in:cV, \seq_if_in:cv,\seq_if_in:ce, 
%     \seq_if_in:co, \seq_if_in:cx
%   }
% \UnitTested
% \begin{macro}{\@@_if_in:}
%   The approach here is to define \cs{@@_item:n} to compare its
%   argument with the test sequence. If the two items are equal, the
%   mapping is terminated and \cs{group_end:} \cs{prg_return_true:}
%   is inserted after skipping over the rest of the recursion. On the
%   other hand, if there is no match then the loop breaks, returning
%   \cs{prg_return_false:}.
%   Everything is inside a group so that \cs{@@_item:n} is preserved
%   in nested situations.
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \seq_if_in:Nn #1#2
  { T , F , TF }
  {
    \group_begin:
      \tl_set:Nn \l_@@_tmpa_tl {#2}
      \cs_set_protected:Npn \@@_item:n ##1
        {
          \tl_set:Nn \l_@@_tmpb_tl {##1}
          \if_meaning:w \l_@@_tmpa_tl \l_@@_tmpb_tl
            \exp_after:wN \@@_if_in:
          \fi:
        }
      #1
    \group_end:
    \prg_return_false:
    \prg_break_point:
  }
\cs_new:Npn \@@_if_in:
  { \prg_break:n { \group_end: \prg_return_true: } }
\prg_generate_conditional_variant:Nnn \seq_if_in:Nn
  { NV , Nv , Ne , No , Nx , c , cV , cv , ce , co , cx } { T , F , TF }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Recovering data from sequences}
%
% \begin{macro}{\@@_pop:NNNN, \@@_pop_TF:NNNN}
%   The two \texttt{pop} functions share their emptiness tests.  We also
%   use a common emptiness test for all branching \texttt{get} and
%   \texttt{pop} functions.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_pop:NNNN #1#2#3#4
  {
    \if_meaning:w #3 \c_empty_seq
      \tl_set:Nn #4 { \q_no_value }
    \else:
      #1#2#3#4
    \fi:
  }
\cs_new_protected:Npn \@@_pop_TF:NNNN #1#2#3#4
  {
    \if_meaning:w #3 \c_empty_seq
      % \tl_set:Nn #4 { \q_no_value }
      \prg_return_false:
    \else:
      #1#2#3#4
      \prg_return_true:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_get_left:NN, \seq_get_left:cN}
% \UnitTested
% \begin{macro}{\@@_get_left:wnw}
%   Getting an item from the left of a sequence is pretty easy: just
%   trim off the first item after \cs{@@_item:n} at the start.  We
%   append a \cs{q_no_value} item to cover the case of an empty sequence
%    \begin{macrocode}
\cs_new_protected:Npn \seq_get_left:NN #1#2
  {
    \__kernel_tl_set:Nx #2
      {
        \exp_after:wN \@@_get_left:wnw
        #1 \@@_item:n { \q_no_value } \s_@@_stop
      }
  }
\cs_new:Npn \@@_get_left:wnw #1 \@@_item:n #2#3 \s_@@_stop
  { \exp_not:n {#2} }
\cs_generate_variant:Nn \seq_get_left:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_pop_left:NN, \seq_pop_left:cN}
% \UnitTested
% \begin{macro}{\seq_gpop_left:NN, \seq_gpop_left:cN}
% \UnitTested
% \begin{macro}{\@@_pop_left:NNN, \@@_pop_left:wnwNNN}
%   The approach to popping an item is pretty similar to that to get
%   an item, with the only difference being that the sequence itself has
%   to be redefined. This makes it more sensible to use an auxiliary
%   function for the local and global cases.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_pop_left:NN
  { \@@_pop:NNNN \@@_pop_left:NNN \tl_set:Nn }
\cs_new_protected:Npn \seq_gpop_left:NN
  { \@@_pop:NNNN \@@_pop_left:NNN \tl_gset:Nn }
\cs_new_protected:Npn \@@_pop_left:NNN #1#2#3
  { \exp_after:wN \@@_pop_left:wnwNNN #2 \s_@@_stop #1#2#3 }
\cs_new_protected:Npn \@@_pop_left:wnwNNN
    #1 \@@_item:n #2#3 \s_@@_stop #4#5#6
  {
    #4 #5 { #1 #3 }
    \tl_set:Nn #6 {#2}
  }
\cs_generate_variant:Nn \seq_pop_left:NN  { c }
\cs_generate_variant:Nn \seq_gpop_left:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_get_right:NN, \seq_get_right:cN}
% \UnitTested
% \begin{macro}[EXP]{\@@_get_right_loop:nw, \@@_get_right_end:NnN}
%   First remove \cs{s_@@} and prepend \cs{q_no_value}.  The first
%   argument of \cs{@@_get_right_loop:nw} is the last item found, and
%   the second argument is empty until the end of the loop, where it is
%   code that applies \cs{exp_not:n} to the last item and ends the loop.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_get_right:NN #1#2
  {
    \__kernel_tl_set:Nx #2
      {
        \exp_after:wN \use_i_ii:nnn
        \exp_after:wN \@@_get_right_loop:nw
        \exp_after:wN \q_no_value
        #1
        \@@_get_right_end:NnN \@@_item:n
      }
  }
\cs_new:Npn \@@_get_right_loop:nw #1#2 \@@_item:n
  {
    #2 \use_none:n {#1}
    \@@_get_right_loop:nw
  }
\cs_new:Npn \@@_get_right_end:NnN #1#2#3 { \exp_not:n {#2} }
\cs_generate_variant:Nn \seq_get_right:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_pop_right:NN, \seq_pop_right:cN}
% \UnitTested
% \begin{macro}{\seq_gpop_right:NN, \seq_gpop_right:cN}
% \UnitTested
% \begin{macro}{\@@_pop_right:NNN, \@@_pop_right_loop:nn}
%   The approach to popping from the right is a bit more involved, but does
%   use some of the same ideas as getting from the right. What is needed is a
%   \enquote{flexible length} way to set a token list variable. This is
%   supplied by the |{ \if_false: } \fi:| \ldots
%   |\if_false: { \fi: }| construct. Using an \texttt{x}-type
%   expansion and a \enquote{non-expanding} definition for \cs{@@_item:n},
%   the left-most $n - 1$ entries in a sequence of $n$ items are stored
%   back in the sequence. That needs a loop of unknown length, hence using the
%   strange \cs{if_false:} way of including braces. When the last item
%   of the sequence is reached, the closing brace for the assignment is
%   inserted, and |\tl_set:Nn #3| is inserted in front of the final
%   entry.  This therefore does the pop assignment.  One more iteration
%   is performed, with an empty argument and \cs{use_none:nn}, which
%   finally stops the loop.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_pop_right:NN
  { \@@_pop:NNNN \@@_pop_right:NNN \__kernel_tl_set:Nx }
\cs_new_protected:Npn \seq_gpop_right:NN
  { \@@_pop:NNNN \@@_pop_right:NNN \__kernel_tl_gset:Nx }
\cs_new_protected:Npn \@@_pop_right:NNN #1#2#3
  {
    \cs_set_eq:NN \@@_tmp:w \@@_item:n
    \cs_set_eq:NN \@@_item:n \scan_stop:
    #1 #2
      { \if_false: } \fi: \s_@@
        \exp_after:wN \use_i:nnn
        \exp_after:wN \@@_pop_right_loop:nn
        #2
        {
          \if_false: { \fi: }
          \__kernel_tl_set:Nx #3
        }
        { } \use_none:nn
    \cs_set_eq:NN \@@_item:n \@@_tmp:w
  }
\cs_new:Npn \@@_pop_right_loop:nn #1#2
  {
    #2 { \exp_not:n {#1} }
    \@@_pop_right_loop:nn
  }
\cs_generate_variant:Nn \seq_pop_right:NN  { c }
\cs_generate_variant:Nn \seq_gpop_right:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[TF]{\seq_get_left:NN, \seq_get_left:cN}
% \begin{macro}[TF]{\seq_get_right:NN, \seq_get_right:cN}
%   Getting from the left or right with a check on the results.  The
%   first argument to \cs{@@_pop_TF:NNNN} is left unused.
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \seq_get_left:NN #1#2 { T , F , TF }
  { \@@_pop_TF:NNNN \prg_do_nothing: \seq_get_left:NN #1#2 }
\prg_new_protected_conditional:Npnn \seq_get_right:NN #1#2 { T , F , TF }
  { \@@_pop_TF:NNNN \prg_do_nothing: \seq_get_right:NN #1#2 }
\prg_generate_conditional_variant:Nnn \seq_get_left:NN
  { c } { T , F , TF }
\prg_generate_conditional_variant:Nnn \seq_get_right:NN
  { c } { T , F , TF }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[TF]{\seq_pop_left:NN, \seq_pop_left:cN}
% \begin{macro}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN}
% \begin{macro}[TF]{\seq_pop_right:NN, \seq_pop_right:cN}
% \begin{macro}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN}
%   More or less the same for popping.
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \seq_pop_left:NN #1#2
  { T , F , TF }
  { \@@_pop_TF:NNNN \@@_pop_left:NNN \tl_set:Nn #1 #2 }
\prg_new_protected_conditional:Npnn \seq_gpop_left:NN #1#2
  { T , F , TF }
  { \@@_pop_TF:NNNN \@@_pop_left:NNN \tl_gset:Nn #1 #2 }
\prg_new_protected_conditional:Npnn \seq_pop_right:NN #1#2
  { T , F , TF }
  { \@@_pop_TF:NNNN \@@_pop_right:NNN \__kernel_tl_set:Nx #1 #2 }
\prg_new_protected_conditional:Npnn \seq_gpop_right:NN #1#2
  { T , F , TF }
  { \@@_pop_TF:NNNN \@@_pop_right:NNN \__kernel_tl_gset:Nx #1 #2 }
\prg_generate_conditional_variant:Nnn \seq_pop_left:NN { c }
  { T , F , TF }
\prg_generate_conditional_variant:Nnn \seq_gpop_left:NN { c }
  { T , F , TF }
\prg_generate_conditional_variant:Nnn \seq_pop_right:NN { c }
  { T , F , TF }
\prg_generate_conditional_variant:Nnn \seq_gpop_right:NN { c }
  { T , F , TF }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {\seq_item:Nn, \seq_item:NV, \seq_item:Ne, \seq_item:cn, \seq_item:cV, \seq_item:ce}
% \begin{macro}{\@@_item:wNn, \@@_item:nN, \@@_item:nwn}
%   The idea here is to find the offset of the item from the left, then use
%   a loop to grab the correct item. If the resulting offset is too large,
%   then the argument delimited by \cs{@@_item:n} is \cs{prg_break:} instead
%   of being empty, terminating the loop and returning nothing at all.
%    \begin{macrocode}
\cs_new:Npn \seq_item:Nn #1
  { \exp_after:wN \@@_item:wNn #1 \s_@@_stop #1 }
\cs_new:Npn \@@_item:wNn \s_@@ #1 \s_@@_stop #2#3
  {
    \exp_args:Nf \@@_item:nwn
      { \exp_args:Nf \@@_item:nN { \int_eval:n {#3} } #2 }
    #1
    \prg_break: \@@_item:n { }
    \prg_break_point:
  }
\cs_new:Npn \@@_item:nN #1#2
  {
    \int_compare:nNnTF {#1} < 0
      { \int_eval:n { \seq_count:N #2 + 1 + #1 } }
      {#1}
  }
\cs_new:Npn \@@_item:nwn #1#2 \@@_item:n #3
  {
    #2
    \int_compare:nNnTF {#1} = 1
      { \prg_break:n { \exp_not:n {#3} } }
      { \exp_args:Nf \@@_item:nwn { \int_eval:n { #1 - 1 } } }
  }
\cs_generate_variant:Nn \seq_item:Nn { NV , Ne , c , cV , ce }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_rand_item:N, \seq_rand_item:c}
%   Importantly, \cs{seq_item:Nn} only evaluates its argument once.
%    \begin{macrocode}
\cs_new:Npn \seq_rand_item:N #1
  {
    \seq_if_empty:NF #1
      { \seq_item:Nn #1 { \int_rand:nn { 1 } { \seq_count:N #1 } } }
  }
\cs_generate_variant:Nn \seq_rand_item:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Mapping over sequences}
%
% \begin{macro}{\seq_map_break:}
% \UnitTested
% \begin{macro}{\seq_map_break:n}
% \UnitTested
%   To break a function, the special token \cs{prg_break_point:Nn} is
%   used to find the end of the code. Any ending code is then inserted
%   before the return value of \cs{seq_map_break:n} is inserted.
%    \begin{macrocode}
\cs_new:Npn \seq_map_break:
  { \prg_map_break:Nn \seq_map_break: { } }
\cs_new:Npn \seq_map_break:n
  { \prg_map_break:Nn \seq_map_break: }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_map_function:NN, \seq_map_function:cN}
% \UnitTested
% \begin{macro}[rEXP]{\@@_map_function:Nw}
%   The idea here is to apply the code of |#2| to each item in the
%   sequence without altering the definition of \cs{@@_item:n}.  The
%   even-numbered arguments of \cs{@@_map_function:Nw} delimited by
%   \cs{@@_item:n} are almost always empty, except
%   at the end of the loop where it is \cs{prg_break:}.  This allows to
%   break the loop without needing to do a (relatively-expensive) quark
%   test.
%    \begin{macrocode}
\cs_new:Npn \seq_map_function:NN #1#2
  {
    \exp_after:wN \use_i_ii:nnn
    \exp_after:wN \@@_map_function:Nw
    \exp_after:wN #2
    #1
    \prg_break:
    \@@_item:n { } \@@_item:n { } \@@_item:n { } \@@_item:n { }
    \prg_break_point:
    \prg_break_point:Nn \seq_map_break: { }
  }
\cs_new:Npn \@@_map_function:Nw #1
    #2 \@@_item:n #3
    #4 \@@_item:n #5
    #6 \@@_item:n #7
    #8 \@@_item:n #9
  {
    #2 #1 {#3}
    #4 #1 {#5}
    #6 #1 {#7}
    #8 #1 {#9}
    \@@_map_function:Nw #1
  }
\cs_generate_variant:Nn \seq_map_function:NN { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_push_item_def:n, \@@_push_item_def:e}
% \begin{macro}{\@@_push_item_def:}
% \begin{macro}{\@@_pop_item_def:}
%   The definition of \cs{@@_item:n} needs to be saved and restored at
%   various points within the mapping and manipulation code. That is handled
%   here: as always, this approach uses global assignments.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_push_item_def:n
  {
    \@@_push_item_def:
    \cs_gset:Npn \@@_item:n ##1
  }
\cs_new_protected:Npn \@@_push_item_def:e
  {
    \@@_push_item_def:
    \cs_gset:Npe \@@_item:n ##1
  }
\cs_new_protected:Npn \@@_push_item_def:
  {
    \int_gincr:N \g__kernel_prg_map_int
    \cs_gset_eq:cN { @@_map_ \int_use:N \g__kernel_prg_map_int :w }
      \@@_item:n
  }
\cs_new_protected:Npn \@@_pop_item_def:
  {
    \cs_gset_eq:Nc \@@_item:n
      { @@_map_ \int_use:N \g__kernel_prg_map_int :w }
    \int_gdecr:N \g__kernel_prg_map_int
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_map_inline:Nn, \seq_map_inline:cn}
% \UnitTested
%   The idea here is that \cs{@@_item:n} is already \enquote{applied} to
%   each item in a sequence, and so an in-line mapping is just a case of
%   redefining \cs{@@_item:n}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_map_inline:Nn #1#2
  {
    \@@_push_item_def:n {#2}
    #1
    \prg_break_point:Nn \seq_map_break: { \@@_pop_item_def: }
  }
\cs_generate_variant:Nn \seq_map_inline:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_map_tokens:Nn, \seq_map_tokens:cn}
% \begin{macro}{\@@_map_tokens:nw}
%   This is based on the function mapping but using the same tricks as
%   described for \cs{prop_map_tokens:Nn}. The idea is to remove the leading
%   \cs{s_@@} and apply the tokens such that they are safe with the
%   break points, hence the \cs{use:n}.
%    \begin{macrocode}
\cs_new:Npn \seq_map_tokens:Nn #1#2
  {
    \exp_last_unbraced:Nno
      \use_i:nn { \@@_map_tokens:nw {#2} } #1
    \prg_break:
    \@@_item:n { } \@@_item:n { } \@@_item:n { } \@@_item:n { }
    \prg_break_point:
    \prg_break_point:Nn \seq_map_break: { }
  }
\cs_generate_variant:Nn \seq_map_tokens:Nn { c }
\cs_new:Npn \@@_map_tokens:nw #1
    #2 \@@_item:n #3
    #4 \@@_item:n #5
    #6 \@@_item:n #7
    #8 \@@_item:n #9
  {
    #2 \use:n {#1} {#3}
    #4 \use:n {#1} {#5}
    #6 \use:n {#1} {#7}
    #8 \use:n {#1} {#9}
    \@@_map_tokens:nw {#1}
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_map_variable:NNn, \seq_map_variable:Ncn,
%     \seq_map_variable:cNn, \seq_map_variable:ccn
%   }
% \UnitTested
%   This is just a specialized version of the in-line mapping function,
%   using an \texttt{e}-type expansion for the code set up so that the
%   number of |#| tokens required is as expected.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_map_variable:NNn #1#2#3
  {
    \@@_push_item_def:e
      {
        \tl_set:Nn \exp_not:N #2 {##1}
        \exp_not:n {#3}
      }
    #1
    \prg_break_point:Nn \seq_map_break: { \@@_pop_item_def: }
  }
\cs_generate_variant:Nn \seq_map_variable:NNn {     Nc }
\cs_generate_variant:Nn \seq_map_variable:NNn { c , cc }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_sep:}
%    \begin{macrocode}
\cs_new_eq:NN \@@_sep: \__kernel_int_sep:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_map_indexed_function:NN, \seq_map_indexed_inline:Nn,
%     \@@_map_indexed:nNN, \@@_map_indexed:Nw
%   }
%   Similar to \cs{seq_map_function:NN} but we keep track of the item
%   index as a |;|-delimited argument of \cs{@@_map_indexed:Nw}.
%    \begin{macrocode}
\cs_new:Npn \seq_map_indexed_function:NN #1#2
  {
    \@@_map_indexed:NN #1#2
    \prg_break_point:Nn \seq_map_break: { }
  }
\cs_new_protected:Npn \seq_map_indexed_inline:Nn #1#2
  {
    \int_gincr:N \g__kernel_prg_map_int
    \cs_gset_protected:cpn
      { @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1##2 {#2}
    \exp_args:NNc \@@_map_indexed:NN #1
      { @@_map_ \int_use:N \g__kernel_prg_map_int :w }
    \prg_break_point:Nn \seq_map_break:
      { \int_gdecr:N \g__kernel_prg_map_int }
  }
\cs_new:Npn \@@_map_indexed:NN #1#2
  {
    \exp_after:wN \@@_map_indexed:Nw
    \exp_after:wN #2
    \int_value:w 1
    \exp_after:wN \use_i:nn
    \exp_after:wN \@@_sep:
    #1
    \prg_break: \@@_item:n { } \prg_break_point:
  }
\cs_new:Npn \@@_map_indexed:Nw #1#2 \@@_sep: #3 \@@_item:n #4
  {
    #3
    #1 {#2} {#4}
    \exp_after:wN \@@_map_indexed:Nw
    \exp_after:wN #1
    \int_value:w \int_eval:w 1 + #2 \@@_sep:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_map_pairwise_function:NNN, \seq_map_pairwise_function:NcN,
%     \seq_map_pairwise_function:cNN, \seq_map_pairwise_function:ccN
%   }
% \begin{macro}
%   {
%     \@@_map_pairwise_function:wNN, \@@_map_pairwise_function:wNw,
%     \@@_map_pairwise_function:Nnnwnn
%   }
%   The idea is to first expand both sequences, adding the
%   usual |{ ? \prg_break: } { }| to the end of each one.  This is
%   most conveniently done in two steps using an auxiliary function.
%   The mapping then throws away the first tokens of |#2| and |#5|,
%   which for items in both sequences are \cs{s_@@}
%   \cs{@@_item:n}.  The function to be mapped are then be applied to
%   the two entries.  When the code hits the end of one of the
%   sequences, the break material stops the entire loop and tidy up.
%   This avoids needing to find the count of the two sequences, or
%   worrying about which is longer.
%    \begin{macrocode}
\cs_new:Npn \seq_map_pairwise_function:NNN #1#2#3
  { \exp_after:wN \@@_map_pairwise_function:wNN #2 \s_@@_stop #1 #3 }
\cs_new:Npn \@@_map_pairwise_function:wNN \s_@@ #1 \s_@@_stop #2#3
  {
    \exp_after:wN \@@_map_pairwise_function:wNw #2 \s_@@_stop #3
      #1 { ? \prg_break: } { }
    \prg_break_point:
    \prg_break_point:Nn \seq_map_break: { }
  }
\cs_new:Npn \@@_map_pairwise_function:wNw \s_@@ #1 \s_@@_stop #2
  {
    \@@_map_pairwise_function:Nnnwnn #2
      #1 { ? \prg_break: } { }
    \s_@@_stop
  }
\cs_new:Npn \@@_map_pairwise_function:Nnnwnn #1#2#3#4 \s_@@_stop #5#6
  {
    \use_none:n #2
    \use_none:n #5
    #1 {#3} {#6}
    \@@_map_pairwise_function:Nnnwnn #1 #4 \s_@@_stop
  }
\cs_generate_variant:Nn \seq_map_pairwise_function:NNN { Nc , c , cc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_map_e:NNn, \seq_gset_map_e:NNn}
% \begin{macro}{\@@_set_map_e:NNNn}
%   Very similar to \cs{seq_set_filter:NNn}. We could actually
%   merge the two within a single function, but it would have weird
%   semantics.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_map_e:NNn
  { \@@_set_map_e:NNNn \__kernel_tl_set:Nx }
\cs_new_protected:Npn \seq_gset_map_e:NNn
  { \@@_set_map_e:NNNn \__kernel_tl_gset:Nx }
\cs_new_protected:Npn \@@_set_map_e:NNNn #1#2#3#4
  {
    \@@_push_item_def:n { \exp_not:N \@@_item:n {#4} }
    #1 #2 { #3 }
    \@@_pop_item_def:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_map:NNn, \seq_gset_map:NNn}
% \begin{macro}{\@@_set_map:NNNn}
%   Similar to \cs{seq_set_map_e:NNn}, but prevents expansion of the
%   <inline function>.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_map:NNn
  { \@@_set_map:NNNn \__kernel_tl_set:Nx }
\cs_new_protected:Npn \seq_gset_map:NNn
  { \@@_set_map:NNNn \__kernel_tl_gset:Nx }
\cs_new_protected:Npn \@@_set_map:NNNn #1#2#3#4
  {
    \@@_push_item_def:n { \exp_not:n { \@@_item:n {#4} } }
    #1 #2 { #3 }
    \@@_pop_item_def:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_count:N, \seq_count:c}
% \begin{macro}{\@@_count:w, \@@_count_end:w}
%   Since counting the items in a sequence is quite common, we optimize
%   it by grabbing $8$~items at a time and correspondingly adding $8$ to
%   an integer expression.  At the end of the loop, |#9| is
%   \cs{@@_count_end:w} instead of being empty.  It removes |8+| and
%   instead places the number of \cs{@@_item:n} that \cs{@@_count:w}
%   grabbed before reaching the end of the sequence.
%    \begin{macrocode}
\cs_new:Npn \seq_count:N #1
  {
    \int_eval:n
      {
        \exp_after:wN \use_i:nn
        \exp_after:wN \@@_count:w
        #1
        \@@_count_end:w \@@_item:n 7
        \@@_count_end:w \@@_item:n 6
        \@@_count_end:w \@@_item:n 5
        \@@_count_end:w \@@_item:n 4
        \@@_count_end:w \@@_item:n 3
        \@@_count_end:w \@@_item:n 2
        \@@_count_end:w \@@_item:n 1
        \@@_count_end:w \@@_item:n 0
        \prg_break_point:
      }
  }
\cs_new:Npn \@@_count:w
    #1 \@@_item:n #2 \@@_item:n #3 \@@_item:n #4 \@@_item:n
    #5 \@@_item:n #6 \@@_item:n #7 \@@_item:n #8 #9 \@@_item:n
  { #9 8 + \@@_count:w }
\cs_new:Npn \@@_count_end:w 8 + \@@_count:w #1#2 \prg_break_point: {#1}
\cs_generate_variant:Nn \seq_count:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Using sequences}
%
% \begin{macro}[EXP]{\seq_use:Nnnn, \seq_use:cnnn}
% \begin{macro}[EXP]
%   {\@@_use:NNnNnn, \@@_use_setup:w, \@@_use:nwwwwnwn, \@@_use:nwwn}
% \begin{macro}[EXP]{\seq_use:Nn, \seq_use:cn}
%   See \cs{clist_use:Nnnn} for a general explanation.  The main
%   difference is that we use \cs{@@_item:n} as a delimiter rather than
%   commas.  We also need to add \cs{@@_item:n} at various places, and
%   \cs{s_@@}.
%    \begin{macrocode}
\cs_new:Npn \seq_use:Nnnn #1#2#3#4
  {
    \seq_if_exist:NTF #1
      {
        \int_case:nnF { \seq_count:N #1 }
          {
            { 0 } { }
            { 1 } { \exp_after:wN \@@_use:NNnNnn #1 ? { } { } }
            { 2 } { \exp_after:wN \@@_use:NNnNnn #1 {#2} }
          }
          {
            \exp_after:wN \@@_use_setup:w #1 \@@_item:n
            \s_@@_mark { \@@_use:nwwwwnwn {#3} }
            \s_@@_mark { \@@_use:nwwn {#4} }
            \s_@@_stop { }
          }
      }
      {
        \msg_expandable_error:nnn
          { kernel } { bad-variable } {#1}
      }
  }
\cs_generate_variant:Nn \seq_use:Nnnn { c }
\cs_new:Npn \@@_use:NNnNnn #1#2#3#4#5#6 { \exp_not:n { #3 #6 #5 } }
\cs_new:Npn \@@_use_setup:w \s_@@ { \@@_use:nwwwwnwn { } }
\cs_new:Npn \@@_use:nwwwwnwn
    #1 \@@_item:n #2 \@@_item:n #3 \@@_item:n #4#5
    \s_@@_mark #6#7 \s_@@_stop #8
  {
    #6 \@@_item:n {#3} \@@_item:n {#4} #5
    \s_@@_mark {#6} #7 \s_@@_stop { #8 #1 #2 }
  }
\cs_new:Npn \@@_use:nwwn #1 \@@_item:n #2 #3 \s_@@_stop #4
  { \exp_not:n { #4 #1 #2 } }
\cs_new:Npn \seq_use:Nn #1#2
  { \seq_use:Nnnn #1 {#2} {#2} {#2} }
\cs_generate_variant:Nn \seq_use:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Sequence stacks}
%
% The same functions as for sequences, but with the correct naming.
%
% \begin{macro}{
%     \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:Ne,
%     \seq_push:No, \seq_push:Nx,
%     \seq_push:cn, \seq_push:cV, \seq_push:cv,  \seq_push:ce,
%     \seq_push:co, \seq_push:cx
% }
% \UnitTested
% \begin{macro}{
%     \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv,  \seq_gpush:Ne,
%     \seq_gpush:No, \seq_gpush:Nx,
%     \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv,  \seq_gpush:ce,
%     \seq_gpush:co, \seq_gpush:cx
% }
% \UnitTested
%   Pushing to a sequence is the same as adding on the left.
%    \begin{macrocode}
\cs_new_eq:NN \seq_push:Nn \seq_put_left:Nn
\cs_generate_variant:Nn \seq_push:Nn { NV , Nv , Ne , c , cV , cv , ce }
\cs_generate_variant:Nn \seq_push:Nn { No , Nx , co , cx }
\cs_new_eq:NN \seq_gpush:Nn \seq_gput_left:Nn
\cs_generate_variant:Nn \seq_gpush:Nn { NV , Nv , Ne , c , cV , cv , ce }
\cs_generate_variant:Nn \seq_gpush:Nn { No , Nx , co , cx }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_get:NN, \seq_get:cN}
% \UnitTested
% \begin{macro}{\seq_pop:NN, \seq_pop:cN}
% \UnitTested
% \begin{macro}{\seq_gpop:NN, \seq_gpop:cN}
% \UnitTested
%   In most cases, getting items from the stack does not need to specify
%   that this is from the left. So alias are provided.
%    \begin{macrocode}
\cs_new_eq:NN \seq_get:NN \seq_get_left:NN
\cs_new_eq:NN \seq_get:cN \seq_get_left:cN
\cs_new_eq:NN \seq_pop:NN \seq_pop_left:NN
\cs_new_eq:NN \seq_pop:cN \seq_pop_left:cN
\cs_new_eq:NN \seq_gpop:NN \seq_gpop_left:NN
\cs_new_eq:NN \seq_gpop:cN \seq_gpop_left:cN
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[TF]{\seq_get:NN, \seq_get:cN}
% \begin{macro}[TF]{\seq_pop:NN, \seq_pop:cN}
% \begin{macro}[TF]{\seq_gpop:NN, \seq_gpop:cN}
%   More copies.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \seq_get:NN  \seq_get_left:NN  { T , F , TF }
\prg_new_eq_conditional:NNn \seq_get:cN  \seq_get_left:cN  { T , F , TF }
\prg_new_eq_conditional:NNn \seq_pop:NN  \seq_pop_left:NN  { T , F , TF }
\prg_new_eq_conditional:NNn \seq_pop:cN  \seq_pop_left:cN  { T , F , TF }
\prg_new_eq_conditional:NNn \seq_gpop:NN \seq_gpop_left:NN { T , F , TF }
\prg_new_eq_conditional:NNn \seq_gpop:cN \seq_gpop_left:cN { T , F , TF }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Viewing sequences}
%
% \begin{macro}{\seq_show:N, \seq_show:c, \seq_log:N, \seq_log:c, \@@_show:NN}
% \begin{macro}[rEXP]{\@@_show_validate:nn}
% \UnitTested
%   Apply the general \cs{__kernel_chk_tl_type:NnnT}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_show:N { \@@_show:NN \msg_show:nneeee }
\cs_generate_variant:Nn \seq_show:N { c }
\cs_new_protected:Npn \seq_log:N { \@@_show:NN \msg_log:nneeee }
\cs_generate_variant:Nn \seq_log:N { c }
\cs_new_protected:Npn \@@_show:NN #1#2
  {
    \__kernel_chk_tl_type:NnnT #2 { seq }
      {
        \s_@@
        \exp_after:wN \use_i:nn \exp_after:wN \@@_show_validate:nn #2
        \q_recursion_tail \q_recursion_tail \q_recursion_stop
      }
      {
        #1 { seq } { show }
          { \token_to_str:N #2 }
          { \seq_map_function:NN #2 \msg_show_item:n }
          { } { }
      }
  }
\cs_new:Npn \@@_show_validate:nn #1#2
  {
    \quark_if_recursion_tail_stop:n {#2}
    \@@_wrap_item:n {#2}
    \@@_show_validate:nn
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Scratch sequences}
%
% \begin{variable}{\l_tmpa_seq, \l_tmpb_seq, \g_tmpa_seq, \g_tmpb_seq}
%   Temporary comma list variables.
%    \begin{macrocode}
\seq_new:N \l_tmpa_seq
\seq_new:N \l_tmpb_seq
\seq_new:N \g_tmpa_seq
\seq_new:N \g_tmpb_seq
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%</code>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
