docs: public void permute(final PermutationProxy proxy) {
      checkArgument(numElements() == proxy.length());
  
      final boolean[] seen = new boolean[numElements()];
  
      for (int startIdx = 0; startIdx < seen.length; ++startIdx) {
        if (!seen[startIdx]) {
          // starting at any element, we can follow the chain of sources
          // in a cycle
          int curIdx = startIdx;
          // we have to save the data in our starting spot
          // because it will be overwritten by the time
          // we encounter the last element in the cycle, which
          // will need them
          proxy.shiftIntoTemporaryBufferFrom(startIdx);
          while (true) {
            seen[curIdx] = true;
            final int sourceIdx = sourceOfIndex(curIdx);
            if (sourceIdx == startIdx) {
              // completed the cycle
              proxy.shiftOutOfTemporaryBufferTo(curIdx);
              break;
            } else {
              // shift data from source to cur index
              proxy.shift(sourceIdx, curIdx);
              curIdx = sourceIdx;
            }
          }
        }
      }
    }