<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki.lostsouls.org/w/skins/common/feed.css"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://wiki.lostsouls.org/w/index.php?action=history&amp;feed=atom&amp;title=Man_mappings</id>
		<title>Man mappings - Revision history</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.lostsouls.org/w/index.php?action=history&amp;feed=atom&amp;title=Man_mappings"/>
		<link rel="alternate" type="text/html" href="http://wiki.lostsouls.org/w/index.php?title=Man_mappings&amp;action=history"/>
		<updated>2026-05-05T21:39:13Z</updated>
		<subtitle>Revision history for this page on the wiki</subtitle>
		<generator>MediaWiki 1.8.2</generator>

	<entry>
		<id>http://wiki.lostsouls.org/w/index.php?title=Man_mappings&amp;diff=3937&amp;oldid=prev</id>
		<title>Laine at 17:25, 11 June 2007</title>
		<link rel="alternate" type="text/html" href="http://wiki.lostsouls.org/w/index.php?title=Man_mappings&amp;diff=3937&amp;oldid=prev"/>
				<updated>2007-06-11T17:25:22Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==Description==&lt;br /&gt;
&lt;br /&gt;
A mapping is a datatype which allows to store data associated to a key.&lt;br /&gt;
In other languages  they are also  known  as 'dictionaries' or  'alists'.&lt;br /&gt;
There are also alists in LPC but they are not a separate datatype but are&lt;br /&gt;
implemented on  top of arrays.  Alists are  the predecessors of mappings.&lt;br /&gt;
The keys and the values  can be of  any type.  But most common  datatypes&lt;br /&gt;
for keys are strings, integers and objects.  Others like arrays, mappings&lt;br /&gt;
or closures aren't a good choice because comparision between i.e.  arrays&lt;br /&gt;
often returns false  even if they equal  in content.  This is because the&lt;br /&gt;
driver compares i.e. two arrays by their internal pointers and not by&lt;br /&gt;
their content. The reason for this is simple: speed.&lt;br /&gt;
&lt;br /&gt;
Mappings  are allways  treated  as references    when passing  them  to&lt;br /&gt;
functions. This means when you pass a mapping  to another object and this&lt;br /&gt;
object modifies the mapping the modification will  take place in a global&lt;br /&gt;
scope - visible to all objects holding this mapping in a variable.&lt;br /&gt;
&lt;br /&gt;
The term 'dictionary'  probably describes the  use  of a mapping  best.&lt;br /&gt;
Opposed  to arrays mappings don't have  a specific  order. They provide a&lt;br /&gt;
mechanism to   create  a set  of associations  between  values.  Such  an&lt;br /&gt;
association consists of a unique  key and data  that is identified by the&lt;br /&gt;
key. Think of  a dictionary  where you have  a  word and a definition  of&lt;br /&gt;
it. You use the word to lookup its definition.&lt;br /&gt;
&lt;br /&gt;
Mappings can be used i.e.  to hold  aliases for commands. The key would&lt;br /&gt;
then be the  name of  the alias and  the  data the command(s) behind   an&lt;br /&gt;
alias.  Or they can be used for  the exits of a  room.  The keys would be&lt;br /&gt;
the directions where one can go  to and the associated  data would be the&lt;br /&gt;
file names of the  rooms.  But mappings can  also be used  as a kind of a&lt;br /&gt;
sparse array.   A  sparse array is  an  array where most of  the elements&lt;br /&gt;
aren't used  (occupied by 0).  I.e.  if  you want to  store values at the&lt;br /&gt;
position 0, 13  and 37642 of an  array you would  have to create an array&lt;br /&gt;
with a size of at least 37643.  This  costs a lot  of memory so a mapping&lt;br /&gt;
would be  more useful because you would  then use the  numbers 0,  13 and&lt;br /&gt;
37642 as a key and not as an index to a position  (actually the keys of a&lt;br /&gt;
mapping are sometimes  called indices  but this  is just  because the way&lt;br /&gt;
data is accessed in a mapping is similar to  arrays: by the [] operator).&lt;br /&gt;
This also allows to  query all occupied   positions of a sparse array  by&lt;br /&gt;
querying for all  the keys of  the mapping opposed  to an array where you&lt;br /&gt;
have to iterate over all elements.&lt;br /&gt;
&lt;br /&gt;
There are several ways to create a mapping. The most convenient is the following:&lt;br /&gt;
&lt;br /&gt;
      mapping map;&lt;br /&gt;
      map = ([ key0: value00; ...; value0n,&lt;br /&gt;
               ... : ...    ; ...; ...    ,&lt;br /&gt;
               keyn: valuen0; ...; valuenn ]);&lt;br /&gt;
&lt;br /&gt;
As you can see, a key may  have more than  one value assigned.  But the&lt;br /&gt;
amount of values per key must always be equal.  It  is  even  possible to&lt;br /&gt;
have mappings without any values!&lt;br /&gt;
&lt;br /&gt;
Another  method is  to use the   efun mkmapping().  This  efun gets two&lt;br /&gt;
arguments with the first beeing an array of keys and the following beeing&lt;br /&gt;
arrays of values:&lt;br /&gt;
&lt;br /&gt;
      mapping map;&lt;br /&gt;
      map = mkmapping (({ key0   , ..., keyn    }),&lt;br /&gt;
                       ({ value00, ..., value0n }),&lt;br /&gt;
                       ({ ...    , ..., ...     }),&lt;br /&gt;
                       ({ valuen0, ..., valuenn }));&lt;br /&gt;
&lt;br /&gt;
If the efun only gets one argument, then this argument will be taken as&lt;br /&gt;
an array of keys and a mapping  without values will  be returned.&lt;br /&gt;
&lt;br /&gt;
An empty mapping can be created by using the above described methods by&lt;br /&gt;
simply ommitting the keys and values:&lt;br /&gt;
&lt;br /&gt;
      mapping map;&lt;br /&gt;
      map = ([]);&lt;br /&gt;
  or:&lt;br /&gt;
      map = mkmapping(({}), ({}));&lt;br /&gt;
&lt;br /&gt;
Or  by  using the efun   m_allocate().  This efun gets  as  first&lt;br /&gt;
argument the  amount  of keys which will  be  added soon and  an optional&lt;br /&gt;
second argument specifying the width of the mapping:&lt;br /&gt;
&lt;br /&gt;
      map = m_allocate(n, width);&lt;br /&gt;
&lt;br /&gt;
The value &amp;lt;n&amp;gt;  may be a bit  confusing  since mappings shrink and  grow&lt;br /&gt;
dynamically. This value just tells the driver how 'long' this  mapping is&lt;br /&gt;
going to be  so proper memory  allocations  will be  performed to  reduce&lt;br /&gt;
the overhead of memory reallocation.  I.e.  if you want to read in a file&lt;br /&gt;
and store the  read data in  a mapping  you probably  know  the amount of&lt;br /&gt;
keys.  So you allocate  a mapping with this  efun and tell the driver how&lt;br /&gt;
much memory should  be allocated  by specifing  a proper &amp;lt;n&amp;gt;  value.&lt;br /&gt;
Thus causing  a    speedup when adding  the  read   data to the   mapping&lt;br /&gt;
afterwards.    The &amp;lt;width&amp;gt; just specifies how   many  values per key this&lt;br /&gt;
mapping is   going to have. If  no  width is given, 1  will  be  taken as&lt;br /&gt;
default.&lt;br /&gt;
&lt;br /&gt;
An empty mapping created with '([])' will always have a width of 1. To&lt;br /&gt;
create empty mappings with other widths, write it as&lt;br /&gt;
&lt;br /&gt;
      map = ([:width ]);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;width&amp;gt; can be any expression returning an integer value (including&lt;br /&gt;
function calls), and in fact this notation is just a fancy way of&lt;br /&gt;
writing&lt;br /&gt;
&lt;br /&gt;
      map = m_allocate(0, width);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Adding a  new key is similiar to   modifying the associated  data of an&lt;br /&gt;
existing key:&lt;br /&gt;
&lt;br /&gt;
      map += ([ key: value0; ...; valuen ]);&lt;br /&gt;
&lt;br /&gt;
Or in case only a single value should be modified:&lt;br /&gt;
&lt;br /&gt;
      map[key, n] = valuen;&lt;br /&gt;
&lt;br /&gt;
If  &amp;lt;n&amp;gt; is out of  range or if &amp;lt;key&amp;gt; doesn't  exists and &amp;lt;n&amp;gt; is greater&lt;br /&gt;
than 0 an &amp;quot;Illegal index&amp;quot; error will be reported. If &amp;lt;n&amp;gt; is equal to 0 or&lt;br /&gt;
the mapping only has a single value per key one can abbreviate it with:&lt;br /&gt;
&lt;br /&gt;
      map[key] = value;&lt;br /&gt;
&lt;br /&gt;
If there is no &amp;lt;key&amp;gt; (and &amp;lt;n&amp;gt; is equal to 0 or  not specified at all) a&lt;br /&gt;
new one will be added automatically.&lt;br /&gt;
&lt;br /&gt;
Deletion   of a key    is  done with    the  -=  operator or  the  efun&lt;br /&gt;
m_delete(). A mapping can only be substracted by one without any values:&lt;br /&gt;
&lt;br /&gt;
      map -= ([ key ]);&lt;br /&gt;
  or:&lt;br /&gt;
      map -= ([ key0, ..., keyn ]);&lt;br /&gt;
&lt;br /&gt;
The efun takes a mapping as first and a key as second argument:&lt;br /&gt;
&lt;br /&gt;
      m_delete(map, key);&lt;br /&gt;
&lt;br /&gt;
The  efun   m_delete() returns  the mapping   but because  mappings are&lt;br /&gt;
handled as references there is no need of an assignment like:&lt;br /&gt;
&lt;br /&gt;
      map = m_delete(map, key);&lt;br /&gt;
&lt;br /&gt;
Data stored in a mapping can be accessed by:&lt;br /&gt;
&lt;br /&gt;
      valuen = map[key, n];&lt;br /&gt;
&lt;br /&gt;
Or in case of a mapping with just one value per key:&lt;br /&gt;
&lt;br /&gt;
      value0 = map[key];&lt;br /&gt;
&lt;br /&gt;
If there is no  &amp;lt;key&amp;gt; in the mapping  and &amp;lt;n&amp;gt; is  0 or not specified at&lt;br /&gt;
all (which is the same) a 0 will be returned or if &amp;lt;n&amp;gt;  is greater than 0&lt;br /&gt;
an &amp;quot;Illegal index&amp;quot; error will be reported.&lt;br /&gt;
&lt;br /&gt;
A  return value of 0 is  sufficient for most applications but sometimes&lt;br /&gt;
the ambiguity  between an existing value of  0 and  a nonexisting key can&lt;br /&gt;
lead   to  a  problem.  Therefore   one  can use   the  efun member()  or&lt;br /&gt;
mapping_contains() to check if there actually is a key in the mapping:&lt;br /&gt;
&lt;br /&gt;
      if (member(map, key)) {&lt;br /&gt;
        ...&lt;br /&gt;
      }&lt;br /&gt;
  or:&lt;br /&gt;
      if (mapping_contains(&amp;amp;value0, ..., &amp;amp;valuen, map, key)) {&lt;br /&gt;
        ...&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
This also shows how  one can retrieve all values   associated to a  key&lt;br /&gt;
from a mapping in a single step. The '&amp;amp;' is  the reference operator which&lt;br /&gt;
is neccesary to let the efun store the values in the variables.&lt;br /&gt;
&lt;br /&gt;
In case   of  mappings   with   no  values,   the  efun   member()  and&lt;br /&gt;
mapping_contains() are equal in their behaviour  and their way of calling&lt;br /&gt;
because mapping_contains() won't get any reference variables to store the&lt;br /&gt;
values in (obviously, because there aren't any).&lt;br /&gt;
&lt;br /&gt;
Also normally member() is known to return the postion of an element in&lt;br /&gt;
a list (i.e.  a  character in a  string or data   in an array) and if  an&lt;br /&gt;
element couldn't be  found -1 is returned.   But in the case  of mappings&lt;br /&gt;
there are no such things as order and postion. So member() only returns 0&lt;br /&gt;
or 1.&lt;br /&gt;
&lt;br /&gt;
A  mapping can  be  copied   with  the  +  operator   or by the    efun&lt;br /&gt;
copy_mapping():&lt;br /&gt;
&lt;br /&gt;
      newmap = ([]) + map;&lt;br /&gt;
  or:&lt;br /&gt;
      newmap = copy_mapping(map);&lt;br /&gt;
&lt;br /&gt;
A mapping should only be copied when it is neccesary to get an own copy&lt;br /&gt;
of it that  must not be  shared by other objects.&lt;br /&gt;
&lt;br /&gt;
The  efun m_indices() gets a mapping  as argument  and returns an array&lt;br /&gt;
holding all keys defined in this mapping:&lt;br /&gt;
&lt;br /&gt;
      keys = m_indices(map);&lt;br /&gt;
&lt;br /&gt;
The efun m_values() gets  a mapping as  argument  and returns  an array&lt;br /&gt;
holding all the first (second, ...) values of it.&lt;br /&gt;
&lt;br /&gt;
      values0 = m_values(map);     returns the first values&lt;br /&gt;
      values0 = m_values(map, 0);  dito&lt;br /&gt;
      values1 = m_values(map, 1);  returns the second values&lt;br /&gt;
        etc&lt;br /&gt;
&lt;br /&gt;
Because a mapping is a kind of rectangle it has two sizes: a length and&lt;br /&gt;
a width.  There are three different efuns  to query these values. The first&lt;br /&gt;
two are the  efuns sizeof(), which returns the  amount of key-value&lt;br /&gt;
associations (the length of  a mapping), and widthof(), which returns the&lt;br /&gt;
number of values per key (the width). The third is the efun get_type_info().&lt;br /&gt;
get_type_info() is meant  to be a function  to identify a datatype.   Its&lt;br /&gt;
return value is an  array of two  numerical values.  The first  specifies&lt;br /&gt;
the datatype   of the argument and   the second is a   datatype dependend&lt;br /&gt;
value. In the case of a mapping the first value  is T_MAPPING (which is a&lt;br /&gt;
value defined in  &amp;lt;lpctypes.h&amp;gt;) and the  second the amount of values  per&lt;br /&gt;
key (a.k.a.  columns or the width  of the mapping  - actually it would be&lt;br /&gt;
correct to say that the width of a mapping is the  amount of columns plus&lt;br /&gt;
one for the keys but this is uncommon).&lt;br /&gt;
&lt;br /&gt;
The main purpose of a mapping is not meant to  be a set of&lt;br /&gt;
data to iterate over. Afterall the keys in a mapping have no specific but&lt;br /&gt;
a random order (at least on the LPC side).  But  still it is possible and&lt;br /&gt;
sometimes even neccesary to do so.&lt;br /&gt;
&lt;br /&gt;
If all key-value associations  should be processed  then one should use&lt;br /&gt;
walk_mapping().  If all keys of a mapping should be processed to create a&lt;br /&gt;
new mapping being a subset of the given one, then filter_mapping() should&lt;br /&gt;
be  used.  If all  keys  are going to  be  processed and  to create a new&lt;br /&gt;
mapping with the  same set of keys as  the given mapping, then one  would&lt;br /&gt;
use map_mapping().  But in the case of an  iteration that should/can stop&lt;br /&gt;
even if not all data is processed it is probably wise to iterate over the&lt;br /&gt;
mapping by first querying for the keys and then to iterate over them with&lt;br /&gt;
a for() or a while() loop and querying the values by 'hand'.&lt;br /&gt;
&lt;br /&gt;
The efun walk_mapping() gets  a mapping as  first argument and the name&lt;br /&gt;
of a function  as second one. All the  following arguments are treated as&lt;br /&gt;
extras which  will  be  passed to the   function specified  with the  2nd&lt;br /&gt;
argument. Instead of a string for the name of a function a closure can be&lt;br /&gt;
used, too. Nothing will be returned:&lt;br /&gt;
&lt;br /&gt;
      ...&lt;br /&gt;
      walk_mapping(map, &amp;quot;func&amp;quot;, xarg0, ..., xargn);&lt;br /&gt;
      ...&lt;br /&gt;
&lt;br /&gt;
      void func(mixed key, mixed value0, ..., mixed valuen,&lt;br /&gt;
                mixed xarg0, ..., mixed xargn) {&lt;br /&gt;
        ...&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
func() will be called for all key-value associations  and gets as first&lt;br /&gt;
argument the key.  The next arguments are the  values behind the key  and&lt;br /&gt;
are passed as references.  The  rest  of the  passed arguments are  those&lt;br /&gt;
specified as extras. Because the values are passed as references (opposed&lt;br /&gt;
to  copies) it is possible  to modify them  from  inside func() by simply&lt;br /&gt;
assigning new value to the variables &amp;lt;value0&amp;gt;, ..., &amp;lt;valuen&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The efun filter_mapping() calls  a function for  each key in  a mapping&lt;br /&gt;
and creates a new mapping  which only contains key-value associations for&lt;br /&gt;
which the called function returned true (not  equal 0 that is). The first&lt;br /&gt;
argument is the mapping to iterate over and the second is a function name&lt;br /&gt;
given as a string or a closure:&lt;br /&gt;
&lt;br /&gt;
      ...&lt;br /&gt;
      submap = filter_mapping(map, &amp;quot;func&amp;quot;, xarg0, ..., xargn);&lt;br /&gt;
      ...&lt;br /&gt;
&lt;br /&gt;
      int func(mixed key, mixed xarg0, ..., mixed xargn) {&lt;br /&gt;
        ...&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
func() gets  as first argument the key  and the others are those passed&lt;br /&gt;
as extras to filter_mapping().&lt;br /&gt;
&lt;br /&gt;
The efun map_mapping() gets a mapping as first argument and a string as&lt;br /&gt;
a function name (or again a closure) as  second argument.  Any additional&lt;br /&gt;
arguments are again used  as extras that will  be passed to the iteration&lt;br /&gt;
function. This efun returns a new mapping with the same keys as the given&lt;br /&gt;
one.  The values  returned by the function  that is invoked  for each key&lt;br /&gt;
will be used as the associated data behind each key of the new mapping:&lt;br /&gt;
&lt;br /&gt;
      ...&lt;br /&gt;
      newmap = map_mapping(map, &amp;quot;func&amp;quot;, xarg0, ..., xargn);&lt;br /&gt;
      ...&lt;br /&gt;
&lt;br /&gt;
      mixed func(mixed key, mixed xarg0, ..., mixed xargn) {&lt;br /&gt;
        ...&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
func() gets  as first argument the key  and the others are those passed&lt;br /&gt;
as extras to map_mapping().&lt;br /&gt;
&lt;br /&gt;
Because a function can only return  a single value  (even when it is an&lt;br /&gt;
array) it restricts the use  of map_mapping() to  only allow creation  of&lt;br /&gt;
mappings with a single value per key.&lt;br /&gt;
&lt;br /&gt;
Joining mappings is only possible, if  they have the same width (amount&lt;br /&gt;
of values per key). One can use the + and += operator:&lt;br /&gt;
&lt;br /&gt;
      map = map1 + map2 + ... + mapn;&lt;br /&gt;
      map += map1 + map2 + ... + mapn;&lt;br /&gt;
&lt;br /&gt;
Intersection     of   two   mappings is    only      possible by  using&lt;br /&gt;
filter_mapping(). There is  no efun or operator  which features this. The&lt;br /&gt;
'easiest' way may be the following function:&lt;br /&gt;
&lt;br /&gt;
      mapping intersect_mapping(mapping map1, mapping map2) {&lt;br /&gt;
        closure cl;&lt;br /&gt;
&lt;br /&gt;
        cl = lambda(({ 'key }), ({ #'member, map2, 'key }));&lt;br /&gt;
        return filter_mapping(map1, cl, map2);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
This function returns a  new mapping which   consists of all  key-value&lt;br /&gt;
associations   of  &amp;lt;map1&amp;gt;  for which  an  equal  key  could   be found in&lt;br /&gt;
&amp;lt;map2&amp;gt;. This function uses  a closure which returns 0  or 1  depending on&lt;br /&gt;
whether a key from &amp;lt;map1&amp;gt; is contained in &amp;lt;map2&amp;gt; or not.&lt;br /&gt;
&lt;br /&gt;
Cutting out  all key-value associations of a   mapping for which  a key&lt;br /&gt;
could be  found in another mapping  can  be done  by using  the  - and -=&lt;br /&gt;
operator:&lt;br /&gt;
&lt;br /&gt;
      mapping cut_mapping(mapping map1, mapping map2) {&lt;br /&gt;
        return map1 - mkmapping(m_indices(map2));&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
Because a mapping can  only be substracted by one  without any values we&lt;br /&gt;
first have to create such by using m_indices() and mkmapping().&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Bugs==&lt;br /&gt;
Mappings can't use lfun or identifier closures as keys. This&lt;br /&gt;
restriction has been corrected in 3.3 .&lt;br /&gt;
&lt;br /&gt;
==History==&lt;br /&gt;
The ([:width ]) notation was added in LDMud 3.2.9 .&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
&lt;br /&gt;
[[man alists|alists(LPC)]], [[man closures|closures(LPC)]], [[man mkmapping|mkmapping(E)]], [[man walk mapping|walk_mapping(E)]]&lt;/div&gt;</summary>
		<author><name>Laine</name></author>	</entry>

	</feed>