refactor(util/name_generator): make sure there is no risk of overflow, name generators will be extensively used in version 0.2

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-02-20 11:20:31 -08:00
parent 501435f6fc
commit 50300126a5
6 changed files with 68 additions and 8 deletions

View file

@ -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"}, name{"fo", "bla", "foo"}));
lean_assert(!is_prefix_of(name{"foo", "bla", "foo"}, name{"foo", "bla"})); 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{"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() { static void tst5() {
@ -157,6 +162,15 @@ static void tst12() {
lean_assert(mk_unique(s, name("foo")) == name(name("foo"), 2)); 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() { int main() {
tst1(); tst1();
tst2(); tst2();
@ -170,5 +184,6 @@ int main() {
tst10(); tst10();
tst11(); tst11();
tst12(); tst12();
tst13();
return has_violations() ? 1 : 0; return has_violations() ? 1 : 0;
} }

View file

@ -4,7 +4,7 @@ else()
set(THREAD_CPP "") set(THREAD_CPP "")
endif() 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 exception.cpp interrupt.cpp hash.cpp escaped.cpp bit_tricks.cpp
safe_arith.cpp ascii.cpp memory.cpp shared_mutex.cpp realpath.cpp safe_arith.cpp ascii.cpp memory.cpp shared_mutex.cpp realpath.cpp
script_state.cpp script_exception.cpp splay_map.cpp lua.cpp script_state.cpp script_exception.cpp splay_map.cpp lua.cpp

View file

@ -212,6 +212,8 @@ bool operator==(name const & a, name const & b) {
} }
bool is_prefix_of(name const & n1, name const & n2) { bool is_prefix_of(name const & n1, name const & n2) {
if (n2.is_atomic())
return n1 == n2;
buffer<name::imp*> limbs1, limbs2; buffer<name::imp*> limbs1, limbs2;
name::imp* i1 = n1.m_ptr; name::imp* i1 = n1.m_ptr;
name::imp* i2 = n2.m_ptr; name::imp* i2 = n2.m_ptr;

View file

@ -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_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); } }; 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); serializer & operator<<(serializer & s, name const & n);
name read_name(deserializer & d); name read_name(deserializer & d);
inline deserializer & operator>>(deserializer & d, name & n) { n = read_name(d); return d; } inline deserializer & operator>>(deserializer & d, name & n) { n = read_name(d); return d; }

View file

@ -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 <limits>
#include "util/name_generator.h"
namespace lean {
name name_generator::next() {
if (m_next_idx == std::numeric_limits<unsigned>::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);
}
}

View file

@ -11,8 +11,10 @@ Author: Leonardo de Moura
namespace lean { namespace lean {
/** /**
\brief A generator of unique names modulo a prefix. \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 If the initial prefix is independent of all other names in the system, then all generated names are unique.
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<unsigned>::max(),
then the prefix becomes name(m_prefix, m_next_idx), and m_next_idx is reset to 0
*/ */
class name_generator { class name_generator {
name m_prefix; name m_prefix;
@ -23,11 +25,15 @@ public:
name const & prefix() const { return m_prefix; } name const & prefix() const { return m_prefix; }
/** \brief Return a unique name modulo \c 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); \brief Create a child name_generator, each child name_generator is guaranteed to produce
std::swap(a.m_next_idx, b.m_next_idx); 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);
} }