How to implement a generic c++ non-deterministic predicate?

Hi all,
I’m trying to write a generic c++ non-deterministic predicate, but have no idea about how to transfer the context. What I’ve tried always causes crash:(

%mycall.pl
:- module(mycall, [mycall/1]).

:- use_foreign_library('./mycall.dylib').

:- meta_predicate
  mycall(0).

//mycall.cpp
#define PROLOG_MODULE "mycall"

#include <SWI-cpp.h>
#include <iostream>

using namespace std;

struct RetryContext {
  PlTerm term;
  PlTermv termv;
  PlQuery query;
  RetryContext(PlTerm const &t) : term(t), termv{term}, query("call", termv) {}
};

PREDICATE_NONDET(mycall, 1) {
  int ctl = PL_foreign_control(handle);
  int ret = 0;

  RetryContext *rcp = nullptr;

  switch (ctl) {
  case PL_FIRST_CALL:
    cout << "first call\n";
    rcp = new RetryContext(A1);
    ret = rcp->query.next_solution();
    if (!ret)
      goto out;
    PL_retry_address(rcp);

  case PL_REDO:
    cout << "redo\n";
    rcp = (RetryContext *)PL_foreign_context_address(handle);
    ret = rcp->query.next_solution();
    if (!ret)
      goto out;
    PL_retry_address(rcp);

  case PL_PRUNED:
    cout << "pruned\n";
    rcp = (RetryContext *)PL_foreign_context_address(handle);
    delete rcp;
    return TRUE;
  }

out:
  cout << "out\n";
  if (rcp)
    delete rcp;
  return ret ? TRUE : FALSE;
}

laowang@bogon test % clang++ --std=c++17 -I/usr/local/lib/swipl/include -L/usr/local/lib/swipl/lib/x86_64-darwin -lswipl -shared -o mycall.dylib mycall.cpp
laowang@bogon test % swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.9)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- use_module(mycall).
true.

?- assert(test(a)).
true.

?- mycall(test(X)).
first call
X = a.

SWI-Prolog [thread 1 (main) at Sat Dec 7 16:36:01 2019]: received fatal signal 11 (segv)
C-stack trace labeled “crash”:
[0] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(save_backtrace+0x62) [0x106434042]
[1] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(print_c_backtrace+0x15) [0x106434915]
[2] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(sigCrashHandler+0xf4) [0x106434824]
[3] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(dispatch_signal+0x41c) [0x10639571c]
[4] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(pl_signal_handler+0x15) [0x106398155]
[5] /usr/lib/system/libsystem_platform.dylib(_sigtramp+0x1d) [0x7fff67626b1d]
[6] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(releaseStream+0x26) [0x1063fe966]
[7] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(query_loop+0xd5) [0x10636f235]
[8] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(prologToplevel+0x7a) [0x10636fd7a]
[9] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.1.9.dylib(PL_toplevel+0x21) [0x10630a451]
[10] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/bin/swipl(main+0x42) [0x1062d5f52]
[11] /usr/lib/system/libdyld.dylib(start+0x1) [0x7fff674252e5]
Running on_halt hooks with status 139
Killing 71566 with default signal handlers
zsh: segmentation fault swipl

laowang@bogon test % swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.9)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- use_module(’./mycall.pl’).
true.

?- assert(test(a)).
true.

?- assert(test(b)).
true.

?- mycall(test(X)).
first call
X = a ;
laowang@bogon test %

I’ll greatly appreciate any helps!

Arthur Wang

I don’t know specifically, but I descry a lack of break statements which you probably want at the end of each case. If that doesn’t solve the problem, can you perhaps identify which exact line of code causes the segfault?

Thank you for response. The break statements do not matter here because PL_retry_address/1 returns back to prolog from c++.

You must complete a opened query before returning to Prolog. For short, what you are truing to do will never work. Sorry …

Thank you Jan for pointing out that. I’ll not try in that way.