/* * Souffle - A Datalog Compiler * Copyright (c) 2021, The Souffle Developers. All rights reserved * Licensed under the Universal Permissive License v 1.0 as shown at: * - https://opensource.org/licenses/UPL * - /licenses/SOUFFLE-UPL.txt */ /************************************************************************ * * @file ContainerUtil.h * * @brief Datalog project utilities * ***********************************************************************/ #pragma once #include "souffle/utility/DynamicCasting.h" #include "souffle/utility/Iteration.h" #include "souffle/utility/MiscUtil.h" #include "souffle/utility/Types.h" #include #include #include #include #include #include #include #include namespace souffle { // ------------------------------------------------------------------------------- // General Container Utilities // ------------------------------------------------------------------------------- /** * Use to range-for iterate in reverse. * Assumes `std::rbegin` and `std::rend` are defined for type `A`. */ template struct reverse { reverse(A& iterable) : iterable(iterable) {} A& iterable; auto begin() { return std::rbegin(iterable); } auto end() { return std::rend(iterable); } }; /** * A utility to check generically whether a given element is contained in a given * container. */ template >> bool contains(const C& container, const typename C::value_type& element) { return std::find(container.begin(), container.end(), element) != container.end(); } /** * A utility to check generically whether a given key exists within a given * associative container. */ template >> bool contains(const C& container, A&& element) { return container.find(element) != container.end(); } /** * Returns the first element in a container that satisfies a given predicate, * nullptr otherwise. */ template auto getIf(C&& container, F&& pred) { auto it = std::find_if(container.begin(), container.end(), std::forward(pred)); return it == container.end() ? nullptr : *it; } /** * Get value for a given key; if not found, return default value. */ template >> typename C::mapped_type const& getOr( const C& container, A&& key, const typename C::mapped_type& defaultValue) { auto it = container.find(key); if (it != container.end()) { return it->second; } else { return defaultValue; } } /** * Append elements to a container */ template void append(C& container, R&& range) { container.insert(container.end(), std::begin(range), std::end(range)); } /** * A utility function enabling the creation of a vector with a fixed set of * elements within a single expression. This is the base case covering empty * vectors. */ template std::vector toVector() { return std::vector(); } /** * A utility function enabling the creation of a vector with a fixed set of * elements within a single expression. This is the step case covering vectors * of arbitrary length. */ template std::vector toVector(T first, R... rest) { // Init-lists are effectively const-arrays. You can't `move` out of them. // Combine with `vector`s not having variadic constructors, can't do: // `vector{Own{}, Own{}}` // This is inexcusably awful and defeats the purpose of having init-lists. std::vector xs; T ary[] = {std::move(first), std::move(rest)...}; for (auto& x : ary) { xs.push_back(std::move(x)); } return xs; } /** * A utility function enabling the creation of a vector of pointers. */ template , T, A>> std::vector toPtrVector(const VecOwn& v) { std::vector res; for (auto& e : v) { res.push_back(e.get()); } return res; } // ------------------------------------------------------------------------------- // Equality Utilities // ------------------------------------------------------------------------------- /** * Cast the values, from baseType to toType and compare using ==. (if casting fails -> return false.) * * @tparam baseType, initial Type of values * @tparam toType, type where equality comparison takes place. */ template bool castEq(const baseType* left, const baseType* right) { if (auto castedLeft = as(left)) { if (auto castedRight = as(right)) { return castedLeft == castedRight; } } return false; } /** * A functor class supporting the values pointers are pointing to. */ template struct comp_deref { bool operator()(const T& a, const T& b) const { if (a == nullptr) { return false; } if (b == nullptr) { return false; } return *a == *b; } }; /** * A function testing whether two containers are equal with the given Comparator. */ template bool equal_targets(const Container& a, const Container& b, const Comparator& comp) { // check reference if (&a == &b) { return true; } // check size if (a.size() != b.size()) { return false; } // check content return std::equal(a.begin(), a.end(), b.begin(), comp); } /** * A function testing whether two containers of pointers are referencing equivalent * targets. */ template class Container> bool equal_targets(const Container& a, const Container& b) { return equal_targets(a, b, comp_deref()); } /** * A function testing whether two containers of unique pointers are referencing equivalent * targets. */ template class Container> bool equal_targets(const Container>& a, const Container>& b) { return equal_targets(a, b, comp_deref>()); } #ifdef _MSC_VER // issue: // https://developercommunity.visualstudio.com/t/c-template-template-not-recognized-as-class-templa/558979 template bool equal_targets(const std::vector>& a, const std::vector>& b) { return equal_targets(a, b, comp_deref>()); } template bool equal_targets(const std::vector& a, const std::vector& b) { return equal_targets(a, b, comp_deref()); } #endif /** * A function testing whether two maps of unique pointers are referencing to equivalent * targets. */ template bool equal_targets(const std::map>& a, const std::map>& b) { auto comp = comp_deref>(); return equal_targets( a, b, [&comp](auto& a, auto& b) { return a.first == b.first && comp(a.second, b.second); }); } /** * A function testing whether two maps are equivalent using projected values. */ template bool equal_targets_map(const std::map& a, const std::map& b, F&& comp) { return equal_targets( a, b, [&](auto& a, auto& b) { return a.first == b.first && comp(a.second, b.second); }); } // ------------------------------------------------------------------------------- // Checking Utilities // ------------------------------------------------------------------------------- template bool allValidPtrs(R const& range) { return std::all_of(range.begin(), range.end(), [](auto&& p) { return (bool)p; }); } } // namespace souffle namespace std { template struct iterator_traits> { using iter_t = std::iterator_traits; using iter_tag = typename iter_t::iterator_category; using difference_type = typename iter_t::difference_type; using reference = decltype(std::declval()(*std::declval())); using value_type = std::remove_cv_t>; using iterator_category = std::conditional_t, std::random_access_iterator_tag, iter_tag>; }; } // namespace std