<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://quuxplusone.github.io/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://quuxplusone.github.io/blog/" rel="alternate" type="text/html" /><updated>2026-07-20T15:32:26+00:00</updated><id>https://quuxplusone.github.io/blog/feed.xml</id><title type="html">Arthur O’Dwyer</title><subtitle>Stuff mostly about C++</subtitle><entry><title type="html">Egerton MS 1995</title><link href="https://quuxplusone.github.io/blog/2026/07/16/egerton-ms-1995/" rel="alternate" type="text/html" title="Egerton MS 1995" /><published>2026-07-16T00:01:00+00:00</published><updated>2026-07-16T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/07/16/egerton-ms-1995</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/07/16/egerton-ms-1995/"><![CDATA[<p>Previously on this blog: <a href="/blog/2026/05/22/exaltation-of-larks/">“The <em>Book of St Albans</em> (1486)”</a> (2026-05-22),
in which I made a table of terms of venery, a.k.a. company terms, e.g. “an exaltation of larks,”
as in the eponymous <a href="https://archive.org/details/exaltationoflark00jame">book</a> by James Lipton.
I mentioned that the <em>Book of St Albans</em> actually has “an exaltyng of larkis,” and that it’s only
in <a href="https://searcharchives.bl.uk/catalog/032-001982919">Egerton MS 1995</a> (circa 1450), according to
Lipton, that we find “an exaltacyon of larkys” proper. But I couldn’t find any digitized copy of
Egerton MS 1995 to verify that claim.</p>

<p>Well, I wrote to the British Library and got the relevant folios digitized; so I can now present a
rough transcription of the Egerton manuscript’s venereal passages. (Sadly there is insufficient communication
between the Library’s division who scan things for money and the division who publish things in the
digital online catalog; I have the scan, but the British Library’s online catalog still will not.
Therefore I’ve uploaded it also to <a href="https://archive.org/details/EgertonMS1995-ff54-65/page/n3/mode/1up">the Internet Archive</a>,
where — at least for now — you also may view it.)</p>

<p>For brief inventories of the whole contents of Egerton MS 1995, see:</p>

<ul>
  <li>
    <p><a href="https://searcharchives.bl.uk/catalog/032-001982919">The British Museum’s catalog entry</a></p>
  </li>
  <li>
    <p><a href="https://archive.org/details/catalogueofsomebooksnobleman/page/154">Item 2105</a> in an 1865
  auction catalog of “highly important and valuable books and
  manuscripts of a nobleman of great literary and artistic taste”</p>
  </li>
  <li>
    <p>James Gairdner,
  <a href="https://archive.org/details/11326849bsb/page/n7"><em>The historical collections of a citizen of London in the fifteenth century</em></a>
  (Camden Society, 1876)</p>
  </li>
</ul>

<p>Do you have a correction or helpful comment on this transcription?
<a href="mailto:arthur.j.odwyer@gmail.com">Send me an email!</a></p>

<hr />

<p>(Fols. 55v ff.)</p>

<p>Note ye the properteys that longythe to a yonge gentylle man to have knowynge of ſuche
thyngys that longythe unto hym that he fayle not in hys propyr termys that longythe unto hym
as hyt ſhalle folowe hereynne wrytynge ❦</p>

<p>The Condyſcyons of a grehounde ande of hys <strike>propyrnyng ~</strike> propyrteys ~</p>

<p>Thy grehounde moſte be heddyd lyke a ſnake<br />
  <i>y-</i>neckyd lyke a drake<br />
  <i>y-</i>breſtyde lyke a lyon<br />
  <strike><i>y-</i>fotyd lyke a noymon</strike><br />
  <i>y-</i>ſyded lyke a <a href="https://en.wikipedia.org/wiki/Ichneumon_(medieval_zoology)">noynon</a><br />
  <i>y-</i>fotyde lyke a catte<br />
  <i>y-</i>taylyd lyke a ratte<br /></p>

<p>Thenne ys the grehounde welle <i>y-</i>ſhapte ~</p>

<hr />

<p>Termys of venery ❦</p>

<table class="smaller">
  <tbody>
    <tr>
      <td>A herde of hertys</td>
      <td>Draſſe of houndys</td>
    </tr>
    <tr>
      <td>herde of Dere</td>
      <td>kenelle of Raychys</td>
    </tr>
    <tr>
      <td>herde of Swannys</td>
      <td>Copylle of Spaynellys</td>
    </tr>
    <tr>
      <td>herde of Cranys</td>
      <td>Sowſe of a lyonas<sup>(?)</sup></td>
    </tr>
    <tr>
      <td>herde of Curlewys</td>
      <td>lyttur of whelpys</td>
    </tr>
    <tr>
      <td>Ny of Feſauntys</td>
      <td>Cowardenys of Currys</td>
    </tr>
    <tr>
      <td>Covaye of Parterygys</td>
      <td>Synguler of Boorys</td>
    </tr>
    <tr>
      <td>Bevy of ladyes</td>
      <td>Sundyr of wylde Swyne</td>
    </tr>
    <tr>
      <td>Bevy of Quaylys</td>
      <td>Dryfte of Tame Swyne</td>
    </tr>
    <tr>
      <td>Bevy of Roys</td>
      <td><strike>Cond</strike> Cloudyr of Cattys<br /> <i>Non dicitur a clouſter</i></td>
    </tr>
    <tr>
      <td>Sege of Betowrys</td>
      <td>harrys of hors</td>
    </tr>
    <tr>
      <td>Sege of hayrynnys</td>
      <td>Stoode of marys</td>
    </tr>
    <tr>
      <td>Sege unto a Caſtelle</td>
      <td>Stalyn of olde hors</td>
    </tr>
    <tr>
      <td>ſprynge of Telys</td>
      <td>Rage of Coltys</td>
    </tr>
    <tr>
      <td>Fluſche of mallardys</td>
      <td>Paſſe of Aſſys</td>
    </tr>
    <tr>
      <td>Dyſſayte of lepwynkys</td>
      <td>Burdynne of mulyſſe</td>
    </tr>
    <tr>
      <td>mouſtyr of Pecockys</td>
      <td>Droffe of Nete</td>
    </tr>
    <tr>
      <td>Falle of woodecockys</td>
      <td>Tryppe of Gete</td>
    </tr>
    <tr>
      <td>walke of Snytys</td>
      <td>Flocke of Schepe</td>
    </tr>
    <tr>
      <td>Congregacyon of Plovers</td>
      <td>Drove or a huſke of Harrys</td>
    </tr>
    <tr>
      <td>Coverete of Cootys</td>
      <td>Gagelynge of Geſſe</td>
    </tr>
    <tr>
      <td>Exaltacyon of larkys</td>
      <td>Broode of hennyſſe</td>
    </tr>
    <tr>
      <td>wayche of Nyghtynggalys</td>
      <td>Pype of Chekynnyſſe</td>
    </tr>
    <tr>
      <td>Flyght of Dovys</td>
      <td>Padelynge of Dookyſſe</td>
    </tr>
    <tr>
      <td>Flyght of Swalys</td>
      <td>Pontyfycalle of Preſtyſſe</td>
    </tr>
    <tr>
      <td>Tydynge of Pyys</td>
      <td>State of Pryncyſſe</td>
    </tr>
    <tr>
      <td>Oſte of men</td>
      <td>Dygnyte of Chanonnyſſe</td>
    </tr>
    <tr>
      <td>Oſte of Sparowys</td>
      <td>Trought of Barronnyſſe</td>
    </tr>
    <tr>
      <td>Felyſchyppe of yemen</td>
      <td>Carge of Curettyſſe</td>
    </tr>
    <tr>
      <td>Swarme of Beys</td>
      <td>Prudens of Vycaryſſe</td>
    </tr>
    <tr>
      <td>Chyrme of Goldefynchys</td>
      <td>Dyſcrecyon of Preſtys</td>
    </tr>
    <tr>
      <td>Caſte of hawkys of the Towre</td>
      <td>Doctryne of Docterſſe</td>
    </tr>
    <tr>
      <td>Flyght of Goſſe hawkys</td>
      <td>Convertynge of Precheryſſe</td>
    </tr>
    <tr>
      <td>Unkyndenys of ravynnys</td>
      <td>Sedent of Juggyſſe</td>
    </tr>
    <tr>
      <td>murther of Crowys</td>
      <td>Eloquens of lawyers</td>
    </tr>
    <tr>
      <td>Byldynge of Rookys</td>
      <td>Dampnynge of Juryerſſe</td>
    </tr>
    <tr>
      <td>murmuracyon of Starys</td>
      <td>Execucyon of Offycers</td>
    </tr>
    <tr>
      <td>Chatterynge of Choughys</td>
      <td>Dylygens of maſſyngers</td>
    </tr>
    <tr>
      <td>Dyſſymylacyon of alle ſmalle Bryddys</td>
      <td>Faythe of marchauntyſſe</td>
    </tr>
    <tr>
      <td>Rowte of knyghtys</td>
      <td>Obedyens of Servandys</td>
    </tr>
    <tr>
      <td>Rowte of Gentylle men</td>
      <td>Prevyſyon of ſtywardyſſe</td>
    </tr>
    <tr>
      <td>Rowte of wylde wolfys</td>
      <td>Sete of huſcheryſſe</td>
    </tr>
    <tr>
      <td>Pryde of lyons</td>
      <td>kerffe of Panterſſe</td>
    </tr>
    <tr>
      <td>lepe of lybardys</td>
      <td>Draught of Buttelerys</td>
    </tr>
    <tr>
      <td>Slouthe of Beerys</td>
      <td>Temporens of Cokys</td>
    </tr>
    <tr>
      <td>Schrewdenys of Apys</td>
      <td>Savegarde of Porteryſſe</td>
    </tr>
    <tr>
      <td>Syght of Grayys</td>
      <td>Stalke of Foſterſſe</td>
    </tr>
    <tr>
      <td>Nerthe of Foxys</td>
      <td>Blaste of hunterſſe</td>
    </tr>
    <tr>
      <td>Bery of Connys</td>
      <td>Thretynge of Curtyers</td>
    </tr>
    <tr>
      <td>Neſte of Rabettys</td>
      <td>lawghtur of Oſtylerſſe</td>
    </tr>
    <tr>
      <td>labyr of mollys</td>
      <td>Promys of Tapsteryſſe</td>
    </tr>
    <tr>
      <td>Beſynys of Ferettys</td>
      <td>Gloſyng of Taverneryſſe</td>
    </tr>
    <tr>
      <td>leſſe of Grehoundys</td>
      <td>lyynge of Pardynerſſe</td>
    </tr>
  </tbody>
</table>

<p>Here begynnythe the Termys of kervynge of Fowlys ande of Fyſchyſſe ❦</p>

<table class="smaller">
  <tbody>
    <tr>
      <td>A Ryſte<sup>(?)</sup> a Dere ys Br<sup>o</sup>kynne</td>
      <td>Pecocke ys dyſfyguryde</td>
    </tr>
    <tr>
      <td>Brawyn ys leyſchyde</td>
      <td>Corlowe ys unrowtyde<sup>(?)</sup></td>
    </tr>
    <tr>
      <td>Paſtey ys brouderydde</td>
      <td>Bytterne ys untachyde</td>
    </tr>
    <tr>
      <td>Goſſe ys rerryde</td>
      <td>Egrete ys <i>y-</i>kneyde</td>
    </tr>
    <tr>
      <td>Swanne ys lyfte</td>
      <td>Papyr ys lowryde<sup>(?)</sup></td>
    </tr>
    <tr>
      <td>Caponne ys Sawſyde</td>
      <td>Gulle ys <i>y-</i>Brawynde</td>
    </tr>
    <tr>
      <td>Henne ys ſpoylyde</td>
      <td>Feſonde ys <i>y-</i>haylyde</td>
    </tr>
    <tr>
      <td>Chekynne ys ffaſſyde</td>
      <td>Parteryche — Alle thes benne wyngyde<br />Quayle</td>
    </tr>
    <tr>
      <td>Mallerde ys unbraſſydde</td>
      <td>Rayle ys Breſtyde</td>
    </tr>
    <tr>
      <td>Conyng ys unlaſyde</td>
      <td>Plouer ys mynſchyde</td>
    </tr>
    <tr>
      <td>Hayryn ys dysmemberyde</td>
      <td>Woodecocke — Alle thes benne <i>y-</i>ſchrydde<br />Pegonne<sup>(?)</sup></td>
    </tr>
    <tr>
      <td>Crane ys Dyſplayde</td>
      <td>¶ And alle ſmalle Bryddys ben <i>y-</i>ſchrydde</td>
    </tr>
  </tbody>
</table>

<p>Alle the Termys that longgythe unto fyſche ~</p>

<table class="smaller">
  <tbody>
    <tr>
      <td>Samon ys Chynyde</td>
      <td> </td>
    </tr>
    <tr>
      <td>Gounarde Chynyde</td>
      <td>Chevynne ys vynnydde</td>
    </tr>
    <tr>
      <td>lampray ys cordyde</td>
      <td>Barbule ys <i>y-</i>Tuſkydde</td>
    </tr>
    <tr>
      <td>Pyke ſplayde</td>
      <td>Ele ys Trowſyde or ellys <i>y-</i>colpynnyd</td>
    </tr>
    <tr>
      <td>Tenche ſowſyde<br /> Or ellys he may be take yn a jollye<sup>(?)</sup></td>
      <td>Trowght <i>y-</i>colpynnyde<br /> or ellys he ys Chevernyd or ellys ynundate<sup>(?)</sup> ~</td>
    </tr>
    <tr>
      <td>Playſſe ys ſawſyde</td>
      <td>Roche <i>y-</i>Bonyde or rybbyde</td>
    </tr>
    <tr>
      <td>Haddocke ys Sydyde</td>
      <td>Crabbe ys mynyde<sup>(?)</sup></td>
    </tr>
    <tr>
      <td>Breme ys Splayde</td>
      <td>Crawys ys unmaylyde</td>
    </tr>
  </tbody>
</table>

<p>Explicit ❦</p>

<hr />

<p>There follows a poem, “Litylle chyldrynne here may ye lere,” which is transcribed in
F. J. Furnivall’s <a href="https://archive.org/details/b24854967/page/265/mode/2up"><em>Early English Meals and Manners</em></a>
(Early English Text Society #32, 1868). Picking up again at folio 60r:</p>

<blockquote>
  <p>Here endythe the boke of Curteſy that ys fulle neceſſary unto yonge
chyldryn that muſte nedys lerne the maner of curteſy ~</p>

  <p>Explicit; Amen.</p>
</blockquote>

<hr />

<blockquote>
  <p>There was a man that hadde nought,<br />
There come thevys &amp; robbyd hỹ &amp; toke nought,<br />
He ranne owte and cryde nought,<br />
Why ſhulde he crye, he loſte nought,<br />
Here ys a tale of ryght noughte.</p>
</blockquote>

<hr />

<blockquote>
  <p>Cronica ſi pences ſi certant oxonienſes<br />
Poſt paucos menſes pugnabũt &amp; angliginences</p>
</blockquote>

<p>A <a href="https://en.wikipedia.org/wiki/Leonine_verse">“Leonine”</a> witticism also
attested <a href="https://archive.org/details/dictionarylatin00rilegoog/page/51">elsewhere</a>:
“The chronicles tell us that when Oxford men contend / in months all England wars from end to end.”</p>

<hr />

<p>There follows (fols. 60v–61v) a 2.5-page treatise on prophesying by the first windy night
after Christmas: <i>Si ventus fuerit in prima nocte Natalis dm̃ in illo anno
Reges et Principes Pontifices et ceteri duutes<sup>(?)</sup> vel potentes
per univerſum orbem ꝑibunt. Secunda die vel in nocte Natalis dm̃ ventus fuerit unia
per univerſum orbem frumenta et grana deficient…</i> For an 11th-century variation
on this text, see
<a href="https://gallica.bnf.fr/ark:/12148/btv1b10548488f/f389.item">BnF NAL 873, fol. 200r</a> ff.</p>

<hr />

<p>There follows (fols. 61v–62v) some Latin commentary on the twelve months.</p>

<hr />

<blockquote>
  <p>Here benne alle the namys of the byſcheppe richys of alle yngelonde and thoo
that longythe unto Yngelonde ~</p>

  <p>Canntyrbury, Yorke, Exceter, Bathe, Salyſbury, Wyncheſtye, Worceter, Rocheſter,
Cheſter, Lyncolle, Lonndon, Chicheſter, Ely, Syndavy,<sup>(?)</sup>
Synt Aſfe, Bangor, Herforde, Cardeaffe, Northewiche, Carlylle, Dyrham
[Later addition in a blacker ink: Peterborow]
— Non plura<sup>(?)</sup><br />
Sm<sup>ii</sup> anñ XXIV<sup>(?)</sup></p>

  <p>Deo gracias &amp;<sup>(?)</sup> Hylle ~</p>
</blockquote>

<p>(“Syndavy” might be St David’s, in Wales; I’m surer that “Synt Aſfe” is St Asaph’s.
I can’t hazard a guess on the Latin abbreviations, except to note that if
“annum 24” is a regnal year, the 24th year of Henry VI’s reign would have been 1448.)</p>

<hr />

<p>(Fols. 63r ff.)</p>

<p>For a yong gentylle man to knowe the termys of venery and the crafte whyche
the iiij beſtys of venery ~
The herte, the hare, the wolfe, and the wylde Bore — Of venery there bynne nomore.</p>

<p>The Beſtys of the Chaſſe as hyt apperythe ~
The Bucke, the Doo, the Roobucke, the Roodoo, the Bere,<sup>(?)</sup> and the rayne dere.</p>

<p>The Elke that ys to ſay a herte of II wyntyr
age. ¶ The ſpycurde that ys to ſay a herte of III wyntyr of age.</p>

<p>The Fulmer,<sup>(?)</sup> the Fechewe,<sup>(?)</sup> the Catte of the mountayne,
the Gray, the Fox, the Weſylle,
the martoun, the ſquyrelle, the Ottyr, the Polkatte — Alle thes benne of the ſtynkyng
Fute or ſtynkying Chaſſe, for the wylle bothe clym and crepe as for the ſubſtance of hem ❦</p>

<p>There ben Grehoundys for game and many othyr dyvers houndys
ſum<sup>(?)</sup> honeſte &amp; ſum profytabylle as hit ſhalle folowe here in wrytynge ❦</p>

<p>Fyrste a Grehounde, a Baſtarde grehounde, a mongrelle, a maſtowe,<sup>(?)</sup>
aloundys, lymoire — Alle thes ben take in to the leſſe.
¶ Spaynellys, Rangys, Kenellys, Trerors — Alle thes wylle range for to rayſſe uppe the game.
¶ Bocherhoundys, Dunghylle Currys, and ſmalle Popys for ladys Chambers.</p>

<p>Aloundys ben cuſte, lymors drawyn, a Blode hounde or a dogge for the bowe drawythe,
kenettys rennyn, ſpaynellys retryvyn. The Terer gothe undyr the gounde for to feſtyn
the Fox or the Graye ❦</p>

<p>A hunt caſtythe of a copylle of Alundys unto an herde of hertys. Then he browythe comfortỹg
hys houndys. ¶ The herte takythe the water then
the herte ſevſythe<sup>(?)</sup> <i>[perhaps <i>fuite</i>? cf. Hare’s <i>The Language of Field Sports</i>
<a href="https://archive.org/details/bwb_KQ-367-113/page/16">p16</a>]</i>.
Whenne the he ſwỹmythe downe
thanne he fletythe. ¶ Whenne that he ſwỹmythe up
on the water thenne he brekythe, or brethythe. ¶ When
that he ſwỹmythe ovyr thenne he croſſythe. ¶ Whenne
he retornythe thenne he croſſythe.<sup>(?)</sup> ¶ Whenne that
he takythe dry londe thenne he fleythe. ❦</p>

<table class="smaller">
  <tbody>
    <tr>
      <td>A herte at nyghte ben herborowde</td>
      <td>A hare ys Formyde</td>
    </tr>
    <tr>
      <td>A Bucke ys loggyde</td>
      <td>A Conyng ſyttythe</td>
    </tr>
    <tr>
      <td>A Roobucke ys Beddyde</td>
      <td>A Parterygge lythe</td>
    </tr>
    <tr>
      <td>A yeman ys Beddyde</td>
      <td>A Feſaunt ſtalkythe</td>
    </tr>
  </tbody>
</table>

<p>Explicit.</p>

<hr />

<p>The namys of hawkys and to what maner of
Perſonys that they longe unto every man aftyr
hys owne degre and ordyr ❦</p>

<p>There longyn unto an Emꝑour thre maner of hawkys ~ That ys to ſay:
an Egylle, a <a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED50761">vature</a>,
a <a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED27263.5">melounde</a>.</p>

<p>And the ſympylyſte of thes wylle ſlee an hynde
Calfe by hym ſelfe, or a doys Fawyn, or a
Roo, or a crane or a Buſtarde other wyſe namyde
a derefoule. Or a ſtorke or a Fox.</p>

<p>¶ And thes hawkys benne not namyd or callyd
unto the lewre; the cauſe ys for they ben ovyr hevy &amp;
ponderos for any man to bere.
¶ But they ben made unto the <a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED33005">Perke portatyf</a>
and ther by they benne governyde.</p>

<p>¶ Ther ben hawkys of the Towre ❦</p>

<p>A Gerfaukyn, a Terſelle, a Grfaukyn — for a kynge;
a Faukyn Gentylle and a Taſſelle gentylle — For a Prynce;
a Faukyn of the Rooke — For a Duke;
a Faukyn Peragryne — for an Erle;
a Baſtarde — for every lorde;
a <a href="https://en.wikipedia.org/wiki/Saker_falcon">Saker</a> and a ſakerette — for a knyght;
a <a href="https://en.wikipedia.org/wiki/Lanner_falcon">laner</a> or a lanerette — for a ſquyer;
a <a href="https://en.wikipedia.org/wiki/Merlin_(bird)">Merlyon</a> — for a lady;
a <a href="https://en.wikipedia.org/wiki/Eurasian_hobby">Hobby</a> — for a yong ſquyer.
Alle thes ben hawkys of the Towre ~ And alle thes fleyn fro the lewre.</p>

<p>¶ The Goſhawke ys for a yeman;
a ſperhawk for a preſte;
a muſkette for a clerke.
Ande thes ben made unto the fyſte ande fle w<sup>t</sup>
hyr fre wylle yf they benne in ther proſpyte
for to make game unto hyr mayſter more þen
for any gredynys of mete for they ben noo
Rayvyners. ¶ And ſum of the hawkys
a fore ſayde wylle be made unto the fyſte
welle <i>y-</i>nowe, but they moſte gave grete labyr
to bryng them there to. ❦</p>

<p>Explicit.</p>

<hr />

<blockquote>
  <p>Gret huntyng by ryvers and wode<br />
Makythe a man ys here to growe thorowe hys hoode.</p>
</blockquote>

<hr />

<p>There follows (fols. 65r ff.) “a nobylle tretys of medyſyns for mannys body.”</p>]]></content><author><name></name></author><category term="old-shit" /><category term="transcription" /><category term="word-ways" /><summary type="html"><![CDATA[Previously on this blog: “The Book of St Albans (1486)” (2026-05-22), in which I made a table of terms of venery, a.k.a. company terms, e.g. “an exaltation of larks,” as in the eponymous book by James Lipton. I mentioned that the Book of St Albans actually has “an exaltyng of larkis,” and that it’s only in Egerton MS 1995 (circa 1450), according to Lipton, that we find “an exaltacyon of larkys” proper. But I couldn’t find any digitized copy of Egerton MS 1995 to verify that claim.]]></summary></entry><entry><title type="html">Some recent discoveries</title><link href="https://quuxplusone.github.io/blog/2026/07/01/blog-roundup/" rel="alternate" type="text/html" title="Some recent discoveries" /><published>2026-07-01T00:01:00+00:00</published><updated>2026-07-01T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/07/01/blog-roundup</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/07/01/blog-roundup/"><![CDATA[<p><b>First images of PHerc. 1667.</b>
When Vesuvius buried Herculaneum, it turned many papyrus scrolls in the <a href="https://en.wikipedia.org/wiki/Villa_of_the_Papyri">Villa dei Papiri</a>
to burnt hunks of carbon without destroying their physical structure. Since
<a href="https://web.archive.org/web/20150121160151/http://news.nationalgeographic.com/news/2015/01/150120-roman-scrolls-xray-archeology-science/">the 2010s</a>
(or earlier?), people have tried to non-invasively image what remains of the scrolls.
In June 2026, the latest “Vesuvius Challenge” prize was
awarded to a team who successfully imaged the first “complete” scroll.
The team’s report (<a href="https://scrollprize.org/pdf/main.pdf">“Complete virtual unwrapping and reading of a rolled Herculaneum papyrus”</a>,
Angelotti et al., 2026) points out that
the scroll is even less “complete” than it used to be: invasive efforts in the late 20th century
had already reduced it from about 14 grams of carbonized gunk to about 6 grams. The group’s full
transcription consists of only 300 to 400 complete words. They identify PHerc. 1667
as some sort of philosophical treatise — unsurprising, as many of the scrolls that could
already be deciphered turned out to be works of <a href="https://en.wikipedia.org/wiki/Philodemus">Philodemus</a>.
Contrary to some media reports, the title of PHerc. 1667’s work is unknown;
but a separate finding reported in the same paper identifies PHerc. 139 as
book 8 of Philodemus’s <em>On gods</em> (<em>περὶ θεῶν</em>, book <em>Η</em>).</p>

<hr />

<p><b>Three lost songs from <i>Iolanthe</i>.</b>
In April 2026, Marc Shepherd was looking at a manuscript full score of Gilbert &amp; Sullivan’s
<em>Iolanthe</em> in the British Library (<a href="https://searcharchives.bl.uk/catalog/040-003392199">MS Mus. 1824/1/7/4</a>)
and discovered at the back of the manuscript the orchestra parts for these three songs,
all cut from <em>Iolanthe</em> before the end of its run and up to now believed about as lost
as <em>Thespis</em>:</p>

<ul>
  <li>“On you they’d set a coronet” (Phyllis, Tolloller, Mountararat, Lord Chancellor)</li>
  <li>“My love for him is dead” (Phyllis)</li>
  <li>“De Belville was regarded as the Crichton of his age” (Mountararat)</li>
</ul>

<p>More information can be found in <a href="https://www.dropbox.com/scl/fi/6q23rbvwzr2w08kww476q/Iolanthe-Lost-Songs-Full-Score.pdf?rlkey=usk85rf7sv8yhcsdjx791mjjl">Shepherd’s transcription of the full score</a>;
in his blog post <a href="https://marc154391.substack.com/p/three-deleted-songs-from-iolanthe">“Three Deleted Songs from Iolanthe”</a> (May 2026);
and in a two-hour <a href="https://www.youtube.com/watch?v=wwVXI1lfs_Q">video interview</a> with William Remmers, the
music director of New York’s Utopia Opera. Utopia Opera has already put
<a href="https://www.youtube.com/watch?v=OztnnHCztSU">recordings of all three songs</a> on YouTube.</p>

<p>Shepherd remarks that Phyllis is a soprano without an aria; the deleted song would naturally
have been her big number. But Act II already has its share of wishy-washy love songs —
“You plead in vain,” “Oh foolish fay” — and “My love for him” must have seemed too samey.
Mountararat, meanwhile, is coming straight from his three-verse comic song
“When Britain really ruled the waves”; it doesn’t make much sense to
give him a <em>second</em> three-verse comic song in the same act! Still, Gilbert liked
“De Belville” <em>per se</em> so much that he republished its words in
<a href="https://archive.org/details/songsofsavoyard00gilbiala/songsofsavoyard00gilbiala/page/57"><em>Songs of a Savoyard</em></a> (1890);
it was only Sullivan’s melody that was lost.</p>

<p>Shepherd is also the coauthor of <a href="https://www.lulu.com/shop/marc-shepherd-and-michael-walters-and-w-s-gilbert/the-variorum-gilbert-sullivan-volume-i/paperback/product-17qvev44.html"><em>The Variorum Gilbert &amp; Sullivan, Volume 1</em></a>
(2015) and has edited the full scores of many of the operettas. The most interesting parts of
the Utopia interview, for me, were in the first 15 minutes where Shepherd talks about his
ongoing projects (including volumes 2–5 of the <em>Variorum</em>); and circa an hour in,
where they discuss the importance of a well-edited score and the crazy things one does when
one is lacking. The former reminds me that I have plenty of unfinished projects of my own.
For example, after I wrote <a href="/blog/2023/01/09/in-search-of-adventure-iii/">“In search of <em>Adventure ]I[</em>”</a> (2023-01-09)
I did actually receive a playable version, which I haven’t gotten around to blogging about yet;
nor have I yet written a post about my online collection of <a href="https://quuxplusone.github.io/Wikisource/Sousa/">John Philip Sousa operettas</a>.
The latter reminded me of what George Bernard Shaw said in the third edition
of <a href="https://archive.org/details/perfectwagnerite0000bern_y5w0/page/107"><em>The Perfect Wagnerite</em></a>:</p>

<blockquote>
  <p>It is possible to learn more of the world by producing a single opera,
or even conducting a single orchestral rehearsal, than by ten years
reading in the library of the British Museum.</p>
</blockquote>

<hr />

<p><b>Yet another proposed decipherment of Linear A.</b>
Via <a href="https://news.ycombinator.com/item?id=48600107">Hacker News</a>: “Amateur linguist”
Tom di Mino proposes that the Linear A script of Minoan Crete encodes a spoken language
from the Semitic family, and claims to have a list of phonetic values that
make sense of at least one inscription. He announced the news via
<a href="https://www.linkedin.com/feed/update/urn:li:activity:7471395019157835776/">LinkedIn</a>
and via <a href="https://aiclambake.com/clamtakes/linear-a/">Stephen Kosloff’s AI-themed blog</a>,
which are weird venues: weird enough to attract attention from hackers with
<a href="https://web.archive.org/web/20070714204136/http://www.michaelcrichton.net/speech-whyspeculate.html">Gell-Mann amnesia</a>,
for sure.</p>

<p>I hadn’t yet heard this news when I posted <a href="/blog/2026/06/12/syllabaries/">“Katakana and Cypriot”</a> (2026-06-12);
that was just serendipity. But on that note I observe that you can find some autodidacts
(and even allodidacts) who unironically claim that Linear A encodes spoken <em>Japanese;</em> notably
<a href="https://konosos.net/2014/12/09/the-phonetic-method-in-linear-a-decipherment/">Gretchen E. Leonhardt</a>
and <a href="https://independent.academia.edu/HiroKuroda">Mizuhiro Kuroda</a>. Needless to say,
it does not.</p>

<hr />

<p><b>Hat sighting in the wild.</b> Last week I visited ArtsWestchester in White Plains, New York,
which is housed in a former bank and occasionally uses its armored vault for art installations.
This month it’s Rana Amirtahmasebi’s “Continuum: Terra,” in which the artist covers various things
(walls, floors, dishes) with the <a href="https://en.wikipedia.org/wiki/Einstein_problem">aperiodic monotile</a>
known as the “hat.” The hat itself is a recent discovery — it was first discovered in 2022 and announced
publicly in March 2023.</p>

<p>ArtsWestchester’s <a href="https://artswestchester.org/gallery-exhibit/the-janet-langsam-vault-project-continuum-terra-by-rana-amirtahmasebi/">official gallery page</a>
inexplicably displays an AI-generated image of some bullshit, rather than Amirtahmasebi’s actual work.
What, does nobody at ArtsWestchester own a camera?
Top: ArtsWestchester’s AI slop. Middle and bottom: The real-life vault, with hat pattern.</p>

<table>
  <tbody>
    <tr>
      <td><img src="/blog/images/2026-07-01-ai-slop.jpg" alt="" width="640" /></td>
    </tr>
    <tr>
      <td><img src="/blog/images/2026-07-01-amirtahmasebi1.jpg" alt="" width="640" /></td>
    </tr>
    <tr>
      <td><img src="/blog/images/2026-07-01-amirtahmasebi2.jpg" alt="" width="640" /></td>
    </tr>
  </tbody>
</table>

<p>Now, the hat will tile the plane, but you’ll have trouble tiling a curved surface (such as
Amirtahmasebi’s lumpy pottery). Her solution was in some cases to deform or truncate the hat, and in
other cases to just give up and stop tiling. It wasn’t mathematically satisfying at all. But I liked
seeing the hat in the wild, anyway.</p>

<hr />

<p>See also:</p>

<ul>
  <li><a href="/blog/2026/05/08/two-minute-iolanthe/">“Two-Minute <em>Iolanthe</em>”</a> (2026-05-08)</li>
  <li><a href="/blog/2023/03/30/hat-parquet/">“Escheresque parquet deformations of an aperiodic monotile”</a> (2023-03-30)</li>
</ul>]]></content><author><name></name></author><category term="ai" /><category term="blog-roundup" /><category term="gilbert-and-sullivan" /><category term="linguistics" /><category term="litclub" /><category term="math" /><category term="theater" /><summary type="html"><![CDATA[First images of PHerc. 1667. When Vesuvius buried Herculaneum, it turned many papyrus scrolls in the Villa dei Papiri to burnt hunks of carbon without destroying their physical structure. Since the 2010s (or earlier?), people have tried to non-invasively image what remains of the scrolls. In June 2026, the latest “Vesuvius Challenge” prize was awarded to a team who successfully imaged the first “complete” scroll. The team’s report (“Complete virtual unwrapping and reading of a rolled Herculaneum papyrus”, Angelotti et al., 2026) points out that the scroll is even less “complete” than it used to be: invasive efforts in the late 20th century had already reduced it from about 14 grams of carbonized gunk to about 6 grams. The group’s full transcription consists of only 300 to 400 complete words. They identify PHerc. 1667 as some sort of philosophical treatise — unsurprising, as many of the scrolls that could already be deciphered turned out to be works of Philodemus. Contrary to some media reports, the title of PHerc. 1667’s work is unknown; but a separate finding reported in the same paper identifies PHerc. 139 as book 8 of Philodemus’s On gods (περὶ θεῶν, book Η).]]></summary></entry><entry><title type="html">Katakana and Cypriot</title><link href="https://quuxplusone.github.io/blog/2026/06/12/syllabaries/" rel="alternate" type="text/html" title="Katakana and Cypriot" /><published>2026-06-12T00:01:00+00:00</published><updated>2026-06-12T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/06/12/syllabaries</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/06/12/syllabaries/"><![CDATA[<p>From Louis Godart’s <em>The Phaistos Disc: The Enigma of an Aegean Script</em> (1994,
tr. Alexandra Doumas):</p>

<blockquote>
  <p>Whoever studies the history of writing, ancient or modern, should be mindful of
one basic methodological principle: a comparison between the signs encountered
in different scripts should always be treated with skepticism and subjected
to severe criticism. There are plenty of examples of signs that are graphically
the same, and indeed have the same phonetic value, in scripts that have
absolutely nothing in common. A case in point are the nine signs in the classical
Cypriot syllabic script, in use on Cyprus until the fourth century BC, and
modern Japanese. The signs YE [<em>sic</em>], VE [<em>sic</em>], RO, SE, TO, KO, RU, ME, and PE are written
in exactly the same way in both, without anyone ever even imagining an affinity
between the script of ancient Cyprus and the <em>kana</em> script of Japan.</p>
</blockquote>

<p>These days both <a href="https://en.wikipedia.org/wiki/Katakana_(Unicode_block)">katakana</a>
and the <a href="https://en.wikipedia.org/wiki/Cypriot_syllabary">Cypriot syllabary</a>
are encoded in Unicode, so it’s convenient to present the following table of glyphs
that (according to their Unicode character names) represent the “same” phonetic values:</p>

<table>
  <thead>
    <tr>
      <th>Cypriot</th>
      <th>Kana</th>
      <th>Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>𐠀</td>
      <td>ア</td>
      <td>A</td>
    </tr>
    <tr>
      <td>𐠊</td>
      <td>カ</td>
      <td>KA</td>
    </tr>
    <tr>
      <td>𐠔</td>
      <td>マ</td>
      <td>MA</td>
    </tr>
    <tr>
      <td>𐠙</td>
      <td>ナ</td>
      <td>NA</td>
    </tr>
    <tr>
      <td>𐠞</td>
      <td>パ</td>
      <td>PA</td>
    </tr>
    <tr>
      <td>𐠣</td>
      <td>ラ</td>
      <td>RA</td>
    </tr>
    <tr>
      <td>𐠨</td>
      <td>サ</td>
      <td>SA</td>
    </tr>
    <tr>
      <td>𐠭</td>
      <td>タ</td>
      <td>TA</td>
    </tr>
    <tr>
      <td>𐠲</td>
      <td>ワ</td>
      <td>WA</td>
    </tr>
    <tr>
      <td>𐠼</td>
      <td>ザ</td>
      <td>ZA</td>
    </tr>
    <tr>
      <td>𐠁</td>
      <td>エ</td>
      <td>E</td>
    </tr>
    <tr>
      <td>𐠋</td>
      <td>ケ</td>
      <td>KE</td>
    </tr>
    <tr>
      <td>𐠕</td>
      <td>メ</td>
      <td><b>ME</b></td>
    </tr>
    <tr>
      <td>𐠚</td>
      <td>ネ</td>
      <td>NE</td>
    </tr>
    <tr>
      <td>𐠟</td>
      <td>ペ</td>
      <td><b>PE</b> (cf. katakana ヘ, “HE”)</td>
    </tr>
    <tr>
      <td>𐠤</td>
      <td>レ</td>
      <td>RE</td>
    </tr>
    <tr>
      <td>𐠩</td>
      <td>セ</td>
      <td><b>SE</b></td>
    </tr>
    <tr>
      <td>𐠮</td>
      <td>テ</td>
      <td>TE</td>
    </tr>
    <tr>
      <td>𐠳</td>
      <td>ヱ</td>
      <td><b>WE</b> (cf. katakana エ, “E”)</td>
    </tr>
    <tr>
      <td>𐠂</td>
      <td>イ</td>
      <td>I</td>
    </tr>
    <tr>
      <td>𐠌</td>
      <td>キ</td>
      <td>KI</td>
    </tr>
    <tr>
      <td>𐠖</td>
      <td>ミ</td>
      <td>MI</td>
    </tr>
    <tr>
      <td>𐠛</td>
      <td>ニ</td>
      <td>NI</td>
    </tr>
    <tr>
      <td>𐠠</td>
      <td>ピ</td>
      <td>PI</td>
    </tr>
    <tr>
      <td>𐠥</td>
      <td>リ</td>
      <td>RI</td>
    </tr>
    <tr>
      <td>𐠪</td>
      <td>シ</td>
      <td>SI</td>
    </tr>
    <tr>
      <td>𐠯</td>
      <td>チ</td>
      <td>TI</td>
    </tr>
    <tr>
      <td>𐠴</td>
      <td>ヰ</td>
      <td>WI</td>
    </tr>
    <tr>
      <td>𐠃</td>
      <td>オ</td>
      <td>O</td>
    </tr>
    <tr>
      <td>𐠍</td>
      <td>コ</td>
      <td><b>KO</b></td>
    </tr>
    <tr>
      <td>𐠗</td>
      <td>モ</td>
      <td>MO</td>
    </tr>
    <tr>
      <td>𐠜</td>
      <td>ノ</td>
      <td>NO</td>
    </tr>
    <tr>
      <td>𐠡</td>
      <td>ポ</td>
      <td>PO</td>
    </tr>
    <tr>
      <td>𐠦</td>
      <td>ロ</td>
      <td><b>RO</b></td>
    </tr>
    <tr>
      <td>𐠫</td>
      <td>ソ</td>
      <td>SO</td>
    </tr>
    <tr>
      <td>𐠰</td>
      <td>ト</td>
      <td><b>TO</b></td>
    </tr>
    <tr>
      <td>𐠵</td>
      <td>ヲ</td>
      <td>WO</td>
    </tr>
    <tr>
      <td>𐠿</td>
      <td>ゾ</td>
      <td>ZO</td>
    </tr>
    <tr>
      <td>𐠄</td>
      <td>ウ</td>
      <td>U</td>
    </tr>
    <tr>
      <td>𐠎</td>
      <td>ク</td>
      <td>KU</td>
    </tr>
    <tr>
      <td>𐠘</td>
      <td>ム</td>
      <td>MU</td>
    </tr>
    <tr>
      <td>𐠝</td>
      <td>ヌ</td>
      <td>NU</td>
    </tr>
    <tr>
      <td>𐠢</td>
      <td>プ</td>
      <td>PU</td>
    </tr>
    <tr>
      <td>𐠧</td>
      <td>ル</td>
      <td><b>RU</b></td>
    </tr>
    <tr>
      <td>𐠬</td>
      <td>ス</td>
      <td>SU</td>
    </tr>
    <tr>
      <td>𐠱</td>
      <td>ツ</td>
      <td>TU</td>
    </tr>
  </tbody>
</table>

<p>See also a nice diagram of a few of these on <a href="https://air.unimi.it/retrieve/dfa8b990-b058-748b-e053-3a05fe0a3a96/phd_unimi_R08526.pdf">page 11</a>
of Francesco Soldani’s doctoral thesis “Interconnessione grafica tra i vari sillabari egei e loro leggibilità”
(University of Milan, 2013).</p>]]></content><author><name></name></author><category term="linguistics" /><category term="typography" /><summary type="html"><![CDATA[From Louis Godart’s The Phaistos Disc: The Enigma of an Aegean Script (1994, tr. Alexandra Doumas):]]></summary></entry><entry><title type="html">C++26 Reflection gives us universal template parameters</title><link href="https://quuxplusone.github.io/blog/2026/06/07/meta-to/" rel="alternate" type="text/html" title="C++26 Reflection gives us universal template parameters" /><published>2026-06-07T00:01:00+00:00</published><updated>2026-06-07T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/06/07/meta-to</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/06/07/meta-to/"><![CDATA[<p>Keenan Horrigan on the std-proposals mailing list <a href="https://lists.isocpp.org/std-proposals/2026/06/18544.php">pointed out</a>
an interesting consequence of C++26 Reflection: it seems to give us “universal template parameters”
almost for free.</p>

<p>The STL sometimes tries to pretend we have “universal template parameters” by overloading templates
with the same name. For example, we have both <code class="language-plaintext highlighter-rouge">std::get&lt;T&gt;(tp)</code> taking a type and <code class="language-plaintext highlighter-rouge">std::get&lt;I&gt;(tp)</code>
taking an integer; but these are just two completely different signatures of <code class="language-plaintext highlighter-rouge">std::get</code> in the same overload
set. Likewise in C++23 you can write either <code class="language-plaintext highlighter-rouge">rg | ranges::to&lt;std::vector&lt;int&gt;&gt;()</code> (where the argument to
<code class="language-plaintext highlighter-rouge">to</code> is a type) or <code class="language-plaintext highlighter-rouge">rg | ranges::to&lt;std::vector&gt;()</code> (where the argument is a class template).
Again this is accomplished with an overload set — roughly like this (modulo I’ve totally mangled
the actual job of <code class="language-plaintext highlighter-rouge">ranges::to</code>, which is generally <em>not</em> to forward its arguments to <code class="language-plaintext highlighter-rouge">To</code>’s constructor):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template&lt;class To, class... Args&gt;  // #1
auto rangish_to(Args&amp;&amp;... args) {
  return To(std::forward&lt;Args&gt;(args)...);
}
template&lt;template&lt;class...&gt; class To, class... Args&gt;  // #2
auto rangish_to(Args&amp;&amp;... args) {
  return To(std::forward&lt;Args&gt;(args)...);
}

int *a, *b;
auto x = rangish_to&lt;std::vector&lt;int&gt;&gt;(a, b);      // OK, #1
auto y = rangish_to&lt;std::vector&gt;(a, b);           // OK, #2
</code></pre></div></div>

<p>But even this overload set won’t accept a caller like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>auto z = rangish_to&lt;std::ranges::subrange&gt;(a, b); // error
</code></pre></div></div>

<p>because <code class="language-plaintext highlighter-rouge">std::ranges::subrange</code> as a template argument matches neither <code class="language-plaintext highlighter-rouge">class To</code> nor
<code class="language-plaintext highlighter-rouge">template&lt;class...&gt; class To</code>. It’s actually a class template of two type parameters and a constant!
(<a href="https://en.cppreference.com/cpp/ranges/subrange">cppreference.</a>)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enum class subrange_kind : bool {
  unsized,
  sized,
};
template&lt;
  input_or_output_iterator I,
  sentinel_for&lt;I&gt; S = I,
  subrange_kind K = sized_sentinel_for&lt;S, I&gt; ? sized : unsized&gt;
class subrange { ~~~~ };
</code></pre></div></div>

<p>We could accept <code class="language-plaintext highlighter-rouge">subrange</code> ad-hoc via a third overload:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template&lt;template&lt;class,class,auto&gt; class To, class... Args&gt;  // #3
auto rangish_to(Args&amp;&amp;... args) {
  return To(std::forward&lt;Args&gt;(args)...);
}
</code></pre></div></div>

<p>but in general there’s no way to write out the set of <em>all possible</em> kinds of
class templates, so we can’t make our <code class="language-plaintext highlighter-rouge">rangish_to</code> accept all of them.</p>

<blockquote>
  <p>You might point out that the real <code class="language-plaintext highlighter-rouge">ranges::to</code> wouldn’t accept <code class="language-plaintext highlighter-rouge">subrange</code> anyway, because the real
<code class="language-plaintext highlighter-rouge">ranges::to</code> accepts only containers like <code class="language-plaintext highlighter-rouge">vector</code>, not views like <code class="language-plaintext highlighter-rouge">subrange</code> or <code class="language-plaintext highlighter-rouge">span</code>. However,
this deficiency is likely to be <a href="/blog/2019/08/02/the-tough-guide-to-cpp-acronyms/#dr">DR’ed</a>
in the near future thanks to Hewill Kang’s well-received
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3544r0.html">P3544 “<code class="language-plaintext highlighter-rouge">ranges::to&lt;view&gt;</code>.”</a></p>
</blockquote>

<p>C++26 Reflection to the rescue! C++26 Reflection is “untyped”: it uses
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2996r13.html#why-a-single-opaque-reflection-type">a single type</a>
<code class="language-plaintext highlighter-rouge">std::meta::info</code> to represent the reflections of every kind of thing
in the language. Therefore a template parameter of type <code class="language-plaintext highlighter-rouge">meta::info</code> alone can represent
<code class="language-plaintext highlighter-rouge">std::vector</code>, <code class="language-plaintext highlighter-rouge">std::ranges::subrange</code>, <code class="language-plaintext highlighter-rouge">std::array</code>, or anything else (<code class="language-plaintext highlighter-rouge">std::vector&lt;int&gt;</code>,
<code class="language-plaintext highlighter-rouge">size_t</code>, <code class="language-plaintext highlighter-rouge">42</code>, <code class="language-plaintext highlighter-rouge">std::ignore</code>…) and so we can write a single function template like this
(<a href="https://godbolt.org/z/czYzKEczT">Godbolt</a>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template&lt;std::meta::info To, class... Args&gt;
auto meta_to(Args&amp;&amp;... args) {
  return typename [:To:](std::forward&lt;Args&gt;(args)...);
}

auto x = meta_to&lt;^^std::vector&lt;int&gt;&gt;(a, b);      // OK
auto y = meta_to&lt;^^std::vector&gt;(a, b);           // OK
auto z = meta_to&lt;^^std::ranges::subrange&gt;(a, b); // OK!
</code></pre></div></div>

<p>For the cost of two characters <code class="language-plaintext highlighter-rouge">^^</code> (and a really cryptic error message if you forget
the <code class="language-plaintext highlighter-rouge">typename</code> keyword), C++26 seems to have given us universal template parameters!</p>

<p>(Does this mean <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2989r2.pdf">P2989 “Universal template parameters”</a>
is obsolete? IMHO, yes. But I can see how one might debate it: those two <code class="language-plaintext highlighter-rouge">^^</code> characters
<em>are</em> kind of ugly.)</p>]]></content><author><name></name></author><category term="class-template-argument-deduction" /><category term="paradigm-shift" /><category term="ranges" /><category term="reflection" /><category term="templates" /><summary type="html"><![CDATA[Keenan Horrigan on the std-proposals mailing list pointed out an interesting consequence of C++26 Reflection: it seems to give us “universal template parameters” almost for free.]]></summary></entry><entry><title type="html">Branchless sorting of trivially relocatable types</title><link href="https://quuxplusone.github.io/blog/2026/06/05/branchless-sorting/" rel="alternate" type="text/html" title="Branchless sorting of trivially relocatable types" /><published>2026-06-05T00:01:00+00:00</published><updated>2026-06-05T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/06/05/branchless-sorting</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/06/05/branchless-sorting/"><![CDATA[<p>A few days ago Christof Kaser posted a very impressive blog post on
<a href="https://tiki.li/blog/blqsort">“Fast Branchless Quicksort using Sorting-Networks”</a>
(<a href="https://github.com/chkas/blqsort">chkas/blqsort</a>). A “branchless” algorithm is
one designed to exploit modern processors’ conditional-move instructions. So for
example the <code class="language-plaintext highlighter-rouge">blqs::sort2</code> primitive, which looks like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template&lt;class T, class Compare&gt;
void sort2(T&amp; a, T&amp; b, Compare comp) {
  T x = a;
  T y = b;
  bool m = comp(x, y);
  a = m ? x : y;
  b = m ? y : x;
}
</code></pre></div></div>

<p>when instantiated for <code class="language-plaintext highlighter-rouge">int</code> compiles down to a couple of <code class="language-plaintext highlighter-rouge">cmov</code> instructions on x86-64
and a couple of <code class="language-plaintext highlighter-rouge">csel</code> instructions on ARM64. (<a href="https://godbolt.org/z/v34v5oor1">Godbolt.</a>)</p>

<p>But at the higher generic-programming level, count all the copy operations in <code class="language-plaintext highlighter-rouge">sort2</code>!
It copies <code class="language-plaintext highlighter-rouge">a</code> into <code class="language-plaintext highlighter-rouge">x</code>; then copy-assigns <code class="language-plaintext highlighter-rouge">x</code> back into <code class="language-plaintext highlighter-rouge">a</code>. If <code class="language-plaintext highlighter-rouge">T</code> were an expensive-to-copy
type like <code class="language-plaintext highlighter-rouge">std::string</code>, this would be slow code; and if <code class="language-plaintext highlighter-rouge">T</code> were <code class="language-plaintext highlighter-rouge">unique_ptr</code>, it wouldn’t
compile at all. Therefore, <code class="language-plaintext highlighter-rouge">blqsort</code> enables its entire branchless “fast path” only for
types that are trivially copyable and roughly register-sized.</p>

<blockquote>
  <p>As of this writing the gating condition is <code class="language-plaintext highlighter-rouge">std::is_trivially_copyable&lt;T&gt;::value &amp;&amp; sizeof(T) &lt;= 16</code>,
but I’ve pointed out to Christof that his <code class="language-plaintext highlighter-rouge">heap_sort</code> also depends on <code class="language-plaintext highlighter-rouge">T</code> to be trivially
default-constructible. It’s also possible (if pathological) for <code class="language-plaintext highlighter-rouge">T</code> to be trivially copyable
yet not copy-constructible or (more commonly) not copy-assignable. But this blog post isn’t
really about narrowing the gate; we’re going to broaden it instead!</p>
</blockquote>

<p>“Trivially copyable” is what I call a “holistic” trait: it means something about the behavior
of the entire type, rather than about just one special member function or just one kind of expression.
And specifically <em>what</em> it means is that you can do any value-semantic operation — bringing new
copies into existence, poofing them out of existence, overwriting one’s value with another’s,
swapping or permuting or copying — as if the objects were just bags of bits. As long as you
never try to invent a <em>new</em> value out of whole cloth, you can shift copies of your <em>given</em> values
around as much as you like, even into completely new areas of memory, simply by memcpying them.
In the following diagram, each box represents a C++ <em>object</em>, and the color of the box represents
the object’s <em>value</em> (for example 42, or 3.14, or “hello,” or Tuesday).</p>

<p><img src="/blog/images/2026-06-05-holistic-tc.png" alt="" /></p>

<p>We see that in the “After” picture, the green object has become blue. Was that by copy-assignment
from the original blue object? or move-assignment? or copying from the yellow, destroying, and
then copy-constructing from a blue object? With trivial copyability, we needn’t say! Each of those
possible operation-sequences is guaranteed to be <em>physically</em> tantamount to simply memcpying the
“blue” bytes into their final location.</p>

<p>“Trivially relocatable” (the widely deployed P1144 idiom, I mean, not the unusable version that
was briefly merged into the C++26 draft in 2025) is another “holistic” trait. Specifically
what <em>trivially relocatable</em> means is that you can do any <em>affine</em> value-semantic operation —
swapping, permuting, relocating from one place to another — as if the objects were just bags of
bits. As long as you preserve the <em>number of copies of each given value,</em> you can shift that
particular set of values around as much as you like, even into completely new areas of memory,
simply by memcpying them. (But unlike two paragraphs ago, with <em>trivially relocatable</em> you’re
not allowed to turn one value into two, or poof a value completely out of existence: each and
every input value must be represented the same number of times in the final output.)</p>

<p><img src="/blog/images/2026-06-05-holistic-tr.png" alt="" /></p>

<p>As long as whatever highest-level algorithm we’re doing preserves this “affine,” one-to-one
property, every possible operation-sequence is guaranteed to be <em>physically</em> tantamount to
simply memcpying the bytes around.</p>

<blockquote>
  <p>The above images come from a ten-slide presentation on holistic traits I wrote in mid-2024.
See the whole slide deck <a href="/blog/code/2026-06-05-holistic-traits.pdf">here</a>.</p>
</blockquote>

<p>Algorithms that have this “affine” one-to-one property include <code class="language-plaintext highlighter-rouge">swap</code>, <code class="language-plaintext highlighter-rouge">rotate</code>, <code class="language-plaintext highlighter-rouge">partition</code>, and… <code class="language-plaintext highlighter-rouge">sort</code>!
Imagine rewriting <code class="language-plaintext highlighter-rouge">blqs::sort2</code> like this (<a href="https://godbolt.org/z/czfaKWrcc">Godbolt</a>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template&lt;class T, class Compare&gt;
void sort2(T&amp; a, T&amp; b, Compare comp) {
  union U { T t; U() {} ~U() {} };
  U x, y;
  std::relocate_at(&amp;a, &amp;x.t);
  std::relocate_at(&amp;b, &amp;y.t);
  bool m = comp(x.t, y.t);
  std::relocate_at(m ? &amp;x.t : &amp;y.t, &amp;a);
  std::relocate_at(m ? &amp;y.t : &amp;x.t, &amp;b);
}
</code></pre></div></div>

<p>This is conceptually closer to what our <code class="language-plaintext highlighter-rouge">sort2</code> algorithm actually “needs” to do.
It doesn’t really care that it’s making copies of <code class="language-plaintext highlighter-rouge">T</code> objects; conceptually it’s just
bringing the values “closer to hand” (which could be a relocate), comparing its close-up
copies, and then putting the values back “in memory” (which could be a relocate). For
trivially copyable <code class="language-plaintext highlighter-rouge">T</code>, it’s totally fine to replace the first relocate with a copy-construct
and the second relocate with a copy-assign: the end result is guaranteed to be the same,
assuming it compiles at all. The relocation-based version merely extends that guarantee
from “trivially copyable <code class="language-plaintext highlighter-rouge">T</code>” to “trivially relocatable <code class="language-plaintext highlighter-rouge">T</code>.”</p>

<p>But the above code both depends on P1144/P3516 <code class="language-plaintext highlighter-rouge">relocate_at</code> and is super ugly.
Imagine patching every helper in <code class="language-plaintext highlighter-rouge">blqsort.h</code> with this pedantry! We can actually
achieve the same effect much more easily by leaning on the holistic guarantee: We know
that the end result of <code class="language-plaintext highlighter-rouge">sort2</code> — in fact the end result of <code class="language-plaintext highlighter-rouge">blqsort</code> — will be an affine,
one-to-one, permutation of the input values. So we can actually run the whole algorithm
working entirely with object representations! The patch for this is only a few lines long:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  constexpr bool copy_is_cheap =
    std::is_trivially_copyable&lt;T&gt;::value &amp;&amp; sizeof(T) &lt;= 16;

+ constexpr bool relocate_is_cheap =
+   std::is_trivially_relocatable&lt;T&gt;::value &amp;&amp; sizeof(T) &lt;= 16;

  if constexpr (copy_is_cheap) {
    blqsort(first, last - 1, comp);
+ } else if constexpr (relocate_is_cheap) {
+   struct Rep {
+     alignas(T) char data_[sizeof(T)];
+   };
+   blqsort((Rep*)first, (Rep*)(last - 1),
+     [&amp;](const Rep&amp; a, const Rep&amp; b) { return comp(*(const T*)&amp;a, *(const T*)&amp;b); });
  } else {
    block_qsort(first, last - 1, comp);
  }
</code></pre></div></div>

<p>This says, “If we know that <code class="language-plaintext highlighter-rouge">T</code> is trivially relocatable, then let’s just pretend we’re sorting
anonymous blocks of bytes instead. Make sure to treat them as <code class="language-plaintext highlighter-rouge">T</code> objects for the purposes
of <code class="language-plaintext highlighter-rouge">comp</code>, but don’t worry about the value-semantic bookkeeping; I promise it will all come out
correctly in the end.”</p>

<p>Christof’s <code class="language-plaintext highlighter-rouge">blqs::sort</code> uses the branchless fast path, <code class="language-plaintext highlighter-rouge">blqsort</code>, only for trivially copyable
types; types that don’t make it through that gate will use the slow path, <code class="language-plaintext highlighter-rouge">block_qsort</code>, instead.
This patch broadens the gate: now we can use the fast path for all trivially relocatable types,
including for example <code class="language-plaintext highlighter-rouge">unique_ptr</code> and <code class="language-plaintext highlighter-rouge">shared_ptr</code>. (But not <code class="language-plaintext highlighter-rouge">string</code>, because it fails the
<code class="language-plaintext highlighter-rouge">sizeof</code> check.)</p>

<h2 id="benchmark-results">Benchmark results</h2>

<p>This turns out to be a perfect testbed for the kinds of performance improvements you can get
from P1144-style trivial relocation on something as familiar as sorting a vector of <code class="language-plaintext highlighter-rouge">shared_ptr</code>.
I wrote a benchmark (<a href="/blog/code/2026-06-05-blqs-bench.cpp">backup</a>) comparing the performance
of the high-level <code class="language-plaintext highlighter-rouge">blqs::sort</code> on four different kinds of <code class="language-plaintext highlighter-rouge">T</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struct TC {
  Int *p_;
  void *ctrl_;
  explicit TC() = default;
  explicit TC(Int&amp; i) : p_(&amp;i) {}
  friend auto operator&lt;=&gt;(const TC&amp; a, const TC&amp; b) { return *a.p_ &lt;=&gt; *b.p_; }
};

struct TR {
  std::shared_ptr&lt;Int&gt; p_;
  explicit TR() = default;
  explicit TR(Int&amp; i) : p_(&amp;i, [](Int*){}) {}
  friend auto operator&lt;=&gt;(const TR&amp; a, const TR&amp; b) { return *a.p_ &lt;=&gt; *b.p_; }
};

struct NTC : TC {
  using TC::TC;
  ~NTC() {}
};

struct NTR : TR {
  using TR::TR;
  NTR(NTR&amp;&amp;) = default;
  NTR(const NTR&amp;) = default;
  NTR&amp; operator=(NTR&amp;&amp;) = default;
  NTR&amp; operator=(const NTR&amp;) = default;
  ~NTR() {}
};
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">TR</code> is a Rule-of-Zero type that pays all the same costs as <code class="language-plaintext highlighter-rouge">shared_ptr</code>
for its value-semantic operations — yet it is trivially relocatable. Then <code class="language-plaintext highlighter-rouge">NTC</code> is
exactly the same as <code class="language-plaintext highlighter-rouge">TC</code> except that its no-op destructor makes it not-trivially-anything;
and <code class="language-plaintext highlighter-rouge">NTR</code> is exactly the same as <code class="language-plaintext highlighter-rouge">TR</code> (paying <code class="language-plaintext highlighter-rouge">shared_ptr</code> costs) except that its no-op
destructor makes it not-trivially-anything.</p>

<p>Sorting a vector of 50 million elements with Christof’s (current) implementation of
<code class="language-plaintext highlighter-rouge">blqs::sort</code> out of the box shows <code class="language-plaintext highlighter-rouge">TC</code> taking the fast path and all three of
<code class="language-plaintext highlighter-rouge">TR</code>, <code class="language-plaintext highlighter-rouge">NTC</code>, <code class="language-plaintext highlighter-rouge">NTR</code> taking the slow path, as predicted. Here the “<code class="language-plaintext highlighter-rouge">std::sort</code>” column
refers to libc++’s current implementation.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Type</th>
      <th style="text-align: right"><code class="language-plaintext highlighter-rouge">std::sort</code></th>
      <th style="text-align: right"><code class="language-plaintext highlighter-rouge">blqs::sort</code></th>
      <th style="text-align: right">Savings</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">TC</code></td>
      <td style="text-align: right">5.9s</td>
      <td style="text-align: right">3.5s</td>
      <td style="text-align: right">41%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">TR</code></td>
      <td style="text-align: right">6.5s</td>
      <td style="text-align: right"><b>6.2s</b></td>
      <td style="text-align: right"><b>4%</b></td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">NTC</code></td>
      <td style="text-align: right">5.8s</td>
      <td style="text-align: right">4.3s</td>
      <td style="text-align: right">25%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">NTR</code></td>
      <td style="text-align: right">6.3s</td>
      <td style="text-align: right">6.7s</td>
      <td style="text-align: right">−6%</td>
    </tr>
  </tbody>
</table>

<p>Now we apply the patch above, to enable the fast path whenever <code class="language-plaintext highlighter-rouge">relocate_is_cheap</code>.
The numbers for <code class="language-plaintext highlighter-rouge">TC</code>, <code class="language-plaintext highlighter-rouge">NTC</code>, and <code class="language-plaintext highlighter-rouge">NTR</code> aren’t expected to change; so you can see
roughly how noisy this microbenchmark is.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Type</th>
      <th style="text-align: right"><code class="language-plaintext highlighter-rouge">std::sort</code></th>
      <th style="text-align: right"><code class="language-plaintext highlighter-rouge">blqs::sort</code></th>
      <th style="text-align: right">Savings</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">TC</code></td>
      <td style="text-align: right">5.8s</td>
      <td style="text-align: right">3.4s</td>
      <td style="text-align: right">42%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">TR</code></td>
      <td style="text-align: right">6.5s</td>
      <td style="text-align: right"><b>4.0s</b></td>
      <td style="text-align: right"><b>38%</b></td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">NTC</code></td>
      <td style="text-align: right">5.8s</td>
      <td style="text-align: right">4.4s</td>
      <td style="text-align: right">24%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">NTR</code></td>
      <td style="text-align: right">6.2s</td>
      <td style="text-align: right">6.3s</td>
      <td style="text-align: right">−2%</td>
    </tr>
  </tbody>
</table>

<p>That is, by applying an eight-line patch to use the fast path for trivially relocatable
<code class="language-plaintext highlighter-rouge">shared_ptr</code>, we’ve turned <code class="language-plaintext highlighter-rouge">blqs::sort</code> from a 4% win into a 38% win, right in line
with its speedup for trivially copyable types.</p>

<h2 id="what-gave-us-this-speedup">What gave us this speedup?</h2>

<p>To get this speedup, we used one “dirty trick” and one compiler extension.
Our dirty trick was:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struct Rep {
  alignas(T) char data_[sizeof(T)];
};
blqsort((Rep*)first, (Rep*)(last - 1),
  [&amp;](const Rep&amp; a, const Rep&amp; b) { return comp(*(const T*)&amp;a, *(const T*)&amp;b); });
</code></pre></div></div>

<p>Those casts are <code class="language-plaintext highlighter-rouge">reinterpret_cast</code> in disguise. This is type-punning, and
technically it’s undefined behavior. (It’s certainly not constexpr-friendly.)
We can make it well-defined and constexpr-friendly by using the P1144/P3516
entrypoint <code class="language-plaintext highlighter-rouge">std::relocate_at</code> on <code class="language-plaintext highlighter-rouge">T</code> objects instead of copy-assignment on <code class="language-plaintext highlighter-rouge">Rep</code>
objects; but as we’ve seen, that’s very ugly — and in fact very error-prone.
Changing a copy-assignment-based algorithm to use relocation takes a major
code audit to make sure you balanced out every construction and destruction, never
moved or relocated twice from the same object, never accessed an object outside
its lifetime, etc. Our “dirty trick” foolproofly accomplished the same codegen,
with just a little surgical patch at the top level. If we really needed constexpr-friendliness,
I’d add an <code class="language-plaintext highlighter-rouge">if consteval</code> at the top level sooner than I’d give up this trick.</p>

<p>But of course the thing we <em>must</em> have, in order to apply this optimization,
is a reliable way to detect <code class="language-plaintext highlighter-rouge">is_trivially_relocatable&lt;T&gt;</code>. My code makes it look
easy, because I use a compiler (and standard library) with full P1144 support.
Sadly neither Clang nor GCC is such a compiler.</p>

<p>Mainline Clang actually has two
different builtins in this area — <code class="language-plaintext highlighter-rouge">__is_trivially_relocatable</code> and
<code class="language-plaintext highlighter-rouge">__builtin_is_cpp_trivially_relocatable</code> — but both of them have too many false
positives to use safely in production: the latter by design (it intended to
implement the failed P2786 proposal) and the former merely by neglect. An attempt
was made to fix up the former in <a href="https://github.com/llvm/llvm-project/pull/84621">Clang #84621</a>,
but the maintainers resisted, and the patch was eventually abandoned.
Obviously I’d like to see it revived.</p>]]></content><author><name></name></author><category term="algorithms" /><category term="benchmarks" /><category term="llvm" /><category term="relocatability" /><category term="triviality" /><category term="value-semantics" /><summary type="html"><![CDATA[A few days ago Christof Kaser posted a very impressive blog post on “Fast Branchless Quicksort using Sorting-Networks” (chkas/blqsort). A “branchless” algorithm is one designed to exploit modern processors’ conditional-move instructions. So for example the blqs::sort2 primitive, which looks like this:]]></summary></entry><entry><title type="html">Does bulk memmove speed up `std::remove_if`? (No.)</title><link href="https://quuxplusone.github.io/blog/2026/05/23/chunked-remove/" rel="alternate" type="text/html" title="Does bulk memmove speed up `std::remove_if`? (No.)" /><published>2026-05-23T00:01:00+00:00</published><updated>2026-05-23T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/05/23/chunked-remove</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/05/23/chunked-remove/"><![CDATA[<p>This morning I was reading the umpteenth std-proposals thread proposing some variety of
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0041r0.html"><code class="language-plaintext highlighter-rouge">unstable_remove</code></a>
and it occurred to me that one odd thing about a swap-and-pop-based <code class="language-plaintext highlighter-rouge">unstable_remove</code>
is that it tends to replace large swaths of contiguous removals by <em>reversing</em> the
elements that are kept. For example (<a href="https://godbolt.org/z/f9doebhch">Godbolt</a>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template&lt;class BidirIt, class Pred&gt;
BidirIt unstable_remove_if(BidirIt first, BidirIt last, Pred pred) {
  while (true) {
    first = std::find_if(first, last, pred);
    if (first == last) return first;
    while (true) {
      --last;
      if (first == last) return first;
      if (!pred(*last)) break;
    }
    *first++ = std::move(*last);
  }
}

int main() {
  auto in234 = [](int x) { return 2 &lt;= x &amp;&amp; x &lt;= 4; };
  std::vector&lt;int&gt; v = {1,2,3,4,5,6,7,8,9};
  v.erase(unstable_remove_if(v.begin(), v.end(), in234), v.end());
  // v is {1,9,8,7,5,6}
}
</code></pre></div></div>

<p>It would be more aesthetically pleasing to produce <code class="language-plaintext highlighter-rouge">{1,7,8,9,5,6}</code>: for trivially copyable
elements, this would be a single memmove. In a sense, “reversing the elements” is extra work
that we might save time by avoiding. But to avoid <em>that</em> work, we might have to do <em>even more</em>
work in the form of bookkeeping. I haven’t attempted to benchmark any such change to
<code class="language-plaintext highlighter-rouge">unstable_remove</code>.</p>

<p>But the same aesthetic consideration applies to the ordinary, stable <code class="language-plaintext highlighter-rouge">std::remove_if</code>.
Traditionally it’s a loop over <code class="language-plaintext highlighter-rouge">operator=</code>, like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template &lt;class FwdIt, class Pred&gt;
FwdIt smooth_remove_if(FwdIt first, FwdIt last, Pred pred) {
  FwdIt dfirst = std::find_if(first, last, pred);
  if (dfirst != last) {
    for (first = std::next(dfirst); first != last; ++first) {
      if (!pred(*first)) {
        *dfirst++ = std::move(*first);
      }
    }
  }
  return dfirst;
}
</code></pre></div></div>

<p>But what if we “chunked” the writes to <code class="language-plaintext highlighter-rouge">*dfirst</code>, like this?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template &lt;class FwdIt, class Pred&gt;
FwdIt chunky_remove_if(FwdIt first, FwdIt last, Pred pred) {
  FwdIt dfirst = std::find_if(first, last, pred);
  if (dfirst != last) {
    for (first = std::next(dfirst); first != last; ++first) {
      if (!pred(*first)) {
        FwdIt sfirst = first;
        first = std::find_if(std::next(first), last, pred);
        dfirst = std::move(sfirst, first, dfirst);
        if (first == last) break;
      }
    }
  }
  return dfirst;
}
</code></pre></div></div>

<p>Delegating the work to the <a href="https://en.cppreference.com/cpp/algorithm/move"><code class="language-plaintext highlighter-rouge">std::move</code></a> algorithm
allows the library to use memmove for that work, if the element type happens to be trivially
copyable. The nested loop complicates the generated code (<a href="https://godbolt.org/z/ja48jh4nv">Godbolt</a>),
but is it worth it? Do we actually save CPU cycles?</p>

<p>Well, if the average length of a “run” of survivors is long, then we
might expect the cost of a single large memmove to beat out the cost of <code class="language-plaintext highlighter-rouge">operator=</code>-in-a-loop.
But at the other extreme, if the average length of a run is only 1 element, then memmove won’t
save anything; we’ll be paying all the bookkeeping cost for none of the benefit.</p>

<blockquote>
  <p>By “bookkeeping” I mean not only the extra register and icache pressure of the more complicated
algorithm, but also the overhead of the call to memmove itself, and that memmove will necessarily
start by checking whether it needs to handle forward overlap. (That branch is completely predictable
— it doesn’t — but is still overhead absent from the “smooth” version.)</p>
</blockquote>

<p>I wrote a little benchmark (<a href="/blog/code/2026-05-23-chunked-remove-benchmark.cpp">backup</a>)
to time a call to <code class="language-plaintext highlighter-rouge">std::remove_if</code> on an array of a million ints,
with a bit-masking predicate that removed half of the elements; one in 8;
one in 128; or one in 1024. I contrived this benchmark deliberately to play
to the “chunky” algorithm’s strengths: trivially copyable elements, with large swaths moved
contiguously.</p>

<p>The “smooth” column here is merely to prove that my <code class="language-plaintext highlighter-rouge">smooth_remove_if</code> implementation
is essentially the same as libc++’s default implementation:
my <code class="language-plaintext highlighter-rouge">chunky_remove_if</code> can’t blame its defeat on “library vendor magic.”
Yet it <em>is</em> defeated, and decisively so:</p>

<table class="smaller">
  <thead>
    <tr>
      <th style="text-align: left">Elements removed</th>
      <th style="text-align: right"><code class="language-plaintext highlighter-rouge">std</code></th>
      <th style="text-align: right">smooth</th>
      <th style="text-align: right">chunky</th>
      <th style="text-align: right">Penalty</th>
      <th style="text-align: right">smooth<br />assignments</th>
      <th style="text-align: right">chunky<br />memmoves</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">1 in 2</td>
      <td style="text-align: right">3122 us</td>
      <td style="text-align: right">3157 us</td>
      <td style="text-align: right">3797 us</td>
      <td style="text-align: right">+20%</td>
      <td style="text-align: right">499549</td>
      <td style="text-align: right">249971</td>
    </tr>
    <tr>
      <td style="text-align: left">1 in 8</td>
      <td style="text-align: right">1082 us</td>
      <td style="text-align: right">1105 us</td>
      <td style="text-align: right">1471 us</td>
      <td style="text-align: right">+33%</td>
      <td style="text-align: right">874707</td>
      <td style="text-align: right">109724</td>
    </tr>
    <tr>
      <td style="text-align: left">1 in 128</td>
      <td style="text-align: right">416 us</td>
      <td style="text-align: right">420 us</td>
      <td style="text-align: right">468 us</td>
      <td style="text-align: right">+11%</td>
      <td style="text-align: right">992148</td>
      <td style="text-align: right">7750</td>
    </tr>
    <tr>
      <td style="text-align: left">1 in 1024</td>
      <td style="text-align: right">327 us</td>
      <td style="text-align: right">326 us</td>
      <td style="text-align: right">396 us</td>
      <td style="text-align: right">+21%</td>
      <td style="text-align: right">998482</td>
      <td style="text-align: right">958</td>
    </tr>
  </tbody>
</table>

<p>As expected, <code class="language-plaintext highlighter-rouge">chunky_remove_if</code> loses when the expected length of a memmove is short.
But it also loses when the expected length of a memmove is long! And, counterintuitively,
as we remove <em>fewer</em> elements (and thus execute <em>more</em> individual assignments in the “smooth”
case and <em>fewer</em> individual memmoves in the “chunky” case), <code class="language-plaintext highlighter-rouge">smooth_remove_if</code> gets faster and
faster, and <code class="language-plaintext highlighter-rouge">chunky_remove_if</code>’s performance penalty doesn’t budge.</p>

<p>I tentatively blame this on the branch predictor. The fewer elements we remove, the more
predictable the result of <code class="language-plaintext highlighter-rouge">pred(*first)</code>. Removing half the elements is the worst case for
<code class="language-plaintext highlighter-rouge">smooth_remove_if</code> simply because that turns it into a tight loop over a single completely
unpredictable branch. Making that branch more predictable dominates every other consideration,
including any speedup we might get from memmove (which, after all, is also a tight loop over
a mostly predictable branch: “have we counted all the way to <code class="language-plaintext highlighter-rouge">n</code> yet?”)</p>

<p>Conclusion: “Chunking” the elements moved by <code class="language-plaintext highlighter-rouge">remove_if</code> into larger memmoves
isn’t an optimization; it’s a pessimization.</p>

<p>This doesn’t directly say anything about <code class="language-plaintext highlighter-rouge">unstable_remove</code>, but it does suggest that
when it comes to benchmarking <code class="language-plaintext highlighter-rouge">remove</code>-related algorithms, we ought not to rabbit-hole on
<em>simply</em> minimizing the number of move-assignments; that kind of thing may be outweighed
by cache and branch-prediction effects.</p>]]></content><author><name></name></author><category term="benchmarks" /><category term="stl-classic" /><category term="triviality" /><summary type="html"><![CDATA[This morning I was reading the umpteenth std-proposals thread proposing some variety of unstable_remove and it occurred to me that one odd thing about a swap-and-pop-based unstable_remove is that it tends to replace large swaths of contiguous removals by reversing the elements that are kept. For example (Godbolt):]]></summary></entry><entry><title type="html">The _Book of St Albans_ (1486)</title><link href="https://quuxplusone.github.io/blog/2026/05/22/exaltation-of-larks/" rel="alternate" type="text/html" title="The _Book of St Albans_ (1486)" /><published>2026-05-22T00:01:00+00:00</published><updated>2026-05-22T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/05/22/exaltation-of-larks</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/05/22/exaltation-of-larks/"><![CDATA[<p>This week I read James Lipton’s <em>An Exaltation of Larks; or, The Venereal Game</em> (2nd edition, 1977),
a discursive collection and celebration of “terms of venery” — the collective nouns like
“school of fish” and “pride of lions” that were (so the story goes) mostly invented by
medieval hunters who wanted to have their own proper jargon to distinguish the real hunters
from the dilettantes.</p>

<blockquote>
  <p>Hark ye! Only last week that jack-fool, the young Lord of Brocas, was here talking
of having seen a covey of pheasants in the wood. One such speech would have been the
ruin of a young squire at the court.</p>

  <p>—Arthur Conan Doyle, <a href="https://archive.org/details/sirnigel02doylgoog/page/123"><em>Sir Nigel</em></a> (1905)</p>
</blockquote>

<p>Lipton’s starting point was a list of 164 terms for “the companies of beasts and fowls”
included — merely to fill out the last few pages of a <a href="https://en.wikipedia.org/wiki/Section_(bookbinding)">signature</a>
(so <a href="https://archive.org/details/bokeofsaintalban00bernuoft/page/21">says</a> William Blades’ excellent preface) —
in the <a href="https://en.wikipedia.org/wiki/Book_of_Saint_Albans"><em>Book of St Albans</em></a> (1486).
But from Lipton’s entertaining notes we can see he modernized a few of the terms; for example,
he discusses his difficulty in rendering the term “corueseris” (corvisers) for modern readers,
and ultimately lands on “shoemakers.”
This led me to wonder exactly what other changes Lipton might have snuck in, and therefore to look up the
original orthography of the <em>Book of St Albans</em>. That orthography is visible today both
<a href="https://archive.org/details/bokeofsaintalban00bernuoft/page/115/mode/1up">in Blades’ facsimile</a>
and <a href="https://www.gutenberg.org/files/71266/71266-h/71266-h.htm">in Unicode transliteration</a> at Project Gutenberg.
I was surprised to find that Lipton’s title, in the <em>Book of St Albans,</em> is rendered as “an exaltyng of larkis”;
it’s only in <a href="/blog/2026/07/16/egerton-ms-1995/">Egerton MS 1995</a> (fol. 56r)
that we find “an exaltacyon of larkys” proper.</p>

<hr />

<p>C. E. Hare, in <a href="https://archive.org/details/bwb_KQ-367-113/page/226"><em>The Language of Field Sports</em></a> (2nd edition 1949)
— which Lipton cites! — points out that many of the <em>Book’s</em> terms are not really “company terms.”
For example, “a couple or pair of bottles” is no more a company term than “a brace of pheasants”
or “a trio of tenors”; and as far as I can tell, “a cast of bread” parallels our “loaf of bread”:
no more a company term than “a jug of wine.”</p>

<p>Hare’s notes on the <em>Book</em> are well worth reading. See pages 232–239 for his collection
of neologisms including “a glitter of flying-fish” (R. Beale), “a sending of robins” (L. Dawson Campbell),
and “a scold of magpies.”</p>

<p>Hare credits “a scold of magpies” to <em>Country Life</em> magazine; but searching that periodical
I find only a Letter to the Editor from J. H. Owen (in the 1941-09-26 issue) on the subject
of <a href="https://archive.org/details/sim_country-life_1941-09-26_90_2332/page/590">“Congregations of Magpies”</a>
which also uses the terms “flock” and “party” but never (as noun nor verb) “scold.”</p>

<hr />

<p>Here are the terms of venery from the <em>Book of St Albans</em> and from Egerton MS 1995, starting with those for
beasts and fowls that might be considered “serious,” and followed by those for human beings
of various professions which we might consider “jocular.” The original makes no such
distinction: serious and jocular are thoroughly intermixed. My tables appear in alphabetical
order, except that I’ll start as the <em>Book</em> does with “herd,” a term associated with
the royalty of the animal world.</p>

<table class="smaller">
  <thead>
    <tr>
      <th>Original orthography (St Albans)</th>
      <th>Egerton</th>
      <th>Modern orthography</th>
      <th>Lipton</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>The Compaẏnẏs of beeſtẏs and fowlẏs</td>
      <td> </td>
      <td>The Companies of Beasts and Fowls</td>
      <td> </td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td>an Herde of Hertis<br />an herde of all manͬ dere</td>
      <td>a herde of hertys<br />a herde of Dere</td>
      <td>a herd of harts<br />  " of all manner of deer</td>
      <td>a herd of harts<br />(etc)</td>
    </tr>
    <tr>
      <td>an Herde of Swannys</td>
      <td> " of Swannys</td>
      <td> " of swans</td>
      <td>a wedge of swans</td>
    </tr>
    <tr>
      <td>an Herde of Cranys</td>
      <td> " of Cranys</td>
      <td> " of cranes</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an Herde of Corlewys</td>
      <td> " of Curlewys</td>
      <td> " of curlews</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an Herde of wrennys</td>
      <td>—</td>
      <td> " of wrens</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a badelyng of Dokis</td>
      <td>a Padelynge of Dookyſſe</td>
      <td>a paddling (or badling) of ducks</td>
      <td>a paddling of ducks</td>
    </tr>
    <tr>
      <td>a Baren of Mulis</td>
      <td>a Burdynne of mulyſſe</td>
      <td>a barren (or burden) of mules</td>
      <td>a barren (or bearing) of mules</td>
    </tr>
    <tr>
      <td>a Beuy of Roos</td>
      <td>a Bevy of Roys</td>
      <td>a bevy of <a href="https://en.wikipedia.org/wiki/Roe_deer">roes</a></td>
      <td>a bevy of roebucks</td>
    </tr>
    <tr>
      <td>a Beuy of Quaylis</td>
      <td> " of Quaylys</td>
      <td> " of quails</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a beldyng of Rookes</td>
      <td>a Byldynge of Rookys</td>
      <td>a building of rooks</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Bery of Conyis</td>
      <td>a Bery of Connys</td>
      <td>a bury of coneys</td>
      <td>(a colony of rabbits)</td>
    </tr>
    <tr>
      <td>a Beſynes of ferettis</td>
      <td>a Beſynys of Ferettys</td>
      <td>a business of ferrets</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Brace of grehoundis of ij<br />a Lece of Grehoundis of iij</td>
      <td>a leſſe of Grehoundys</td>
      <td>a brace of greyhounds (2)<br />a lease of greyhounds (3)</td>
      <td>a leash of greyhounds<br />also a brace</td>
    </tr>
    <tr>
      <td>a Brode of hennys</td>
      <td>a Broode of hennyſſe</td>
      <td>a brood of hens</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a caſt of haukis of yᵉ tour ij<br />a Lece of theſſame haukis iij</td>
      <td>a Caſte of hawkys of the Towre</td>
      <td>a cast of hawks of the tower (2)<br />a lease of the same hawks (3)</td>
      <td> </td>
    </tr>
    <tr>
      <td>a Cete of Graies</td>
      <td>a Syght of Grayys</td>
      <td>a cete of <a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED19331">greys</a></td>
      <td>a cete of badgers</td>
    </tr>
    <tr>
      <td>a Cherme of Goldefynches</td>
      <td>a Chyrme of Goldefynchys</td>
      <td>a charm of goldfinches</td>
      <td>a charm of finches<br />(a glister of goldfinches)</td>
    </tr>
    <tr>
      <td>a Clateryng of choughes</td>
      <td>a Chatterynge of Choughys</td>
      <td>a clattering of choughs</td>
      <td>a chattering of choughs</td>
    </tr>
    <tr>
      <td>a Congregacion of peple</td>
      <td>—</td>
      <td>a congregation of people</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Congregacion of Pleuers</td>
      <td>a Congregacyon of Plovers</td>
      <td>a congregation of plovers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Couert of cootis</td>
      <td>a Coverete of Cootys</td>
      <td>a covert of coots</td>
      <td>a cover of coots</td>
    </tr>
    <tr>
      <td>a Couple of rennyng houndis</td>
      <td>—</td>
      <td>a couple of running hounds</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a Coupull of ſpaynellis</td>
      <td>a Copylle of Spaynellys</td>
      <td>a couple of spaniels</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Couy of partrichis</td>
      <td>a Covaye of Parterygys</td>
      <td>a covey of partridges</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Cowardnes of curris</td>
      <td>a Cowardenys of Currys</td>
      <td>a cowardness of curs</td>
      <td>a cowardice of curs</td>
    </tr>
    <tr>
      <td>a Deſſerte of Lapwyngꝭ</td>
      <td>a Dyſſayte of lepwynkys</td>
      <td>a desert [<em>sic</em>] of lapwings</td>
      <td>a deceit of lapwings</td>
    </tr>
    <tr>
      <td>a Diſſimulacion of breddis</td>
      <td>a Dyſſymylacyon of alle ſmalle Bryddys</td>
      <td>a dissimulation of birds</td>
      <td>a dissimulation of birds</td>
    </tr>
    <tr>
      <td>a Droue of Nete</td>
      <td>a Droffe of Nete</td>
      <td>a drove of <a href="https://en.wiktionary.org/wiki/neat#Old_English">neats</a></td>
      <td>a drove of cattle</td>
    </tr>
    <tr>
      <td>a Dryft of tame Swyne</td>
      <td>a Dryfte of Tame Swyne</td>
      <td>a drift of tame swine</td>
      <td>a drift of hogs</td>
    </tr>
    <tr>
      <td>a Duell of Turtillis</td>
      <td>—</td>
      <td>a <a href="https://en.wiktionary.org/wiki/deuil#French">deuil</a> of <a href="https://en.wikipedia.org/wiki/European_turtle_dove">turtles</a></td>
      <td>a true love of turtledoves</td>
    </tr>
    <tr>
      <td>an Exaltyng of Larkis</td>
      <td>an Exaltacyon of larkys</td>
      <td>an exalting of larks</td>
      <td>an exaltation of larks</td>
    </tr>
    <tr>
      <td>a fall of woodecockis</td>
      <td>a Falle of woodecockys</td>
      <td>a fall of woodcocks</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a fflight of Doues</td>
      <td>a Flyght of Dovys</td>
      <td>a flight of doves</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Flight of Goſhaukes</td>
      <td> " of Goſſe hawkys</td>
      <td>a flight of goshawks</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Flight of ſwalowes</td>
      <td> " of Swalys</td>
      <td> " of swallows</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a fflocke of Shepe</td>
      <td>a Flocke of Schepe</td>
      <td>a flock of sheep</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Gagle of gees</td>
      <td>a Gagelynge of Geſſe</td>
      <td>a gaggle of geese</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an Harraſſe of horſe</td>
      <td>a harrys of hors<br />a Stalyn of olde hors</td>
      <td>a <a href="https://en.wiktionary.org/wiki/harras">harras</a> of horses</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an hooſt of men</td>
      <td>a Oſte of men</td>
      <td>a host of men</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an Oſt of ſparowis</td>
      <td>a Oſte of Sparowys</td>
      <td> " of sparrows</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Kenell of Rachis</td>
      <td>a kenelle of Raychys</td>
      <td>a kennel of <a href="https://en.wiktionary.org/wiki/rach#English">raches</a></td>
      <td>a kennel of dogs</td>
    </tr>
    <tr>
      <td>a Kyndyll of yong Cattis</td>
      <td>—</td>
      <td>a kindle of young cats</td>
      <td>a kindle of kittens</td>
    </tr>
    <tr>
      <td>a Labor of Mollis</td>
      <td>a labyr of mollys</td>
      <td>a labor of moles</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Lepe of Lebardis</td>
      <td>a lepe of lybardys</td>
      <td>a leap of leopards</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Litter of welpis</td>
      <td>a lyttur of whelpys</td>
      <td>a litter of whelps</td>
      <td>a litter of pups</td>
    </tr>
    <tr>
      <td>a Murmuracion of ſtares</td>
      <td>a murmuracyon of Starys</td>
      <td>a murmuration of starlings</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Muſtre of Pecockys</td>
      <td>a mouſtyr of Pecockys</td>
      <td>a muster of peacocks</td>
      <td>an ostentation of peacocks</td>
    </tr>
    <tr>
      <td>a Mute of houndes</td>
      <td>a Draſſe of houndys</td>
      <td>a mute (or drass?) of hounds</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Neſt of Rabettis</td>
      <td>a Neſte of Rabettys</td>
      <td>a nest of rabbits</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Nye of ffeſaunttys</td>
      <td>a Ny of Feſauntys</td>
      <td>a nye of pheasants</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Paſe of Aſſis</td>
      <td>a Paſſe of Aſſys</td>
      <td>a pass of asses</td>
      <td>a pass of asses<br />(1st ed.: “pace”)</td>
    </tr>
    <tr>
      <td>a Pepe of chykennys</td>
      <td>a Pype of Chekynnyſſe</td>
      <td>a peep of chickens</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Pride of Lionys</td>
      <td>a Pryde of lyons</td>
      <td>a pride of lions</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Ragg of coltis<br />or a Rake</td>
      <td>a Rage of Coltys</td>
      <td>a rag (or rake) of colts</td>
      <td>a rag of colts</td>
    </tr>
    <tr>
      <td>a Riches of Martronys</td>
      <td>—</td>
      <td>a richesse of martens</td>
      <td>a richness of martens</td>
    </tr>
    <tr>
      <td>a Route of woluess</td>
      <td>a Rowte of wylde wolfys</td>
      <td>a rout of wolves</td>
      <td>a route of wolves</td>
    </tr>
    <tr>
      <td>a Scoll of ffyſh</td>
      <td>—</td>
      <td>a school of fish</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Sege of heronnys</td>
      <td>a Sege of hayrynnys</td>
      <td>a siege of herons</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Sege of betouris</td>
      <td> " of Betowrys</td>
      <td> " of bitterns</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Shrewdenes of Apis</td>
      <td>a Schrewdenys of Apys</td>
      <td>a shrewdness of apes</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Sculke of foxis<br />a ſkulke of ffoxis</td>
      <td>a Nerthe of Foxys</td>
      <td>a skulk of foxes</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Sleuth of Beeris</td>
      <td>a Slouthe of Beerys</td>
      <td>a sleuth of bears</td>
      <td>a sloth of bears</td>
    </tr>
    <tr>
      <td>a Sorde or a ſute of malardis</td>
      <td>a Fluſche of mallardys</td>
      <td>a sord (or suit) of mallards</td>
      <td>a sorde of mallards<br />(2nd ed.: “sord”)</td>
    </tr>
    <tr>
      <td>a Soundre of wilde ſwyne</td>
      <td>a Sundyr of wylde Swyne</td>
      <td>a sounder of wild swine</td>
      <td>a sounder of swine</td>
    </tr>
    <tr>
      <td>a Sprynge of Telis</td>
      <td>a ſprynge of Telys</td>
      <td>a spring of teals</td>
      <td>a spring of teal</td>
    </tr>
    <tr>
      <td>a Stode of Maris</td>
      <td>a Stoode of marys</td>
      <td>a stud of mares</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Sute of a lyam</td>
      <td>—</td>
      <td>a suit<sup>(?)</sup> of a <a href="https://en.wiktionary.org/wiki/lyam-hound">lyam</a></td>
      <td>—</td>
    </tr>
    <tr>
      <td>a Swarme of bees</td>
      <td>a Swarme of Beys</td>
      <td>a swarm of bees</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Synguler of Boris</td>
      <td>a Synguler of Boorys</td>
      <td>a singular of boars</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Titengis of Pies</td>
      <td>a Tydynge of Pyys</td>
      <td>a tidings of pies</td>
      <td>a tidings of magpies</td>
    </tr>
    <tr>
      <td>a Trippe of Gete</td>
      <td>a Tryppe of Gete</td>
      <td>a trip of goats</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Trippe of haaris</td>
      <td>a Drove or a huſke of Harrys</td>
      <td>a trip (or drove or husk) of hares</td>
      <td>a husk (or down or drove) of hares</td>
    </tr>
    <tr>
      <td>an vnkyndenes of Rauenes</td>
      <td>a Unkyndenys of ravynnys</td>
      <td>an unkindness of ravens</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a walke of Snytis</td>
      <td>a walke of Snytys</td>
      <td>a walk of snipe</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a wache of Nyghtingalis</td>
      <td>a wayche of Nyghtynggalys</td>
      <td>a watch of nightingales</td>
      <td>✓</td>
    </tr>
  </tbody>
</table>

<p>The jocular terms for companies of human beings and/or inanimate objects:</p>

<table class="smaller">
  <tbody>
    <tr>
      <td>a Beuy of Ladies</td>
      <td>a Bevy of ladyes</td>
      <td>a bevy of ladies</td>
      <td>a bevy of beauties</td>
    </tr>
    <tr>
      <td>a bhomynable ſight of mõkis</td>
      <td>—</td>
      <td>an abominable sight of monks</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Blaſt of hunteris</td>
      <td>a Blaste of hunterſſe</td>
      <td>a blast of hunters</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Bleche of ſowteris</td>
      <td>—</td>
      <td>a blatch of souters</td>
      <td>a blackening of shoemakers</td>
    </tr>
    <tr>
      <td>a bluſh of boyes</td>
      <td>—</td>
      <td>a blush of boys</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Booſt of ſaudiouris</td>
      <td>—</td>
      <td>a boast of soldiers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Caſt of Brede</td>
      <td>—</td>
      <td>a cast of bread</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Charge of curatis</td>
      <td>a Carge of Curettyſſe</td>
      <td>a charge of curates</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Cluſtre of chorlis</td>
      <td>—</td>
      <td>a cluster of churls</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Cluſtre of Grapys</td>
      <td>—</td>
      <td> " of grapes</td>
      <td>” (or bunch) of grapes</td>
    </tr>
    <tr>
      <td>a Cluſtre of Nottis</td>
      <td>—</td>
      <td> " of knots</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Conuͬtyng of prechouris</td>
      <td>a Convertynge of Precheryſſe</td>
      <td>a converting of preachers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Couple or a payer of botillis</td>
      <td>—</td>
      <td>a couple (or pair) of bottles</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a Credens of Seweris</td>
      <td>—</td>
      <td>a credence of <a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED39665">sewers</a></td>
      <td>a credence of tasters</td>
    </tr>
    <tr>
      <td>a Dampnyng of Iurrouris</td>
      <td>a Dampnynge of Juryerſſe</td>
      <td>a damning of jurors</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Dignyte of chanonys</td>
      <td>a Dygnyte of Chanonnyſſe</td>
      <td>a dignity of canons</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Diligens of Meſſangeris</td>
      <td>a Dylygens of maſſyngers</td>
      <td>a diligence of messengers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Diſcrecion of Preſtis</td>
      <td>a Dyſcrecyon of Preſtys</td>
      <td>a discretion of priests</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Diſgyſyng of Taylours</td>
      <td>—</td>
      <td>a disguising of tailors</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Diſworſhip of Scottis</td>
      <td>—</td>
      <td>a disworship of Scots</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Doctryne of doctoris</td>
      <td>a Doctryne of Docterſſe</td>
      <td>a doctrine of doctors</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Draught of boteleris</td>
      <td>a Draught of Buttelerys</td>
      <td>a draught of butlers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Drifte of fiſhers</td>
      <td>—</td>
      <td>a drift of fishers</td>
      <td>a drift of fishermen</td>
    </tr>
    <tr>
      <td>a Dronkſhip of Coblers</td>
      <td>—</td>
      <td>a drunkship of cobblers</td>
      <td>a drunkenness of cobblers</td>
    </tr>
    <tr>
      <td>an Eloquens of laweyeris</td>
      <td>a Eloquens of lawyers</td>
      <td>an eloquence of lawyers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Example of Maiſteris</td>
      <td>—</td>
      <td>an example of masters</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an Execucion of Officerys</td>
      <td>a Execucyon of Offycers</td>
      <td>an execution of officers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a faith of Marchandis</td>
      <td>a Faythe of marchauntyſſe</td>
      <td>a faith of merchants</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Feſtre of Brewris</td>
      <td>—</td>
      <td>a fester of brewers</td>
      <td>a <a href="https://en.wiktionary.org/wiki/sester">sester</a> of brewers</td>
    </tr>
    <tr>
      <td>a ffeliſhippyng of yomen</td>
      <td>a Felyſchyppe of yemen</td>
      <td>a fellowshipping of yeomen</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a ffraunch of Mylneris</td>
      <td>—</td>
      <td>a fraunch of millers<br />(not “a french of milliners”!)</td>
      <td>a gobble of millers</td>
    </tr>
    <tr>
      <td>a Fightyng of beggers</td>
      <td>—</td>
      <td>a fighting of beggars</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Gagle of women</td>
      <td>—</td>
      <td>a gaggle of women</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Gloſyng of Tauerneris</td>
      <td>a Gloſyng of Taverneryſſe</td>
      <td>a glosing of taverners</td>
      <td>a cajolery of taverners</td>
    </tr>
    <tr>
      <td>a Goryng of Bochouris</td>
      <td>—</td>
      <td>a goring of butchers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an Herde of harlottys</td>
      <td>—</td>
      <td>a herd of harlots</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Kerff of Panteris</td>
      <td>a kerffe of Panterſſe</td>
      <td>a kerf of panterers</td>
      <td>a slice of pantrymen</td>
    </tr>
    <tr>
      <td>a Laſh of Carteris</td>
      <td>—</td>
      <td>a lash of carters</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Laughtre of Oſteloris</td>
      <td>a lawghtur of Oſtylerſſe</td>
      <td>a laughter of ostlers</td>
      <td>a laughter of hostelers</td>
    </tr>
    <tr>
      <td>a Lyeng of pardeneris</td>
      <td>a lyynge of Pardynerſſe</td>
      <td>a lying of pardoners</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Malepertnes of pedleres</td>
      <td>—</td>
      <td>a malapertness of pedlars</td>
      <td>an impudence of peddlers</td>
    </tr>
    <tr>
      <td>a Melody of Harpers</td>
      <td>—</td>
      <td>a melody of harpers</td>
      <td>a melody of harpists</td>
    </tr>
    <tr>
      <td>a Miſbeleue of paynteris</td>
      <td>—</td>
      <td>a misbelief of painters</td>
      <td>an illusion of painters</td>
    </tr>
    <tr>
      <td>a Multiplieng of huſbondis</td>
      <td>—</td>
      <td>a multiplying of husbands</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Neuͬthriuyng of Iogoleris</td>
      <td>—</td>
      <td>a neverthriving of jugglers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Noonpaciens of wyues</td>
      <td>—</td>
      <td>a nonpatience of wives</td>
      <td>an impatience of wives</td>
    </tr>
    <tr>
      <td>an Obeiſians of ſͬuauntis</td>
      <td>a Obedyens of Servandys</td>
      <td>an obeisance of servants</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>an Obſͬuans of herimytis</td>
      <td>—</td>
      <td>an observance of hermits</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Pauuerty of pypers</td>
      <td>—</td>
      <td>a poverty of pipers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Plocke of Shoturneris</td>
      <td>—</td>
      <td>a pluck of shoeturners</td>
      <td>a plocke of shoeturners</td>
    </tr>
    <tr>
      <td>a Pontificalite of prelatis</td>
      <td>a Pontyfycalle of Preſtyſſe</td>
      <td>a pontificality of prelates</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Promyſe of Tapſteris</td>
      <td>a Promys of Tapsteryſſe</td>
      <td>a promise of tapsters</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Proude ſhewyng of taloris</td>
      <td>—</td>
      <td>a proud showing of tailors</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a ꝑuiſion of ſtewardꝭ of hous</td>
      <td>a Prevyſyon of ſtywardyſſe</td>
      <td>a provision of stewards-of-house</td>
      <td>a provision of stewards</td>
    </tr>
    <tr>
      <td>a Prudens of vikeris</td>
      <td>Prudens of Vycaryſſe</td>
      <td>a prudence of vicars</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Rafull of Knauys</td>
      <td>—</td>
      <td>a raffle of knaves</td>
      <td>a riffraff of knaves</td>
    </tr>
    <tr>
      <td>a Rage of Maydenys</td>
      <td>—</td>
      <td>a rage of maidens</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Rage of the teethe</td>
      <td>—</td>
      <td>a rage of the teeth</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Raſcall of Boyes</td>
      <td>—</td>
      <td>a rascal of boys</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Route of Knyghtis</td>
      <td>a Rowte of knyghtys<br />  " of Gentylle men</td>
      <td>a rout of knights</td>
      <td>a route of knights</td>
    </tr>
    <tr>
      <td>a Safegarde of Porteris</td>
      <td>a Savegarde of Porteryſſe</td>
      <td>a safeguard of porters</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Scoldyng of Kemſteris</td>
      <td>—</td>
      <td>a scolding of <a href="https://en.wiktionary.org/wiki/kembster">kembsters</a></td>
      <td>a scold of seamstresses</td>
    </tr>
    <tr>
      <td>a Scole of clerkes</td>
      <td>—</td>
      <td>a school of clerks</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Sentence of Iuges</td>
      <td>a Sedent of Juggyſſe</td>
      <td>a sentence (or sedent) of judges</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Sete of vſſheris</td>
      <td>a Sete of huſcheryſſe</td>
      <td>a seat of ushers</td>
      <td>a set of ushers</td>
    </tr>
    <tr>
      <td>a Sculke of freris</td>
      <td>—</td>
      <td>a skulk of friars</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Skulke of Theuys</td>
      <td>—</td>
      <td> " of thieves</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Smere of Coryouris</td>
      <td>—</td>
      <td>a smear of curriers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a ſotelty of ſergeauntis</td>
      <td>—</td>
      <td>a subtlety of serjeants</td>
      <td>a subtlety of sergeants</td>
    </tr>
    <tr>
      <td>a ſquatte of Dawberis</td>
      <td>—</td>
      <td>a squat of daubers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Stalke of foſteris</td>
      <td>a Stalke of Foſterſſe</td>
      <td>a stalk of foresters</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a State of Prynces</td>
      <td>a State of Pryncyſſe</td>
      <td>a state of princes</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Suꝑfluyte of Nunnys</td>
      <td>—</td>
      <td>a superfluity of nuns</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Tabernacle of bakers</td>
      <td>—</td>
      <td>a tabernacle of bakers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Temꝑans of cokys</td>
      <td>a Temporens of Cokys</td>
      <td>a temperance of cooks</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Thongh of barons</td>
      <td>a Trought of Barronnyſſe</td>
      <td>a thong [<em>sic</em>] (or troth) of barons</td>
      <td>a troth of barons</td>
    </tr>
    <tr>
      <td>a Thraue of Throſheris</td>
      <td>—</td>
      <td>a thrave of threshers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Thretenyng of courteyeris</td>
      <td>a Thretynge of Curtyers</td>
      <td>a threatening of courtiers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a Trynket of Corueſeris</td>
      <td>—</td>
      <td>a trinket of corvisers</td>
      <td>a cutting of cobblers</td>
    </tr>
    <tr>
      <td>an vnbrewyng of Kerueris</td>
      <td>—</td>
      <td>an imbruing of carvers</td>
      <td>a mess of carvers</td>
    </tr>
    <tr>
      <td>an vncredibilite of Cocoldis</td>
      <td>—</td>
      <td>an incredibility of cuckolds</td>
      <td>an incredulity of cuckolds</td>
    </tr>
    <tr>
      <td>an vntrouth of ſompneris</td>
      <td>—</td>
      <td>an untruth of summoners</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a waywardnes of haywardis</td>
      <td>—</td>
      <td>a waywardness of haywards</td>
      <td>a waywardness of herdsmen</td>
    </tr>
    <tr>
      <td>a wonderyng of Tynkeris</td>
      <td>—</td>
      <td>a wandering of tinkers</td>
      <td>✓</td>
    </tr>
    <tr>
      <td>a worſhip of writeris</td>
      <td>—</td>
      <td>a worship of writers</td>
      <td>✓</td>
    </tr>
  </tbody>
</table>

<p>Leaving <em>An Exaltation of Larks</em> behind, the next list in the <em>Book of St Albans</em> interested me
because I had serendipitously just seen it quoted in H. H. Furness’s notes on <em>Love’s Labours Lost</em>,
regarding the use of the technical term “break up” in
<a href="https://archive.org/details/bwb_C0-BNX-215/page/117">IV.i</a>:</p>

<blockquote>
  <p>COSTARD: I have a letter from Monsieur Berowne to one Lady Rosaline.</p>

  <p>PRINCESS: O, thy letter, thy letter! He’s a good friend of mine.
Stand aside, good bearer.—Boyet, you can carve;
Break up this capon.</p>
</blockquote>

<p>In fact the <em>Book of St Albans</em> says that a capon is not “broken up” at table but “sawsed.”
One might guess (as Henry Scougal apparently does in his 1789
<a href="https://archive.org/details/bim_eighteenth-century_a-new-academy-of-complim_scougal-henry_1789/page/38"><em>New Academy of Compliments</em></a>)
that that word means “sawn,” i.e. “cut up,” but in fact it means “sauced.”</p>

<p>Many of these terms are repeated, as commands, in Wynken de Worde’s
<a href="https://archive.org/details/boke-of-keruynge/page/n11"><em>Boke of Kervynge</em></a> (1508).</p>

<table class="smaller">
  <thead>
    <tr>
      <th>St Albans</th>
      <th>Modern orthography</th>
      <th>Egerton MS 1995</th>
      <th>Boke of Kervynge</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>a Dere brokenne</td>
      <td>a deer broken</td>
      <td>Dere ys Brokynne</td>
      <td>Breke that dere</td>
    </tr>
    <tr>
      <td>a Gooſe rerede</td>
      <td>a goose reared</td>
      <td>Goſſe ys rerryde</td>
      <td>rere that gooſe</td>
    </tr>
    <tr>
      <td>a Pigge hedede and ſydede</td>
      <td>a pig headed and sided</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a Capoon ſawſede</td>
      <td>a capon sauced</td>
      <td>Caponne ys Sawſyde</td>
      <td>ſauce that capon</td>
    </tr>
    <tr>
      <td>a Checoon fruſſhyd</td>
      <td>a chicken <a href="https://en.wiktionary.org/wiki/frush">frushed</a></td>
      <td>Chekynne ys Faſſyde</td>
      <td>fruche that chekyn</td>
    </tr>
    <tr>
      <td>a Cony vnlaceedde</td>
      <td>a coney unlaced</td>
      <td>Conyng ys unlaſyde</td>
      <td>vnlace that conye</td>
    </tr>
    <tr>
      <td>a Crane diſplayde</td>
      <td>a crane displayed</td>
      <td>Crane ys Dyſplayde</td>
      <td>dyſplaye that crane</td>
    </tr>
    <tr>
      <td>a Curlew vnioyntede</td>
      <td>a curlew unjointed</td>
      <td>Corlowe ys unrowtyde</td>
      <td>vntache that curlewe</td>
    </tr>
    <tr>
      <td>a ffeſawnt alet</td>
      <td>a pheasant allayed</td>
      <td>Feſonde ys <i>y-</i>haylyde</td>
      <td>alaye that feſande</td>
    </tr>
    <tr>
      <td>a Quayle wyngged</td>
      <td>a quail winged</td>
      <td>Quayle [ys] wyngyde</td>
      <td>wynge that quayle</td>
    </tr>
    <tr>
      <td>a Plouer Mynſed</td>
      <td>a plover minced</td>
      <td>Plouer ys mynſchyde</td>
      <td>mynce that plouer</td>
    </tr>
    <tr>
      <td>a Pegeon thyghed</td>
      <td>a pigeon thighed</td>
      <td>Pegonne [ys] <i>y-</i>ſchrydde</td>
      <td>thye that pegyon</td>
    </tr>
    <tr>
      <td>Brawne leechyd</td>
      <td><a href="https://en.wikipedia.org/wiki/Head_cheese">brawn</a> <a href="https://archive.org/details/bim_eighteenth-century_le-dictionnaire-royal-fr_boyer-abel_1759_2/page/n509/mode/1up?q=l%C3%A9che">leached</a></td>
      <td>Brawyn ys leyſchyde</td>
      <td>leſche yͭ brawne</td>
    </tr>
    <tr>
      <td>a Swanne lyfte</td>
      <td>a swan lifted</td>
      <td>Swanne ys lyfte</td>
      <td>lyft that ſwanne</td>
    </tr>
    <tr>
      <td>a Lambe ſhulderide</td>
      <td>a lamb shouldered</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a Kidde ſhulderide</td>
      <td>a kid "</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>an Hen ſpoylede</td>
      <td>a hen spoiled</td>
      <td>Henne ys ſpoylyde</td>
      <td>ſpoyle that henne</td>
    </tr>
    <tr>
      <td>a Malarde vnbraſid</td>
      <td>a mallard unbraced</td>
      <td>Mallerde ys unbraſſydde</td>
      <td>vnbrace that malarde</td>
    </tr>
    <tr>
      <td>an Heron dyſmembrid</td>
      <td>a heron dismembered</td>
      <td>Hayryn ys dysmemberyde</td>
      <td>dyſmembre that heron</td>
    </tr>
    <tr>
      <td>a Pecoke diſfigured</td>
      <td>a peacock disfigured</td>
      <td>Pecocke ys dyſfyguryde</td>
      <td>dyſfygure that pecocke</td>
    </tr>
    <tr>
      <td>a Beture vntachid</td>
      <td>a bittern untached</td>
      <td>Bytterne ys untachyde</td>
      <td>vnioynt that bytture</td>
    </tr>
    <tr>
      <td>a Partrich alet</td>
      <td>a partridge allayed</td>
      <td>Parteryche [ys] wyngyde</td>
      <td>wynge that partryche</td>
    </tr>
    <tr>
      <td>a Raale breſtyde</td>
      <td>a rail breasted</td>
      <td>Rayle ys Breſtyde</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a Wodecoke thyghed</td>
      <td>a woodcock thighed</td>
      <td>Woodecocke [ys] <i>y-</i>ſchrydde</td>
      <td>thye that woodcocke</td>
    </tr>
    <tr>
      <td>—</td>
      <td>(thigh, or shred, all manner of small birds)</td>
      <td>alle ſmalle Bryddys ben <i>y-</i>ſchrydde</td>
      <td>thye all maner ſmall byrdes</td>
    </tr>
    <tr>
      <td>A Sawmon Chyned</td>
      <td>a salmon chined</td>
      <td>Samon ys Chynyde</td>
      <td>chynne that ſamon</td>
    </tr>
    <tr>
      <td>a Pyke ſplatted</td>
      <td>a pike splatted</td>
      <td>Pyke ſplayde</td>
      <td>ſplatte that pyke</td>
    </tr>
    <tr>
      <td>an Haddoke ſided</td>
      <td>a haddock sided</td>
      <td>Haddocke ys Sydyde</td>
      <td>ſyde that haddocke</td>
    </tr>
    <tr>
      <td>a Cheuen fynned</td>
      <td>a <a href="https://en.wiktionary.org/wiki/chevin">chevin</a> finned</td>
      <td>Chevynne ys vynnydde</td>
      <td>fynne that cheuen</td>
    </tr>
    <tr>
      <td>a Sole loyned</td>
      <td>a sole loined</td>
      <td>—</td>
      <td>—</td>
    </tr>
    <tr>
      <td>a Gurnarde chyned</td>
      <td>a <a href="https://en.wikipedia.org/wiki/Grey_gurnard">gurnard</a> chined</td>
      <td>Gounarde Chynyde</td>
      <td>—</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a <a href="https://en.wiktionary.org/wiki/plaice">plaice</a> sauced</td>
      <td>Playſſe ys ſawſyde</td>
      <td>ſauce that place</td>
    </tr>
    <tr>
      <td>a Tenche ſawced</td>
      <td>a tench sauced</td>
      <td>Tenche ſowſyde</td>
      <td>ſauce that tenche</td>
    </tr>
    <tr>
      <td>an Ele trouſoned</td>
      <td>an eel trassened</td>
      <td>Ele ys Trowſyde<br />or ellys <i>y-</i>colpynnyd</td>
      <td>traſſene that ele</td>
    </tr>
    <tr>
      <td>a Breme ſplayed</td>
      <td>a bream splayed</td>
      <td>Breme ys Splayde</td>
      <td>ſplaye that breme</td>
    </tr>
    <tr>
      <td>a Barbill tuſkyd</td>
      <td>a barbel tusked</td>
      <td>Barbule ys <i>y-</i>Tuſkydde</td>
      <td>tuſke that berbell</td>
    </tr>
    <tr>
      <td>a Trought gobettid</td>
      <td>a trout gobbeted<br />or <a href="https://archive.org/details/newdictionaryofe01rich/page/459">culponed</a></td>
      <td>Trowght y-colpynnyde</td>
      <td>culpon that troute</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a <a href="https://en.wikipedia.org/wiki/Common_roach">roach</a> boned or ribbed</td>
      <td>Roche <i>y-</i>Bonyde or rybbyde</td>
      <td>—</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a lamprey strung (or corded)</td>
      <td>lampray ys cordyde</td>
      <td>ſtrynge that lampraye</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a sturgeon <a href="https://en.wiktionary.org/wiki/tranch">tranched</a></td>
      <td>—</td>
      <td>traunche that ſturgyon</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a porpoise undertranched</td>
      <td>—</td>
      <td>vndertraunche that purpos</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a crab tamed (or mined<sup>(?)</sup>)</td>
      <td>Crabbe ys mynyde</td>
      <td>tayme that crabbe</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a lobster barbed</td>
      <td>—</td>
      <td>barbe that lopſter</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a crawfish unmailed</td>
      <td>Crawys ys unmaylyde</td>
      <td>—</td>
    </tr>
    <tr>
      <td>an Egge Tyred</td>
      <td>an egg tired</td>
      <td>—</td>
      <td>tyere that egge</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a pasty bordered</td>
      <td>Paſtey ys brouderydde</td>
      <td>border that paſty</td>
    </tr>
    <tr>
      <td>a ffyre Tymbered</td>
      <td>the fire timbered</td>
      <td>—</td>
      <td>tymbre that fyre</td>
    </tr>
  </tbody>
</table>

<p>Note the difference between <em>St Albans’</em> “an ele trousoned” and <em>Kervynge’s</em> “trassene that ele.”
(<em>Egerton</em> has “trowsed.”)
Charles Cooper in <em>The English Table in History and Literature</em> (1929) splits the difference
and <a href="https://archive.org/details/b3135533x/page/20">writes</a> “<em>traunsene</em> an eel.”
A comic poem in the <em>Literary Gazette</em> of 1827-06-23 <a href="https://archive.org/details/sim_literary-gazette_1827-06-23_544/page/396">has</a> “eels were <em>transened</em>.”
A correspondent in <em>Notes &amp; Queries</em> (January 1918) <a href="https://archive.org/details/s12notesqueries04londuoft/s12notesqueries04londuoft/page/26">mangles it</a>
all the way to “<em>transom</em> an eel.” I’ve gone with “trassened” for no particular reason.</p>

<p>Note that the two <em>Bokes</em> swap their verbs for bittern and curlew: you <em>unjoint</em> the one and <em>untach</em> the other,
but they can’t decide which is which. Some modernizations have “<em>untack</em> that curlew,” but <em>untach</em>
(like <em>tranch</em>) seems to be good old French: already in Middle English <em>tachen</em> means
“<a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED44371">pin together</a>,”
and so <em>untach</em> would mean “take apart.” (Another sense of <em>tachen</em>
<a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED44373">relates</a>
to a visible <em>token</em> predictive of <a href="https://www.etymonline.com/word/tetchy"><em>tetchiness.</em></a>)</p>

<hr />

<p>Finally, the <em>Book of St Albans</em> provides a short list of words for when animals bed down
for the night:</p>

<table class="smaller">
  <thead>
    <tr>
      <th>St Albans</th>
      <th>Egerton MS 1995</th>
      <th>Modern orthography</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>An hert <a href="https://quod.lib.umich.edu/m/middle-english-dictionary/dictionary/MED20464">Herbourghith</a></td>
      <td>A herte ben herborowde</td>
      <td>a hart harbors</td>
    </tr>
    <tr>
      <td>a Bucke lodgith</td>
      <td>a Bucke ys loggyde</td>
      <td>a buck lodges</td>
    </tr>
    <tr>
      <td>an Eſquyer lodgith</td>
      <td>—</td>
      <td>a squire "</td>
    </tr>
    <tr>
      <td>a Roo beddith</td>
      <td>a Roobucke ys Beddyde</td>
      <td>a roe beds</td>
    </tr>
    <tr>
      <td>a yoman beddith</td>
      <td>—</td>
      <td>a yeoman "</td>
    </tr>
    <tr>
      <td>an haare in her forme<br />ſhulderyng or leenyng</td>
      <td>a hare ys Formyde</td>
      <td>a hare in her <a href="https://archive.org/details/bim_eighteenth-century_the-sportsmans-dictiona_1735_1/page/n239/mode/1up">form</a><br />shoulders or leans</td>
    </tr>
    <tr>
      <td>a Cony ſittyng</td>
      <td>a Conyng ſyttythe</td>
      <td>a coney sits</td>
    </tr>
    <tr>
      <td>a Wodecoke beekyng</td>
      <td>—</td>
      <td>a woodcock <a href="https://en.wiktionary.org/wiki/beek">beeks</a></td>
    </tr>
    <tr>
      <td>—</td>
      <td>a Parterygge lythe</td>
      <td>a partridge lies</td>
    </tr>
    <tr>
      <td>—</td>
      <td>a Feſaunt ſtalkythe</td>
      <td>a pheasant stalks</td>
    </tr>
  </tbody>
</table>

<p>The <em>hare in her form</em> is proverbial for being snug-fitting and inconspicuous
(like a <a href="https://en.wikipedia.org/wiki/Aplysiida">sea hare</a> in its own habitat),
as in Jonathan Swift’s <a href="https://archive.org/details/bim_eighteenth-century_the-poetical-works-of-j_swift-jonathan_1736/page/160">poem</a>
on mint-master for Ireland <a href="https://en.wikipedia.org/wiki/William_Wood_(ironmaster)">William Wood</a> (1725):</p>

<blockquote>
  <p>The next is an Insect we call a Wood-worm,<br />
That lies in old Wood like a Hare in her Form.</p>
</blockquote>

<p>The shallow temporary scrapes of rabbit or roe posed a hazard to hikers: stepping into one
and taking a tumble, one might find oneself “in a scrape.”
(<em>Eclectic Magazine</em> <a href="https://archive.org/details/sim_eclectic-magazine-of-foreign-literature_1865-07_2_1/page/87">July 1865</a>.)
Similarly, if one took a tumble aboard ship, one might be said to be “scuppered.”
(<a href="https://archive.org/details/sim_notes-and-queries_1910-10-08_2_41/page/298">“Scupper,”</a> <em>Notes &amp; Queries</em> 1910-10-08).</p>

<p><em>A</em> to <em>B:</em> “Mr. <em>C</em> reminds me of a hare.” — “In what way?” — “In that he’ll always lie in a scrape.”</p>

<p>The opposite of “in her form” is <a href="https://archive.org/details/bim_early-english-books-1641-1700_a-new-dictionary-french-_miege-guy_1677/page/n369/mode/1up">“in relief,”</a>
i.e., “standing out” (cf. <em>bas-relief</em>). Reverse the syllables and you get <em>lièvre</em>, the French for “hare,”
which relates to <em>livre</em> as <em>coney</em> does to <em>coin</em> (i.e., not at all).</p>]]></content><author><name></name></author><category term="etymology" /><category term="litclub" /><category term="old-shit" /><category term="transcription" /><category term="word-ways" /><summary type="html"><![CDATA[This week I read James Lipton’s An Exaltation of Larks; or, The Venereal Game (2nd edition, 1977), a discursive collection and celebration of “terms of venery” — the collective nouns like “school of fish” and “pride of lions” that were (so the story goes) mostly invented by medieval hunters who wanted to have their own proper jargon to distinguish the real hunters from the dilettantes.]]></summary></entry><entry><title type="html">`std::is_heap` could be faster</title><link href="https://quuxplusone.github.io/blog/2026/05/11/is-heap/" rel="alternate" type="text/html" title="`std::is_heap` could be faster" /><published>2026-05-11T00:01:00+00:00</published><updated>2026-05-11T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/05/11/is-heap</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/05/11/is-heap/"><![CDATA[<p>The other day I was noodling around with some libc++ unit-test code that looked
roughly like this (<a href="https://godbolt.org/z/cGWcrdjcs">Godbolt</a>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template&lt;class A&gt;
auto extract_container(A&amp; a) {
  struct UnwrapAdaptor : A { A::container_type&amp; cc = A::c; };
  return UnwrapAdaptor(a).cc;
}

template&lt;class Adaptor&gt;
void test_push_range(bool is_heapified) {
  int in1[] = {1,3,7};
  int in2[] = {2,4,5,6};
  int expected[] = {1,3,7,2,4,5,6};
  Adaptor a;
  a.push_range(in1);
  a.push_range(in2);
  if (auto c = extract_container(a); is_heapified) {
    assert(std::ranges::is_heap(c));
    assert(std::ranges::is_permutation(c, expected));
  } else {
    assert(std::ranges::equal(c, expected));
  }
}

int main() {
  test_push_range&lt;std::stack&lt;int&gt;&gt;(false);
  test_push_range&lt;std::queue&lt;int&gt;&gt;(false);
  test_push_range&lt;std::priority_queue&lt;int&gt;&gt;(true);
}
</code></pre></div></div>

<p>I tried to extend <code class="language-plaintext highlighter-rouge">main</code> to test also some non-default containers.
(Incidentally, did you know <code class="language-plaintext highlighter-rouge">stack</code>’s default container is <code class="language-plaintext highlighter-rouge">deque</code>,
not <code class="language-plaintext highlighter-rouge">vector</code>?)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  test_push_range&lt;std::stack&lt;int, std::vector&lt;int&gt;&gt;&gt;(false);
  test_push_range&lt;std::stack&lt;int, std::list&lt;int&gt;&gt;&gt;(false);
</code></pre></div></div>

<p>…And suddenly the unit test no longer compiled!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>error: no matching function for call to object of type 'const __is_heap'
   22 |     assert(std::ranges::is_heap(c));
      |            ^~~~~~~~~~~~~~~~~~~~
[...]
note: because 'std::list&lt;int&gt; &amp;' does not satisfy 'random_access_range'
</code></pre></div></div>

<p>That caught me by surprise. Why should testing whether a range is heapified
require random access? It’s simple to implement with only forward traversal,
and <code class="language-plaintext highlighter-rouge">make_heap</code>/<code class="language-plaintext highlighter-rouge">is_heap</code> seems to analogize perfectly against <code class="language-plaintext highlighter-rouge">sort</code>/<code class="language-plaintext highlighter-rouge">is_sorted</code>.
<code class="language-plaintext highlighter-rouge">is_sorted</code> doesn’t require random access; why should <code class="language-plaintext highlighter-rouge">is_heap</code>?</p>

<table>
  <thead>
    <tr>
      <th>Ranges algorithm</th>
      <th>Constraint</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">sort</code></td>
      <td><code class="language-plaintext highlighter-rouge">random_access_range</code></td>
    </tr>
    <tr>
      <td>  <code class="language-plaintext highlighter-rouge">is_sorted</code></td>
      <td><code class="language-plaintext highlighter-rouge">forward_range</code></td>
    </tr>
    <tr>
      <td>  <code class="language-plaintext highlighter-rouge">is_sorted_until</code></td>
      <td><code class="language-plaintext highlighter-rouge">forward_range</code></td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">make_heap</code></td>
      <td><code class="language-plaintext highlighter-rouge">random_access_range</code></td>
    </tr>
    <tr>
      <td>  <code class="language-plaintext highlighter-rouge">is_heap</code></td>
      <td><code class="language-plaintext highlighter-rouge">random_access_range</code> (could be <code class="language-plaintext highlighter-rouge">forward_range</code>)</td>
    </tr>
    <tr>
      <td>  <code class="language-plaintext highlighter-rouge">is_heap_until</code></td>
      <td><code class="language-plaintext highlighter-rouge">random_access_range</code> (could be <code class="language-plaintext highlighter-rouge">forward_range</code>)</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">partition</code></td>
      <td><code class="language-plaintext highlighter-rouge">forward_range</code></td>
    </tr>
    <tr>
      <td>  <code class="language-plaintext highlighter-rouge">is_partitioned</code></td>
      <td><code class="language-plaintext highlighter-rouge">input_range</code></td>
    </tr>
    <tr>
      <td>  <a href="https://www.boost.org/doc/libs/latest/libs/algorithm/doc/html/algorithm/Misc.html#the_boost_algorithm_library.Misc.misc_inner_algorithms.is_partitioned_until"><code class="language-plaintext highlighter-rouge">is_partitioned_until</code></a></td>
      <td><code class="language-plaintext highlighter-rouge">input_range</code></td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">unique</code></td>
      <td><code class="language-plaintext highlighter-rouge">forward_range</code></td>
    </tr>
    <tr>
      <td>  <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2848r1.html"><code class="language-plaintext highlighter-rouge">is_uniqued</code></a></td>
      <td><code class="language-plaintext highlighter-rouge">forward_range</code></td>
    </tr>
    <tr>
      <td>  <code class="language-plaintext highlighter-rouge">adjacent_find</code></td>
      <td><code class="language-plaintext highlighter-rouge">forward_range</code></td>
    </tr>
  </tbody>
</table>

<p>Note that <code class="language-plaintext highlighter-rouge">is_partitioned</code> only needs to view one element at a time, and remember
the boolean value of <code class="language-plaintext highlighter-rouge">pred(elt)</code>. By contrast, <code class="language-plaintext highlighter-rouge">is_sorted</code>, <code class="language-plaintext highlighter-rouge">adjacent_find</code>, and <code class="language-plaintext highlighter-rouge">is_heap</code>
need to view two elements at a time; that’s why they can’t handle <code class="language-plaintext highlighter-rouge">input_range</code>.</p>

<p>The two “could bes” in the table above seem to indicate a design defect.</p>

<h2 id="benchmark-it">Benchmark it!</h2>

<p>libc++’s implementation of <code class="language-plaintext highlighter-rouge">std::is_heap</code> looks <a href="https://github.com/llvm/llvm-project/blob/17e0686ab1107a1a675d8783383dedf70fa24033/libcxx/include/__algorithm/is_heap_until.h#L23-L46">shockingly inefficient</a>:
its 24 lines spend a lot of time recomputing subexpressions like <code class="language-plaintext highlighter-rouge">__first + __c</code> (to get to the <code class="language-plaintext highlighter-rouge">c</code>’th element)
and <code class="language-plaintext highlighter-rouge">2 * __p + 1</code> (to compute the child index from the parent). A straight-line implementation,
avoiding all arithmetic and just advancing two iterators in lockstep,
would have taken only 18 lines:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template &lt;class _Compare, class _ForwardIterator, class _Sentinel&gt;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
__is_heap_until(_ForwardIterator __first, _Sentinel __last, _Compare&amp;&amp; __comp) {
  _ForwardIterator __child = __first;
  if (__child == __last) {
    return __child;
  }
  while (true) {
    ++__child;
    if (__child == __last || __comp(*__first, *__child))
      break;
    ++__child;
    if (__child == __last || __comp(*__first, *__child))
      break;
    ++__first;
  }
  return __child;
}
</code></pre></div></div>

<p>Surprisingly, <a href="https://github.com/gcc-mirror/gcc/blob/319c0f0249cb30c2290426a3a9d4ce81a47a684d/libstdc%2B%2B-v3/include/bits/stl_heap.h#L72-L94">libstdc++</a>
and <a href="https://github.com/microsoft/STL/blob/main/stl/inc/algorithm#L7667-L7679">MS STL</a> also spend time adding and dividing
(or shifting) when they don’t need to.</p>

<p>Still, just because a piece of code <em>looks</em> inefficient doesn’t always mean that it <em>is</em> inefficient.
So I whipped up a simple benchmark:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void BM_vector_half(benchmark::State&amp; state) {
  auto n = state.range(0);
  auto v = std::vector&lt;unsigned&gt;(n);
  std::mt19937 g;
  std::generate(v.begin(), v.end(), g);
  std::make_heap(v.begin(), v.begin() + (n / 2));
  for (auto _ : state) {
    benchmark::DoNotOptimize(v);
    auto it = std::is_heap_until(v.begin(), v.end());
    benchmark::DoNotOptimize(it);
  }
}
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">vector_full</code> is the same but with <code class="language-plaintext highlighter-rouge">make_heap(v.begin(), v.end())</code>.
<code class="language-plaintext highlighter-rouge">deque_{half,full}</code> are the same but with <code class="language-plaintext highlighter-rouge">deque</code> instead of <code class="language-plaintext highlighter-rouge">vector</code>.</p>

<p>Here’s the benchmark result before and after applying the patch above to libc++.
In this case, our eyes don’t lie: what <em>looks</em> inefficient <em>is</em> inefficient!
(Note that our comparator here is <code class="language-plaintext highlighter-rouge">less&lt;int&gt;</code>, which is cheap. An expensive comparator
could dwarf the cost of arithmetic, making the benefit of this patch less perceptible.)</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Benchmark</th>
      <th style="text-align: left"><code class="language-plaintext highlighter-rouge">n</code></th>
      <th style="text-align: right">CPU time (before)</th>
      <th style="text-align: right">CPU time (after)</th>
      <th style="text-align: right">%</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">vector_half</code></td>
      <td style="text-align: left">1K</td>
      <td style="text-align: right">4155 ns</td>
      <td style="text-align: right">2658 ns</td>
      <td style="text-align: right">−36%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">vector_half</code></td>
      <td style="text-align: left">100K</td>
      <td style="text-align: right">311560 ns</td>
      <td style="text-align: right">263807 ns</td>
      <td style="text-align: right">−15%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">vector_half</code></td>
      <td style="text-align: left">10M</td>
      <td style="text-align: right">32487789 ns</td>
      <td style="text-align: right">26089364 ns</td>
      <td style="text-align: right">−19%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">vector_full</code></td>
      <td style="text-align: left">1K</td>
      <td style="text-align: right">8813 ns</td>
      <td style="text-align: right">5294 ns</td>
      <td style="text-align: right">−39%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">vector_full</code></td>
      <td style="text-align: left">100K</td>
      <td style="text-align: right">644535 ns</td>
      <td style="text-align: right">535987 ns</td>
      <td style="text-align: right">−16%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">vector_full</code></td>
      <td style="text-align: left">10M</td>
      <td style="text-align: right">59771100 ns</td>
      <td style="text-align: right">52807359 ns</td>
      <td style="text-align: right">−11%</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">deque_half</code></td>
      <td style="text-align: left">1K</td>
      <td style="text-align: right">4186 ns</td>
      <td style="text-align: right">2662 ns</td>
      <td style="text-align: right">−36%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">deque_half</code></td>
      <td style="text-align: left">100K</td>
      <td style="text-align: right">375844 ns</td>
      <td style="text-align: right">264856 ns</td>
      <td style="text-align: right">−29%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">deque_half</code></td>
      <td style="text-align: left">10M</td>
      <td style="text-align: right">31999750 ns</td>
      <td style="text-align: right">26152052 ns</td>
      <td style="text-align: right">−18%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">deque_full</code></td>
      <td style="text-align: left">1K</td>
      <td style="text-align: right">9002 ns</td>
      <td style="text-align: right">5271 ns</td>
      <td style="text-align: right">−41%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">deque_full</code></td>
      <td style="text-align: left">100K</td>
      <td style="text-align: right">619876 ns</td>
      <td style="text-align: right">523727 ns</td>
      <td style="text-align: right">−15%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">deque_full</code></td>
      <td style="text-align: left">10M</td>
      <td style="text-align: right">65697333 ns</td>
      <td style="text-align: right">52488343 ns</td>
      <td style="text-align: right">−20%</td>
    </tr>
  </tbody>
</table>

<p>Even with the current specification of <code class="language-plaintext highlighter-rouge">is_heap</code>, we can achieve this performance today.
The algorithm can remain <em>constrained</em> on <code class="language-plaintext highlighter-rouge">random_access_range</code>
(thus doing nothing to solve the motivating use-case that introduced this post)
while internally <em>using</em> nothing more than forward-iterator operations.
But once the algorithm uses nothing more than forward-iterator operations…
wouldn’t it be nice for the Standard to say so?</p>

<h2 id="conclusions">Conclusions</h2>

<ul>
  <li>
    <p>libc++ should improve its <code class="language-plaintext highlighter-rouge">is_heap</code> implementation along the lines above,
  reaping the performance benefit.</p>
  </li>
  <li>
    <p>So should libstdc++ and Microsoft STL, I expect.</p>
  </li>
  <li>
    <p>WG21 should consider relaxing the constraint on <code class="language-plaintext highlighter-rouge">is_heap</code> and <code class="language-plaintext highlighter-rouge">is_heap_until</code> from “random access” to “forward,”
  incidentally solving my original use-case. I’ll probably bring a paper to this effect at some point.
  Note that if such a paper were adopted, all three vendors would <em>have</em> to change their
  implementations to the faster one.</p>
  </li>
</ul>

<hr />

<p>UPDATE, 2026-07-07: Louis Dionne has added an official libc++ benchmark for <code class="language-plaintext highlighter-rouge">is_heap</code>
(<a href="https://github.com/llvm/llvm-project/pull/207045">llvm-project#207045</a>).</p>

<table class="smaller">
  <thead>
    <tr>
      <th style="text-align: left">Benchmark</th>
      <th style="text-align: right">CPU time (before)</th>
      <th style="text-align: right">CPU time (after)</th>
      <th style="text-align: right">%</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap(vector&lt;int&gt;)/8192</code></td>
      <td style="text-align: right">2366 ns</td>
      <td style="text-align: right">2382 ns</td>
      <td style="text-align: right">+1%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap(deque&lt;int&gt;)/8192</code></td>
      <td style="text-align: right">4442 ns</td>
      <td style="text-align: right">4307 ns</td>
      <td style="text-align: right">−3%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap(vector&lt;int&gt;, pred)/8192</code></td>
      <td style="text-align: right">3802 ns</td>
      <td style="text-align: right">3743 ns</td>
      <td style="text-align: right">−2%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap(deque&lt;int&gt;, pred)/8192</code></td>
      <td style="text-align: right">6864 ns</td>
      <td style="text-align: right">5397 ns</td>
      <td style="text-align: right">−21%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap_until(vector&lt;int&gt;)/8192</code></td>
      <td style="text-align: right">2420 ns</td>
      <td style="text-align: right">2386 ns</td>
      <td style="text-align: right">−1%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap_until(deque&lt;int&gt;)/8192</code></td>
      <td style="text-align: right">4702 ns</td>
      <td style="text-align: right">4225 ns</td>
      <td style="text-align: right">−10%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap_until(vector&lt;int&gt;, pred)/8192</code></td>
      <td style="text-align: right">3755 ns</td>
      <td style="text-align: right">3760 ns</td>
      <td style="text-align: right">+0%</td>
    </tr>
    <tr>
      <td style="text-align: left"><code class="language-plaintext highlighter-rouge">is_heap_until(deque&lt;int&gt;, pred)/8192</code></td>
      <td style="text-align: right">6911 ns</td>
      <td style="text-align: right">5392 ns</td>
      <td style="text-align: right">−22%</td>
    </tr>
  </tbody>
</table>]]></content><author><name></name></author><category term="benchmarks" /><category term="library-design" /><category term="proposal" /><category term="stl-classic" /><summary type="html"><![CDATA[`is_sorted` doesn't require random access; why should `is_heap`?]]></summary></entry><entry><title type="html">Two-Minute _Iolanthe_</title><link href="https://quuxplusone.github.io/blog/2026/05/08/two-minute-iolanthe/" rel="alternate" type="text/html" title="Two-Minute _Iolanthe_" /><published>2026-05-08T00:01:00+00:00</published><updated>2026-05-08T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/05/08/two-minute-iolanthe</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/05/08/two-minute-iolanthe/"><![CDATA[<p>The other day I came across Connie Kleinjans’ <a href="https://www.misosoup.com/connie/TwoMin/TwoMin.html">page of “two-minute versions”</a>
of G&amp;S shows. She’s got two versions of <em>Gondoliers</em> and one each of <em>Iolanthe</em> and <em>Ruddigore</em>.
The technique is the same as in <a href="https://en.wikipedia.org/wiki/Blackout_poetry">blackout poetry</a>:
take the whole work and black out all but the most important and/or funniest bits.</p>

<p><img src="/blog/images/2026-05-08-iolanthe-blackout.png" alt="" /></p>

<p>Kleinjans’ short scripts are funny in their own rights, but I wanted audio versions; so I made one.
Presenting <a href="https://www.youtube.com/watch?v=lhXP-kBlt5k">“Two-Minute <em>Iolanthe</em> in five minutes”</a>.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/lhXP-kBlt5k" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>The <a href="https://www.youtube.com/watch?v=DLYSZN2IqeU">original recording</a> I “blacked out” for this
video is a TV broadcast of a 1976 production at the Sydney Opera House featuring Rosemary Gunn
(Iolanthe), Heather Begg (Fairy Queen), Dennis Olsen (the Lord Chancellor), June Bronhill (Phyllis),
Lyndon Terracini (Strephon), Graeme Ewer (Mountararat), Ronald Maconaghie (Tolloller), and
Alan Light (Private Willis). This is a low-quality VHS rip of an excellent performance.</p>

<p>The VHS rip on YouTube is missing a chunk of the finale, which
prompted some alterations to the script; I made a few other alterations for pacing. Even after
those cuts, this “two-minute” <em>Iolanthe</em> is almost five minutes long; watch at 2.3x speed for
a true two-minute experience.</p>

<hr />

<p>To create the video, I used <code class="language-plaintext highlighter-rouge">ffmpeg</code> to clip and concat the snippets. When concatenating 169 tiny snippets,
your biggest problem will be “timestamp drift” between the audio and video channels. I spent a long
time cajoling ChatGPT into giving me new permutations of command-line switches to try before finally
settling on the programs linked below.</p>

<p>Step 1 was to get the original video (2.4 gigabytes, saved as <code class="language-plaintext highlighter-rouge">input.mkv</code>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew install ffmpeg yt-dlp
yt-dlp 'https://www.youtube.com/watch?v=DLYSZN2IqeU'
</code></pre></div></div>

<p>Step 2 was to snip the constituent bits via <code class="language-plaintext highlighter-rouge">ffmpeg</code> commands. I factored out the common arguments
into environment variables so I didn’t have to keep typing or tabbing over them.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PREFIX="-y"
SUFFIX="-i input.mkv -c:v libx264 -preset veryfast -crf 20 -c:a aac"
ffmpeg $PREFIX -ss 00:07:07.2 -to 00:07:10.5 $SUFFIX part001.mkv
ffmpeg $PREFIX -ss 00:07:45.0 -to 00:07:48.6 $SUFFIX part002.mkv
~~~~
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ffmpeg</code> turns out to be supremely sensitive to whether you put the input
(<code class="language-plaintext highlighter-rouge">-i input.mkv</code>) before, or after, the <code class="language-plaintext highlighter-rouge">-ss</code> and <code class="language-plaintext highlighter-rouge">-to</code> switches. With <code class="language-plaintext highlighter-rouge">-i input.mkv</code> as
part of the <code class="language-plaintext highlighter-rouge">SUFFIX</code>, my whole script.txt runs in 61 seconds; as part of the <code class="language-plaintext highlighter-rouge">PREFIX</code>,
it takes 98 <em>minutes.</em></p>

<p>To concatenate all those clips and re-encode a “preview” video, we can do this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm list.txt
for i in part*.mkv ; do echo "file $i" &gt;&gt;list.txt ; done
ffmpeg -y -f concat -safe 0 -i list.txt \
  -c:v libx264 -crf 20 -preset veryfast -c:a aac -ar 48000 output.mp4
</code></pre></div></div>

<p>Step 3 was to fight timestamp desynchronization. My solution here was generated entirely
by blind fumbling and incantations, with input from ChatGPT. It seems that there are
basically two ways to get <code class="language-plaintext highlighter-rouge">ffmpeg</code> to “supercut” a video as we’re doing here: either
clip out the clips into temporary files and then concatenate all those little files
(as we did above — this way causes a lot of drift), or do one big “filter” operation
to take just the frames you care about in a single <code class="language-plaintext highlighter-rouge">ffmpeg</code> invocation. That looks like
this, except with 169 clips instead of 3:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ffmpeg -y -i input.mkv -filter_complex \
 "[0:v]trim=start=427.2:end=430.5,setpts=PTS-STARTPTS[v0];
  [0:a]atrim=start=427.2:end=430.5,asetpts=PTS-STARTPTS[a0];
  [0:v]trim=start=465.0:end=468.6,setpts=PTS-STARTPTS[v1];
  [0:a]atrim=start=465.0:end=468.6,asetpts=PTS-STARTPTS[a1];
  [0:v]trim=start=616.5:end=618.7,setpts=PTS-STARTPTS[v2];
  [0:a]atrim=start=616.5:end=618.7,asetpts=PTS-STARTPTS[a2];
  [v0][a0][v1][a1][v2][a2]concat=n=3:v=1:a=1[v][a]"
  -map [v] -map [a] \
  -c:v libx264 -crf 20 -preset veryfast \
  -c:a aac -b:a 192k -ar 48000 \
  output.mp4
</code></pre></div></div>

<p>That’s horribly slow; it seems to have quadratic behavior as the number of clips
increases. Even worse is trying to use the non-“<code class="language-plaintext highlighter-rouge">complex</code>” filter options <code class="language-plaintext highlighter-rouge">-vf</code> and <code class="language-plaintext highlighter-rouge">-af</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ffmpeg -y -i input.mkv \
  -vf "select=between(t,427.2,430.5)+between(t,465.0,468.6)+between(t,616.5,618.7),setpts=N/FRAME_RATE/TB" \
  -af "aselect=between(t,427.2,430.5)+between(t,465.0,468.6)+between(t,616.5,618.7),asetpts=N/SR/TB" \
  -c:v libx264 -crf 20 -preset veryfast \
  -c:a aac -b:a 192k -ar 48000 \
  output.mp4
</code></pre></div></div>

<p>That just makes <code class="language-plaintext highlighter-rouge">ffmpeg</code> run out of memory before you’ve even hit 50 clips.
So I ended up using a hybrid approach: I used <code class="language-plaintext highlighter-rouge">-filter_complex</code> to produce
nine intermediate concatenations of 20 clips at a time, and then used</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ffmpeg -y -f concat -i list.txt -c copy output.mp4
</code></pre></div></div>

<p>to paste those nine files together. I’ve saved my programs for posterity:
<a href="/blog/code/2026-05-08-iolanthe-script.txt">script.txt</a> runs as a Bash script
(in just over 1 minute on my machine) to create that “draft preview” video output;
its textual contents also serve as input to <a href="/blog/code/2026-05-08-iolanthe-script.py">script.py</a>,
which creates the final product (in about 9 minutes) using the two-level <code class="language-plaintext highlighter-rouge">-filter_complex</code>
approach. The finished <code class="language-plaintext highlighter-rouge">output.mp4</code> is about 42 megabytes in size.</p>]]></content><author><name></name></author><category term="gilbert-and-sullivan" /><category term="how-to" /><category term="jokes" /><category term="memes" /><category term="television" /><category term="web" /><summary type="html"><![CDATA[The other day I came across Connie Kleinjans’ page of “two-minute versions” of G&amp;S shows. She’s got two versions of Gondoliers and one each of Iolanthe and Ruddigore. The technique is the same as in blackout poetry: take the whole work and black out all but the most important and/or funniest bits.]]></summary></entry><entry><title type="html">C++ Alignment Chart</title><link href="https://quuxplusone.github.io/blog/2026/05/06/cpp-alignment-chart/" rel="alternate" type="text/html" title="C++ Alignment Chart" /><published>2026-05-06T00:01:00+00:00</published><updated>2026-05-06T00:01:00+00:00</updated><id>https://quuxplusone.github.io/blog/2026/05/06/cpp-alignment-chart</id><content type="html" xml:base="https://quuxplusone.github.io/blog/2026/05/06/cpp-alignment-chart/"><![CDATA[<p><img src="/blog/images/2026-05-06-alignment-chart.jpg" alt="" class="meme" /></p>]]></content><author><name></name></author><category term="alignment" /><category term="memes" /><summary type="html"><![CDATA[]]></summary></entry></feed>