Coverage Report

Created: 2026-10-26 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libyul/backends/evm/ssa/util/UseCountSet.h
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
19
#pragma once
20
21
#include <range/v3/range/concepts.hpp>
22
#include <range/v3/range/traits.hpp>
23
24
#include <algorithm>
25
#include <concepts>
26
#include <cstdint>
27
#include <iterator>
28
#include <utility>
29
#include <vector>
30
31
namespace solidity::yul::ssa::util
32
{
33
34
/// Vector-backed reference-counted set keyed on `Key`. Each entry carries a non-zero use count; absent keys have
35
/// effective count 0. Designed for small working sets such that linear scan beats the constant overhead
36
/// of a hashed or tree-based associative container.
37
template <std::equality_comparable Key>
38
class UseCountSet
39
{
40
public:
41
  using Value = Key;
42
  using Count = std::uint32_t;
43
  using Entries = std::vector<std::pair<Key, Count>>;
44
45
0
  UseCountSet() = default;
46
  template<std::input_iterator Iter, std::sentinel_for<Iter> Sentinel>
47
  UseCountSet(Iter _begin, Sentinel _end): m_entries(_begin, _end) {}
48
0
  explicit UseCountSet(Entries _entries): m_entries(std::move(_entries)) {}
49
50
  bool contains(Key const& _key) const
51
0
  {
52
0
    return findEntry(_key) != m_entries.end();
53
0
  }
Unexecuted instantiation: solidity::yul::ssa::util::UseCountSet<solidity::yul::ssa::InstId>::contains(solidity::yul::ssa::InstId const&) const
Unexecuted instantiation: solidity::yul::ssa::util::UseCountSet<solidity::yul::ssa::StackSlot>::contains(solidity::yul::ssa::StackSlot const&) const
54
  Count count(Key const& _key) const
55
  {
56
    auto const it = findEntry(_key);
57
    return it == m_entries.end() ? Count{0} : it->second;
58
  }
59
0
  typename Entries::const_iterator begin() const { return m_entries.begin(); }
60
0
  typename Entries::const_iterator end() const { return m_entries.end(); }
61
0
  typename Entries::size_type size() const { return m_entries.size(); }
62
  bool empty() const { return m_entries.empty(); }
63
64
  /// Add `_count` to existing entry or insert a new one. No-op if `_count == 0`.
65
  void insert(Key const& _key, Count _count = 1)
66
0
  {
67
0
    if (_count == 0)
68
0
      return;
69
0
    auto it = findEntry(_key);
70
0
    if (it != m_entries.end())
71
0
      it->second += _count;
72
0
    else
73
0
      m_entries.emplace_back(_key, _count);
74
0
  }
75
76
  /// Remove the entry for `_key` if present.
77
  void erase(Key const& _key)
78
0
  {
79
0
    if (auto const it = findEntry(_key); it != m_entries.end())
80
0
      m_entries.erase(it);
81
0
  }
82
83
  /// Subtract `_count` from the entry for `_key`, removing it if the count
84
  /// drops to zero. No-op if `_key` is absent or `_count == 0`.
85
  void remove(Key const& _key, Count _count = 1)
86
0
  {
87
0
    if (_count == 0)
88
0
      return;
89
0
    auto it = findEntry(_key);
90
0
    if (it == m_entries.end())
91
0
      return;
92
0
    if (it->second <= _count)
93
0
      m_entries.erase(it);
94
0
    else
95
0
      it->second -= _count;
96
0
  }
97
98
  /// Sum-merge counts from `_other` into this.
99
  UseCountSet& operator+=(UseCountSet const& _other)
100
0
  {
101
0
    for (auto const& [key, count]: _other.m_entries)
102
0
      insert(key, count);
103
0
    return *this;
104
0
  }
105
106
  /// Union with `_other`, taking max count per key.
107
  UseCountSet& maxUnion(UseCountSet const& _other)
108
0
  {
109
0
    for (auto const& [key, count]: _other.m_entries)
110
0
    {
111
0
      auto it = findEntry(key);
112
0
      if (it != m_entries.end())
113
0
        it->second = std::max(it->second, count);
114
0
      else
115
0
        m_entries.emplace_back(key, count);
116
0
    }
117
0
    return *this;
118
0
  }
119
120
  void insertAll(ranges::input_range auto&& _values) requires std::convertible_to<ranges::range_reference_t<decltype(_values)>, Key>
121
0
  {
122
0
    for (auto const& value: _values)
123
0
      insert(value);
124
0
  }
125
126
  void eraseAll(ranges::input_range auto&& _values) requires std::convertible_to<ranges::range_reference_t<decltype(_values)>, Key>
127
0
  {
128
0
    for (auto const& value: _values)
129
0
      erase(value);
130
0
  }
131
132
  template<typename Predicate>
133
  void eraseIf(Predicate&& _predicate)
134
0
  {
135
0
    std::erase_if(m_entries, std::forward<Predicate>(_predicate));
136
0
  }
137
138
private:
139
  typename Entries::iterator findEntry(Key const& _key)
140
0
  {
141
0
    return std::find_if(m_entries.begin(), m_entries.end(), [&](auto const& _entry) { return _entry.first == _key; });
142
0
  }
143
  typename Entries::const_iterator findEntry(Key const& _key) const
144
0
  {
145
0
    return std::find_if(m_entries.begin(), m_entries.end(), [&](auto const& _entry) { return _entry.first == _key; });
Unexecuted instantiation: auto solidity::yul::ssa::util::UseCountSet<solidity::yul::ssa::InstId>::findEntry(solidity::yul::ssa::InstId const&) const::{lambda(auto:1 const&)#1}::operator()<std::__1::pair<solidity::yul::ssa::InstId, unsigned int> >(std::__1::pair<solidity::yul::ssa::InstId, unsigned int> const&) const
Unexecuted instantiation: auto solidity::yul::ssa::util::UseCountSet<solidity::yul::ssa::StackSlot>::findEntry(solidity::yul::ssa::StackSlot const&) const::{lambda(auto:1 const&)#1}::operator()<std::__1::pair<solidity::yul::ssa::StackSlot, unsigned int> >(std::__1::pair<solidity::yul::ssa::StackSlot, unsigned int> const&) const
146
0
  }
Unexecuted instantiation: solidity::yul::ssa::util::UseCountSet<solidity::yul::ssa::InstId>::findEntry(solidity::yul::ssa::InstId const&) const
Unexecuted instantiation: solidity::yul::ssa::util::UseCountSet<solidity::yul::ssa::StackSlot>::findEntry(solidity::yul::ssa::StackSlot const&) const
147
148
  Entries m_entries;
149
};
150
151
}