diff --git a/CMakeLists.txt b/CMakeLists.txt index f21e5ecf..87b495a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,6 +189,7 @@ list ( APPEND UTIL_FILES adapter.hpp adapter.cpp + algo/search.hpp algo/sort.cpp algo/sort.hpp alloc/fwd.hpp @@ -508,6 +509,7 @@ if (TESTS) list ( APPEND TEST_BIN ascii + algo/search algo/sort alloc/aligned/foreign alloc/aligned/direct diff --git a/algo/search.hpp b/algo/search.hpp new file mode 100644 index 00000000..dc6b3d41 --- /dev/null +++ b/algo/search.hpp @@ -0,0 +1,43 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright: + * 2018, Danny Robson + */ + +#pragma once + +#include + + +namespace cruft::search { + /// Performs a linear search to discover the iterator corresponding to + /// the value which minimises a function. + /// + /// Useful as a mechanism to avoid possibly expensive comparison + /// calculations; eg recomputing path distances when testing a series of + /// possible routes. + /// + /// The provided function will be invoked with the supplied argument pack + /// as the first arguments and the dereferenced iterator as the final + /// argument. + template + InputT + minimises (InputT first, InputT last, FunctionT &&func, Args &&...args) + { + auto best_score = std::invoke (func, args..., *first); + auto best_item = first; + + for (++first; first != last; ++first) { + auto this_score = std::invoke (func, args..., *first); + if (this_score < best_score) { + best_score = this_score; + best_item = first; + } + } + + return best_item; + } +} \ No newline at end of file diff --git a/test/algo/search.cpp b/test/algo/search.cpp new file mode 100644 index 00000000..e8ef3bbf --- /dev/null +++ b/test/algo/search.cpp @@ -0,0 +1,45 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright: + * 2018, Danny Robson + */ + +#include +#include +#include + + +int +main (void) +{ + cruft::TAP::logger tap; + + // Check that 'minimises' uses the distance2 metric to correctly find the + // closest point to the origin. + { + cruft::point3f const dst { 0, 0, 0 }; + + cruft::point3f const src[] { + { 9, 9, 9 }, + { 3, 4, 55 }, + { 5, 1, 1 }, + { 13, 4, 6 }, + }; + + + auto best = cruft::search::minimises ( + std::begin (src), + std::end (src), + [] (auto const a, auto const b) { return cruft::distance2 (a, b); }, + dst + ); + + tap.expect_eq (best, src + 2, "minimises point3 using distance2"); + } + + + return tap.status (); +}