/*******************************************************************\

Module: Value Set

Author: Daniel Kroening, kroening@cs.cmu.edu

\*******************************************************************/

#ifndef CPROVER_POINTER_ANALYSIS_VALUE_SET_H
#define CPROVER_POINTER_ANALYSIS_VALUE_SET_H

#include <ref_expr_set.h>

#include <hash_cont.h>
#include <namespace.h>

class value_sett
{
public:
  typedef irep_idt idt;
  
  static const std::string &id2string(const idt &id)
  {
    #ifdef USE_DSTRING
    return id.as_string();
    #else
    return id;
    #endif
  }
  
  struct entryt
  {
    ref_expr_sett expr_set;
    idt identifier;
    std::string suffix;
  };
  
  typedef hash_set_cont<exprt, irep_hash> expr_sett;

  #ifdef USE_DSTRING   
  typedef std::map<idt, entryt> valuest;
  #else
  typedef hash_map_cont<idt, entryt, string_hash> valuest;
  #endif

  void get_value_set(
    const exprt &expr,
    expr_sett &expr_set,
    const namespacet &ns) const;

  expr_sett &get(
    const idt &identifier,
    const std::string &suffix);

  void make_any()
  {
    values.clear();
  }
  
  void clear()
  {
    values.clear();
  }
  
  void add_var(const idt &id, const std::string &suffix)
  {
    get_entry(id, suffix);
  }
  
  void add_var(const entryt &e)
  {
    get_entry(e.identifier, e.suffix);
  }
  
  entryt &get_entry(const idt &id, const std::string &suffix)
  {
    entryt e;
    e.identifier=id;
    e.suffix=suffix;
    return get_entry(e);
  }
  
  entryt &get_entry(const entryt &e)
  {
    std::string index=id2string(e.identifier)+e.suffix;

    std::pair<valuest::iterator, bool> r=
      values.insert(std::pair<idt, entryt>(index, e));

    return r.first->second;
  }
  
  void add_vars(const std::list<entryt> &vars)
  {
    for(std::list<entryt>::const_iterator
        it=vars.begin();
        it!=vars.end();
        it++)
      add_var(*it);
  }

  void output(
    const namespacet &ns,
    std::ostream &out) const;
    
  valuest values;

  // true = added s.th. new
  bool make_union(const valuest &new_values);

  // true = added s.th. new
  bool make_union(const value_sett &new_values)
  {
    return make_union(new_values.values);
  }

  void apply_code(
    const exprt &code,
    const namespacet &ns);

  void assign(
    const exprt &lhs,
    const exprt &rhs,
    const namespacet &ns,
    bool add_to_sets=false);

  void do_return(
    const exprt &lhs,
    const exprt &code,
    const namespacet &ns);

protected:
  void get_value_set_rec(
    const exprt &expr,
    expr_sett &expr_set,
    const std::string &suffix,
    const namespacet &ns) const;

  void get_reference_set_rec(
    const exprt &expr,
    expr_sett &expr_set,
    const namespacet &ns) const;

  void dereference_rec(
    const exprt &src,
    exprt &dest) const;

  void assign_rec(
    const exprt &lhs,
    expr_sett &values_rhs,
    const std::string &suffix,
    const namespacet &ns,
    bool add_to_sets);
  
  void do_functioncall_rec(
    const exprt &lhs,
    const exprt &function,
    const exprt &call,
    const namespacet &ns);
};

#endif
