source/RootPatriciaTreeAbstractPartition.h (124 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include <initializer_list> #include <vector> #include <boost/iterator/transform_iterator.hpp> #include <AbstractDomain.h> #include <PatriciaTreeMapAbstractPartition.h> #include <mariana-trench/Access.h> namespace marianatrench { /** * A patricia tree map abstract partition from root to the given domain. */ template <typename Domain> class RootPatriciaTreeAbstractPartition final : public sparta::AbstractDomain<RootPatriciaTreeAbstractPartition<Domain>> { private: using Map = sparta::PatriciaTreeMapAbstractPartition<Root::IntegerEncoding, Domain>; // Since the patricia tree map key needs to be an integer, we need this to // transform the key back to a `Root` when iterating on the map. struct ExposeBinding { const std::pair<Root, Domain>& operator()( const std::pair<Root::IntegerEncoding, Domain>& pair) const { // This is safe as long as `Root` stores `IntegerEncoding` internally. return *reinterpret_cast<const std::pair<Root, Domain>*>(&pair); } }; public: // C++ container concept member types using key_type = Root; using mapped_type = Domain; using value_type = std::pair<Root, Domain>; using iterator = boost::transform_iterator<ExposeBinding, typename Map::MapType::iterator>; using const_iterator = iterator; using difference_type = std::ptrdiff_t; using size_type = std::size_t; using const_reference = const value_type&; using const_pointer = const value_type*; private: // Safety checks of `boost::transform_iterator`. static_assert(std::is_same_v<typename iterator::value_type, value_type>); static_assert( std::is_same_v<typename iterator::difference_type, difference_type>); static_assert(std::is_same_v<typename iterator::reference, const_reference>); static_assert(std::is_same_v<typename iterator::pointer, const_pointer>); private: explicit RootPatriciaTreeAbstractPartition(Map map) : map_(std::move(map)) {} public: /* Return the bottom value (i.e, the empty tree). */ RootPatriciaTreeAbstractPartition() = default; RootPatriciaTreeAbstractPartition( std::initializer_list<std::pair<Root, Domain>> bindings) { for (const auto& [root, value] : bindings) { set(root, value); } } RootPatriciaTreeAbstractPartition( const std::vector<std::pair<Root, Domain>>& bindings) { for (const auto& [root, value] : bindings) { set(root, value); } } RootPatriciaTreeAbstractPartition(const RootPatriciaTreeAbstractPartition&) = default; RootPatriciaTreeAbstractPartition(RootPatriciaTreeAbstractPartition&&) = default; RootPatriciaTreeAbstractPartition& operator=( const RootPatriciaTreeAbstractPartition&) = default; RootPatriciaTreeAbstractPartition& operator=( RootPatriciaTreeAbstractPartition&&) = default; static RootPatriciaTreeAbstractPartition bottom() { return RootPatriciaTreeAbstractPartition(Map::bottom()); } static RootPatriciaTreeAbstractPartition top() { return RootPatriciaTreeAbstractPartition(Map::top()); } bool is_bottom() const override { return map_.is_bottom(); } bool is_top() const override { return map_.is_top(); } void set_to_bottom() override { map_.set_to_bottom(); } void set_to_top() override { map_.set_to_top(); } /* Return the number of bindings not set to bottom. */ std::size_t size() const { return map_.size(); } iterator begin() const { return boost::make_transform_iterator( map_.bindings().begin(), ExposeBinding()); } iterator end() const { return boost::make_transform_iterator( map_.bindings().end(), ExposeBinding()); } bool leq(const RootPatriciaTreeAbstractPartition& other) const override { return map_.leq(other.map_); } bool equals(const RootPatriciaTreeAbstractPartition& other) const override { return map_.equals(other.map_); } void join_with(const RootPatriciaTreeAbstractPartition& other) override { map_.join_with(other.map_); } void widen_with(const RootPatriciaTreeAbstractPartition& other) override { map_.widen_with(other.map_); } void meet_with(const RootPatriciaTreeAbstractPartition& other) override { map_.meet_with(other.map_); } void narrow_with(const RootPatriciaTreeAbstractPartition& other) override { map_.narrow_with(other.map_); } const Domain& get(Root root) const { return map_.get(root.encode()); } void set(Root root, const Domain& value) { map_.set(root.encode(), value); } void update(Root root, std::function<Domain(const Domain&)> operation) { map_.update(root.encode(), std::move(operation)); } bool map(std::function<Domain(const Domain&)> f) { return map_.map(std::move(f)); } private: Map map_; }; } // namespace marianatrench