// Copyright (c) 2022, The Monero Project // // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Miscellaneous container helpers. #pragma once //local headers //third party headers //standard headers #include #include #include //forward declarations namespace tools { /// convert an arbitrary function to functor template inline auto as_functor(F f) { return [f = std::move(f)](auto&&... args) { return f(std::forward(args)...); }; } /// convert a binary comparison function to a functor /// note: for most use-cases 'const T&' will work because only non-trivial types need a user-defined comparison operation template inline auto compare_func(ComparisonOpT comparison_op_func) { static_assert( std::is_same< bool, decltype( comparison_op_func( std::declval>(), std::declval>() ) ) >::value, "invalid callable - expected callable in form bool(T, T)" ); return as_functor(std::move(comparison_op_func)); } /// test if a container is sorted and unique according to a comparison criteria (defaults to operator<) /// NOTE: ComparisonOpT must establish 'strict weak ordering' https://en.cppreference.com/w/cpp/named_req/Compare template > bool is_sorted_and_unique(const T &container, ComparisonOpT comparison_op = ComparisonOpT{}) { using ValueT = typename T::value_type; static_assert( std::is_same< bool, decltype( comparison_op( std::declval>(), std::declval>() ) ) >::value, "invalid callable - expected callable in form bool(ValueT, ValueT)" ); if (!std::is_sorted(container.begin(), container.end(), comparison_op)) return false; if (std::adjacent_find(container.begin(), container.end(), [comparison_op = std::move(comparison_op)](const ValueT &a, const ValueT &b) -> bool { return !comparison_op(a, b) && !comparison_op(b, a); }) != container.end()) return false; return true; } /// specialization for raw function pointers template bool is_sorted_and_unique(const T &container, bool (*const comparison_op_func)(const typename T::value_type&, const typename T::value_type&)) { return is_sorted_and_unique(container, compare_func(comparison_op_func)); } /// convenience wrapper for checking if the key to a mapped object is correct for that object /// example: std::unorderd_map> where the map key is supposed to /// reproduce the pair's rct::key; use the predicate to check that relationship template bool keys_match_internal_values(const std::unordered_map &map, PredT check_key_func) { static_assert( std::is_same< bool, decltype( check_key_func( std::declval>(), std::declval>() ) ) >::value, "invalid callable - expected callable in form bool(KeyT, ValueT)" ); for (const auto &map_element : map) { if (!check_key_func(map_element.first, map_element.second)) return false; } return true; } /// convenience wrapper for getting the last element after emplacing back template typename ContainerT::value_type& add_element(ContainerT &container) { container.emplace_back(); return container.back(); } /// convenience erasor for unordered maps: std::erase_if(std::unordered_map) is C++20 template void for_all_in_map_erase_if(std::unordered_map &map_inout, PredT predicate) { using MapValueT = typename std::unordered_map::value_type; static_assert( std::is_same< bool, decltype(predicate(std::declval>())) >::value, "invalid callable - expected callable in form bool(Value)" ); for (auto map_it = map_inout.begin(); map_it != map_inout.end();) { if (predicate(*map_it)) map_it = map_inout.erase(map_it); else ++map_it; } } } //namespace tools