{"id":111955,"date":"2026-01-01T07:00:00","date_gmt":"2026-01-01T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111955"},"modified":"2026-01-03T07:55:49","modified_gmt":"2026-01-03T15:55:49","slug":"20260101-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260101-00\/?p=111955","title":{"rendered":"Swapping two blocks of memory that reside inside a larger block, in constant memory"},"content":{"rendered":"<p>Suppose you have a large block of memory, and you want to swap two blocks that reside inside that large block. For concreteness, say you have a block of memory of the form A1, A2, B1, B2, C1, C2, D1, D2, D3, E1, and you want to swap the B&#8217;s and D&#8217;s, producing A1, A2, D1, D2, D3, C1, C2, B1, B2, E1.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" title=\"See text above\" border=\"0\" cellspacing=\"0\" cellpadding=\"1\">\n<tbody>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<p><!-- weird structure of these separators to work around WordPress \"assistance\" --><\/p>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"2\"><!-- --><\/td>\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"3\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td colspan=\"4\">\u00a0<\/td>\n<td colspan=\"1\">\u00a0<\/td>\n<td colspan=\"1\">\u2929<\/td>\n<td colspan=\"4\">\u00a0<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"3\"><!-- --><\/td>\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"2\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Like, say, you have a double-null-terminated string and you want to swap two strings in it. Now, of course, the easy way would be just to allocate a second buffer equal in size to the original buffer and copy the strings to the second buffer in the desired order. But just as an exercise, can you do this without allocating additional memory?<\/p>\n<p>Here&#8217;s a hint: There is an algorithm to swap two <i>adjacent<\/i> buffers using no additional space. In C++, this algorithm is implemented by the <code>std::<wbr \/>rotate<\/code> method. For example, if you have a block of memory of the form X1, X2, Y1, Y2, Y3, then you can call <code>std::rotate(v.begin(), v.begin() + 2, v.end())<\/code> to get Y1, Y2, Y3, X1, X2.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" title=\"See text above\" border=\"0\" cellspacing=\"0\" cellpadding=\"1\">\n<tbody>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">Y2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y3<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"5\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"3\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td colspan=\"5\">\u2929<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"3\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"2\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">Y2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The function is called <code>rotate<\/code> because you can view it as taking the combined buffer and doing a circular rotation until Y1 is the new first element.<\/p>\n<p>You can perform the desired exchange of non-adjacent blocks by performing three rotations. Starting with A1, A2, B1, B2, C1, C2, D1, D2, D3, E1, your first rotation exchanges the B&#8217;s with the C&#8217;s: your second rotation exchanges the B&#8217;s with the D&#8217;s, and your final rotation exchanges the C&#8217;s with the D&#8217;s.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" title=\"See text\" border=\"0\" cellspacing=\"0\" cellpadding=\"1\">\n<tbody>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"2\"><!-- --><\/td>\n<td colspan=\"3\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td colspan=\"3\">\u00a0<\/td>\n<td colspan=\"2\">\u2929<\/td>\n<td colspan=\"4\">\u00a0<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"2\"><!-- --><\/td>\n<td colspan=\"3\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"3\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td colspan=\"4\">\u00a0<\/td>\n<td colspan=\"5\">\u2929<\/td>\n<td colspan=\"1\">\u00a0<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"3\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"2\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none;\" colspan=\"3\"><!-- --><\/td>\n<td colspan=\"2\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\">\u00a0<\/td>\n<td colspan=\"5\">\u2929<\/td>\n<td colspan=\"3\">\u00a0<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"3\"><!-- --><\/td>\n<td style=\"border: solid 1px currentcolor; border-bottom: none;\" colspan=\"2\"><!-- --><\/td>\n<td colspan=\"2\"><!-- --><\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>(There are other ways to accomplish this with three rotations.)<\/p>\n<p>But you can do better.<\/p>\n<p>The way rotation works is by reversing the two buffers separately, and then reversing the combined buffer. Starting with X1, X2, Y1, Y2, Y3, we reverse the X&#8217;s (producing X2, X1) and reverse the Y&#8217;s (producing Y3, Y2, Y1), and then reverse the whole thing, giving a final result of Y1, Y2, Y3, X1, X2.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" title=\"See text above\" border=\"0\" cellspacing=\"0\" cellpadding=\"1\">\n<tbody>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">Y2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y3<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"5\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: none solid;\" colspan=\"2\">\u21c6<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid;\" colspan=\"3\">\u21c6<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"5\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">Y2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y1<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"5\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: none solid;\" colspan=\"5\">\u21c6<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"5\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">Y2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">Y3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">X2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The cost of reversing <var>n<\/var> elements is <var>n<\/var>\/2 swaps, so the cost of a rotation of <var>n<\/var> elements is <var>n<\/var> swaps. (You reverse the first part and the second part, which together add up to <var>n<\/var>\/2 swaps; and then you reverse the whole thing, which is another <var>n<\/var>\/2 swaps, for a total of <var>n<\/var>.)<\/p>\n<p>Therefore, our three-rotation version costs a total of 2<var>n<\/var> swaps, where <var>n<\/var> is the combined size of the two blocks being swapped as well as the block that is sandwiched between them.<\/p>\n<p>We can reduce the cost to <var>n<\/var> swaps by applying the reversal trick directly: Reverse the two blocks, reverse the block that is sandwiched between them, and then reverse the combo block.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" title=\"See text above\" border=\"0\" cellspacing=\"0\" cellpadding=\"1\">\n<tbody>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid;\" colspan=\"2\">\u21c4<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid;\" colspan=\"2\">\u21c4<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid;\" colspan=\"3\">\u21c4<\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\"><!-- --><\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid;\" colspan=\"7\">\u21c4<\/td>\n<td colspan=\"1\"><!-- --><\/td>\n<\/tr>\n<tr style=\"height: 1ex;\">\n<td colspan=\"10\"><!-- --><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">A2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, lch(from currentcolor l c h \/ .2), lch(from currentcolor l c h \/ .2) .5em, transparent .5em, transparent 1em);\">D2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background-image: repeating-linear-gradient(45deg, transparent, transparent .5em, lch(from currentcolor l c h \/ .2) .5em, lch(from currentcolor l c h \/ .2) 1em);\">D3<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">C2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B1<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor; background: lch(from currentcolor l c h \/ .1);\">B2<\/td>\n<td style=\"width: 2em; border: solid 1px currentcolor;\">E1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre>template&lt;typename BiDirIt&gt;\r\nvoid swap_discontiguous(BiDirIt first1, BiDirIt last1,\r\n                        BiDirIt first2, BiDirIt last2)\r\n{\r\n    std::reverse(first1, last1);\r\n    std::reverse(last1, first2);\r\n    std::reverse(first2, last2);\r\n    std::reverse(first1, last2);\r\n}\r\n<\/pre>\n<p>But wait. If you look at the specification for <code>std::<wbr \/>rotate<\/code>, you see that it requires only a forward iterator, not a bidirectional iterator. Yet <code>std::<wbr \/>reverse<\/code> requires a bidirectional iterator. So how does <code>std::<wbr \/>rotate<\/code> operate if it is given only forward iterators? We&#8217;ll look at that next time.<\/p>\n<p><b>Bonus chatter<\/b>: <a href=\"https:\/\/github.com\/llvm\/llvm-project\/blob\/682c8e22e61f50ce2d9a0c42475a3aa6d578a1ad\/libcxx\/include\/__algorithm\/rotate.h\"> clang&#8217;s libcxx<\/a> and <a href=\"https:\/\/github.com\/gcc-mirror\/gcc\/blob\/master\/libstdc%2B%2B-v3\/include\/bits\/stl_algo.h\"> gcc&#8217;s libstdc++<\/a> contain specializations of <code>std::<wbr \/>rotate<\/code> for random-access iterators which perform only <var>n<\/var>\/2 swaps, moving each element directly to its final destination by breaking the element movements into disjoint cycles and then moving the elements within each cycle. They also have special-cases for rotating zero elements (nop), as well as rotating a single element and swapping two equal-sized blocks (which reduces the number of swaps to <var>n<\/var>\/2). I guess these cases happen often enough for the extra code to be worth it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A variation on the constant-memory rotation.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-111955","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A variation on the constant-memory rotation.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111955","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=111955"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111955\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=111955"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111955"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111955"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}