Skip to content

Commit

Permalink
Merge pull request #3112 from andralex/between
Browse files Browse the repository at this point in the history
Testing whether a few given values are ordered
  • Loading branch information
MartinNowak committed Apr 19, 2015
2 parents fbd0e04 + d54047a commit 41d1162
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 4 deletions.
1 change: 1 addition & 0 deletions std/algorithm/comparison.d
Expand Up @@ -221,6 +221,7 @@ Params:
handlers that accept one argument. There can also be a choice that
accepts zero arguments. That choice will be invoked if the $(D
switchObject) is null.
switchObject = the object against which the tests are being made.
Returns:
The value of the selected choice.
Expand Down
82 changes: 78 additions & 4 deletions std/algorithm/sorting.d
Expand Up @@ -193,6 +193,80 @@ bool isSorted(alias less = "a < b", Range)(Range r) if (isForwardRange!(Range))
assert(isSorted(s)); // bidirectional
}

/**
Like $(D isSorted), returns $(D true) if the given $(D values) are ordered
according to the comparison operation $(D less). Unlike $(D isSorted), takes values
directly instead of structured in a range.
$(D ordered) allows repeated values, e.g. $(D ordered(1, 1, 2)) is $(D true). To verify
that the values are ordered strictly monotonically, use $(D strictlyOrdered);
$(D strictlyOrdered(1, 1, 2)) is $(D false).
With either function, the predicate must be a strict ordering just like with $(D isSorted). For
example, using $(D "a <= b") instead of $(D "a < b") is incorrect and will cause failed
assertions.
Params:
values = The tested value
less = The comparison predicate
Returns:
$(D true) if the values are ordered; $(D ordered) allows for duplicates,
$(D strictlyOrdered) does not.
*/

bool ordered(alias less = "a < b", T...)(T values)
if ((T.length == 2 && is(typeof(binaryFun!less(values[1], values[0])) : bool))
||
(T.length > 2 && is(typeof(ordered!less(values[0 .. 1 + $ / 2])))
&& is(typeof(ordered!less(values[$ / 2 .. $]))))
)
{
foreach (i, _; T[0 .. $ - 1])
{
if (binaryFun!less(values[i + 1], values[i]))
{
assert(!binaryFun!less(values[i], values[i + 1]),
__FUNCTION__ ~ ": incorrect non-strict predicate.");
return false;
}
}
return true;
}

/// ditto
bool strictlyOrdered(alias less = "a < b", T...)(T values)
if (is(typeof(ordered!less(values))))
{
foreach (i, _; T[0 .. $ - 1])
{
if (!binaryFun!less(values[i], values[i + 1]))
{
return false;
}
assert(!binaryFun!less(values[i + 1], values[i]),
__FUNCTION__ ~ ": incorrect non-strict predicate.");
}
return true;
}

///
unittest
{
assert(ordered(42, 42, 43));
assert(!strictlyOrdered(43, 42, 45));
assert(ordered(42, 42, 43));
assert(!strictlyOrdered(42, 42, 43));
assert(!ordered(43, 42, 45));
// Ordered lexicographically
assert(ordered("Jane", "Jim", "Joe"));
assert(strictlyOrdered("Jane", "Jim", "Joe"));
// Incidentally also ordered by length decreasing
assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
// ... but not strictly so: "Jim" and "Joe" have the same length
assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
}

// partition
/**
Partitions a range in two using $(D pred) as a
Expand Down Expand Up @@ -1229,19 +1303,19 @@ private template TimSortImpl(alias pred, R)
immutable run3 = stackLen - 2;
immutable run2 = stackLen - 3;
immutable run1 = stackLen - 4;
if ( (stackLen > 2 && stack[run2].length <= stack[run3].length + stack[run4].length) ||

if ( (stackLen > 2 && stack[run2].length <= stack[run3].length + stack[run4].length) ||
(stackLen > 3 && stack[run1].length <= stack[run3].length + stack[run2].length) )
{
immutable at = stack[run2].length < stack[run4].length ? run2 : run3;
mergeAt(range, stack[0 .. stackLen], at, minGallop, temp);
}
else if (stack[run3].length > stack[run4].length) break;
else mergeAt(range, stack[0 .. stackLen], run3, minGallop, temp);

stackLen -= 1;
}

// Assert that the code above established the invariant correctly
version (assert)
{
Expand Down

0 comments on commit 41d1162

Please sign in to comment.