    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Using Compile Time Maps for Sorting</title>
        <link>https://members.accu.org/index.php/journals/2771</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>


        <h2>Journal Articles</h2>


<div class="xar-mod-head"><span class="xar-mod-title">Overload Journal #156 - April 2020 + Programming Topics</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c409/">o156</a>
                    (8)
<br />

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c65/">Programming</a>
                    (877)
<br />

                                            <a href="https://members.accu.org/index.php/journals/c409-65/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/journals/c409+65/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Using Compile Time Maps for Sorting</h1>
<p><strong>Author:</strong>&nbsp;Bob Schmidt</p>
<p>
<strong>Date:</strong> 04 April 2020 18:51:45 +01:00 or Sat, 04 April 2020 18:51:45 +01:00</p>
<p><strong>Summary:</strong>&nbsp;Compile time sorting can be interesting. Norman Wilson shows how to sort a map.</p>
<p><strong>Body:</strong>&nbsp;<p>In the previous article I described a way of doing compile time sorting. One of the questions that came out of this was why would anyone want to do that? The first answer is just for fun, itâ€™s just pretty for its own sake, and I think we as programmers ought to be able to appreciate that even if there is no practical use. To put it another way, quoting Albert Einstein, what use is a newborn baby? Secondly, the sorting algorithm illustrates some techniques that can be applied more generally to solve other problems â€“ really itâ€™s just playing with parameter pack expansion. Last but not least, there are real reasons why youâ€™d want to sort at compile time and in this article Iâ€™m going to show you one.</p>

<p>Firstly though Iâ€™m going to show another little trick, apply it to create yet another compile time sorting algorithm and then use that to solve a practical problem.</p>

<h2>A simple compile time map</h2>

<p>Look at the following bit of code.</p>

<pre class="programlisting">
  template&lt;typename... Members&gt;
  struct Map: Members... {};</pre>

<p>If we instantiate <code>Map</code> with a pack of types, (assuming we can derive from  all of the types) we end up with a type that is a composition of these. Furthermore we also know we can implicitly cast from the composed type to any of its bases. So given:</p>

<pre class="programlisting">
  struct A {}; struct B {}; struct C {};
  auto abc = Map&lt;A, B, C&gt;{};</pre>
  
<p>Then I can select the <code>A</code> base of <code>abc</code> like this:</p>

<pre class="programlisting">
  inline decltype(auto) getA(const A&amp; a)
  { return a; }
  const A&amp; a = getA(abc);</pre>

<p>And similarly for the other bases. Nothing particularly radical about that, but what if our bases look like this?</p>

<pre class="programlisting">
  #include &lt;cstddef&gt;
  
  template&lt;std::size_t key, typename Value&gt;
  struct Pair { using type = Value; };</pre>

<p>Now we can write a generalised <code>get</code>.</p>

<pre class="programlisting">
  template&lt;std::size_t key, typename Value&gt;
  inline constexpr decltype(auto) 
    get(const Pair&lt;key, Value&gt;&amp; result)
  { return result; }</pre>

<p>The crucial thing is that type deduction now comes into play. So given:</p>

<pre class="programlisting">
  using ABCMap = Map&lt;Pair&lt;0, A&gt;, Pair&lt;1, B&gt;,
    Pair&lt;2, C&gt; &gt;;
  ABCMap abcMap;</pre>

<p>I can write:</p>

<pre class="programlisting">
  #include &lt;utility&gt;
  #include &lt;type_traits&gt;
  
  const auto&amp; x = get&lt;1&gt;(abcMap);</pre>

<p>We have constrained key and, since our keys are unique, when the compiler tries to deduce <code>Value</code> there is only one possible solution, <code>abcMap</code> must be cast to <code>const Pair&lt;1, B&gt;&amp;</code>. The expression is unambiguous and <code>x</code> ends up referencing the appropriate base of <code>abcMap</code>.</p>

<pre class="programlisting">
  static_assert(std::is_same_v&lt;std::decay_t
    &lt;decltype(x)&gt;, Pair&lt;1, B&gt; &gt;,
    &quot;get() pulls out the corresponding base.&quot;);</pre>

<p>We can translate this back to the world of types with this slightly ugly incantation:</p>

<pre class="programlisting">
  template&lt;typename M, std::size_t key&gt;
  using Get = typename std::decay_t&lt;
    decltype(get&lt;key&gt;(std::declval&lt;M&gt;()))&gt;::type;
  static_assert(std::is_same_v&lt;Get&lt;ABCMap, 2&gt;, C&gt;,
   &quot;Get works too.&quot;);</pre>

<p>So we have a very simple way of mapping from integers to types. The <code>key</code> doesnâ€™t have to be a non-type and it doesnâ€™t have to be an <code>int</code>, but it does have to be a compile time construct. There are other ways of making compile time maps but I quite like this one as itâ€™s simple, and uses the basic rules of C++ that we all (should) understand. This <code>map</code> type is obviously very similar to <code>std::tuple</code> â€“ but weâ€™ll come back to that later. The order we declare the pairs in the mapping is not important. We could have said:</p>

<pre class="programlisting">
  using ABCMap2 = Map&lt;Pair&lt;2, C&gt;, Pair&lt;1, B&gt;,
    Pair&lt;0, A&gt; &gt;;</pre>

<p>Type deduction will still produce the same result â€“ another MacGuffin.</p>

<h2>Another way to sort</h2>

<p>If we can rank each element of a set, then sorting is just forming a mapping from rank to element. In other words a sorted sequence allows us to access the elements by rank. Letâ€™s express that in code.</p>

<p>Letâ€™s start with a simple type:</p>

<pre class="programlisting">
  template&lt;typename... Ts&gt; struct TypeList {};</pre>

<p>Primary definition. We require an <code>index_sequence</code>, some traits to generalize how we do the sort and some types to sort.</p>

<pre class="programlisting">
  template&lt;typename Index, typename Traits,
    typename... Ts&gt; struct MapSortImpl;</pre>

<p>Partially specialize to break out the <code>index_sequence</code>. The index pack gives us 0..<code>sizeof..(Ts) - 1</code>. This corresponds to the position of each <code>T</code> in <code>Ts</code>. Weâ€™ll need this throughout the following code and a shorthand to use traits.</p>

<pre class="programlisting">
  template&lt;std::size_t... index, typename Traits,
  typename... Ts&gt;
  struct MapSortImpl&lt;std::index_sequence&lt;index...&gt;,
    Traits, Ts...&gt;: Traits
  {</pre>

<p>Note weâ€™ve derived from <code>Traits</code> to make this easier.</p>

<pre class="programlisting">
    template&lt;typename T&gt;
    static constexpr auto value()
    { return Traits::template value&lt;T&gt;(); }
    using Traits::compare;</pre>

<p>How do we find the rank of an element? Firstly we count up how many other elements rank lower than it using the traits <code>compare</code> function.</p>

<p>We then consider equal ranking elements. We want a stable sort, so we add on the count of the equal elements preceding this element in the list. This keeps equal ranking elements in their existing order and ensures every element has a well defined place.</p>

<p>In order to find the rank of element <code>T</code> which was at position <code>pos</code> in <code>Ts</code>, we need the following function:</p>

<pre class="programlisting">
    template&lt;typename T, std::size_t pos&gt;
    static constexpr auto rankOf()
    {
      auto countOfTsWithLesserValue =
        (compare(value&lt;Ts&gt;(), value&lt;T&gt;()) +...);
      auto countOfEqualTsPrecedingInList =
        ((value&lt;T&gt;() == value&lt;Ts&gt;() &amp;&amp; index &lt; pos)
        +...);
      return countOfTsWithLesserValue +
        countOfEqualTsPrecedingInList;
    }</pre>

<p>Now we can define the ranking as a mapping from rank to <code>T</code> for each <code>T</code> in <code>Ts</code>.</p>

<pre class="programlisting">
    using Ranking = Map&lt;Pair&lt;rankOf&lt;Ts, index&gt;(),
      Ts&gt;...&gt;;</pre>

<p>Can you dig it? What Iâ€™m saying here is <code>Ranking</code> is a map whose keys are the ranks (defined by <code>rankOf()</code>) of the corresponding <code>Ts</code>. In other words, itâ€™s a map from sorted position to type.</p>

<p>We can produce the sorted result by <code>Get</code>ting from the ranking map in sequence.</p>

<pre class="programlisting">
    static constexpr auto sort()
    { return TypeList&lt;Get&lt;Ranking, index&gt;...&gt;{}; }
  };</pre>

<p>Finally some syntactic sugar.</p>

<pre class="programlisting">
  template&lt;typename Traits, typename... Ts&gt;
  inline constexpr auto mapSort(TypeList&lt;Ts...&gt;)
  {
    return
      MapSortImpl&lt;std::index_sequence_for&lt;Ts...&gt;,
      Traits, Ts...&gt;::sort();
  }</pre>

<p>Does it work? See Listing 1.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
#include &lt;functional&gt;
  
template&lt;int i&gt;
using Int = std::integral_constant&lt;int, i&gt;;
  
struct Traits {
  template&lt;typename T&gt;
  static constexpr auto value()
  { return T::value; }
  static constexpr std::less&lt;&gt; compare;
};
using In = TypeList&lt;Int&lt;42&gt;, Int&lt;7&gt;, Int&lt;13&gt;,
  Int&lt;7&gt; &gt;;
using Out = decltype(mapSort&lt;Traits&gt;(In{}));
static_assert(
  std::is_same_v&lt; Out, TypeList&lt;Int&lt;7&gt;, Int&lt;7&gt;,
  Int&lt;13&gt;, Int&lt;42&gt; &gt; &gt;, &quot;mapSort works!&quot;);
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 1</td>
	</tr>
</table>

<h2>Whatâ€™s the point?</h2>

<p>Consider:</p>

<pre class="programlisting">
  using T1 = std::tuple&lt;bool, std::int16_t, char,
    std::int32_t, std::int64_t&gt;;
  static_assert(sizeof(T1) == 24, 
    &quot;pathological case std::tuple pads&quot;);

  using T2 = std::tuple&lt;std::int64_t, std::int32_t,
    std::int16_t, bool, char&gt;;
  static_assert(sizeof(T2) == 16, 
    &quot;efficient layout sorts by size&quot;);</pre>

<p>We all know that on most architectures types have an alignment. And we ought to know that to get a space-efficient layout, we should sort our members by size, biggest to smallest. Efficient layouts make better use of cache and that makes code go faster.</p>

<p>In many cases where we define a <code>std::tuple</code> we can rearrange the members by hand for efficiency, but sometime we might not be able to â€“ maybe the type is generated by TMP, or maybe we want future proof our code against changes which affect the alignments. So can we come up with something like a <code>std::tuple</code> but which automatically lays itself out efficiently? Letâ€™s try.</p>

<p>Firstly weâ€™ll revisit the compile time map we started with, but with a little tweak. Field now holds a value.</p>

<pre class="programlisting">
  template&lt;std::size_t key, typename T&gt;
  struct Field { T value; };</pre>

<p><code>get()</code> returns that value.</p>

<pre class="programlisting">
  template&lt;std::size_t key, typename T&gt;
  decltype(auto) get(const Field&lt;key, T&gt;&amp; f)
  { return (f.value); }</pre>

<p>We can actually reuse the <code>Map</code> template but the name no longer makes sense so Iâ€™ll rename it.</p>

<pre class="programlisting">
  template&lt;typename... Ts&gt;
  using Tuple = Map&lt;Ts...&gt;;</pre>

<p>To prove this works I define the contents of Listing 2.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
template&lt;std::size_t key, typename T,
  typename Tuple&gt;
constexpr auto checkType(Tuple&amp;&amp; t)
{
  return
    std::is_same_v&lt;std::decay_t
    &lt;decltype(get&lt;key&gt;(t))&gt;, T&gt;;
}
auto boolShort = Tuple&lt;Field&lt;0, bool&gt;, Field&lt;1,
  std::int16_t&gt; &gt;{};
static_assert(checkType&lt;0, bool&gt;(boolShort),
  &quot;pulls out bool&quot;);
static_assert(checkType&lt;1,
  std::int16_t&gt;(boolShort), &quot;pulls out short&quot;);
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 2</td>
	</tr>
</table>

<p>So weâ€™ve defined the very barest bones of a tuple template. I leave it to the reader to flesh out the missing parts. The important difference from <code>std::tuple</code> is that we explicitly associate a key with an element. The keys could be given out of order and could be non-contiguous, but the association between key and type is still maintained. So we can define a tuple where the elements can be reordered to form a space efficient layout? All we need to do now is sort the types by size. Listing 3 shows we do that.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
// First we define an appropriate traits class.
struct EfficientLayoutTraits
{
  // We want to sort by size.
  template&lt;typename T&gt;
  static constexpr auto value()
  { return sizeof(T::value); }
  
  // Biggest first.
  static constexpr std::greater&lt;&gt; compare;
};

// A little helper that transforms a TypeList 
// to a Tuple.
template&lt;typename... Ts&gt;
auto typeListToTuple(TypeList&lt;Ts...&gt;)
{ return Tuple&lt;Ts...&gt;{}; }

// Shorthand to expand index_sequence. This little
// function deserves an article in itself.
template&lt;std::size_t... index, typename F&gt;
auto applySequence(std::index_sequence&lt;index...&gt;,
  F&amp;&amp; f)
{
  return f(std::integral_constant&lt;std::size_t,
    index&gt;{}...);
}

// Given some Ts create a Tuple with efficient
// layout.
template&lt;typename... Ts&gt;
auto makeEfficientLayout()
{
  // Form a list of Fields containing Ts,
  // indexed by declaration order.
  auto unsortedFields = applySequence(
    std::index_sequence_for&lt;Ts...&gt;{},
    [](auto... index)
    { return TypeList&lt;Field&lt;index, Ts&gt;...&gt;{}; });
  // Sort it using our traits.
  auto sortedFields =
    mapSort&lt;EfficientLayoutTraits&gt;
    (unsortedFields);
  // Turn it into a Tuple.
  return typeListToTuple(sortedFields);
}
// Our previous pathological case.
auto efficientTuple = 
  makeEfficientLayout&lt;bool, std::int16_t,
  char, std::int32_t, std::int64_t&gt;();

// Tuple elements have been reordered to use
// minimum space.
static_assert(sizeof(efficientTuple) == 
  16, &quot;QED&quot;);
// But are accessed by original declaration order.
static_assert(checkType&lt;0, 
  bool&gt;(efficientTuple));
static_assert(checkType&lt;1,
  std::int16_t &gt;(efficientTuple));
static_assert(checkType&lt;2,
  char&gt;(efficientTuple));
static_assert(checkType&lt;3,
  std::int32_t &gt;(efficientTuple));
static_assert(checkType&lt;4,
  std::int64_t &gt;(efficientTuple));

int main(){}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 3</td>
	</tr>
</table>

<h2>Footnote: is it any good?</h2>

<p>The sort I presented in the previous article â€“ no. Itâ€™s actually astonishingly bad. Never in all my time as a programmer have I burned so many clock cycles on so simple a problem. So lets add another reason to why youâ€™d want to do a compile time sort â€“ you can go and make a coffee while your code is compiling.</p>

<p>What about <code>mapSort</code>? Thatâ€™s actually much better but is still at least <em>n</em><sup>2</sup>. Iâ€™ve pulled down the code for <code>skew_sort</code> that comes from the <em>Stack Overflow</em> thread [<a href="#[Stackoverflow]">Stackoverflow</a>] that started all this off to compare. The graphs show this is radically faster than both, but blows the compilerâ€™s maximum template recursion depth for data sets larger that 1024. Clearly the story is not over. Can we write a non-recursive sort in <code>n log(n)</code>? Will it be any good? Find out next time.</p>

<h2>Reference</h2>

<p class="bibliomixed"><a id="[Stackoverflow]"></a>[Stackoverflow] â€˜C++ calculate and sort vector at compile timeâ€™, available from https://stackoverflow.com/questions/32660523/c-calculate-and-sort-vector-at-compile-time</p>

<p class="bio"><span class="author"><b>Norman Wilson</b></span> has been coding since he was a spotty teenager in the early 80s and learned C++ while at university. Since then heâ€™s spent most of his career in finance. When not staring at template error messages, he rock climbs, makes music and helps bring up three daughters.</p>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
