2019-09-09 10:22:36 +10:00
|
|
|
/*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*
|
|
|
|
* Copyright 2019 Danny Robson <danny@nerdcruft.net>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "list/sort.hpp"
|
|
|
|
#include "random.hpp"
|
|
|
|
#include "tap.hpp"
|
|
|
|
#include "iterator/zip.hpp"
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template <std::size_t N, typename ...ArgsT>
|
|
|
|
static void
|
|
|
|
test_sort (
|
|
|
|
cruft::TAP::logger &tap,
|
|
|
|
std::vector<int> &&data,
|
|
|
|
char const (&fmt)[N],
|
|
|
|
ArgsT&&...args
|
|
|
|
) {
|
|
|
|
// Pre-allocate the array so that we don't get caught by pointer
|
|
|
|
// invalidation as we build the nodes.
|
|
|
|
std::vector<
|
2019-09-10 14:43:08 +10:00
|
|
|
cruft::list::node::compound<int>
|
2019-09-09 10:22:36 +10:00
|
|
|
> nodes (data.size ());
|
|
|
|
|
|
|
|
// Build the list and fold in the supplied data.
|
|
|
|
for (auto [node, value]: cruft::iterator::zip (nodes, data)) {
|
|
|
|
node.next = &node + 1;
|
|
|
|
node.data = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
nodes.back ().next = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
// Actually do the sort and test the result.
|
|
|
|
auto head = cruft::list::sort (
|
|
|
|
&nodes.front (),
|
|
|
|
&nodes.back ()
|
|
|
|
);
|
|
|
|
|
|
|
|
tap.expect (
|
2019-09-10 14:43:08 +10:00
|
|
|
cruft::list::is_sorted (head),
|
2019-09-09 10:22:36 +10:00
|
|
|
fmt,
|
|
|
|
std::forward<ArgsT> (args)...
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int main ()
|
|
|
|
{
|
|
|
|
cruft::TAP::logger tap;
|
|
|
|
|
|
|
|
// Try sorting a 'large' array of unique, but shuffled, contiguous integers.
|
|
|
|
{
|
|
|
|
// Don't use a power of two here. It won't exercise any edge cases in
|
|
|
|
// the splitting logic of some sorts (like merge).
|
|
|
|
static constexpr int COUNT = 500'000;
|
|
|
|
|
|
|
|
// Create a list of randomly distributed integers. Use a constant seed so
|
|
|
|
// we don't get randomised test results.
|
|
|
|
std::vector<int> data (COUNT);
|
|
|
|
std::iota (std::begin (data), std::end (data), 0);
|
|
|
|
std::shuffle (
|
|
|
|
std::begin (data),
|
|
|
|
std::end (data),
|
|
|
|
std::mt19937 {COUNT}
|
|
|
|
);
|
|
|
|
|
|
|
|
test_sort (tap, std::move (data), "sorting large unique and shuffled array");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try sorting a small array with identical elements
|
|
|
|
{
|
|
|
|
static constexpr int COUNT = 15;
|
|
|
|
std::vector<int> data (COUNT, COUNT);
|
|
|
|
test_sort (tap, std::move (data), "sorting small identical array");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tap.status ();
|
|
|
|
}
|