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:
parent
501435f6fc
commit
50300126a5
6 changed files with 68 additions and 8 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<name::imp*> limbs1, limbs2;
|
||||
name::imp* i1 = n1.m_ptr;
|
||||
name::imp* i2 = n2.m_ptr;
|
||||
|
|
|
@ -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; }
|
||||
|
|
26
src/util/name_generator.cpp
Normal file
26
src/util/name_generator.cpp
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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<unsigned>::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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue