/* Copyright (c) 2016 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Gabriel Ebner */ #include #include #include "util/subscripted_name_set.h" namespace lean { void subscripted_name_set::check_invariants() const { m_names.for_each([&] (name const & n) { if (auto is_subscripted = n.is_subscripted()) { auto subscripts = m_prefixes.find(is_subscripted->first); lean_assert(subscripts); DEBUG_CODE(auto free_region =) subscripts->find_next_greater_or_equal(closed_ival(is_subscripted->second)); lean_assert(free_region); lean_assert(!free_region->contains(is_subscripted->second)); } }); m_prefixes.for_each([&] (name const &, free_subscript_set const & subscripts) { unsigned last_end = 0; subscripts.for_each([&] (closed_ival const & region) { lean_assert(last_end < region.begin); lean_assert(region.begin <= region.end); last_end = region.end; }); lean_assert(last_end == std::numeric_limits::max()); }); } void subscripted_name_set::insert(name const & n) { if (contains(n)) return; m_names.insert(n); if (auto is_subscripted = n.is_subscripted()) { free_subscript_set subscripts; if (auto entry = m_prefixes.find(is_subscripted->first)) { subscripts = *entry; } else { subscripts.insert(closed_ival()); } unsigned idx = is_subscripted->second; closed_ival free_region = *subscripts.find_next_greater_or_equal(closed_ival(idx)); if (free_region.contains(idx)) { subscripts.erase(free_region); if (free_region.begin < idx) subscripts.insert(closed_ival(free_region.begin, idx - 1)); if (idx < free_region.end) subscripts.insert(closed_ival(idx + 1, free_region.end)); } m_prefixes.insert(is_subscripted->first, subscripts); } DEBUG_CODE(check_invariants()); } void subscripted_name_set::erase(name const & n) { if (!contains(n)) return; m_names.erase(n); if (auto is_subscripted = n.is_subscripted()) { unsigned idx = is_subscripted->second; free_subscript_set subscripts = *m_prefixes.find(is_subscripted->first); auto prev_free_region = *subscripts.find_next_greater_or_equal(closed_ival(idx - 1)); auto next_free_region = *subscripts.find_next_greater_or_equal(closed_ival(idx)); if (prev_free_region.end == next_free_region.end) { if (next_free_region.begin == idx + 1) { subscripts.insert(closed_ival(idx, next_free_region.end)); // replaces next_free_region } else { lean_assert(next_free_region.begin > idx + 1); subscripts.insert(closed_ival(idx)); } } else { lean_assert(prev_free_region.end == idx - 1); if (next_free_region.begin == idx + 1) { subscripts.erase(prev_free_region); subscripts.insert(closed_ival(prev_free_region.begin, next_free_region.end)); // replaces next_free_region } else { lean_assert(next_free_region.begin > idx + 1); subscripts.erase(prev_free_region); subscripts.insert(closed_ival(prev_free_region.begin, idx)); } } m_prefixes.insert(is_subscripted->first, subscripts); } DEBUG_CODE(check_invariants()); } name subscripted_name_set::get_unused_name(name const & prefix, unsigned idx) const { if (auto free_subscripts = m_prefixes.find(prefix.get_subscript_base())) { auto free_region = free_subscripts->find_next_greater_or_equal(closed_ival(idx)); if (free_region->begin >= idx) idx = free_region->begin; } name n = prefix.append_after(idx); if (contains(n)) { lean_unreachable(); } return n; } name subscripted_name_set::get_unused_name(name const & suggestion) const { if (!contains(suggestion)) return suggestion; return get_unused_name(suggestion, 1); } }