305 lines · cpp
1//===------ MappedIteratorTest.cpp - Unit tests for mapped_iterator -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ADT/STLExtras.h"10#include "gtest/gtest.h"11 12using namespace llvm;13 14namespace {15 16template <typename T> class MappedIteratorTestBasic : public testing::Test {};17 18struct Plus1Lambda {19 auto operator()() const {20 return [](int X) { return X + 1; };21 }22};23 24struct Plus1LambdaWithCapture {25 const int One = 1;26 27 auto operator()() const {28 return [=](int X) { return X + One; };29 }30};31 32struct Plus1FunctionRef {33 static int plus1(int X) { return X + 1; }34 35 using FuncT = int (&)(int);36 37 FuncT operator()() const { return (FuncT)*plus1; }38};39 40struct Plus1FunctionPtr {41 static int plus1(int X) { return X + 1; }42 43 using FuncT = int (*)(int);44 45 FuncT operator()() const { return plus1; }46};47 48struct Plus1Functor {49 struct Plus1 {50 int operator()(int X) const { return X + 1; }51 };52 53 auto operator()() const { return Plus1(); }54};55 56struct Plus1FunctorNotDefaultConstructible {57 class PlusN {58 const int N;59 60 public:61 PlusN(int NArg) : N(NArg) {}62 63 int operator()(int X) const { return X + N; }64 };65 66 auto operator()() const { return PlusN(1); }67};68 69// clang-format off70using FunctionTypes =71 ::testing::Types<72 Plus1Lambda,73 Plus1LambdaWithCapture,74 Plus1FunctionRef,75 Plus1FunctionPtr,76 Plus1Functor,77 Plus1FunctorNotDefaultConstructible78 >;79// clang-format on80 81TYPED_TEST_SUITE(MappedIteratorTestBasic, FunctionTypes, );82 83template <typename T> using GetFuncT = decltype(std::declval<T>().operator()());84 85TYPED_TEST(MappedIteratorTestBasic, DefaultConstruct) {86 using FuncT = GetFuncT<TypeParam>;87 using IterT = mapped_iterator<typename std::vector<int>::iterator, FuncT>;88 TypeParam GetCallable;89 90 auto Func = GetCallable();91 (void)Func;92 constexpr bool DefaultConstruct =93 std::is_default_constructible_v<callable_detail::Callable<FuncT>>;94 EXPECT_TRUE(DefaultConstruct);95 EXPECT_TRUE(std::is_default_constructible_v<IterT>);96 97 if constexpr (std::is_default_constructible_v<IterT>) {98 IterT I;99 (void)I;100 }101}102 103TYPED_TEST(MappedIteratorTestBasic, CopyConstruct) {104 std::vector<int> V({0});105 106 using FuncT = GetFuncT<TypeParam>;107 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;108 109 EXPECT_TRUE(std::is_copy_constructible_v<IterT>);110 111 if constexpr (std::is_copy_constructible_v<IterT>) {112 TypeParam GetCallable;113 114 IterT I1(V.begin(), GetCallable());115 IterT I2(I1);116 117 EXPECT_EQ(I2, I1) << "copy constructed iterator is a different position";118 }119}120 121TYPED_TEST(MappedIteratorTestBasic, MoveConstruct) {122 std::vector<int> V({0});123 124 using FuncT = GetFuncT<TypeParam>;125 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;126 127 EXPECT_TRUE(std::is_move_constructible_v<IterT>);128 129 if constexpr (std::is_move_constructible_v<IterT>) {130 TypeParam GetCallable;131 132 IterT I1(V.begin(), GetCallable());133 IterT I2(V.begin(), GetCallable());134 IterT I3(std::move(I2));135 136 EXPECT_EQ(I3, I1) << "move constructed iterator is a different position";137 }138}139 140TYPED_TEST(MappedIteratorTestBasic, CopyAssign) {141 std::vector<int> V({0});142 143 using FuncT = GetFuncT<TypeParam>;144 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;145 146 EXPECT_TRUE(std::is_copy_assignable_v<IterT>);147 148 if constexpr (std::is_copy_assignable_v<IterT>) {149 TypeParam GetCallable;150 151 IterT I1(V.begin(), GetCallable());152 IterT I2(V.end(), GetCallable());153 154 I2 = I1;155 156 EXPECT_EQ(I2, I1) << "copy assigned iterator is a different position";157 }158}159 160TYPED_TEST(MappedIteratorTestBasic, MoveAssign) {161 std::vector<int> V({0});162 163 using FuncT = GetFuncT<TypeParam>;164 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;165 166 EXPECT_TRUE(std::is_move_assignable_v<IterT>);167 168 if constexpr (std::is_move_assignable_v<IterT>) {169 TypeParam GetCallable;170 171 IterT I1(V.begin(), GetCallable());172 IterT I2(V.begin(), GetCallable());173 IterT I3(V.end(), GetCallable());174 175 I3 = std::move(I2);176 177 EXPECT_EQ(I3, I1) << "move assigned iterator is a different position";178 }179}180 181TYPED_TEST(MappedIteratorTestBasic, GetFunction) {182 std::vector<int> V({0});183 184 using FuncT = GetFuncT<TypeParam>;185 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;186 187 TypeParam GetCallable;188 IterT I(V.begin(), GetCallable());189 190 EXPECT_EQ(I.getFunction()(200), 201);191}192 193TYPED_TEST(MappedIteratorTestBasic, GetCurrent) {194 std::vector<int> V({0});195 196 using FuncT = GetFuncT<TypeParam>;197 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;198 199 TypeParam GetCallable;200 IterT I(V.begin(), GetCallable());201 202 EXPECT_EQ(I.getCurrent(), V.begin());203 EXPECT_EQ(std::next(I).getCurrent(), V.end());204}205 206TYPED_TEST(MappedIteratorTestBasic, ApplyFunctionOnDereference) {207 std::vector<int> V({0});208 TypeParam GetCallable;209 210 auto I = map_iterator(V.begin(), GetCallable());211 212 EXPECT_EQ(*I, 1) << "should have applied function in dereference";213}214 215TEST(MappedIteratorTest, ApplyFunctionOnArrow) {216 struct S {217 int Z = 0;218 };219 220 std::vector<int> V({0});221 S Y;222 S *P = &Y;223 224 auto I = map_iterator(V.begin(), [&](int X) -> S & { return *(P + X); });225 226 I->Z = 42;227 228 EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";229}230 231TEST(MappedIteratorTest, FunctionPreservesReferences) {232 std::vector<int> V({1});233 std::map<int, int> M({{1, 1}});234 235 auto I = map_iterator(V.begin(), [&](int X) -> int & { return M[X]; });236 *I = 42;237 238 EXPECT_EQ(M[1], 42) << "assignment should have modified M";239}240 241TEST(MappedIteratorTest, CustomIteratorApplyFunctionOnDereference) {242 struct CustomMapIterator243 : public llvm::mapped_iterator_base<CustomMapIterator,244 std::vector<int>::iterator, int> {245 using BaseT::BaseT;246 247 /// Map the element to the iterator result type.248 int mapElement(int X) const { return X + 1; }249 };250 251 std::vector<int> V({0});252 253 CustomMapIterator I(V.begin());254 255 EXPECT_EQ(*I, 1) << "should have applied function in dereference";256}257 258TEST(MappedIteratorTest, CustomIteratorApplyFunctionOnArrow) {259 struct S {260 int Z = 0;261 };262 struct CustomMapIterator263 : public llvm::mapped_iterator_base<CustomMapIterator,264 std::vector<int>::iterator, S &> {265 CustomMapIterator(std::vector<int>::iterator it, S *P) : BaseT(it), P(P) {}266 267 /// Map the element to the iterator result type.268 S &mapElement(int X) const { return *(P + X); }269 270 S *P;271 };272 273 std::vector<int> V({0});274 S Y;275 276 CustomMapIterator I(V.begin(), &Y);277 278 I->Z = 42;279 280 EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";281}282 283TEST(MappedIteratorTest, CustomIteratorFunctionPreservesReferences) {284 struct CustomMapIterator285 : public llvm::mapped_iterator_base<CustomMapIterator,286 std::vector<int>::iterator, int &> {287 CustomMapIterator(std::vector<int>::iterator it, std::map<int, int> &M)288 : BaseT(it), M(M) {}289 290 /// Map the element to the iterator result type.291 int &mapElement(int X) const { return M[X]; }292 293 std::map<int, int> &M;294 };295 std::vector<int> V({1});296 std::map<int, int> M({{1, 1}});297 298 auto I = CustomMapIterator(V.begin(), M);299 *I = 42;300 301 EXPECT_EQ(M[1], 42) << "assignment should have modified M";302}303 304} // anonymous namespace305