mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 10:25:18 +00:00
879 lines
27 KiB
C++
879 lines
27 KiB
C++
/*++
|
|
Copyright (c) 2006 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dl_util.h
|
|
|
|
Abstract:
|
|
|
|
Datalog utility function and structures.
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2010-05-20.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#ifndef _DL_UTIL_H_
|
|
#define _DL_UTIL_H_
|
|
|
|
#include"ast.h"
|
|
#include"hashtable.h"
|
|
#include"obj_hashtable.h"
|
|
#include"uint_set.h"
|
|
#include"horn_subsume_model_converter.h"
|
|
#include"replace_proof_converter.h"
|
|
#include"substitution.h"
|
|
|
|
namespace datalog {
|
|
|
|
class context;
|
|
class rule;
|
|
class relation_base;
|
|
class relation_manager;
|
|
class table_base;
|
|
class pentagon_relation;
|
|
class relation_fact;
|
|
class relation_signature;
|
|
|
|
enum PDR_CACHE_MODE {
|
|
NO_CACHE,
|
|
HASH_CACHE,
|
|
CONSTRAINT_CACHE,
|
|
LAST_CACHE_MODE
|
|
};
|
|
|
|
enum DL_ENGINE {
|
|
DATALOG_ENGINE,
|
|
PDR_ENGINE,
|
|
QPDR_ENGINE,
|
|
BMC_ENGINE,
|
|
LAST_ENGINE
|
|
};
|
|
|
|
struct std_string_hash_proc {
|
|
unsigned operator()(const std::string & s) const
|
|
{ return string_hash(s.c_str(), static_cast<unsigned>(s.length()), 17); }
|
|
};
|
|
|
|
// typedef int_hashtable<int_hash, default_eq<int> > idx_set;
|
|
typedef uint_set idx_set;
|
|
typedef idx_set var_idx_set;
|
|
typedef u_map<var *> varidx2var_map;
|
|
typedef obj_hashtable<func_decl> func_decl_set; //!< Rule dependencies.
|
|
typedef vector<std::string> string_vector;
|
|
|
|
|
|
/**
|
|
\brief Collect top-level conjunctions and disjunctions.
|
|
*/
|
|
void flatten_and(expr_ref_vector& result);
|
|
|
|
void flatten_and(expr* fml, expr_ref_vector& result);
|
|
|
|
void flatten_or(expr_ref_vector& result);
|
|
|
|
void flatten_or(expr* fml, expr_ref_vector& result);
|
|
|
|
/**
|
|
Transform
|
|
~(a1 | ... | aN)
|
|
into
|
|
~a1 | ... | ~aN
|
|
and
|
|
~(a1 & ... & aN)
|
|
into
|
|
~a1 | ... | ~aN
|
|
|
|
Return true if something was done.
|
|
*/
|
|
bool push_toplevel_junction_negation_inside(expr_ref& e);
|
|
|
|
|
|
bool contains_var(expr * trm, unsigned var_idx);
|
|
|
|
/**
|
|
\brief Collect the variables in \c pred.
|
|
\pre \c pred must be a valid head or tail.
|
|
*/
|
|
void collect_vars(ast_manager & m, expr * pred, var_idx_set & result);
|
|
void collect_tail_vars(ast_manager & m, rule * r, var_idx_set & result);
|
|
|
|
void get_free_vars(rule * r, ptr_vector<sort>& sorts);
|
|
|
|
/**
|
|
\brief Return number of arguments of \c pred that are variables
|
|
*/
|
|
unsigned count_variable_arguments(app * pred);
|
|
|
|
/**
|
|
\brief Store in \c result the set of variables used by \c r when ignoring the tail \c t.
|
|
*/
|
|
void collect_non_local_vars(ast_manager & m, rule const * r, app * t, var_idx_set & result);
|
|
|
|
/**
|
|
\brief Store in \c result the set of variables used by \c r when ignoring the tail elements \c t_1 and \c t_2.
|
|
*/
|
|
void collect_non_local_vars(ast_manager & m, rule const * r, app * t_1, app * t_2, var_idx_set & result);
|
|
|
|
template<typename T>
|
|
void copy_nonvariables(app * src, T& tgt)
|
|
{
|
|
unsigned n = src->get_num_args();
|
|
for (unsigned i = 0; i < n; i++) {
|
|
expr * arg = src->get_arg(i);
|
|
if (!is_var(arg)) {
|
|
tgt[i]=arg;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
\brief Auxiliary function used to create a tail based on \c pred for a new rule.
|
|
The variables in \c pred are re-assigned using \c next_idx and \c varidx2var.
|
|
A variable is considered non-local to the rule if it is in the set \c non_local_vars.
|
|
Non-local variables are coppied to new_rule_args, and their sorts to \c new_rule_domain.
|
|
The new predicate is stored in \c new_pred.
|
|
*/
|
|
void mk_new_rule_tail(ast_manager & m, app * pred,
|
|
var_idx_set const & non_local_vars,
|
|
unsigned & next_idx, varidx2var_map & varidx2var,
|
|
sort_ref_buffer & new_rule_domain, expr_ref_buffer & new_rule_args,
|
|
app_ref & new_pred);
|
|
|
|
/**
|
|
\brief Simpler version of the previous function. Initializes next_idx with 0, and
|
|
an empty varid2var
|
|
*/
|
|
inline void mk_new_rule_tail(ast_manager & m, app * pred,
|
|
var_idx_set const & non_local_vars,
|
|
sort_ref_buffer & new_rule_domain, expr_ref_buffer & new_rule_args,
|
|
app_ref & new_pred) {
|
|
unsigned next_idx = 0;
|
|
varidx2var_map varidx2var;
|
|
mk_new_rule_tail(m, pred, non_local_vars, next_idx, varidx2var, new_rule_domain, new_rule_args, new_pred);
|
|
}
|
|
|
|
/**
|
|
\brief Print a predicate \c f to the stream \c out.
|
|
*/
|
|
void display_predicate(context & ctx, app * f, std::ostream & out);
|
|
|
|
/**
|
|
\brief Like \c display_predicate, just without the final '\n' character.
|
|
*/
|
|
void output_predicate(context & ctx, app * f, std::ostream & out);
|
|
|
|
/**
|
|
\brief Print a fact \c f to the stream \c out in a format conforming to Bddbddb.
|
|
*/
|
|
void display_fact(context & ctx, app * f, std::ostream & out);
|
|
|
|
class scoped_coarse_proof {
|
|
ast_manager& m;
|
|
proof_gen_mode m_mode;
|
|
public:
|
|
scoped_coarse_proof(ast_manager& m): m(m) {
|
|
m_mode = m.proof_mode();
|
|
m.toggle_proof_mode(PGM_COARSE);
|
|
}
|
|
~scoped_coarse_proof() {
|
|
m.toggle_proof_mode(m_mode);
|
|
}
|
|
};
|
|
|
|
class variable_intersection
|
|
{
|
|
bool values_match(const expr * v1, const expr * v2);
|
|
|
|
ast_manager & m_manager;
|
|
|
|
unsigned_vector m_args1;
|
|
unsigned_vector m_args2;
|
|
|
|
unsigned_vector m_const_indexes;
|
|
app_ref_vector m_consts;
|
|
|
|
static unsigned expr_cont_get_size(app * a) { return a->get_num_args(); }
|
|
static expr * expr_cont_get(app * a, unsigned i) { return a->get_arg(i); }
|
|
static unsigned expr_cont_get_size(const ptr_vector<expr> & v) { return v.size(); }
|
|
static expr * expr_cont_get(const ptr_vector<expr> & v, unsigned i) { return v[i]; }
|
|
public:
|
|
variable_intersection(ast_manager & m) : m_manager(m), m_consts(m) {}
|
|
|
|
unsigned size() const {
|
|
return m_args1.size();
|
|
}
|
|
|
|
const unsigned * get_cols1() const {
|
|
return m_args1.c_ptr();
|
|
}
|
|
|
|
const unsigned * get_cols2() const {
|
|
return m_args2.c_ptr();
|
|
}
|
|
|
|
bool empty() const {
|
|
return size()==0;
|
|
}
|
|
|
|
void get(unsigned i, unsigned & index1, unsigned & index2) const {
|
|
index1=m_args1[i];
|
|
index2=m_args2[i];
|
|
}
|
|
|
|
void reset() {
|
|
m_args1.reset();
|
|
m_args2.reset();
|
|
m_const_indexes.reset();
|
|
m_consts.reset();
|
|
}
|
|
|
|
bool args_match(const app * f1, const app * f2);
|
|
bool args_self_match(const app * f);
|
|
|
|
/**
|
|
\brief Fill arguments of \c f1 into corresponding positions in
|
|
\c tgt using its \c operator[].
|
|
*/
|
|
template<typename T>
|
|
void fill_into_second(const app * f1, T & tgt) const {
|
|
unsigned n=size();
|
|
for(unsigned i=0; i<n; i++) {
|
|
unsigned f1_index, tgt_index;
|
|
get(i, f1_index, tgt_index);
|
|
tgt[tgt_index]=f1->get_arg(f1_index);
|
|
}
|
|
}
|
|
|
|
void add_pair(unsigned idx1, unsigned idx2) {
|
|
m_args1.push_back(idx1);
|
|
m_args2.push_back(idx2);
|
|
}
|
|
|
|
/**
|
|
Find pairs of indexes of arguments of \c a1 and \c a2 that correspond to the same
|
|
variable. Here we do not detect the constant arguments in \c a1 and \c a2.
|
|
*/
|
|
template<typename T1, typename T2>
|
|
void populate(const T1 & a1, const T2 & a2)
|
|
{
|
|
//TODO: optimize quadratic complexity
|
|
//TODO: optimize number of checks when variable occurs multiple times
|
|
unsigned a1num = expr_cont_get_size(a1);
|
|
unsigned a2num = expr_cont_get_size(a2);
|
|
for(unsigned i1=0; i1<a1num; i1++) {
|
|
expr * e1=expr_cont_get(a1,i1);
|
|
if(!is_var(e1)) {
|
|
continue;
|
|
}
|
|
var* v1=to_var(e1);
|
|
for(unsigned i2=0; i2<a2num; i2++) {
|
|
expr * e2=expr_cont_get(a2,i2);
|
|
if(!is_var(e2)) {
|
|
continue;
|
|
}
|
|
var* v2=to_var(e2);
|
|
if(v1->get_idx()==v2->get_idx()) {
|
|
add_pair(i1, i2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Find pairs of indexes of arguments of \c a that correspond to the same variable
|
|
and indexes that correspond to a constant.
|
|
*/
|
|
void populate_self(const app * a);
|
|
};
|
|
|
|
template<class T>
|
|
void project_out_vector_columns(T & container, unsigned removed_col_cnt, const unsigned * removed_cols) {
|
|
if(removed_col_cnt==0) {
|
|
return;
|
|
}
|
|
unsigned n = container.size();
|
|
unsigned ofs = 1;
|
|
unsigned r_i = 1;
|
|
for(unsigned i=removed_cols[0]+1; i<n; i++) {
|
|
if(r_i!=removed_col_cnt && removed_cols[r_i]==i) {
|
|
r_i++;
|
|
ofs++;
|
|
continue;
|
|
}
|
|
container[i-ofs] = container[i];
|
|
}
|
|
SASSERT(r_i==removed_col_cnt);
|
|
container.resize(n-removed_col_cnt);
|
|
}
|
|
|
|
template<class T, class M>
|
|
void project_out_vector_columns(ref_vector<T,M> & container, unsigned removed_col_cnt,
|
|
const unsigned * removed_cols) {
|
|
if(removed_col_cnt==0) {
|
|
return;
|
|
}
|
|
unsigned n = container.size();
|
|
unsigned ofs = 1;
|
|
int r_i = 1;
|
|
for(unsigned i=removed_cols[0]+1; i<n; i++) {
|
|
if(r_i!=removed_col_cnt && removed_cols[r_i]==i) {
|
|
r_i++;
|
|
ofs++;
|
|
continue;
|
|
}
|
|
container.set(i-ofs, container.get(i));
|
|
}
|
|
SASSERT(r_i==removed_col_cnt);
|
|
container.resize(n-removed_col_cnt);
|
|
}
|
|
|
|
template<class T>
|
|
void project_out_vector_columns(T & container, const unsigned_vector removed_cols) {
|
|
project_out_vector_columns(container, removed_cols.size(), removed_cols.c_ptr());
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
\brief Take a single cycle permutation and store it in the form of a cycle.
|
|
|
|
The function modifies the \c permutation vector
|
|
*/
|
|
void cycle_from_permutation(unsigned_vector & permutation, unsigned_vector & cycle);
|
|
|
|
|
|
/**
|
|
\brief If \c permutation is an identity, return false. Otherwise remove one cycle from the
|
|
permutation, store it in the form of a cycle in \c cycle and return true.
|
|
|
|
Using this function one can retrieve all cycles in a permutation.
|
|
|
|
\c cycle must be empty before calling the function.
|
|
*/
|
|
bool try_remove_cycle_from_permutation(unsigned_vector & permutation, unsigned_vector & cycle);
|
|
|
|
void collect_sub_permutation(const unsigned_vector & permutation, const unsigned_vector & translation,
|
|
unsigned_vector & res, bool & identity);
|
|
|
|
template<class T>
|
|
void permutate_by_cycle(T & container, unsigned cycle_len, const unsigned * permutation_cycle) {
|
|
if(cycle_len<2) {
|
|
return;
|
|
}
|
|
typename T::data aux = container[permutation_cycle[0]];
|
|
for(unsigned i=1; i<cycle_len; i++) {
|
|
container[permutation_cycle[i-1]]=container[permutation_cycle[i]];
|
|
}
|
|
container[permutation_cycle[cycle_len-1]]=aux;
|
|
}
|
|
|
|
template<class T, class M>
|
|
void permutate_by_cycle(ref_vector<T,M> & container, unsigned cycle_len, const unsigned * permutation_cycle) {
|
|
if(cycle_len<2) {
|
|
return;
|
|
}
|
|
T * aux = container.get(permutation_cycle[0]);
|
|
for(unsigned i=1; i<cycle_len; i++) {
|
|
container.set(permutation_cycle[i-1], container.get(permutation_cycle[i]));
|
|
}
|
|
container.set(permutation_cycle[cycle_len-1], aux);
|
|
}
|
|
|
|
template<class T>
|
|
void permutate_by_cycle(T & container, const unsigned_vector permutation_cycle) {
|
|
permutate_by_cycle(container, permutation_cycle.size(), permutation_cycle.c_ptr());
|
|
}
|
|
|
|
|
|
class counter {
|
|
protected:
|
|
typedef u_map<int> map_impl;
|
|
map_impl m_data;
|
|
const bool m_stay_non_negative;
|
|
public:
|
|
typedef map_impl::iterator iterator;
|
|
|
|
counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
|
|
|
|
iterator begin() const { return m_data.begin(); }
|
|
iterator end() const { return m_data.end(); }
|
|
|
|
void update(unsigned el, int delta);
|
|
int & get(unsigned el);
|
|
/**
|
|
\brief Increase values of elements in \c els by \c delta.
|
|
|
|
The function returns a reference to \c *this to allow for expressions like
|
|
counter().count(sz, arr).get_positive_count()
|
|
*/
|
|
counter & count(unsigned sz, const unsigned * els, int delta = 1);
|
|
counter & count(const unsigned_vector & els, int delta = 1) {
|
|
return count(els.size(), els.c_ptr(), delta);
|
|
}
|
|
|
|
void collect_positive(idx_set & acc) const;
|
|
unsigned get_positive_count() const;
|
|
bool get_max_positive(unsigned & res) const;
|
|
unsigned get_max_positive() const;
|
|
/**
|
|
Since the default counter value of a counter is zero, the result is never negative.
|
|
*/
|
|
int get_max_counter_value() const;
|
|
};
|
|
|
|
class var_counter : public counter {
|
|
ptr_vector<sort> m_sorts;
|
|
expr_fast_mark1 m_visited;
|
|
ptr_vector<expr> m_todo;
|
|
unsigned_vector m_scopes;
|
|
unsigned get_max_var(bool & has_var);
|
|
|
|
public:
|
|
var_counter(bool stay_non_negative = true) : counter(stay_non_negative) {}
|
|
void count_vars(ast_manager & m, const app * t, int coef = 1);
|
|
void count_vars(ast_manager & m, const rule * r, int coef = 1);
|
|
unsigned get_max_var(const rule& r);
|
|
unsigned get_max_var(expr* e);
|
|
unsigned get_next_var(expr* e);
|
|
};
|
|
|
|
class ast_counter {
|
|
typedef obj_map<ast, int> map_impl;
|
|
map_impl m_data;
|
|
bool m_stay_non_negative;
|
|
public:
|
|
typedef map_impl::iterator iterator;
|
|
|
|
ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
|
|
|
|
iterator begin() const { return m_data.begin(); }
|
|
iterator end() const { return m_data.end(); }
|
|
|
|
int & get(ast * el) {
|
|
return m_data.insert_if_not_there2(el, 0)->get_data().m_value;
|
|
}
|
|
void update(ast * el, int delta){
|
|
get(el)+=delta;
|
|
SASSERT(!m_stay_non_negative || get(el)>=0);
|
|
}
|
|
|
|
void inc(ast * el) { update(el, 1); }
|
|
void dec(ast * el) { update(el, -1); }
|
|
};
|
|
|
|
void del_rule(horn_subsume_model_converter* mc, rule& r);
|
|
|
|
void resolve_rule(replace_proof_converter* pc, rule& r1, rule& r2, unsigned idx,
|
|
expr_ref_vector const& s1, expr_ref_vector const& s2, rule& res);
|
|
|
|
model_converter* mk_skip_model_converter();
|
|
|
|
proof_converter* mk_skip_proof_converter();
|
|
|
|
|
|
/**
|
|
Return maximal variable number, or zero is there isn't any
|
|
*/
|
|
// unsigned get_max_var(const rule & r, ast_manager & m);
|
|
|
|
void reverse_renaming(ast_manager & m, const expr_ref_vector & src, expr_ref_vector & tgt);
|
|
|
|
/**
|
|
\brief Populate vector \c renaming_args so that it can be used as an argument to \c var_subst.
|
|
The renaming we want is one that transforms variables with numbers of indexes of \c map into the
|
|
values of at those indexes. If a value if \c UINT_MAX, it means we do not transform the index
|
|
corresponding to it.
|
|
*/
|
|
void get_renaming_args(const unsigned_vector & map, const relation_signature & orig_sig,
|
|
expr_ref_vector & renaming_arg);
|
|
|
|
void print_renaming(const expr_ref_vector & cont, std::ostream & out);
|
|
|
|
/**
|
|
\brief Update tgt with effect of applying substitution from 'sub' to it.
|
|
tgt is extended by variables that are substituted by 'sub'.
|
|
We use the convention that the entry at index 'i' corresponds to variable
|
|
with de-Bruijn index 'i'.
|
|
*/
|
|
void apply_subst(expr_ref_vector& tgt, expr_ref_vector const& sub);
|
|
|
|
// -----------------------------------
|
|
//
|
|
// container functions
|
|
//
|
|
// -----------------------------------
|
|
|
|
template<class Set>
|
|
void set_intersection(Set & tgt, const Set & src) {
|
|
svector<typename Set::data> to_remove;
|
|
typename Set::iterator vit = tgt.begin();
|
|
typename Set::iterator vend = tgt.end();
|
|
for(;vit!=vend;++vit) {
|
|
typename Set::data itm=*vit;
|
|
if(!src.contains(itm)) {
|
|
to_remove.push_back(itm);
|
|
}
|
|
}
|
|
while(!to_remove.empty()) {
|
|
tgt.remove(to_remove.back());
|
|
to_remove.pop_back();
|
|
}
|
|
}
|
|
|
|
template<class Set>
|
|
void set_difference(Set & tgt, const Set & to_remove) {
|
|
typename Set::iterator vit = to_remove.begin();
|
|
typename Set::iterator vend = to_remove.end();
|
|
for(;vit!=vend;++vit) {
|
|
typename Set::data itm=*vit;
|
|
tgt.remove(itm);
|
|
}
|
|
}
|
|
|
|
template<class Set>
|
|
void set_union(Set & tgt, const Set & to_add) {
|
|
typename Set::iterator vit = to_add.begin();
|
|
typename Set::iterator vend = to_add.end();
|
|
for(;vit!=vend;++vit) {
|
|
typename Set::data itm=*vit;
|
|
tgt.insert(itm);
|
|
}
|
|
}
|
|
|
|
void idx_set_union(idx_set & tgt, const idx_set & src);
|
|
|
|
template<class T>
|
|
void unite_disjoint_maps(T & tgt, const T & src) {
|
|
typename T::iterator it = src.begin();
|
|
typename T::iterator end = src.end();
|
|
for(; it!=end; ++it) {
|
|
SASSERT(!tgt.contains(it->m_key));
|
|
tgt.insert(it->m_key, it->m_value);
|
|
}
|
|
}
|
|
|
|
template<class T, class U>
|
|
void collect_map_range(T & acc, const U & map) {
|
|
typename U::iterator it = map.begin();
|
|
typename U::iterator end = map.end();
|
|
for(; it!=end; ++it) {
|
|
acc.push_back(it->m_value);
|
|
}
|
|
}
|
|
|
|
|
|
template<class T>
|
|
void print_container(const T & begin, const T & end, std::ostream & out) {
|
|
T it = begin;
|
|
out << "(";
|
|
bool first = true;
|
|
for(; it!=end; ++it) {
|
|
if(first) { first = false; } else { out << ","; }
|
|
out << (*it);
|
|
}
|
|
out << ")";
|
|
}
|
|
|
|
template<class T>
|
|
void print_container(const T & cont, std::ostream & out) {
|
|
print_container(cont.begin(), cont.end(), out);
|
|
}
|
|
|
|
template<class T, class M>
|
|
void print_container(const ref_vector<T,M> & cont, std::ostream & out) {
|
|
print_container(cont.c_ptr(), cont.c_ptr() + cont.size(), out);
|
|
}
|
|
|
|
template<class T>
|
|
void print_map(const T & cont, std::ostream & out) {
|
|
typename T::iterator it = cont.begin();
|
|
typename T::iterator end = cont.end();
|
|
out << "(";
|
|
bool first = true;
|
|
for(; it!=end; ++it) {
|
|
if(first) { first = false; } else { out << ","; }
|
|
out << it->m_key << "->" << it->m_value;
|
|
}
|
|
out << ")";
|
|
}
|
|
|
|
template<class It, class V>
|
|
unsigned find_index(const It & begin, const It & end, const V & val) {
|
|
unsigned idx = 0;
|
|
It it = begin;
|
|
for(; it!=end; it++, idx++) {
|
|
if(*it==val) {
|
|
return idx;
|
|
}
|
|
}
|
|
return UINT_MAX;
|
|
}
|
|
|
|
template<class T, class U>
|
|
bool containers_equal(const T & begin1, const T & end1, const U & begin2, const U & end2) {
|
|
T it1 = begin1;
|
|
U it2 = begin2;
|
|
for(; it1!=end1 && it2!=end2; ++it1, ++it2) {
|
|
if(*it1!=*it2) {
|
|
return false;
|
|
}
|
|
}
|
|
return it1==end1 && it2==end2;
|
|
}
|
|
|
|
template<class T, class U>
|
|
bool vectors_equal(const T & c1, const U & c2) {
|
|
if(c1.size()!=c2.size()) {
|
|
return false;
|
|
}
|
|
typename T::data * it1 = c1.c_ptr();
|
|
typename T::data * end1 = c1.c_ptr()+c1.size();
|
|
typename U::data * it2 = c2.c_ptr();
|
|
for(; it1!=end1; ++it1, ++it2) {
|
|
if(*it1!=*it2) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template<class T>
|
|
unsigned int_vector_hash(const T & cont) {
|
|
return string_hash(reinterpret_cast<const char *>(cont.c_ptr()),
|
|
cont.size()*sizeof(typename T::data), 0);
|
|
}
|
|
|
|
template<class T>
|
|
struct int_vector_hash_proc {
|
|
unsigned operator()(const T & cont) const {
|
|
return int_vector_hash(cont);
|
|
}
|
|
};
|
|
template<class T>
|
|
struct vector_eq_proc {
|
|
bool operator()(const T & c1, const T & c2) const { return vectors_equal(c1, c2); }
|
|
};
|
|
|
|
template<class T>
|
|
void dealloc_ptr_vector_content(ptr_vector<T> & v) {
|
|
typename ptr_vector<T>::iterator it = v.begin();
|
|
typename ptr_vector<T>::iterator end = v.end();
|
|
for(; it!=end; ++it) {
|
|
dealloc(*it);
|
|
}
|
|
}
|
|
|
|
void dealloc_ptr_vector_content(ptr_vector<relation_base> & v);
|
|
|
|
/**
|
|
\brief Add elements from an iterable object \c src into the vector \c vector.
|
|
*/
|
|
template<class VectType, class U>
|
|
void push_into_vector(VectType & vector, const U & src) {
|
|
typename U::iterator it = src.begin();
|
|
typename U::iterator end = src.end();
|
|
for(; it!=end; ++it) {
|
|
vector.push_back(*it);
|
|
}
|
|
}
|
|
|
|
template<class VectType, class U, class M>
|
|
void push_into_vector(VectType & vector, const ref_vector<U,M> & src) {
|
|
U * const * it = src.begin();
|
|
U * const * end = src.end();
|
|
for(; it!=end; ++it) {
|
|
vector.push_back(*it);
|
|
}
|
|
}
|
|
|
|
template<class SetType, class U>
|
|
void insert_into_set(SetType & tgt, const U & src) {
|
|
typename U::const_iterator it = src.begin();
|
|
typename U::const_iterator end = src.end();
|
|
for(; it!=end; ++it) {
|
|
tgt.insert(*it);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Remove the first occurence of \c el from \c v and return \c true. If
|
|
\c el is not present in \c v, return \c false. The order of elements in \c v
|
|
is not preserved.
|
|
*/
|
|
template<class T>
|
|
bool remove_from_vector(T & v, const typename T::data & el) {
|
|
unsigned sz = v.size();
|
|
for(unsigned i=0; i<sz; i++) {
|
|
if(v[i]==el) {
|
|
std::swap(v[i], v.back());
|
|
v.pop_back();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Reset and deallocate the values stored in a mapping of the form obj_map<Key, Value*>
|
|
*/
|
|
template<typename Key, typename Value, typename Hash, typename Eq>
|
|
void reset_dealloc_values(map<Key, Value*, Hash, Eq> & m) {
|
|
typename map<Key, Value*, Hash, Eq>::iterator it = m.begin();
|
|
typename map<Key, Value*, Hash, Eq>::iterator end = m.end();
|
|
for (; it != end; ++it) {
|
|
dealloc(it->m_value);
|
|
}
|
|
m.reset();
|
|
}
|
|
|
|
template<class T>
|
|
struct aux__index_comparator {
|
|
T* m_keys;
|
|
aux__index_comparator(T* keys) : m_keys(keys) {}
|
|
bool operator()(unsigned a, unsigned b) {
|
|
return m_keys[a]<m_keys[b];
|
|
}
|
|
};
|
|
|
|
template<class T, class U>
|
|
void sort_two_arrays(unsigned len, T* keys, U* vals) {
|
|
if(len<2) {
|
|
return;
|
|
}
|
|
if(len==2) {
|
|
if(keys[0]>keys[1]) {
|
|
std::swap(keys[0], keys[1]);
|
|
std::swap(vals[0], vals[1]);
|
|
}
|
|
return;
|
|
}
|
|
unsigned_vector numbers;
|
|
for(unsigned i=0; i<len; i++) {
|
|
numbers.push_back(i);
|
|
}
|
|
aux__index_comparator<T> cmp(keys);
|
|
std::sort(numbers.begin(), numbers.end(), cmp);
|
|
for(unsigned i=0; i<len; i++) {
|
|
unsigned prev_i = i;
|
|
for(;;) {
|
|
unsigned src_i = numbers[prev_i];
|
|
numbers[prev_i]=prev_i;
|
|
if(src_i==i) {
|
|
break;
|
|
}
|
|
std::swap(keys[prev_i], keys[src_i]);
|
|
std::swap(vals[prev_i], vals[src_i]);
|
|
prev_i = src_i;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Consider \c translation as a map from indexes to values. Iterate through \c src and store
|
|
transformed values of elements into \c res unless they are equal to \c UINT_MAX.
|
|
*/
|
|
void collect_and_transform(const unsigned_vector & src, const unsigned_vector & translation,
|
|
unsigned_vector & res);
|
|
|
|
/**
|
|
\brief Insert into \c res values of \c src transformed by \c map (understood as a function
|
|
from its indexes to the values stored in it).
|
|
*/
|
|
void transform_set(const unsigned_vector & map, const idx_set & src, idx_set & result);
|
|
|
|
void add_sequence(unsigned start, unsigned count, unsigned_vector & v);
|
|
|
|
template<class Container>
|
|
void add_sequence_without_set(unsigned start, unsigned count, const Container & complement, unsigned_vector & v) {
|
|
unsigned after_last = start+count;
|
|
for(unsigned i=start; i<after_last; i++) {
|
|
if(!complement.contains(i)) {
|
|
v.push_back(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// -----------------------------------
|
|
//
|
|
// filesystem functions
|
|
//
|
|
// -----------------------------------
|
|
|
|
void get_file_names(std::string directory, std::string extension, bool traverse_subdirs,
|
|
string_vector & res);
|
|
|
|
bool file_exists(std::string name);
|
|
bool is_directory(std::string name);
|
|
|
|
std::string get_file_name_without_extension(std::string name);
|
|
|
|
// -----------------------------------
|
|
//
|
|
// misc
|
|
//
|
|
// -----------------------------------
|
|
|
|
struct uint64_hash {
|
|
typedef uint64 data;
|
|
unsigned operator()(uint64 x) const { return hash_ull(x); }
|
|
};
|
|
|
|
template<class T>
|
|
void universal_delete(T* ptr) {
|
|
dealloc(ptr);
|
|
}
|
|
|
|
void universal_delete(relation_base* ptr);
|
|
void universal_delete(table_base* ptr);
|
|
|
|
template<typename T>
|
|
class scoped_rel {
|
|
T* m_t;
|
|
public:
|
|
scoped_rel(T* t) : m_t(t) {}
|
|
~scoped_rel() { if (m_t) { universal_delete(m_t); } }
|
|
scoped_rel() : m_t(0) {}
|
|
scoped_rel& operator=(T* t) { if (m_t) { universal_delete(m_t); } m_t = t; return *this; }
|
|
T* operator->() { return m_t; }
|
|
const T* operator->() const { return m_t; }
|
|
T& operator*() { return *m_t; }
|
|
const T& operator*() const { return *m_t; }
|
|
operator bool() const { return m_t!=0; }
|
|
T* get() { return m_t; }
|
|
/**
|
|
\brief Remove object from \c scoped_rel without deleting it.
|
|
*/
|
|
T* release() {
|
|
T* res = m_t;
|
|
m_t = 0;
|
|
return res;
|
|
}
|
|
};
|
|
|
|
/**
|
|
\brief If it is possible to convert the beginning of \c s to uint64,
|
|
store the result of conversion and return true; otherwise return false.
|
|
*/
|
|
bool string_to_uint64(const char * s, uint64 & res);
|
|
std::string to_string(uint64 num);
|
|
/**
|
|
\brief Read the sequence of decimal digits starting at \c s and interpret it as
|
|
uint64. If successful, \c res will contain the read number and \c s will point
|
|
to the first non-digit character, and true is returned. If the first character
|
|
is not a digit, no parameter is modified and false is returned. If the uint64
|
|
overflows, \c points to the character which caused the overflow and false is
|
|
returned.
|
|
*/
|
|
bool read_uint64(const char * & s, uint64 & res);
|
|
};
|
|
|
|
#endif /* _DL_UTIL_H_ */
|
|
|