#ifndef __RESULTS__HPP
#define __RESULTS__HPP

#include "llvm/ADT/BitVector.h"

#include "CommonTypes.hpp"

namespace llvm
{
  class GlobalAlias;
  class Module;
}

class argument_t
{
public:
  argument_t(const llvm::Function * fn,
             const llvm::Argument * arg);

  bool isVarg() const;
  bool operator < (const argument_t &a) const;
  
  const llvm::Function * _fn;
  const llvm::Argument * _arg;
};

class state_t
{
public:
  state_t();

  void setBit(unsigned b);
  void unsetBit(unsigned b);
  bool queryBit(unsigned b) const;
private:
  llvm::BitVector _State;
};

class results_t
{
public:
  results_t(const llvm::Module * M);

  void resetDirtyFlag();
  // If the results are dirty, that means progress has been made.
  bool isDirty() const;
  
  void markAllocator(const llvm::Function * fn);
  void markNotDeallocator(const llvm::Function * fn, const llvm::Argument * arg);
  void pinDeallocator(const std::string & function_name, short index);
  void markArray(const llvm::Function * fn, const llvm::Argument * arg, short depth);
  bool markStrongEscape(const llvm::Function * fn, const llvm::Argument * arg);
  bool markWeakEscape(const llvm::Function * fn, const llvm::Argument * arg);
  void markIn(const llvm::Function * fn, const llvm::Argument * arg);
  void markOut(const llvm::Function * fn, const llvm::Argument * arg);
  
  bool isAllocator(const llvm::Function * fn);
  level_set arrayLevels(const llvm::Function * fn, const llvm::Argument * arg);
  bool deallocatesArgument(const llvm::Function * fn, const llvm::Argument * arg);
  bool argumentEscapesStrong(const llvm::Function * fn, const llvm::Argument * arg);
  bool argumentEscapesWeak(const llvm::Function * fn, const llvm::Argument * arg);  
  bool isIn(const llvm::Function * fn, const llvm::Argument * arg);
  bool isOut(const llvm::Function * fn, const llvm::Argument * arg);
  bool isWeakField(const std::string & structName, short index);
  
  // Register a user-provided annotation; these should never be
  // overwritten (unlike markWeakEscape, which doesn't really have
  // any purpose right now).
  // void registerWeakArgument(const llvm::Function * fn, const llvm::Argument * arg);
  void registerWeakField(const std::string & sname, short idx);
  void registerFinalizer(const std::string & allocator,
                         const std::string & finalizer);
  
  // void print() const;
  // This is a member of the results_t class, but is implemented in Driver.cpp
  // with the other Guile-related functions.
  void annotateSignature() const;
  void removeResultsFor(const llvm::Function * F);
  void addAlias(const llvm::Function * F, const llvm::GlobalAlias* A);
  
private:
  void ensureDependencyMet(argument_t arg);
  void ensureAllocator(argument_t arg);
  bool hasExternalFunction(argument_t arg);
  bool entryInSystem(argument_t arg);

  void printArgument(std::pair<argument_t, state_t> p);

private:
  typedef std::multimap<std::string, short> weak_map;
  typedef std::multimap<const argument_t, short> array_map;
  typedef std::map<const llvm::Function *, std::string> alias_map;
  typedef std::map<argument_t, state_t> state_map;
  typedef std::set<argument_t> argset;
  typedef std::map<const llvm::Function*, const llvm::Function*> finalizer_map;
  
private:
  function_set _hidden_functions;
  
  function_set _allocators;
  finalizer_map _pairings;
  argset _pinnedDeallocators;
  
  alias_map _aliases;
  state_map _results;
  array_map _arrays;
  weak_map _weak;
  bool _dirty;
  
  const llvm::Module * _M;
};
#endif // __RESULTS__HPP
