1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
// Range v3 library
//
// Copyright Eric Niebler 2013-present
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/ericniebler/range-v3
//
#include <chrono>
#include <iostream>
#include <random>
#include <range/v3/all.hpp>
RANGES_DIAGNOSTIC_IGNORE_SIGN_CONVERSION
class timer
{
public:
using clock_t = std::chrono::high_resolution_clock;
using duration_t = clock_t::time_point::duration;
timer()
{
reset();
}
void reset()
{
start_ = clock_t::now();
}
duration_t elapsed() const
{
return clock_t::now() - start_;
}
friend std::ostream &operator<<(std::ostream &sout, timer const &t)
{
return sout << t.elapsed().count() << "ms";
}
private:
clock_t::time_point start_;
};
template<typename D>
std::chrono::milliseconds::rep to_millis(D d) {
return std::chrono::duration_cast<std::chrono::milliseconds>(d).count();
}
template<typename It>
struct forward_iterator
{
It it_;
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
forward_iterator() = default;
explicit forward_iterator(It it) : it_(std::move(it)) {}
reference operator*() const {return *it_;}
pointer operator->() const {return it_;}
forward_iterator& operator++() {++it_; return *this;}
forward_iterator operator++(int)
{forward_iterator tmp(*this); ++(*this); return tmp;}
friend bool operator==(const forward_iterator& x, const forward_iterator& y)
{return x.it_ == y.it_;}
friend bool operator!=(const forward_iterator& x, const forward_iterator& y)
{return !(x == y);}
};
template<typename I, typename V2>
I upper_bound_n(I first, typename std::iterator_traits<I>::difference_type d, V2 const &val)
{
while(0 != d)
{
auto half = d / 2;
auto middle = std::next(first, half);
if(val < *middle)
d = half;
else
{
first = ++middle;
d -= half + 1;
}
}
return first;
}
template<typename I>
void insertion_sort_n(I first, typename std::iterator_traits<I>::difference_type n)
{
auto m = 0;
for(auto it = first; m != n; ++it, ++m)
{
auto insertion = upper_bound_n(first, m, *it);
ranges::rotate(insertion, it, std::next(it));
}
}
template<typename I, typename S>
void insertion_sort(I first, S last)
{
for(auto it = first; it != last; ++it)
{
auto insertion = ranges::upper_bound(first, it, *it);
ranges::rotate(insertion, it, std::next(it));
}
}
template<typename Rng>
void insertion_sort(Rng && rng)
{
::insertion_sort(std::begin(rng), std::end(rng));
}
std::unique_ptr<int> data(int i)
{
std::unique_ptr<int> a(new int[i]);
auto rng = ranges::views::counted(a.get(), i);
ranges::iota(rng, 0);
return a;
}
template<typename Gen>
void shuffle(int *a, int i, Gen && rand)
{
auto rng = ranges::views::counted(a, i);
rng |= ranges::actions::shuffle(std::forward<Gen>(rand));
}
constexpr int cloops = 3;
template<typename I>
void benchmark_n(int i)
{
std::mt19937 gen;
auto a = data(i);
timer::duration_t ms = {};
for(int j = 0; j < cloops; ++j)
{
::shuffle(a.get(), i, gen);
timer t;
insertion_sort_n(I{a.get()}, i);
ms += t.elapsed();
}
std::cout << to_millis(ms/cloops) << std::endl;
}
template<typename I>
void benchmark_counted(int i)
{
std::mt19937 gen;
auto a = data(i);
timer::duration_t ms = {};
for(int j = 0; j < cloops; ++j)
{
::shuffle(a.get(), i, gen);
timer t;
insertion_sort(ranges::views::counted(I{a.get()}, i));
ms += t.elapsed();
}
std::cout << to_millis(ms/cloops) << std::endl;
}
int main(int argc, char *argv[])
{
if(argc < 2)
return -1;
int i = std::atoi(argv[1]);
std::cout << "insertion_sort_n (random-access) : ";
benchmark_n<int*>(i);
std::cout << "insertion_sort (random-access) : ";
benchmark_counted<int*>(i);
std::cout << "\n";
std::cout << "insertion_sort_n (forward) : ";
benchmark_n<forward_iterator<int*>>(i);
std::cout << "insertion_sort (forward) : ";
benchmark_counted<forward_iterator<int*>>(i);
}
|