From 26d9ecb398d51d319ef956e160e261cb8b5284ad Mon Sep 17 00:00:00 2001 From: nadavi Date: Wed, 31 Mar 2021 20:37:44 +0000 Subject: [PATCH] split vtkm/Algorithms.h into UpperBound.h, LowerBound.h, and BinarySearch.h --- vtkm/Algorithms.h | 175 ++------------------------ vtkm/BinarySearch.h | 87 +++++++++++++ vtkm/CMakeLists.txt | 5 +- vtkm/LowerBound.h | 81 ++++++++++++ vtkm/UpperBound.h | 81 ++++++++++++ vtkm/cont/internal/FunctorsGeneral.h | 3 +- vtkm/testing/CMakeLists.txt | 4 +- vtkm/testing/UnitTestAlgorithms.cxx | 164 ------------------------ vtkm/testing/UnitTestBinarySearch.cxx | 88 +++++++++++++ vtkm/testing/UnitTestLowerBound.cxx | 74 +++++++++++ vtkm/testing/UnitTestUpperBound.cxx | 74 +++++++++++ 11 files changed, 502 insertions(+), 334 deletions(-) create mode 100644 vtkm/BinarySearch.h create mode 100644 vtkm/LowerBound.h create mode 100644 vtkm/UpperBound.h delete mode 100644 vtkm/testing/UnitTestAlgorithms.cxx create mode 100644 vtkm/testing/UnitTestBinarySearch.cxx create mode 100644 vtkm/testing/UnitTestLowerBound.cxx create mode 100644 vtkm/testing/UnitTestUpperBound.cxx diff --git a/vtkm/Algorithms.h b/vtkm/Algorithms.h index 2c53a4bd9..2d208b0b9 100644 --- a/vtkm/Algorithms.h +++ b/vtkm/Algorithms.h @@ -11,180 +11,21 @@ #ifndef vtk_m_Algorithms_h #define vtk_m_Algorithms_h -#include - -#include - -#include - -#include -#include +#include +#include +#include +#include namespace vtkm { -/// Similar to std::lower_bound and std::upper_bound, but returns an iterator -/// to any matching item (rather than a specific one). Returns @a last when -/// @a val is not found. -/// @{ -template -VTKM_EXEC_CONT IterT BinarySearch(IterT first, IterT last, const T& val, Comp comp) -{ - auto len = last - first; - while (len != 0) - { - const auto halfLen = len / 2; - IterT mid = first + halfLen; - if (comp(*mid, val)) - { - first = mid + 1; - len -= halfLen + 1; - } - else if (comp(val, *mid)) - { - len = halfLen; - } - else - { - return mid; // found element - } - } - return last; // did not find element -} +VTKM_DEPRECATED(1.6, "Use BinarySearch.h, LowerBound.h, or UpperBound.h instead of Algorithms.h.") +inline void Algorithms_h_deprecated() {} -template -VTKM_EXEC_CONT IterT BinarySearch(IterT first, IterT last, const T& val) +inline void ActivateAlgorithms_h_deprecated_warning() { - return vtkm::BinarySearch(first, last, val, vtkm::SortLess{}); + Algorithms_h_deprecated(); } -/// @} - -/// Similar to std::lower_bound and std::upper_bound, but returns the index of -/// any matching item (rather than a specific one). Returns -1 when @a val is not -/// found. -/// @{ -template -VTKM_EXEC_CONT vtkm::Id BinarySearch(const PortalT& portal, const T& val, Comp comp) -{ - auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); - auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); - auto result = vtkm::BinarySearch(first, last, val, comp); - return result == last ? static_cast(-1) : static_cast(result - first); -} - -// Return -1 if not found -template -VTKM_EXEC_CONT vtkm::Id BinarySearch(const PortalT& portal, const T& val) -{ - auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); - auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); - auto result = vtkm::BinarySearch(first, last, val, vtkm::SortLess{}); - return result == last ? static_cast(-1) : static_cast(result - first); -} -/// @} - -/// Implementation of std::lower_bound or std::upper_bound that is appropriate -/// for both control and execution environments. -/// The overloads that take portals return indices instead of iterators. -/// @{ -template -VTKM_EXEC_CONT IterT LowerBound(IterT first, IterT last, const T& val, Comp comp) -{ -#if defined(VTKM_CUDA) || defined(VTKM_HIP) - auto len = last - first; - while (len != 0) - { - const auto halfLen = len / 2; - IterT mid = first + halfLen; - if (comp(*mid, val)) - { - first = mid + 1; - len -= halfLen + 1; - } - else - { - len = halfLen; - } - } - return first; -#else // VTKM_CUDA || VTKM_HIP - return std::lower_bound(first, last, val, std::move(comp)); -#endif // VTKM_CUDA || VTKM_HIP -} - -template -VTKM_EXEC_CONT IterT LowerBound(IterT first, IterT last, const T& val) -{ - return vtkm::LowerBound(first, last, val, vtkm::SortLess{}); -} - -template -VTKM_EXEC_CONT vtkm::Id LowerBound(const PortalT& portal, const T& val, Comp comp) -{ - auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); - auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); - auto result = vtkm::LowerBound(first, last, val, comp); - return static_cast(result - first); -} - -template -VTKM_EXEC_CONT vtkm::Id LowerBound(const PortalT& portal, const T& val) -{ - auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); - auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); - auto result = vtkm::LowerBound(first, last, val, vtkm::SortLess{}); - return static_cast(result - first); -} - -template -VTKM_EXEC_CONT IterT UpperBound(IterT first, IterT last, const T& val, Comp comp) -{ -#if defined(VTKM_CUDA) || defined(VTKM_HIP) - auto len = last - first; - while (len != 0) - { - const auto halfLen = len / 2; - IterT mid = first + halfLen; - if (!comp(val, *mid)) - { - first = mid + 1; - len -= halfLen + 1; - } - else - { - len = halfLen; - } - } - return first; -#else // VTKM_CUDA || VTKM_HIP - return std::upper_bound(first, last, val, std::move(comp)); -#endif // VTKM_CUDA || VTKM_HIP -} - -template -VTKM_EXEC_CONT IterT UpperBound(IterT first, IterT last, const T& val) -{ - return vtkm::UpperBound(first, last, val, vtkm::SortLess{}); -} - -template -VTKM_EXEC_CONT vtkm::Id UpperBound(const PortalT& portal, const T& val, Comp comp) -{ - auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); - auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); - auto result = vtkm::UpperBound(first, last, val, comp); - return static_cast(result - first); -} - -template -VTKM_EXEC_CONT vtkm::Id UpperBound(const PortalT& portal, const T& val) -{ - auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); - auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); - auto result = vtkm::UpperBound(first, last, val, vtkm::SortLess{}); - return static_cast(result - first); -} -/// @} } // end namespace vtkm diff --git a/vtkm/BinarySearch.h b/vtkm/BinarySearch.h new file mode 100644 index 000000000..beea9ad18 --- /dev/null +++ b/vtkm/BinarySearch.h @@ -0,0 +1,87 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ + +#ifndef vtk_m_BinarySearch_h +#define vtk_m_BinarySearch_h + +#include +#include + +#include + +#include +#include + +namespace vtkm +{ + +/// Similar to std::lower_bound and std::upper_bound, but returns an iterator +/// to any matching item (rather than a specific one). Returns @a last when +/// @a val is not found. +/// @{ +template +VTKM_EXEC_CONT IterT BinarySearch(IterT first, IterT last, const T& val, Comp comp) +{ + auto len = last - first; + while (len != 0) + { + const auto halfLen = len / 2; + IterT mid = first + halfLen; + if (comp(*mid, val)) + { + first = mid + 1; + len -= halfLen + 1; + } + else if (comp(val, *mid)) + { + len = halfLen; + } + else + { + return mid; // found element + } + } + return last; // did not find element +} + +template +VTKM_EXEC_CONT IterT BinarySearch(IterT first, IterT last, const T& val) +{ + return vtkm::BinarySearch(first, last, val, vtkm::SortLess{}); +} +/// @} + +/// Similar to std::lower_bound and std::upper_bound, but returns the index of +/// any matching item (rather than a specific one). Returns -1 when @a val is not +/// found. +/// @{ +template +VTKM_EXEC_CONT vtkm::Id BinarySearch(const PortalT& portal, const T& val, Comp comp) +{ + auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); + auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); + auto result = vtkm::BinarySearch(first, last, val, comp); + return result == last ? static_cast(-1) : static_cast(result - first); +} + +// Return -1 if not found +template +VTKM_EXEC_CONT vtkm::Id BinarySearch(const PortalT& portal, const T& val) +{ + auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); + auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); + auto result = vtkm::BinarySearch(first, last, val, vtkm::SortLess{}); + return result == last ? static_cast(-1) : static_cast(result - first); +} +/// @} + +} // end namespace vtkm + +#endif // vtk_m_BinarySearch_h diff --git a/vtkm/CMakeLists.txt b/vtkm/CMakeLists.txt index ef6d4b187..2dd87eafb 100644 --- a/vtkm/CMakeLists.txt +++ b/vtkm/CMakeLists.txt @@ -17,11 +17,12 @@ vtkm_install_headers( vtkm ${VTKm_BINARY_INCLUDE_DIR}/${kit_dir}/Version.h) set(headers - Algorithms.h + Algorithms.h # Deprecated, split into BinarySearch.h, LowerBound.h, UpperBound.h Assert.h Atomic.h BinaryPredicates.h BinaryOperators.h + BinarySearch.h Bitset.h Bounds.h CellClassification.h @@ -35,6 +36,7 @@ set(headers ImplicitFunction.h List.h ListTag.h + LowerBound.h Math.h Matrix.h NewtonsMethod.h @@ -63,6 +65,7 @@ set(headers VecVariable.h VirtualObjectBase.h UnaryPredicates.h + UpperBound.h ) set(template_sources diff --git a/vtkm/LowerBound.h b/vtkm/LowerBound.h new file mode 100644 index 000000000..4c7a4374e --- /dev/null +++ b/vtkm/LowerBound.h @@ -0,0 +1,81 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ + +#ifndef vtk_m_LowerBound_h +#define vtk_m_LowerBound_h + +#include +#include + +#include + +#include +#include + +namespace vtkm +{ + +/// Implementation of std::lower_bound that is appropriate +/// for both control and execution environments. +/// The overloads that take portals return indices instead of iterators. +/// @{ +template +VTKM_EXEC_CONT IterT LowerBound(IterT first, IterT last, const T& val, Comp comp) +{ +#if defined(VTKM_CUDA) || defined(VTKM_HIP) + auto len = last - first; + while (len != 0) + { + const auto halfLen = len / 2; + IterT mid = first + halfLen; + if (comp(*mid, val)) + { + first = mid + 1; + len -= halfLen + 1; + } + else + { + len = halfLen; + } + } + return first; +#else // VTKM_CUDA || VTKM_HIP + return std::lower_bound(first, last, val, std::move(comp)); +#endif // VTKM_CUDA || VTKM_HIP +} + +template +VTKM_EXEC_CONT IterT LowerBound(IterT first, IterT last, const T& val) +{ + return vtkm::LowerBound(first, last, val, vtkm::SortLess{}); +} + +template +VTKM_EXEC_CONT vtkm::Id LowerBound(const PortalT& portal, const T& val, Comp comp) +{ + auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); + auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); + auto result = vtkm::LowerBound(first, last, val, comp); + return static_cast(result - first); +} + +template +VTKM_EXEC_CONT vtkm::Id LowerBound(const PortalT& portal, const T& val) +{ + auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); + auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); + auto result = vtkm::LowerBound(first, last, val, vtkm::SortLess{}); + return static_cast(result - first); +} +/// @} + +} // end namespace vtkm + +#endif // vtk_m_LowerBound_h diff --git a/vtkm/UpperBound.h b/vtkm/UpperBound.h new file mode 100644 index 000000000..2e5c5793e --- /dev/null +++ b/vtkm/UpperBound.h @@ -0,0 +1,81 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ + +#ifndef vtk_m_UpperBound_h +#define vtk_m_UpperBound_h + +#include +#include + +#include + +#include +#include + +namespace vtkm +{ + +/// Implementation of std::upper_bound that is appropriate +/// for both control and execution environments. +/// The overloads that take portals return indices instead of iterators. +/// @{ +template +VTKM_EXEC_CONT IterT UpperBound(IterT first, IterT last, const T& val, Comp comp) +{ +#if defined(VTKM_CUDA) || defined(VTKM_HIP) + auto len = last - first; + while (len != 0) + { + const auto halfLen = len / 2; + IterT mid = first + halfLen; + if (!comp(val, *mid)) + { + first = mid + 1; + len -= halfLen + 1; + } + else + { + len = halfLen; + } + } + return first; +#else // VTKM_CUDA || VTKM_HIP + return std::upper_bound(first, last, val, std::move(comp)); +#endif // VTKM_CUDA || VTKM_HIP +} + +template +VTKM_EXEC_CONT IterT UpperBound(IterT first, IterT last, const T& val) +{ + return vtkm::UpperBound(first, last, val, vtkm::SortLess{}); +} + +template +VTKM_EXEC_CONT vtkm::Id UpperBound(const PortalT& portal, const T& val, Comp comp) +{ + auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); + auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); + auto result = vtkm::UpperBound(first, last, val, comp); + return static_cast(result - first); +} + +template +VTKM_EXEC_CONT vtkm::Id UpperBound(const PortalT& portal, const T& val) +{ + auto first = vtkm::cont::ArrayPortalToIteratorBegin(portal); + auto last = vtkm::cont::ArrayPortalToIteratorEnd(portal); + auto result = vtkm::UpperBound(first, last, val, vtkm::SortLess{}); + return static_cast(result - first); +} +/// @} + +} // end namespace vtkm + +#endif // vtk_m_UpperBound_h diff --git a/vtkm/cont/internal/FunctorsGeneral.h b/vtkm/cont/internal/FunctorsGeneral.h index 976a2b0a2..f8e54c1b6 100644 --- a/vtkm/cont/internal/FunctorsGeneral.h +++ b/vtkm/cont/internal/FunctorsGeneral.h @@ -10,11 +10,12 @@ #ifndef vtk_m_cont_internal_FunctorsGeneral_h #define vtk_m_cont_internal_FunctorsGeneral_h -#include #include #include +#include #include #include +#include #include #include diff --git a/vtkm/testing/CMakeLists.txt b/vtkm/testing/CMakeLists.txt index ab20a46f3..1afcca38c 100644 --- a/vtkm/testing/CMakeLists.txt +++ b/vtkm/testing/CMakeLists.txt @@ -49,10 +49,12 @@ set(unit_tests # Unit tests that have device-specific code to be tested set(unit_tests_device - UnitTestAlgorithms.cxx UnitTestAtomic.cxx + UnitTestBinarySearch.cxx UnitTestGeometry.cxx + UnitTestLowerBound.cxx UnitTestMath.cxx + UnitTestUpperBound.cxx ) diff --git a/vtkm/testing/UnitTestAlgorithms.cxx b/vtkm/testing/UnitTestAlgorithms.cxx deleted file mode 100644 index 994e3cd1a..000000000 --- a/vtkm/testing/UnitTestAlgorithms.cxx +++ /dev/null @@ -1,164 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include - -#include -#include - -#include - -#include - -#include - -namespace -{ - -using IdArray = vtkm::cont::ArrayHandle; - -struct TestBinarySearch -{ - struct Impl : public vtkm::worklet::WorkletMapField - { - using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); - using ExecutionSignature = _3(_1, _2); - using InputDomain = _1; - - template - VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const - { - return vtkm::BinarySearch(haystack, needle); - } - }; - - static void Run() - { - IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); - IdArray haystack = - vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); - IdArray results; - - std::vector expectedFound{ - false, true, true, false, true, true, false, false, true, false - }; - - vtkm::cont::Invoker invoke; - invoke(Impl{}, needles, haystack, results); - - // Verify: - auto needlesPortal = needles.ReadPortal(); - auto haystackPortal = haystack.ReadPortal(); - auto resultsPortal = results.ReadPortal(); - for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) - { - if (expectedFound[static_cast(i)]) - { - const auto resIdx = resultsPortal.Get(i); - const auto expVal = needlesPortal.Get(i); - VTKM_TEST_ASSERT(resIdx >= 0); - VTKM_TEST_ASSERT(haystackPortal.Get(resIdx) == expVal); - } - else - { - VTKM_TEST_ASSERT(resultsPortal.Get(i) == -1); - } - } - } -}; - -struct TestLowerBound -{ - struct Impl : public vtkm::worklet::WorkletMapField - { - using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); - using ExecutionSignature = _3(_1, _2); - using InputDomain = _1; - - template - VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const - { - return vtkm::LowerBound(haystack, needle); - } - }; - - static void Run() - { - IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); - IdArray haystack = - vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); - IdArray results; - - std::vector expected{ 0, 0, 1, 4, 4, 6, 9, 9, 9, 11 }; - - vtkm::cont::Invoker invoke; - invoke(Impl{}, needles, haystack, results); - - // Verify: - auto resultsPortal = results.ReadPortal(); - for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) - { - VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); - } - } -}; - -struct TestUpperBound -{ - struct Impl : public vtkm::worklet::WorkletMapField - { - using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); - using ExecutionSignature = _3(_1, _2); - using InputDomain = _1; - - template - VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const - { - return vtkm::UpperBound(haystack, needle); - } - }; - - static void Run() - { - IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); - IdArray haystack = - vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); - IdArray results; - - std::vector expected{ 0, 1, 4, 4, 6, 9, 9, 9, 11, 11 }; - - vtkm::cont::Invoker invoke; - invoke(Impl{}, needles, haystack, results); - - // Verify: - auto resultsPortal = results.ReadPortal(); - for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) - { - VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); - } - } -}; - -void RunAlgorithmsTests() -{ - std::cout << "Testing binary search." << std::endl; - TestBinarySearch::Run(); - std::cout << "Testing lower bound." << std::endl; - TestLowerBound::Run(); - std::cout << "Testing upper bound." << std::endl; - TestUpperBound::Run(); -} - -} // anon namespace - -int UnitTestAlgorithms(int argc, char* argv[]) -{ - return vtkm::cont::testing::Testing::Run(RunAlgorithmsTests, argc, argv); -} diff --git a/vtkm/testing/UnitTestBinarySearch.cxx b/vtkm/testing/UnitTestBinarySearch.cxx new file mode 100644 index 000000000..ada7fc104 --- /dev/null +++ b/vtkm/testing/UnitTestBinarySearch.cxx @@ -0,0 +1,88 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ + +#include + +#include +#include + +#include + +#include + +#include + +namespace +{ + +using IdArray = vtkm::cont::ArrayHandle; + +struct TestBinarySearch +{ + struct Impl : public vtkm::worklet::WorkletMapField + { + using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); + using ExecutionSignature = _3(_1, _2); + using InputDomain = _1; + + template + VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const + { + return vtkm::BinarySearch(haystack, needle); + } + }; + + static void Run() + { + IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); + IdArray haystack = + vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); + IdArray results; + + std::vector expectedFound{ + false, true, true, false, true, true, false, false, true, false + }; + + vtkm::cont::Invoker invoke; + invoke(Impl{}, needles, haystack, results); + + // Verify: + auto needlesPortal = needles.ReadPortal(); + auto haystackPortal = haystack.ReadPortal(); + auto resultsPortal = results.ReadPortal(); + for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) + { + if (expectedFound[static_cast(i)]) + { + const auto resIdx = resultsPortal.Get(i); + const auto expVal = needlesPortal.Get(i); + VTKM_TEST_ASSERT(resIdx >= 0); + VTKM_TEST_ASSERT(haystackPortal.Get(resIdx) == expVal); + } + else + { + VTKM_TEST_ASSERT(resultsPortal.Get(i) == -1); + } + } + } +}; + +void RunBinarySearchTest() +{ + std::cout << "Testing binary search." << std::endl; + TestBinarySearch::Run(); +} + +} // anon namespace + +int UnitTestBinarySearch(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(RunBinarySearchTest, argc, argv); +} diff --git a/vtkm/testing/UnitTestLowerBound.cxx b/vtkm/testing/UnitTestLowerBound.cxx new file mode 100644 index 000000000..11e5667f9 --- /dev/null +++ b/vtkm/testing/UnitTestLowerBound.cxx @@ -0,0 +1,74 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ + +#include + +#include +#include + +#include + +#include + +#include + +namespace +{ + +using IdArray = vtkm::cont::ArrayHandle; + +struct TestLowerBound +{ + struct Impl : public vtkm::worklet::WorkletMapField + { + using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); + using ExecutionSignature = _3(_1, _2); + using InputDomain = _1; + + template + VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const + { + return vtkm::LowerBound(haystack, needle); + } + }; + + static void Run() + { + IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); + IdArray haystack = + vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); + IdArray results; + + std::vector expected{ 0, 0, 1, 4, 4, 6, 9, 9, 9, 11 }; + + vtkm::cont::Invoker invoke; + invoke(Impl{}, needles, haystack, results); + + // Verify: + auto resultsPortal = results.ReadPortal(); + for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) + { + VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); + } + } +}; + +void RunLowerBoundTest() +{ + std::cout << "Testing lower bound." << std::endl; + TestLowerBound::Run(); +} + +} // anon namespace + +int UnitTestLowerBound(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(RunLowerBoundTest, argc, argv); +} diff --git a/vtkm/testing/UnitTestUpperBound.cxx b/vtkm/testing/UnitTestUpperBound.cxx new file mode 100644 index 000000000..19d08c0fa --- /dev/null +++ b/vtkm/testing/UnitTestUpperBound.cxx @@ -0,0 +1,74 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +//============================================================================ + +#include + +#include +#include + +#include + +#include + +#include + +namespace +{ + +using IdArray = vtkm::cont::ArrayHandle; + +struct TestUpperBound +{ + struct Impl : public vtkm::worklet::WorkletMapField + { + using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); + using ExecutionSignature = _3(_1, _2); + using InputDomain = _1; + + template + VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const + { + return vtkm::UpperBound(haystack, needle); + } + }; + + static void Run() + { + IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); + IdArray haystack = + vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); + IdArray results; + + std::vector expected{ 0, 1, 4, 4, 6, 9, 9, 9, 11, 11 }; + + vtkm::cont::Invoker invoke; + invoke(Impl{}, needles, haystack, results); + + // Verify: + auto resultsPortal = results.ReadPortal(); + for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) + { + VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); + } + } +}; + +void RunUpperBoundTest() +{ + std::cout << "Testing upper bound." << std::endl; + TestUpperBound::Run(); +} + +} // anon namespace + +int UnitTestUpperBound(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(RunUpperBoundTest, argc, argv); +}