+=head2 C<vshift>
+
+ vshift $v, $start, $length => $bits, $insert;
+
+In the area starting at C<$start> and of length C<$length> in C<$v>, shift bits C<abs $bits> positions left if C<< $bits > 0 >> and right otherwise.
+
+When C<$insert> is defined, the resulting gap is also filled with ones if C<$insert> is true and with zeros if C<$insert> is false.
+
+C<$v> is upgraded to a string if it isn't one already.
+If C<$start + $length> goes out of the bounds of C<$v>, then the extra bits are treated as zeros.
+Bits that are outside of the specified area are left untouched.
+
+This function does not need to allocate any extra memory.
+
+=cut
+
+sub vshift ($$$$;$) {
+ my ($start, $length, $bits, $insert) = @_[1 .. 4];
+ return unless $length and $bits;
+ croak 'Invalid negative offset' if $start < 0;
+ croak 'Invalid negative length' if $length < 0;
+ my $left = 1;
+ if ($bits < 0) {
+ $left = 0;
+ $bits = -$bits;
+ }
+ if ($bits < $length) {
+ $length -= $bits;
+ if ($left) {
+ vcopy($_[0], $start, $_[0], $start + $bits, $length);
+ vfill($_[0], $start, $bits, $insert) if defined $insert;
+ } else {
+ vcopy($_[0], $start + $bits, $_[0], $start, $length);
+ vfill($_[0], $start + $length, $bits, $insert) if defined $insert;
+ }
+ } else {
+ vfill($_[0], $start, $length, $insert) if defined $insert;
+ }
+}
+
+=head2 C<vrot>
+
+ vrot $v, $start, $length, $bits;
+
+In the area starting at C<$start> and of length C<$length> in C<$v>, rotates bits C<abs $bits> positions left if C<< $bits > 0 >> and right otherwise.
+
+C<$v> is upgraded to a string if it isn't one already.
+If C<$start + $length> goes out of the bounds of C<$v>, then the extra bits are treated as zeros.
+Bits that are outside of the specified area are left untouched.
+
+This function currently allocates an extra buffer of size C<O($bits)>.
+
+=cut
+
+sub vrot ($$$$) {
+ my ($start, $length, $bits) = @_[1 .. 3];
+ return unless $length and $bits;
+ croak 'Invalid negative offset' if $start < 0;
+ croak 'Invalid negative length' if $length < 0;
+ my $left = 1;
+ if ($bits < 0) {
+ $left = 0;
+ $bits = -$bits;
+ }
+ $bits %= $length;
+ return unless $bits;
+ $length -= $bits;
+ my $buf = '';
+ if ($left) {
+ vcopy($_[0], $start + $length, $buf, 0, $bits);
+ vcopy($_[0], $start, $_[0], $start + $bits, $length);
+ vcopy($buf, 0, $_[0], $start, $bits);
+ } else {
+ vcopy($_[0], $start, $buf, 0, $bits);
+ vcopy($_[0], $start + $bits, $_[0], $start, $length);
+ vcopy($buf, 0, $_[0], $start + $length, $bits);
+ }
+}
+
+=head2 C<veq>
+
+ veq $v1 => $v1_start, $v2 => $v2_start, $length;