std::flip
Monday, September 29, 2025
Morwenn posted a blog about implementing a
std::flip
operation in C++:
This is basically walking up the tree from the child node as if it were a linked list. The reverse operation either implies walking through two children nodes, or simply flipping the order of parameters, which is where
std::flip
intervenes:auto is_descendant_of = std::flip(is_ancestor_of); // This property should always hold assert(is_descendant_of(node1, node2) == is_ancestor_of(node2, node1));
Spoiler: the std::flip
operator is not part of the C++ standard
library, although an implementation is
providing at the end of the blog post in around 90 lines of code.
Still, I thought it would be fun to implement in Factor.
As it turns out, we already have a
flip word that
modifies a sequence, essentially by returning the transpose of a matrix. One
could argue that
transpose
might be a better name for that operation. In any event, let’s focus on
implementing the std::flip
operation.
How would we reverse the arguments to a word?
a b
can becomeb a
by callingswap
.a b c
can becomec b a
by callingswap rot
.a b c d
can becomed c b a
by callingswap rot roll
.
We can generalize this into a macro by repeatedly calling -nrot:
MACRO: reverse-stack ( n -- quot )
0 [a..b) [ '[ _ -nrot ] ] map [ ] concat-as ;
And then show that it works:
IN: scratchpad { } [ 0 reverse-stack ] with-datastack .
{ }
IN: scratchpad { "a" } [ 1 reverse-stack ] with-datastack .
{ "a" }
IN: scratchpad { "a" "b" } [ 2 reverse-stack ] with-datastack .
{ "b" "a" }
IN: scratchpad { "a" "b" "c" } [ 3 reverse-stack ] with-datastack .
{ "c" "b" "a" }
IN: scratchpad { "a" "b" "c" "d" } [ 4 reverse-stack ] with-datastack .
{ "d" "c" "b" "a" }
IN: scratchpad { "a" "b" "c" "d" "e" } [ 5 reverse-stack ] with-datastack .
{ "e" "d" "c" "b" "a" }
Using this, we can build some syntax that takes the next token and searches for a matching word with that name, and then calls it after reversing the inputs:
SYNTAX: flip:
scan-word [ stack-effect in>> length ] keep
'[ _ reverse-stack _ execute ] append! ;
As an example, we will use the 4array word that returns an array consisting of four arguments from the stack.
IN: scratchpad 10 20 30 40 4array .
{ 10 20 30 40 }
IN: scratchpad 10 20 30 40 flip: 4array .
{ 40 30 20 10 }
And only 5 lines of code in total.
Pretty cool!