#include
#include
#include
#include
#include
#include
#include
#include "helpers.hpp"
#include "catch.hpp"
using iter::sorted;
using Vec = const std::vector;
TEST_CASE("sorted: iterates through a vector in sorted order", "[sorted]") {
Vec ns = {4, 0, 5, 1, 6, 7, 9, 3, 2, 8};
auto s = sorted(ns);
Vec v(std::begin(s), std::end(s));
Vec vc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
REQUIRE(v == vc);
}
TEST_CASE("sorted: can modify elements through sorted", "[sorted]") {
std::vector ns(3, 9);
for (auto&& n : sorted(ns)) {
n = -1;
}
Vec vc(3, -1);
REQUIRE(ns == vc);
}
TEST_CASE("sorted: can iterate over unordered container", "[sorted]") {
std::unordered_set ns = {1, 3, 2, 0, 4};
auto s = sorted(ns);
Vec v(std::begin(s), std::end(s));
Vec vc = {0, 1, 2, 3, 4};
REQUIRE(v == vc);
}
TEST_CASE("sorted: empty when iterable is empty", "[sorted]") {
Vec ns{};
auto s = sorted(ns);
REQUIRE(std::begin(s) == std::end(s));
}
namespace {
bool int_greater_than(int lhs, int rhs) {
return lhs > rhs;
}
struct IntGreaterThan {
bool operator()(int lhs, int rhs) const {
return lhs > rhs;
}
};
}
TEST_CASE("sorted: works with different functor types", "[sorted]") {
Vec ns = {4, 1, 3, 2, 0};
std::vector v;
SECTION("with function pointer") {
auto s = sorted(ns, int_greater_than);
v.insert(v.begin(), std::begin(s), std::end(s));
}
SECTION("with callable object") {
auto s = sorted(ns, IntGreaterThan{});
v.insert(v.begin(), std::begin(s), std::end(s));
}
SECTION("with lambda") {
auto s = sorted(ns, [](int lhs, int rhs) { return lhs > rhs; });
v.insert(v.begin(), std::begin(s), std::end(s));
}
Vec vc = {4, 3, 2, 1, 0};
REQUIRE(v == vc);
}
namespace {
template
class BasicIterableWithConstDeref {
private:
T* data;
std::size_t size;
bool was_moved_from_ = false;
public:
BasicIterableWithConstDeref(std::initializer_list il)
: data{new T[il.size()]}, size{il.size()} {
// would like to use enumerate, can't because it's for unit
// testing enumerate
std::size_t i = 0;
for (auto&& e : il) {
data[i] = e;
++i;
}
}
BasicIterableWithConstDeref& operator=(
BasicIterableWithConstDeref&&) = delete;
BasicIterableWithConstDeref& operator=(
const BasicIterableWithConstDeref&) = delete;
BasicIterableWithConstDeref(const BasicIterableWithConstDeref&) = delete;
BasicIterableWithConstDeref(BasicIterableWithConstDeref&& other)
: data{other.data}, size{other.size} {
other.data = nullptr;
other.was_moved_from_ = true;
}
bool was_moved_from() const {
return this->was_moved_from_;
}
~BasicIterableWithConstDeref() {
delete[] this->data;
}
class Iterator {
private:
T* p;
public:
Iterator(T* b) : p{b} {}
bool operator!=(const Iterator& other) const {
return this->p != other.p;
}
Iterator& operator++() {
++this->p;
return *this;
}
T& operator*() {
return *this->p;
}
const T& operator*() const {
return *this->p;
}
};
Iterator begin() {
return {this->data};
}
Iterator end() {
return {this->data + this->size};
}
};
}
TEST_CASE("sorted: moves rvalues and binds to lvalues", "[sorted]") {
BasicIterableWithConstDeref bi{1, 2};
sorted(bi);
REQUIRE_FALSE(bi.was_moved_from());
sorted(std::move(bi));
REQUIRE(bi.was_moved_from());
}
TEST_CASE("sorted: doesn't move or copy elements of iterable", "[sorted]") {
using itertest::SolidInt;
constexpr SolidInt arr[] = {{6}, {7}, {8}};
for (auto &&i : sorted(arr, [](const SolidInt &lhs, const SolidInt &rhs) {
return lhs.getint() < rhs.getint();
})) {
(void)i;
}
}
template
using ImpT = decltype(sorted(std::declval()));
TEST_CASE("sorted: has correct ctor and assign ops", "[sorted]") {
REQUIRE(itertest::IsMoveConstructibleOnly>::value);
REQUIRE(itertest::IsMoveConstructibleOnly>::value);
}
TEST_CASE("sorted: iterator meets requirements", "[sorted]") {
Vec v;
auto r = sorted(v);
REQUIRE( itertest::IsIterator::value );
}