Line data Source code
1 : /*! 2 : * \file esys/repo/sharing/inventory_sharing.cpp 3 : * \brief In-memory dependency inventory (ADR-0042) 4 : * 5 : * \cond 6 : * __legal_b__ 7 : * 8 : * Copyright (c) 2026 Michel Gillet 9 : * Distributed under the MIT License. 10 : * (See accompanying file LICENSE.txt or 11 : * copy at https://opensource.org/licenses/MIT) 12 : * 13 : * __legal_e__ 14 : * \endcond 15 : * 16 : */ 17 : 18 : #include "esys/repo/esysrepo_prec.h" 19 : #include "esys/repo/sharing/inventory.h" 20 : 21 : namespace esys::repo::sharing 22 : { 23 : 24 27 : void Inventory::clear() 25 : { 26 27 : m_occurrences.clear(); 27 27 : m_coverage = Coverage::Unknown; 28 27 : m_inspected_scopes.clear(); 29 27 : m_seen_keys_this_pass.clear(); 30 27 : } 31 : 32 5 : void Inventory::upsert(const Occurrence &occurrence) 33 : { 34 5 : const std::string key = occurrence.scope_key(); 35 5 : m_seen_keys_this_pass.insert(key); 36 8 : for (auto &existing : m_occurrences) 37 : { 38 4 : if (existing.scope_key() == key) 39 : { 40 1 : existing = occurrence; 41 1 : return; 42 : } 43 : } 44 4 : m_occurrences.push_back(occurrence); 45 5 : } 46 : 47 2 : const std::vector<Occurrence> &Inventory::get_occurrences() const 48 : { 49 2 : return m_occurrences; 50 : } 51 : 52 1 : void Inventory::set_coverage(Coverage coverage) 53 : { 54 1 : m_coverage = coverage; 55 1 : } 56 : 57 1 : Coverage Inventory::get_coverage() const 58 : { 59 1 : return m_coverage; 60 : } 61 : 62 1 : void Inventory::mark_scope_inspected(const std::string &consumer_path) 63 : { 64 1 : m_inspected_scopes.insert(consumer_path); 65 : // New inspection pass for this scope: clear seen keys that belong to it 66 1 : for (auto it = m_seen_keys_this_pass.begin(); it != m_seen_keys_this_pass.end();) 67 : { 68 0 : if (it->size() >= consumer_path.size() && it->compare(0, consumer_path.size(), consumer_path) == 0 && 69 0 : (it->size() == consumer_path.size() || (*it)[consumer_path.size()] == '\x1f')) 70 0 : it = m_seen_keys_this_pass.erase(it); 71 : else 72 1 : ++it; 73 : } 74 1 : } 75 : 76 1 : void Inventory::drop_stale_in_scope(const std::string &consumer_path) 77 : { 78 1 : if (m_inspected_scopes.find(consumer_path) == m_inspected_scopes.end()) return; 79 : 80 1 : std::vector<Occurrence> kept; 81 1 : kept.reserve(m_occurrences.size()); 82 2 : for (const auto &occ : m_occurrences) 83 : { 84 1 : if (occ.get_consumer_path() != consumer_path) 85 : { 86 0 : kept.push_back(occ); 87 0 : continue; 88 : } 89 3 : if (m_seen_keys_this_pass.count(occ.scope_key()) != 0) kept.push_back(occ); 90 : } 91 1 : m_occurrences.swap(kept); 92 1 : } 93 : 94 3 : std::map<std::string, std::vector<Occurrence>> Inventory::group_by_identity() const 95 : { 96 3 : std::map<std::string, std::vector<Occurrence>> groups; 97 10 : for (const auto &occ : m_occurrences) 98 : { 99 7 : if (occ.get_normalized_identity().empty()) continue; 100 5 : groups[occ.get_normalized_identity()].push_back(occ); 101 : } 102 3 : return groups; 103 0 : } 104 : 105 : std::map<std::string, std::vector<Occurrence>> 106 3 : Inventory::unregistered_duplicates(const std::set<std::string> ®istered_identities) const 107 : { 108 3 : std::map<std::string, std::vector<Occurrence>> result; 109 6 : for (const auto &pair : group_by_identity()) 110 : { 111 3 : if (pair.second.size() < 2) continue; 112 2 : if (registered_identities.count(pair.first) != 0) continue; 113 1 : result[pair.first] = pair.second; 114 0 : } 115 3 : return result; 116 0 : } 117 : 118 : } // namespace esys::repo::sharing