2013-07-16 01:43:32 +00:00
|
|
|
/*
|
2013-07-19 17:29:33 +00:00
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
2013-07-16 01:43:32 +00:00
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
2013-07-19 17:29:33 +00:00
|
|
|
Author: Leonardo de Moura
|
2013-07-16 01:43:32 +00:00
|
|
|
*/
|
|
|
|
#include <cstring>
|
2013-07-21 22:56:18 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
2013-07-16 01:43:32 +00:00
|
|
|
#include "name.h"
|
|
|
|
#include "debug.h"
|
2013-07-16 17:11:14 +00:00
|
|
|
#include "rc.h"
|
2013-07-20 21:15:54 +00:00
|
|
|
#include "hash.h"
|
2013-07-21 22:56:18 +00:00
|
|
|
#include "trace.h"
|
2013-07-16 01:43:32 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
|
|
|
|
constexpr char const * anonymous_str = "[anonymous]";
|
|
|
|
|
|
|
|
struct name::imp {
|
2013-07-16 17:11:14 +00:00
|
|
|
MK_LEAN_RC()
|
2013-07-16 01:43:32 +00:00
|
|
|
bool m_is_string;
|
|
|
|
imp * m_prefix;
|
|
|
|
union {
|
|
|
|
char * m_str;
|
|
|
|
unsigned m_k;
|
|
|
|
};
|
2013-07-19 17:29:33 +00:00
|
|
|
|
2013-07-16 17:11:14 +00:00
|
|
|
void dealloc() {
|
2013-07-16 01:43:32 +00:00
|
|
|
imp * curr = this;
|
2013-07-16 17:11:14 +00:00
|
|
|
while (true) {
|
|
|
|
lean_assert(curr->get_rc() == 0);
|
|
|
|
imp * p = curr->m_prefix;
|
|
|
|
if (curr->m_is_string)
|
|
|
|
delete[] reinterpret_cast<char*>(curr);
|
|
|
|
else
|
|
|
|
delete curr;
|
|
|
|
curr = p;
|
|
|
|
if (!curr || !curr->dec_ref_core())
|
|
|
|
break;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-16 17:11:14 +00:00
|
|
|
imp(bool s, imp * p):m_rc(1), m_is_string(s), m_prefix(p) { if (p) p->inc_ref(); }
|
2013-07-16 01:43:32 +00:00
|
|
|
|
|
|
|
static void display_core(std::ostream & out, char const * sep, imp * p) {
|
|
|
|
lean_assert(p != nullptr);
|
|
|
|
if (p->m_prefix) {
|
|
|
|
display_core(out, sep, p->m_prefix);
|
|
|
|
out << sep;
|
|
|
|
}
|
2013-07-19 17:29:33 +00:00
|
|
|
if (p->m_is_string)
|
2013-07-16 01:43:32 +00:00
|
|
|
out << p->m_str;
|
|
|
|
else
|
|
|
|
out << p->m_k;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void display(std::ostream & out, char const * sep, imp * p) {
|
|
|
|
if (p == nullptr)
|
|
|
|
out << anonymous_str;
|
|
|
|
else
|
|
|
|
display_core(out, sep, p);
|
|
|
|
}
|
2013-07-21 22:56:18 +00:00
|
|
|
|
|
|
|
friend void copy_limbs(imp * p, std::vector<name::imp *> & limbs) {
|
|
|
|
limbs.clear();
|
|
|
|
while (p != nullptr) {
|
|
|
|
limbs.push_back(p);
|
|
|
|
p = p->m_prefix;
|
|
|
|
}
|
|
|
|
std::reverse(limbs.begin(), limbs.end());
|
|
|
|
}
|
2013-07-16 01:43:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
name::name(imp * p) {
|
|
|
|
m_imp = p;
|
|
|
|
if (m_imp)
|
|
|
|
m_imp->inc_ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
name::name() {
|
|
|
|
m_imp = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
name::name(name const & prefix, char const * name) {
|
|
|
|
size_t sz = strlen(name);
|
|
|
|
lean_assert(sz < 1u<<31);
|
|
|
|
char * mem = new char[sizeof(imp) + sz + 1];
|
|
|
|
m_imp = new (mem) imp(true, prefix.m_imp);
|
|
|
|
memcpy(mem + sizeof(imp), name, sz + 1);
|
|
|
|
m_imp->m_str = mem + sizeof(imp);
|
|
|
|
}
|
|
|
|
|
|
|
|
name::name(name const & prefix, unsigned k) {
|
|
|
|
m_imp = new imp(false, prefix.m_imp);
|
|
|
|
m_imp->m_k = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
name::name(char const * n):name(name(), n) {
|
|
|
|
}
|
|
|
|
|
|
|
|
name::name(unsigned k):name(name(), k) {
|
|
|
|
}
|
|
|
|
|
|
|
|
name::name(name const & other):m_imp(other.m_imp) {
|
|
|
|
m_imp->inc_ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
name::name(name && other):m_imp(other.m_imp) {
|
|
|
|
other.m_imp = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
name::~name() {
|
|
|
|
if (m_imp)
|
|
|
|
m_imp->dec_ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
name & name::operator=(name const & other) {
|
2013-07-19 17:29:33 +00:00
|
|
|
if (other.m_imp)
|
2013-07-16 01:43:32 +00:00
|
|
|
other.m_imp->inc_ref();
|
|
|
|
if (m_imp)
|
|
|
|
m_imp->dec_ref();
|
|
|
|
m_imp = other.m_imp;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
name & name::operator=(name && other) {
|
|
|
|
lean_assert(this != &other);
|
|
|
|
if (m_imp)
|
|
|
|
m_imp->dec_ref();
|
|
|
|
m_imp = other.m_imp;
|
|
|
|
other.m_imp = 0;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2013-07-22 11:14:01 +00:00
|
|
|
name_kind name::kind() const {
|
2013-07-19 17:29:33 +00:00
|
|
|
if (m_imp == nullptr)
|
2013-07-22 11:14:01 +00:00
|
|
|
return name_kind::ANONYMOUS;
|
2013-07-19 17:29:33 +00:00
|
|
|
else
|
2013-07-22 11:14:01 +00:00
|
|
|
return m_imp->m_is_string ? name_kind::STRING : name_kind::NUMERAL;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned name::get_numeral() const {
|
|
|
|
lean_assert(is_numeral());
|
|
|
|
return m_imp->m_k;
|
|
|
|
}
|
|
|
|
|
|
|
|
char const * name::get_string() const {
|
|
|
|
lean_assert(is_string());
|
|
|
|
return m_imp->m_str;
|
|
|
|
}
|
|
|
|
|
2013-07-21 22:08:14 +00:00
|
|
|
bool operator==(name const & a, name const & b) {
|
|
|
|
name::imp * i1 = a.m_imp;
|
|
|
|
name::imp * i2 = b.m_imp;
|
2013-07-16 01:43:32 +00:00
|
|
|
while (true) {
|
|
|
|
if (i1 == i2)
|
|
|
|
return true;
|
|
|
|
if ((i1 == nullptr) != (i2 == nullptr))
|
|
|
|
return false;
|
|
|
|
lean_assert(i1 != nullptr);
|
|
|
|
lean_assert(i2 != nullptr);
|
|
|
|
if (i1->m_is_string != i2->m_is_string)
|
|
|
|
return false;
|
2013-07-21 22:08:14 +00:00
|
|
|
if (i1->m_is_string) {
|
|
|
|
if (strcmp(i1->m_str, i2->m_str) != 0)
|
2013-07-16 01:43:32 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
2013-07-21 22:08:14 +00:00
|
|
|
if (i1->m_k != i2->m_k)
|
2013-07-16 01:43:32 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
i1 = i1->m_prefix;
|
|
|
|
i2 = i2->m_prefix;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-21 22:56:18 +00:00
|
|
|
int cmp(name::imp * i1, name::imp * i2) {
|
|
|
|
static thread_local std::vector<name::imp *> limbs1;
|
|
|
|
static thread_local std::vector<name::imp *> limbs2;
|
|
|
|
copy_limbs(i1, limbs1);
|
|
|
|
copy_limbs(i2, limbs2);
|
|
|
|
auto it1 = limbs1.begin();
|
|
|
|
auto it2 = limbs2.begin();
|
|
|
|
for (; it1 != limbs1.end() && it2 != limbs2.end(); ++it1, ++it2) {
|
|
|
|
i1 = *it1;
|
|
|
|
i2 = *it2;
|
|
|
|
|
|
|
|
if (i1->m_is_string != i2->m_is_string)
|
|
|
|
return i1->m_is_string ? 1 : -1;
|
|
|
|
|
|
|
|
if (i1->m_is_string) {
|
|
|
|
int c = strcmp(i1->m_str, i2->m_str);
|
|
|
|
if (c != 0)
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
else if (i1->m_k != i2->m_k) {
|
|
|
|
return i1->m_k < i2->m_k ? -1 : 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (it1 == limbs1.end() && it2 == limbs2.end())
|
|
|
|
return 0;
|
|
|
|
else return it1 == limbs1.end() ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
2013-07-16 01:43:32 +00:00
|
|
|
bool name::is_atomic() const {
|
|
|
|
return m_imp == nullptr || m_imp->m_prefix == nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
name name::get_prefix() const {
|
|
|
|
lean_assert(!is_atomic());
|
|
|
|
return name(m_imp->m_prefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned num_digits(unsigned k) {
|
|
|
|
if (k == 0)
|
|
|
|
return 1;
|
2013-07-19 17:29:33 +00:00
|
|
|
int r = 0;
|
|
|
|
while (k != 0) {
|
|
|
|
k /= 10;
|
|
|
|
r++;
|
2013-07-16 01:43:32 +00:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t name::size(char const * sep) const {
|
|
|
|
if (m_imp == nullptr) {
|
|
|
|
return strlen(anonymous_str);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
imp * i = m_imp;
|
|
|
|
size_t sep_sz = strlen(sep);
|
|
|
|
size_t r = 0;
|
|
|
|
while (true) {
|
|
|
|
if (i->m_is_string) {
|
|
|
|
r += strlen(i->m_str);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
r += num_digits(i->m_k);
|
|
|
|
}
|
|
|
|
if (i->m_prefix) {
|
|
|
|
r += sep_sz;
|
|
|
|
i = i->m_prefix;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-20 21:15:54 +00:00
|
|
|
unsigned name::hash() const {
|
|
|
|
if (m_imp == nullptr)
|
|
|
|
return 17;
|
|
|
|
else {
|
|
|
|
unsigned h = 13;
|
|
|
|
imp const * i = m_imp;
|
|
|
|
do {
|
|
|
|
if (i->m_is_string)
|
|
|
|
h = ::lean::hash(i->m_str, strlen(i->m_str), h);
|
|
|
|
else
|
|
|
|
h = ::lean::hash(h, i->m_k);
|
|
|
|
i = i->m_prefix;
|
|
|
|
}
|
|
|
|
while (i != nullptr);
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-16 01:43:32 +00:00
|
|
|
std::ostream & operator<<(std::ostream & out, name const & n) {
|
|
|
|
name::imp::display(out, default_name_separator, n.m_imp);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
name::sep::sep(name const & n, char const * s):m_name(n), m_sep(s) {}
|
|
|
|
|
|
|
|
std::ostream & operator<<(std::ostream & out, name::sep const & s) {
|
|
|
|
name::imp::display(out, s.m_sep, s.m_name.m_imp);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|