<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Daniele Margutti</title>
 <subtitle>Post in italiano</subtitle>
 <link href="https://www.danielemargutti.com/atom-it.xml" rel="self"/>
 <link href="https://www.danielemargutti.com/"/>
 <updated>2026-09-25T17:01:03+00:00</updated>
 <id>https://www.danielemargutti.com</id>
 <author>
   <name>Daniele Margutti</name>
   <uri>https://www.danielemargutti.com</uri>
 </author>

 
 
 <entry>
   <title>L&apos;intuito mente: lezioni da un parser CSV — Parte 3: Il 9%</title>
   <link href="https://www.danielemargutti.com/it/2026/09/14/parser-csv-il-nove-percento/"/>
   <summary>Una volta misurata l&apos;intera pipeline arriva la sorpresa: la fase su cui mi ero accanito pesa appena il 9% del lavoro reale.</summary>
   <updated>2026-09-14T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/it/2026/09/14/parser-csv-il-nove-percento</id>
   <content type="html">&lt;!-- Series navigation: shows prev/next in multi-part articles --&gt;
&lt;!--
  ATTENZIONE: niente indentazione nell&apos;HTML qui sotto.
  Questo include viene iniettato dentro il corpo Markdown dei post, e kramdown
  tratta come blocco di codice qualunque riga rientrata di 4 o piu spazi:
  il markup finirebbe stampato a schermo invece di essere renderizzato.
--&gt;

&lt;!-- Find all posts in this series --&gt;

&lt;div class=&quot;series-nav&quot;&gt;
&lt;div class=&quot;series-header&quot;&gt;
&lt;div class=&quot;series-badge&quot;&gt;
Part &lt;span class=&quot;series-part&quot;&gt;3&lt;/span&gt; of &lt;span class=&quot;series-total&quot;&gt;3&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;series-progress&quot;&gt;
&lt;div class=&quot;series-bar&quot;&gt;
&lt;div class=&quot;series-fill&quot; style=&quot;width: calc(3 / 3 * 100%)&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;nav class=&quot;series-links&quot;&gt;
&lt;!-- Previous button --&gt;



&lt;a href=&quot;/it/2026/09/14/parser-csv-corretto-poi-veloce/&quot; class=&quot;series-link series-prev&quot;&gt;
&lt;span class=&quot;series-label&quot;&gt;← Previous&lt;/span&gt;
&lt;span class=&quot;series-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 2: Corretto, poi veloce&lt;/span&gt;
&lt;/a&gt;






&lt;!-- Next button --&gt;

&lt;/nav&gt;

&lt;!-- All parts overview --&gt;
&lt;details class=&quot;series-all&quot;&gt;
&lt;summary&gt;View all parts&lt;/summary&gt;
&lt;ul class=&quot;series-list&quot;&gt;

&lt;li&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-corretto-poi-veloce/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 2&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 2: Corretto, poi veloce&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;li class=&quot;is-current&quot;&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-il-nove-percento/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 3&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 3: Il 9%&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;
&lt;/details&gt;
&lt;/div&gt;

&lt;style&gt;
.series-nav {
  margin: var(--s-7) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.series-header {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}

.series-badge {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
}

.series-progress {
  flex: 1;
}

.series-bar {
  height: 4px;
  background: var(--rule);
  border-radius: 2px;
  overflow: hidden;
}

.series-fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.3s ease;
}

.series-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}

.series-link {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  padding: var(--s-3) var(--s-4);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  transition: border-color 0.18s ease, transform 0.18s ease;
}

.series-link:hover {
  border-color: var(--accent-soft);
  transform: translateY(-2px);
}

/* Il tema aggiunge una freccia dopo ogni link nel corpo del post. Qui e&apos; di
   troppo: la direzione la dicono gia&apos; le etichette &quot;Previous&quot;/&quot;Next&quot;, e su
   &quot;Previous&quot; punterebbe pure dalla parte sbagliata. Per spegnerla serve
   almeno la specificita&apos; della regola base (0,3,2), quindi la catena di
   :not() va ripetuta. */
.post-body .series-nav a:not(.tag):not(.entry-link)::after {
  content: none;
}

.series-label {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.series-link:hover .series-label {
  color: var(--accent);
}

.series-title {
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  line-height: 1.3;
}

.series-all {
  cursor: pointer;
}

.series-all summary {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--s-2);
  margin: calc(-1 * var(--s-2));
  transition: color 0.18s ease;
}

.series-all summary:hover {
  color: var(--accent);
}

.series-all[open] summary {
  color: var(--accent);
  margin-bottom: var(--s-3);
}

.series-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.series-list li {
  margin: 0;
}

.series-list a {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-radius: 4px;
  color: var(--text);
  text-decoration: none;
  transition: background-color 0.18s ease, color 0.18s ease;
}

.series-list a:hover {
  background-color: var(--bg);
  color: var(--accent);
}

.series-list li.is-current a {
  background-color: var(--bg);
  color: var(--accent);
  font-weight: 600;
}

.series-num {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
}

.series-list li.is-current .series-num {
  color: var(--accent);
}

.series-item-title {
  flex: 1;
  font-family: var(--font-ui);
}
&lt;/style&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;Dove eravamo rimasti&lt;/strong&gt;
    
    &lt;p&gt;Un parser che non si fa ingannare da una virgoletta in mezzo a un campo, costruito sopra un file mappato in memoria.&lt;br /&gt;&lt;br /&gt;L&amp;#39;indicizzazione è scesa da 0,38 a 0,065 secondi grazie a &lt;code&gt;memchr&lt;/code&gt; e a un controllo che decide da solo quando può permettersi la scorciatoia. Le righe non copiano un byte, e i campi si materializzano soltanto se qualcuno li chiede.&lt;/p&gt;&lt;p&gt;Tutto misurato, tutto più veloce di prima.&lt;/p&gt;Tranne che non avevo mai cronometrato il lavoro completo.
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;h2 id=&quot;il-9&quot;&gt;Il 9%&lt;/h2&gt;

&lt;p&gt;Era giunto il momento di riprendere il cronometro in mano per misurare le fasi separatamente. Il trucco è far girare il ciclo con il corpo vuoto:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Questo divide ogni riga nei suoi campi e poi butta via tutto senza costruire un solo valore. La differenza fra questo tempo e quello del ciclo che fa davvero il lavoro è, per sottrazione, il costo della materializzazione degli oggetti.&lt;/p&gt;

&lt;p&gt;Tre misure da prendere:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;l’apertura del file&lt;/li&gt;
  &lt;li&gt;il ciclo a vuoto&lt;/li&gt;
  &lt;li&gt;il ciclo vero&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- Linked code snippet: click to view in popup --&gt;

&lt;div class=&quot;code-link-block&quot;&gt;
&lt;a href=&quot;#&quot; class=&quot;code-link&quot; data-code-id=&quot;test-stop-times&quot; data-code-title=&quot;The test: the pipeline broken down by phases&quot; data-code-subtitle=&quot;The complete code is on GitHub, along with the file used for measurements.&quot;&gt;&lt;svg class=&quot;icon&quot; viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.5&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M7.2 6.4 3.4 10l3.8 3.6M12.8 6.4 16.6 10l-3.8 3.6M11.4 4.6 8.6 15.4&quot; /&gt;&lt;/svg&gt;
&lt;span class=&quot;code-link-text&quot;&gt;&lt;span class=&quot;code-link-label&quot;&gt;The test: the pipeline broken down by phases&lt;/span&gt;&lt;span class=&quot;code-link-note&quot;&gt;The complete code is on GitHub, along with the file used for measurements.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;code-link-source&quot; id=&quot;code-src-test-stop-times&quot; hidden=&quot;&quot;&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;kd&quot;&gt;@Test&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stopTimes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;clock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ContinuousClock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Warm-up: one empty run brings the 260 MB into page cache.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Without it, the first measurement times the disk instead of the code—the same&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// read goes from ~0.19s to ~0.44s depending on whether pages are there or not.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;warmup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hasHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;#expect(warmup.rowCount &amp;gt; 0)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 1 — indexing (the init: mmap, sniff, scan for offsets)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rssBefore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;residentMemoryMB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hasHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;indexing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rssAfterIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;residentMemoryMB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iTrip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;trip_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iArr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;arrival_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;departure_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iStop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iSeq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_sequence&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iHead&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_headsign&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iPick&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pickup_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDrop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;drop_off_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;shape_dist_traveled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;timepoint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Issue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;header diverso da quello atteso: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columnNames&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2a — just iteration: splitFields on every row, empty body.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Isolates the cost of splitting into fields from materializing values.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rowsVisited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tSplit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rowsVisited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;splitOnly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tSplit&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2b — direct access, building the exact same StopTime&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;builtDirectly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;trip_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTrip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;arrival_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;departure_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iSeq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_headsign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isFieldEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;pickup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iPick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;drop_off_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;shape_dist_traveled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;doubleField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;timepoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;builtDirectly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;direct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2c — the same StopTime, but converting numbers by passing through String:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// it&apos;s the obvious way, what you&apos;d write without typed accessors.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;builtViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;trip_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTrip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;arrival_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;departure_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iSeq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_headsign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isEmpty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;pickup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iPick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;drop_off_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;shape_dist_traveled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;timepoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;builtViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;viaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tStr&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 3 — the same thing via Codable&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;codable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;#expect(rowsVisited == reader.rowCount)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == decoded)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == builtViaStrings)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == reader.rowCount)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;valuesViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viaStrings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;

    ── stop_times.txt — &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rowCount&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; righe ──
      1. indicizzazione         &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexing&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;   (RSS +&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.0f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rssAfterIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rssBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; MB)
      2a. solo splitFields      &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2b. + accessori tipizzati &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2c. + conversione da String &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viaStrings&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      3. Codable                &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codable&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;

         dividere in campi        &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         materializzare (tipizzati)  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         materializzare (da String)  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;valuesViaStrings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         gli accessori tipizzati fanno risparmiare &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;valuesViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x
         Codable costa &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x l&apos;accesso diretto

    &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/div&gt;

&lt;script&gt;
(function() {
  if (window.__codeLinkReady) return;
  window.__codeLinkReady = true;

  /* Create popup container */
  const popup = document.createElement(&apos;div&apos;);
  popup.className = &apos;code-popup&apos;;
  popup.innerHTML = `
    &lt;div class=&quot;code-popup-backdrop&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;code-popup-dialog&quot;&gt;
      &lt;div class=&quot;code-popup-header&quot;&gt;
        &lt;div class=&quot;code-popup-heading&quot;&gt;
          &lt;h3 id=&quot;code-popup-title&quot;&gt;&lt;/h3&gt;
          &lt;p class=&quot;code-popup-subtitle&quot; id=&quot;code-popup-subtitle&quot; hidden&gt;&lt;/p&gt;
        &lt;/div&gt;
        &lt;button class=&quot;code-popup-close&quot; aria-label=&quot;Close&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;line x1=&quot;18&quot; y1=&quot;6&quot; x2=&quot;6&quot; y2=&quot;18&quot; /&gt;
            &lt;line x1=&quot;6&quot; y1=&quot;6&quot; x2=&quot;18&quot; y2=&quot;18&quot; /&gt;
          &lt;/svg&gt;
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;code-popup-content&quot; id=&quot;code-popup-content&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;code-popup-footer&quot;&gt;
        &lt;button class=&quot;code-popup-expand&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;path d=&quot;M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3&quot; /&gt;
          &lt;/svg&gt;
          Expand to fullscreen
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
  document.body.appendChild(popup);

  const popupDialog = popup.querySelector(&apos;.code-popup-dialog&apos;);
  const popupBackdrop = popup.querySelector(&apos;.code-popup-backdrop&apos;);
  const popupTitle = popup.querySelector(&apos;#code-popup-title&apos;);
  const popupSubtitle = popup.querySelector(&apos;#code-popup-subtitle&apos;);
  const popupContent = popup.querySelector(&apos;#code-popup-content&apos;);
  const popupClose = popup.querySelector(&apos;.code-popup-close&apos;);
  const popupExpand = popup.querySelector(&apos;.code-popup-expand&apos;);

  function closePopup() {
    popup.classList.remove(&apos;is-open&apos;);
  }

  /* Close handlers */
  popupBackdrop.addEventListener(&apos;click&apos;, closePopup);
  popupClose.addEventListener(&apos;click&apos;, closePopup);
  document.addEventListener(&apos;keydown&apos;, (e) =&gt; {
    if (e.key === &apos;Escape&apos; &amp;&amp; popup.classList.contains(&apos;is-open&apos;)) {
      closePopup();
    }
  });

  /* Expand to fullscreen */
  popupExpand.addEventListener(&apos;click&apos;, () =&gt; {
    closePopup();
    /* Use the existing code-modal if available */
    const codeModal = document.querySelector(&apos;.code-modal&apos;);
    if (codeModal) {
      const modalCode = codeModal.querySelector(&apos;#code-modal-code&apos;);
      /* popupContent contiene gia il markup completo di Rouge, wrapper
         compreso, quindi si copia cosi com&apos;e */
      modalCode.innerHTML = popupContent.innerHTML;
      codeModal.classList.add(&apos;is-open&apos;);
      modalCode.focus();
    }
  });

  /* Prevent popup close when clicking inside */
  popupDialog.addEventListener(&apos;click&apos;, (e) =&gt; {
    e.stopPropagation();
  });

  /* Delega sul documento: cosi funziona anche per i link che nel DOM */
  /* arrivano dopo questo script. */
  document.addEventListener(&apos;click&apos;, (e) =&gt; {
    const link = e.target.closest(&apos;.code-link&apos;);
    if (link) {
      e.preventDefault();
      const codeId = link.getAttribute(&apos;data-code-id&apos;);
      const source = document.getElementById(&apos;code-src-&apos; + codeId);
      if (!source) return;

      popupTitle.textContent = link.getAttribute(&apos;data-code-title&apos;);

      const subtitle = link.getAttribute(&apos;data-code-subtitle&apos;);
      popupSubtitle.textContent = subtitle || &apos;&apos;;
      popupSubtitle.hidden = !subtitle;
      /* HTML gia evidenziato da Rouge in fase di build: porta con se il &lt;pre&gt;,
         quindi indentazione e colori sopravvivono alla compressione */
      popupContent.innerHTML = source.innerHTML;

      popup.classList.add(&apos;is-open&apos;);
    }
  });
})();
&lt;/script&gt;

&lt;style&gt;
/* Code link styling */
.code-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.5em 0.75em;
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--accent);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease;
}

.code-link:hover {
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-link .icon {
  /* due righe di testo accanto: un&apos;icona da 1em sparirebbe */
  width: 1.9em;
  height: 1.9em;
  flex: none;
  opacity: 0.75;
}

/* La freccia del tema qui e un&apos;affordance, non un ornamento da hover: dice
   che il link apre qualcosa. Va tenuta visibile, e per farlo bisogna ripetere
   la catena di :not() della regola base, che altrimenti pesa di piu (0,3,2)
   e rimette opacity a 0. */
.post-body a.code-link:not(.tag):not(.entry-link)::after {
  opacity: 1;
  transform: none;
  align-self: center;
}

.code-link-label { min-width: 0; }

.code-link-error {
  color: var(--text-muted);
  font-size: 0.9em;
}

/* Code popup */
.code-popup {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.code-popup.is-open {
  opacity: 1;
  pointer-events: auto;
}

.code-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
}

.code-popup-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: 70vw;
  max-height: 70vh;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.code-popup-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--rule);
}

.code-popup-header h3 {
  margin: 0;
  font-size: var(--t-0);
  font-weight: 600;
  font-family: var(--font-mono);
}

.code-popup-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}

.code-popup-close:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
}

.code-popup-close svg {
  width: 16px;
  height: 16px;
}

.code-popup-content {
  flex: 1;
  overflow: auto;
  padding: var(--s-4);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg-sunken);
}

.code-popup-content pre,
.code-popup-content .highlight,
.code-popup-content .highlighter-rouge {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  font-size: inherit;
  line-height: inherit;
}

/* il sorgente vive nella pagina solo per essere copiato nel popup */
.code-link-source { display: none; }

.code-link-block {
  display: flex;
  margin: var(--s-4) 0;
}

/* titolo e sottotitolo incolonnati dentro al riquadro, accanto all&apos;icona */
.code-link-text {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-width: 0;
}

.code-link-note,
.code-popup-subtitle {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--t--2);
  color: var(--text-muted);
  line-height: 1.4;
}

.code-popup-heading { min-width: 0; }

.code-popup-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--rule);
  background: var(--bg);
}

.code-popup-expand {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.45em 0.9em;
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--text);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}

.code-popup-expand:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-popup-expand svg {
  width: 1em;
  height: 1em;
}

/* Mobile responsive */
@media (max-width: 40rem) {
  .code-popup-dialog {
    max-width: 95vw;
    max-height: 80vh;
  }

  .code-popup-content {
    font-size: 0.75em;
  }
}
&lt;/style&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Fase&lt;/th&gt;
      &lt;th&gt;Tempo&lt;/th&gt;
      &lt;th&gt;Quota&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Indicizzazione&lt;/td&gt;
      &lt;td&gt;0,062s&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;9%&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dividere le righe in campi&lt;/td&gt;
      &lt;td&gt;0,260s&lt;/td&gt;
      &lt;td&gt;38%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Trasformare i campi in valori&lt;/td&gt;
      &lt;td&gt;0,427s&lt;/td&gt;
      &lt;td&gt;62%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Totale&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0,687s&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Mi ero concentrato a &lt;em&gt;spremere 315 millesimi dall’indicizzazione per poi scoprire che gli altri 625 millesimi non li avevo mai guardati&lt;/em&gt;. Non è che avessi ottimizzato male: l’indice adesso è davvero &lt;em&gt;cinque volte più veloce&lt;/em&gt;, e i numeri sono quelli. È che avevo ottimizzato con cura chirurgica la fase più piccola del programma, quella che nell’uso reale pesa meno di un decimo.&lt;/p&gt;

&lt;p&gt;Questo per due motivi:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;l’indice era la parte che vedevo&lt;/strong&gt;: il codice appena scritto, quello che avevo in testa. Le altre due fasi funzionavano già e proprio per questo erano invisibili&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;l’indice era l’unico ad avere un numero&lt;/strong&gt;: era facile da cronometrare, e quello che non ha un numero non compete per la nostra attenzione&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All’inizio ho citato Knuth tagliando la parola &lt;em&gt;premature&lt;/em&gt;. Ma la frase intera dice qualcosa di più specifico di quanto ricordassi:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«We should forget about small efficiencies, say about 97% of the time: &lt;em&gt;premature&lt;/em&gt; optimization is the root of all evil.»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Il 97% delle volte. Io ho trovato il mio 9% e mi ci sono buttato dentro con entusiasmo per tre sezioni.&lt;br /&gt;
La differenza fra me e quel consiglio non è che lui lo sapeva e io no: lo sapevo anch’io, l’ho scritto nell’introduzione di questo articolo.&lt;/p&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;È che sapere una cosa e averla misurata sono due stati mentali diversi, e solo il secondo cambia quello che fai il lunedì mattina.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;dividere-i-campi&quot;&gt;Dividere i campi&lt;/h2&gt;

&lt;p&gt;Dai test era evidente come il 38% del tempo se ne andava a spezzare le righe nelle loro colonne. E’ qui che mi sono accorto che la risposta ce l’avevo già in casa ma l’avevo buttata via.&lt;/p&gt;

&lt;p&gt;Se vi ricordate, all’apertura del file “annuso” le virgolette per decidere come costruire l’indice. Quel risultato (&lt;em&gt;“questo file non contiene nemmeno una virgoletta”&lt;/em&gt;) lo usavo per una riga di codice e poi lo scartavo. In realtà può essere utile anche dopo: &lt;strong&gt;se non ci sono virgolette in tutto il file, allora quando divido una riga in campi ogni virgola che incontro è un separatore vero, senza eccezioni da controllare.&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// `start` e `end` delimitano la riga da spezzare, `ranges` raccoglie i campi.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;splitFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ranges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;inout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ranges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;removeAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;keepingCapacity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// `hasQuotes` è l&apos;esito dell&apos;annusata fatta all&apos;apertura del file.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Se è falso, in tutti i 260 MB non c&apos;è una virgoletta: nessun campo&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// è quotato, e ogni virgola che incontro è un separatore vero.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasQuotes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fieldStart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// dove comincia il campo che sto leggendo&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// da dove riprendere a cercare&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// memchr cerca la prossima virgola fra `pos` e la fine della riga.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Il terzo argomento, `end - pos`, limita la ricerca a questa riga:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// non può sconfinare in quella dopo.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Restituisce nil quando non ne trova più: siamo all&apos;ultimo campo.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;memchr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delimiterByte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// memchr restituisce un puntatore, a me serve una posizione:&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// la ottengo sottraendo l&apos;indirizzo di partenza della mappa.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UnsafeRawPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UnsafeRawPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;ranges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldStart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// il campo va da fieldStart alla virgola&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;fieldStart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;// il prossimo comincia subito dopo&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// L&apos;ultimo campo non ha una virgola che lo chiude: finisce con la riga.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ranges&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldStart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Il file contiene virgolette: non si scappa dalla macchina a stati,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// byte per byte, con i quattro rami di prima.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;!-- Chart using Chart.js with theme colors --&gt;
&lt;div class=&quot;chart-container&quot; style=&quot;position: relative; height: 180px; margin: var(--s-5) 0;&quot;&gt;
  &lt;canvas id=&quot;chart-tempi-split&quot;&gt;&lt;/canvas&gt;
&lt;/div&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
(function() {
  /* Theme colors as CSS variables */
  const getComputedColor = (varName) =&gt; {
    return getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
  };

  const accentColor = getComputedColor(&apos;--accent&apos;);
  const accentSoft = getComputedColor(&apos;--accent-soft&apos;);
  const textColor = getComputedColor(&apos;--text&apos;);
  const textMuted = getComputedColor(&apos;--text-muted&apos;);
  const bgSunken = getComputedColor(&apos;--bg-sunken&apos;);

  /* Parse data from include parameters */
  const chartType = &apos;bar&apos;;
  const chartTitle = &apos;Secondi per spezzare in campi 5,6 milioni di righe&apos;;

  /* Parse labels and datasets from JSON strings */
  const labels = [&quot;Macchina a stati&quot;, &quot;memchr&quot;];
  const datasets = [{&quot;label&quot;:&quot;Secondi&quot;,&quot;data&quot;:[0.484, 0.323]}];

  /* Apply theme colors to datasets if not specified */
  const coloredDatasets = datasets.map((dataset, index) =&gt; {
    const colors = [accentColor, &apos;#a3b18a&apos;, &apos;#cf9b73&apos;, &apos;#dcc9a6&apos;, &apos;#c49a6c&apos;];
    return {
      ...dataset,
      borderColor: dataset.borderColor || colors[index % colors.length],
      backgroundColor: dataset.backgroundColor || (chartType === &apos;line&apos;
        ? colors[index % colors.length] + &apos;15&apos;
        : colors[index % colors.length]),
      borderWidth: dataset.borderWidth || (chartType === &apos;pie&apos; || chartType === &apos;doughnut&apos; ? 0 : 2),
      tension: dataset.tension || (chartType === &apos;line&apos; ? 0.4 : undefined),
      fill: dataset.fill !== undefined ? dataset.fill : (chartType === &apos;line&apos;),
    };
  });

  const ctx = document.getElementById(&apos;chart-tempi-split&apos;).getContext(&apos;2d&apos;);

  new Chart(ctx, {
    type: chartType,
    data: {
      labels: labels,
      datasets: coloredDatasets,
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      /* horizontal=&quot;true&quot; ribalta gli assi: utile con poche barre ed
         etichette lunghe, che cosi si leggono dritte invece che storte */
      indexAxis: &apos;y&apos;,
      plugins: {
        legend: {
          display: false,
          labels: {
            color: textMuted,
            font: { family: &quot;system-ui, -apple-system, &apos;Segoe UI&apos;, Arial, Helvetica, sans-serif&quot; },
            padding: 15,
          },
        },
        title: {
          display: chartTitle !== &apos;&apos;,
          text: chartTitle,
          color: textColor,
          font: { size: 16, weight: &apos;bold&apos;, family: &quot;system-ui, -apple-system, &apos;Segoe UI&apos;, Arial, Helvetica, sans-serif&quot; },
          padding: 20,
        },
      },
      scales: {
        x: {
          display: chartType !== &apos;pie&apos; &amp;&amp; chartType !== &apos;doughnut&apos;,
          ticks: { color: textMuted },
          grid: { color: bgSunken, drawBorder: false },
        },
        y: {
          display: chartType !== &apos;pie&apos; &amp;&amp; chartType !== &apos;doughnut&apos;,
          ticks: { color: textMuted },
          grid: { color: bgSunken, drawBorder: false },
          beginAtZero: true,
        },
      },
    },
  });
})();
&lt;/script&gt;

&lt;style&gt;
.chart-container {
  padding: var(--s-4);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
&lt;/style&gt;

&lt;p&gt;Un 1,5x.&lt;br /&gt;
&lt;em&gt;Mi aspettavo qualcosa di più.&lt;/em&gt;&lt;/p&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;Perché memchr questa volta non ci ha aiutati?&lt;/strong&gt;
    
    &lt;p&gt;Ma perchè così poco, se sull&apos;indice lo stesso approccio mi aveva portato un 5,7x? D&apos;altronde era la stessa funzione, stesso file, stessa idea.&lt;/p&gt;&lt;p&gt;In fondo però il motivo è molto più semplice: &lt;code&gt;memchr&lt;/code&gt; conviene quando il byte che cerchiamo è raro: carica sedici byte alla volta, li confronta tutti insieme, e ci guadagna finché continua a non trovare niente. Ogni chiamata ha però un costo fisso di avvio.&lt;/p&gt;&lt;p&gt;Sull&apos;indice cercavo gli a capo: uno ogni quarantasei byte. Tempo per prendere il ritmo, e cinque milioni di chiamate in tutto.&lt;/p&gt;&lt;p&gt;Qui cerco le virgole: una ogni quattro byte e mezzo, e cinquantasei milioni di chiamate. &lt;code&gt;memchr&lt;/code&gt; fa si e no un giro vettoriale e torna indietro. Di fatto è quasi il caso peggiore in cui può lavorare.&lt;/p&gt;&lt;p&gt;La stessa ottimizzazione, sugli stessi dati, vale cinque volte o una volta e mezza a seconda di quanto è fitto quello che stai cercando. Non esistono ottimizzazioni buone: esistono ottimizzazioni adatte a una certa forma dei dati.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;p&gt;A questo punto restava una una cosa evidente: per ogni campo facevo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;append&lt;/code&gt; su un array per cinquatasei milioni di righe, ognuno con il suo controllo di capacità e di unicità.&lt;/p&gt;

&lt;p&gt;Toglierli sembrava facile: se l’array è già dimensionato sul numero di colonne dell’header, posso scrivere direttamente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ranges[n]&lt;/code&gt; invece di accodare. L’idea era di recuperare fra 170 e 280 millesimi. Ne ho recuperati 48.&lt;/p&gt;

&lt;!-- Chart using Chart.js with theme colors --&gt;
&lt;div class=&quot;chart-container&quot; style=&quot;position: relative; height: 180px; margin: var(--s-5) 0;&quot;&gt;
  &lt;canvas id=&quot;chart-tempi-append&quot;&gt;&lt;/canvas&gt;
&lt;/div&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
(function() {
  /* Theme colors as CSS variables */
  const getComputedColor = (varName) =&gt; {
    return getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
  };

  const accentColor = getComputedColor(&apos;--accent&apos;);
  const accentSoft = getComputedColor(&apos;--accent-soft&apos;);
  const textColor = getComputedColor(&apos;--text&apos;);
  const textMuted = getComputedColor(&apos;--text-muted&apos;);
  const bgSunken = getComputedColor(&apos;--bg-sunken&apos;);

  /* Parse data from include parameters */
  const chartType = &apos;bar&apos;;
  const chartTitle = &apos;Secondi per spezzare in campi 5,6 milioni di righe&apos;;

  /* Parse labels and datasets from JSON strings */
  const labels = [&quot;Con append&quot;, &quot;Scrivendo per indice&quot;];
  const datasets = [{&quot;label&quot;:&quot;Secondi&quot;,&quot;data&quot;:[0.323, 0.275]}];

  /* Apply theme colors to datasets if not specified */
  const coloredDatasets = datasets.map((dataset, index) =&gt; {
    const colors = [accentColor, &apos;#a3b18a&apos;, &apos;#cf9b73&apos;, &apos;#dcc9a6&apos;, &apos;#c49a6c&apos;];
    return {
      ...dataset,
      borderColor: dataset.borderColor || colors[index % colors.length],
      backgroundColor: dataset.backgroundColor || (chartType === &apos;line&apos;
        ? colors[index % colors.length] + &apos;15&apos;
        : colors[index % colors.length]),
      borderWidth: dataset.borderWidth || (chartType === &apos;pie&apos; || chartType === &apos;doughnut&apos; ? 0 : 2),
      tension: dataset.tension || (chartType === &apos;line&apos; ? 0.4 : undefined),
      fill: dataset.fill !== undefined ? dataset.fill : (chartType === &apos;line&apos;),
    };
  });

  const ctx = document.getElementById(&apos;chart-tempi-append&apos;).getContext(&apos;2d&apos;);

  new Chart(ctx, {
    type: chartType,
    data: {
      labels: labels,
      datasets: coloredDatasets,
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      /* horizontal=&quot;true&quot; ribalta gli assi: utile con poche barre ed
         etichette lunghe, che cosi si leggono dritte invece che storte */
      indexAxis: &apos;y&apos;,
      plugins: {
        legend: {
          display: coloredDatasets.length &gt; 0,
          labels: {
            color: textMuted,
            font: { family: &quot;system-ui, -apple-system, &apos;Segoe UI&apos;, Arial, Helvetica, sans-serif&quot; },
            padding: 15,
          },
        },
        title: {
          display: chartTitle !== &apos;&apos;,
          text: chartTitle,
          color: textColor,
          font: { size: 16, weight: &apos;bold&apos;, family: &quot;system-ui, -apple-system, &apos;Segoe UI&apos;, Arial, Helvetica, sans-serif&quot; },
          padding: 20,
        },
      },
      scales: {
        x: {
          display: chartType !== &apos;pie&apos; &amp;&amp; chartType !== &apos;doughnut&apos;,
          ticks: { color: textMuted },
          grid: { color: bgSunken, drawBorder: false },
        },
        y: {
          display: chartType !== &apos;pie&apos; &amp;&amp; chartType !== &apos;doughnut&apos;,
          ticks: { color: textMuted },
          grid: { color: bgSunken, drawBorder: false },
          beginAtZero: true,
        },
      },
    },
  });
})();
&lt;/script&gt;

&lt;style&gt;
.chart-container {
  padding: var(--s-4);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
&lt;/style&gt;

&lt;p&gt;&lt;em&gt;Anche qui un bel buco nell’acqua.&lt;/em&gt;&lt;/p&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;Perché togliere gli append non ha reso quasi niente&lt;/strong&gt;
    
    &lt;p&gt;Il motivo è che davo a ogni append tre o quattro nanosecondi, e ne costava meno di uno. Con la capacità già riservata, in release il compilatore solleva quasi del tutto il controllo di unicità, e quello sulla capacità è un ramo che il predittore della CPU azzecca ogni singola volta.&lt;/p&gt;&lt;p&gt;In più, scrivendo &lt;code&gt;ranges[n]&lt;/code&gt;, un controllo l&apos;ho semplicemente sostituito con un altro: quello sui limiti dell&apos;array.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;p&gt;Comuque alla fine, con due mosse, ero &lt;strong&gt;passato da 0,484 a 0,275 secondi, guadagnando il 1,76x complessivo sulla divisione in campi.&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Fase&lt;/th&gt;
      &lt;th&gt;Tempo&lt;/th&gt;
      &lt;th&gt;Quota&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Indicizzazione&lt;/td&gt;
      &lt;td&gt;0,062s&lt;/td&gt;
      &lt;td&gt;8%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dividere in campi&lt;/td&gt;
      &lt;td&gt;0,275s&lt;/td&gt;
      &lt;td&gt;35%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Trasformare i campi in valori&lt;/td&gt;
      &lt;td&gt;0,427s&lt;/td&gt;
      &lt;td&gt;57%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Totale&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0,764s&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Rimane soltanto la &lt;em&gt;materializzazione dei valori&lt;/em&gt; che adesso è la parte più grossa del programma.&lt;br /&gt;
Ed è l’unica fase che non ho ancora toccato.&lt;/p&gt;

&lt;h2 id=&quot;da-byte-a-valori&quot;&gt;Da byte a valori&lt;/h2&gt;

&lt;p&gt;Per leggere i dati, come ad esempio il numero di sequenza di una fermata, la via più ovvia è quella di ottenere la stringa e fare il casting.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iSeq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;Questa innocua operazione ne nasconde però due: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;field(at:)&lt;/code&gt; prende i byte dal file mappato e ne costruisce una &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;; poi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int(_:)&lt;/code&gt; legge quella stringa e ne ricava un numero.&lt;br /&gt;
Un’istruzione dopo, &lt;em&gt;la stringa non serve più a nessuno&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Mi sembrava evidente che il costo fosse lì: &lt;strong&gt;costruire un oggetto per buttarlo via subito, cinque milioni e mezzo di volte&lt;/strong&gt;.&lt;br /&gt;
Così ho scritto un accessory che i byte li legge direttamente, senza che nessuna stringa venga mai creata.&lt;/p&gt;

&lt;p&gt;Vale la pena guardare cosa significa, perché non è complicato.&lt;/p&gt;

&lt;p&gt;In un file non ci sono numeri: ci sono byte. Prendete &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;74763&lt;/code&gt;, uno degli identificativi di fermata della riga d’esempio all’inizio dell’articolo. Sul disco non è il numero settantaquattromilasettecentosessantatré, sono &lt;strong&gt;cinque byte separati&lt;/strong&gt;, uno per cifra, ciascuno con il codice del carattere corrispondente.&lt;/p&gt;

&lt;p&gt;Per ricavarne un intero li si percorre uno alla volta ricostruendo il valore: si parte da zero, moltiplica per dieci, si aggiunge la cifra, si ripete. Cinque giri per questo campo soltanto, e una decina di campi per riga, su cinque milioni e mezzo di righe.&lt;/p&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;Perché non usare una funzione di sistema?&lt;/strong&gt;
    
    &lt;p&gt;La libreria C ha &lt;code&gt;strtol&lt;/code&gt;, che converte cifre in numeri lavorando direttamente sui byte grezzi: niente &lt;code&gt;String&lt;/code&gt; di mezzo, ed è un candidato serio.&lt;/p&gt;&lt;p&gt;L&apos;ho scartata per un motivo preciso: &lt;code&gt;strtol&lt;/code&gt; vuole una sequenza terminata da uno zero, e i miei byte stanno &lt;strong&gt;in mezzo&lt;/strong&gt; a un file mappato, dove dopo il campo c&apos;è una virgola. In pratica funzionerebbe lo stesso, perché la funzione si ferma comunque al primo carattere che non è una cifra. Ma non è una garanzia scritta da nessuna parte, e c&apos;è un caso cattivo: un numero all&apos;ultimo byte di un file la cui dimensione sia un multiplo esatto della pagina. Lì leggere un byte oltre il campo significa leggere oltre la mappa, e sono di nuovo &lt;code&gt;SIGBUS&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Non mi andava che la libreria funzionasse a patto che i file dei suoi utenti non fossero multipli di 16 KB.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;p&gt;Il parser a mano, invece, si ferma dove gli dico io:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lowerBound&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;upperBound&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;digit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// il carattere &apos;0&apos; vale 48&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Un campo da trenta cifre non è impossibile in un file che non ho scritto io.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Con `result * 10 + digit` scritto in modo ingenuo, lì il processo muore.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;scaled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;overflowA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;multipliedReportingOverflow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;overflowA&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;overflowB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scaled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addingReportingOverflow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;digit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;overflowB&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Le due righe sull’overflow meritano un attimo. La versione ovvia &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;result = result * 10 + digit&lt;/code&gt; su un campo abbastanza lungo sfora la capacità di un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int&lt;/code&gt;, e in Swift sforare non dà un numero sbagliato: &lt;strong&gt;fa terminare il processo&lt;/strong&gt;.&lt;br /&gt;
Le varianti &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;...ReportingOverflow&lt;/code&gt; costano quanto gli operatori normali, perché il controllo il compilatore lo genera comunque, ma restituiscono &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; invece di ammazzare tutto.&lt;/p&gt;

&lt;h3 id=&quot;sui-decimali-la-regola-si-inverte&quot;&gt;Sui decimali la regola si inverte&lt;/h3&gt;

&lt;p&gt;Per i &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Double&lt;/code&gt; ho pensato di fare lo stesso, e ho fatto bene a fermarmi.&lt;br /&gt;
Scrivere un parser di virgola mobile &lt;em&gt;corretto&lt;/em&gt; è una di quelle cose su cui esistono articoli scientifici: arrotondamento all’ultima cifra, notazione esponenziale, casi limite di precisione.&lt;br /&gt;
È il tipo di codice che sembra funzionare per sei mesi.&lt;/p&gt;

&lt;p&gt;Quindi qui vince la libreria. Con una sorpresa: &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Double(String)&lt;/code&gt; di Swift non passa da &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strtod&lt;/code&gt;&lt;/strong&gt;, ha un parser suo, e non dipende dalla locale. Il bug classico per cui su una macchina italiana &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3.14&lt;/code&gt; diventa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt;, perché il separatore decimale atteso è la virgola, in Swift non esiste.&lt;/p&gt;

&lt;p&gt;E la &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt; che dovevo evitare a tutti i costi? Sotto i sedici byte Swift la tiene &lt;strong&gt;dentro&lt;/strong&gt; la struct, senza toccare l’heap. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;41.902782&lt;/code&gt; sono nove caratteri: quella stringa vive nei registri e sparisce.&lt;/p&gt;

&lt;h3 id=&quot;quanto-è-servito&quot;&gt;Quanto è servito&lt;/h3&gt;

&lt;!-- Linked code snippet: click to view in popup --&gt;

&lt;div class=&quot;code-link-block&quot;&gt;
&lt;a href=&quot;#&quot; class=&quot;code-link&quot; data-code-id=&quot;test-stop-times&quot; data-code-title=&quot;The test: the pipeline broken down by phases&quot; data-code-subtitle=&quot;The complete code is on GitHub, along with the file used for measurements.&quot;&gt;&lt;svg class=&quot;icon&quot; viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.5&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M7.2 6.4 3.4 10l3.8 3.6M12.8 6.4 16.6 10l-3.8 3.6M11.4 4.6 8.6 15.4&quot; /&gt;&lt;/svg&gt;
&lt;span class=&quot;code-link-text&quot;&gt;&lt;span class=&quot;code-link-label&quot;&gt;The test: the pipeline broken down by phases&lt;/span&gt;&lt;span class=&quot;code-link-note&quot;&gt;The complete code is on GitHub, along with the file used for measurements.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;code-link-source&quot; id=&quot;code-src-test-stop-times&quot; hidden=&quot;&quot;&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;kd&quot;&gt;@Test&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stopTimes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;clock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ContinuousClock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Warm-up: one empty run brings the 260 MB into page cache.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Without it, the first measurement times the disk instead of the code—the same&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// read goes from ~0.19s to ~0.44s depending on whether pages are there or not.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;warmup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hasHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;#expect(warmup.rowCount &amp;gt; 0)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 1 — indexing (the init: mmap, sniff, scan for offsets)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rssBefore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;residentMemoryMB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hasHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;indexing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rssAfterIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;residentMemoryMB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iTrip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;trip_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iArr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;arrival_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;departure_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iStop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iSeq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_sequence&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iHead&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_headsign&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iPick&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pickup_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDrop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;drop_off_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;shape_dist_traveled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;timepoint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Issue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;header diverso da quello atteso: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columnNames&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2a — just iteration: splitFields on every row, empty body.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Isolates the cost of splitting into fields from materializing values.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rowsVisited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tSplit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rowsVisited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;splitOnly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tSplit&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2b — direct access, building the exact same StopTime&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;builtDirectly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;trip_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTrip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;arrival_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;departure_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iSeq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_headsign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isFieldEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;pickup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iPick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;drop_off_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;shape_dist_traveled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;doubleField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;timepoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;builtDirectly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;direct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2c — the same StopTime, but converting numbers by passing through String:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// it&apos;s the obvious way, what you&apos;d write without typed accessors.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;builtViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;trip_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTrip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;arrival_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;departure_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iSeq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_headsign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isEmpty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;pickup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iPick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;drop_off_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;shape_dist_traveled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;timepoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;builtViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;viaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tStr&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 3 — the same thing via Codable&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;codable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;#expect(rowsVisited == reader.rowCount)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == decoded)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == builtViaStrings)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == reader.rowCount)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;valuesViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viaStrings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;

    ── stop_times.txt — &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rowCount&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; righe ──
      1. indicizzazione         &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexing&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;   (RSS +&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.0f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rssAfterIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rssBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; MB)
      2a. solo splitFields      &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2b. + accessori tipizzati &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2c. + conversione da String &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viaStrings&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      3. Codable                &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codable&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;

         dividere in campi        &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         materializzare (tipizzati)  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         materializzare (da String)  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;valuesViaStrings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         gli accessori tipizzati fanno risparmiare &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;valuesViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x
         Codable costa &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x l&apos;accesso diretto

    &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/div&gt;

&lt;script&gt;
(function() {
  if (window.__codeLinkReady) return;
  window.__codeLinkReady = true;

  /* Create popup container */
  const popup = document.createElement(&apos;div&apos;);
  popup.className = &apos;code-popup&apos;;
  popup.innerHTML = `
    &lt;div class=&quot;code-popup-backdrop&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;code-popup-dialog&quot;&gt;
      &lt;div class=&quot;code-popup-header&quot;&gt;
        &lt;div class=&quot;code-popup-heading&quot;&gt;
          &lt;h3 id=&quot;code-popup-title&quot;&gt;&lt;/h3&gt;
          &lt;p class=&quot;code-popup-subtitle&quot; id=&quot;code-popup-subtitle&quot; hidden&gt;&lt;/p&gt;
        &lt;/div&gt;
        &lt;button class=&quot;code-popup-close&quot; aria-label=&quot;Close&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;line x1=&quot;18&quot; y1=&quot;6&quot; x2=&quot;6&quot; y2=&quot;18&quot; /&gt;
            &lt;line x1=&quot;6&quot; y1=&quot;6&quot; x2=&quot;18&quot; y2=&quot;18&quot; /&gt;
          &lt;/svg&gt;
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;code-popup-content&quot; id=&quot;code-popup-content&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;code-popup-footer&quot;&gt;
        &lt;button class=&quot;code-popup-expand&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;path d=&quot;M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3&quot; /&gt;
          &lt;/svg&gt;
          Expand to fullscreen
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
  document.body.appendChild(popup);

  const popupDialog = popup.querySelector(&apos;.code-popup-dialog&apos;);
  const popupBackdrop = popup.querySelector(&apos;.code-popup-backdrop&apos;);
  const popupTitle = popup.querySelector(&apos;#code-popup-title&apos;);
  const popupSubtitle = popup.querySelector(&apos;#code-popup-subtitle&apos;);
  const popupContent = popup.querySelector(&apos;#code-popup-content&apos;);
  const popupClose = popup.querySelector(&apos;.code-popup-close&apos;);
  const popupExpand = popup.querySelector(&apos;.code-popup-expand&apos;);

  function closePopup() {
    popup.classList.remove(&apos;is-open&apos;);
  }

  /* Close handlers */
  popupBackdrop.addEventListener(&apos;click&apos;, closePopup);
  popupClose.addEventListener(&apos;click&apos;, closePopup);
  document.addEventListener(&apos;keydown&apos;, (e) =&gt; {
    if (e.key === &apos;Escape&apos; &amp;&amp; popup.classList.contains(&apos;is-open&apos;)) {
      closePopup();
    }
  });

  /* Expand to fullscreen */
  popupExpand.addEventListener(&apos;click&apos;, () =&gt; {
    closePopup();
    /* Use the existing code-modal if available */
    const codeModal = document.querySelector(&apos;.code-modal&apos;);
    if (codeModal) {
      const modalCode = codeModal.querySelector(&apos;#code-modal-code&apos;);
      /* popupContent contiene gia il markup completo di Rouge, wrapper
         compreso, quindi si copia cosi com&apos;e */
      modalCode.innerHTML = popupContent.innerHTML;
      codeModal.classList.add(&apos;is-open&apos;);
      modalCode.focus();
    }
  });

  /* Prevent popup close when clicking inside */
  popupDialog.addEventListener(&apos;click&apos;, (e) =&gt; {
    e.stopPropagation();
  });

  /* Delega sul documento: cosi funziona anche per i link che nel DOM */
  /* arrivano dopo questo script. */
  document.addEventListener(&apos;click&apos;, (e) =&gt; {
    const link = e.target.closest(&apos;.code-link&apos;);
    if (link) {
      e.preventDefault();
      const codeId = link.getAttribute(&apos;data-code-id&apos;);
      const source = document.getElementById(&apos;code-src-&apos; + codeId);
      if (!source) return;

      popupTitle.textContent = link.getAttribute(&apos;data-code-title&apos;);

      const subtitle = link.getAttribute(&apos;data-code-subtitle&apos;);
      popupSubtitle.textContent = subtitle || &apos;&apos;;
      popupSubtitle.hidden = !subtitle;
      /* HTML gia evidenziato da Rouge in fase di build: porta con se il &lt;pre&gt;,
         quindi indentazione e colori sopravvivono alla compressione */
      popupContent.innerHTML = source.innerHTML;

      popup.classList.add(&apos;is-open&apos;);
    }
  });
})();
&lt;/script&gt;

&lt;style&gt;
/* Code link styling */
.code-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.5em 0.75em;
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--accent);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease;
}

.code-link:hover {
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-link .icon {
  /* due righe di testo accanto: un&apos;icona da 1em sparirebbe */
  width: 1.9em;
  height: 1.9em;
  flex: none;
  opacity: 0.75;
}

/* La freccia del tema qui e un&apos;affordance, non un ornamento da hover: dice
   che il link apre qualcosa. Va tenuta visibile, e per farlo bisogna ripetere
   la catena di :not() della regola base, che altrimenti pesa di piu (0,3,2)
   e rimette opacity a 0. */
.post-body a.code-link:not(.tag):not(.entry-link)::after {
  opacity: 1;
  transform: none;
  align-self: center;
}

.code-link-label { min-width: 0; }

.code-link-error {
  color: var(--text-muted);
  font-size: 0.9em;
}

/* Code popup */
.code-popup {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.code-popup.is-open {
  opacity: 1;
  pointer-events: auto;
}

.code-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
}

.code-popup-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: 70vw;
  max-height: 70vh;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.code-popup-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--rule);
}

.code-popup-header h3 {
  margin: 0;
  font-size: var(--t-0);
  font-weight: 600;
  font-family: var(--font-mono);
}

.code-popup-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}

.code-popup-close:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
}

.code-popup-close svg {
  width: 16px;
  height: 16px;
}

.code-popup-content {
  flex: 1;
  overflow: auto;
  padding: var(--s-4);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg-sunken);
}

.code-popup-content pre,
.code-popup-content .highlight,
.code-popup-content .highlighter-rouge {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  font-size: inherit;
  line-height: inherit;
}

/* il sorgente vive nella pagina solo per essere copiato nel popup */
.code-link-source { display: none; }

.code-link-block {
  display: flex;
  margin: var(--s-4) 0;
}

/* titolo e sottotitolo incolonnati dentro al riquadro, accanto all&apos;icona */
.code-link-text {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-width: 0;
}

.code-link-note,
.code-popup-subtitle {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--t--2);
  color: var(--text-muted);
  line-height: 1.4;
}

.code-popup-heading { min-width: 0; }

.code-popup-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--rule);
  background: var(--bg);
}

.code-popup-expand {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.45em 0.9em;
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--text);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}

.code-popup-expand:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-popup-expand svg {
  width: 1em;
  height: 1em;
}

/* Mobile responsive */
@media (max-width: 40rem) {
  .code-popup-dialog {
    max-width: 95vw;
    max-height: 80vh;
  }

  .code-popup-content {
    font-size: 0.75em;
  }
}
&lt;/style&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Materializzazione&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;conversione da &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;0,572s&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;accessori tipizzati&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0,446s&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Un 1,3x. Sul percorso completo, 1,18x.&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Meno di quanto il ragionamento promettesse: il fatto è che &lt;strong&gt;la stringa che stavo evitando, in gran parte, non veniva allocata.&lt;/strong&gt; I campi numerici di un CSV sono corti per natura,  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1167&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;07:30:00&lt;/code&gt;, quindi finiscono tutti dentro la soglia dei sedici byte e restano inline.&lt;/p&gt;

&lt;p&gt;È la stessa scoperta che avevo appena fatto sui decimali dove ero convinto che il costo fosse l’allocazione. L’allocazione non c’era.&lt;/p&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Il parser a mano resta la cosa giusta da avere, 1,3x è 1,3x, e una volta scritto non costa più niente&lt;/strong&gt;, ma per una ragione diversa da quella per cui l’avevo scritto: non evita di allocare, evita di &lt;strong&gt;costruire e validare una stringa UTF-8&lt;/strong&gt; per poi scartarla un’istruzione dopo.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;La regola d’oro qui è: &lt;em&gt;crivilo a mano quando la grammatica è banale e la libreria generica ti chiede garanzie che non hai; usa la libreria quando la correttezza è difficile.&lt;/em&gt;&lt;br /&gt;
Ma soprattutto c’è bisogno di &lt;strong&gt;controllare cosa stai davvero risparmiando&lt;/strong&gt;, perché nel mio caso non era quello che credevo.&lt;/p&gt;

&lt;h2 id=&quot;dove-siamo-arrivati&quot;&gt;Dove siamo arrivati&lt;/h2&gt;

&lt;p&gt;Questa è la fotografia finale, con i numeri dell’ultimo giro:&lt;/p&gt;

&lt;!-- Linked code snippet: click to view in popup --&gt;

&lt;div class=&quot;code-link-block&quot;&gt;
&lt;a href=&quot;#&quot; class=&quot;code-link&quot; data-code-id=&quot;test-stop-times&quot; data-code-title=&quot;The test: the pipeline broken down by phases&quot; data-code-subtitle=&quot;The complete code is on GitHub, along with the file used for measurements.&quot;&gt;&lt;svg class=&quot;icon&quot; viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.5&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M7.2 6.4 3.4 10l3.8 3.6M12.8 6.4 16.6 10l-3.8 3.6M11.4 4.6 8.6 15.4&quot; /&gt;&lt;/svg&gt;
&lt;span class=&quot;code-link-text&quot;&gt;&lt;span class=&quot;code-link-label&quot;&gt;The test: the pipeline broken down by phases&lt;/span&gt;&lt;span class=&quot;code-link-note&quot;&gt;The complete code is on GitHub, along with the file used for measurements.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;code-link-source&quot; id=&quot;code-src-test-stop-times&quot; hidden=&quot;&quot;&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;kd&quot;&gt;@Test&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stopTimes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;clock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ContinuousClock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Warm-up: one empty run brings the 260 MB into page cache.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Without it, the first measurement times the disk instead of the code—the same&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// read goes from ~0.19s to ~0.44s depending on whether pages are there or not.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;warmup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hasHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;#expect(warmup.rowCount &amp;gt; 0)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 1 — indexing (the init: mmap, sniff, scan for offsets)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rssBefore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;residentMemoryMB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hasHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;indexing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rssAfterIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;residentMemoryMB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iTrip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;trip_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iArr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;arrival_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;departure_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iStop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iSeq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_sequence&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iHead&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop_headsign&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iPick&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pickup_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDrop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;drop_off_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iDist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;shape_dist_traveled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;iTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;columnIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;timepoint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Issue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;header diverso da quello atteso: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columnNames&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2a — just iteration: splitFields on every row, empty body.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Isolates the cost of splitting into fields from materializing values.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rowsVisited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tSplit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rowsVisited&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;splitOnly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tSplit&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2b — direct access, building the exact same StopTime&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;builtDirectly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;trip_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTrip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;arrival_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;departure_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iSeq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_headsign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isFieldEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;pickup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iPick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;drop_off_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;shape_dist_traveled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;doubleField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;timepoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;intField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;builtDirectly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;direct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 2c — the same StopTime, but converting numbers by passing through String:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// it&apos;s the obvious way, what you&apos;d write without typed accessors.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;builtViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;trip_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTrip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;arrival_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;departure_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iSeq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;stop_headsign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isEmpty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iHead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;pickup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iPick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;drop_off_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;shape_dist_traveled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iDist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;timepoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;builtViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;viaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tStr&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 3 — the same thing via Codable&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;StopTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;codable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;#expect(rowsVisited == reader.rowCount)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == decoded)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == builtViaStrings)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(builtDirectly == reader.rowCount)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;valuesViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viaStrings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;

    ── stop_times.txt — &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rowCount&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; righe ──
      1. indicizzazione         &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indexing&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;   (RSS +&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.0f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rssAfterIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rssBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; MB)
      2a. solo splitFields      &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2b. + accessori tipizzati &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2c. + conversione da String &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viaStrings&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      3. Codable                &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codable&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;

         dividere in campi        &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splitOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         materializzare (tipizzati)  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         materializzare (da String)  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;valuesViaStrings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s
         gli accessori tipizzati fanno risparmiare &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;valuesViaStrings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x
         Codable costa &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x l&apos;accesso diretto

    &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/div&gt;

&lt;script&gt;
(function() {
  if (window.__codeLinkReady) return;
  window.__codeLinkReady = true;

  /* Create popup container */
  const popup = document.createElement(&apos;div&apos;);
  popup.className = &apos;code-popup&apos;;
  popup.innerHTML = `
    &lt;div class=&quot;code-popup-backdrop&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;code-popup-dialog&quot;&gt;
      &lt;div class=&quot;code-popup-header&quot;&gt;
        &lt;div class=&quot;code-popup-heading&quot;&gt;
          &lt;h3 id=&quot;code-popup-title&quot;&gt;&lt;/h3&gt;
          &lt;p class=&quot;code-popup-subtitle&quot; id=&quot;code-popup-subtitle&quot; hidden&gt;&lt;/p&gt;
        &lt;/div&gt;
        &lt;button class=&quot;code-popup-close&quot; aria-label=&quot;Close&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;line x1=&quot;18&quot; y1=&quot;6&quot; x2=&quot;6&quot; y2=&quot;18&quot; /&gt;
            &lt;line x1=&quot;6&quot; y1=&quot;6&quot; x2=&quot;18&quot; y2=&quot;18&quot; /&gt;
          &lt;/svg&gt;
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;code-popup-content&quot; id=&quot;code-popup-content&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;code-popup-footer&quot;&gt;
        &lt;button class=&quot;code-popup-expand&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;path d=&quot;M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3&quot; /&gt;
          &lt;/svg&gt;
          Expand to fullscreen
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
  document.body.appendChild(popup);

  const popupDialog = popup.querySelector(&apos;.code-popup-dialog&apos;);
  const popupBackdrop = popup.querySelector(&apos;.code-popup-backdrop&apos;);
  const popupTitle = popup.querySelector(&apos;#code-popup-title&apos;);
  const popupSubtitle = popup.querySelector(&apos;#code-popup-subtitle&apos;);
  const popupContent = popup.querySelector(&apos;#code-popup-content&apos;);
  const popupClose = popup.querySelector(&apos;.code-popup-close&apos;);
  const popupExpand = popup.querySelector(&apos;.code-popup-expand&apos;);

  function closePopup() {
    popup.classList.remove(&apos;is-open&apos;);
  }

  /* Close handlers */
  popupBackdrop.addEventListener(&apos;click&apos;, closePopup);
  popupClose.addEventListener(&apos;click&apos;, closePopup);
  document.addEventListener(&apos;keydown&apos;, (e) =&gt; {
    if (e.key === &apos;Escape&apos; &amp;&amp; popup.classList.contains(&apos;is-open&apos;)) {
      closePopup();
    }
  });

  /* Expand to fullscreen */
  popupExpand.addEventListener(&apos;click&apos;, () =&gt; {
    closePopup();
    /* Use the existing code-modal if available */
    const codeModal = document.querySelector(&apos;.code-modal&apos;);
    if (codeModal) {
      const modalCode = codeModal.querySelector(&apos;#code-modal-code&apos;);
      /* popupContent contiene gia il markup completo di Rouge, wrapper
         compreso, quindi si copia cosi com&apos;e */
      modalCode.innerHTML = popupContent.innerHTML;
      codeModal.classList.add(&apos;is-open&apos;);
      modalCode.focus();
    }
  });

  /* Prevent popup close when clicking inside */
  popupDialog.addEventListener(&apos;click&apos;, (e) =&gt; {
    e.stopPropagation();
  });

  /* Delega sul documento: cosi funziona anche per i link che nel DOM */
  /* arrivano dopo questo script. */
  document.addEventListener(&apos;click&apos;, (e) =&gt; {
    const link = e.target.closest(&apos;.code-link&apos;);
    if (link) {
      e.preventDefault();
      const codeId = link.getAttribute(&apos;data-code-id&apos;);
      const source = document.getElementById(&apos;code-src-&apos; + codeId);
      if (!source) return;

      popupTitle.textContent = link.getAttribute(&apos;data-code-title&apos;);

      const subtitle = link.getAttribute(&apos;data-code-subtitle&apos;);
      popupSubtitle.textContent = subtitle || &apos;&apos;;
      popupSubtitle.hidden = !subtitle;
      /* HTML gia evidenziato da Rouge in fase di build: porta con se il &lt;pre&gt;,
         quindi indentazione e colori sopravvivono alla compressione */
      popupContent.innerHTML = source.innerHTML;

      popup.classList.add(&apos;is-open&apos;);
    }
  });
})();
&lt;/script&gt;

&lt;style&gt;
/* Code link styling */
.code-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.5em 0.75em;
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--accent);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease;
}

.code-link:hover {
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-link .icon {
  /* due righe di testo accanto: un&apos;icona da 1em sparirebbe */
  width: 1.9em;
  height: 1.9em;
  flex: none;
  opacity: 0.75;
}

/* La freccia del tema qui e un&apos;affordance, non un ornamento da hover: dice
   che il link apre qualcosa. Va tenuta visibile, e per farlo bisogna ripetere
   la catena di :not() della regola base, che altrimenti pesa di piu (0,3,2)
   e rimette opacity a 0. */
.post-body a.code-link:not(.tag):not(.entry-link)::after {
  opacity: 1;
  transform: none;
  align-self: center;
}

.code-link-label { min-width: 0; }

.code-link-error {
  color: var(--text-muted);
  font-size: 0.9em;
}

/* Code popup */
.code-popup {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.code-popup.is-open {
  opacity: 1;
  pointer-events: auto;
}

.code-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
}

.code-popup-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: 70vw;
  max-height: 70vh;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.code-popup-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--rule);
}

.code-popup-header h3 {
  margin: 0;
  font-size: var(--t-0);
  font-weight: 600;
  font-family: var(--font-mono);
}

.code-popup-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}

.code-popup-close:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
}

.code-popup-close svg {
  width: 16px;
  height: 16px;
}

.code-popup-content {
  flex: 1;
  overflow: auto;
  padding: var(--s-4);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg-sunken);
}

.code-popup-content pre,
.code-popup-content .highlight,
.code-popup-content .highlighter-rouge {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  font-size: inherit;
  line-height: inherit;
}

/* il sorgente vive nella pagina solo per essere copiato nel popup */
.code-link-source { display: none; }

.code-link-block {
  display: flex;
  margin: var(--s-4) 0;
}

/* titolo e sottotitolo incolonnati dentro al riquadro, accanto all&apos;icona */
.code-link-text {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-width: 0;
}

.code-link-note,
.code-popup-subtitle {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--t--2);
  color: var(--text-muted);
  line-height: 1.4;
}

.code-popup-heading { min-width: 0; }

.code-popup-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--rule);
  background: var(--bg);
}

.code-popup-expand {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.45em 0.9em;
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--text);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}

.code-popup-expand:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-popup-expand svg {
  width: 1em;
  height: 1em;
}

/* Mobile responsive */
@media (max-width: 40rem) {
  .code-popup-dialog {
    max-width: 95vw;
    max-height: 80vh;
  }

  .code-popup-content {
    font-size: 0.75em;
  }
}
&lt;/style&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Fase&lt;/th&gt;
      &lt;th&gt;Tempo&lt;/th&gt;
      &lt;th&gt;Quota&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Indicizzazione&lt;/td&gt;
      &lt;td&gt;0,064s&lt;/td&gt;
      &lt;td&gt;8%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dividere le righe in campi&lt;/td&gt;
      &lt;td&gt;0,271s&lt;/td&gt;
      &lt;td&gt;35%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Trasformare i campi in valori&lt;/td&gt;
      &lt;td&gt;0,446s&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;57%&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Totale&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0,781s&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;La fase su cui ho lavorato di più, tre sezioni, quattro riscritture, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt; e &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memchr&lt;/code&gt; e l’annusata delle virgolette, è quella che pesa l’&lt;strong&gt;8%&lt;/strong&gt;. Quella che ne pesa il &lt;strong&gt;57%&lt;/strong&gt; l’ho grattata una volta sola, per un 1,3x, e mi sono fermato lì.&lt;/p&gt;

&lt;p&gt;Non perché sia la scelta giusta. Perché è dove sono arrivato.&lt;/p&gt;

&lt;h3 id=&quot;e-il-confronto-con-cui-abbiamo-aperto&quot;&gt;E il confronto con cui abbiamo aperto&lt;/h3&gt;

&lt;p&gt;Undici secondi contro 0,34: quei 0,34 sono l’indicizzazione più la divisione in campi, cioè &lt;strong&gt;esattamente il lavoro che faceva la versione ovvia&lt;/strong&gt;, leggere il file e spezzare ogni riga nelle sue colonne. Il confronto regge.&lt;/p&gt;

&lt;p&gt;Costruire i valori tipizzati sopra è un lavoro in più che la versione ovvia non faceva affatto, e porta il totale a 0,781s. Se l’avesse fatto anche lei, i suoi undici secondi sarebbero stati parecchi di più.&lt;/p&gt;

&lt;h3 id=&quot;i-250-mb&quot;&gt;I 250 MB&lt;/h3&gt;

&lt;p&gt;Anche l’altro numero dell’apertura merita una spiegazione, perché non è quello che sembra.&lt;/p&gt;

&lt;p&gt;Dei 251 MB occupati, &lt;strong&gt;circa 45 sono l’indice&lt;/strong&gt;: cinque milioni e mezzo di posizioni da otto byte l’una. Memoria vera, allocata da me, e l’unico punto del programma in cui la struttura dati costa più di quanto verrebbe da pensare. Con offset a 32 bit invece che a 64 sarebbero 22, al prezzo di rinunciare ai file oltre i 4 GB — un compromesso che non ho voluto fare, ma che è lì.&lt;/p&gt;

&lt;p&gt;Gli altri &lt;strong&gt;206 MB sono le pagine del file mappato&lt;/strong&gt;, finite nel conteggio perché la scansione le tocca tutte. E qui la differenza con i 782 MB della versione ovvia non è solo di quantità: quelle pagine sono &lt;strong&gt;pulite&lt;/strong&gt;, il kernel le può scartare gratis quando ha bisogno di spazio e rileggerle dal disco se servono ancora. Le stringhe della versione ovvia sono memoria &lt;strong&gt;sporca&lt;/strong&gt;: o stanno in RAM, o finiscono in swap.&lt;/p&gt;

&lt;p&gt;Due modi molto diversi di occupare un quarto di gigabyte.&lt;/p&gt;

&lt;h2 id=&quot;cosa-mi-porto-via&quot;&gt;Cosa mi porto via&lt;/h2&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;Riguardando l’intera storia, la parte che mi resta non sono le ottimizzazioni.&lt;br /&gt;
Sono le volte in cui ero convinto di qualcosa e il cronometro ha detto un’altra cosa.&lt;/p&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Ho creduto che il mio parser fosse lento e &lt;em&gt;invece era il compilatore, in debug, a essere cinquantacinque volte più lento&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Ho creduto che &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt; avrebbe accelerato la scansione &lt;em&gt;e non l’ha accelerata di un millesimo&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Ho creduto che &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memchr&lt;/code&gt; avrebbe reso poco sui delimitatori &lt;em&gt;e ha reso un 1,5x; poi ho creduto che togliere cinquantasei milioni di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;append&lt;/code&gt; avrebbe reso molto, e ha reso 48 millesimi&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;Ho creduto che gli accessori tipizzati evitassero un’allocazione, e &lt;em&gt;quell’allocazione non c’era mai stata&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cinque previsioni, e quasi tutte sbagliate, alcune per eccesso, altre per difetto, il che almeno esclude che stessi barando a favore della mia tesi.&lt;/p&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;Quello che le ha smontate, ogni volta, non è stata l’esperienza o l’intuizione. &lt;strong&gt;È stato costruire la cosa che le avrebbe potute smentire&lt;/strong&gt;: un benchmark, un test fatto per distinguere due guasti diversi, una tabellina su un foglio.
&lt;br /&gt;&lt;br /&gt;
Non è che misurare renda più intelligenti. È che &lt;strong&gt;ti costringe a scoprire cosa stai davvero facendo&lt;/strong&gt;, che di solito è un’altra cosa rispetto a quella che credevi.&lt;/p&gt;
&lt;/div&gt;

&lt;h3 id=&quot;quello-che-resta-sul-tavolo&quot;&gt;Quello che resta sul tavolo&lt;/h3&gt;

&lt;p&gt;Il 57% della materializzazione è ancora lì e non l’ho quasi toccato. E c’è un salto più grosso che non ho nemmeno tentato: &lt;strong&gt;le righe sono indipendenti fra loro&lt;/strong&gt;, grazie all’indice, e nessuna dipende da quella prima o da quella dopo. Su otto core quei 0,78 secondi potrebbero diventarne 0,14.&lt;/p&gt;

&lt;p&gt;Ma lì entra (forse) in gioco SIMD, quindi il tetto lo fissa proprio la fase che vale l’8%.&lt;br /&gt;
&lt;em&gt;È la storia delle prossime parti.&lt;/em&gt;&lt;/p&gt;

&lt;!-- Series navigation: shows prev/next in multi-part articles --&gt;
&lt;!--
  ATTENZIONE: niente indentazione nell&apos;HTML qui sotto.
  Questo include viene iniettato dentro il corpo Markdown dei post, e kramdown
  tratta come blocco di codice qualunque riga rientrata di 4 o piu spazi:
  il markup finirebbe stampato a schermo invece di essere renderizzato.
--&gt;

&lt;!-- Find all posts in this series --&gt;

&lt;div class=&quot;series-nav&quot;&gt;
&lt;div class=&quot;series-header&quot;&gt;
&lt;div class=&quot;series-badge&quot;&gt;
Part &lt;span class=&quot;series-part&quot;&gt;3&lt;/span&gt; of &lt;span class=&quot;series-total&quot;&gt;3&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;series-progress&quot;&gt;
&lt;div class=&quot;series-bar&quot;&gt;
&lt;div class=&quot;series-fill&quot; style=&quot;width: calc(3 / 3 * 100%)&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;nav class=&quot;series-links&quot;&gt;
&lt;!-- Previous button --&gt;



&lt;a href=&quot;/it/2026/09/14/parser-csv-corretto-poi-veloce/&quot; class=&quot;series-link series-prev&quot;&gt;
&lt;span class=&quot;series-label&quot;&gt;← Previous&lt;/span&gt;
&lt;span class=&quot;series-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 2: Corretto, poi veloce&lt;/span&gt;
&lt;/a&gt;






&lt;!-- Next button --&gt;

&lt;/nav&gt;

&lt;!-- All parts overview --&gt;
&lt;details class=&quot;series-all&quot;&gt;
&lt;summary&gt;View all parts&lt;/summary&gt;
&lt;ul class=&quot;series-list&quot;&gt;

&lt;li&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-corretto-poi-veloce/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 2&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 2: Corretto, poi veloce&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;li class=&quot;is-current&quot;&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-il-nove-percento/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 3&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 3: Il 9%&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;
&lt;/details&gt;
&lt;/div&gt;

&lt;style&gt;
.series-nav {
  margin: var(--s-7) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.series-header {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}

.series-badge {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
}

.series-progress {
  flex: 1;
}

.series-bar {
  height: 4px;
  background: var(--rule);
  border-radius: 2px;
  overflow: hidden;
}

.series-fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.3s ease;
}

.series-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}

.series-link {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  padding: var(--s-3) var(--s-4);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  transition: border-color 0.18s ease, transform 0.18s ease;
}

.series-link:hover {
  border-color: var(--accent-soft);
  transform: translateY(-2px);
}

/* Il tema aggiunge una freccia dopo ogni link nel corpo del post. Qui e&apos; di
   troppo: la direzione la dicono gia&apos; le etichette &quot;Previous&quot;/&quot;Next&quot;, e su
   &quot;Previous&quot; punterebbe pure dalla parte sbagliata. Per spegnerla serve
   almeno la specificita&apos; della regola base (0,3,2), quindi la catena di
   :not() va ripetuta. */
.post-body .series-nav a:not(.tag):not(.entry-link)::after {
  content: none;
}

.series-label {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.series-link:hover .series-label {
  color: var(--accent);
}

.series-title {
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  line-height: 1.3;
}

.series-all {
  cursor: pointer;
}

.series-all summary {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--s-2);
  margin: calc(-1 * var(--s-2));
  transition: color 0.18s ease;
}

.series-all summary:hover {
  color: var(--accent);
}

.series-all[open] summary {
  color: var(--accent);
  margin-bottom: var(--s-3);
}

.series-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.series-list li {
  margin: 0;
}

.series-list a {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-radius: 4px;
  color: var(--text);
  text-decoration: none;
  transition: background-color 0.18s ease, color 0.18s ease;
}

.series-list a:hover {
  background-color: var(--bg);
  color: var(--accent);
}

.series-list li.is-current a {
  background-color: var(--bg);
  color: var(--accent);
  font-weight: 600;
}

.series-num {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
}

.series-list li.is-current .series-num {
  color: var(--accent);
}

.series-item-title {
  flex: 1;
  font-family: var(--font-ui);
}
&lt;/style&gt;

</content>
 </entry>
 
 <entry>
   <title>L&apos;intuito mente: lezioni da un parser CSV — Parte 2: Corretto, poi veloce</title>
   <link href="https://www.danielemargutti.com/it/2026/09/14/parser-csv-corretto-poi-veloce/"/>
   <summary>Basta una virgoletta fuori posto per far crollare il parser. Come correggere il caso limite e portare l&apos;indicizzazione a soli 65 millisecondi.</summary>
   <updated>2026-09-14T00:00:00+00:00</updated>
   <id>https://www.danielemargutti.com/it/2026/09/14/parser-csv-corretto-poi-veloce</id>
   <content type="html">&lt;!-- Series navigation: shows prev/next in multi-part articles --&gt;
&lt;!--
  ATTENZIONE: niente indentazione nell&apos;HTML qui sotto.
  Questo include viene iniettato dentro il corpo Markdown dei post, e kramdown
  tratta come blocco di codice qualunque riga rientrata di 4 o piu spazi:
  il markup finirebbe stampato a schermo invece di essere renderizzato.
--&gt;

&lt;!-- Find all posts in this series --&gt;

&lt;div class=&quot;series-nav&quot;&gt;
&lt;div class=&quot;series-header&quot;&gt;
&lt;div class=&quot;series-badge&quot;&gt;
Part &lt;span class=&quot;series-part&quot;&gt;2&lt;/span&gt; of &lt;span class=&quot;series-total&quot;&gt;3&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;series-progress&quot;&gt;
&lt;div class=&quot;series-bar&quot;&gt;
&lt;div class=&quot;series-fill&quot; style=&quot;width: calc(2 / 3 * 100%)&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;nav class=&quot;series-links&quot;&gt;
&lt;!-- Previous button --&gt;








&lt;!-- Next button --&gt;





&lt;a href=&quot;/it/2026/09/14/parser-csv-il-nove-percento/&quot; class=&quot;series-link series-next&quot;&gt;
&lt;span class=&quot;series-label&quot;&gt;Next →&lt;/span&gt;
&lt;span class=&quot;series-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 3: Il 9%&lt;/span&gt;
&lt;/a&gt;



&lt;/nav&gt;

&lt;!-- All parts overview --&gt;
&lt;details class=&quot;series-all&quot;&gt;
&lt;summary&gt;View all parts&lt;/summary&gt;
&lt;ul class=&quot;series-list&quot;&gt;

&lt;li class=&quot;is-current&quot;&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-corretto-poi-veloce/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 2&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 2: Corretto, poi veloce&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-il-nove-percento/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 3&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 3: Il 9%&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;
&lt;/details&gt;
&lt;/div&gt;

&lt;style&gt;
.series-nav {
  margin: var(--s-7) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.series-header {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}

.series-badge {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
}

.series-progress {
  flex: 1;
}

.series-bar {
  height: 4px;
  background: var(--rule);
  border-radius: 2px;
  overflow: hidden;
}

.series-fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.3s ease;
}

.series-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}

.series-link {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  padding: var(--s-3) var(--s-4);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  transition: border-color 0.18s ease, transform 0.18s ease;
}

.series-link:hover {
  border-color: var(--accent-soft);
  transform: translateY(-2px);
}

/* Il tema aggiunge una freccia dopo ogni link nel corpo del post. Qui e&apos; di
   troppo: la direzione la dicono gia&apos; le etichette &quot;Previous&quot;/&quot;Next&quot;, e su
   &quot;Previous&quot; punterebbe pure dalla parte sbagliata. Per spegnerla serve
   almeno la specificita&apos; della regola base (0,3,2), quindi la catena di
   :not() va ripetuta. */
.post-body .series-nav a:not(.tag):not(.entry-link)::after {
  content: none;
}

.series-label {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.series-link:hover .series-label {
  color: var(--accent);
}

.series-title {
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  line-height: 1.3;
}

.series-all {
  cursor: pointer;
}

.series-all summary {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--s-2);
  margin: calc(-1 * var(--s-2));
  transition: color 0.18s ease;
}

.series-all summary:hover {
  color: var(--accent);
}

.series-all[open] summary {
  color: var(--accent);
  margin-bottom: var(--s-3);
}

.series-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.series-list li {
  margin: 0;
}

.series-list a {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-radius: 4px;
  color: var(--text);
  text-decoration: none;
  transition: background-color 0.18s ease, color 0.18s ease;
}

.series-list a:hover {
  background-color: var(--bg);
  color: var(--accent);
}

.series-list li.is-current a {
  background-color: var(--bg);
  color: var(--accent);
  font-weight: 600;
}

.series-num {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
}

.series-list li.is-current .series-num {
  color: var(--accent);
}

.series-item-title {
  flex: 1;
  font-family: var(--font-ui);
}
&lt;/style&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;Dove eravamo rimasti&lt;/strong&gt;
    
    &lt;p&gt;Un file GTFS da 260 MB, cinque milioni e mezzo di righe, e la scoperta che leggerlo costa l&amp;#39;1% del tempo: tutto il resto se ne va a trasformare byte in oggetti. Avevo preso tre decisioni di struttura (leggere a blocchi, indicizzare solo l&amp;#39;inizio delle righe, chiedere all&amp;#39;utente se c&amp;#39;è l&amp;#39;intestazione invece di indovinarla) e scritto la prima versione. Ci metteva venti secondi, quasi il doppio del codice ovvio, e non era colpa dell&amp;#39;algoritmo: era la build in debug.&lt;/p&gt;&lt;p&gt;In release erano 0,38 secondi. Il parser era veloce.&lt;/p&gt;&lt;p&gt;Restava da scoprire che non era corretto.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;h2 id=&quot;quando-una-virgoletta-fa-sparire-il-file&quot;&gt;Quando una virgoletta fa sparire il file&lt;/h2&gt;

&lt;p&gt;Questa prima versione gestisce bene un a-capo tra virgolette quando queste racchiudono per intero il valore di una colonna.&lt;br /&gt;
Evitiamo infatti di interpretare il dato come la fine di una riga:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csv&quot;&gt;Mario,&quot;Via Roma 1
00100 Roma&quot;,RM
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ma cosa succede se abbiamo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&lt;/code&gt; che non sono in un campo quotato?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csv&quot;&gt;prodotto,prezzo
monitor 24&quot; full HD,199
tastiera,49
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Quelle virgolette sono ovviamente i pollici dello schermo. Il nostro codice però vede una virgoletta e cambia stato di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inQuotes&lt;/code&gt;.
Mi sono scritto una tabellina a penna per chiarirmi il flusso: nessun benchmark, nessun test, solo quattro byte tracciati a mano su un file inventato di tre righe, ed è bastata a far crollare l’ipotesi.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Byte&lt;/th&gt;
      &lt;th&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inQuotes&lt;/code&gt; prima&lt;/th&gt;
      &lt;th&gt;Cosa fa&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt; fine riga 1&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;registra la riga - OK!&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&lt;/code&gt; di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;24&quot;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;toggle → &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;&lt;/strong&gt; - FAIL&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt; fine riga 2&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;salta&lt;/em&gt; - SKIP&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt; fine riga 3&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;em&gt;salta&lt;/em&gt; - SKIP&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Da quel momento in avanti il resto del file finisce per essere male interpretato e diventa pressoché spazzatura.&lt;/p&gt;

&lt;p&gt;La buona notizia è che l’&lt;a href=&quot;https://www.rfc-editor.org/info/rfc4180/&quot;&gt;RFC del CSV&lt;/a&gt; ci dà una semplice regola per gestire il tutto: &lt;em&gt;una virgoletta apre un campo quotato solo se è il primo byte del campo&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;Via Roma 1\n00100 Roma&quot;&lt;/code&gt; la virgoletta è a inizio campo, il campo è quotato, l’a-capo dentro è un dato&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;monitor 24&quot; full HD&lt;/code&gt; la virgoletta è a metà campo, quindi è solo un carattere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;È il motivo per cui è necessario &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if atFieldStart&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;le-virgolette-raddoppiate-si-annullano-da-sole&quot;&gt;Le virgolette raddoppiate si annullano da sole&lt;/h3&gt;

&lt;p&gt;Un altro caso potenzialmente da gestire erano le virgolette letterali.
Dentro un campo quotato, una virgoletta letterale la si scrive raddoppiandola:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csv&quot;&gt;Mario,&quot;disse &quot;&quot;ciao&quot;&quot; e se ne andò&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Verrebbe da gestirlo: vedo una virgoletta, sbircio la prossima, se è ancora una virgoletta allora è un escape.&lt;br /&gt;
In realtà non serve. Il toggle se la cava da solo:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;hello&quot;&quot;world&quot;
^                inQuotes = true
      ^          inQuotes = false
       ^         inQuotes = true    ← i due si annullano
             ^   inQuotes = false
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Due cambi di stato consecutivi non cambiano niente, e lo stato finale è quello giusto.&lt;/p&gt;

&lt;p&gt;Sembra un dettaglio, e invece è la cosa che tiene in piedi tutta la lettura a blocchi: senza sbirciare in avanti, il confine dei 64 KB smette di essere un caso speciale. Un “” a cavallo di due blocchi non va gestito, perché non esiste niente da gestire: il primo byte arriva in un blocco, il secondo nell’altro, e il conto torna comunque.&lt;/p&gt;

&lt;p&gt;Se avessi scelto di sbirciare in avanti avrei dovuto gestire quel caso limite a mano, e i casi limite scritti a mano sono esattamente quelli che ci si perde più facilmente per strada.&lt;/p&gt;

&lt;h3 id=&quot;il-test-che-parla-chiaro&quot;&gt;Il test che parla chiaro&lt;/h3&gt;

&lt;p&gt;A questo punto c’è soltanto una cosa che lavora meglio di un debugger per validare il tutto, ed è un test:&lt;/p&gt;

&lt;!-- Linked code snippet: click to view in popup --&gt;

&lt;div class=&quot;code-link-block&quot;&gt;
&lt;a href=&quot;#&quot; class=&quot;code-link&quot; data-code-id=&quot;test-virgolette&quot; data-code-title=&quot;The test: the newline inside quotes&quot; data-code-subtitle=&quot;The complete code is on GitHub, along with the file used for measurements.&quot;&gt;&lt;svg class=&quot;icon&quot; viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.5&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M7.2 6.4 3.4 10l3.8 3.6M12.8 6.4 16.6 10l-3.8 3.6M11.4 4.6 8.6 15.4&quot; /&gt;&lt;/svg&gt;
&lt;span class=&quot;code-link-text&quot;&gt;&lt;span class=&quot;code-link-label&quot;&gt;The test: the newline inside quotes&lt;/span&gt;&lt;span class=&quot;code-link-note&quot;&gt;The complete code is on GitHub, along with the file used for measurements.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;code-link-source&quot; id=&quot;code-src-test-virgolette&quot; hidden=&quot;&quot;&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// There are three \n in the bytes but only two real rows: the one at position 4 is inside quotes,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// and the final one produces a phantom row to discard.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// If you get [0, 5, 10] quote tracking isn&apos;t working at all;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// if you get [0, 10, 16] the phantom row isn&apos;t being discarded.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// The test tells apart the two failures, which is half its value.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;@Test&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;indexIgnoreNewlineInsideQuote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//          a  ,  &quot;  x  \n y  &quot;  ,  b  \n&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// indices  0  1  2  3  4  5  6  7  8  9&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1,2,3&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;offsets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;withUnsafeBufferPointer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baseAddress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;quoteByte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;delimiterByte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;trackQuotes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;#expect(offsets == [0, 10])&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/div&gt;

&lt;script&gt;
(function() {
  if (window.__codeLinkReady) return;
  window.__codeLinkReady = true;

  /* Create popup container */
  const popup = document.createElement(&apos;div&apos;);
  popup.className = &apos;code-popup&apos;;
  popup.innerHTML = `
    &lt;div class=&quot;code-popup-backdrop&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;code-popup-dialog&quot;&gt;
      &lt;div class=&quot;code-popup-header&quot;&gt;
        &lt;div class=&quot;code-popup-heading&quot;&gt;
          &lt;h3 id=&quot;code-popup-title&quot;&gt;&lt;/h3&gt;
          &lt;p class=&quot;code-popup-subtitle&quot; id=&quot;code-popup-subtitle&quot; hidden&gt;&lt;/p&gt;
        &lt;/div&gt;
        &lt;button class=&quot;code-popup-close&quot; aria-label=&quot;Close&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;line x1=&quot;18&quot; y1=&quot;6&quot; x2=&quot;6&quot; y2=&quot;18&quot; /&gt;
            &lt;line x1=&quot;6&quot; y1=&quot;6&quot; x2=&quot;18&quot; y2=&quot;18&quot; /&gt;
          &lt;/svg&gt;
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;code-popup-content&quot; id=&quot;code-popup-content&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;code-popup-footer&quot;&gt;
        &lt;button class=&quot;code-popup-expand&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;path d=&quot;M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3&quot; /&gt;
          &lt;/svg&gt;
          Expand to fullscreen
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
  document.body.appendChild(popup);

  const popupDialog = popup.querySelector(&apos;.code-popup-dialog&apos;);
  const popupBackdrop = popup.querySelector(&apos;.code-popup-backdrop&apos;);
  const popupTitle = popup.querySelector(&apos;#code-popup-title&apos;);
  const popupSubtitle = popup.querySelector(&apos;#code-popup-subtitle&apos;);
  const popupContent = popup.querySelector(&apos;#code-popup-content&apos;);
  const popupClose = popup.querySelector(&apos;.code-popup-close&apos;);
  const popupExpand = popup.querySelector(&apos;.code-popup-expand&apos;);

  function closePopup() {
    popup.classList.remove(&apos;is-open&apos;);
  }

  /* Close handlers */
  popupBackdrop.addEventListener(&apos;click&apos;, closePopup);
  popupClose.addEventListener(&apos;click&apos;, closePopup);
  document.addEventListener(&apos;keydown&apos;, (e) =&gt; {
    if (e.key === &apos;Escape&apos; &amp;&amp; popup.classList.contains(&apos;is-open&apos;)) {
      closePopup();
    }
  });

  /* Expand to fullscreen */
  popupExpand.addEventListener(&apos;click&apos;, () =&gt; {
    closePopup();
    /* Use the existing code-modal if available */
    const codeModal = document.querySelector(&apos;.code-modal&apos;);
    if (codeModal) {
      const modalCode = codeModal.querySelector(&apos;#code-modal-code&apos;);
      /* popupContent contiene gia il markup completo di Rouge, wrapper
         compreso, quindi si copia cosi com&apos;e */
      modalCode.innerHTML = popupContent.innerHTML;
      codeModal.classList.add(&apos;is-open&apos;);
      modalCode.focus();
    }
  });

  /* Prevent popup close when clicking inside */
  popupDialog.addEventListener(&apos;click&apos;, (e) =&gt; {
    e.stopPropagation();
  });

  /* Delega sul documento: cosi funziona anche per i link che nel DOM */
  /* arrivano dopo questo script. */
  document.addEventListener(&apos;click&apos;, (e) =&gt; {
    const link = e.target.closest(&apos;.code-link&apos;);
    if (link) {
      e.preventDefault();
      const codeId = link.getAttribute(&apos;data-code-id&apos;);
      const source = document.getElementById(&apos;code-src-&apos; + codeId);
      if (!source) return;

      popupTitle.textContent = link.getAttribute(&apos;data-code-title&apos;);

      const subtitle = link.getAttribute(&apos;data-code-subtitle&apos;);
      popupSubtitle.textContent = subtitle || &apos;&apos;;
      popupSubtitle.hidden = !subtitle;
      /* HTML gia evidenziato da Rouge in fase di build: porta con se il &lt;pre&gt;,
         quindi indentazione e colori sopravvivono alla compressione */
      popupContent.innerHTML = source.innerHTML;

      popup.classList.add(&apos;is-open&apos;);
    }
  });
})();
&lt;/script&gt;

&lt;style&gt;
/* Code link styling */
.code-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.5em 0.75em;
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--accent);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease;
}

.code-link:hover {
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-link .icon {
  /* due righe di testo accanto: un&apos;icona da 1em sparirebbe */
  width: 1.9em;
  height: 1.9em;
  flex: none;
  opacity: 0.75;
}

/* La freccia del tema qui e un&apos;affordance, non un ornamento da hover: dice
   che il link apre qualcosa. Va tenuta visibile, e per farlo bisogna ripetere
   la catena di :not() della regola base, che altrimenti pesa di piu (0,3,2)
   e rimette opacity a 0. */
.post-body a.code-link:not(.tag):not(.entry-link)::after {
  opacity: 1;
  transform: none;
  align-self: center;
}

.code-link-label { min-width: 0; }

.code-link-error {
  color: var(--text-muted);
  font-size: 0.9em;
}

/* Code popup */
.code-popup {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.code-popup.is-open {
  opacity: 1;
  pointer-events: auto;
}

.code-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
}

.code-popup-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: 70vw;
  max-height: 70vh;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.code-popup-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--rule);
}

.code-popup-header h3 {
  margin: 0;
  font-size: var(--t-0);
  font-weight: 600;
  font-family: var(--font-mono);
}

.code-popup-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}

.code-popup-close:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
}

.code-popup-close svg {
  width: 16px;
  height: 16px;
}

.code-popup-content {
  flex: 1;
  overflow: auto;
  padding: var(--s-4);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg-sunken);
}

.code-popup-content pre,
.code-popup-content .highlight,
.code-popup-content .highlighter-rouge {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  font-size: inherit;
  line-height: inherit;
}

/* il sorgente vive nella pagina solo per essere copiato nel popup */
.code-link-source { display: none; }

.code-link-block {
  display: flex;
  margin: var(--s-4) 0;
}

/* titolo e sottotitolo incolonnati dentro al riquadro, accanto all&apos;icona */
.code-link-text {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-width: 0;
}

.code-link-note,
.code-popup-subtitle {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--t--2);
  color: var(--text-muted);
  line-height: 1.4;
}

.code-popup-heading { min-width: 0; }

.code-popup-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--rule);
  background: var(--bg);
}

.code-popup-expand {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.45em 0.9em;
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--text);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}

.code-popup-expand:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-popup-expand svg {
  width: 1em;
  height: 1em;
}

/* Mobile responsive */
@media (max-width: 40rem) {
  .code-popup-dialog {
    max-width: 95vw;
    max-height: 80vh;
  }

  .code-popup-content {
    font-size: 0.75em;
  }
}
&lt;/style&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,b&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1,2,3&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// indice:            0 1 2 3 4  5 6 7 8 9 …&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#expect(offsets == [0, 10])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tre &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt; nei byte, solo due righe sono vere: quello in posizione 4 è dentro le virgolette, e quello finale produce una riga fantasma da scartare.&lt;/p&gt;

&lt;p&gt;Ma il valore del test non è nel controllo. È in cosa significano i modi di fallire:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Risultato&lt;/th&gt;
      &lt;th&gt;Diagnosi&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0, 10]&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;corretto&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0, 5, 10]&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;il tracciamento delle virgolette non sta girando affatto&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0, 10, 16]&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;gira, ma non scarta la riga fantasma finale&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Due difetti diversi producono due numeri diversi. Il test non dice «sbagliato»: dice quale sbagliato.&lt;/p&gt;

&lt;p&gt;E ha funzionato. Al primo lancio: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0, 5, 10]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Che è precisamente l’output di un parser che ignora le virgolette: quindi il problema non era la logica delle quote, era che quella logica non veniva eseguita. Sono andato a guardare il solo punto in cui poteva succedere, e il colpevole era un else scritto male:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;// scatta su qualunque byte&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inQuotes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// scatta solo fuori dalle virgolette&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Il ramo dei separatori si attivava anche dentro un campo quotato. Un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt; protetto dalle virgolette veniva registrato lo stesso.
Il debugger non l’ho aperto.&lt;/p&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;A un test non chiedo di dirmi che ho sbagliato: quello lo so già.&lt;br /&gt;
Gli chiedo di dirmi &lt;em&gt;dove&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;lottimizzazione-che-non-ha-ottimizzato-niente&quot;&gt;L’ottimizzazione che non ha ottimizzato niente&lt;/h2&gt;

&lt;p&gt;A questo punto il parser generava correttamente un array con tutti gli indici di partenza delle righe.&lt;br /&gt;
Peccato che i dati, letti a blocchi da 64 KB, fossero già stati scartati: ogni blocco sovrascriveva il precedente.&lt;/p&gt;

&lt;p&gt;Per estrarre davvero una riga dovevo tornare a prendermi quei byte, e le strade per farlo erano poche:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Rileggere riga per riga, saltando ogni volta alla posizione giusta&lt;/strong&gt;: vuol dire una chiamata al sistema operativo per riga, sei milioni di chiamate per leggere in media quarantasei byte l’una. &lt;em&gt;Decisamente da escludere&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rileggere a blocchi e consegnare le righe man man&lt;/strong&gt;o, ma vuol dire attraversare il file una seconda volta e rifare tutte quelle copie che volevo evitare. In più una riga può cominciare in un blocco e finire in quello dopo: per consegnarla intera devo conservare la coda del primo e attaccarla alla testa del secondo, con un caso speciale da scrivere e da ricordarsi. &lt;em&gt;Anche questa poco attraente&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mappare il file&lt;/strong&gt; e tenermelo tutto indirizzabile in una volta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ed è qui che mi sono accorto di una cosa che avevo davanti dall’inizio: l’indice che avevo appena costruito contiene posizioni assolute dentro il file. Non sono offset relativi a un blocco, ma numeri che danno la posizione assoliuta.&lt;br /&gt;
Che è esattamente il linguaggio di una memoria mappata, dove il file è un array.&lt;/p&gt;

&lt;p&gt;In effetti avevo già fatto metà del lavoro che rendeva &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt; comodo:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;O_RDONLY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;c1&quot;&gt;// Una volta creata la mappa, il descrittore del file non serve più. &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// La mappatura tiene un suo riferimento, e la memoria resta valida anche a file chiuso.&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;fstat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;st_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// mmap non dà i byte: riserva soltanto un intervallo di indirizzi nello spazio di memoria del processo &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// e dice al kernel «quando qualcuno tocca questi indirizzi, vai a prendere i pezzi di quel file». &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mapped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;PROT_READ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;MAP_PRIVATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;munmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// rilascia la prenotazione alla fine&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// crea il puntatore alla memoria tipizzato&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UnsafePointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapped&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assumingMemoryBound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UInt8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;La parte di indicizzazione di colpo si era semplificata, senza il &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;while&lt;/code&gt;, senza &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readData&lt;/code&gt; e senza dover mantenere un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fileOffset&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inoltre le tre variabili di stato, che erano fuori dal ciclo per tenere traccia tra una lettura e l’altra del blocco, ora erano normali variabili locale di un ciclo che percorre il file dall’inizio alla fine.&lt;br /&gt;
Il campo quotato spezzato a metà fra due letture, che non è stato risolto, aveva ha smesso di poter accadere.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;offsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atFieldStart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fieldIsQuoted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;inQuotes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...identico a prima, gli stessi quattro rami byte per byte&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A parte la semplificazione del codice mi aspettavo però anche un miglioramento delle performance; ho quindi provato a misurare la differenza con la lettura a blocchi:&lt;/p&gt;

&lt;!-- Linked code snippet: click to view in popup --&gt;

&lt;div class=&quot;code-link-block&quot;&gt;
&lt;a href=&quot;#&quot; class=&quot;code-link&quot; data-code-id=&quot;test-stadi&quot; data-code-title=&quot;The test: three indexing stages compared&quot; data-code-subtitle=&quot;The complete code is on GitHub, along with the file used for measurements.&quot;&gt;&lt;svg class=&quot;icon&quot; viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.5&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M7.2 6.4 3.4 10l3.8 3.6M12.8 6.4 16.6 10l-3.8 3.6M11.4 4.6 8.6 15.4&quot; /&gt;&lt;/svg&gt;
&lt;span class=&quot;code-link-text&quot;&gt;&lt;span class=&quot;code-link-label&quot;&gt;The test: three indexing stages compared&lt;/span&gt;&lt;span class=&quot;code-link-note&quot;&gt;The complete code is on GitHub, along with the file used for measurements.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;code-link-source&quot; id=&quot;code-src-test-stadi&quot; hidden=&quot;&quot;&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;kd&quot;&gt;@Test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stageComparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;clock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ContinuousClock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Warm-up: pulls the 260 MB into the page cache, otherwise the first stage&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// measured is timing the disk and looks like the worst of the three.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageMemchr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chunks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageChunks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chunksTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t0&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mapped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageMmap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mappedTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memchr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageMemchr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memchrTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Again: same result, or the timings mean nothing.&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(mapped == chunks)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(memchr == chunks)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FileManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attributesOfItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;atPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gigabytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as?&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1_073_741_824&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.2f GB/s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gigabytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;

    ── line indexing, &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; rows ──
      1. 64 KB blocks       &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%7.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s   &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2. mmap               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%7.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s   &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      3. mmap + memchr      &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%7.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s   &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;

         1 → 2: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x
         2 → 3: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x
         total: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x

    &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/div&gt;

&lt;script&gt;
(function() {
  if (window.__codeLinkReady) return;
  window.__codeLinkReady = true;

  /* Create popup container */
  const popup = document.createElement(&apos;div&apos;);
  popup.className = &apos;code-popup&apos;;
  popup.innerHTML = `
    &lt;div class=&quot;code-popup-backdrop&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;code-popup-dialog&quot;&gt;
      &lt;div class=&quot;code-popup-header&quot;&gt;
        &lt;div class=&quot;code-popup-heading&quot;&gt;
          &lt;h3 id=&quot;code-popup-title&quot;&gt;&lt;/h3&gt;
          &lt;p class=&quot;code-popup-subtitle&quot; id=&quot;code-popup-subtitle&quot; hidden&gt;&lt;/p&gt;
        &lt;/div&gt;
        &lt;button class=&quot;code-popup-close&quot; aria-label=&quot;Close&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;line x1=&quot;18&quot; y1=&quot;6&quot; x2=&quot;6&quot; y2=&quot;18&quot; /&gt;
            &lt;line x1=&quot;6&quot; y1=&quot;6&quot; x2=&quot;18&quot; y2=&quot;18&quot; /&gt;
          &lt;/svg&gt;
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;code-popup-content&quot; id=&quot;code-popup-content&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;code-popup-footer&quot;&gt;
        &lt;button class=&quot;code-popup-expand&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;path d=&quot;M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3&quot; /&gt;
          &lt;/svg&gt;
          Expand to fullscreen
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
  document.body.appendChild(popup);

  const popupDialog = popup.querySelector(&apos;.code-popup-dialog&apos;);
  const popupBackdrop = popup.querySelector(&apos;.code-popup-backdrop&apos;);
  const popupTitle = popup.querySelector(&apos;#code-popup-title&apos;);
  const popupSubtitle = popup.querySelector(&apos;#code-popup-subtitle&apos;);
  const popupContent = popup.querySelector(&apos;#code-popup-content&apos;);
  const popupClose = popup.querySelector(&apos;.code-popup-close&apos;);
  const popupExpand = popup.querySelector(&apos;.code-popup-expand&apos;);

  function closePopup() {
    popup.classList.remove(&apos;is-open&apos;);
  }

  /* Close handlers */
  popupBackdrop.addEventListener(&apos;click&apos;, closePopup);
  popupClose.addEventListener(&apos;click&apos;, closePopup);
  document.addEventListener(&apos;keydown&apos;, (e) =&gt; {
    if (e.key === &apos;Escape&apos; &amp;&amp; popup.classList.contains(&apos;is-open&apos;)) {
      closePopup();
    }
  });

  /* Expand to fullscreen */
  popupExpand.addEventListener(&apos;click&apos;, () =&gt; {
    closePopup();
    /* Use the existing code-modal if available */
    const codeModal = document.querySelector(&apos;.code-modal&apos;);
    if (codeModal) {
      const modalCode = codeModal.querySelector(&apos;#code-modal-code&apos;);
      /* popupContent contiene gia il markup completo di Rouge, wrapper
         compreso, quindi si copia cosi com&apos;e */
      modalCode.innerHTML = popupContent.innerHTML;
      codeModal.classList.add(&apos;is-open&apos;);
      modalCode.focus();
    }
  });

  /* Prevent popup close when clicking inside */
  popupDialog.addEventListener(&apos;click&apos;, (e) =&gt; {
    e.stopPropagation();
  });

  /* Delega sul documento: cosi funziona anche per i link che nel DOM */
  /* arrivano dopo questo script. */
  document.addEventListener(&apos;click&apos;, (e) =&gt; {
    const link = e.target.closest(&apos;.code-link&apos;);
    if (link) {
      e.preventDefault();
      const codeId = link.getAttribute(&apos;data-code-id&apos;);
      const source = document.getElementById(&apos;code-src-&apos; + codeId);
      if (!source) return;

      popupTitle.textContent = link.getAttribute(&apos;data-code-title&apos;);

      const subtitle = link.getAttribute(&apos;data-code-subtitle&apos;);
      popupSubtitle.textContent = subtitle || &apos;&apos;;
      popupSubtitle.hidden = !subtitle;
      /* HTML gia evidenziato da Rouge in fase di build: porta con se il &lt;pre&gt;,
         quindi indentazione e colori sopravvivono alla compressione */
      popupContent.innerHTML = source.innerHTML;

      popup.classList.add(&apos;is-open&apos;);
    }
  });
})();
&lt;/script&gt;

&lt;style&gt;
/* Code link styling */
.code-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.5em 0.75em;
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--accent);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease;
}

.code-link:hover {
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-link .icon {
  /* due righe di testo accanto: un&apos;icona da 1em sparirebbe */
  width: 1.9em;
  height: 1.9em;
  flex: none;
  opacity: 0.75;
}

/* La freccia del tema qui e un&apos;affordance, non un ornamento da hover: dice
   che il link apre qualcosa. Va tenuta visibile, e per farlo bisogna ripetere
   la catena di :not() della regola base, che altrimenti pesa di piu (0,3,2)
   e rimette opacity a 0. */
.post-body a.code-link:not(.tag):not(.entry-link)::after {
  opacity: 1;
  transform: none;
  align-self: center;
}

.code-link-label { min-width: 0; }

.code-link-error {
  color: var(--text-muted);
  font-size: 0.9em;
}

/* Code popup */
.code-popup {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.code-popup.is-open {
  opacity: 1;
  pointer-events: auto;
}

.code-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
}

.code-popup-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: 70vw;
  max-height: 70vh;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.code-popup-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--rule);
}

.code-popup-header h3 {
  margin: 0;
  font-size: var(--t-0);
  font-weight: 600;
  font-family: var(--font-mono);
}

.code-popup-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}

.code-popup-close:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
}

.code-popup-close svg {
  width: 16px;
  height: 16px;
}

.code-popup-content {
  flex: 1;
  overflow: auto;
  padding: var(--s-4);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg-sunken);
}

.code-popup-content pre,
.code-popup-content .highlight,
.code-popup-content .highlighter-rouge {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  font-size: inherit;
  line-height: inherit;
}

/* il sorgente vive nella pagina solo per essere copiato nel popup */
.code-link-source { display: none; }

.code-link-block {
  display: flex;
  margin: var(--s-4) 0;
}

/* titolo e sottotitolo incolonnati dentro al riquadro, accanto all&apos;icona */
.code-link-text {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-width: 0;
}

.code-link-note,
.code-popup-subtitle {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--t--2);
  color: var(--text-muted);
  line-height: 1.4;
}

.code-popup-heading { min-width: 0; }

.code-popup-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--rule);
  background: var(--bg);
}

.code-popup-expand {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.45em 0.9em;
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--text);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}

.code-popup-expand:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-popup-expand svg {
  width: 1em;
  height: 1em;
}

/* Mobile responsive */
@media (max-width: 40rem) {
  .code-popup-dialog {
    max-width: 95vw;
    max-height: 80vh;
  }

  .code-popup-content {
    font-size: 0.75em;
  }
}
&lt;/style&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Release&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;blocchi da 64 KB&lt;/td&gt;
      &lt;td&gt;0,384s&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;0,373s&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;em&gt;Niente. Un uno virgola zero.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Neanche &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;madvise(MADV_SEQUENTIAL)&lt;/code&gt; ha funzionato, ho rosicchiato giusto un altro centesimo.&lt;/p&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;Cos&apos;è madvise()?&lt;/strong&gt;
    
    &lt;p&gt;È un modo per dire al kernel come vogliamo usare una regione di memoria mappata, così che possa regolarsi di conseguenza. Con &lt;code&gt;MADV_SEQUENTIAL&lt;/code&gt; stiamo dicendo «questo file lo leggerò dall&apos;inizio alla fine, una volta sola».&lt;/p&gt;&lt;p&gt;Due cose cambiano. La prima è il &lt;em&gt;readahead&lt;/em&gt;: quando tocchiamo una pagina, il kernel ne carica in anticipo anche un certo numero di quelle successive, invece di aspettare che gliele chiediamo una per una. Senza il suggerimento deve prima accorgersi da solo che stiamo procedendo in ordine, quindi parte più cauto.&lt;/p&gt;&lt;p&gt;La seconda è che le pagine che ci seiamo lasciati indietro vengono liberate prima, perché gli hai promesso che non tornerai a guardarle. Su un file da 260 MB è la differenza fra tenerselo tutto residente e tenerne una finestra che scorre.&lt;/p&gt;&lt;p&gt;È un suggerimento, non un ordine: il kernel può tranquillamente ignorarlo.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;p&gt;Che non abbia funzionato, comunque, ha perfettamente senso.&lt;/p&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;Pensandoci il &lt;strong&gt;collo di bottiglia non è mai stato il modo in cui i byte arrivano, ma il ciclo che ne guarda uno alla volta facendogli quattro domande&lt;/strong&gt;. Ho cambiato come il file viene &lt;em&gt;preparato&lt;/em&gt;, non come viene letto, e il tempo se ne andava tutto nella lettura.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Ora, tenersi una modifica che non fa guadagnare niente somiglia parecchio a un capriccio.&lt;br /&gt;
La differenza fra le due cose sta però tutta nel saper dire cosa ci ha comprato, anche quando non è velocità.&lt;/p&gt;

&lt;p&gt;Qui erano &lt;strong&gt;meno codice e un caso limite in meno da ricordare, ma soprattutto un puntatore stabile&lt;/strong&gt;: un indirizzo valido per tutta la vita del lettore, su cui potrò far puntare i campi senza doverli copiare da nessuna parte. A cosa serva davvero lo vedremo fra poco.&lt;/p&gt;

&lt;p&gt;Per ora il cronometro segna &lt;strong&gt;0,373 secondi&lt;/strong&gt;, e non si è mosso di un millimetro.&lt;/p&gt;

&lt;h2 id=&quot;cercare-invece-di-guardare&quot;&gt;Cercare invece di guardare&lt;/h2&gt;

&lt;p&gt;All’interno del mio ciclo di indicizzazione &lt;strong&gt;facciamo quattro domande per ogni byte&lt;/strong&gt;.&lt;/p&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;Sono però domande che il &lt;strong&gt;più delle volte non servono a niente&lt;/strong&gt;: la stragrande maggioranza dei byte sono dati, non caratteri di controllo &lt;em&gt;(virgolette, virgole, a-capo)&lt;/em&gt;.&lt;br /&gt;
Un sacco di domande la cui risposta non ci interessa, e che in ogni caso sarebbe “no”.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;L’obiettivo era quindi evitare di esaminare ogni byte: bastava &lt;strong&gt;trovare il prossimo byte interessante nella sequenza&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Fortunamente il C ha da sempre una funzione dedicata: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memchr&lt;/code&gt; prende un blocco di memoria e un byte, e restituisce la posizione della prima occorrenza. Dentro non c’è niente di magico, solo del codice scritto in SIMD a mano: invece di confrontare un byte alla volta ne carica sedici in un registro e li confronta tutti insieme.&lt;/p&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;SIMD?&lt;/strong&gt;
    
    SIMD (Single Instruction, Multiple Data) è una tecnica di parallelismo a livello di microprocessore che consente di eseguire un&apos;unica istruzione su un intero insieme di dati contemporaneamente, anziché elaborare un singolo dato alla volta.
  Solitamente scrivere codice SIMD non è la cosa più facile del mondo: fortunatamente qui il lavoro è già fatto ed è più veloce di qualunque ciclo che potrei scrivere in Swift.
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;p&gt;C’è un problema, però, ed è grosso: &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memchr&lt;/code&gt; cerca un byte solo&lt;/strong&gt;. Il mio parser non deve trovare un byte, deve sapere se in questo momento si trova dentro o fuori dalle virgolette. Quello è uno stato, e uno stato non si esprime con una ricerca.&lt;/p&gt;

&lt;h3 id=&quot;la-domanda-che-scioglie-il-nodo&quot;&gt;La domanda che scioglie il nodo&lt;/h3&gt;

&lt;p&gt;Sembrava un vicolo cieco, finché non mi sono posto una domanda diversa: &lt;em&gt;quand’è che lo stato non serve?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;La risposta è quasi banale una volta detta: &lt;strong&gt;Se in tutto il file non c’è nemmeno una virgoletta, allora nessun campo può essere quotato&lt;/strong&gt;. E se nessun campo è quotato, nessun a capo può trovarsi dentro un campo. Quindi cercare gli a capo e basta non è un’approssimazione: è &lt;strong&gt;dimostrabilmente corretto&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;E per saperlo basta una &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memchr&lt;/code&gt; che cerchi una virgoletta sull’intero file.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// C&apos;è almeno una virgoletta, in tutti i 260 MB?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hasQuotes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;memchr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quoteByte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasQuotes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// No. Allora nessun campo è quotato, e trovare gli a capo basta.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;memchr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x0A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UnsafeRawPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UnsafeRawPointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;offsets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offsets&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Sì. Allora serve la macchina a stati, byte per byte, come prima.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;La parte che mi piace di più non è la velocità: è che &lt;strong&gt;non sto chiedendo niente a chi usa la libreria&lt;/strong&gt;. Nessuna opzione da attivare, nessuna promessa da fare sui propri dati. Il codice guarda il file e decide da solo quale scorciatoia può permettersi.&lt;/p&gt;

&lt;h3 id=&quot;quanto-ha-reso&quot;&gt;Quanto ha reso&lt;/h3&gt;

&lt;!-- Linked code snippet: click to view in popup --&gt;

&lt;div class=&quot;code-link-block&quot;&gt;
&lt;a href=&quot;#&quot; class=&quot;code-link&quot; data-code-id=&quot;test-stadi&quot; data-code-title=&quot;The test: three indexing stages compared&quot; data-code-subtitle=&quot;The complete code is on GitHub, along with the file used for measurements.&quot;&gt;&lt;svg class=&quot;icon&quot; viewBox=&quot;0 0 20 20&quot; width=&quot;20&quot; height=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;1.5&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot; focusable=&quot;false&quot;&gt;&lt;path d=&quot;M7.2 6.4 3.4 10l3.8 3.6M12.8 6.4 16.6 10l-3.8 3.6M11.4 4.6 8.6 15.4&quot; /&gt;&lt;/svg&gt;
&lt;span class=&quot;code-link-text&quot;&gt;&lt;span class=&quot;code-link-label&quot;&gt;The test: three indexing stages compared&lt;/span&gt;&lt;span class=&quot;code-link-note&quot;&gt;The complete code is on GitHub, along with the file used for measurements.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;code-link-source&quot; id=&quot;code-src-test-stadi&quot; hidden=&quot;&quot;&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-swift&quot; data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;kd&quot;&gt;@Test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stageComparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;clock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ContinuousClock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Warm-up: pulls the 260 MB into the page cache, otherwise the first stage&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// measured is timing the disk and looks like the worst of the three.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageMemchr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chunks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageChunks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;chunksTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t0&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mapped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageMmap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;mappedTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t1&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memchr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;StageMemchr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;indexLines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;memchrTime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t2&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Again: same result, or the timings mean nothing.&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(mapped == chunks)&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#expect(memchr == chunks)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;FileManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attributesOfItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;atPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gtfsURL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gigabytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as?&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1_073_741_824&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.2f GB/s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gigabytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;

    ── line indexing, &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; rows ──
      1. 64 KB blocks       &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%7.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s   &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      2. mmap               &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%7.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s   &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;
      3. mmap + memchr      &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%7.3f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s   &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;

         1 → 2: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x
         2 → 3: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mappedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x
         total: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;%.1f&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunksTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memchrTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x

    &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/div&gt;

&lt;script&gt;
(function() {
  if (window.__codeLinkReady) return;
  window.__codeLinkReady = true;

  /* Create popup container */
  const popup = document.createElement(&apos;div&apos;);
  popup.className = &apos;code-popup&apos;;
  popup.innerHTML = `
    &lt;div class=&quot;code-popup-backdrop&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;code-popup-dialog&quot;&gt;
      &lt;div class=&quot;code-popup-header&quot;&gt;
        &lt;div class=&quot;code-popup-heading&quot;&gt;
          &lt;h3 id=&quot;code-popup-title&quot;&gt;&lt;/h3&gt;
          &lt;p class=&quot;code-popup-subtitle&quot; id=&quot;code-popup-subtitle&quot; hidden&gt;&lt;/p&gt;
        &lt;/div&gt;
        &lt;button class=&quot;code-popup-close&quot; aria-label=&quot;Close&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;line x1=&quot;18&quot; y1=&quot;6&quot; x2=&quot;6&quot; y2=&quot;18&quot; /&gt;
            &lt;line x1=&quot;6&quot; y1=&quot;6&quot; x2=&quot;18&quot; y2=&quot;18&quot; /&gt;
          &lt;/svg&gt;
        &lt;/button&gt;
      &lt;/div&gt;
      &lt;div class=&quot;code-popup-content&quot; id=&quot;code-popup-content&quot;&gt;&lt;/div&gt;
      &lt;div class=&quot;code-popup-footer&quot;&gt;
        &lt;button class=&quot;code-popup-expand&quot;&gt;
          &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot;&gt;
            &lt;path d=&quot;M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3&quot; /&gt;
          &lt;/svg&gt;
          Expand to fullscreen
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
  document.body.appendChild(popup);

  const popupDialog = popup.querySelector(&apos;.code-popup-dialog&apos;);
  const popupBackdrop = popup.querySelector(&apos;.code-popup-backdrop&apos;);
  const popupTitle = popup.querySelector(&apos;#code-popup-title&apos;);
  const popupSubtitle = popup.querySelector(&apos;#code-popup-subtitle&apos;);
  const popupContent = popup.querySelector(&apos;#code-popup-content&apos;);
  const popupClose = popup.querySelector(&apos;.code-popup-close&apos;);
  const popupExpand = popup.querySelector(&apos;.code-popup-expand&apos;);

  function closePopup() {
    popup.classList.remove(&apos;is-open&apos;);
  }

  /* Close handlers */
  popupBackdrop.addEventListener(&apos;click&apos;, closePopup);
  popupClose.addEventListener(&apos;click&apos;, closePopup);
  document.addEventListener(&apos;keydown&apos;, (e) =&gt; {
    if (e.key === &apos;Escape&apos; &amp;&amp; popup.classList.contains(&apos;is-open&apos;)) {
      closePopup();
    }
  });

  /* Expand to fullscreen */
  popupExpand.addEventListener(&apos;click&apos;, () =&gt; {
    closePopup();
    /* Use the existing code-modal if available */
    const codeModal = document.querySelector(&apos;.code-modal&apos;);
    if (codeModal) {
      const modalCode = codeModal.querySelector(&apos;#code-modal-code&apos;);
      /* popupContent contiene gia il markup completo di Rouge, wrapper
         compreso, quindi si copia cosi com&apos;e */
      modalCode.innerHTML = popupContent.innerHTML;
      codeModal.classList.add(&apos;is-open&apos;);
      modalCode.focus();
    }
  });

  /* Prevent popup close when clicking inside */
  popupDialog.addEventListener(&apos;click&apos;, (e) =&gt; {
    e.stopPropagation();
  });

  /* Delega sul documento: cosi funziona anche per i link che nel DOM */
  /* arrivano dopo questo script. */
  document.addEventListener(&apos;click&apos;, (e) =&gt; {
    const link = e.target.closest(&apos;.code-link&apos;);
    if (link) {
      e.preventDefault();
      const codeId = link.getAttribute(&apos;data-code-id&apos;);
      const source = document.getElementById(&apos;code-src-&apos; + codeId);
      if (!source) return;

      popupTitle.textContent = link.getAttribute(&apos;data-code-title&apos;);

      const subtitle = link.getAttribute(&apos;data-code-subtitle&apos;);
      popupSubtitle.textContent = subtitle || &apos;&apos;;
      popupSubtitle.hidden = !subtitle;
      /* HTML gia evidenziato da Rouge in fase di build: porta con se il &lt;pre&gt;,
         quindi indentazione e colori sopravvivono alla compressione */
      popupContent.innerHTML = source.innerHTML;

      popup.classList.add(&apos;is-open&apos;);
    }
  });
})();
&lt;/script&gt;

&lt;style&gt;
/* Code link styling */
.code-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.5em 0.75em;
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--accent);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease;
}

.code-link:hover {
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-link .icon {
  /* due righe di testo accanto: un&apos;icona da 1em sparirebbe */
  width: 1.9em;
  height: 1.9em;
  flex: none;
  opacity: 0.75;
}

/* La freccia del tema qui e un&apos;affordance, non un ornamento da hover: dice
   che il link apre qualcosa. Va tenuta visibile, e per farlo bisogna ripetere
   la catena di :not() della regola base, che altrimenti pesa di piu (0,3,2)
   e rimette opacity a 0. */
.post-body a.code-link:not(.tag):not(.entry-link)::after {
  opacity: 1;
  transform: none;
  align-self: center;
}

.code-link-label { min-width: 0; }

.code-link-error {
  color: var(--text-muted);
  font-size: 0.9em;
}

/* Code popup */
.code-popup {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.code-popup.is-open {
  opacity: 1;
  pointer-events: auto;
}

.code-popup-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
}

.code-popup-dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: 70vw;
  max-height: 70vh;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}

.code-popup-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--rule);
}

.code-popup-header h3 {
  margin: 0;
  font-size: var(--t-0);
  font-weight: 600;
  font-family: var(--font-mono);
}

.code-popup-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}

.code-popup-close:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
}

.code-popup-close svg {
  width: 16px;
  height: 16px;
}

.code-popup-content {
  flex: 1;
  overflow: auto;
  padding: var(--s-4);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg-sunken);
}

.code-popup-content pre,
.code-popup-content .highlight,
.code-popup-content .highlighter-rouge {
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  border-radius: 0;
  font-size: inherit;
  line-height: inherit;
}

/* il sorgente vive nella pagina solo per essere copiato nel popup */
.code-link-source { display: none; }

.code-link-block {
  display: flex;
  margin: var(--s-4) 0;
}

/* titolo e sottotitolo incolonnati dentro al riquadro, accanto all&apos;icona */
.code-link-text {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-width: 0;
}

.code-link-note,
.code-popup-subtitle {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--t--2);
  color: var(--text-muted);
  line-height: 1.4;
}

.code-popup-heading { min-width: 0; }

.code-popup-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--rule);
  background: var(--bg);
}

.code-popup-expand {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.45em 0.9em;
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--text);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}

.code-popup-expand:hover {
  color: var(--accent);
  border-color: var(--accent-soft);
  background: var(--bg);
}

.code-popup-expand svg {
  width: 1em;
  height: 1em;
}

/* Mobile responsive */
@media (max-width: 40rem) {
  .code-popup-dialog {
    max-width: 95vw;
    max-height: 80vh;
  }

  .code-popup-content {
    font-size: 0.75em;
  }
}
&lt;/style&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Release&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt;, ciclo scalare&lt;/td&gt;
      &lt;td&gt;0,373s&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mmap&lt;/code&gt; + annusata + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memchr&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0,065s&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Un &lt;strong&gt;5,7x&lt;/strong&gt;, il primo vero salto di velocità.&lt;br /&gt;
C’è anche un effetto collaterale che non mi aspettavo. Prima dell’&lt;em&gt;annusata&lt;/em&gt; avevo una variabile di configurazione — &lt;em&gt;«prometto che nessun campo contiene a capo»&lt;/em&gt;, che dava il percorso veloce a chi la attivava. Dopo, non serviva più a niente: la velocità arriva comunque. L’ho tolta.&lt;/p&gt;

&lt;!-- Confluence-style note boxes with icons --&gt;
&lt;div class=&quot;note note-info&quot;&gt;
  &lt;div class=&quot;note-icon&quot;&gt;
    
        &lt;svg viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot;&gt;
          &lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z&quot; /&gt;
        &lt;/svg&gt;
    
  &lt;/div&gt;

  &lt;div class=&quot;note-content&quot;&gt;
    
      &lt;strong class=&quot;note-title&quot;&gt;E se avessi misurato in debug?&lt;/strong&gt;
    
    Ricordate la figuraccia della build in debug? Vale la pena tornarci, perché questa ottimizzazione ci dà un altro punto di vista.
  Se avessi misurato questo stesso passaggio in debug, avrei visto un 176x invece di un 5,7x. Il motivo è che `memchr` è codice C già compilato, che la build di debug non tocca nemmeno, mentre il ciclo scritto a mano in Swift è precisamente ciò che il debug massacra. &lt;br /&gt;Il confronto fra i due, in debug, è truccato in favore del primo di un fattore trenta.&lt;br /&gt;&lt;br /&gt;
  Misurare nella configurazione sbagliata non dà soltanto il numero sbagliato, ma un suggerimento sbagliato di cosa convenga ottimizzare. Cosa che, come vedremo fra poco, è esattamente quello che avevo appena finito di fare.
  &lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.note {
  display: flex;
  gap: var(--s-4);
  margin: var(--s-5) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}

.note-icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-top: 2px;
}

.note-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 1.5;
}

.note-content {
  flex: 1;
  font-size: var(--type-ui);
  line-height: var(--lh-ui);
  color: var(--text);
}

.note-content p {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
}

.note-content p + p {
  margin-top: var(--s-3);
}

.note-title {
  display: block;
  margin-bottom: var(--s-2);
  font-size: 1.1em;
  font-weight: 700;
  color: var(--accent);
}

.note-success {
  border-left-color: #5b6f45;
}

.note-success .note-icon {
  color: #5b6f45;
}

.note-warning {
  border-left-color: #96542b;
}

.note-warning .note-icon {
  color: #96542b;
}

.note-alert,
.note-danger {
  border-left-color: #c98a8a;
}

.note-alert .note-icon,
.note-danger .note-icon {
  color: #c98a8a;
}

.note-tip {
  border-left-color: var(--accent);
}

.note-tip .note-icon {
  color: var(--accent);
}

.note-info {
  border-left-color: var(--accent);
}

.note-info .note-icon {
  color: var(--accent);
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=&quot;light&quot;]) {
    .note-success {
      border-left-color: #a3b18a;
    }

    .note-success .note-icon {
      color: #a3b18a;
    }

    .note-warning {
      border-left-color: #cf9b73;
    }

    .note-warning .note-icon {
      color: #cf9b73;
    }

    .note-alert,
    .note-danger {
      border-left-color: #d9a5a5;
    }

    .note-alert .note-icon,
    .note-danger .note-icon {
      color: #d9a5a5;
    }
  }
}

:root[data-theme=&quot;dark&quot;] {
  .note-success {
    border-left-color: #a3b18a;
  }

  .note-success .note-icon {
    color: #a3b18a;
  }

  .note-warning {
    border-left-color: #cf9b73;
  }

  .note-warning .note-icon {
    color: #cf9b73;
  }

  .note-alert,
  .note-danger {
    border-left-color: #d9a5a5;
  }

  .note-alert .note-icon,
  .note-danger .note-icon {
    color: #d9a5a5;
  }
}
&lt;/style&gt;

&lt;h2 id=&quot;una-riga-che-non-contiene-niente&quot;&gt;Una riga che non contiene niente&lt;/h2&gt;

&lt;p&gt;A questo punto avevo ottenuto un codice più leggibile, meno flag di configurazione e non ultimo, la fase di indicizzazione era passata da 0,38s a 0,065s.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Batti il cinque! …Peccato che non sapessi come ottenere la riga numero n&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;due-problemi-una-soluzione&quot;&gt;Due problemi, una soluzione&lt;/h3&gt;

&lt;p&gt;Prima di andare avanti abbiamo necessità di rappresenta è una riga. Potrebbe essere qualcosa di simile a questo?&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// i vari campi di ogni riga&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;potremmo leggerla con un cursore che avanza, una riga alla volta:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nextRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;È sicuramente l’approccio più semplice, ma anche il più costoso&lt;/strong&gt;: per costruirla dovrei prendere i byte dal file, copiarli in una stringa nuova e metterla in un array.&lt;br /&gt;
&lt;em&gt;Per ogni campo 56 milioni di stringhe, ognuna con la sua allocazione sull’heap.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Di fatto questo è l’approccio che si ottiene attraverso &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components(separatedBy:)&lt;/code&gt; e che avrebbe eclissato per tempi e consumi i piccoli passi di ottimizzazione fatti sopra.&lt;/p&gt;

&lt;p&gt;Pensandoci però, i dati sono già in memoria: sono nel file mappato, contigui e già pronti. &lt;em&gt;Vale davvero la pena copiarli per renderli visibili da un’altra parte?&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UnsafePointer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UInt8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// il riferimento al file mappato&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UnsafeBufferPointer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// gli intervalli di ogni campo&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In questa versione il testo della riga non viene mai copiato (&lt;a href=&quot;https://en.wikipedia.org/wiki/Zero-copy&quot;&gt;zero-copy&lt;/a&gt;); si crea semplicemente una finestra su dati che sono già caricati altrove che vengono letti e processati solo nel momento in cui vengono richiesti (un po’ come fa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Substring&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Ma anche questo approccio crea un problema: una riga che non contiene i propri dati è una riga che dipende da qualcun altro per restare valida in memoria; nel nostro caso dipenderà dall’esistenza della mappa nella classe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CSVReader&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;riga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;CSVReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;riga&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nextRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// qui il reader muore, e con lui la munmap&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;riga&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// SIGBUS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Il compilatore non segnalerà nulla ma a runtime la memoria non è più mappata e il processo muore con un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGBUS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Un secondo problema riguarda nuovamente le allocazioni.&lt;br /&gt;
Per dare accesso alle varie colonne per ogni riga c’è bisogno di un array di intervalli: un array per riga, cioè 5,6 milioni di altre allocazioni.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Suona familiare?&lt;/em&gt;&lt;br /&gt;
E’ esattamente il problema con cui siamo partiti all’inizio leggendo le righe, questa volta applicato alle colonne.&lt;/p&gt;

&lt;p&gt;I due problemi hanno una radice comune: &lt;strong&gt;non c’è nessun momento in cui io sappia che una riga ha finito di servire. Se lo sapessi, potrei riusare lo stesso buffer per la riga successiva, e potrei garantire che nessuna riga sopravviva alla mappa&lt;/strong&gt;. Quel momento me lo posso costruire, ed è la fine di una closure:&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forEachRow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// qui `row` è valida, e solo qui&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// qui non più&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;post-highlight&quot;&gt;
  &lt;p&gt;Dentro la closure il reader è vivo per definizione, quindi la mappa c’è.&lt;br /&gt;
E all’uscita so che quella riga è finita, quindi posso svuotare il buffer degli intervalli e riempirlo con la riga dopo.&lt;br /&gt;
&lt;strong&gt;Questo si traduce in una sola allocazione per l’intero file, invece di una per riga.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;h3 id=&quot;il-prezzo-da-pagare&quot;&gt;Il prezzo da pagare&lt;/h3&gt;

&lt;p&gt;Questa scelta ha un prezzo: si perde il &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;while let&lt;/code&gt;, che è più familiare. Si perde l’uscita anticipata: per fermarsi alla prima riga che interessa serve un artificio, perché una closure che restituisce Void non sa dire «basta così» (nulla di complicato, qui, basterà far tornare un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bool&lt;/code&gt; in uscita).&lt;/p&gt;

&lt;p&gt;Ovviamente niente mi vieta di catturare la riga dentro la closure e portarmela fuori, e se lo faccio torno al &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGBUS&lt;/code&gt; di prima.
Per ora è una convenzione, non una regola: sta scritto nella documentazione, non nel compilatore. Swift avrebbe gli strumenti per renderlo un errore di compilazione, ma quella è una storia per un’altra volta.&lt;/p&gt;

&lt;p&gt;A questo punto avevo tutto: un indice veloce, righe che non copiano niente, campi che si materializzano solo se qualcuno li chiede.&lt;br /&gt;
Mancava misurare quanto costasse davvero leggere quel file.&lt;/p&gt;

&lt;!-- Series navigation: shows prev/next in multi-part articles --&gt;
&lt;!--
  ATTENZIONE: niente indentazione nell&apos;HTML qui sotto.
  Questo include viene iniettato dentro il corpo Markdown dei post, e kramdown
  tratta come blocco di codice qualunque riga rientrata di 4 o piu spazi:
  il markup finirebbe stampato a schermo invece di essere renderizzato.
--&gt;

&lt;!-- Find all posts in this series --&gt;

&lt;div class=&quot;series-nav&quot;&gt;
&lt;div class=&quot;series-header&quot;&gt;
&lt;div class=&quot;series-badge&quot;&gt;
Part &lt;span class=&quot;series-part&quot;&gt;2&lt;/span&gt; of &lt;span class=&quot;series-total&quot;&gt;3&lt;/span&gt;
&lt;/div&gt;
&lt;div class=&quot;series-progress&quot;&gt;
&lt;div class=&quot;series-bar&quot;&gt;
&lt;div class=&quot;series-fill&quot; style=&quot;width: calc(2 / 3 * 100%)&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;nav class=&quot;series-links&quot;&gt;
&lt;!-- Previous button --&gt;








&lt;!-- Next button --&gt;





&lt;a href=&quot;/it/2026/09/14/parser-csv-il-nove-percento/&quot; class=&quot;series-link series-next&quot;&gt;
&lt;span class=&quot;series-label&quot;&gt;Next →&lt;/span&gt;
&lt;span class=&quot;series-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 3: Il 9%&lt;/span&gt;
&lt;/a&gt;



&lt;/nav&gt;

&lt;!-- All parts overview --&gt;
&lt;details class=&quot;series-all&quot;&gt;
&lt;summary&gt;View all parts&lt;/summary&gt;
&lt;ul class=&quot;series-list&quot;&gt;

&lt;li class=&quot;is-current&quot;&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-corretto-poi-veloce/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 2&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 2: Corretto, poi veloce&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;a href=&quot;/it/2026/09/14/parser-csv-il-nove-percento/&quot;&gt;
&lt;span class=&quot;series-num&quot;&gt;Part 3&lt;/span&gt;
&lt;span class=&quot;series-item-title&quot;&gt;L&apos;intuito mente: lezioni da un parser CSV — Parte 3: Il 9%&lt;/span&gt;
&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;
&lt;/details&gt;
&lt;/div&gt;

&lt;style&gt;
.series-nav {
  margin: var(--s-7) 0;
  padding: var(--s-4) var(--s-5);
  background: var(--bg-sunken);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.series-header {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-4);
}

.series-badge {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--1);
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
}

.series-progress {
  flex: 1;
}

.series-bar {
  height: 4px;
  background: var(--rule);
  border-radius: 2px;
  overflow: hidden;
}

.series-fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.3s ease;
}

.series-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--s-3);
  margin-bottom: var(--s-3);
}

.series-link {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  padding: var(--s-3) var(--s-4);
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  transition: border-color 0.18s ease, transform 0.18s ease;
}

.series-link:hover {
  border-color: var(--accent-soft);
  transform: translateY(-2px);
}

/* Il tema aggiunge una freccia dopo ogni link nel corpo del post. Qui e&apos; di
   troppo: la direzione la dicono gia&apos; le etichette &quot;Previous&quot;/&quot;Next&quot;, e su
   &quot;Previous&quot; punterebbe pure dalla parte sbagliata. Per spegnerla serve
   almeno la specificita&apos; della regola base (0,3,2), quindi la catena di
   :not() va ripetuta. */
.post-body .series-nav a:not(.tag):not(.entry-link)::after {
  content: none;
}

.series-label {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.series-link:hover .series-label {
  color: var(--accent);
}

.series-title {
  font-family: var(--font-ui);
  font-size: var(--t--1);
  font-weight: 600;
  line-height: 1.3;
}

.series-all {
  cursor: pointer;
}

.series-all summary {
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--s-2);
  margin: calc(-1 * var(--s-2));
  transition: color 0.18s ease;
}

.series-all summary:hover {
  color: var(--accent);
}

.series-all[open] summary {
  color: var(--accent);
  margin-bottom: var(--s-3);
}

.series-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.series-list li {
  margin: 0;
}

.series-list a {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-radius: 4px;
  color: var(--text);
  text-decoration: none;
  transition: background-color 0.18s ease, color 0.18s ease;
}

.series-list a:hover {
  background-color: var(--bg);
  color: var(--accent);
}

.series-list li.is-current a {
  background-color: var(--bg);
  color: var(--accent);
  font-weight: 600;
}

.series-num {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--t--2);
  color: var(--text-muted);
}

.series-list li.is-current .series-num {
  color: var(--accent);
}

.series-item-title {
  flex: 1;
  font-family: var(--font-ui);
}
&lt;/style&gt;

</content>
 </entry>
 

</feed>
