/* -*- C++ -*- */

#ifndef _TRACEHEAP_H_
#define _TRACEHEAP_H_

#include <stdlib.h>

#ifdef WIN32
#include <io.h>
#endif

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>

// An object that manages direct writing to a file.

class FileObject {
public:

  FileObject (void)
    : isOpen (0)
  {}
 
  ~FileObject (void) {
    close();
  }
 
  void open (char * fname)
  {
#if 1
    file = fopen(fname, "w+");
#else
#ifdef WIN32
    file = _open(fname, _O_WRONLY | _O_CREAT, _S_IREAD | _S_IWRITE);
#else
    file = ::open(fname, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
#endif
#endif
  }
 
  int is_open (void) {
    return isOpen;
  }
 
  void close (void)
  {
    if (isOpen) {
#if 1
      fclose (file);
#else
#ifdef WIN32
      _close (file);
#else
      ::close (file);
#endif
#endif
      isOpen = 0;
    }
  }
 
 
  friend FileObject& operator<<(FileObject& f, int n) {
    //          fprintf (f.file, "%d", n);
    char buf[255];
    sprintf (buf, "%d", n);
    f.writeString (buf);
    return f;
  }
 
  friend FileObject& operator<<(FileObject& f, char * s) {
    //                      fprintf (f.file, "%s", s);
    char buf[255];
    sprintf (buf, "%s", s);
    f.writeString (buf);
    return f;
  }
 
  friend FileObject& operator<<(FileObject& f, void * s) {
    //                      fprintf (f.file, "%p", s);
    char buf[255];
    sprintf (buf, "%p", s);
    f.writeString (buf);
    return f;
  }
 
private:

  void writeString (char * buf) {
#if 1
	  fprintf(file, buf);
#else
#ifdef WIN32
    _write (file, buf, strlen(buf));
#else
    write (file, buf, strlen(buf));
#endif
#endif
  }

#if 1
  FILE * file;
#else
  int file;
#endif

  bool isOpen;

};


// The TraceHeap itself.
// Traces malloc & free calls.
 
template <class Super, int Number>
class TraceHeap : public Super {
public:

  TraceHeap (void)
  {
    if (!theFile().is_open()) {
      char fname[255];
      sprintf (fname, "trace-%d", Number);
      theFile().open (fname);
      printf ("OPEN %s\n", fname);
    }
    getRefs()++;
  }
 
  ~TraceHeap (void)
  {
    //                      theFile() << ::std::flush;
    --getRefs();
    if (getRefs() == 0) {
      if (theFile().is_open())
	theFile().close();
    }
  }
 
  inline void * malloc (size_t sz) {
    void * ptr = Super::malloc (sz);
    theFile() << "M " << Number << "\t" << sz << "\t" << ptr << "\n";
    return ptr;
  }
  
  inline void free (void * ptr) {
    theFile() << "F " << Number << "\t" << ptr << "\n";
    Super::free (ptr);
  }
 
private:
 
  FileObject& theFile (void) {
    static FileObject f;
    return f;
  }
 
  int& getRefs (void) {
    static int refs = 0;
    return refs;
  }
 
};
 
 
#endif

#if 0
/* -*- C++ -*- */
#ifndef _TRACEHEAP_H_
#define _TRACEHEAP_H_
// #include <iostream.h>
//#include <fstream.h>
#include <fstream>
#include <map>

template <class Super, int Number>
class TraceHeap : public Super {
public:
  
  TraceHeap (void)
  {
    if (!theFile().is_open()) {
      printf ("OPEN\n");
      theFile().open ("trace");
    }
    getRefs()++;
  }
  ~TraceHeap (void)
  {
    theFile() << ::std::flush;
    --getRefs();
    if (getRefs() == 0) {
      if (theFile().is_open())
	theFile().close();
    }
  }
  inline void * malloc (size_t sz) {
    void * ptr = Super::malloc (sz);
    theFile() << "M\t" << sz << "\t" << ptr << "\n";
    return ptr;
  }
  
  inline void free (void * ptr) {
    theFile() << "F\t" << ptr << "\n";
    Super::free (ptr);
  }
private:
  std::ofstream& theFile (void) {
    static std::ofstream f;
    return f;
  }
  int& getRefs (void) {
    static int refs = 0;
    return refs;
  }
};

#endif
#endif
