diff --git a/src/tests/util/name.cpp b/src/tests/util/name.cpp index 8becec283..e9c75f465 100644 --- a/src/tests/util/name.cpp +++ b/src/tests/util/name.cpp @@ -70,6 +70,11 @@ static void tst4() { lean_assert(!is_prefix_of(name{"foo"}, name{"fo", "bla", "foo"})); lean_assert(!is_prefix_of(name{"foo", "bla", "foo"}, name{"foo", "bla"})); lean_assert(is_prefix_of(name{"foo", "bla"}, name(name{"foo", "bla"}, 0u))); + lean_assert(is_prefix_of(name("aaa"), name("aaa"))); + lean_assert(!is_prefix_of(name("aaa"), name("aaab"))); + lean_assert(!is_prefix_of(name("aaab"), name("aaa"))); + lean_assert(!is_prefix_of(name{"foo", "bla"}, name{"foo"})); + lean_assert(is_prefix_of(name{"foo"}, name{"foo", "bla"})); } static void tst5() { @@ -157,6 +162,15 @@ static void tst12() { lean_assert(mk_unique(s, name("foo")) == name(name("foo"), 2)); } +static void tst13() { + name_generator g1("a"); + name_generator c1 = g1.mk_child(); + name_generator c2 = g1.mk_child(); + lean_assert(c1.next() != c2.next()); + std::cout << c1.next() << "\n"; + std::cout << c2.next() << "\n"; +} + int main() { tst1(); tst2(); @@ -170,5 +184,6 @@ int main() { tst10(); tst11(); tst12(); + tst13(); return has_violations() ? 1 : 0; } diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 02b4f32c3..b941c05e5 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -4,7 +4,7 @@ else() set(THREAD_CPP "") endif() -add_library(util trace.cpp debug.cpp name.cpp name_set.cpp +add_library(util trace.cpp debug.cpp name.cpp name_set.cpp name_generator.cpp exception.cpp interrupt.cpp hash.cpp escaped.cpp bit_tricks.cpp safe_arith.cpp ascii.cpp memory.cpp shared_mutex.cpp realpath.cpp script_state.cpp script_exception.cpp splay_map.cpp lua.cpp diff --git a/src/util/name.cpp b/src/util/name.cpp index 8f6c2b749..723743ae0 100644 --- a/src/util/name.cpp +++ b/src/util/name.cpp @@ -212,6 +212,8 @@ bool operator==(name const & a, name const & b) { } bool is_prefix_of(name const & n1, name const & n2) { + if (n2.is_atomic()) + return n1 == n2; buffer limbs1, limbs2; name::imp* i1 = n1.m_ptr; name::imp* i2 = n2.m_ptr; diff --git a/src/util/name.h b/src/util/name.h index 577ee2610..5e45674f8 100644 --- a/src/util/name.h +++ b/src/util/name.h @@ -129,6 +129,17 @@ struct name_eq { bool operator()(name const & n1, name const & n2) const { retur struct name_cmp { int operator()(name const & n1, name const & n2) const { return cmp(n1, n2); } }; struct name_quick_cmp { int operator()(name const & n1, name const & n2) const { return quick_cmp(n1, n2); } }; +/** + \brief Return true iff the two given names are independent. + That \c a is not a prefix of \c b, nor \c b is a prefix of \c a + + \remark forall a b c d, + independent(a, b) => independent(join(a, c), join(b, d)) +*/ +inline bool independent(name const & a, name const & b) { + return !is_prefix_of(a, b) && !is_prefix_of(b, a); +} + serializer & operator<<(serializer & s, name const & n); name read_name(deserializer & d); inline deserializer & operator>>(deserializer & d, name & n) { n = read_name(d); return d; } diff --git a/src/util/name_generator.cpp b/src/util/name_generator.cpp new file mode 100644 index 000000000..e8e9b58ba --- /dev/null +++ b/src/util/name_generator.cpp @@ -0,0 +1,26 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Leonardo de Moura +*/ +#include +#include "util/name_generator.h" + +namespace lean { +name name_generator::next() { + if (m_next_idx == std::numeric_limits::max()) { + // avoid overflow + m_prefix = name(m_prefix, m_next_idx); + m_next_idx = 0; + } + name r(m_prefix, m_next_idx); + m_next_idx++; + return r; +} + +void swap(name_generator & a, name_generator & b) { + swap(a.m_prefix, b.m_prefix); + std::swap(a.m_next_idx, b.m_next_idx); +} +} diff --git a/src/util/name_generator.h b/src/util/name_generator.h index b10813abf..ead534044 100644 --- a/src/util/name_generator.h +++ b/src/util/name_generator.h @@ -11,8 +11,10 @@ Author: Leonardo de Moura namespace lean { /** \brief A generator of unique names modulo a prefix. - If the prefix is unique (i.e., it is not the prefix of any other name in the system), then - all generated names are unique. + If the initial prefix is independent of all other names in the system, then all generated names are unique. + + \remark There is no risk of overflow in the m_next_idx. If m_next_idx reaches std::numeric_limits::max(), + then the prefix becomes name(m_prefix, m_next_idx), and m_next_idx is reset to 0 */ class name_generator { name m_prefix; @@ -23,11 +25,15 @@ public: name const & prefix() const { return m_prefix; } /** \brief Return a unique name modulo \c prefix. */ - name next() { name r(m_prefix, m_next_idx); m_next_idx++; return r; } + name next(); - friend void swap(name_generator & a, name_generator & b) { - swap(a.m_prefix, b.m_prefix); - std::swap(a.m_next_idx, b.m_next_idx); - } + /** + \brief Create a child name_generator, each child name_generator is guaranteed to produce + names different from this name_generator and any other name_generator created with this generator. + */ + name_generator mk_child() { return name_generator(next()); } + + friend void swap(name_generator & a, name_generator & b); }; +void swap(name_generator & a, name_generator & b); }