| 1 | /*
|
| 2 | * Souffle - A Datalog Compiler
|
| 3 | * Copyright (c) 2021, The Souffle Developers. All rights reserved
|
| 4 | * Licensed under the Universal Permissive License v 1.0 as shown at:
|
| 5 | * - https://opensource.org/licenses/UPL
|
| 6 | * - <souffle root>/licenses/SOUFFLE-UPL.txt
|
| 7 | */
|
| 8 |
|
| 9 | /************************************************************************
|
| 10 | *
|
| 11 | * @file ContainerUtil.h
|
| 12 | *
|
| 13 | * @brief Datalog project utilities
|
| 14 | *
|
| 15 | ***********************************************************************/
|
| 16 |
|
| 17 | #pragma once
|
| 18 |
|
| 19 | #include "souffle/utility/DynamicCasting.h"
|
| 20 | #include "souffle/utility/Iteration.h"
|
| 21 | #include "souffle/utility/MiscUtil.h"
|
| 22 | #include "souffle/utility/Types.h"
|
| 23 |
|
| 24 | #include <algorithm>
|
| 25 | #include <functional>
|
| 26 | #include <iterator>
|
| 27 | #include <map>
|
| 28 | #include <set>
|
| 29 | #include <type_traits>
|
| 30 | #include <utility>
|
| 31 | #include <vector>
|
| 32 |
|
| 33 | namespace souffle {
|
| 34 |
|
| 35 | // -------------------------------------------------------------------------------
|
| 36 | // General Container Utilities
|
| 37 | // -------------------------------------------------------------------------------
|
| 38 |
|
| 39 | /**
|
| 40 | * Use to range-for iterate in reverse.
|
| 41 | * Assumes `std::rbegin` and `std::rend` are defined for type `A`.
|
| 42 | */
|
| 43 | template <typename A>
|
| 44 | struct reverse {
|
| 45 | reverse(A& iterable) : iterable(iterable) {}
|
| 46 | A& iterable;
|
| 47 |
|
| 48 | auto begin() {
|
| 49 | return std::rbegin(iterable);
|
| 50 | }
|
| 51 |
|
| 52 | auto end() {
|
| 53 | return std::rend(iterable);
|
| 54 | }
|
| 55 | };
|
| 56 |
|
| 57 | /**
|
| 58 | * A utility to check generically whether a given element is contained in a given
|
| 59 | * container.
|
| 60 | */
|
| 61 | template <typename C, typename = std::enable_if_t<!is_associative<C>>>
|
| 62 | bool contains(const C& container, const typename C::value_type& element) {
|
| 63 | return std::find(container.begin(), container.end(), element) != container.end();
|
| 64 | }
|
| 65 |
|
| 66 | /**
|
| 67 | * A utility to check generically whether a given key exists within a given
|
| 68 | * associative container.
|
| 69 | */
|
| 70 | template <typename C, typename A, typename = std::enable_if_t<is_associative<C>>>
|
| 71 | bool contains(const C& container, A&& element) {
|
| 72 | return container.find(element) != container.end();
|
| 73 | }
|
| 74 |
|
| 75 | /**
|
| 76 | * Returns the first element in a container that satisfies a given predicate,
|
| 77 | * nullptr otherwise.
|
| 78 | */
|
| 79 | template <typename C, typename F>
|
| 80 | auto getIf(C&& container, F&& pred) {
|
| 81 | auto it = std::find_if(container.begin(), container.end(), std::forward<F>(pred));
|
| 82 | return it == container.end() ? nullptr : *it;
|
| 83 | }
|
| 84 |
|
| 85 | /**
|
| 86 | * Get value for a given key; if not found, return default value.
|
| 87 | */
|
| 88 | template <typename C, typename A, typename = std::enable_if_t<is_associative<C>>>
|
| 89 | typename C::mapped_type const& getOr(
|
| 90 | const C& container, A&& key, const typename C::mapped_type& defaultValue) {
|
| 91 | auto it = container.find(key);
|
| 92 |
|
| 93 | if (it != container.end()) {
|
| 94 | return it->second;
|
| 95 | } else {
|
| 96 | return defaultValue;
|
| 97 | }
|
| 98 | }
|
| 99 |
|
| 100 | /**
|
| 101 | * Append elements to a container
|
| 102 | */
|
| 103 | template <class C, typename R>
|
| 104 | void append(C& container, R&& range) {
|
| 105 | container.insert(container.end(), std::begin(range), std::end(range));
|
| 106 | }
|
| 107 |
|
| 108 | /**
|
| 109 | * A utility function enabling the creation of a vector with a fixed set of
|
| 110 | * elements within a single expression. This is the base case covering empty
|
| 111 | * vectors.
|
| 112 | */
|
| 113 | template <typename T>
|
| 114 | std::vector<T> toVector() {
|
| 115 | return std::vector<T>();
|
| 116 | }
|
| 117 |
|
| 118 | /**
|
| 119 | * A utility function enabling the creation of a vector with a fixed set of
|
| 120 | * elements within a single expression. This is the step case covering vectors
|
| 121 | * of arbitrary length.
|
| 122 | */
|
| 123 | template <typename T, typename... R>
|
| 124 | std::vector<T> toVector(T first, R... rest) {
|
| 125 | // Init-lists are effectively const-arrays. You can't `move` out of them.
|
| 126 | // Combine with `vector`s not having variadic constructors, can't do:
|
| 127 | // `vector{Own<A>{}, Own<A>{}}`
|
| 128 | // This is inexcusably awful and defeats the purpose of having init-lists.
|
| 129 | std::vector<T> xs;
|
| 130 | T ary[] = {std::move(first), std::move(rest)...};
|
| 131 | for (auto& x : ary) {
|
| 132 | xs.push_back(std::move(x));
|
| 133 | }
|
| 134 | return xs;
|
| 135 | }
|
| 136 |
|
| 137 | /**
|
| 138 | * A utility function enabling the creation of a vector of pointers.
|
| 139 | */
|
| 140 | template <typename A = void, typename T, typename U = std::conditional_t<std::is_same_v<A, void>, T, A>>
|
| 141 | std::vector<U*> toPtrVector(const VecOwn<T>& v) {
|
| 142 | std::vector<U*> res;
|
| 143 | for (auto& e : v) {
|
| 144 | res.push_back(e.get());
|
| 145 | }
|
| 146 | return res;
|
| 147 | }
|
| 148 |
|
| 149 | // -------------------------------------------------------------------------------
|
| 150 | // Equality Utilities
|
| 151 | // -------------------------------------------------------------------------------
|
| 152 |
|
| 153 | /**
|
| 154 | * Cast the values, from baseType to toType and compare using ==. (if casting fails -> return false.)
|
| 155 | *
|
| 156 | * @tparam baseType, initial Type of values
|
| 157 | * @tparam toType, type where equality comparison takes place.
|
| 158 | */
|
| 159 | template <typename toType, typename baseType>
|
| 160 | bool castEq(const baseType* left, const baseType* right) {
|
| 161 | if (auto castedLeft = as<toType>(left)) {
|
| 162 | if (auto castedRight = as<toType>(right)) {
|
| 163 | return castedLeft == castedRight;
|
| 164 | }
|
| 165 | }
|
| 166 | return false;
|
| 167 | }
|
| 168 |
|
| 169 | /**
|
| 170 | * A functor class supporting the values pointers are pointing to.
|
| 171 | */
|
| 172 | template <typename T>
|
| 173 | struct comp_deref {
|
| 174 | bool operator()(const T& a, const T& b) const {
|
| 175 | if (a == nullptr) {
|
| 176 | return false;
|
| 177 | }
|
| 178 | if (b == nullptr) {
|
| 179 | return false;
|
| 180 | }
|
| 181 | return *a == *b;
|
| 182 | }
|
| 183 | };
|
| 184 |
|
| 185 | /**
|
| 186 | * A function testing whether two containers are equal with the given Comparator.
|
| 187 | */
|
| 188 | template <typename Container, typename Comparator>
|
| 189 | bool equal_targets(const Container& a, const Container& b, const Comparator& comp) {
|
| 190 | // check reference
|
| 191 | if (&a == &b) {
|
| 192 | return true;
|
| 193 | }
|
| 194 |
|
| 195 | // check size
|
| 196 | if (a.size() != b.size()) {
|
| 197 | return false;
|
| 198 | }
|
| 199 |
|
| 200 | // check content
|
| 201 | return std::equal(a.begin(), a.end(), b.begin(), comp);
|
| 202 | }
|
| 203 |
|
| 204 | /**
|
| 205 | * A function testing whether two containers of pointers are referencing equivalent
|
| 206 | * targets.
|
| 207 | */
|
| 208 | template <typename T, template <typename...> class Container>
|
| 209 | bool equal_targets(const Container<T*>& a, const Container<T*>& b) {
|
| 210 | return equal_targets(a, b, comp_deref<T*>());
|
| 211 | }
|
| 212 |
|
| 213 | /**
|
| 214 | * A function testing whether two containers of unique pointers are referencing equivalent
|
| 215 | * targets.
|
| 216 | */
|
| 217 | template <typename T, template <typename...> class Container>
|
| 218 | bool equal_targets(const Container<Own<T>>& a, const Container<Own<T>>& b) {
|
| 219 | return equal_targets(a, b, comp_deref<Own<T>>());
|
| 220 | }
|
| 221 |
|
| 222 | #ifdef _MSC_VER
|
| 223 | // issue:
|
| 224 | // https://developercommunity.visualstudio.com/t/c-template-template-not-recognized-as-class-templa/558979
|
| 225 | template <typename T>
|
| 226 | bool equal_targets(const std::vector<Own<T>>& a, const std::vector<Own<T>>& b) {
|
| 227 | return equal_targets(a, b, comp_deref<Own<T>>());
|
| 228 | }
|
| 229 |
|
| 230 | template <typename T>
|
| 231 | bool equal_targets(const std::vector<T>& a, const std::vector<T>& b) {
|
| 232 | return equal_targets(a, b, comp_deref<T>());
|
| 233 | }
|
| 234 | #endif
|
| 235 |
|
| 236 | /**
|
| 237 | * A function testing whether two maps of unique pointers are referencing to equivalent
|
| 238 | * targets.
|
| 239 | */
|
| 240 | template <typename Key, typename Value, typename Cmp>
|
| 241 | bool equal_targets(const std::map<Key, Own<Value>, Cmp>& a, const std::map<Key, Own<Value>, Cmp>& b) {
|
| 242 | auto comp = comp_deref<Own<Value>>();
|
| 243 | return equal_targets(
|
| 244 | a, b, [&comp](auto& a, auto& b) { return a.first == b.first && comp(a.second, b.second); });
|
| 245 | }
|
| 246 |
|
| 247 | /**
|
| 248 | * A function testing whether two maps are equivalent using projected values.
|
| 249 | */
|
| 250 | template <typename Key, typename Value, typename Cmp, typename F>
|
| 251 | bool equal_targets_map(const std::map<Key, Value, Cmp>& a, const std::map<Key, Value, Cmp>& b, F&& comp) {
|
| 252 | return equal_targets(
|
| 253 | a, b, [&](auto& a, auto& b) { return a.first == b.first && comp(a.second, b.second); });
|
| 254 | }
|
| 255 |
|
| 256 | // -------------------------------------------------------------------------------
|
| 257 | // Checking Utilities
|
| 258 | // -------------------------------------------------------------------------------
|
| 259 | template <typename R>
|
| 260 | bool allValidPtrs(R const& range) {
|
| 261 | return std::all_of(range.begin(), range.end(), [](auto&& p) { return (bool)p; });
|
| 262 | }
|
| 263 |
|
| 264 | } // namespace souffle
|
| 265 |
|
| 266 | namespace std {
|
| 267 | template <typename Iter, typename F>
|
| 268 | struct iterator_traits<souffle::TransformIterator<Iter, F>> {
|
| 269 | using iter_t = std::iterator_traits<Iter>;
|
| 270 | using iter_tag = typename iter_t::iterator_category;
|
| 271 | using difference_type = typename iter_t::difference_type;
|
| 272 | using reference = decltype(std::declval<F&>()(*std::declval<Iter>()));
|
| 273 | using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
|
| 274 | using iterator_category = std::conditional_t<std::is_base_of_v<std::random_access_iterator_tag, iter_tag>,
|
| 275 | std::random_access_iterator_tag, iter_tag>;
|
| 276 | };
|
| 277 | } // namespace std
|