-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
lukas
committed
Oct 22, 2021
1 parent
2371f0a
commit 4ca3ddd
Showing
7 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
cmake_minimum_required(VERSION 3.12) | ||
|
||
project( | ||
"UnionFind" | ||
VERSION 0.0.1 | ||
DESCRIPTION "A single header c++ library that provides a union find datastructure") | ||
|
||
|
||
add_library(${PROJECT_NAME} INTERFACE) | ||
# add alias so the project can be uses with add_subdirectory | ||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) | ||
|
||
include(GNUInstallDirs) | ||
|
||
# Adding the install interface generator expression makes sure that the include | ||
# files are installed to the proper location (provided by GNUInstallDirs) | ||
target_include_directories( | ||
${PROJECT_NAME} | ||
INTERFACE $<BUILD_INTERFACE:${${PROJECT_NAME}_SOURCE_DIR}/include> | ||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>) | ||
|
||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17) | ||
|
||
# Tests | ||
option(BUILD_TESTS "build tests" ON) | ||
if (BUILD_TESTS) | ||
include(cmake/gtest.cmake) | ||
enable_testing() | ||
add_subdirectory(test) | ||
endif (BUILD_TESTS) | ||
|
||
# locations are provided by GNUInstallDirs | ||
install(TARGETS ${PROJECT_NAME} | ||
EXPORT ${PROJECT_NAME}_Targets | ||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | ||
|
||
include(CMakePackageConfigHelpers) | ||
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake" | ||
VERSION ${PROJECT_VERSION} | ||
COMPATIBILITY SameMajorVersion) | ||
|
||
configure_package_config_file( | ||
"${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" | ||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" | ||
INSTALL_DESTINATION | ||
${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) | ||
|
||
install(EXPORT ${PROJECT_NAME}_Targets | ||
FILE ${PROJECT_NAME}Targets.cmake | ||
NAMESPACE ${PROJECT_NAME}:: | ||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) | ||
|
||
install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" | ||
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" | ||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) | ||
|
||
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/SI DESTINATION include) | ||
|
||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") | ||
|
||
include(CPack) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
include(ExternalProject) | ||
include(GNUInstallDirs) | ||
|
||
set(CMAKE_ARGS | ||
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> | ||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} | ||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} | ||
-DBUILD_STATIC_LIBS=ON | ||
-DBUILD_SHARED_LIBS=OFF | ||
-Dgtest_build_samples=OFF | ||
-Dgtest_build_tests=OFF | ||
-DINSTALL_GTEST=ON | ||
-DBUILD_GMOCK=OFF) | ||
|
||
ExternalProject_Add(gtest-project | ||
PREFIX deps/gtest | ||
DOWNLOAD_NAME gtest-1.11.0.tar.gz | ||
DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/downloads | ||
URL https://github.com/google/googletest/archive/release-1.11.0.tar.gz | ||
PATCH_COMMAND cmake -E make_directory <SOURCE_DIR>/win32-deps/include | ||
CMAKE_ARGS ${CMAKE_ARGS} | ||
# Overwtire build and install commands to force Release build on MSVC. | ||
BUILD_COMMAND cmake --build <BINARY_DIR> --config Release | ||
INSTALL_COMMAND cmake --build <BINARY_DIR> --config Release --target install | ||
) | ||
|
||
|
||
ExternalProject_Get_Property(gtest-project INSTALL_DIR) | ||
add_library(gtest STATIC IMPORTED) | ||
if (CMAKE_BUILD_TYPE STREQUAL "Debug") | ||
set(GTEST_LIBRARY ${INSTALL_DIR}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtestd${CMAKE_STATIC_LIBRARY_SUFFIX}) | ||
else() | ||
set(GTEST_LIBRARY ${INSTALL_DIR}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}) | ||
endif () | ||
set(GTEST_INCLUDE_DIR ${INSTALL_DIR}/include) | ||
file(MAKE_DIRECTORY ${GTEST_INCLUDE_DIR}) # Must exist. | ||
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${GTEST_LIBRARY}) | ||
set_property(TARGET gtest PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${GTEST_INCLUDE_DIR}) | ||
|
||
unset(INSTALL_DIR) | ||
unset(CMAKE_ARGS) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#pragma once | ||
|
||
#include <compare> | ||
#include <functional> | ||
#include <numeric> | ||
#include <optional> | ||
#include <vector> | ||
|
||
namespace unionfind { | ||
|
||
class UnionFind | ||
{ | ||
public: | ||
explicit UnionFind(std::size_t size) noexcept | ||
: root_(size), | ||
rank_(size, 1), | ||
number_of_sets_(size) | ||
{ | ||
std::iota(std::begin(root_), | ||
std::end(root_), | ||
0); | ||
} | ||
|
||
[[nodiscard]] auto find(std::size_t x) noexcept | ||
-> std::optional<std::size_t> | ||
{ | ||
if(x >= root_.size()) { | ||
return std::nullopt; | ||
} | ||
|
||
if(root_[x] != x) { | ||
return root_[x] = findUnsafe(root_[x]); | ||
} | ||
|
||
return x; | ||
} | ||
|
||
|
||
[[nodiscard]] auto findUnsafe(std::size_t x) noexcept | ||
-> std::size_t | ||
{ | ||
if(root_[x] != x) { | ||
return root_[x] = findUnsafe(root_[x]); | ||
} | ||
|
||
return x; | ||
} | ||
|
||
auto merge(std::size_t x, std::size_t y) noexcept | ||
-> void | ||
{ | ||
const auto x_opt = find(x); | ||
const auto y_opt = find(y); | ||
|
||
if(!x_opt or !y_opt) { | ||
return; | ||
} | ||
|
||
x = x_opt.value(); | ||
y = y_opt.value(); | ||
|
||
if(x == y) { | ||
return; | ||
} | ||
|
||
number_of_sets_--; | ||
|
||
if(rank_[x] < rank_[y]) { | ||
root_[x] = y; | ||
} else if(rank_[x] > rank_[y]) { | ||
root_[y] = x; | ||
} else { | ||
root_[x] = y; | ||
rank_[y]++; | ||
} | ||
} | ||
|
||
[[nodiscard]] auto numberOfSets() const noexcept | ||
-> std::size_t | ||
{ | ||
return number_of_sets_; | ||
} | ||
|
||
|
||
private: | ||
std::vector<std::size_t> root_; | ||
std::vector<std::size_t> rank_; | ||
std::size_t number_of_sets_; | ||
}; | ||
|
||
} // namespace unionfind |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
set(CMAKE_CXX_STANDARD 17) | ||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
set(CMAKE_CXX_EXTENSIONS OFF) | ||
|
||
# needed for multithreading | ||
find_package(Threads REQUIRED) | ||
|
||
add_executable(unit_tests | ||
main.cpp | ||
tests.cpp | ||
) | ||
|
||
target_link_libraries(unit_tests LINK_PRIVATE | ||
gtest | ||
${CMAKE_THREAD_LIBS_INIT}) | ||
|
||
target_include_directories( | ||
unit_tests PUBLIC | ||
gtest | ||
${NAMEDTYPE_INCLUDE_DIR} | ||
${CMAKE_CURRENT_SOURCE_DIR}/../include | ||
) | ||
|
||
add_test( | ||
NAME unit_tests | ||
COMMAND | ||
${CMAKE_BINARY_DIR}/test/unit_tests | ||
) | ||
|
||
|
||
add_dependencies(unit_tests gtest-project) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#include <gtest/gtest.h> | ||
|
||
auto main(int argc, char **argv) | ||
-> int | ||
{ | ||
::testing::InitGoogleTest(&argc, argv); | ||
return RUN_ALL_TESTS(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
//all the includes you want to use before the gtest include | ||
#include <unionfind/unionfind.hpp> | ||
|
||
#include <gtest/gtest.h> | ||
|
||
TEST(UnionFindTest, UnmergedTest) | ||
{ | ||
unionfind::UnionFind uf{5}; | ||
|
||
EXPECT_EQ(uf.findUnsafe(0), 0); | ||
EXPECT_EQ(uf.findUnsafe(1), 1); | ||
EXPECT_EQ(uf.findUnsafe(2), 2); | ||
EXPECT_EQ(uf.findUnsafe(3), 3); | ||
EXPECT_EQ(uf.findUnsafe(4), 4); | ||
|
||
EXPECT_EQ(uf.find(0), 0); | ||
EXPECT_EQ(uf.find(1), 1); | ||
EXPECT_EQ(uf.find(2), 2); | ||
EXPECT_EQ(uf.find(3), 3); | ||
EXPECT_EQ(uf.find(4), 4); | ||
|
||
EXPECT_EQ(uf.numberOfSets(), 5); | ||
} | ||
|
||
TEST(UnionFindTest, SimpleMergeTest0) | ||
{ | ||
unionfind::UnionFind uf{5}; | ||
|
||
uf.merge(0, 4); | ||
|
||
EXPECT_EQ(uf.find(0), 4); | ||
EXPECT_EQ(uf.find(1), 1); | ||
EXPECT_EQ(uf.find(2), 2); | ||
EXPECT_EQ(uf.find(3), 3); | ||
EXPECT_EQ(uf.find(4), 4); | ||
|
||
EXPECT_EQ(uf.numberOfSets(), 4); | ||
} | ||
|
||
TEST(UnionFindTest, SimpleMergeTest2) | ||
{ | ||
unionfind::UnionFind uf{5}; | ||
|
||
uf.merge(0, 4); | ||
uf.merge(2, 3); | ||
|
||
EXPECT_EQ(uf.find(0), 4); | ||
EXPECT_EQ(uf.find(1), 1); | ||
EXPECT_EQ(uf.find(2), 3); | ||
EXPECT_EQ(uf.find(3), 3); | ||
EXPECT_EQ(uf.find(4), 4); | ||
|
||
EXPECT_EQ(uf.numberOfSets(), 3); | ||
} | ||
|
||
TEST(UnionFindTest, SimpleMergeTest3) | ||
{ | ||
unionfind::UnionFind uf{5}; | ||
|
||
uf.merge(0, 4); | ||
uf.merge(2, 3); | ||
uf.merge(0, 1); | ||
|
||
EXPECT_EQ(uf.find(0), 4); | ||
EXPECT_EQ(uf.find(1), 4); | ||
EXPECT_EQ(uf.find(2), 3); | ||
EXPECT_EQ(uf.find(3), 3); | ||
EXPECT_EQ(uf.find(4), 4); | ||
|
||
EXPECT_EQ(uf.numberOfSets(), 2); | ||
} | ||
|
||
TEST(UnionFindTest, SimpleMergeTest4) | ||
{ | ||
unionfind::UnionFind uf{5}; | ||
|
||
uf.merge(0, 4); | ||
uf.merge(2, 3); | ||
uf.merge(0, 1); | ||
uf.merge(3, 0); | ||
|
||
EXPECT_EQ(uf.find(0), 4); | ||
EXPECT_EQ(uf.find(1), 4); | ||
EXPECT_EQ(uf.find(2), 4); | ||
EXPECT_EQ(uf.find(3), 4); | ||
EXPECT_EQ(uf.find(4), 4); | ||
|
||
EXPECT_EQ(uf.numberOfSets(), 1); | ||
} |