blob: f2858bd11eceb2ce9cfc91b5d57a4f1253bb0323 [file] [log] [blame]
//===------ MappedIteratorTest.cpp - Unit tests for mapped_iterator -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
template <typename T> class MappedIteratorTestBasic : public testing::Test {};
struct Plus1Lambda {
auto operator()() const {
return [](int X) { return X + 1; };
}
};
struct Plus1LambdaWithCapture {
const int One = 1;
auto operator()() const {
return [=](int X) { return X + One; };
}
};
struct Plus1FunctionRef {
static int plus1(int X) { return X + 1; }
using FuncT = int (&)(int);
FuncT operator()() const { return (FuncT)*plus1; }
};
struct Plus1FunctionPtr {
static int plus1(int X) { return X + 1; }
using FuncT = int (*)(int);
FuncT operator()() const { return plus1; }
};
struct Plus1Functor {
struct Plus1 {
int operator()(int X) const { return X + 1; }
};
auto operator()() const { return Plus1(); }
};
struct Plus1FunctorNotDefaultConstructible {
class PlusN {
const int N;
public:
PlusN(int NArg) : N(NArg) {}
int operator()(int X) const { return X + N; }
};
auto operator()() const { return PlusN(1); }
};
// clang-format off
using FunctionTypes =
::testing::Types<
Plus1Lambda,
Plus1LambdaWithCapture,
Plus1FunctionRef,
Plus1FunctionPtr,
Plus1Functor,
Plus1FunctorNotDefaultConstructible
>;
// clang-format on
TYPED_TEST_SUITE(MappedIteratorTestBasic, FunctionTypes, );
template <typename T> using GetFuncT = decltype(std::declval<T>().operator()());
TYPED_TEST(MappedIteratorTestBasic, DefaultConstruct) {
using FuncT = GetFuncT<TypeParam>;
using IterT = mapped_iterator<typename std::vector<int>::iterator, FuncT>;
TypeParam GetCallable;
auto Func = GetCallable();
(void)Func;
constexpr bool DefaultConstruct =
std::is_default_constructible_v<callable_detail::Callable<FuncT>>;
EXPECT_TRUE(DefaultConstruct);
EXPECT_TRUE(std::is_default_constructible_v<IterT>);
if constexpr (std::is_default_constructible_v<IterT>) {
IterT I;
(void)I;
}
}
TYPED_TEST(MappedIteratorTestBasic, CopyConstruct) {
std::vector<int> V({0});
using FuncT = GetFuncT<TypeParam>;
using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
EXPECT_TRUE(std::is_copy_constructible_v<IterT>);
if constexpr (std::is_copy_constructible_v<IterT>) {
TypeParam GetCallable;
IterT I1(V.begin(), GetCallable());
IterT I2(I1);
EXPECT_EQ(I2, I1) << "copy constructed iterator is a different position";
}
}
TYPED_TEST(MappedIteratorTestBasic, MoveConstruct) {
std::vector<int> V({0});
using FuncT = GetFuncT<TypeParam>;
using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
EXPECT_TRUE(std::is_move_constructible_v<IterT>);
if constexpr (std::is_move_constructible_v<IterT>) {
TypeParam GetCallable;
IterT I1(V.begin(), GetCallable());
IterT I2(V.begin(), GetCallable());
IterT I3(std::move(I2));
EXPECT_EQ(I3, I1) << "move constructed iterator is a different position";
}
}
TYPED_TEST(MappedIteratorTestBasic, CopyAssign) {
std::vector<int> V({0});
using FuncT = GetFuncT<TypeParam>;
using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
EXPECT_TRUE(std::is_copy_assignable_v<IterT>);
if constexpr (std::is_copy_assignable_v<IterT>) {
TypeParam GetCallable;
IterT I1(V.begin(), GetCallable());
IterT I2(V.end(), GetCallable());
I2 = I1;
EXPECT_EQ(I2, I1) << "copy assigned iterator is a different position";
}
}
TYPED_TEST(MappedIteratorTestBasic, MoveAssign) {
std::vector<int> V({0});
using FuncT = GetFuncT<TypeParam>;
using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
EXPECT_TRUE(std::is_move_assignable_v<IterT>);
if constexpr (std::is_move_assignable_v<IterT>) {
TypeParam GetCallable;
IterT I1(V.begin(), GetCallable());
IterT I2(V.begin(), GetCallable());
IterT I3(V.end(), GetCallable());
I3 = std::move(I2);
EXPECT_EQ(I2, I1) << "move assigned iterator is a different position";
}
}
TYPED_TEST(MappedIteratorTestBasic, GetFunction) {
std::vector<int> V({0});
using FuncT = GetFuncT<TypeParam>;
using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
TypeParam GetCallable;
IterT I(V.begin(), GetCallable());
EXPECT_EQ(I.getFunction()(200), 201);
}
TYPED_TEST(MappedIteratorTestBasic, GetCurrent) {
std::vector<int> V({0});
using FuncT = GetFuncT<TypeParam>;
using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
TypeParam GetCallable;
IterT I(V.begin(), GetCallable());
EXPECT_EQ(I.getCurrent(), V.begin());
EXPECT_EQ(std::next(I).getCurrent(), V.end());
}
TYPED_TEST(MappedIteratorTestBasic, ApplyFunctionOnDereference) {
std::vector<int> V({0});
TypeParam GetCallable;
auto I = map_iterator(V.begin(), GetCallable());
EXPECT_EQ(*I, 1) << "should have applied function in dereference";
}
TEST(MappedIteratorTest, ApplyFunctionOnArrow) {
struct S {
int Z = 0;
};
std::vector<int> V({0});
S Y;
S *P = &Y;
auto I = map_iterator(V.begin(), [&](int X) -> S & { return *(P + X); });
I->Z = 42;
EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";
}
TEST(MappedIteratorTest, FunctionPreservesReferences) {
std::vector<int> V({1});
std::map<int, int> M({{1, 1}});
auto I = map_iterator(V.begin(), [&](int X) -> int & { return M[X]; });
*I = 42;
EXPECT_EQ(M[1], 42) << "assignment should have modified M";
}
TEST(MappedIteratorTest, CustomIteratorApplyFunctionOnDereference) {
struct CustomMapIterator
: public llvm::mapped_iterator_base<CustomMapIterator,
std::vector<int>::iterator, int> {
using BaseT::BaseT;
/// Map the element to the iterator result type.
int mapElement(int X) const { return X + 1; }
};
std::vector<int> V({0});
CustomMapIterator I(V.begin());
EXPECT_EQ(*I, 1) << "should have applied function in dereference";
}
TEST(MappedIteratorTest, CustomIteratorApplyFunctionOnArrow) {
struct S {
int Z = 0;
};
struct CustomMapIterator
: public llvm::mapped_iterator_base<CustomMapIterator,
std::vector<int>::iterator, S &> {
CustomMapIterator(std::vector<int>::iterator it, S *P) : BaseT(it), P(P) {}
/// Map the element to the iterator result type.
S &mapElement(int X) const { return *(P + X); }
S *P;
};
std::vector<int> V({0});
S Y;
CustomMapIterator I(V.begin(), &Y);
I->Z = 42;
EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";
}
TEST(MappedIteratorTest, CustomIteratorFunctionPreservesReferences) {
struct CustomMapIterator
: public llvm::mapped_iterator_base<CustomMapIterator,
std::vector<int>::iterator, int &> {
CustomMapIterator(std::vector<int>::iterator it, std::map<int, int> &M)
: BaseT(it), M(M) {}
/// Map the element to the iterator result type.
int &mapElement(int X) const { return M[X]; }
std::map<int, int> &M;
};
std::vector<int> V({1});
std::map<int, int> M({{1, 1}});
auto I = CustomMapIterator(V.begin(), M);
*I = 42;
EXPECT_EQ(M[1], 42) << "assignment should have modified M";
}
} // anonymous namespace