feature. See also
. The project being documented here (as the example) is the Zig library itself.
block.mergeInPlace
fn mergeInPlace(
comptime T: type,
items: []T,
A_arg: Range,
B_arg: Range,
context: anytype,
comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool,
) void
File
Code
fn mergeInPlace(
comptime T: type,
items: []T,
A_arg: Range,
B_arg: Range,
context: anytype,
comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool,
) void {
if (A_arg.length() == 0 or B_arg.length() == 0) return;
// the paper suggests using the 'rotation-based Hwang and Lin algorithm' here,
// but I decided to stick with this because it had better situational performance
//
// (Hwang and Lin is designed for merging subarrays of very different sizes,
// but WikiSort almost always uses subarrays that are roughly the same size)
//
// normally this is incredibly suboptimal, but this function is only called
// when none of the A or B blocks in any subarray contained 2√A unique values,
// which places a hard limit on the number of times this will ACTUALLY need
// to binary search and rotate.
//
// according to my analysis the worst case is √A rotations performed on √A items
// once the constant factors are removed, which ends up being O(n)
//
// again, this is NOT a general-purpose solution – it only works well in this case!
// kind of like how the O(n^2) insertion sort is used in some places
var A = A_arg;
var B = B_arg;
while (true) {
const mid = binaryFirst(T, items, items[A.start], B, context, lessThan);
const amount = mid - A.end;
mem.rotate(T, items[A.start..mid], A.length());
if (B.end == mid) break;
B.start = mid;
A = Range.init(A.start + amount, B.start);
A.start = binaryLast(T, items, items[A.start], A, context, lessThan);
if (A.length() == 0) break;
}
}