#include <stdio.h>
#include <stdlib.h>
#include <new>

#if __cplusplus < 201103L
#define NEW_EXCEPTION throw(std::bad_alloc)
#define NO_NEW_EXCEPTION throw()
#else
#define NEW_EXCEPTION
#define NO_NEW_EXCEPTION noexcept
#endif

void *operator new (size_t ) NEW_EXCEPTION;

void *operator new (size_t s) NEW_EXCEPTION {
  return malloc (s);
}

void *operator new[] (size_t s) NEW_EXCEPTION {
  return malloc (s);
}

void operator delete (void *obj) NO_NEW_EXCEPTION {
  free (obj);
}

void operator delete[] (void *obj) NO_NEW_EXCEPTION {
  free (obj);
}

#if __cpp_sized_deallocation   // on Windows/MinGW this variant is used!
void operator delete(void *obj, std::size_t) NO_NEW_EXCEPTION {
  free(obj);
}

void operator delete[](void *obj, std::size_t) NO_NEW_EXCEPTION {
  free(obj);
}
#endif

struct A { // bug 517
  /*static*/ void operator delete(void* ptr) NO_NEW_EXCEPTION; // bug 517 was: fails without 'static'
};

void A::operator delete (void* ptr) NO_NEW_EXCEPTION {}


class C {
public:
  void f () {}

  // we always use the same C instance
  void *operator new (size_t) {
    static C c;
    return &c;
  }
  void operator delete (void *) {
  }

};

#define STRING(x) #x

aspect HeapSurveillance {
  advice execution ("% ...::operator new(...)" ||
		    "% ...::operator delete(...)" ||
		    "% ...::operator new[](...)" ||
		    "% ...::operator delete[](...)") : before () {
    printf ("executing heap operation \"%s\"\n", JoinPoint::signature ());
    printf ("  tjp->that() is %s (should be 0)\n", (tjp->that () ? "not 0" : "0"));
  }
};

int main () {
  printf ("ExecAdviceNewDelete: execution advice for heap operations\n");
  printf ("=========================================================\n");
  C *c = new C;
  c->f ();
  delete c;
  delete new int;
  delete[] new double[20];
  delete new A;
  printf ("=========================================================\n");
}
