/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "gtest/gtest.h" #include "transform_iterator.h" namespace art { namespace { // anonymous namespace struct ValueHolder { // Deliberately not explicit. ValueHolder(int v) : value(v) { } // NOLINT int value; }; bool operator==(const ValueHolder& lhs, const ValueHolder& rhs) { return lhs.value == rhs.value; } } // anonymous namespace TEST(TransformIterator, VectorAdd1) { auto add1 = [](const ValueHolder& h) { return h.value + 1; }; std::vector input({ 1, 7, 3, 8 }); std::vector output; using vector_titer = decltype(MakeTransformIterator(input.begin(), add1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_ctiter = decltype(MakeTransformIterator(input.cbegin(), add1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), add1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_crtiter = decltype(MakeTransformIterator(input.crbegin(), add1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); std::copy(MakeTransformIterator(input.begin(), add1), MakeTransformIterator(input.end(), add1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 2, 8, 4, 9 }), output); output.clear(); std::copy(MakeTransformIterator(input.cbegin(), add1), MakeTransformIterator(input.cend(), add1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 2, 8, 4, 9 }), output); output.clear(); std::copy(MakeTransformIterator(input.rbegin(), add1), MakeTransformIterator(input.rend(), add1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 9, 4, 8, 2 }), output); output.clear(); std::copy(MakeTransformIterator(input.crbegin(), add1), MakeTransformIterator(input.crend(), add1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 9, 4, 8, 2 }), output); output.clear(); for (size_t i = 0; i != input.size(); ++i) { ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.begin(), add1)[i]); ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.cbegin(), add1)[i]); ptrdiff_t index_from_rbegin = static_cast(input.size() - i - 1u); ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.rbegin(), add1)[index_from_rbegin]); ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.crbegin(), add1)[index_from_rbegin]); ptrdiff_t index_from_end = -static_cast(input.size() - i); ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.end(), add1)[index_from_end]); ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.cend(), add1)[index_from_end]); ptrdiff_t index_from_rend = -1 - static_cast(i); ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.rend(), add1)[index_from_rend]); ASSERT_EQ(input[i].value + 1, MakeTransformIterator(input.crend(), add1)[index_from_rend]); ASSERT_EQ(MakeTransformIterator(input.begin(), add1) + i, MakeTransformIterator(input.begin() + i, add1)); ASSERT_EQ(MakeTransformIterator(input.cbegin(), add1) + i, MakeTransformIterator(input.cbegin() + i, add1)); ASSERT_EQ(MakeTransformIterator(input.rbegin(), add1) + i, MakeTransformIterator(input.rbegin() + i, add1)); ASSERT_EQ(MakeTransformIterator(input.crbegin(), add1) + i, MakeTransformIterator(input.crbegin() + i, add1)); ASSERT_EQ(MakeTransformIterator(input.end(), add1) - i, MakeTransformIterator(input.end() - i, add1)); ASSERT_EQ(MakeTransformIterator(input.cend(), add1) - i, MakeTransformIterator(input.cend() - i, add1)); ASSERT_EQ(MakeTransformIterator(input.rend(), add1) - i, MakeTransformIterator(input.rend() - i, add1)); ASSERT_EQ(MakeTransformIterator(input.crend(), add1) - i, MakeTransformIterator(input.crend() - i, add1)); } ASSERT_EQ(input.end(), (MakeTransformIterator(input.begin(), add1) + input.size()).base()); ASSERT_EQ(MakeTransformIterator(input.end(), add1) - MakeTransformIterator(input.begin(), add1), static_cast(input.size())); // Test iterator->const_iterator conversion and comparison. auto it = MakeTransformIterator(input.begin(), add1); decltype(MakeTransformIterator(input.cbegin(), add1)) cit = it; static_assert(!std::is_same::value, "Types must be different"); ASSERT_EQ(it, cit); auto rit = MakeTransformIterator(input.rbegin(), add1); decltype(MakeTransformIterator(input.crbegin(), add1)) crit(rit); static_assert(!std::is_same::value, "Types must be different"); ASSERT_EQ(rit, crit); } TEST(TransformIterator, ListSub1) { auto sub1 = [](const ValueHolder& h) { return h.value - 1; }; std::list input({ 2, 3, 5, 7, 11 }); std::vector output; using list_titer = decltype(MakeTransformIterator(input.begin(), sub1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using list_ctiter = decltype(MakeTransformIterator(input.cbegin(), sub1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using list_rtiter = decltype(MakeTransformIterator(input.rbegin(), sub1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using list_crtiter = decltype(MakeTransformIterator(input.crbegin(), sub1)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); std::copy(MakeTransformIterator(input.begin(), sub1), MakeTransformIterator(input.end(), sub1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 1, 2, 4, 6, 10 }), output); output.clear(); std::copy(MakeTransformIterator(input.cbegin(), sub1), MakeTransformIterator(input.cend(), sub1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 1, 2, 4, 6, 10 }), output); output.clear(); std::copy(MakeTransformIterator(input.rbegin(), sub1), MakeTransformIterator(input.rend(), sub1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 10, 6, 4, 2, 1 }), output); output.clear(); std::copy(MakeTransformIterator(input.crbegin(), sub1), MakeTransformIterator(input.crend(), sub1), std::back_inserter(output)); ASSERT_EQ(std::vector({ 10, 6, 4, 2, 1 }), output); output.clear(); // Test iterator->const_iterator conversion and comparison. auto it = MakeTransformIterator(input.begin(), sub1); decltype(MakeTransformIterator(input.cbegin(), sub1)) cit = it; static_assert(!std::is_same::value, "Types must be different"); ASSERT_EQ(it, cit); } TEST(TransformIterator, ForwardListSub1) { auto mul3 = [](const ValueHolder& h) { return h.value * 3; }; std::forward_list input({ 1, 1, 2, 3, 5, 8 }); std::vector output; using flist_titer = decltype(MakeTransformIterator(input.begin(), mul3)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using flist_ctiter = decltype(MakeTransformIterator(input.cbegin(), mul3)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); std::copy(MakeTransformIterator(input.begin(), mul3), MakeTransformIterator(input.end(), mul3), std::back_inserter(output)); ASSERT_EQ(std::vector({ 3, 3, 6, 9, 15, 24 }), output); output.clear(); std::copy(MakeTransformIterator(input.cbegin(), mul3), MakeTransformIterator(input.cend(), mul3), std::back_inserter(output)); ASSERT_EQ(std::vector({ 3, 3, 6, 9, 15, 24 }), output); output.clear(); // Test iterator->const_iterator conversion and comparison. auto it = MakeTransformIterator(input.begin(), mul3); decltype(MakeTransformIterator(input.cbegin(), mul3)) cit = it; static_assert(!std::is_same::value, "Types must be different"); ASSERT_EQ(it, cit); } TEST(TransformIterator, VectorConstReference) { auto ref = [](const ValueHolder& h) -> const int& { return h.value; }; std::vector input({ 7, 3, 1, 2, 4, 8 }); std::vector output; using vector_titer = decltype(MakeTransformIterator(input.begin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_ctiter = decltype(MakeTransformIterator(input.cbegin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_crtiter = decltype(MakeTransformIterator(input.crbegin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); std::copy(MakeTransformIterator(input.begin(), ref), MakeTransformIterator(input.end(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 7, 3, 1, 2, 4, 8 }), output); output.clear(); std::copy(MakeTransformIterator(input.cbegin(), ref), MakeTransformIterator(input.cend(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 7, 3, 1, 2, 4, 8 }), output); output.clear(); std::copy(MakeTransformIterator(input.rbegin(), ref), MakeTransformIterator(input.rend(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 8, 4, 2, 1, 3, 7 }), output); output.clear(); std::copy(MakeTransformIterator(input.crbegin(), ref), MakeTransformIterator(input.crend(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 8, 4, 2, 1, 3, 7 }), output); output.clear(); for (size_t i = 0; i != input.size(); ++i) { ASSERT_EQ(input[i].value, MakeTransformIterator(input.begin(), ref)[i]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.cbegin(), ref)[i]); ptrdiff_t index_from_rbegin = static_cast(input.size() - i - 1u); ASSERT_EQ(input[i].value, MakeTransformIterator(input.rbegin(), ref)[index_from_rbegin]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.crbegin(), ref)[index_from_rbegin]); ptrdiff_t index_from_end = -static_cast(input.size() - i); ASSERT_EQ(input[i].value, MakeTransformIterator(input.end(), ref)[index_from_end]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.cend(), ref)[index_from_end]); ptrdiff_t index_from_rend = -1 - static_cast(i); ASSERT_EQ(input[i].value, MakeTransformIterator(input.rend(), ref)[index_from_rend]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.crend(), ref)[index_from_rend]); ASSERT_EQ(MakeTransformIterator(input.begin(), ref) + i, MakeTransformIterator(input.begin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.cbegin(), ref) + i, MakeTransformIterator(input.cbegin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.rbegin(), ref) + i, MakeTransformIterator(input.rbegin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.crbegin(), ref) + i, MakeTransformIterator(input.crbegin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.end(), ref) - i, MakeTransformIterator(input.end() - i, ref)); ASSERT_EQ(MakeTransformIterator(input.cend(), ref) - i, MakeTransformIterator(input.cend() - i, ref)); ASSERT_EQ(MakeTransformIterator(input.rend(), ref) - i, MakeTransformIterator(input.rend() - i, ref)); ASSERT_EQ(MakeTransformIterator(input.crend(), ref) - i, MakeTransformIterator(input.crend() - i, ref)); } ASSERT_EQ(input.end(), (MakeTransformIterator(input.begin(), ref) + input.size()).base()); ASSERT_EQ(MakeTransformIterator(input.end(), ref) - MakeTransformIterator(input.begin(), ref), static_cast(input.size())); } TEST(TransformIterator, VectorNonConstReference) { auto ref = [](ValueHolder& h) -> int& { return h.value; }; std::vector input({ 7, 3, 1, 2, 4, 8 }); std::vector output; using vector_titer = decltype(MakeTransformIterator(input.begin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); std::copy(MakeTransformIterator(input.begin(), ref), MakeTransformIterator(input.end(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 7, 3, 1, 2, 4, 8 }), output); output.clear(); std::copy(MakeTransformIterator(input.rbegin(), ref), MakeTransformIterator(input.rend(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 8, 4, 2, 1, 3, 7 }), output); output.clear(); for (size_t i = 0; i != input.size(); ++i) { ASSERT_EQ(input[i].value, MakeTransformIterator(input.begin(), ref)[i]); ptrdiff_t index_from_rbegin = static_cast(input.size() - i - 1u); ASSERT_EQ(input[i].value, MakeTransformIterator(input.rbegin(), ref)[index_from_rbegin]); ptrdiff_t index_from_end = -static_cast(input.size() - i); ASSERT_EQ(input[i].value, MakeTransformIterator(input.end(), ref)[index_from_end]); ptrdiff_t index_from_rend = -1 - static_cast(i); ASSERT_EQ(input[i].value, MakeTransformIterator(input.rend(), ref)[index_from_rend]); ASSERT_EQ(MakeTransformIterator(input.begin(), ref) + i, MakeTransformIterator(input.begin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.rbegin(), ref) + i, MakeTransformIterator(input.rbegin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.end(), ref) - i, MakeTransformIterator(input.end() - i, ref)); ASSERT_EQ(MakeTransformIterator(input.rend(), ref) - i, MakeTransformIterator(input.rend() - i, ref)); } ASSERT_EQ(input.end(), (MakeTransformIterator(input.begin(), ref) + input.size()).base()); ASSERT_EQ(MakeTransformIterator(input.end(), ref) - MakeTransformIterator(input.begin(), ref), static_cast(input.size())); // Test writing through the transform iterator. std::list transform_input({ 1, -1, 2, -2, 3, -3 }); std::vector transformed(transform_input.size(), 0); std::transform(transform_input.begin(), transform_input.end(), MakeTransformIterator(transformed.begin(), ref), [](int v) { return -2 * v; }); ASSERT_EQ(std::vector({ -2, 2, -4, 4, -6, 6 }), transformed); } TEST(TransformIterator, VectorConstAndNonConstReference) { struct Ref { int& operator()(ValueHolder& h) const { return h.value; } const int& operator()(const ValueHolder& h) const { return h.value; } }; Ref ref; std::vector input({ 7, 3, 1, 2, 4, 8 }); std::vector output; using vector_titer = decltype(MakeTransformIterator(input.begin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_ctiter = decltype(MakeTransformIterator(input.cbegin(), ref)); static_assert(std::is_same::value, "category"); // static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_rtiter = decltype(MakeTransformIterator(input.rbegin(), ref)); static_assert(std::is_same::value, "category"); static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); using vector_crtiter = decltype(MakeTransformIterator(input.crbegin(), ref)); static_assert(std::is_same::value, "category"); // static_assert(std::is_same::value, "value_type"); static_assert(std::is_same::value, "pointer"); static_assert(std::is_same::value, "reference"); std::copy(MakeTransformIterator(input.begin(), ref), MakeTransformIterator(input.end(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 7, 3, 1, 2, 4, 8 }), output); output.clear(); std::copy(MakeTransformIterator(input.cbegin(), ref), MakeTransformIterator(input.cend(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 7, 3, 1, 2, 4, 8 }), output); output.clear(); std::copy(MakeTransformIterator(input.rbegin(), ref), MakeTransformIterator(input.rend(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 8, 4, 2, 1, 3, 7 }), output); output.clear(); std::copy(MakeTransformIterator(input.crbegin(), ref), MakeTransformIterator(input.crend(), ref), std::back_inserter(output)); ASSERT_EQ(std::vector({ 8, 4, 2, 1, 3, 7 }), output); output.clear(); for (size_t i = 0; i != input.size(); ++i) { ASSERT_EQ(input[i].value, MakeTransformIterator(input.begin(), ref)[i]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.cbegin(), ref)[i]); ptrdiff_t index_from_rbegin = static_cast(input.size() - i - 1u); ASSERT_EQ(input[i].value, MakeTransformIterator(input.rbegin(), ref)[index_from_rbegin]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.crbegin(), ref)[index_from_rbegin]); ptrdiff_t index_from_end = -static_cast(input.size() - i); ASSERT_EQ(input[i].value, MakeTransformIterator(input.end(), ref)[index_from_end]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.cend(), ref)[index_from_end]); ptrdiff_t index_from_rend = -1 - static_cast(i); ASSERT_EQ(input[i].value, MakeTransformIterator(input.rend(), ref)[index_from_rend]); ASSERT_EQ(input[i].value, MakeTransformIterator(input.crend(), ref)[index_from_rend]); ASSERT_EQ(MakeTransformIterator(input.begin(), ref) + i, MakeTransformIterator(input.begin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.cbegin(), ref) + i, MakeTransformIterator(input.cbegin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.rbegin(), ref) + i, MakeTransformIterator(input.rbegin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.crbegin(), ref) + i, MakeTransformIterator(input.crbegin() + i, ref)); ASSERT_EQ(MakeTransformIterator(input.end(), ref) - i, MakeTransformIterator(input.end() - i, ref)); ASSERT_EQ(MakeTransformIterator(input.cend(), ref) - i, MakeTransformIterator(input.cend() - i, ref)); ASSERT_EQ(MakeTransformIterator(input.rend(), ref) - i, MakeTransformIterator(input.rend() - i, ref)); ASSERT_EQ(MakeTransformIterator(input.crend(), ref) - i, MakeTransformIterator(input.crend() - i, ref)); } ASSERT_EQ(input.end(), (MakeTransformIterator(input.begin(), ref) + input.size()).base()); ASSERT_EQ(MakeTransformIterator(input.end(), ref) - MakeTransformIterator(input.begin(), ref), static_cast(input.size())); // Test iterator->const_iterator conversion and comparison. auto it = MakeTransformIterator(input.begin(), ref); decltype(MakeTransformIterator(input.cbegin(), ref)) cit = it; static_assert(!std::is_same::value, "Types must be different"); ASSERT_EQ(it, cit); auto rit = MakeTransformIterator(input.rbegin(), ref); decltype(MakeTransformIterator(input.crbegin(), ref)) crit(rit); static_assert(!std::is_same::value, "Types must be different"); ASSERT_EQ(rit, crit); // Test writing through the transform iterator. std::list transform_input({ 42, 73, 11, 17 }); std::vector transformed(transform_input.size(), 0); std::transform(transform_input.begin(), transform_input.end(), MakeTransformIterator(transformed.begin(), ref), [](int v) { return -v; }); ASSERT_EQ(std::vector({ -42, -73, -11, -17 }), transformed); } TEST(TransformIterator, TransformRange) { auto ref = [](ValueHolder& h) -> int& { return h.value; }; std::vector data({ 1, 0, 1, 3, 1, 0 }); for (int& v : MakeTransformRange(data, ref)) { v += 11; } ASSERT_EQ(std::vector({ 12, 11, 12, 14, 12, 11 }), data); } } // namespace art