#include <iostream>

/* Extern reference to the longjmp-using code we'll call */
extern "C" {
	void calledFromCppCode();
};

/*
 * A typical reference-counted object using embedded-style
 * refcounting, and a typical counted reference to it.
 */

class RefCountedObject {
  int refCount;
public:
  RefCountedObject() : refCount(0) {
  }
  ~RefCountedObject() {
    std::cerr << "RefCountedObject destroyed with refcount==" << refCount << std::endl;
  }
  int getRefCount() {
    return refCount;
  }
protected:
  friend class Reference;
  void incRef() {
    std::cerr << "Incrementing refcount from " << refCount << " to " << (refCount+1) << std::endl;
    refCount++;
  }
  void decRef() {
    std::cerr << "Decrementing refcount from " << refCount << " to " << (refCount-1) << std::endl;
    refCount--;
  }
};

class Reference {
  RefCountedObject& ref;
public:
  Reference(RefCountedObject& refObj) : ref(refObj) {
    ref.incRef();
  }
  ~Reference() {
    ref.decRef();
  }
  RefCountedObject& operator*() {
    return ref;
  }
  RefCountedObject * get() {
    return &ref;
  }
};

static RefCountedObject fred = RefCountedObject();

extern "C" void cppCall() {
  std::cerr << "Entering C++ module, refcount is " << fred.getRefCount() << '\n';
  if (1) {
    /* Use of stack-based object with dtor - in this case, a reference - somewhere where should be scope-unwound */
    Reference ref( fred );
    /* and call into the C code that'll end up doing a longjmp() while that stack object still exists */
    std::cerr << "Calling back into C, refcount is " << fred.getRefCount() << '\n';
    calledFromCppCode();
    std::cerr << "Returning from call into C, refcount is " << fred.getRefCount() << '\n';
  }
  std::cerr << "Scope with ref exited, refcount is " << fred.getRefCount() << '\n';
}

extern "C" int cppSanityCheck() {
  /* Refcount should be zero if everything is OK and we haven't leaked any references,
   * as there's no way to go back to where we started from. */
  int refCount = fred.getRefCount();
  std::cerr << "Final ref count is: " << refCount << std::endl;
  return refCount;
}
