lean4-htt/src/library/attribute_manager.h
Leonardo de Moura 127ecff79c fix(attribute_manager): finalization problem
Global variables must be simple types. Reason: the finalization of
global objects in different compilation units is not specified by the
standard. The only exception is the global at src/shared/init.cpp.
It is used to automatically initialize the lean shared library.

Before this commit, attribute_manager used a std::unique_ptr in a global
variable. The test shared_test was crashing in one of my machines
because a different finalization order was being used.
2016-12-20 10:02:31 -08:00

300 lines
11 KiB
C++

/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <string>
#include "util/sstream.h"
#include "util/priority_queue.h"
#include "kernel/environment.h"
#include "library/abstract_parser.h"
#include "library/io_state.h"
#ifndef LEAN_DEFAULT_PRIORITY
#define LEAN_DEFAULT_PRIORITY 1000u
#endif
namespace lean {
struct attr_data {
virtual unsigned hash() const {
return 0;
}
virtual void parse(abstract_parser &) {}
virtual void print(std::ostream &) {}
virtual ~attr_data() {}
};
typedef std::shared_ptr<attr_data> attr_data_ptr;
struct attr_config;
/* Return an instance of the basic attr_data */
attr_data_ptr get_default_attr_data();
typedef std::function<environment(environment const &, io_state const &, name const &, unsigned, bool)> after_set_proc;
typedef std::function<void(environment const &, name const &, bool)> after_set_check_proc;
typedef std::function<environment(environment const &, name const &, bool)> before_unset_proc;
class attribute {
friend struct attr_config;
friend class decl_attributes;
private:
name m_id;
std::string m_descr;
after_set_proc m_after_set;
before_unset_proc m_before_unset;
protected:
environment set_core(environment const &, io_state const &, name const &, unsigned, attr_data_ptr, bool) const;
virtual environment set_untyped(environment const &, io_state const &, name const &, unsigned, attr_data_ptr, bool) const = 0;
virtual void write_entry(serializer &, attr_data const &) const = 0;
virtual attr_data_ptr read_entry(deserializer &) const = 0;
public:
attribute(name const & id, char const * descr, after_set_proc after_set = {}, before_unset_proc before_unset = {}) :
m_id(id), m_descr(descr), m_after_set(after_set), m_before_unset(before_unset) {}
virtual ~attribute() {}
name const & get_name() const { return m_id; }
std::string const & get_description() const { return m_descr; }
virtual attr_data_ptr get_untyped(environment const &, name const &) const;
bool is_instance(environment const & env, name const & n) const {
return static_cast<bool>(get_untyped(env, n));
}
unsigned get_prio(environment const &, name const &) const;
virtual void get_instances(environment const &, buffer<name> &) const;
priority_queue<name, name_quick_cmp> get_instances_by_prio(environment const &) const;
virtual attr_data_ptr parse_data(abstract_parser &) const;
virtual environment unset(environment env, io_state const & ios, name const & n, bool persistent) const;
virtual unsigned get_fingerprint(environment const & env) const;
};
typedef std::shared_ptr<attribute const> attribute_ptr;
/** \brief An attribute without associated data */
class basic_attribute : public attribute {
protected:
virtual void write_entry(serializer &, attr_data const &) const override final {}
virtual attr_data_ptr read_entry(deserializer &) const override final { return get_default_attr_data(); }
virtual environment set_untyped(environment const & env, io_state const & ios, name const & n, unsigned prio, attr_data_ptr,
bool persistent) const override final {
return set(env, ios, n, prio, persistent);
}
public:
basic_attribute(name const & id, char const * descr, after_set_proc after_set = {}, before_unset_proc before_unset = {}) :
attribute(id, descr, after_set, before_unset) {}
static basic_attribute with_check(name const & id, char const * descr, after_set_check_proc after_set) {
return basic_attribute(
id, descr,
[=](environment const & env, io_state const &, name const & n, unsigned, bool persistent) {
after_set(env, n, persistent);
return env;
},
[](environment const & env, name const &, bool) {
return env;
});
}
virtual environment set(environment const & env, io_state const & ios,
name const & n, unsigned prio, bool persistent) const {
return set_core(env, ios, n, prio, get_default_attr_data(), persistent);
}
};
template<typename Data>
class typed_attribute : public attribute {
protected:
virtual environment set_untyped(environment const & env, io_state const & ios, name const & n, unsigned prio,
attr_data_ptr data, bool persistent) const final override {
lean_assert(dynamic_cast<Data const *>(&*data));
return set(env, ios, n, prio, static_cast<Data const &>(*data), persistent);
}
virtual void write_entry(serializer & s, attr_data const & data) const final override {
lean_assert(dynamic_cast<Data const *>(&data));
static_cast<Data const &>(data).write(s);
}
virtual attr_data_ptr read_entry(deserializer & d) const final override {
auto data = new Data;
data->read(d);
return attr_data_ptr(data);
}
public:
typed_attribute(name const & id, char const * descr, after_set_proc after_set = {}, before_unset_proc before_unset = {}) :
attribute(id, descr, after_set, before_unset) {}
virtual attr_data_ptr parse_data(abstract_parser & p) const final override {
auto data = new Data;
data->parse(p);
return attr_data_ptr(data);
}
virtual environment set(environment const & env, io_state const & ios, name const & n, unsigned prio,
Data const & data, bool persistent) const {
return set_core(env, ios, n, prio, std::unique_ptr<attr_data>(new Data(data)), persistent);
}
std::shared_ptr<Data> get(environment const & env, name const & n) const {
auto data = get_untyped(env, n);
if (!data)
return {};
lean_assert(std::dynamic_pointer_cast<Data>(data));
return std::static_pointer_cast<Data>(data);
}
};
template<typename Data>
class proxy_attribute : public basic_attribute {
private:
Data m_status;
public:
proxy_attribute(char const * id, char const * descr, Data const & status):
basic_attribute(id, descr), m_status(status) {}
virtual typed_attribute<Data> const & get_attribute() const = 0;
virtual attr_data_ptr get_untyped(environment const & env, name const & n) const override {
if (auto data = get_attribute().get(env, n)) {
if (data->m_status == m_status)
return get_default_attr_data();
}
return attr_data_ptr();
}
virtual environment set(environment const & env, io_state const & ios, name const & n,
unsigned prio, bool persistent) const override {
return get_attribute().set(env, ios, n, prio, m_status, persistent);
}
virtual environment unset(environment, io_state const &, name const &, bool) const override {
throw exception(sstream() << "cannot remove attribute [" << get_name() << "]");
}
virtual void get_instances(environment const & env, buffer<name> & r) const override {
buffer<name> tmp;
get_attribute().get_instances(env, tmp);
for (name const & n : tmp)
if (is_instance(env, n))
r.push_back(n);
}
virtual unsigned get_fingerprint(environment const & env) const override {
return get_attribute().get_fingerprint(env);
}
};
struct indices_attribute_data : public attr_data {
list<unsigned> m_idxs;
indices_attribute_data(list<unsigned> const & idxs) : m_idxs(idxs) {}
indices_attribute_data() : indices_attribute_data(list<unsigned>()) {}
virtual unsigned hash() const override {
unsigned h = 0;
for (unsigned i : m_idxs)
h = ::lean::hash(h, i);
return h;
}
void write(serializer & s) const {
write_list(s, m_idxs);
}
void read(deserializer & d) {
m_idxs = read_list<unsigned>(d);
}
void parse(abstract_parser & p) override;
virtual void print(std::ostream & out) override {
for (auto p : m_idxs) {
out << " " << p + 1;
}
}
};
struct key_value_data : public attr_data {
// generalize: name_map<std::string> m_pairs;
std::string m_symbol;
std::string m_library;
virtual unsigned hash() const override {
// unsigned h = 0;
// // This isn't right ..., well maybe? I don't really know.
// // Rust's Hash trait is super good at this.
// m_pairs.for_each([&] (name const & n, std::string const & value) {
// h += n.hash();
// // h += ::lean::hash_str(value, h);
// });
return 0;
}
void write(serializer & s) const {
s << m_symbol;
s << m_library;
}
void read(deserializer & d) {
std::string m_symbol, m_library;
d >> m_symbol;
d >> m_library;
}
void parse(abstract_parser & p) override {
std::cout << "in extern parser" << std::endl;
std::string n = p.parse_string_lit();
std::string l = p.parse_string_lit();
std::cout << "link symbol: " << n << std::endl;
std::cout << "library symbol: " << l << std::endl;
this->m_symbol = n;
this->m_library = l;
}
virtual void print(std::ostream & out) override {
out << "external";
// for (auto p : m_idxs) {
// out << " " << p + 1;
// }
}
};
template class typed_attribute<indices_attribute_data>;
/** \brief Attribute that represents a list of indices. input and output are 1-indexed for convenience. */
typedef typed_attribute<indices_attribute_data> indices_attribute;
template class typed_attribute<key_value_data>;
/** \brief Attribute that represents a list of indices. input and output are 1-indexed for convenience. */
typedef typed_attribute<key_value_data> key_value_attribute;
class user_attribute_ext {
public:
virtual ~user_attribute_ext() {}
virtual name_map<attribute_ptr> get_attributes(environment const & env);
virtual void write_entry(serializer &, attr_data const &) {}
virtual attr_data_ptr read_entry(deserializer &) {
return get_default_attr_data();
}
};
/** \brief Register the user_attribute handlers, if included in the compilation */
void set_user_attribute_ext(std::unique_ptr<user_attribute_ext>);
void register_system_attribute(attribute_ptr);
template<typename Attribute>
void register_system_attribute(Attribute attr) {
register_system_attribute(attribute_ptr(new Attribute(attr)));
}
void register_incompatible(char const * attr1, char const * attr2);
bool is_system_attribute(name const & attr_name);
bool is_attribute(environment const & env, name const & attr);
attribute const & get_attribute(environment const & env, name const & attr);
attribute const & get_system_attribute(name const & attr);
void get_attributes(environment const & env, buffer<attribute const *> &);
bool has_attribute(environment const & env, name const & attr, name const & d);
bool are_incompatible(attribute const & attr1, attribute const & attr2);
unsigned get_attribute_fingerprint(environment const & env, name const & attr);
void initialize_attribute_manager();
void finalize_attribute_manager();
}