% \iffalse
%% File: l3prop.dtx Copyright (C) 1990-2009 LaTeX3 project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the ``expl3 bundle'' (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
\RequirePackage{l3names}
%</driver|package>
%\fi
\GetIdInfo$Id: l3prop.dtx 1857 2010-03-21 21:32:09Z joseph $
          {L3 Experimental Property Lists}
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\filename.\filenameext}
  [\filedate\space v\fileversion\space\filedescription]
%\iffalse
\documentclass[full]{l3doc}
\begin{document}
\DocInput{\filename.\filenameext}
\end{document}
%</driver>
% \fi
%
%
% \title{The \textsf{l3prop} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}\\
% Property Lists}
% \author{\Team}
% \date{\filedate}
% \maketitle
%
% \def\propkey{key}
% \def\propval{info}
% \def\proplist{prop}
%
% \begin{documentation}
%
% \LaTeX3 implements a data structure called a `property list' which allows 
% arbitrary information to be stored and accessed using keywords rather than
% numerical indexing.
%
% A property list might contain a set of keys such as "name", "age", and "ID",
% which each have individual values that can be saved and retrieved.
%
% \section{Functions}
%
% \begin{function}{%
%                  \prop_new:N |
%                  \prop_new:c |
% }
% \begin{syntax}
%    "\prop_new:N" <\proplist>
% \end{syntax}
% Defines <\proplist> to be a variable of type \meta{\proplist}.
% \end{function}
%
% \begin{function}{%
%                  \prop_clear:N |
%                  \prop_clear:c |
%                  \prop_gclear:N |
%                  \prop_gclear:c |
% }
% \begin{syntax}
%   "\prop_clear:N"  <\proplist>
% \end{syntax}
% These functions locally or globally clear <\proplist>.
% \end{function}
%
% \begin{function}{%
%                  \prop_put:Nnn |
%                  \prop_put:NnV |
%                  \prop_put:NVn |
%                  \prop_put:NVV |
%                  \prop_put:cnn |
%                  \prop_gput:Nnn |
%                  \prop_gput:NVn |
%                  \prop_gput:Nno |
%                  \prop_gput:NnV |
%                  \prop_gput:Nnx |
%                  \prop_gput:cnn |
%                  \prop_gput:ccx |
% }
% \begin{syntax}
%   "\prop_put:Nnn" <\proplist> \Arg{\propkey} \Arg{token list}
% \end{syntax}
% Locally or globally associates <token list> with <\propkey> in the <\proplist>
% <\proplist>. If <\propkey> has already a meaning within <\proplist> this value is
% overwritten.
%
% The <\propkey> must not contain unescaped "#" tokens but the <token list> may.
% \end{function}
%
% \begin{function}{%
%                  \prop_gput_if_new:Nnn |
% }
% \begin{syntax}
%   "\prop_gput_if_new:Nnn" <\proplist> \Arg{\propkey} \Arg{token list}
% \end{syntax}
% Globally associates <token list> with <\propkey> in the <\proplist>
% <\proplist> but only if <\propkey> has so far no meaning within <\proplist>.
% Silently ignored if <\propkey> is already set in the <\proplist>.
% \end{function}
%
% \begin{function}{%
%                  \prop_get:NnN |
%                  \prop_get:NVN |
%                  \prop_get:cnN |
%                  \prop_get:cVN |
%                  \prop_gget:NnN |
%                  \prop_gget:NVN |
%                  \prop_gget:cnN |
%                  \prop_gget:cVN |
% }
% \begin{syntax}
%    "\prop_get:NnN" <\proplist> \Arg{\propkey} <tl var.>
% \end{syntax}
% If <\propval> is the information associated with <\propkey> in the <\proplist>
% <\proplist> then the token list variable <tl var.> gets <\propval> assigned.
% Otherwise its value is the special quark "\q_no_value".
%^^A See section \ref{sec:quarks} to test this.
% The assignment is done either locally or globally.
% \end{function}
%
% \begin{function}{ \prop_set_eq:NN  |
%                   \prop_set_eq:cN  |
%                   \prop_set_eq:Nc  |
%                   \prop_set_eq:cc  |
%                   \prop_gset_eq:NN |
%                   \prop_gset_eq:cN |
%                   \prop_gset_eq:Nc |
%                   \prop_gset_eq:cc }
% \begin{syntax}
%    "\prop_set_eq:NN" <\proplist 1> <\proplist 2>
% \end{syntax}
% A fast assignment of <\proplist>s.
% \end{function}
%
% \begin{function}{%
%                  \prop_get_gdel:NnN |
% }
% \begin{syntax}
%    "\prop_get_gdel:NnN" <\proplist> \Arg{\propkey} <tl var.>
% \end{syntax}
% Like "\prop_get:NnN" but additionally removes <\propkey> (and its <\propval>)
% from <\proplist>.
% \end{function}
%
% \begin{function}{%
%                  \prop_del:Nn |
%                  \prop_del:NV |
%                  \prop_gdel:Nn |
%                  \prop_gdel:NV |
% }
% \begin{syntax}
%    "\prop_del:Nn" <\proplist> \Arg{\propkey}
% \end{syntax}
% Locally or globally deletes <\propkey> and its <\propval> from <\proplist> if
% found. Otherwise does nothing.
% \end{function}
%
%
% \begin{function}{ \prop_map_function:NN / (EXP) | 
%                   \prop_map_function:cN / (EXP) |
%                   \prop_map_function:Nc / (EXP) |
%                   \prop_map_function:cc / (EXP) }
% \begin{syntax}
%   "\prop_map_function:NN" <\proplist> <function>
% \end{syntax}
% Maps <function> which should be a function with two arguments (<\propkey>
% and <\propval>) over every <\propkey> <\propval> pair of <\proplist>. 
% Property lists do not have any intrinsic ``order'' when stored. As a 
% result, you should not expect any particular order to apply when using
% these mapping functions, even with newly-created properly lists. 
% \end{function}
%
% \begin{function}{\prop_map_inline:Nn |
%                  \prop_map_inline:cn
% }
% \begin{syntax}
%   "\prop_map_inline:Nn" <\proplist> \Arg{inline function}
% \end{syntax}
% Just like "\prop_map_function:NN" but with the function of two arguments
% supplied as inline code. Within <inline function> refer to the
% arguments via "#1" (<\propkey>) and "#2" (<\propval>). Nestable.
% Property lists do not have any intrinsic ``order'' when stored. As a 
% result, you should not expect any particular order to apply when using
% these mapping functions, even with newly-created properly lists. 
% \end{function}
%
%
% \begin{function}{%
%                  \prop_map_break: |
% }
% \begin{syntax}
%    "\prop_map_inline:Nn" \meta{\proplist} "{"\\
%    "  ... \"\meta{break test}":T {\prop_map_break:} }"
% \end{syntax}
% For breaking out of a loop. To be used inside "TF"-type functions as shown
% in the example above.
% \end{function}
%
% \begin{function}{ \prop_show:N |
%                   \prop_show:c }
% \begin{syntax}
%    "\prop_show:N" <\proplist>
% \end{syntax}
% Pauses the compilation and shows <\proplist> on the terminal output and 
% in the log file.
% \end{function}
%
% \begin{function}{ \prop_display:N |
%                   \prop_display:c }
% \begin{syntax}
%   "\prop_display:N" <prop>
% \end{syntax}
% As with "\prop_show:N" but pretty prints the output one line per property pair.
% \end{function}
%
%
% \section{Predicates and conditionals}
%
% \begin{function}{ \prop_if_empty_p:N |
%                   \prop_if_empty_p:c }
% \begin{syntax}
%   "\prop_if_empty_p:N" <\proplist> \Arg{true code} \Arg{false code}
% \end{syntax}
% Predicates to test whether or not a particular <\proplist> is empty.
% \end{function}
%
% \begin{function}{ \prop_if_empty:N / (TF)(EXP) |
%                   \prop_if_empty:c / (TF)(EXP) }
% \begin{syntax}
%   "\prop_if_empty:NTF" <\proplist> \Arg{true code} \Arg{false code}
% \end{syntax}
% Set of conditionals that test whether or not a particular <\proplist>
% is empty.
% \end{function}
%
% \begin{function}{
%                  \prop_if_eq_p:NN / (EXP) |
%                  \prop_if_eq_p:cN / (EXP) |
%                  \prop_if_eq_p:Nc / (EXP) |
%                  \prop_if_eq_p:cc / (EXP) |
%                  \prop_if_eq:NN / (EXP)(TF) |
%                  \prop_if_eq:cN / (EXP)(TF) |
%                  \prop_if_eq:Nc / (EXP)(TF) |
%                  \prop_if_eq:cc / (EXP)(TF) |
%                  }
% \begin{syntax}
%   "\prop_if_eq:NNF" <\proplist 1> <\proplist 2> \Arg{false code}
% \end{syntax}
% Execute <false code> if <\proplist 1> doesn't hold the same token list as
% <\proplist 2>. Only expandable for new versions of pdf\TeX.
% \end{function}
%
%
% \begin{function}{%
%                  \prop_if_in:Nn / (TF) |
%                  \prop_if_in:NV / (TF) |
%                  \prop_if_in:No / (TF) |
%                  \prop_if_in:cn / (TF) |
%                  \prop_if_in:cc / (TF) |
% }
% \begin{syntax}
%   "\prop_if_in:NnTF" <\proplist> \Arg{\propkey} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if <\propkey> is used in <\proplist> and then either executes <true code>
% or <false code>.
% \end{function}
%
% \section{Internal functions}
%
% \begin{function}{\q_prop}
% Quark used to delimit property lists internally.
% \end{function}
%
% \begin{function}{%
%                  \prop_put_aux:w |
%                  \prop_put_if_new_aux:w |
% }
% Internal functions implementing the put operations.
% \end{function}
%
% \begin{function}{%
%                  \prop_get_aux:w |
%                  \prop_gget_aux:w |
%                  \prop_get_del_aux:w |
%                  \prop_del_aux:w |
% }
% Internal functions implementing the get and delete operations.
% \end{function}
%
% \begin{function}{%
%                  \prop_if_in_aux:w |
% }
% Internal function implementing the key test operation.
% \end{function}
%
% \begin{function}{%
%                  \prop_map_function_aux:w |
% }
% Internal function implementing the map operations.
% \end{function}
%
% \begin{function}{%
%                  \g_prop_inline_level_int |
% }
% Integer used in internal name for function used inside
% "\prop_map_inline:NN".
% \end{function}
%
% \begin{function}{\prop_split_aux:Nnn}
% \begin{syntax}
%   "\prop_split_aux:Nnn" <\proplist> <\propkey> <cmd>
% \end{syntax}
% Internal function that invokes <cmd> with 3 arguments: 1st is the
% beginning of <\proplist> before <\propkey>, 2nd is the value associated with
% <\propkey>, 3rd is the rest of <\proplist> after <\propkey>.  If there is no key
% <\propkey> in <\proplist>, then the 2 arg is "\q_no_value" and the 3rd arg is
% empty; otherwise the 3rd argument has the two extra tokens <\propkey>
% "\q_no_value" at the end.
%
% This function is used to implement various get operations.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3prop} implementation}
%
% A property list is a token register whose contents is
% of the form\par
% {\centering|\q_prop| \meta{\propkey$\sb1$} |\q_prop| \marg{\propval$\sb1$} \ldots{}
% |\q_prop| \meta{\propkey$\sb n$} |\q_prop| \marg{\propval$\sb n$}\par}
%
% The property \m{\propkey}s and \m{\propval}s might be arbitrary token lists; each
% \m{\propval} is surrounded by braces.
%
%    We start by ensuring that the required packages are loaded.
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\filename}{\filedate}{\fileversion}{\filedescription}
\package_check_loaded_expl:
%</package>
%<*initex|package>
%    \end{macrocode}
%
% \begin{macro}{\q_prop}
% The separator between \m{\propkey}s and \m{\propval}s and \m{\propkey}s.
%    \begin{macrocode}
\quark_new:N\q_prop
%    \end{macrocode}
% \end{macro}
%
% To get values from property-lists, token lists should be passed to
% the appropriate functions.
%
% \subsection{Functions}
%
% \begin{macro}{\prop_new:N}
% \begin{macro}{\prop_new:c}
%    Property lists are implemented as token registers.
%    \begin{macrocode}
\cs_new_eq:NN \prop_new:N \toks_new:N
\cs_new_eq:NN \prop_new:c \toks_new:c
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_clear:N}
% \begin{macro}{\prop_clear:c}
% \begin{macro}{\prop_gclear:N}
% \begin{macro}{\prop_gclear:c}
%    The same goes for clearing a property list, either
%    locally or globally.
%    \begin{macrocode}
\cs_new_eq:NN \prop_clear:N  \toks_clear:N
\cs_new_eq:NN \prop_clear:c  \toks_clear:c
\cs_new_eq:NN \prop_gclear:N \toks_gclear:N
\cs_new_eq:NN \prop_gclear:c \toks_gclear:c
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_set_eq:NN}
% \begin{macro}{\prop_set_eq:Nc}
% \begin{macro}{\prop_set_eq:cN}
% \begin{macro}{\prop_set_eq:cc}
% \begin{macro}{\prop_gset_eq:NN}
% \begin{macro}{\prop_gset_eq:Nc}
% \begin{macro}{\prop_gset_eq:cN}
% \begin{macro}{\prop_gset_eq:cc}
%    This makes two \m{\proplist}s have the same contents.
%    \begin{macrocode}
\cs_new_eq:NN \prop_set_eq:NN  \toks_set_eq:NN
\cs_new_eq:NN \prop_set_eq:Nc  \toks_set_eq:Nc
\cs_new_eq:NN \prop_set_eq:cN  \toks_set_eq:cN
\cs_new_eq:NN \prop_set_eq:cc  \toks_set_eq:cc
\cs_new_eq:NN \prop_gset_eq:NN \toks_gset_eq:NN
\cs_new_eq:NN \prop_gset_eq:Nc \toks_gset_eq:Nc
\cs_new_eq:NN \prop_gset_eq:cN \toks_gset_eq:cN
\cs_new_eq:NN \prop_gset_eq:cc \toks_gset_eq:cc
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_show:N}
% \begin{macro}{\prop_show:c}
% Show on the console the raw contents of a property list's token register.
%    \begin{macrocode}
\cs_new_eq:NN \prop_show:N \toks_show:N
\cs_new_eq:NN \prop_show:c \toks_show:c
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_display:N}
% \begin{macro}{\prop_display:c}
% Pretty print the contents of a property list on the console.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \prop_display:N #1 {
  \iow_term:x { Property-list~\token_to_str:N #1~contains~
                   the~pairs~(without~outer~braces): }
  \toks_clear:N \l_tmpa_toks
  \prop_map_inline:Nn #1 {
    \toks_if_empty:NF  \l_tmpa_toks {
      \toks_put_right:Nx \l_tmpa_toks {^^J>~}
    }
    \toks_put_right:Nx \l_tmpa_toks {
      \c_space_tl \iow_char:N \{ \exp_not:n {##1} \iow_char:N \} \c_space_tl
      \c_space_tl => \c_space_tl
      \c_space_tl \iow_char:N \{ \exp_not:n {##2} \iow_char:N \}
    }
  }
  \toks_show:N \l_tmpa_toks
}
\cs_generate_variant:Nn \prop_display:N {c}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\prop_split_aux:Nnn}
%   |\prop_split_aux:Nnn|\meta{\proplist}\meta{\propkey}\meta{cmd} invokes \meta{cmd}
%   with 3 arguments: 1st is the beginning of \meta{\proplist} before
%   \meta{\propkey}, 2nd is the value associated with \meta{\propkey}, 3rd is the
%   rest of \meta{\proplist} after \meta{\propkey}.  If there is no property
%   \meta{\propkey} in \meta{\proplist}, then the 2nd argument will be |\q_no_value|
%   and the 3rd argument is empty; otherwise the 3rd argument has the 
%   extra tokens  |\q_prop| \meta{\propkey} |\q_prop| |\q_no_value| at the end.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_split_aux:Nnn #1#2#3{
  \cs_set:Npn \prop_tmp:w ##1 \q_prop #2 \q_prop ##2##3 \q_stop { 
    #3 {##1}{##2}{##3} 
  }
  \exp_after:wN \prop_tmp:w \toks_use:N #1 \q_prop #2 \q_prop \q_no_value \q_stop
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\prop_get:NnN}
% \begin{macro}{\prop_get:NVN}
% \begin{macro}{\prop_get:cnN}
% \begin{macro}{\prop_get:cVN}
% \begin{macro}{\prop_get_aux:w}
%    |\prop_get:NnN |\meta{\proplist}\meta{\propkey}\meta{tl var.}~defines
%    \meta{tl var.}~to be the value associated with \meta{\propkey} in \meta{\proplist},
%    |\q_no_value| if not found.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_get:NnN #1#2 {
  \prop_split_aux:Nnn #1{#2}\prop_get_aux:w
}
\cs_new_protected:Npn \prop_get_aux:w #1#2#3#4 { \tl_set:Nn #4 {#2} }
%    \end{macrocode}
%    
%    \begin{macrocode}
\cs_generate_variant:Nn \prop_get:NnN { NVN, cnN, cVN }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_gget:NnN}
% \begin{macro}{\prop_gget:NVN}
% \begin{macro}{\prop_gget:NnN}
% \begin{macro}{\prop_gget:NVN}
% \begin{macro}{\prop_gget_aux:w}
%    The global version of the previous function.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_gget:NnN #1#2{
  \prop_split_aux:Nnn #1{#2}\prop_gget_aux:w}
\cs_new_protected:Npn \prop_gget_aux:w #1#2#3#4{\tl_gset:Nx#4{\exp_not:n{#2}}}
%    \end{macrocode}
%    
%    \begin{macrocode}
\cs_generate_variant:Nn \prop_gget:NnN { NVN, cnN, cVN }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_get_gdel:NnN}
% \begin{macro}{\prop_get_del_aux:w}
%    |\prop_get_gdel:NnN| is the same as |\prop_get:NnN| but the
%    \m{\propkey} and its value are afterwards globally removed
%    from \m{property_list}. One probably also needs the local
%    variants or only the local one, or\ldots\ We decide this later.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_get_gdel:NnN #1#2#3{
  \prop_split_aux:Nnn #1{#2}{\prop_get_del_aux:w #3{\toks_gset:Nn #1}{#2}}}
\cs_new_protected:Npn \prop_get_del_aux:w #1#2#3#4#5#6{
  \tl_set:Nn #1 {#5}
  \quark_if_no_value:NF #1 {
    \cs_set_nopar:Npn \prop_tmp:w ##1\q_prop#3\q_prop\q_no_value {#2{#4##1}}
    \prop_tmp:w #6}
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_put:Nnn}
% \begin{macro}{\prop_put:NnV}
% \begin{macro}{\prop_put:NVn}
% \begin{macro}{\prop_put:NVV}
% \begin{macro}{\prop_put:cnn} 
% \begin{macro}{\prop_gput:Nnn}
% \begin{macro}{\prop_gput:NVn}
% \begin{macro}{\prop_gput:NnV}
% \begin{macro}{\prop_gput:Nno}
% \begin{macro}{\prop_gput:Nnx}
% \begin{macro}{\prop_gput:cnn}
% \begin{macro}{\prop_gput:ccx}
% \begin{macro}{\prop_put_aux:w}
%    |\prop_put:Nnn| \marg{\proplist} \marg{\propkey} \marg{\propval} adds/changes the
%    value associated with \meta{\propkey} in \meta{\proplist} to \meta{\propval}.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_put:Nnn #1#2{
  \prop_split_aux:Nnn #1{#2}{
    \prop_clear:N #1
    \prop_put_aux:w {\toks_put_right:Nn #1}{#2}
  }
}
%    \end{macrocode}
% 
%    \begin{macrocode}
\cs_new_protected:Npn \prop_gput:Nnn #1#2{
  \prop_split_aux:Nnn #1{#2}{
    \prop_gclear:N #1
    \prop_put_aux:w {\toks_gput_right:Nn #1}{#2}
  }
}
%    \end{macrocode}
% 
%    \begin{macrocode}
\cs_new_protected:Npn \prop_put_aux:w #1#2#3#4#5#6{
  #1{\q_prop#2\q_prop{#6}#3}
  \tl_if_empty:nF{#5}
  {
    \cs_set_nopar:Npn \prop_tmp:w ##1\q_prop#2\q_prop\q_no_value {#1{##1}}
    \prop_tmp:w #5
  }
}
%    \end{macrocode}
% 
%    \begin{macrocode}
\cs_generate_variant:Nn \prop_put:Nnn { NnV, NVn, NVV, cnn }
%    \end{macrocode}
%    
%    \begin{macrocode}
\cs_generate_variant:Nn \prop_gput:Nnn {NVn,NnV,Nno,Nnx,Nox,cnn,ccx}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_del:Nn}
% \begin{macro}{\prop_del:NV}
% \begin{macro}{\prop_gdel:NV}
% \begin{macro}{\prop_gdel:Nn}
% \begin{macro}{\prop_del_aux:w}
%    |\prop_del:Nn |\meta{\proplist}\meta{\propkey} deletes the entry for
%    \meta{\propkey} in \meta{\proplist}, if any.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_del:Nn #1#2{
  \prop_split_aux:Nnn #1{#2}{\prop_del_aux:w {\toks_set:Nn #1}{#2}}}
\cs_new_protected:Npn \prop_gdel:Nn #1#2{
  \prop_split_aux:Nnn #1{#2}{\prop_del_aux:w {\toks_gset:Nn #1}{#2}}}
\cs_new_protected:Npn \prop_del_aux:w #1#2#3#4#5{
  \cs_set_nopar:Npn \prop_tmp:w {#4}
  \quark_if_no_value:NF \prop_tmp:w {
    \cs_set_nopar:Npn \prop_tmp:w ##1\q_prop#2\q_prop\q_no_value {#1{#3##1}}
    \prop_tmp:w #5
  }
}
\cs_generate_variant:Nn \prop_del:Nn { NV }
\cs_generate_variant:Nn \prop_gdel:Nn { NV }
%
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\prop_gput_if_new:Nnn}
% \begin{macro}{\prop_put_if_new_aux:w}
%    |\prop_gput_if_new:Nnn| \m{\proplist} \m{\propkey}
%    \m{\propval} is equivalent to
%    \begin{tabbing}
%       xxxxx\=xxxxx\= \kill
%       |\prop_if_in:NnTF |\m{\proplist}\m{\propkey} \\
%       \> |{}%| \\
%       \> |{\prop_gput:Nnn| \\
%       \>\> \m{property_list} \\
%       \>\> \m{\propkey} \\
%       \>\> \m{\propval}|}|
%     \end{tabbing}
%    Here we go (listening to Porgy \& Bess in a recording with Ella
%    F. and Louis A. which makes writing macros sometimes difficult; I
%    find myself humming instead of working):
%    \begin{macrocode}
\cs_new_protected:Npn \prop_gput_if_new:Nnn #1#2{
  \prop_split_aux:Nnn #1{#2}{\prop_put_if_new_aux:w #1{#2}}}
\cs_new_protected:Npn \prop_put_if_new_aux:w #1#2#3#4#5#6{
  \tl_if_empty:nT {#5}{#1{\q_prop#2\q_prop{#6}#3}}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \subsection{Predicates and conditionals}
%
% \begin{macro}{\prop_if_empty_p:N,\prop_if_empty_p:c}
% \begin{macro}[TF]{\prop_if_empty:N,\prop_if_empty:c}
%    This conditional takes a \m{\proplist} as its argument and evaluates
%    either the true or the false case, depending on whether or not
%    \m{\proplist} contains any properties.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \prop_if_empty:N \toks_if_empty:N {p,TF,T,F}
\prg_new_eq_conditional:NNn \prop_if_empty:c \toks_if_empty:c {p,TF,T,F}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\prop_if_eq_p:NN,\prop_if_eq_p:cN,
%               \prop_if_eq_p:Nc,\prop_if_eq_p:cc}
% \begin{macro}[TF]{\prop_if_eq:NN,\prop_if_eq:Nc,
%                   \prop_if_eq:cN,\prop_if_eq:cc}
%    These functions test whether two property lists are equal.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \prop_if_eq:NN \toks_if_eq:NN {p,TF,T,F}
\prg_new_eq_conditional:NNn \prop_if_eq:cN \toks_if_eq:cN {p,TF,T,F}
\prg_new_eq_conditional:NNn \prop_if_eq:Nc \toks_if_eq:Nc {p,TF,T,F}
\prg_new_eq_conditional:NNn \prop_if_eq:cc \toks_if_eq:cc {p,TF,T,F}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[TF]{\prop_if_in:Nn}
% \begin{macro}[TF]{\prop_if_in:NV}
% \begin{macro}[TF]{\prop_if_in:No}
% \begin{macro}[TF]{\prop_if_in:cn}
% \begin{macro}[TF]{\prop_if_in:cc}
% \begin{macro}{\prop_if_in_aux:w}
%    |\prop_if_in:NnTF| \m{property_list} \m{\propkey}
%    \m{true_case} \m{false_case} will check whether or not
%    \m{\propkey} is on the \m{property_list} and then select
%    either the true or false case.
%    \begin{macrocode}
\prg_new_protected_conditional:Nnn \prop_if_in:Nn {TF,T,F} {
  \prop_split_aux:Nnn #1 {#2} {\prop_if_in_aux:w}
}
\cs_new_nopar:Npn \prop_if_in_aux:w #1#2#3 {
  \quark_if_no_value:nTF {#2} {\prg_return_false:} {\prg_return_true:}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_generate_variant:Nn \prop_if_in:NnTF {NV,No,cn,cc}
\cs_generate_variant:Nn \prop_if_in:NnT  {NV,No,cn,cc}
\cs_generate_variant:Nn \prop_if_in:NnF  {NV,No,cn,cc}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Mapping functions}
%
% \begin{macro}{\prop_map_function:NN}
% \begin{macro}{\prop_map_function:cN}
% \begin{macro}{\prop_map_function:Nc}
% \begin{macro}{\prop_map_function:cc}
% \begin{macro}{\prop_map_function_aux:w}
%    Maps a function on every entry in the property list.  The
%    function must take 2 arguments: a key and a value.
%
% First, some failed attempts:
% \begin{verbatim}
% \cs_new_nopar:Npn \prop_map_function:NN #1#2{
%   \exp_after:wN \prop_map_function_aux:w
%   \exp_after:wN #2 \toks_use:N #1 \q_prop{}\q_prop \q_no_value \q_stop
% }
% \cs_new_nopar:Npn \prop_map_function_aux:w #1\q_prop#2\q_prop#3{
%   \if_predicate:w \tl_if_empty_p:n{#2}
%     \exp_after:wN \prop_map_break:
%   \fi:
%   #1{#2}{#3}
%   \prop_map_function_aux:w #1
% }
% \end{verbatim}
% problem with the above implementation is that an empty key stops the mapping but all
% other functions in the module allow the use of empty keys (as one value)
% \begin{verbatim}
% \cs_set_nopar:Npn \prop_map_function:NN #1#2{
%   \exp_after:wN \prop_map_function_aux:w
%   \exp_after:wN #2 \toks_use:N #1 \q_prop \q_no_value \q_prop \q_no_value 
% }
% \cs_set_nopar:Npn \prop_map_function_aux:w #1\q_prop#2\q_prop#3{
%   \quark_if_no_value:nF{#2}
%     {
%      #1{#2}{#3}
%      \prop_map_function_aux:w #1
%     }
% }
% \end{verbatim}
% problem with the above implementation is that |\quark_if_no_value:nF| is fairly slow and
%  if |\quark_if_no_value:NF| is used instead we have to do an assignment thus
%  making the mapping not expandable (is that important?)
%
% Here's the current version of the code:
%    \begin{macrocode}
\cs_set_nopar:Npn \prop_map_function:NN #1#2 {
    \exp_after:wN \prop_map_function_aux:w
    \exp_after:wN #2 \toks_use:N #1 \q_prop \q_nil \q_prop \q_no_value \q_stop
}
\cs_set:Npn \prop_map_function_aux:w #1 \q_prop #2 \q_prop #3 {
  \if_meaning:w \q_nil #2
    \exp_after:wN \prop_map_break:
  \fi:
  #1{#2}{#3}
  \prop_map_function_aux:w #1
}
%    \end{macrocode}
% (potential) problem with the above implementation is that it will
% return true if |#2| contains more than just |\q_nil| thus executing
% whatever follows. Claim: this can't happen |:-)| so we should be ok
%    \begin{macrocode}
\cs_generate_variant:Nn \prop_map_function:NN {c,Nc,cc}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%  \begin{macro}{\prop_map_inline:Nn}
%  \begin{macro}{\prop_map_inline:cn}
%  \begin{macro}{\g_prop_inline_level_int}
%  The inline functions are straight forward. It takes longer
%  to test if the list is empty than to run it on an empty list so
%  we don't waste time doing that.
%    \begin{macrocode}
\int_new:N \g_prop_inline_level_int
\cs_new_protected_nopar:Npn \prop_map_inline:Nn #1#2 {
  \int_gincr:N \g_prop_inline_level_int
  \cs_gset:cpn {prop_map_inline_ \int_use:N \g_prop_inline_level_int :n}
    ##1##2{#2}
  \prop_map_function:Nc #1
    {prop_map_inline_ \int_use:N \g_prop_inline_level_int :n}
  \int_gdecr:N \g_prop_inline_level_int
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_generate_variant:Nn\prop_map_inline:Nn {cn}
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%
%  \begin{macro}{\prop_map_break:}
%  The break statement.
%    \begin{macrocode}
\cs_new_eq:NN \prop_map_break: \use_none_delimit_by_q_stop:w
%    \end{macrocode}
%  \end{macro}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
% 
%    Show token usage:
%    \begin{macrocode}
%<*showmemory>
%\showMemUsage
%</showmemory>
%    \end{macrocode}
%
% \end{implementation}
% \PrintIndex
%
% \endinput
