File 3251-Add-a-chapter-about-maps-to-the-Efficiency-Guide.patch of Package erlang
From 8e6358e0f3bbf82384938197206100a4f071b8d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 1 Jul 2021 07:25:27 +0200
Subject: [PATCH] Add a chapter about maps to the Efficiency Guide
---
lib/stdlib/doc/src/maps.xml | 5 +-
system/doc/efficiency_guide/maps.xml | 686 ++++++++++++++++++++++++
system/doc/efficiency_guide/part.xml | 1 +
system/doc/efficiency_guide/xmlfiles.mk | 3 +-
4 files changed, 693 insertions(+), 2 deletions(-)
create mode 100644 system/doc/efficiency_guide/maps.xml
diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml
index 5df885fc96..fdca524153 100644
--- a/lib/stdlib/doc/src/maps.xml
+++ b/lib/stdlib/doc/src/maps.xml
@@ -30,7 +30,10 @@
<module since="OTP 17.0">maps</module>
<modulesummary>Maps processing functions.</modulesummary>
<description>
- <p>This module contains functions for maps processing.</p>
+ <p>This module contains functions for maps processing. The
+ Efficiency Guide contains a chapter that describes <seeguide
+ marker="system/efficiency_guide:maps">how to use maps
+ efficiently</seeguide>.</p>
</description>
<datatypes>
diff --git a/system/doc/efficiency_guide/maps.xml b/system/doc/efficiency_guide/maps.xml
new file mode 100644
index 0000000000..140bdd549a
--- /dev/null
+++ b/system/doc/efficiency_guide/maps.xml
@@ -0,0 +1,686 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2021</year><year>2021</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ </legalnotice>
+
+ <title>Maps</title>
+ <prepared>Bjorn Gustavsson</prepared>
+ <docno></docno>
+ <date>2021-07-01</date>
+ <rev></rev>
+ <file>maps.xml</file>
+ </header>
+
+ <p>This guide to using maps efficiently starts with a brief section
+ on the choice between records or maps, followed by three sections
+ giving concrete (but brief) advice on using maps as an alternative to
+ records, as dictionaries, and as sets. The remaining sections dig
+ deeper, looking at how maps are implemented, the map syntax, and
+ finally the functions in the <seeerl
+ marker="stdlib:maps">maps</seeerl> module.</p>
+
+ <p>Terminology used in this chapter:</p>
+ <list type="bulleted">
+ <item>A map with at most 32 elements will informally be called a
+ <em>small map</em>.</item>
+ <item>A map with more than 32 elements will informally be called a
+ <em>large map</em>.</item>
+ </list>
+
+ <section>
+ <title>Maps or Records?</title>
+ <p>If the advice in this chapter is followed, the performance of
+ records compared to using small maps instead of records is
+ expected to be similar. Therefore, the choice between records and
+ maps should be based on the desired properties of the data
+ structure and not performance.</p>
+
+ <p>The advantages of records compared to maps are:</p>
+
+ <list type="bulleted">
+ <item>If the name of a record field is misspelled, there will be
+ a compilation error. If a map key is misspelled, the compiler
+ will give no warning and program will fail in some way when it
+ is run.</item>
+
+ <item>Records will use slightly less memory than maps, and
+ performance is expected to be <em>slightly</em> better than maps
+ in most circumstances.</item>
+ </list>
+
+ <p>The disadvantage of records compared to maps is that if a new
+ field is added to a record, all code that uses that record must be
+ recompiled. Because of that, it is recommended to only use records
+ within a unit of code that can easily be recompiled all at once, for
+ example within a single application or single module.</p>
+ </section>
+
+ <section>
+ <title>Using Maps as an Alternative to Records</title>
+
+ <list type="bulleted">
+ <item><p>Use the map syntax instead of the functions in
+ the <seeerl marker="stdlib:maps">maps</seeerl> module.</p></item>
+
+ <item><p>Avoid having more than 32 elements in the
+ map. As soon as there are more than 32 elements in the map,
+ it will require more memory and keys can no longer be shared
+ with other instances of the map.</p></item>
+
+ <item><p>When creating a new map, always create it with all keys
+ that will ever be used. To maximize sharing of keys (thus
+ minimizing memory use), create a single function that constructs
+ the map using the map syntax and always use it.</p></item>
+
+ <item><p>Always update the map using the
+ <c>:=</c> operator (that is, requiring that an element with
+ that key already exists). The <c>:=</c> operator is slightly
+ more efficient, and it helps catching mispellings of
+ keys.</p></item>
+
+ <item><p>Whenever possible, match multiple map elements at
+ once.</p></item>
+
+ <item><p>Whenever possible, update multiple map elements at
+ once.</p></item>
+
+ <item><p>Avoid default values and the <seemfa
+ marker="stdlib:maps#get/3">maps:get/3</seemfa> function. If
+ there are default values, sharing of keys between different
+ instances of the map will be less effective, and it is not
+ possible to match multiple elements having default values in one
+ go. The <c>maps:get/3</c> function is <seeguide
+ marker="#maps_get_3">implemented in Erlang</seeguide>, making it
+ less efficient than <c>maps:get/2</c> or the map matching
+ syntax.</p></item>
+
+ <item><p>To avoid having to deal with a map that may lack some keys,
+ <seemfa marker="stdlib:maps#merge/2">maps:merge/2</seemfa>
+ can efficiently add multiple default values. For example:</p>
+ <code type="erl"><![CDATA[
+ DefaultMap = #{shoe_size => 42, editor => emacs},
+ MapWithDefaultsApplied = maps:merge(DefaultMap, OtherMap)]]></code>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Using Maps as Dictionaries</title>
+
+ <p>Using a map as a dictionary implies the following usage pattern:</p>
+ <list type="bulleted">
+ <item><p>Keys are usually variables not known at compile-time.</p></item>
+ <item><p>There can be any number of elements in the map.</p></item>
+ <item><p>Usually, no more than one element is looked up or
+ updated at once.</p></item>
+ </list>
+
+ <p>Given that usage pattern, the difference in performance between
+ using the map syntax and the maps module is usually
+ small. Therefore, which one to use is mostly a matter of
+ taste.</p>
+
+ <p>Maps are usually the most efficient dictionary data structure,
+ with a few exceptions:</p>
+
+ <list type="bulleted">
+ <item><p>If it is necessary to frequently convert a
+ dictionary to a sorted list, or from a sorted list to a
+ dictionary, using <seeerl marker="stdlib:gb_trees">gb_trees</seeerl>
+ can be a better choice.</p></item>
+
+ <item><p>If all keys are non-negative integers, the <seeerl
+ marker="stdlib:array">array</seeerl> module can be a better
+ choice.</p></item>
+ </list>
+ </section>
+
+ <section>
+ <title>Using Maps as Sets</title>
+
+ <p>Starting in OTP 24, the <seeerl marker="stdlib:sets">sets</seeerl> module
+ has an option to represent sets as maps. Examples:</p>
+
+ <code type="erl"><![CDATA[
+1> sets:new([{version,2}]).
+#{}
+2> sets:from_list([x,y,z], [{version,2}]).
+#{x => [],y => [],z => []}]]></code>
+
+ <p><c>sets</c> backed by maps is generally the most efficient set
+ representation, with a few possible exceptions:</p>
+
+ <list type="bulleted">
+ <item><p><seemfa
+ marker="stdlib:ordsets#intersection/2">ordsets:intersection/2</seemfa>
+ can be more efficient than <seemfa
+ marker="stdlib:sets#intersection/2">sets:intersection/2</seemfa>.
+ If the intersection operation is frequently used and operations
+ that operate on a single element in a set (such as
+ <c>is_element/2</c>) are avoided, <seeerl
+ marker="stdlib:ordsets">ordsets</seeerl> can be a better
+ choice than <seeerl marker="stdlib:sets">sets</seeerl>.</p></item>
+
+ <item><p>If the intersection operation is frequently used and operations
+ that operate on a single element in a set (such as
+ <c>is_element/2</c>) must also be efficient, <seeerl
+ marker="stdlib:gb_sets">gb_sets</seeerl> can potentially be a
+ better choice than <seeerl marker="stdlib:sets">sets</seeerl>.</p></item>
+
+ <item><p>If the elements of the set are integers in a fairly
+ compact range, the set can be represented as an integer where
+ each bit represents an element in the set. The union operation
+ is performed by <c>bor</c> and the intersection operation by
+ <c>band</c>.</p></item>
+ </list>
+ </section>
+
+ <section>
+ <title>How Maps are Implemented</title>
+ <p>Internally, maps have two distinct representations depending on
+ the number of elements in the map. The representation changes
+ when a map grows beyond 32 elements, or when it shrinks to 32
+ elements or less.</p>
+
+ <list type="bulleted">
+ <item>A map with at most 32 elements has a compact
+ representation, making it suitable as an alternative to
+ records.</item>
+ <item>A map with more than 32 elements is represented as a tree
+ that can be efficiently searched and updated regardless of how
+ many elements there are.</item>
+ </list>
+
+ <section>
+ <title>How Small Maps are Implemented</title>
+ <p>A small map looks like this inside the runtime system:</p>
+ <table align="left">
+ <row>
+ <cell align="center"><c>FLATMAP</c></cell>
+ <cell align="center"><em>N</em></cell>
+ <cell align="center"><em>Keys</em></cell>
+ <cell align="center"><em>Value1</em></cell>
+ <cell align="center"><em>. . .</em></cell>
+ <cell align="center"><em>ValueN</em></cell>
+ </row>
+ <tcaption>The representation of a small map</tcaption>
+ </table>
+
+ <taglist>
+ <tag><c>FLATMAP</c></tag>
+ <item>The tag for a small map (called <em>flat map</em> in
+ the source code for the runtime system).</item>
+
+ <tag>N</tag>
+ <item>The number of elements in the map.</item>
+
+ <tag>Keys</tag>
+ <item>A tuple with keys of the map: <c>{Key1,...,KeyN}</c>. The
+ keys are sorted.</item>
+
+ <tag>Value1</tag>
+ <item>The value corresponding to the first key in the key tuple.</item>
+
+ <tag>ValueN</tag>
+ <item>The value corresponding to the last key in the key tuple.</item>
+ </taglist>
+
+ <p>As an example, let us look at how the map <c>#{a => foo, z => bar}</c>
+ is represented:</p>
+
+ <table align="left">
+ <row>
+ <cell align="center"><c>FLATMAP</c></cell>
+ <cell align="center"><em>2</em></cell>
+ <cell align="center"><em>{a,z}</em></cell>
+ <cell align="center"><em>foo</em></cell>
+ <cell align="center"><em>bar</em></cell>
+ </row>
+ <tcaption>#{a => foo, z => bar}</tcaption>
+ </table>
+
+ <p>Let us update the map: <c>M#{q => baz}</c>. The map now looks
+ like this:</p>
+
+ <table align="left">
+ <row>
+ <cell align="center"><c>FLATMAP</c></cell>
+ <cell align="center"><em>3</em></cell>
+ <cell align="center"><em>{a,q,z}</em></cell>
+ <cell align="center"><em>foo</em></cell>
+ <cell align="center"><em>baz</em></cell>
+ <cell align="center"><em>bar</em></cell>
+ </row>
+ <tcaption>#{a => foo, q => baz, z => bar}</tcaption>
+ </table>
+
+ <p>Finally, change the value of one element: <c>M#{z :=
+ bird}</c>. The map now looks like this:</p>
+
+ <table align="left">
+ <row>
+ <cell align="center"><c>FLATMAP</c></cell>
+ <cell align="center"><em>3</em></cell>
+ <cell align="center"><em>{a,q,z}</em></cell>
+ <cell align="center"><em>foo</em></cell>
+ <cell align="center"><em>baz</em></cell>
+ <cell align="center"><em>bird</em></cell>
+ </row>
+ <tcaption>#{a => foo, q => baz, z => bird}</tcaption>
+ </table>
+
+ <p>When the value for an existing key is updated, the key tuple is not
+ updated, allowing the key tuple to be shared with other instances of the
+ map that have the same keys. In fact, the key tuple can be shared between all
+ maps with the same keys with some care. To arrange that, define a function that
+ returns a map. For example:</p>
+
+ <code type="erl"><![CDATA[
+new() ->
+ #{a => default, b => default, c => default}.]]></code>
+
+ <p>Defined like this, the key tuple <c>{a,b,c}</c> will be a
+ global literal. To ensure that the key tuple is shared
+ when creating an instance of the map, always call
+ <c>new()</c> and modify the returned map:</p>
+
+ <code type="erl"><![CDATA[
+ (SOME_MODULE:new())#{a := 42}.]]></code>
+
+ <p>Using the map syntax with small maps is particularly
+ efficient. As long as the keys are known at compile-time, the
+ map is updated in one go, making the time to update a map
+ essentially constant regardless of the number of keys
+ updated. The same goes for matching. (When the keys are
+ variables, one or more of the keys could be identical, so the
+ operations need to be performed sequentially from left to
+ right.)</p>
+
+ <p>The memory size for a small map is the size of all keys and values
+ plus 5 words. See <seeguide marker="advanced#memory">Advanced</seeguide>
+ for more information about memory sizes.</p>
+ </section>
+
+ <section>
+ <title>How Large Maps are Implemented</title>
+
+ <p>A map with more than 32 elements is implemented as a <url
+ href="https://en.wikipedia.org/wiki/Hash_array_mapped_trie">Hash
+ array mapped trie (HAMT)</url>. A large map can be efficiently
+ searched and updated regardless of the number of elements in the
+ map.</p>
+
+ <p>There is less performance to be gained by matching or
+ updating multiple elements using the map syntax on a large map
+ compared to a small map. The execution time is roughly proportional
+ to the number of elements matched or updated.</p>
+
+ <p>The storage overhead for a large map is higher than for a
+ small map. For a large map, the extra number of words besides
+ the keys and values is roughly proportional to the number of
+ elements. For a map with 33 elements the overhead is at
+ least 53 heap words according to the formula in <seeguide
+ marker="advanced#memory">Advanced</seeguide> (compared to 5
+ extra words for a small map regardless of the number of
+ elements).</p>
+
+ <p>When a large map is updated, the updated map and the original
+ map will share common parts of the HAMT, but sharing will never
+ be as effective as the best possible sharing of the key tuple
+ for small maps.</p>
+
+ <p>Therefore, if maps are used instead of records and it is
+ expected that many instances of the map will be created, it is
+ more efficient from a memory standpoint to avoid using large
+ maps (for example, by grouping related map elements into sub
+ maps to reduce the number of elements).</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Using the Map Syntax</title>
+
+ <p>Using the map syntax is usually slightly more efficient than
+ using the corresponding function in the <seeerl
+ marker="stdlib:maps">maps</seeerl> module.</p>
+
+ <p>The gain in efficiency for the map syntax is more noticeable
+ for the following operations that can only be achieved using the
+ map syntax:</p>
+
+ <list type="bulleted">
+ <item><p>Matching multiple literal keys</p></item>
+ <item><p>Updating multiple literal keys</p></item>
+ <item><p>Adding multiple literal keys to a map</p></item>
+ </list>
+
+ <p>For example:</p>
+
+ <p><em>DO</em></p>
+ <code type="erl"><![CDATA[
+ Map = Map1#{x := X, y := Y, z := Z}]]></code>
+
+ <p><em>DO NOT</em></p>
+ <code type="erl"><![CDATA[
+ Map2 = maps:update(x, X, Map1),
+ Map3 = maps:update(y, Y, Map2),
+ Map = maps:update(z, Z, Map3)]]></code>
+
+ <p>If the map is a small map, the first example runs roughly
+ three times as fast.</p>
+
+ <p>Note that for variable keys, the elements are updated
+ sequentially from left to right. For example, given the following
+ update with variable keys:</p>
+
+ <code type="erl"><![CDATA[
+ Map = Map1#{Key1 := X, Key2 := Y, Key3 := Z}]]></code>
+
+ <p>the compiler rewrites it like this to ensure that the updates
+ are applied from left to right:</p>
+
+ <code type="erl"><![CDATA[
+ Map2 = Map1#{Key1 := X},
+ Map3 = Map2#{Key2 := Y},
+ Map = Map3#{Key3 := Z}]]></code>
+
+ <p>If a key is known to exist in a map, using the <c>:=</c>
+ operator is slightly more efficient than using the <c>=></c>
+ operator for a small map.</p>
+ </section>
+
+ <section>
+ <title>Using the Functions in the maps Module</title>
+
+ <p>Here follows some notes about most of the functions in the
+ <c>maps</c> module. For each function, the implementation language
+ (C or Erlang) is stated. The reason we mention the language is
+ that it gives an hint about how efficient the function is:</p>
+
+ <list type="bulleted">
+ <item><p>If a function is implemented in C, it is pretty much
+ impossible to implement the same functionality more efficiently
+ in Erlang.</p></item>
+
+ <item><p>However, it might be possible to beat the <c>maps</c>
+ modules functions implemented in Erlang, because they are
+ generally implemented in a way that attempts to make the performance
+ reasonable for all possible inputs.</p>
+
+ <p>For example, <seemfa
+ marker="stdlib:maps#map/2">maps:map/2</seemfa> iterates over
+ all elements of the map, calling the mapping fun, collects the
+ updated map elements in a list, and finally converts the list
+ back to a map using <seemfa
+ marker="stdlib:maps#from_list/1">maps:from_list/1</seemfa>. If
+ it is known that at most one percent of the values in the map
+ will change, it can be more efficient to update only the
+ changed values.</p></item>
+ </list>
+
+ <note><p>The implementation details given in this section can
+ change in the future.</p></note>
+
+ <section>
+ <title>maps:filter/2</title>
+ <p><seemfa marker="stdlib:maps#filter/2">maps:filter/2</seemfa>
+ is implemented in Erlang. It creates a new map using <seemfa
+ marker="stdlib:maps#from_list/1">maps:from_list/1</seemfa>. If
+ it is known that only a minority of the values will be removed,
+ it can be more efficient to avoid <c>maps:filter/2</c> and write
+ a function that will use <seemfa
+ marker="stdlib:maps#remove/2">maps:remove/3</seemfa> to remove
+ the unwanted values.</p>
+ </section>
+
+ <section>
+ <title>maps:filtermap/2</title>
+ <p><seemfa
+ marker="stdlib:maps#filtermap/2">maps:filtermap/2</seemfa> is
+ implemented in Erlang. It creates a new map using <seemfa
+ marker="stdlib:maps#from_list/1">maps:from_list/1</seemfa>. See
+ the notes for <c>maps:map/2</c> and <c>maps:filter/2</c> for
+ hints on how to implement a more efficient version.</p>
+ </section>
+
+ <section>
+ <title>maps:find/2</title>
+ <p><seemfa marker="stdlib:maps#find/2">maps:find/2</seemfa> is
+ implemented in C.</p>
+ <p>Using the map matching syntax instead of <c>maps:find/2</c>
+ will be slightly more efficient since building an
+ <c>{ok,Value}</c> tuple will be avoided.</p>
+ </section>
+
+ <section>
+ <title>maps:get/2</title>
+ <p>As an optimization, the compiler will rewrite a call to <seemfa
+ marker="stdlib:maps#get/2">maps:get/2</seemfa> to a call to the
+ guard BIF <seemfa
+ marker="erts:erlang#map_get/2">map_get/2</seemfa>. A call to a
+ guard BIF is more efficient than calls to other BIFs, making the
+ performance similar to using the map matching syntax.</p>
+
+ <p>If the map is small and the keys are constants known at
+ compile-time, using the map matching syntax will be more
+ efficient than multiple calls to <c>maps:get/2</c>.</p>
+ </section>
+
+ <section>
+ <marker id="maps_get_3"/>
+ <title>maps:get/3</title>
+ <p><seemfa marker="stdlib:maps#get/3">maps:get/3</seemfa>
+ is implemented in Erlang essentially like this:</p>
+
+ <code type="erl"><![CDATA[
+get(Key, Map, Default) ->
+ case Map of
+ #{Key := Value} -> Value;
+ #{} -> Default
+ end.]]></code>
+
+ <p>Therefore, a call <c>maps:get/3</c> is more expensive than a
+ call to <c>maps:get/2</c>.</p>
+
+ <p>If a small map is used as alternative to using a record,
+ instead of calling <c>maps:get/3</c> multiple times to handle
+ default values, consider putting the default values in a map and
+ merging that map with the other map:</p>
+
+ <code type="erl"><![CDATA[
+ DefaultMap = #{Key1 => Value2, Key2 => Value2, ..., KeyN => ValueN},
+ MapWithDefaultsApplied = maps:merge(DefaultMap, OtherMap)]]></code>
+
+ <p>Whether that is faster than calling <c>maps:get/3</c>
+ multiple times depends on the size of the map and the number of
+ default values.</p>
+ </section>
+
+ <section>
+ <title>maps:intersect/2, maps:intersect_with/3</title>
+ <p><seemfa marker="stdlib:maps#intersect/2">maps:intersect/2</seemfa> and
+ <seemfa marker="stdlib:maps#intersect_with/3">maps:intersect_with/3</seemfa>
+ are implemented in Erlang. They both create new maps using <seemfa
+ marker="stdlib:maps#from_list/1">maps:from_list/1</seemfa>.</p>
+
+ <note><p>A map is usually the most efficient way to implement a
+ set, but an exception is the intersection operation, where
+ <seemfa
+ marker="stdlib:ordsets#intersection/2">ordsets:intersection/2</seemfa>
+ used on <seeerl marker="stdlib:ordsets">ordsets</seeerl> can be more
+ efficient than <c>maps:intersect/2</c> on sets implemented as maps.</p></note>
+ </section>
+
+ <section>
+ <title>maps:from_list/1</title>
+ <p><seemfa marker="stdlib:maps#from_list/1">maps:from_list/1</seemfa> is
+ implemented in C.</p>
+ </section>
+
+ <section>
+ <title>maps:from_keys/2</title>
+ <p><seemfa marker="stdlib:maps#from_keys/2">maps:from_keys/2</seemfa> is
+ implemented in C.</p>
+ </section>
+
+ <section>
+ <title>maps:is_key/2</title>
+ <p>As an optimization, the compiler rewrites calls to <seemfa
+ marker="stdlib:maps#is_key/2">maps:is_key/2</seemfa> to calls
+ to the guard BIF <seemfa
+ marker="erts:erlang#is_map_key/2">is_map_key/2</seemfa>. A call
+ to a guard BIF is more efficient than calls to other BIFs,
+ making the performance similar to using the map matching syntax.</p>
+ </section>
+
+ <section>
+ <title>maps:iterator/1</title>
+ <p><seemfa marker="stdlib:maps#iterator/1">maps:iterator/1</seemfa>
+ is efficiently implemented in C and Erlang.</p>
+ </section>
+
+ <section>
+ <title>maps:keys/1</title>
+ <p><seemfa marker="stdlib:maps#keys/1">maps:keys/1</seemfa> is
+ implemented in C. If the resulting list needs to be ordered, use
+ <seemfa marker="stdlib:lists#sort/1">lists:sort/1</seemfa> to
+ sort the result.</p>
+ </section>
+
+ <section>
+ <title>maps:map/2</title>
+ <p><seemfa marker="stdlib:maps#map/2">maps:map/2</seemfa> is
+ implemented in Erlang. It creates a new map using <seemfa
+ marker="stdlib:maps#from_list/1">maps:from_list/1</seemfa>. If
+ it is known that only a minority of the values will be updated,
+ it can be more efficient to avoid <c>maps:map/2</c> and write a
+ function that will call <seemfa
+ marker="stdlib:maps#update/3">maps:update/3</seemfa> to update
+ only the values that have changed.</p>
+ </section>
+
+ <section>
+ <title>maps:merge/2</title>
+ <p><seemfa marker="stdlib:maps#merge/2">maps:merge/2</seemfa>
+ is implemented in C.</p>
+ </section>
+
+ <section>
+ <title>maps:merge_with/3</title>
+ <p><seemfa marker="stdlib:maps#merge_with/3">maps:merge_with/3</seemfa>
+ is implemented in Erlang. It updates and returns the larger of the
+ two maps.</p>
+ </section>
+
+ <section>
+ <title>maps:new/0</title>
+ <p>The compiler rewrites a call to <seemfa
+ marker="stdlib:maps#new/0">maps:new/0</seemfa> to using the
+ syntax <c>#{}</c> for constructing an empty map.</p>
+ </section>
+
+ <section>
+ <title>maps:next/1</title>
+ <p><seemfa marker="stdlib:maps#next/1">maps:next/1</seemfa>
+ is efficiently implemented in C and Erlang.</p>
+ </section>
+
+ <section>
+ <title>maps:put/3</title>
+ <p><seemfa marker="stdlib:maps#put/3">maps:put/3</seemfa> is
+ implemented in C.</p>
+ <p>If the key is known to already exist in the map, <seemfa
+ marker="stdlib:maps#update/3">maps:update/3</seemfa> is
+ slightly more efficient than <c>maps:put/3</c>.</p>
+ <p>If the keys are constants known at compile-time, using the
+ map update syntax with the <c>=></c> operator is more
+ efficient than multiple calls to <c>maps:put/3</c>,
+ especially for small maps.</p>
+ </section>
+
+ <section>
+ <title>maps:remove/2</title>
+ <p><seemfa marker="stdlib:maps#remove/2">maps:remove/2</seemfa>
+ is implemented in C.</p>
+ </section>
+
+ <section>
+ <title>maps:size/1</title>
+ <p>As an optimization, the compiler rewrites calls to
+ <seemfa marker="stdlib:maps#size/1">maps:size/1</seemfa>
+ to calls to the guard BIF <seemfa
+ marker="erts:erlang#map_size/1">map_size/1</seemfa>.
+ Calls to guard BIFs are more efficient than calls to other BIFs.</p>
+ </section>
+
+ <section>
+ <title>maps:take/2</title>
+ <p><seemfa marker="stdlib:maps#take/2">maps:take/2</seemfa>
+ is implemented in C.</p>
+ </section>
+
+ <section>
+ <title>maps:to_list/1</title>
+ <p><seemfa
+ marker="stdlib:maps#to_list/1">maps:to_list/1</seemfa> is
+ efficiently implemented in C and Erlang. If the resulting list
+ needs to be ordered, use <seemfa
+ marker="stdlib:lists#sort/1">lists:sort/1</seemfa> to sort
+ the result.</p>
+
+ <note><p>Maps are usually more performant than <seeerl
+ marker="stdlib:gb_trees">gb_trees</seeerl>, but if it is
+ necessary to frequently convert to and from sorted lists,
+ <c>gb_trees</c> can be a better choice.</p></note>
+ </section>
+
+ <section>
+ <title>maps:update/3</title>
+ <p><seemfa marker="stdlib:maps#update/3">maps:update/3</seemfa>
+ is implemented in C.</p>
+
+ <p>If the keys are constants known at compile-time, using the
+ map update syntax with the <c>:=</c> operator is more
+ efficient than multiple calls to <c>maps:update/3</c>,
+ especially for small maps.</p>
+ </section>
+
+ <section>
+ <title>maps:values/1</title>
+ <p><seemfa marker="stdlib:maps#values/1">maps:values/1</seemfa>
+ is implemented in C.</p>
+ </section>
+
+ <section>
+ <title>maps:with/2</title>
+ <p><seemfa marker="stdlib:maps#with/2">maps:with/2</seemfa>
+ is implemented in Erlang. It creates a new map using <seemfa
+ marker="stdlib:maps#from_list/1">maps:from_list/1</seemfa>.</p>
+ </section>
+
+ <section>
+ <title>maps:without/2</title>
+ <p><seemfa marker="stdlib:maps#without/2">maps:without/2</seemfa>
+ is implemented in Erlang. It returns a modified copy of the
+ input map.</p>
+ </section>
+ </section>
+</chapter>
diff --git a/system/doc/efficiency_guide/part.xml b/system/doc/efficiency_guide/part.xml
index 5673ddd320..1d65b3104a 100644
--- a/system/doc/efficiency_guide/part.xml
+++ b/system/doc/efficiency_guide/part.xml
@@ -32,6 +32,7 @@
<xi:include href="myths.xml"/>
<xi:include href="commoncaveats.xml"/>
<xi:include href="binaryhandling.xml"/>
+ <xi:include href="maps.xml"/>
<xi:include href="listhandling.xml"/>
<xi:include href="functions.xml"/>
<xi:include href="tablesDatabases.xml"/>
diff --git a/system/doc/efficiency_guide/xmlfiles.mk b/system/doc/efficiency_guide/xmlfiles.mk
index e275823dd1..3df2e8bd21 100644
--- a/system/doc/efficiency_guide/xmlfiles.mk
+++ b/system/doc/efficiency_guide/xmlfiles.mk
@@ -24,7 +24,8 @@ EFF_GUIDE_CHAPTER_FILES = \
functions.xml \
introduction.xml \
listhandling.xml \
- myths.xml \
+ maps.xml \
+ myths.xml \
part.xml \
processes.xml \
profiling.xml \
--
2.31.1