Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test #3

Merged
merged 18 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Checks: >
-hicpp-named-parameter,
-readability-named-parameter,
-altera-unroll-loops,
-fuchsia-default-arguments-calls,
-cppcoreguidelines-avoid-magic-numbers,
-readability-magic-numbers,

WarningsAsErrors: "*"

Expand Down
7 changes: 4 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cmake.configureArgs": [
"-DENABLE_TESTS=ON",
"-DENABLE_BENCHMARKS=OFF",
"-DENABLE_COVERAGE=ON",
"-DENABLE_COVERAGE=OFF",
"-DENABLE_ASAN=OFF",
],
"cmake.configureOnOpen": true,
Expand All @@ -17,7 +17,7 @@
"editor.defaultFormatter": "xaver.clang-format",
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"coverage-gutters.coverageBaseDir": "**",
"coverage-gutters.coverageBaseDir": "build",
"coverage-gutters.coverageFileNames": [
"coverage.info",
"lcov.info",
Expand Down Expand Up @@ -100,6 +100,7 @@
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"semaphore": "cpp"
"semaphore": "cpp",
"iostream": "cpp"
}
}
46 changes: 46 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Create build directory",
"type": "shell",
"command": "mkdir -p build",
"group": {
"kind": "build",
"isDefault": true
},
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": []
},
{
"label": "CMake",
"type": "shell",
"command": "cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_TESTS=ON -DENABLE_COVERAGE=ON -DENABLE_ASAN=OFF",
"dependsOn": "Create build directory",
"group": {
"kind": "build",
"isDefault": true
},
"options": {
"cwd": "${workspaceFolder}/build"
},
"problemMatcher": []
},
{
"label": "Generate Coverage Report",
"type": "shell",
"command": "cmake --build . --config Debug --target coverage",
"dependsOn": "CMake",
"group": {
"kind": "build",
"isDefault": true
},
"options": {
"cwd": "${workspaceFolder}/build"
},
"problemMatcher": []
}
]
}
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ See [tests](tests/zip_test.cpp).
* Write size() as end() - begin()
* Exception guarantees
* constexpr
* const correctness
* Write benchmarks
* ContainersAndAlgorithms test fails at `EXPECT_EQ(it, std::prev(const_zip.end()));` for std::list
* Consider checked access that returns an optional reference
* List tools required for dev or create devcontainer
* Test
* 100% coverage
* Finish tests
Expand Down
40 changes: 23 additions & 17 deletions include/msd/zip.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,35 @@ class zip_iterator {
return *this;
}

zip_iterator operator+(const std::size_t offset) noexcept
zip_iterator operator+(const std::size_t offset) const noexcept
{
zip_iterator it = *this;
it.advance(std::index_sequence_for<Iterators...>{}, offset);
return it;
auto iterator = *this;
iterator.advance(std::index_sequence_for<Iterators...>{}, offset);
return iterator;
}

zip_iterator operator-(const int offset) const noexcept
{
auto iterator = *this;
iterator.advance(std::index_sequence_for<Iterators...>{}, -offset);
return iterator;
}

private:
template <std::size_t... I>
value_type dereference(std::index_sequence<I...> /*unused*/) const
value_type dereference(std::index_sequence<I...>) const
{
return std::tie(*std::get<I>(iterators_)...);
}

template <std::size_t... I>
bool equal(std::index_sequence<I...> /*unused*/, const zip_iterator& other) const
bool equal(std::index_sequence<I...>, const zip_iterator& other) const
{
return ((std::get<I>(iterators_) == std::get<I>(other.iterators_)) || ...);
}

template <std::size_t... I>
void advance(std::index_sequence<I...> /*unused*/, int offset)
void advance(std::index_sequence<I...>, int offset)
{
((std::advance(std::get<I>(iterators_), offset)), ...);
}
Expand Down Expand Up @@ -91,12 +98,11 @@ class zip {

[[nodiscard]] bool empty() const noexcept { return begin() == end(); }

constexpr explicit operator bool() { return !empty(); }
constexpr explicit operator bool() const { return !empty(); }

value_type front()
{
assert(!empty());
assert(!empty()); // LCOV_EXCL_LINE
return *begin();
}

Expand All @@ -108,39 +114,39 @@ class zip {

value_type back()
{
assert(!empty());
assert(!empty()); // LCOV_EXCL_LINE
return *std::prev(begin() + size());
}

value_type back() const
{
assert(!empty());
assert(!empty()); // LCOV_EXCL_LINE
return *std::prev(begin() + size());
}

constexpr value_type operator[](std::size_t offset)
constexpr value_type operator[](const std::size_t offset) const
{
assert(offset < size());
return *std::next(begin(), offset);
}

private:
template <std::size_t... I>
iterator begin_impl(std::index_sequence<I...> /*unused*/) const
iterator begin_impl(std::index_sequence<I...>) const
{
return iterator{std::get<I>(containers_).begin()...};
}

template <std::size_t... I>
iterator end_impl(std::index_sequence<I...> /*unused*/) const
iterator end_impl(std::index_sequence<I...>) const
{
return iterator{std::get<I>(containers_).end()...};
return std::next(iterator{std::get<I>(containers_).begin()...}, size());
}

template <std::size_t... I>
std::size_t size_impl(std::index_sequence<I...> /*unused*/) const
std::size_t size_impl(std::index_sequence<I...>) const
{
return std::min({std::get<I>(containers_).size()...});
return std::min({std::distance(std::get<I>(containers_).begin(), std::get<I>(containers_).end())...});
}

std::tuple<Containers&...> containers_;
Expand Down
18 changes: 17 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ function(package_add_test TESTNAME)
if (ENABLE_COVERAGE)
target_link_libraries(${TESTNAME} -lgcov -lubsan)
target_compile_options(${TESTNAME} PRIVATE --coverage -fsanitize=undefined)

add_custom_target(
run_tests
COMMAND ctest -C Debug --verbose
DEPENDS tests
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

add_custom_target(
coverage
COMMAND lcov --directory . --capture --output-file coverage.info
&& lcov --remove coverage.info '/usr/*' '*/tests/*' '*/external/*' '*gtest*' '*gmock*' --output-file coverage_filtered.info
&& genhtml coverage_filtered.info --output-directory coverage_html
DEPENDS run_tests
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif ()

if (ENABLE_ASAN)
Expand All @@ -41,7 +57,7 @@ endfunction()
add_custom_target(tests)

# Tests
package_add_test(zip_test zip_test.cpp)
package_add_test(zip_test zip_test.cpp zip_iterator_test.cpp zip_integration_test.cpp)

# Benchmark
if (ENABLE_BENCHMARKS)
Expand Down
6 changes: 6 additions & 0 deletions tests/data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ class data {

data& operator=(const data& other)
{
if (this == &other) {
return *this;
}

++copies_;
num = other.num;
return *this;
Expand All @@ -27,6 +31,8 @@ class data {
num = other.num;
return *this;
}

~data() = default;
};

#endif // MSD_ZIP_TESTS_DATA_HPP
65 changes: 65 additions & 0 deletions tests/zip_integration_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <gtest/gtest.h>

#include <algorithm>
#include <array>
#include <deque>
#include <forward_list>
#include <iterator>
#include <list>
#include <numeric>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "msd/zip.hpp"

TEST(ZipIntegrationTest, ContainersAndAlgorithms)
{
std::vector<int> vector{1, 0};
std::deque<int> deque{1, 2};
std::list<int> list{1, 2, 3};
std::forward_list<int> forward_list{1, 2, 3, 4};
std::array<int, 5> array{1, 2, 3, 4, 5};
std::string string{"123456"};
std::set<int> set{1, 2, 3, 4, 5, 6};
std::multiset<int> multiset{1, 2, 3, 4, 5, 6};
std::map<int, int> map{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}};
std::multimap<int, int> multimap{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}};
const auto zip = msd::zip(vector, deque, list, forward_list, array, string, set, multiset, map, multimap);

const int sum = std::accumulate(zip.begin(), zip.end(), 0, [](int acc, auto&& tuple) {
auto [vec, deq, li, fwd, arr, str, s, mset, mp, mm] = tuple;
return acc + vec + deq + li + fwd + arr + str + s + mset + mp.second + mm.second;
});
EXPECT_EQ(sum, 124);

const auto iterator_find = std::find_if(zip.cbegin(), zip.cend(), [](auto tuple) {
auto [vec, deq, li, fwd, arr, str, s, mset, mp, mm] = tuple;
return li == 4;
});
EXPECT_EQ(iterator_find, zip.cend());

std::unordered_set<int> unordered_set{1, 9, -3};
std::unordered_multiset<int> unordered_multiset{1, 2, 3, 4, 5, 6};
std::unordered_map<int, int> unordered_map{{1, 1}, {2, 2}, {3, 3}, {45, 49}, {5, 5}, {6, 6}};
std::unordered_multimap<int, int> unordered_multimap{{1, 1}, {2, 2}, {3, 3}, {4, 4}};

const msd::zip unordered_zip(unordered_set, unordered_multiset, unordered_map, unordered_multimap);
const bool any_is_negative = std::any_of(unordered_zip.begin(), unordered_zip.cend(), [](auto tuple) {
auto [uset, umset, umap, umm] = tuple;
return uset < 0 || umset < 0 || umap.second < 0 || umm.second < 0;
});
EXPECT_TRUE(any_is_negative);

msd::zip adjacent_zip(list, forward_list);
const auto adjacent_iterator =
std::adjacent_find(adjacent_zip.begin(), adjacent_zip.end(), [](auto&& current, auto&& next) {
auto&& [current_l, current_f] = current;
auto&& [next_l, next_f] = next;

std::cout << current_l << ", " << current_f << " vs " << next_l << ", " << next_f << "\n\n";

return current_l + current_f + next_l + next_f == 6;
});
EXPECT_EQ(adjacent_iterator, adjacent_zip.begin());
}
Loading
Loading