[pypy-commit] pypy default: Merged upstream.
alex_gaynor
noreply at buildbot.pypy.org
Sat Jun 23 20:07:41 CEST 2012
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch:
Changeset: r55790:d8e9dbcc5c64
Date: 2012-06-23 11:07 -0700
http://bitbucket.org/pypy/pypy/changeset/d8e9dbcc5c64/
Log: Merged upstream.
diff too long, truncating to 10000 out of 11470 lines
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -20,6 +20,16 @@
^pypy/module/cpyext/test/.+\.obj$
^pypy/module/cpyext/test/.+\.manifest$
^pypy/module/test_lib_pypy/ctypes_tests/.+\.o$
+^pypy/module/cppyy/src/.+\.o$
+^pypy/module/cppyy/bench/.+\.so$
+^pypy/module/cppyy/bench/.+\.root$
+^pypy/module/cppyy/bench/.+\.d$
+^pypy/module/cppyy/src/.+\.errors$
+^pypy/module/cppyy/test/.+_rflx\.cpp$
+^pypy/module/cppyy/test/.+\.so$
+^pypy/module/cppyy/test/.+\.rootmap$
+^pypy/module/cppyy/test/.+\.exe$
+^pypy/module/cppyy/test/.+_cint.h$
^pypy/doc/.+\.html$
^pypy/doc/config/.+\.rst$
^pypy/doc/basicblock\.asc$
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -216,6 +216,7 @@
DFKI GmbH, Germany
Impara, Germany
Change Maker, Sweden
+ University of California Berkeley, USA
The PyPy Logo as used by http://speed.pypy.org and others was created
by Samuel Reis and is distributed on terms of Creative Commons Share Alike
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -5,8 +5,10 @@
The cppyy module provides C++ bindings for PyPy by using the reflection
information extracted from C++ header files by means of the
`Reflex package`_.
-For this to work, you have to both install Reflex and build PyPy from the
-reflex-support branch.
+For this to work, you have to both install Reflex and build PyPy from source,
+as the cppyy module is not enabled by default.
+Note that the development version of cppyy lives in the reflex-support
+branch.
As indicated by this being a branch, support for Reflex is still
experimental.
However, it is functional enough to put it in the hands of those who want
@@ -71,7 +73,8 @@
.. _`recent snapshot`: http://cern.ch/wlav/reflex-2012-05-02.tar.bz2
.. _`gccxml`: http://www.gccxml.org
-Next, get the `PyPy sources`_, select the reflex-support branch, and build.
+Next, get the `PyPy sources`_, optionally select the reflex-support branch,
+and build it.
For the build to succeed, the ``$ROOTSYS`` environment variable must point to
the location of your ROOT (or standalone Reflex) installation, or the
``root-config`` utility must be accessible through ``PATH`` (e.g. by adding
@@ -82,7 +85,7 @@
$ hg clone https://bitbucket.org/pypy/pypy
$ cd pypy
- $ hg up reflex-support
+ $ hg up reflex-support # optional
$ cd pypy/translator/goal
$ python translate.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy
@@ -368,6 +371,11 @@
The C++ side will not see any overridden methods on the python side, as
cross-inheritance is planned but not yet supported.
+* **memory**: C++ instances created by calling their constructor from python
+ are owned by python.
+ You can check/change the ownership with the _python_owns flag that every
+ bound instance carries.
+
* **methods**: Are represented as python methods and work as expected.
They are first class objects and can be bound to an instance.
Virtual C++ methods work as expected.
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -23,7 +23,7 @@
* Write them in RPython as mixedmodule_, using *rffi* as bindings.
-* Write them in C++ and bind them through Reflex_ (EXPERIMENTAL)
+* Write them in C++ and bind them through Reflex_
.. _ctypes: #CTypes
.. _\_ffi: #LibFFI
diff --git a/pypy/doc/release-1.9.0.rst b/pypy/doc/release-1.9.0.rst
--- a/pypy/doc/release-1.9.0.rst
+++ b/pypy/doc/release-1.9.0.rst
@@ -102,8 +102,8 @@
JitViewer
=========
-There is a corresponding 1.9 release of JitViewer which is guaranteed to work
-with PyPy 1.9. See the `JitViewer docs`_ for details.
+There will be a corresponding 1.9 release of JitViewer which is guaranteed
+to work with PyPy 1.9. See the `JitViewer docs`_ for details.
.. _`JitViewer docs`: http://bitbucket.org/pypy/jitviewer
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -8,6 +8,9 @@
.. branch: default
.. branch: app_main-refactor
.. branch: win-ordinal
+.. branch: reflex-support
+Provides cppyy module (disabled by default) for access to C++ through Reflex.
+See doc/cppyy.rst for full details and functionality.
.. "uninteresting" branches that we should just ignore for the whatsnew:
diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
--- a/pypy/interpreter/buffer.py
+++ b/pypy/interpreter/buffer.py
@@ -44,6 +44,9 @@
# May be overridden. No bounds checks.
return ''.join([self.getitem(i) for i in range(start, stop, step)])
+ def get_raw_address(self):
+ raise ValueError("no raw buffer")
+
# __________ app-level support __________
def descr_len(self, space):
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -133,7 +133,7 @@
optimize_CALL_MAY_FORCE = optimize_CALL
def optimize_FORCE_TOKEN(self, op):
- # The handling of force_token needs a bit of exaplanation.
+ # The handling of force_token needs a bit of explanation.
# The original trace which is getting optimized looks like this:
# i1 = force_token()
# setfield_gc(p0, i1, ...)
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -43,6 +43,7 @@
config.objspace.usemodules._lsprof = False
#
config.objspace.usemodules._ffi = True
+#config.objspace.usemodules.cppyy = True
config.objspace.usemodules.micronumpy = False
#
set_pypy_opt_level(config, level='jit')
diff --git a/pypy/module/_ssl/test/test_ztranslation.py b/pypy/module/_ssl/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test__ffi_translates():
+ checkmodule('_ssl')
diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py
--- a/pypy/module/_ssl/thread_lock.py
+++ b/pypy/module/_ssl/thread_lock.py
@@ -65,6 +65,8 @@
eci = ExternalCompilationInfo(
separate_module_sources=[separate_module_source],
+ post_include_bits=[
+ "int _PyPy_SSL_SetupThreads(void);"],
export_symbols=['_PyPy_SSL_SetupThreads'],
)
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -164,6 +164,8 @@
data[index] = char
array._charbuf_stop()
+ def get_raw_address(self):
+ return self.array._charbuf_start()
def make_array(mytype):
W_ArrayBase = globals()['W_ArrayBase']
diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/__init__.py
@@ -0,0 +1,22 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+ """ """
+
+ interpleveldefs = {
+ '_load_dictionary' : 'interp_cppyy.load_dictionary',
+ '_resolve_name' : 'interp_cppyy.resolve_name',
+ '_scope_byname' : 'interp_cppyy.scope_byname',
+ '_template_byname' : 'interp_cppyy.template_byname',
+ '_set_class_generator' : 'interp_cppyy.set_class_generator',
+ '_register_class' : 'interp_cppyy.register_class',
+ 'CPPInstance' : 'interp_cppyy.W_CPPInstance',
+ 'addressof' : 'interp_cppyy.addressof',
+ 'bind_object' : 'interp_cppyy.bind_object',
+ }
+
+ appleveldefs = {
+ 'gbl' : 'pythonify.gbl',
+ 'load_reflection_info' : 'pythonify.load_reflection_info',
+ 'add_pythonization' : 'pythonify.add_pythonization',
+ }
diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/Makefile
@@ -0,0 +1,29 @@
+all: bench02Dict_reflex.so
+
+ROOTSYS := ${ROOTSYS}
+
+ifeq ($(ROOTSYS),)
+ genreflex=genreflex
+ cppflags=
+else
+ genreflex=$(ROOTSYS)/bin/genreflex
+ cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib
+endif
+
+PLATFORM := $(shell uname -s)
+ifeq ($(PLATFORM),Darwin)
+ cppflags+=-dynamiclib -single_module -arch x86_64
+endif
+
+ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),)
+ genreflexflags=
+ cppflags2=-O3 -fPIC
+else
+ genreflexflags=--with-methptrgetter
+ cppflags2=-Wno-pmf-conversions -O3 -fPIC
+endif
+
+
+bench02Dict_reflex.so: bench02.h bench02.cxx bench02.xml
+ $(genreflex) bench02.h $(genreflexflags) --selection=bench02.xml -I$(ROOTSYS)/include
+ g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex -lHistPainter `root-config --libs` $(cppflags) $(cppflags2)
diff --git a/pypy/module/cppyy/bench/bench02.cxx b/pypy/module/cppyy/bench/bench02.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.cxx
@@ -0,0 +1,79 @@
+#include "bench02.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TDirectory.h"
+#include "TInterpreter.h"
+#include "TSystem.h"
+#include "TBenchmark.h"
+#include "TStyle.h"
+#include "TError.h"
+#include "Getline.h"
+#include "TVirtualX.h"
+
+#include "Api.h"
+
+#include <iostream>
+
+TClass *TClass::GetClass(const char*, Bool_t, Bool_t) {
+ static TClass* dummy = new TClass("__dummy__", kTRUE);
+ return dummy; // is deleted by gROOT at shutdown
+}
+
+class TTestApplication : public TApplication {
+public:
+ TTestApplication(
+ const char* acn, Int_t* argc, char** argv, Bool_t bLoadLibs = kTRUE);
+ virtual ~TTestApplication();
+};
+
+TTestApplication::TTestApplication(
+ const char* acn, int* argc, char** argv, bool do_load) : TApplication(acn, argc, argv) {
+ if (do_load) {
+ // follow TRint to minimize differences with CINT
+ ProcessLine("#include <iostream>", kTRUE);
+ ProcessLine("#include <_string>", kTRUE); // for std::string iostream.
+ ProcessLine("#include <vector>", kTRUE); // needed because they're used within the
+ ProcessLine("#include <pair>", kTRUE); // core ROOT dicts and CINT won't be able
+ // to properly unload these files
+ }
+
+ // save current interpreter context
+ gInterpreter->SaveContext();
+ gInterpreter->SaveGlobalsContext();
+
+ // prevent crashes on accessing history
+ Gl_histinit((char*)"-");
+
+ // prevent ROOT from exiting python
+ SetReturnFromRun(kTRUE);
+}
+
+TTestApplication::~TTestApplication() {}
+
+static const char* appname = "pypy-cppyy";
+
+Bench02RootApp::Bench02RootApp() {
+ gROOT->SetBatch(kTRUE);
+ if (!gApplication) {
+ int argc = 1;
+ char* argv[1]; argv[0] = (char*)appname;
+ gApplication = new TTestApplication(appname, &argc, argv, kFALSE);
+ }
+}
+
+Bench02RootApp::~Bench02RootApp() {
+ // TODO: ROOT globals cleanup ... (?)
+}
+
+void Bench02RootApp::report() {
+ std::cout << "gROOT is: " << gROOT << std::endl;
+ std::cout << "gApplication is: " << gApplication << std::endl;
+}
+
+void Bench02RootApp::close_file(TFile* f) {
+ std::cout << "closing file " << f->GetName() << " ... " << std::endl;
+ f->Write();
+ f->Close();
+ std::cout << "... file closed" << std::endl;
+}
diff --git a/pypy/module/cppyy/bench/bench02.h b/pypy/module/cppyy/bench/bench02.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.h
@@ -0,0 +1,72 @@
+#include "TString.h"
+
+#include "TCanvas.h"
+#include "TFile.h"
+#include "TProfile.h"
+#include "TNtuple.h"
+#include "TH1F.h"
+#include "TH2F.h"
+#include "TRandom.h"
+#include "TRandom3.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TSystem.h"
+
+#include "TArchiveFile.h"
+#include "TBasket.h"
+#include "TBenchmark.h"
+#include "TBox.h"
+#include "TBranchRef.h"
+#include "TBrowser.h"
+#include "TClassGenerator.h"
+#include "TClassRef.h"
+#include "TClassStreamer.h"
+#include "TContextMenu.h"
+#include "TEntryList.h"
+#include "TEventList.h"
+#include "TF1.h"
+#include "TFileCacheRead.h"
+#include "TFileCacheWrite.h"
+#include "TFileMergeInfo.h"
+#include "TFitResult.h"
+#include "TFolder.h"
+//#include "TFormulaPrimitive.h"
+#include "TFunction.h"
+#include "TFrame.h"
+#include "TGlobal.h"
+#include "THashList.h"
+#include "TInetAddress.h"
+#include "TInterpreter.h"
+#include "TKey.h"
+#include "TLegend.h"
+#include "TMethodCall.h"
+#include "TPluginManager.h"
+#include "TProcessUUID.h"
+#include "TSchemaRuleSet.h"
+#include "TStyle.h"
+#include "TSysEvtHandler.h"
+#include "TTimer.h"
+#include "TView.h"
+//#include "TVirtualCollectionProxy.h"
+#include "TVirtualFFT.h"
+#include "TVirtualHistPainter.h"
+#include "TVirtualIndex.h"
+#include "TVirtualIsAProxy.h"
+#include "TVirtualPadPainter.h"
+#include "TVirtualRefProxy.h"
+#include "TVirtualStreamerInfo.h"
+#include "TVirtualViewer3D.h"
+
+#include <typeinfo>
+#include <ostream>
+
+
+class Bench02RootApp {
+public:
+ Bench02RootApp();
+ ~Bench02RootApp();
+
+ void report();
+ void close_file(TFile* f);
+};
diff --git a/pypy/module/cppyy/bench/bench02.xml b/pypy/module/cppyy/bench/bench02.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.xml
@@ -0,0 +1,41 @@
+<lcgdict>
+
+ <selection>
+
+ <!-- ROOT classes -->
+ <class pattern="T[A-Z]*" />
+ <class pattern="ROOT::T[A-Z]*" />
+ <class pattern="ROOT::Fit::*" />
+
+ <!-- ROOT globals -->
+ <variable name="gROOT" />
+ <variable name="gSystem" />
+ <variable name="gRandom" />
+
+ <!-- STL classes actually used -->
+ <class name="std::string" />
+ <class name="std::ostream" />
+ <class name="std::type_info" />
+ <class pattern="std::vector<*>" />
+ <class pattern="std::_Vector_base<*>" />
+
+ <!-- helper -->
+ <class name="Bench02RootApp" />
+
+ </selection>
+
+ <exclusion>
+
+ <struct pattern="TString::*" />
+ <class name="TString" >
+ <field name="fRep" transient="true"/>
+ </class>
+
+ <class name="TUUID::uuid_time_t" />
+
+ <class name="TClass::TNameMapNode" />
+ <class name="TFileOpenHandle" />
+
+ </exclusion>
+
+</lcgdict>
diff --git a/pypy/module/cppyy/bench/hsimple.C b/pypy/module/cppyy/bench/hsimple.C
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.C
@@ -0,0 +1,109 @@
+#include <TFile.h>
+#include <TNtuple.h>
+#include <TH2.h>
+#include <TProfile.h>
+#include <TCanvas.h>
+#include <TFrame.h>
+#include <TROOT.h>
+#include <TSystem.h>
+#include <TRandom3.h>
+#include <TBenchmark.h>
+#include <TInterpreter.h>
+
+TFile *hsimple(Int_t get=0)
+{
+// This program creates :
+// - a one dimensional histogram
+// - a two dimensional histogram
+// - a profile histogram
+// - a memory-resident ntuple
+//
+// These objects are filled with some random numbers and saved on a file.
+// If get=1 the macro returns a pointer to the TFile of "hsimple.root"
+// if this file exists, otherwise it is created.
+// The file "hsimple.root" is created in $ROOTSYS/tutorials if the caller has
+// write access to this directory, otherwise the file is created in $PWD
+
+ TString filename = "hsimple.root";
+ TString dir = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
+ dir.ReplaceAll("hsimple.C","");
+ dir.ReplaceAll("/./","/");
+ TFile *hfile = 0;
+ if (get) {
+ // if the argument get =1 return the file "hsimple.root"
+ // if the file does not exist, it is created
+ TString fullPath = dir+"hsimple.root";
+ if (!gSystem->AccessPathName(fullPath,kFileExists)) {
+ hfile = TFile::Open(fullPath); //in $ROOTSYS/tutorials
+ if (hfile) return hfile;
+ }
+ //otherwise try $PWD/hsimple.root
+ if (!gSystem->AccessPathName("hsimple.root",kFileExists)) {
+ hfile = TFile::Open("hsimple.root"); //in current dir
+ if (hfile) return hfile;
+ }
+ }
+ //no hsimple.root file found. Must generate it !
+ //generate hsimple.root in $ROOTSYS/tutorials if we have write access
+ if (!gSystem->AccessPathName(dir,kWritePermission)) {
+ filename = dir+"hsimple.root";
+ } else if (!gSystem->AccessPathName(".",kWritePermission)) {
+ //otherwise generate hsimple.root in the current directory
+ } else {
+ printf("you must run the script in a directory with write access\n");
+ return 0;
+ }
+ hfile = (TFile*)gROOT->FindObject(filename); if (hfile) hfile->Close();
+ hfile = new TFile(filename,"RECREATE","Demo ROOT file with histograms");
+
+ // Create some histograms, a profile histogram and an ntuple
+ TH1F *hpx = new TH1F("hpx","This is the px distribution",100,-4,4);
+ hpx->SetFillColor(48);
+ TH2F *hpxpy = new TH2F("hpxpy","py vs px",40,-4,4,40,-4,4);
+ TProfile *hprof = new TProfile("hprof","Profile of pz versus px",100,-4,4,0,20);
+ TNtuple *ntuple = new TNtuple("ntuple","Demo ntuple","px:py:pz:random:i");
+
+ gBenchmark->Start("hsimple");
+
+ // Create a new canvas.
+ TCanvas *c1 = new TCanvas("c1","Dynamic Filling Example",200,10,700,500);
+ c1->SetFillColor(42);
+ c1->GetFrame()->SetFillColor(21);
+ c1->GetFrame()->SetBorderSize(6);
+ c1->GetFrame()->SetBorderMode(-1);
+
+
+ // Fill histograms randomly
+ TRandom3 random;
+ Float_t px, py, pz;
+ const Int_t kUPDATE = 1000;
+ for (Int_t i = 0; i < 50000; i++) {
+ // random.Rannor(px,py);
+ px = random.Gaus(0, 1);
+ py = random.Gaus(0, 1);
+ pz = px*px + py*py;
+ Float_t rnd = random.Rndm(1);
+ hpx->Fill(px);
+ hpxpy->Fill(px,py);
+ hprof->Fill(px,pz);
+ ntuple->Fill(px,py,pz,rnd,i);
+ if (i && (i%kUPDATE) == 0) {
+ if (i == kUPDATE) hpx->Draw();
+ c1->Modified();
+ c1->Update();
+ if (gSystem->ProcessEvents())
+ break;
+ }
+ }
+ gBenchmark->Show("hsimple");
+
+ // Save all objects in this file
+ hpx->SetFillColor(0);
+ hfile->Write();
+ hpx->SetFillColor(48);
+ c1->Modified();
+ return hfile;
+
+// Note that the file is automatically close when application terminates
+// or when the file destructor is called.
+}
diff --git a/pypy/module/cppyy/bench/hsimple.py b/pypy/module/cppyy/bench/hsimple.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.py
@@ -0,0 +1,110 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-* This program creates :
+#*-* - a one dimensional histogram
+#*-* - a two dimensional histogram
+#*-* - a profile histogram
+#*-* - a memory-resident ntuple
+#*-*
+#*-* These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+_reflex = True # to keep things equal, set to False for full macro
+
+try:
+ import cppyy, random
+
+ if not hasattr(cppyy.gbl, 'gROOT'):
+ cppyy.load_reflection_info('bench02Dict_reflex.so')
+ _reflex = True
+
+ TCanvas = cppyy.gbl.TCanvas
+ TFile = cppyy.gbl.TFile
+ TProfile = cppyy.gbl.TProfile
+ TNtuple = cppyy.gbl.TNtuple
+ TH1F = cppyy.gbl.TH1F
+ TH2F = cppyy.gbl.TH2F
+ TRandom3 = cppyy.gbl.TRandom3
+
+ gROOT = cppyy.gbl.gROOT
+ gBenchmark = cppyy.gbl.TBenchmark()
+ gSystem = cppyy.gbl.gSystem
+
+except ImportError:
+ from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom3
+ from ROOT import gROOT, gBenchmark, gSystem
+ import random
+
+if _reflex:
+ gROOT.SetBatch(True)
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+if not _reflex:
+ hfile = gROOT.FindObject('hsimple.root')
+ if hfile:
+ hfile.Close()
+ hfile = TFile('hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.SetFillColor(48)
+hpxpy = TH2F('hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4)
+hprof = TProfile('hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20)
+if not _reflex:
+ ntuple = TNtuple('ntuple', 'Demo ntuple', 'px:py:pz:random:i')
+
+gBenchmark.Start('hsimple')
+
+# Create a new canvas, and customize it.
+c1 = TCanvas('c1', 'Dynamic Filling Example', 200, 10, 700, 500)
+c1.SetFillColor(42)
+c1.GetFrame().SetFillColor(21)
+c1.GetFrame().SetBorderSize(6)
+c1.GetFrame().SetBorderMode(-1)
+
+# Fill histograms randomly.
+random = TRandom3()
+kUPDATE = 1000
+for i in xrange(50000):
+ # Generate random numbers
+# px, py = random.gauss(0, 1), random.gauss(0, 1)
+ px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+ pz = px*px + py*py
+# rnd = random.random()
+ rnd = random.Rndm(1)
+
+ # Fill histograms
+ hpx.Fill(px)
+ hpxpy.Fill(px, py)
+ hprof.Fill(px, pz)
+ if not _reflex:
+ ntuple.Fill(px, py, pz, rnd, i)
+
+ # Update display every kUPDATE events
+ if i and i%kUPDATE == 0:
+ if i == kUPDATE:
+ hpx.Draw()
+
+ c1.Modified(True)
+ c1.Update()
+
+ if gSystem.ProcessEvents(): # allow user interrupt
+ break
+
+gBenchmark.Show( 'hsimple' )
+
+# Save all objects in this file
+hpx.SetFillColor(0)
+if not _reflex:
+ hfile.Write()
+hpx.SetFillColor(48)
+c1.Modified(True)
+c1.Update()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/bench/hsimple_rflx.py b/pypy/module/cppyy/bench/hsimple_rflx.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple_rflx.py
@@ -0,0 +1,120 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-* This program creates :
+#*-* - a one dimensional histogram
+#*-* - a two dimensional histogram
+#*-* - a profile histogram
+#*-* - a memory-resident ntuple
+#*-*
+#*-* These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+try:
+ import warnings
+ warnings.simplefilter("ignore")
+
+ import cppyy, random
+ cppyy.load_reflection_info('bench02Dict_reflex.so')
+
+ app = cppyy.gbl.Bench02RootApp()
+ TCanvas = cppyy.gbl.TCanvas
+ TFile = cppyy.gbl.TFile
+ TProfile = cppyy.gbl.TProfile
+ TNtuple = cppyy.gbl.TNtuple
+ TH1F = cppyy.gbl.TH1F
+ TH2F = cppyy.gbl.TH2F
+ TRandom = cppyy.gbl.TRandom
+except ImportError:
+ from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom
+ import random
+
+import math
+
+#gROOT = cppyy.gbl.gROOT
+#gBenchmark = cppyy.gbl.gBenchmark
+#gRandom = cppyy.gbl.gRandom
+#gSystem = cppyy.gbl.gSystem
+
+#gROOT.Reset()
+
+# Create a new canvas, and customize it.
+#c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 )
+#c1.SetFillColor( 42 )
+#c1.GetFrame().SetFillColor( 21 )
+#c1.GetFrame().SetBorderSize( 6 )
+#c1.GetFrame().SetBorderMode( -1 )
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+#hfile = gROOT.FindObject( 'hsimple.root' )
+#if hfile:
+# hfile.Close()
+#hfile = TFile( 'hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.Print()
+#hpxpy = TH2F( 'hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4 )
+#hprof = TProfile( 'hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20 )
+#ntuple = TNtuple( 'ntuple', 'Demo ntuple', 'px:py:pz:random:i' )
+
+# Set canvas/frame attributes.
+#hpx.SetFillColor( 48 )
+
+#gBenchmark.Start( 'hsimple' )
+
+# Initialize random number generator.
+#gRandom.SetSeed()
+#rannor, rndm = gRandom.Rannor, gRandom.Rndm
+
+random = TRandom()
+random.SetSeed(0)
+
+# Fill histograms randomly.
+#px, py = Double(), Double()
+kUPDATE = 1000
+for i in xrange(2500000):
+ # Generate random values.
+# px, py = random.gauss(0, 1), random.gauss(0, 1)
+ px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+# pt = (px*px + py*py)**0.5
+ pt = math.sqrt(px*px + py*py)
+# pt = (px*px + py*py)
+# random = rndm(1)
+
+ # Fill histograms.
+ hpx.Fill(pt)
+# hpxpyFill( px, py )
+# hprofFill( px, pz )
+# ntupleFill( px, py, pz, random, i )
+
+ # Update display every kUPDATE events.
+# if i and i%kUPDATE == 0:
+# if i == kUPDATE:
+# hpx.Draw()
+
+# c1.Modified()
+# c1.Update()
+
+# if gSystem.ProcessEvents(): # allow user interrupt
+# break
+
+#gBenchmark.Show( 'hsimple' )
+
+hpx.Print()
+
+# Save all objects in this file.
+#hpx.SetFillColor( 0 )
+#hfile.Write()
+#hfile.Close()
+#hpx.SetFillColor( 48 )
+#c1.Modified()
+#c1.Update()
+#c1.Draw()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -0,0 +1,450 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import jit
+
+import reflex_capi as backend
+#import cint_capi as backend
+
+identify = backend.identify
+ts_reflect = backend.ts_reflect
+ts_call = backend.ts_call
+ts_memory = backend.ts_memory
+ts_helper = backend.ts_helper
+
+_C_OPAQUE_PTR = rffi.LONG
+_C_OPAQUE_NULL = lltype.nullptr(rffi.LONGP.TO)# ALT: _C_OPAQUE_PTR.TO
+
+C_SCOPE = _C_OPAQUE_PTR
+C_NULL_SCOPE = rffi.cast(C_SCOPE, _C_OPAQUE_NULL)
+
+C_TYPE = C_SCOPE
+C_NULL_TYPE = C_NULL_SCOPE
+
+C_OBJECT = _C_OPAQUE_PTR
+C_NULL_OBJECT = rffi.cast(C_OBJECT, _C_OPAQUE_NULL)
+
+C_METHOD = _C_OPAQUE_PTR
+
+C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
+C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER)
+
+def direct_ptradd(ptr, offset):
+ offset = rffi.cast(rffi.SIZE_T, offset)
+ jit.promote(offset)
+ assert lltype.typeOf(ptr) == C_OBJECT
+ address = rffi.cast(rffi.CCHARP, ptr)
+ return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
+
+c_load_dictionary = backend.c_load_dictionary
+
+# name to opaque C++ scope representation ------------------------------------
+_c_resolve_name = rffi.llexternal(
+ "cppyy_resolve_name",
+ [rffi.CCHARP], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_resolve_name(name):
+ return charp2str_free(_c_resolve_name(name))
+c_get_scope_opaque = rffi.llexternal(
+ "cppyy_get_scope",
+ [rffi.CCHARP], C_SCOPE,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+c_get_template = rffi.llexternal(
+ "cppyy_get_template",
+ [rffi.CCHARP], C_TYPE,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+_c_actual_class = rffi.llexternal(
+ "cppyy_actual_class",
+ [C_TYPE, C_OBJECT], C_TYPE,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_actual_class(cppclass, cppobj):
+ return _c_actual_class(cppclass.handle, cppobj)
+
+# memory management ----------------------------------------------------------
+_c_allocate = rffi.llexternal(
+ "cppyy_allocate",
+ [C_TYPE], C_OBJECT,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+def c_allocate(cppclass):
+ return _c_allocate(cppclass.handle)
+_c_deallocate = rffi.llexternal(
+ "cppyy_deallocate",
+ [C_TYPE, C_OBJECT], lltype.Void,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+def c_deallocate(cppclass, cppobject):
+ _c_deallocate(cppclass.handle, cppobject)
+_c_destruct = rffi.llexternal(
+ "cppyy_destruct",
+ [C_TYPE, C_OBJECT], lltype.Void,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+def c_destruct(cppclass, cppobject):
+ _c_destruct(cppclass.handle, cppobject)
+
+# method/function dispatching ------------------------------------------------
+c_call_v = rffi.llexternal(
+ "cppyy_call_v",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_b = rffi.llexternal(
+ "cppyy_call_b",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_c = rffi.llexternal(
+ "cppyy_call_c",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CHAR,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_h = rffi.llexternal(
+ "cppyy_call_h",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.SHORT,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_i = rffi.llexternal(
+ "cppyy_call_i",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_l = rffi.llexternal(
+ "cppyy_call_l",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONG,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_ll = rffi.llexternal(
+ "cppyy_call_ll",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONGLONG,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_f = rffi.llexternal(
+ "cppyy_call_f",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_d = rffi.llexternal(
+ "cppyy_call_d",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+
+c_call_r = rffi.llexternal(
+ "cppyy_call_r",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.VOIDP,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_s = rffi.llexternal(
+ "cppyy_call_s",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CCHARP,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+
+c_constructor = rffi.llexternal(
+ "cppyy_constructor",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+
+_c_call_o = rffi.llexternal(
+ "cppyy_call_o",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP, C_TYPE], rffi.LONG,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+def c_call_o(method_index, cppobj, nargs, args, cppclass):
+ return _c_call_o(method_index, cppobj, nargs, args, cppclass.handle)
+
+_c_get_methptr_getter = rffi.llexternal(
+ "cppyy_get_methptr_getter",
+ [C_SCOPE, rffi.INT], C_METHPTRGETTER_PTR,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci,
+ elidable_function=True)
+def c_get_methptr_getter(cppscope, method_index):
+ return _c_get_methptr_getter(cppscope.handle, method_index)
+
+# handling of function argument buffer ---------------------------------------
+c_allocate_function_args = rffi.llexternal(
+ "cppyy_allocate_function_args",
+ [rffi.SIZE_T], rffi.VOIDP,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+c_deallocate_function_args = rffi.llexternal(
+ "cppyy_deallocate_function_args",
+ [rffi.VOIDP], lltype.Void,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+c_function_arg_sizeof = rffi.llexternal(
+ "cppyy_function_arg_sizeof",
+ [], rffi.SIZE_T,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci,
+ elidable_function=True)
+c_function_arg_typeoffset = rffi.llexternal(
+ "cppyy_function_arg_typeoffset",
+ [], rffi.SIZE_T,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci,
+ elidable_function=True)
+
+# scope reflection information -----------------------------------------------
+c_is_namespace = rffi.llexternal(
+ "cppyy_is_namespace",
+ [C_SCOPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+c_is_enum = rffi.llexternal(
+ "cppyy_is_enum",
+ [rffi.CCHARP], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+
+# type/class reflection information ------------------------------------------
+_c_final_name = rffi.llexternal(
+ "cppyy_final_name",
+ [C_TYPE], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_final_name(cpptype):
+ return charp2str_free(_c_final_name(cpptype))
+_c_scoped_final_name = rffi.llexternal(
+ "cppyy_scoped_final_name",
+ [C_TYPE], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_scoped_final_name(cpptype):
+ return charp2str_free(_c_scoped_final_name(cpptype))
+c_has_complex_hierarchy = rffi.llexternal(
+ "cppyy_has_complex_hierarchy",
+ [C_TYPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+_c_num_bases = rffi.llexternal(
+ "cppyy_num_bases",
+ [C_TYPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_num_bases(cppclass):
+ return _c_num_bases(cppclass.handle)
+_c_base_name = rffi.llexternal(
+ "cppyy_base_name",
+ [C_TYPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_base_name(cppclass, base_index):
+ return charp2str_free(_c_base_name(cppclass.handle, base_index))
+
+_c_is_subtype = rffi.llexternal(
+ "cppyy_is_subtype",
+ [C_TYPE, C_TYPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci,
+ elidable_function=True)
+ at jit.elidable_promote()
+def c_is_subtype(derived, base):
+ if derived == base:
+ return 1
+ return _c_is_subtype(derived.handle, base.handle)
+
+_c_base_offset = rffi.llexternal(
+ "cppyy_base_offset",
+ [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci,
+ elidable_function=True)
+ at jit.elidable_promote()
+def c_base_offset(derived, base, address, direction):
+ if derived == base:
+ return 0
+ return _c_base_offset(derived.handle, base.handle, address, direction)
+
+# method/function reflection information -------------------------------------
+_c_num_methods = rffi.llexternal(
+ "cppyy_num_methods",
+ [C_SCOPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_num_methods(cppscope):
+ return _c_num_methods(cppscope.handle)
+_c_method_name = rffi.llexternal(
+ "cppyy_method_name",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_name(cppscope, method_index):
+ return charp2str_free(_c_method_name(cppscope.handle, method_index))
+_c_method_result_type = rffi.llexternal(
+ "cppyy_method_result_type",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_result_type(cppscope, method_index):
+ return charp2str_free(_c_method_result_type(cppscope.handle, method_index))
+_c_method_num_args = rffi.llexternal(
+ "cppyy_method_num_args",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_num_args(cppscope, method_index):
+ return _c_method_num_args(cppscope.handle, method_index)
+_c_method_req_args = rffi.llexternal(
+ "cppyy_method_req_args",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_req_args(cppscope, method_index):
+ return _c_method_req_args(cppscope.handle, method_index)
+_c_method_arg_type = rffi.llexternal(
+ "cppyy_method_arg_type",
+ [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_arg_type(cppscope, method_index, arg_index):
+ return charp2str_free(_c_method_arg_type(cppscope.handle, method_index, arg_index))
+_c_method_arg_default = rffi.llexternal(
+ "cppyy_method_arg_default",
+ [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_arg_default(cppscope, method_index, arg_index):
+ return charp2str_free(_c_method_arg_default(cppscope.handle, method_index, arg_index))
+_c_method_signature = rffi.llexternal(
+ "cppyy_method_signature",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_signature(cppscope, method_index):
+ return charp2str_free(_c_method_signature(cppscope.handle, method_index))
+
+_c_method_index = rffi.llexternal(
+ "cppyy_method_index",
+ [C_SCOPE, rffi.CCHARP], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_index(cppscope, name):
+ return _c_method_index(cppscope.handle, name)
+
+_c_get_method = rffi.llexternal(
+ "cppyy_get_method",
+ [C_SCOPE, rffi.INT], C_METHOD,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_get_method(cppscope, method_index):
+ return _c_get_method(cppscope.handle, method_index)
+
+# method properties ----------------------------------------------------------
+_c_is_constructor = rffi.llexternal(
+ "cppyy_is_constructor",
+ [C_TYPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_constructor(cppclass, method_index):
+ return _c_is_constructor(cppclass.handle, method_index)
+_c_is_staticmethod = rffi.llexternal(
+ "cppyy_is_staticmethod",
+ [C_TYPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_staticmethod(cppclass, method_index):
+ return _c_is_staticmethod(cppclass.handle, method_index)
+
+# data member reflection information -----------------------------------------
+_c_num_datamembers = rffi.llexternal(
+ "cppyy_num_datamembers",
+ [C_SCOPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_num_datamembers(cppscope):
+ return _c_num_datamembers(cppscope.handle)
+_c_datamember_name = rffi.llexternal(
+ "cppyy_datamember_name",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_name(cppscope, datamember_index):
+ return charp2str_free(_c_datamember_name(cppscope.handle, datamember_index))
+_c_datamember_type = rffi.llexternal(
+ "cppyy_datamember_type",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_type(cppscope, datamember_index):
+ return charp2str_free(_c_datamember_type(cppscope.handle, datamember_index))
+_c_datamember_offset = rffi.llexternal(
+ "cppyy_datamember_offset",
+ [C_SCOPE, rffi.INT], rffi.SIZE_T,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_offset(cppscope, datamember_index):
+ return _c_datamember_offset(cppscope.handle, datamember_index)
+
+_c_datamember_index = rffi.llexternal(
+ "cppyy_datamember_index",
+ [C_SCOPE, rffi.CCHARP], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_index(cppscope, name):
+ return _c_datamember_index(cppscope.handle, name)
+
+# data member properties -----------------------------------------------------
+_c_is_publicdata = rffi.llexternal(
+ "cppyy_is_publicdata",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_publicdata(cppscope, datamember_index):
+ return _c_is_publicdata(cppscope.handle, datamember_index)
+_c_is_staticdata = rffi.llexternal(
+ "cppyy_is_staticdata",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_staticdata(cppscope, datamember_index):
+ return _c_is_staticdata(cppscope.handle, datamember_index)
+
+# misc helpers ---------------------------------------------------------------
+c_strtoll = rffi.llexternal(
+ "cppyy_strtoll",
+ [rffi.CCHARP], rffi.LONGLONG,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_strtoull = rffi.llexternal(
+ "cppyy_strtoull",
+ [rffi.CCHARP], rffi.ULONGLONG,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_free = rffi.llexternal(
+ "cppyy_free",
+ [rffi.VOIDP], lltype.Void,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+
+def charp2str_free(charp):
+ string = rffi.charp2str(charp)
+ voidp = rffi.cast(rffi.VOIDP, charp)
+ c_free(voidp)
+ return string
+
+c_charp2stdstring = rffi.llexternal(
+ "cppyy_charp2stdstring",
+ [rffi.CCHARP], C_OBJECT,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_stdstring2stdstring = rffi.llexternal(
+ "cppyy_stdstring2stdstring",
+ [C_OBJECT], C_OBJECT,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_assign2stdstring = rffi.llexternal(
+ "cppyy_assign2stdstring",
+ [C_OBJECT, rffi.CCHARP], lltype.Void,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_free_stdstring = rffi.llexternal(
+ "cppyy_free_stdstring",
+ [C_OBJECT], lltype.Void,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/cint_capi.py
@@ -0,0 +1,63 @@
+import py, os
+
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib import libffi, rdynload
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+ import commands
+ (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+ if stat != 0: # presumably Reflex-only
+ rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+ rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+ else:
+ rootincpath = [incdir]
+ rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+ rootincpath = []
+ rootlibpath = []
+
+def identify():
+ return 'CINT'
+
+ts_reflect = False
+ts_call = False
+ts_memory = 'auto'
+ts_helper = 'auto'
+
+# force loading in global mode of core libraries, rather than linking with
+# them as PyPy uses various version of dlopen in various places; note that
+# this isn't going to fly on Windows (note that locking them in objects and
+# calling dlclose in __del__ seems to come too late, so this'll do for now)
+with rffi.scoped_str2charp('libCint.so') as ll_libname:
+ _cintdll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+with rffi.scoped_str2charp('libCore.so') as ll_libname:
+ _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+
+eci = ExternalCompilationInfo(
+ separate_module_files=[srcpath.join("cintcwrapper.cxx")],
+ include_dirs=[incpath] + rootincpath,
+ includes=["cintcwrapper.h"],
+ library_dirs=rootlibpath,
+ link_extra=["-lCore", "-lCint"],
+ use_cpp_linker=True,
+)
+
+_c_load_dictionary = rffi.llexternal(
+ "cppyy_load_dictionary",
+ [rffi.CCHARP], rdynload.DLLHANDLE,
+ threadsafe=False,
+ compilation_info=eci)
+
+def c_load_dictionary(name):
+ result = _c_load_dictionary(name)
+ if not result:
+ err = rdynload.dlerror()
+ raise rdynload.DLOpenError(err)
+ return libffi.CDLL(name) # should return handle to already open file
diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/reflex_capi.py
@@ -0,0 +1,43 @@
+import py, os
+
+from pypy.rlib import libffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+ import commands
+ (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+ if stat != 0: # presumably Reflex-only
+ rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+ rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+ else:
+ rootincpath = [incdir]
+ rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+ rootincpath = []
+ rootlibpath = []
+
+def identify():
+ return 'Reflex'
+
+ts_reflect = False
+ts_call = 'auto'
+ts_memory = 'auto'
+ts_helper = 'auto'
+
+eci = ExternalCompilationInfo(
+ separate_module_files=[srcpath.join("reflexcwrapper.cxx")],
+ include_dirs=[incpath] + rootincpath,
+ includes=["reflexcwrapper.h"],
+ library_dirs=rootlibpath,
+ link_extra=["-lReflex"],
+ use_cpp_linker=True,
+)
+
+def c_load_dictionary(name):
+ return libffi.CDLL(name)
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/converter.py
@@ -0,0 +1,832 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib import jit, libffi, clibffi, rfloat
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+def get_rawobject(space, w_obj):
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+ if cppinstance:
+ rawobject = cppinstance.get_rawobject()
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ return rawobject
+ return capi.C_NULL_OBJECT
+
+def set_rawobject(space, w_obj, address):
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+ if cppinstance:
+ assert lltype.typeOf(cppinstance._rawobject) == capi.C_OBJECT
+ cppinstance._rawobject = rffi.cast(capi.C_OBJECT, address)
+
+def get_rawobject_nonnull(space, w_obj):
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+ if cppinstance:
+ cppinstance._nullcheck()
+ rawobject = cppinstance.get_rawobject()
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ return rawobject
+ return capi.C_NULL_OBJECT
+
+
+class TypeConverter(object):
+ _immutable_ = True
+ libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+ uses_local = False
+
+ name = ""
+
+ def __init__(self, space, extra):
+ pass
+
+ def _get_raw_address(self, space, w_obj, offset):
+ rawobject = get_rawobject_nonnull(space, w_obj)
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ if rawobject:
+ fieldptr = capi.direct_ptradd(rawobject, offset)
+ else:
+ fieldptr = rffi.cast(capi.C_OBJECT, offset)
+ return fieldptr
+
+ def _is_abstract(self, space):
+ raise OperationError(space.w_TypeError, space.wrap("no converter available"))
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ self._is_abstract(space)
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+ def default_argument_libffi(self, space, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ self._is_abstract(space)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ self._is_abstract(space)
+
+ def finalize_call(self, space, w_obj, call_local):
+ pass
+
+ def free_argument(self, space, arg, call_local):
+ pass
+
+
+class ArrayCache(object):
+ def __init__(self, space):
+ self.space = space
+ def __getattr__(self, name):
+ if name.startswith('array_'):
+ typecode = name[len('array_'):]
+ arr = self.space.interp_w(W_Array, unpack_simple_shape(self.space, self.space.wrap(typecode)))
+ setattr(self, name, arr)
+ return arr
+ raise AttributeError(name)
+
+ def _freeze_(self):
+ return True
+
+class ArrayTypeConverterMixin(object):
+ _mixin_ = True
+ _immutable_ = True
+
+ def __init__(self, space, array_size):
+ if array_size <= 0:
+ self.size = sys.maxint
+ else:
+ self.size = array_size
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ # read access, so no copy needed
+ address_value = self._get_raw_address(space, w_obj, offset)
+ address = rffi.cast(rffi.ULONG, address_value)
+ cache = space.fromcache(ArrayCache)
+ arr = getattr(cache, 'array_' + self.typecode)
+ return arr.fromaddress(space, address, self.size)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ # copy the full array (uses byte copy for now)
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ buf = space.buffer_w(w_value)
+ # TODO: report if too many items given?
+ for i in range(min(self.size*self.typesize, buf.getlength())):
+ address[i] = buf.getitem(i)
+
+
+class PtrTypeConverterMixin(object):
+ _mixin_ = True
+ _immutable_ = True
+
+ def __init__(self, space, array_size):
+ self.size = sys.maxint
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ # read access, so no copy needed
+ address_value = self._get_raw_address(space, w_obj, offset)
+ address = rffi.cast(rffi.ULONGP, address_value)
+ cache = space.fromcache(ArrayCache)
+ arr = getattr(cache, 'array_' + self.typecode)
+ return arr.fromaddress(space, address[0], self.size)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ # copy only the pointer value
+ rawobject = get_rawobject_nonnull(space, w_obj)
+ byteptr = rffi.cast(rffi.CCHARPP, capi.direct_ptradd(rawobject, offset))
+ buf = space.buffer_w(w_value)
+ try:
+ byteptr[0] = buf.get_raw_address()
+ except ValueError:
+ raise OperationError(space.w_TypeError,
+ space.wrap("raw buffer interface not supported"))
+
+
+class NumericTypeConverterMixin(object):
+ _mixin_ = True
+ _immutable_ = True
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def default_argument_libffi(self, space, argchain):
+ argchain.arg(self.default)
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(self.c_ptrtype, address)
+ return space.wrap(rffiptr[0])
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(self.c_ptrtype, address)
+ rffiptr[0] = self._unwrap_object(space, w_value)
+
+class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
+ _mixin_ = True
+ _immutable_ = True
+ uses_local = True
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ assert rffi.sizeof(self.c_type) <= 2*rffi.sizeof(rffi.VOIDP) # see interp_cppyy.py
+ obj = self._unwrap_object(space, w_obj)
+ typed_buf = rffi.cast(self.c_ptrtype, call_local)
+ typed_buf[0] = obj
+ argchain.arg(call_local)
+
+class IntTypeConverterMixin(NumericTypeConverterMixin):
+ _mixin_ = True
+ _immutable_ = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(self.c_ptrtype, address)
+ x[0] = self._unwrap_object(space, w_obj)
+
+class FloatTypeConverterMixin(NumericTypeConverterMixin):
+ _mixin_ = True
+ _immutable_ = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(self.c_ptrtype, address)
+ x[0] = self._unwrap_object(space, w_obj)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+
+class VoidConverter(TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.void
+
+ def __init__(self, space, name):
+ self.name = name
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ raise OperationError(space.w_TypeError,
+ space.wrap('no converter available for type "%s"' % self.name))
+
+
+class BoolConverter(TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def _unwrap_object(self, space, w_obj):
+ arg = space.c_int_w(w_obj)
+ if arg != False and arg != True:
+ raise OperationError(space.w_ValueError,
+ space.wrap("boolean value should be bool, or integer 1 or 0"))
+ return arg
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(rffi.LONGP, address)
+ x[0] = self._unwrap_object(space, w_obj)
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ if address[0] == '\x01':
+ return space.w_True
+ return space.w_False
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ arg = self._unwrap_object(space, w_value)
+ if arg:
+ address[0] = '\x01'
+ else:
+ address[0] = '\x00'
+
+class CharConverter(TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def _unwrap_object(self, space, w_value):
+ # allow int to pass to char and make sure that str is of length 1
+ if space.isinstance_w(w_value, space.w_int):
+ ival = space.c_int_w(w_value)
+ if ival < 0 or 256 <= ival:
+ raise OperationError(space.w_ValueError,
+ space.wrap("char arg not in range(256)"))
+
+ value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+ else:
+ value = space.str_w(w_value)
+
+ if len(value) != 1:
+ raise OperationError(space.w_ValueError,
+ space.wrap("char expected, got string of size %d" % len(value)))
+ return value[0] # turn it into a "char" to the annotator
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(rffi.CCHARP, address)
+ x[0] = self._unwrap_object(space, w_obj)
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ return space.wrap(address[0])
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ address[0] = self._unwrap_object(space, w_value)
+
+
+class ShortConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.sshort
+ c_type = rffi.SHORT
+ c_ptrtype = rffi.SHORTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(rffi.SHORT, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(rffi.SHORT, space.int_w(w_obj))
+
+class ConstShortRefConverter(ConstRefNumericTypeConverterMixin, ShortConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class UnsignedShortConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.sshort
+ c_type = rffi.USHORT
+ c_ptrtype = rffi.USHORTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(self.c_type, space.int_w(w_obj))
+
+class ConstUnsignedShortRefConverter(ConstRefNumericTypeConverterMixin, UnsignedShortConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class IntConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.sint
+ c_type = rffi.INT
+ c_ptrtype = rffi.INTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(self.c_type, space.c_int_w(w_obj))
+
+class ConstIntRefConverter(ConstRefNumericTypeConverterMixin, IntConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class UnsignedIntConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.uint
+ c_type = rffi.UINT
+ c_ptrtype = rffi.UINTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(self.c_type, space.uint_w(w_obj))
+
+class ConstUnsignedIntRefConverter(ConstRefNumericTypeConverterMixin, UnsignedIntConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class LongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.slong
+ c_type = rffi.LONG
+ c_ptrtype = rffi.LONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.int_w(w_obj)
+
+class ConstLongRefConverter(ConstRefNumericTypeConverterMixin, LongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'r'
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(self.c_ptrtype, address)
+ x[0] = self._unwrap_object(space, w_obj)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class LongLongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.slong
+ c_type = rffi.LONGLONG
+ c_ptrtype = rffi.LONGLONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.r_longlong_w(w_obj)
+
+class ConstLongLongRefConverter(ConstRefNumericTypeConverterMixin, LongLongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'r'
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(self.c_ptrtype, address)
+ x[0] = self._unwrap_object(space, w_obj)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class UnsignedLongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.ulong
+ c_type = rffi.ULONG
+ c_ptrtype = rffi.ULONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.uint_w(w_obj)
+
+class ConstUnsignedLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class UnsignedLongLongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.ulong
+ c_type = rffi.ULONGLONG
+ c_ptrtype = rffi.ULONGLONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.r_ulonglong_w(w_obj)
+
+class ConstUnsignedLongLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongLongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+
+class FloatConverter(FloatTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.float
+ c_type = rffi.FLOAT
+ c_ptrtype = rffi.FLOATP
+ typecode = 'f'
+
+ def __init__(self, space, default):
+ if default:
+ fval = float(rfloat.rstring_to_float(default))
+ else:
+ fval = float(0.)
+ self.default = r_singlefloat(fval)
+
+ def _unwrap_object(self, space, w_obj):
+ return r_singlefloat(space.float_w(w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(self.c_ptrtype, address)
+ return space.wrap(float(rffiptr[0]))
+
+class ConstFloatRefConverter(FloatConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'F'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+class DoubleConverter(FloatTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.double
+ c_type = rffi.DOUBLE
+ c_ptrtype = rffi.DOUBLEP
+ typecode = 'd'
+
+ def __init__(self, space, default):
+ if default:
+ self.default = rffi.cast(self.c_type, rfloat.rstring_to_float(default))
+ else:
+ self.default = rffi.cast(self.c_type, 0.)
+
+ def _unwrap_object(self, space, w_obj):
+ return space.float_w(w_obj)
+
+class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'D'
+
+
+class CStringConverter(TypeConverter):
+ _immutable_ = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(rffi.LONGP, address)
+ arg = space.str_w(w_obj)
+ x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'o'
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ charpptr = rffi.cast(rffi.CCHARPP, address)
+ return space.wrap(rffi.charp2str(charpptr[0]))
+
+ def free_argument(self, space, arg, call_local):
+ lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
+
+
+class VoidPtrConverter(TypeConverter):
+ _immutable_ = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'a'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(get_rawobject(space, w_obj))
+
+class VoidPtrPtrConverter(TypeConverter):
+ _immutable_ = True
+ uses_local = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ r = rffi.cast(rffi.VOIDPP, call_local)
+ r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = rffi.cast(rffi.VOIDP, call_local)
+ address = rffi.cast(capi.C_OBJECT, address)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'a'
+
+ def finalize_call(self, space, w_obj, call_local):
+ r = rffi.cast(rffi.VOIDPP, call_local)
+ set_rawobject(space, w_obj, r[0])
+
+class VoidPtrRefConverter(TypeConverter):
+ _immutable_ = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'r'
+
+
+class InstancePtrConverter(TypeConverter):
+ _immutable_ = True
+
+ def __init__(self, space, cppclass):
+ from pypy.module.cppyy.interp_cppyy import W_CPPClass
+ assert isinstance(cppclass, W_CPPClass)
+ self.cppclass = cppclass
+
+ def _unwrap_object(self, space, w_obj):
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ obj = space.interpclass_w(w_obj)
+ if isinstance(obj, W_CPPInstance):
+ if capi.c_is_subtype(obj.cppclass, self.cppclass):
+ rawobject = obj.get_rawobject()
+ offset = capi.c_base_offset(obj.cppclass, self.cppclass, rawobject, 1)
+ obj_address = capi.direct_ptradd(rawobject, offset)
+ return rffi.cast(capi.C_OBJECT, obj_address)
+ raise OperationError(space.w_TypeError,
+ space.wrap("cannot pass %s as %s" %
+ (space.type(w_obj).getname(space, "?"), self.cppclass.name)))
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+ address = rffi.cast(capi.C_OBJECT, address)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'o'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+ from pypy.module.cppyy import interp_cppyy
+ return interp_cppyy.wrap_cppobject_nocast(
+ space, w_pycppclass, self.cppclass, address, isref=True, python_owns=False)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
+ address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
+
+class InstanceConverter(InstancePtrConverter):
+ _immutable_ = True
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+ from pypy.module.cppyy import interp_cppyy
+ return interp_cppyy.wrap_cppobject_nocast(
+ space, w_pycppclass, self.cppclass, address, isref=False, python_owns=False)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ self._is_abstract(space)
+
+class InstancePtrPtrConverter(InstancePtrConverter):
+ _immutable_ = True
+ uses_local = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ r = rffi.cast(rffi.VOIDPP, call_local)
+ r[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = rffi.cast(rffi.VOIDP, call_local)
+ address = rffi.cast(capi.C_OBJECT, address)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'o'
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ self._is_abstract(space)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ self._is_abstract(space)
+
+ def finalize_call(self, space, w_obj, call_local):
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ obj = space.interpclass_w(w_obj)
+ assert isinstance(obj, W_CPPInstance)
+ r = rffi.cast(rffi.VOIDPP, call_local)
+ obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
+
+
+class StdStringConverter(InstanceConverter):
+ _immutable_ = True
+
+ def __init__(self, space, extra):
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, "std::string")
+ InstanceConverter.__init__(self, space, cppclass)
+
+ def _unwrap_object(self, space, w_obj):
+ try:
+ charp = rffi.str2charp(space.str_w(w_obj))
+ arg = capi.c_charp2stdstring(charp)
+ rffi.free_charp(charp)
+ return arg
+ except OperationError:
+ arg = InstanceConverter._unwrap_object(self, space, w_obj)
+ return capi.c_stdstring2stdstring(arg)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ try:
+ address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+ charp = rffi.str2charp(space.str_w(w_value))
+ capi.c_assign2stdstring(address, charp)
+ rffi.free_charp(charp)
+ return
+ except Exception:
+ pass
+ return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
+
+ def free_argument(self, space, arg, call_local):
+ capi.c_free_stdstring(rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+class StdStringRefConverter(InstancePtrConverter):
+ _immutable_ = True
+
+ def __init__(self, space, extra):
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, "std::string")
+ InstancePtrConverter.__init__(self, space, cppclass)
+
+
+class PyObjectConverter(TypeConverter):
+ _immutable_ = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ space.getbuiltinmodule("cpyext")
+ from pypy.module.cpyext.pyobject import make_ref
+ ref = make_ref(space, w_obj)
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = rffi.cast(rffi.VOIDP, ref);
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'a'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ space.getbuiltinmodule("cpyext")
+ from pypy.module.cpyext.pyobject import make_ref
+ ref = make_ref(space, w_obj)
+ argchain.arg(rffi.cast(rffi.VOIDP, ref))
+
+ def free_argument(self, space, arg, call_local):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ from pypy.module.cpyext.pyobject import Py_DecRef, PyObject
+ Py_DecRef(space, rffi.cast(PyObject, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+
+_converters = {} # builtin and custom types
+_a_converters = {} # array and ptr versions of above
+def get_converter(space, name, default):
+ # The matching of the name to a converter should follow:
+ # 1) full, exact match
+ # 1a) const-removed match
+ # 2) match of decorated, unqualified type
+ # 3) accept ref as pointer (for the stubs, const& can be
+ # by value, but that does not work for the ffi path)
+ # 4) generalized cases (covers basically all user classes)
+ # 5) void converter, which fails on use
+
+ name = capi.c_resolve_name(name)
+
+ # 1) full, exact match
+ try:
+ return _converters[name](space, default)
+ except KeyError:
+ pass
+
+ # 1a) const-removed match
+ try:
+ return _converters[helper.remove_const(name)](space, default)
+ except KeyError:
+ pass
+
+ # 2) match of decorated, unqualified type
+ compound = helper.compound(name)
+ clean_name = helper.clean_type(name)
+ try:
+ # array_index may be negative to indicate no size or no size found
+ array_size = helper.array_size(name)
+ return _a_converters[clean_name+compound](space, array_size)
+ except KeyError:
+ pass
+
+ # 3) TODO: accept ref as pointer
+
+ # 4) generalized cases (covers basically all user classes)
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, clean_name)
+ if cppclass:
+ # type check for the benefit of the annotator
+ from pypy.module.cppyy.interp_cppyy import W_CPPClass
+ cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+ if compound == "*" or compound == "&":
+ return InstancePtrConverter(space, cppclass)
+ elif compound == "**":
+ return InstancePtrPtrConverter(space, cppclass)
+ elif compound == "":
+ return InstanceConverter(space, cppclass)
+ elif capi.c_is_enum(clean_name):
+ return UnsignedIntConverter(space, default)
+
+ # 5) void converter, which fails on use
+ #
+ # return a void converter here, so that the class can be build even
+ # when some types are unknown; this overload will simply fail on use
+ return VoidConverter(space, name)
+
+
+_converters["bool"] = BoolConverter
+_converters["char"] = CharConverter
+_converters["unsigned char"] = CharConverter
+_converters["short int"] = ShortConverter
+_converters["const short int&"] = ConstShortRefConverter
+_converters["short"] = _converters["short int"]
+_converters["const short&"] = _converters["const short int&"]
+_converters["unsigned short int"] = UnsignedShortConverter
+_converters["const unsigned short int&"] = ConstUnsignedShortRefConverter
+_converters["unsigned short"] = _converters["unsigned short int"]
+_converters["const unsigned short&"] = _converters["const unsigned short int&"]
+_converters["int"] = IntConverter
+_converters["const int&"] = ConstIntRefConverter
+_converters["unsigned int"] = UnsignedIntConverter
+_converters["const unsigned int&"] = ConstUnsignedIntRefConverter
+_converters["long int"] = LongConverter
+_converters["const long int&"] = ConstLongRefConverter
+_converters["long"] = _converters["long int"]
+_converters["const long&"] = _converters["const long int&"]
+_converters["unsigned long int"] = UnsignedLongConverter
+_converters["const unsigned long int&"] = ConstUnsignedLongRefConverter
+_converters["unsigned long"] = _converters["unsigned long int"]
+_converters["const unsigned long&"] = _converters["const unsigned long int&"]
+_converters["long long int"] = LongLongConverter
+_converters["const long long int&"] = ConstLongLongRefConverter
+_converters["long long"] = _converters["long long int"]
+_converters["const long long&"] = _converters["const long long int&"]
+_converters["unsigned long long int"] = UnsignedLongLongConverter
+_converters["const unsigned long long int&"] = ConstUnsignedLongLongRefConverter
+_converters["unsigned long long"] = _converters["unsigned long long int"]
+_converters["const unsigned long long&"] = _converters["const unsigned long long int&"]
+_converters["float"] = FloatConverter
+_converters["const float&"] = ConstFloatRefConverter
+_converters["double"] = DoubleConverter
+_converters["const double&"] = ConstDoubleRefConverter
+_converters["const char*"] = CStringConverter
+_converters["char*"] = CStringConverter
+_converters["void*"] = VoidPtrConverter
+_converters["void**"] = VoidPtrPtrConverter
+_converters["void*&"] = VoidPtrRefConverter
+
+# special cases (note: CINT backend requires the simple name 'string')
+_converters["std::basic_string<char>"] = StdStringConverter
+_converters["string"] = _converters["std::basic_string<char>"]
+_converters["const std::basic_string<char>&"] = StdStringConverter # TODO: shouldn't copy
+_converters["const string&"] = _converters["const std::basic_string<char>&"]
+_converters["std::basic_string<char>&"] = StdStringRefConverter
+_converters["string&"] = _converters["std::basic_string<char>&"]
+
+_converters["PyObject*"] = PyObjectConverter
+_converters["_object*"] = _converters["PyObject*"]
+
+def _build_array_converters():
+ "NOT_RPYTHON"
+ array_info = (
+ ('h', rffi.sizeof(rffi.SHORT), ("short int", "short")),
+ ('H', rffi.sizeof(rffi.USHORT), ("unsigned short int", "unsigned short")),
+ ('i', rffi.sizeof(rffi.INT), ("int",)),
+ ('I', rffi.sizeof(rffi.UINT), ("unsigned int", "unsigned")),
+ ('l', rffi.sizeof(rffi.LONG), ("long int", "long")),
+ ('L', rffi.sizeof(rffi.ULONG), ("unsigned long int", "unsigned long")),
+ ('f', rffi.sizeof(rffi.FLOAT), ("float",)),
+ ('d', rffi.sizeof(rffi.DOUBLE), ("double",)),
+ )
+
+ for info in array_info:
+ class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ typecode = info[0]
+ typesize = info[1]
+ class PtrConverter(PtrTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ typecode = info[0]
+ typesize = info[1]
+ for name in info[2]:
+ _a_converters[name+'[]'] = ArrayConverter
+ _a_converters[name+'*'] = PtrConverter
+_build_array_converters()
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/executor.py
@@ -0,0 +1,466 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import libffi, clibffi
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+
+class FunctionExecutor(object):
+ _immutable_ = True
+ libffitype = NULL
+
+ def __init__(self, space, extra):
+ pass
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ raise OperationError(space.w_TypeError,
+ space.wrap('return type not available or supported'))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+
+class PtrTypeExecutor(FunctionExecutor):
+ _immutable_ = True
+ typecode = 'P'
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ address = rffi.cast(rffi.ULONG, lresult)
+ arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
+ return arr.fromaddress(space, address, sys.maxint)
+
+
+class VoidExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.void
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ capi.c_call_v(cppmethod, cppthis, num_args, args)
+ return space.w_None
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ libffifunc.call(argchain, lltype.Void)
+ return space.w_None
+
+
+class BoolExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_b(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.CHAR)
+ return space.wrap(bool(ord(result)))
+
+class CharExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_c(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.CHAR)
+ return space.wrap(result)
+
+class ShortExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.sshort
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_h(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.SHORT)
+ return space.wrap(result)
+
+class IntExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.sint
+
+ def _wrap_result(self, space, result):
+ return space.wrap(result)
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_i(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.INT)
+ return space.wrap(result)
+
+class UnsignedIntExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.uint
+
+ def _wrap_result(self, space, result):
+ return space.wrap(rffi.cast(rffi.UINT, result))
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.UINT)
+ return space.wrap(result)
+
+class LongExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.slong
+
+ def _wrap_result(self, space, result):
+ return space.wrap(result)
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.LONG)
+ return space.wrap(result)
+
+class UnsignedLongExecutor(LongExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.ulong
+
+ def _wrap_result(self, space, result):
+ return space.wrap(rffi.cast(rffi.ULONG, result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.ULONG)
+ return space.wrap(result)
+
+class LongLongExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.sint64
+
+ def _wrap_result(self, space, result):
+ return space.wrap(result)
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_ll(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.LONGLONG)
+ return space.wrap(result)
+
+class UnsignedLongLongExecutor(LongLongExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.uint64
+
+ def _wrap_result(self, space, result):
+ return space.wrap(rffi.cast(rffi.ULONGLONG, result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.ULONGLONG)
+ return space.wrap(result)
+
+class ConstIntRefExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+ def _wrap_result(self, space, result):
+ intptr = rffi.cast(rffi.INTP, result)
+ return space.wrap(intptr[0])
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.INTP)
+ return space.wrap(result[0])
+
+class ConstLongRefExecutor(ConstIntRefExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+ def _wrap_result(self, space, result):
+ longptr = rffi.cast(rffi.LONGP, result)
+ return space.wrap(longptr[0])
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.LONGP)
+ return space.wrap(result[0])
+
+class FloatExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.float
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_f(cppmethod, cppthis, num_args, args)
+ return space.wrap(float(result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.FLOAT)
+ return space.wrap(float(result))
+
+class DoubleExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.double
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_d(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.DOUBLE)
+ return space.wrap(result)
+
+
+class CStringExecutor(FunctionExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ ccpresult = rffi.cast(rffi.CCHARP, lresult)
+ result = rffi.charp2str(ccpresult) # TODO: make it a choice to free
+ return space.wrap(result)
+
+
+class ShortPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'h'
+
+class IntPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'i'
+
+class UnsignedIntPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'I'
+
+class LongPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'l'
+
+class UnsignedLongPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'L'
+
+class FloatPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'f'
+
+class DoublePtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'd'
+
+
+class ConstructorExecutor(VoidExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ capi.c_constructor(cppmethod, cppthis, num_args, args)
+ return space.w_None
+
+
+class InstancePtrExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+ def __init__(self, space, cppclass):
+ FunctionExecutor.__init__(self, space, cppclass)
+ self.cppclass = cppclass
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ from pypy.module.cppyy import interp_cppyy
+ long_result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ ptr_result = rffi.cast(capi.C_OBJECT, long_result)
+ return interp_cppyy.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy import interp_cppyy
+ ptr_result = rffi.cast(capi.C_OBJECT, libffifunc.call(argchain, rffi.VOIDP))
+ return interp_cppyy.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+class InstancePtrPtrExecutor(InstancePtrExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ from pypy.module.cppyy import interp_cppyy
+ voidp_result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+ ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
+ ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
+ return interp_cppyy.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+class InstanceExecutor(InstancePtrExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ from pypy.module.cppyy import interp_cppyy
+ long_result = capi.c_call_o(cppmethod, cppthis, num_args, args, self.cppclass)
+ ptr_result = rffi.cast(capi.C_OBJECT, long_result)
+ return interp_cppyy.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=True)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+
+class StdStringExecutor(InstancePtrExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ charp_result = capi.c_call_s(cppmethod, cppthis, num_args, args)
+ return space.wrap(capi.charp2str_free(charp_result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+
+class PyObjectExecutor(PtrTypeExecutor):
+ _immutable_ = True
+
+ def wrap_result(self, space, lresult):
+ space.getbuiltinmodule("cpyext")
+ from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, Py_DecRef
+ result = rffi.cast(PyObject, lresult)
+ w_obj = from_ref(space, result)
+ if result:
+ Py_DecRef(space, result)
+ return w_obj
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ return self.wrap_result(space, lresult)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ lresult = libffifunc.call(argchain, rffi.LONG)
+ return self.wrap_result(space, lresult)
+
+
+_executors = {}
+def get_executor(space, name):
+ # Matching of 'name' to an executor factory goes through up to four levels:
+ # 1) full, qualified match
+ # 2) drop '&': by-ref is pretty much the same as by-value, python-wise
+ # 3) types/classes, either by ref/ptr or by value
+ # 4) additional special cases
+ #
+ # If all fails, a default is used, which can be ignored at least until use.
+
+ name = capi.c_resolve_name(name)
+
+ # 1) full, qualified match
+ try:
+ return _executors[name](space, None)
+ except KeyError:
+ pass
+
+ compound = helper.compound(name)
+ clean_name = helper.clean_type(name)
+
+ # 1a) clean lookup
+ try:
+ return _executors[clean_name+compound](space, None)
+ except KeyError:
+ pass
+
+ # 2) drop '&': by-ref is pretty much the same as by-value, python-wise
+ if compound and compound[len(compound)-1] == "&":
+ # TODO: this does not actually work with Reflex (?)
+ try:
+ return _executors[clean_name](space, None)
+ except KeyError:
+ pass
+
+ # 3) types/classes, either by ref/ptr or by value
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, clean_name)
+ if cppclass:
+ # type check for the benefit of the annotator
+ from pypy.module.cppyy.interp_cppyy import W_CPPClass
+ cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+ if compound == "":
+ return InstanceExecutor(space, cppclass)
+ elif compound == "*" or compound == "&":
+ return InstancePtrExecutor(space, cppclass)
+ elif compound == "**" or compound == "*&":
+ return InstancePtrPtrExecutor(space, cppclass)
+ elif capi.c_is_enum(clean_name):
+ return UnsignedIntExecutor(space, None)
+
+ # 4) additional special cases
+ # ... none for now
+
+ # currently used until proper lazy instantiation available in interp_cppyy
+ return FunctionExecutor(space, None)
+
+
+_executors["void"] = VoidExecutor
+_executors["void*"] = PtrTypeExecutor
+_executors["bool"] = BoolExecutor
+_executors["char"] = CharExecutor
+_executors["char*"] = CStringExecutor
+_executors["unsigned char"] = CharExecutor
+_executors["short int"] = ShortExecutor
+_executors["short"] = _executors["short int"]
+_executors["short int*"] = ShortPtrExecutor
+_executors["short*"] = _executors["short int*"]
+_executors["unsigned short int"] = ShortExecutor
+_executors["unsigned short"] = _executors["unsigned short int"]
+_executors["unsigned short int*"] = ShortPtrExecutor
+_executors["unsigned short*"] = _executors["unsigned short int*"]
+_executors["int"] = IntExecutor
+_executors["int*"] = IntPtrExecutor
+_executors["const int&"] = ConstIntRefExecutor
+_executors["int&"] = ConstIntRefExecutor
+_executors["unsigned int"] = UnsignedIntExecutor
+_executors["unsigned int*"] = UnsignedIntPtrExecutor
+_executors["long int"] = LongExecutor
+_executors["long"] = _executors["long int"]
+_executors["long int*"] = LongPtrExecutor
+_executors["long*"] = _executors["long int*"]
+_executors["unsigned long int"] = UnsignedLongExecutor
+_executors["unsigned long"] = _executors["unsigned long int"]
+_executors["unsigned long int*"] = UnsignedLongPtrExecutor
+_executors["unsigned long*"] = _executors["unsigned long int*"]
+_executors["long long int"] = LongLongExecutor
+_executors["long long"] = _executors["long long int"]
+_executors["unsigned long long int"] = UnsignedLongLongExecutor
+_executors["unsigned long long"] = _executors["unsigned long long int"]
+_executors["float"] = FloatExecutor
+_executors["float*"] = FloatPtrExecutor
+_executors["double"] = DoubleExecutor
+_executors["double*"] = DoublePtrExecutor
+
+_executors["constructor"] = ConstructorExecutor
+
+# special cases (note: CINT backend requires the simple name 'string')
+_executors["std::basic_string<char>"] = StdStringExecutor
+_executors["string"] = _executors["std::basic_string<char>"]
+
+_executors["PyObject*"] = PyObjectExecutor
+_executors["_object*"] = _executors["PyObject*"]
diff --git a/pypy/module/cppyy/genreflex-methptrgetter.patch b/pypy/module/cppyy/genreflex-methptrgetter.patch
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/genreflex-methptrgetter.patch
@@ -0,0 +1,126 @@
+Index: cint/reflex/python/genreflex/gendict.py
+===================================================================
+--- cint/reflex/python/genreflex/gendict.py (revision 43705)
++++ cint/reflex/python/genreflex/gendict.py (working copy)
+@@ -52,6 +52,7 @@
+ self.typedefs_for_usr = []
+ self.gccxmlvers = gccxmlvers
+ self.split = opts.get('split', '')
++ self.with_methptrgetter = opts.get('with_methptrgetter', False)
+ # The next is to avoid a known problem with gccxml that it generates a
+ # references to id equal '_0' which is not defined anywhere
+ self.xref['_0'] = {'elem':'Unknown', 'attrs':{'id':'_0','name':''}, 'subelems':[]}
+@@ -1306,6 +1307,8 @@
+ bases = self.getBases( attrs['id'] )
+ if inner and attrs.has_key('demangled') and self.isUnnamedType(attrs['demangled']) :
+ cls = attrs['demangled']
++ if self.xref[attrs['id']]['elem'] == 'Union':
++ return 80*' '
+ clt = ''
+ else:
+ cls = self.genTypeName(attrs['id'],const=True,colon=True)
+@@ -1343,7 +1346,7 @@
+ # Inner class/struct/union/enum.
+ for m in memList :
+ member = self.xref[m]
+- if member['elem'] in ('Class','Struct','Union','Enumeration') \
++ if member['elem'] in ('Class','Struct','Enumeration') \
+ and member['attrs'].get('access') in ('private','protected') \
+ and not self.isUnnamedType(member['attrs'].get('demangled')):
+ cmem = self.genTypeName(member['attrs']['id'],const=True,colon=True)
+@@ -1981,8 +1984,15 @@
+ else : params = '0'
+ s = ' .AddFunctionMember(%s, Reflex::Literal("%s"), %s%s, 0, %s, %s)' % (self.genTypeID(id), name, type, id, params, mod)
+ s += self.genCommentProperty(attrs)
++ s += self.genMethPtrGetterProperty(type, attrs)
+ return s
+ #----------------------------------------------------------------------------------
++ def genMethPtrGetterProperty(self, type, attrs):
++ funcname = self.nameOfMethPtrGetter(type, attrs)
++ if funcname is None:
++ return ''
++ return '\n .AddProperty("MethPtrGetter", (void*)%s)' % funcname
++#----------------------------------------------------------------------------------
+ def genMCODef(self, type, name, attrs, args):
+ id = attrs['id']
+ cl = self.genTypeName(attrs['context'],colon=True)
+@@ -2049,8 +2059,44 @@
+ if returns == 'void' : body += ' }\n'
+ else : body += ' }\n'
+ body += '}\n'
+- return head + body;
++ methptrgetter = self.genMethPtrGetter(type, name, attrs, args)
++ return head + body + methptrgetter
+ #----------------------------------------------------------------------------------
++ def nameOfMethPtrGetter(self, type, attrs):
++ id = attrs['id']
++ if self.with_methptrgetter and 'static' not in attrs and type in ('operator', 'method'):
++ return '%s%s_methptrgetter' % (type, id)
++ return None
++#----------------------------------------------------------------------------------
++ def genMethPtrGetter(self, type, name, attrs, args):
++ funcname = self.nameOfMethPtrGetter(type, attrs)
++ if funcname is None:
++ return ''
++ id = attrs['id']
++ cl = self.genTypeName(attrs['context'],colon=True)
++ rettype = self.genTypeName(attrs['returns'],enum=True, const=True, colon=True)
++ arg_type_list = [self.genTypeName(arg['type'], colon=True) for arg in args]
++ constness = attrs.get('const', 0) and 'const' or ''
++ lines = []
++ a = lines.append
++ a('static void* %s(void* o)' % (funcname,))
++ a('{')
++ if name == 'EmitVA':
++ # TODO: this is for ROOT TQObject, the problem being that ellipses is not
++ # exposed in the arguments and that makes the generated code fail if the named
++ # method is overloaded as is with TQObject::EmitVA
++ a(' return (void*)0;')
++ else:
++ # declare a variable "meth" which is a member pointer
++ a(' %s (%s::*meth)(%s)%s;' % (rettype, cl, ', '.join(arg_type_list), constness))
++ a(' meth = (%s (%s::*)(%s)%s)&%s::%s;' % \
++ (rettype, cl, ', '.join(arg_type_list), constness, cl, name))
++ a(' %s* obj = (%s*)o;' % (cl, cl))
++ a(' return (void*)(obj->*meth);')
++ a('}')
++ return '\n'.join(lines)
++
++#----------------------------------------------------------------------------------
+ def getDefaultArgs(self, args):
+ n = 0
+ for a in args :
+Index: cint/reflex/python/genreflex/genreflex.py
+===================================================================
+--- cint/reflex/python/genreflex/genreflex.py (revision 43705)
++++ cint/reflex/python/genreflex/genreflex.py (working copy)
+@@ -108,6 +108,10 @@
+ Print extra debug information while processing. Keep intermediate files\n
+ --quiet
+ Do not print informational messages\n
++ --with-methptrgetter
++ Add the property MethPtrGetter to every FunctionMember. It contains a pointer to a
++ function which you can call to get the actual function pointer of the method that it's
++ stored in the vtable. It works only with gcc.
+ -h, --help
+ Print this help\n
+ """
+@@ -127,7 +131,8 @@
+ opts, args = getopt.getopt(options, 'ho:s:c:I:U:D:PC', \
+ ['help','debug=', 'output=','selection_file=','pool','dataonly','interpreteronly','deep','gccxmlpath=',
+ 'capabilities=','rootmap=','rootmap-lib=','comments','iocomments','no_membertypedefs',
+- 'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost='])
++ 'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost=',
++ 'with-methptrgetter'])
+ except getopt.GetoptError, e:
+ print "--->> genreflex: ERROR:",e
+ self.usage(2)
+@@ -186,6 +191,8 @@
+ self.rootmap = a
+ if o in ('--rootmap-lib',):
+ self.rootmaplib = a
++ if o in ('--with-methptrgetter',):
++ self.opts['with_methptrgetter'] = True
+ if o in ('-I', '-U', '-D', '-P', '-C') :
+ # escape quotes; we need to use " because of windows cmd
+ poseq = a.find('=')
diff --git a/pypy/module/cppyy/helper.py b/pypy/module/cppyy/helper.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/helper.py
@@ -0,0 +1,179 @@
+from pypy.rlib import rstring
+
+
+#- type name manipulations --------------------------------------------------
+def _remove_const(name):
+ return "".join(rstring.split(name, "const")) # poor man's replace
+
+def remove_const(name):
+ return _remove_const(name).strip(' ')
+
+def compound(name):
+ name = _remove_const(name)
+ if name.endswith("]"): # array type?
+ return "[]"
+ i = _find_qualifier_index(name)
+ return "".join(name[i:].split(" "))
+
+def array_size(name):
+ name = _remove_const(name)
+ if name.endswith("]"): # array type?
+ idx = name.rfind("[")
+ if 0 < idx:
+ end = len(name)-1 # len rather than -1 for rpython
+ if 0 < end and (idx+1) < end: # guarantee non-neg for rpython
+ return int(name[idx+1:end])
+ return -1
+
+def _find_qualifier_index(name):
+ i = len(name)
+ # search from the back; note len(name) > 0 (so rtyper can use uint)
+ for i in range(len(name) - 1, 0, -1):
+ c = name[i]
+ if c.isalnum() or c == ">" or c == "]":
+ break
+ return i + 1
+
+def clean_type(name):
+ # can't strip const early b/c name could be a template ...
+ i = _find_qualifier_index(name)
+ name = name[:i].strip(' ')
+
+ idx = -1
+ if name.endswith("]"): # array type?
+ idx = name.rfind("[")
+ if 0 < idx:
+ name = name[:idx]
+ elif name.endswith(">"): # template type?
+ idx = name.find("<")
+ if 0 < idx: # always true, but just so that the translater knows
+ n1 = _remove_const(name[:idx])
+ name = "".join([n1, name[idx:]])
+ else:
+ name = _remove_const(name)
+ name = name[:_find_qualifier_index(name)]
+ return name.strip(' ')
+
+
+#- operator mappings --------------------------------------------------------
+_operator_mappings = {}
+
+def map_operator_name(cppname, nargs, result_type):
+ from pypy.module.cppyy import capi
+
+ if cppname[0:8] == "operator":
+ op = cppname[8:].strip(' ')
+
+ # look for known mapping
+ try:
+ return _operator_mappings[op]
+ except KeyError:
+ pass
+
+ # return-type dependent mapping
+ if op == "[]":
+ if result_type.find("const") != 0:
+ cpd = compound(result_type)
+ if cpd and cpd[len(cpd)-1] == "&":
+ return "__setitem__"
+ return "__getitem__"
+
+ # a couple more cases that depend on whether args were given
+
+ if op == "*": # dereference (not python) vs. multiplication
+ return nargs and "__mul__" or "__deref__"
+
+ if op == "+": # unary positive vs. binary addition
+ return nargs and "__add__" or "__pos__"
+
+ if op == "-": # unary negative vs. binary subtraction
+ return nargs and "__sub__" or "__neg__"
+
+ if op == "++": # prefix v.s. postfix increment (not python)
+ return nargs and "__postinc__" or "__preinc__";
+
+ if op == "--": # prefix v.s. postfix decrement (not python)
+ return nargs and "__postdec__" or "__predec__";
+
+ # operator could have been a conversion using a typedef (this lookup
+ # is put at the end only as it is unlikely and may trigger unwanted
+ # errors in class loaders in the backend, because a typical operator
+ # name is illegal as a class name)
+ true_op = capi.c_resolve_name(op)
+
+ try:
+ return _operator_mappings[true_op]
+ except KeyError:
+ pass
+
+ # might get here, as not all operator methods handled (although some with
+ # no python equivalent, such as new, delete, etc., are simply retained)
+ # TODO: perhaps absorb or "pythonify" these operators?
+ return cppname
+
+# _operator_mappings["[]"] = "__setitem__" # depends on return type
+# _operator_mappings["+"] = "__add__" # depends on # of args (see __pos__)
+# _operator_mappings["-"] = "__sub__" # id. (eq. __neg__)
+# _operator_mappings["*"] = "__mul__" # double meaning in C++
+
+# _operator_mappings["[]"] = "__getitem__" # depends on return type
+_operator_mappings["()"] = "__call__"
+_operator_mappings["/"] = "__div__" # __truediv__ in p3
+_operator_mappings["%"] = "__mod__"
+_operator_mappings["**"] = "__pow__" # not C++
+_operator_mappings["<<"] = "__lshift__"
+_operator_mappings[">>"] = "__rshift__"
+_operator_mappings["&"] = "__and__"
+_operator_mappings["|"] = "__or__"
+_operator_mappings["^"] = "__xor__"
+_operator_mappings["~"] = "__inv__"
+_operator_mappings["!"] = "__nonzero__"
+_operator_mappings["+="] = "__iadd__"
+_operator_mappings["-="] = "__isub__"
+_operator_mappings["*="] = "__imul__"
+_operator_mappings["/="] = "__idiv__" # __itruediv__ in p3
+_operator_mappings["%="] = "__imod__"
+_operator_mappings["**="] = "__ipow__"
+_operator_mappings["<<="] = "__ilshift__"
+_operator_mappings[">>="] = "__irshift__"
+_operator_mappings["&="] = "__iand__"
+_operator_mappings["|="] = "__ior__"
+_operator_mappings["^="] = "__ixor__"
+_operator_mappings["=="] = "__eq__"
+_operator_mappings["!="] = "__ne__"
+_operator_mappings[">"] = "__gt__"
+_operator_mappings["<"] = "__lt__"
+_operator_mappings[">="] = "__ge__"
+_operator_mappings["<="] = "__le__"
+
+# the following type mappings are "exact"
+_operator_mappings["const char*"] = "__str__"
+_operator_mappings["int"] = "__int__"
+_operator_mappings["long"] = "__long__" # __int__ in p3
+_operator_mappings["double"] = "__float__"
+
+# the following type mappings are "okay"; the assumption is that they
+# are not mixed up with the ones above or between themselves (and if
+# they are, that it is done consistently)
+_operator_mappings["char*"] = "__str__"
+_operator_mappings["short"] = "__int__"
+_operator_mappings["unsigned short"] = "__int__"
+_operator_mappings["unsigned int"] = "__long__" # __int__ in p3
+_operator_mappings["unsigned long"] = "__long__" # id.
+_operator_mappings["long long"] = "__long__" # id.
+_operator_mappings["unsigned long long"] = "__long__" # id.
+_operator_mappings["float"] = "__float__"
+
+_operator_mappings["bool"] = "__nonzero__" # __bool__ in p3
+
+# the following are not python, but useful to expose
+_operator_mappings["->"] = "__follow__"
+_operator_mappings["="] = "__assign__"
+
+# a bundle of operators that have no equivalent and are left "as-is" for now:
+_operator_mappings["&&"] = "&&"
+_operator_mappings["||"] = "||"
+_operator_mappings["new"] = "new"
+_operator_mappings["delete"] = "delete"
+_operator_mappings["new[]"] = "new[]"
+_operator_mappings["delete[]"] = "delete[]"
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/capi.h
@@ -0,0 +1,111 @@
+#ifndef CPPYY_CAPI
+#define CPPYY_CAPI
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+ typedef long cppyy_scope_t;
+ typedef cppyy_scope_t cppyy_type_t;
+ typedef long cppyy_object_t;
+ typedef long cppyy_method_t;
+ typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t);
+
+ /* name to opaque C++ scope representation -------------------------------- */
+ char* cppyy_resolve_name(const char* cppitem_name);
+ cppyy_scope_t cppyy_get_scope(const char* scope_name);
+ cppyy_type_t cppyy_get_template(const char* template_name);
+ cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj);
+
+ /* memory management ------------------------------------------------------ */
+ cppyy_object_t cppyy_allocate(cppyy_type_t type);
+ void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self);
+ void cppyy_destruct(cppyy_type_t type, cppyy_object_t self);
+
+ /* method/function dispatching -------------------------------------------- */
+ void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+ void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+ void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type);
+
+ cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, int method_index);
+
+ /* handling of function argument buffer ----------------------------------- */
+ void* cppyy_allocate_function_args(size_t nargs);
+ void cppyy_deallocate_function_args(void* args);
+ size_t cppyy_function_arg_sizeof();
+ size_t cppyy_function_arg_typeoffset();
+
+ /* scope reflection information ------------------------------------------- */
+ int cppyy_is_namespace(cppyy_scope_t scope);
+ int cppyy_is_enum(const char* type_name);
+
+ /* class reflection information ------------------------------------------- */
+ char* cppyy_final_name(cppyy_type_t type);
+ char* cppyy_scoped_final_name(cppyy_type_t type);
+ int cppyy_has_complex_hierarchy(cppyy_type_t type);
+ int cppyy_num_bases(cppyy_type_t type);
+ char* cppyy_base_name(cppyy_type_t type, int base_index);
+ int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base);
+
+ /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */
+ size_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction);
+
+ /* method/function reflection information --------------------------------- */
+ int cppyy_num_methods(cppyy_scope_t scope);
+ char* cppyy_method_name(cppyy_scope_t scope, int method_index);
+ char* cppyy_method_result_type(cppyy_scope_t scope, int method_index);
+ int cppyy_method_num_args(cppyy_scope_t scope, int method_index);
+ int cppyy_method_req_args(cppyy_scope_t scope, int method_index);
+ char* cppyy_method_arg_type(cppyy_scope_t scope, int method_index, int arg_index);
+ char* cppyy_method_arg_default(cppyy_scope_t scope, int method_index, int arg_index);
+ char* cppyy_method_signature(cppyy_scope_t scope, int method_index);
+
+ int cppyy_method_index(cppyy_scope_t scope, const char* name);
+
+ cppyy_method_t cppyy_get_method(cppyy_scope_t scope, int method_index);
+
+ /* method properties ----------------------------------------------------- */
+ int cppyy_is_constructor(cppyy_type_t type, int method_index);
+ int cppyy_is_staticmethod(cppyy_type_t type, int method_index);
+
+ /* data member reflection information ------------------------------------ */
+ int cppyy_num_datamembers(cppyy_scope_t scope);
+ char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index);
+ char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index);
+ size_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index);
+
+ int cppyy_datamember_index(cppyy_scope_t scope, const char* name);
+
+ /* data member properties ------------------------------------------------ */
+ int cppyy_is_publicdata(cppyy_type_t type, int datamember_index);
+ int cppyy_is_staticdata(cppyy_type_t type, int datamember_index);
+
+ /* misc helpers ----------------------------------------------------------- */
+ void cppyy_free(void* ptr);
+ long long cppyy_strtoll(const char* str);
+ unsigned long long cppyy_strtuoll(const char* str);
+
+ cppyy_object_t cppyy_charp2stdstring(const char* str);
+ cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
+ void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str);
+ void cppyy_free_stdstring(cppyy_object_t ptr);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CAPI
diff --git a/pypy/module/cppyy/include/cintcwrapper.h b/pypy/module/cppyy/include/cintcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cintcwrapper.h
@@ -0,0 +1,16 @@
+#ifndef CPPYY_CINTCWRAPPER
+#define CPPYY_CINTCWRAPPER
+
+#include "capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+ void* cppyy_load_dictionary(const char* lib_name);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CINTCWRAPPER
diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cppyy.h
@@ -0,0 +1,64 @@
+#ifndef CPPYY_CPPYY
+#define CPPYY_CPPYY
+
+#ifdef __cplusplus
+struct CPPYY_G__DUMMY_FOR_CINT7 {
+#else
+typedef struct
+#endif
+ void* fTypeName;
+ unsigned int fModifiers;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__DUMMY_FOR_CINT7;
+#endif
+
+#ifdef __cplusplus
+struct CPPYY_G__p2p {
+#else
+#typedef struct
+#endif
+ long i;
+ int reftype;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__p2p;
+#endif
+
+
+#ifdef __cplusplus
+struct CPPYY_G__value {
+#else
+typedef struct {
+#endif
+ union {
+ double d;
+ long i; /* used to be int */
+ struct CPPYY_G__p2p reftype;
+ char ch;
+ short sh;
+ int in;
+ float fl;
+ unsigned char uch;
+ unsigned short ush;
+ unsigned int uin;
+ unsigned long ulo;
+ long long ll;
+ unsigned long long ull;
+ long double ld;
+ } obj;
+ long ref;
+ int type;
+ int tagnum;
+ int typenum;
+ char isconst;
+ struct CPPYY_G__DUMMY_FOR_CINT7 dummyForCint7;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__value;
+#endif
+
+#endif // CPPYY_CPPYY
diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/reflexcwrapper.h
@@ -0,0 +1,6 @@
+#ifndef CPPYY_REFLEXCWRAPPER
+#define CPPYY_REFLEXCWRAPPER
+
+#include "capi.h"
+
+#endif // ifndef CPPYY_REFLEXCWRAPPER
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -0,0 +1,807 @@
+import pypy.module.cppyy.capi as capi
+
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
+from pypy.interpreter.baseobjspace import Wrappable, W_Root
+
+from pypy.rpython.lltypesystem import rffi, lltype
+
+from pypy.rlib import libffi, rdynload, rweakref
+from pypy.rlib import jit, debug, objectmodel
+
+from pypy.module.cppyy import converter, executor, helper
+
+
+class FastCallNotPossible(Exception):
+ pass
+
+
+ at unwrap_spec(name=str)
+def load_dictionary(space, name):
+ try:
+ cdll = capi.c_load_dictionary(name)
+ except rdynload.DLOpenError, e:
+ raise OperationError(space.w_RuntimeError, space.wrap(str(e)))
+ return W_CPPLibrary(space, cdll)
+
+class State(object):
+ def __init__(self, space):
+ self.cppscope_cache = {
+ "void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+ self.cpptemplate_cache = {}
+ self.cppclass_registry = {}
+ self.w_clgen_callback = None
+
+ at unwrap_spec(name=str)
+def resolve_name(space, name):
+ return space.wrap(capi.c_resolve_name(name))
+
+ at unwrap_spec(name=str)
+def scope_byname(space, name):
+ true_name = capi.c_resolve_name(name)
+
+ state = space.fromcache(State)
+ try:
+ return state.cppscope_cache[true_name]
+ except KeyError:
+ pass
+
+ opaque_handle = capi.c_get_scope_opaque(true_name)
+ assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+ if opaque_handle:
+ final_name = capi.c_final_name(opaque_handle)
+ if capi.c_is_namespace(opaque_handle):
+ cppscope = W_CPPNamespace(space, final_name, opaque_handle)
+ elif capi.c_has_complex_hierarchy(opaque_handle):
+ cppscope = W_ComplexCPPClass(space, final_name, opaque_handle)
+ else:
+ cppscope = W_CPPClass(space, final_name, opaque_handle)
+ state.cppscope_cache[name] = cppscope
+
+ cppscope._find_methods()
+ cppscope._find_datamembers()
+ return cppscope
+
+ return None
+
+ at unwrap_spec(name=str)
+def template_byname(space, name):
+ state = space.fromcache(State)
+ try:
+ return state.cpptemplate_cache[name]
+ except KeyError:
+ pass
+
+ opaque_handle = capi.c_get_template(name)
+ assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+ if opaque_handle:
+ cpptemplate = W_CPPTemplateType(space, name, opaque_handle)
+ state.cpptemplate_cache[name] = cpptemplate
+ return cpptemplate
+
+ return None
+
+ at unwrap_spec(w_callback=W_Root)
+def set_class_generator(space, w_callback):
+ state = space.fromcache(State)
+ state.w_clgen_callback = w_callback
+
+ at unwrap_spec(w_pycppclass=W_Root)
+def register_class(space, w_pycppclass):
+ w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+ cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+ state = space.fromcache(State)
+ state.cppclass_registry[cppclass.handle] = w_pycppclass
+
+
+class W_CPPLibrary(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, cdll):
+ self.cdll = cdll
+ self.space = space
+
+W_CPPLibrary.typedef = TypeDef(
+ 'CPPLibrary',
+)
+W_CPPLibrary.typedef.acceptable_as_base_class = True
+
+
+class CPPMethod(object):
+ """ A concrete function after overloading has been resolved """
+ _immutable_ = True
+
+ def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
+ self.space = space
+ self.scope = containing_scope
+ self.index = method_index
+ self.cppmethod = capi.c_get_method(self.scope, method_index)
+ self.arg_defs = arg_defs
+ self.args_required = args_required
+ self.args_expected = len(arg_defs)
+
+ # Setup of the method dispatch's innards is done lazily, i.e. only when
+ # the method is actually used.
+ self.converters = None
+ self.executor = None
+ self._libffifunc = None
+
+ def _address_from_local_buffer(self, call_local, idx):
+ if not call_local:
+ return call_local
+ stride = 2*rffi.sizeof(rffi.VOIDP)
+ loc_idx = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), idx*stride)
+ return rffi.cast(rffi.VOIDP, loc_idx)
+
+ @jit.unroll_safe
+ def call(self, cppthis, args_w):
+ jit.promote(self)
+ assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+ # check number of given arguments against required (== total - defaults)
+ args_expected = len(self.arg_defs)
+ args_given = len(args_w)
+ if args_expected < args_given or args_given < self.args_required:
+ raise OperationError(self.space.w_TypeError,
+ self.space.wrap("wrong number of arguments"))
+
+ # initial setup of converters, executors, and libffi (if available)
+ if self.converters is None:
+ self._setup(cppthis)
+
+ # some calls, e.g. for ptr-ptr or reference need a local array to store data for
+ # the duration of the call
+ if [conv for conv in self.converters if conv.uses_local]:
+ call_local = lltype.malloc(rffi.VOIDP.TO, 2*len(args_w), flavor='raw')
+ else:
+ call_local = lltype.nullptr(rffi.VOIDP.TO)
+
+ try:
+ # attempt to call directly through ffi chain
+ if self._libffifunc:
+ try:
+ return self.do_fast_call(cppthis, args_w, call_local)
+ except FastCallNotPossible:
+ pass # can happen if converters or executor does not implement ffi
+
+ # ffi chain must have failed; using stub functions instead
+ args = self.prepare_arguments(args_w, call_local)
+ try:
+ return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args)
+ finally:
+ self.finalize_call(args, args_w, call_local)
+ finally:
+ if call_local:
+ lltype.free(call_local, flavor='raw')
+
+ @jit.unroll_safe
+ def do_fast_call(self, cppthis, args_w, call_local):
+ jit.promote(self)
+ argchain = libffi.ArgChain()
+ argchain.arg(cppthis)
+ i = len(self.arg_defs)
+ for i in range(len(args_w)):
+ conv = self.converters[i]
+ w_arg = args_w[i]
+ conv.convert_argument_libffi(self.space, w_arg, argchain, call_local)
+ for j in range(i+1, len(self.arg_defs)):
+ conv = self.converters[j]
+ conv.default_argument_libffi(self.space, argchain)
+ return self.executor.execute_libffi(self.space, self._libffifunc, argchain)
+
+ def _setup(self, cppthis):
+ self.converters = [converter.get_converter(self.space, arg_type, arg_dflt)
+ for arg_type, arg_dflt in self.arg_defs]
+ self.executor = executor.get_executor(self.space, capi.c_method_result_type(self.scope, self.index))
+
+ # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
+ # has been offset to the matching class. Hence, the libffi pointer is
+ # uniquely defined and needs to be setup only once.
+ methgetter = capi.c_get_methptr_getter(self.scope, self.index)
+ if methgetter and cppthis: # methods only for now
+ funcptr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
+ argtypes_libffi = [conv.libffitype for conv in self.converters if conv.libffitype]
+ if (len(argtypes_libffi) == len(self.converters) and
+ self.executor.libffitype):
+ # add c++ this to the arguments
+ libffifunc = libffi.Func("XXX",
+ [libffi.types.pointer] + argtypes_libffi,
+ self.executor.libffitype, funcptr)
+ self._libffifunc = libffifunc
+
+ @jit.unroll_safe
+ def prepare_arguments(self, args_w, call_local):
+ jit.promote(self)
+ args = capi.c_allocate_function_args(len(args_w))
+ stride = capi.c_function_arg_sizeof()
+ for i in range(len(args_w)):
+ conv = self.converters[i]
+ w_arg = args_w[i]
+ try:
+ arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
+ loc_i = self._address_from_local_buffer(call_local, i)
+ conv.convert_argument(self.space, w_arg, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+ except:
+ # fun :-(
+ for j in range(i):
+ conv = self.converters[j]
+ arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), j*stride)
+ loc_j = self._address_from_local_buffer(call_local, j)
+ conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
+ capi.c_deallocate_function_args(args)
+ raise
+ return args
+
+ @jit.unroll_safe
+ def finalize_call(self, args, args_w, call_local):
+ stride = capi.c_function_arg_sizeof()
+ for i in range(len(args_w)):
+ conv = self.converters[i]
+ arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
+ loc_i = self._address_from_local_buffer(call_local, i)
+ conv.finalize_call(self.space, args_w[i], loc_i)
+ conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+ capi.c_deallocate_function_args(args)
+
+ def signature(self):
+ return capi.c_method_signature(self.scope, self.index)
+
+ def __repr__(self):
+ return "CPPMethod: %s" % self.signature()
+
+ def _freeze_(self):
+ assert 0, "you should never have a pre-built instance of this!"
+
+
+class CPPFunction(CPPMethod):
+ _immutable_ = True
+
+ def __repr__(self):
+ return "CPPFunction: %s" % self.signature()
+
+
+class CPPConstructor(CPPMethod):
+ _immutable_ = True
+
+ def call(self, cppthis, args_w):
+ newthis = capi.c_allocate(self.scope)
+ assert lltype.typeOf(newthis) == capi.C_OBJECT
+ try:
+ CPPMethod.call(self, newthis, args_w)
+ except:
+ capi.c_deallocate(self.scope, newthis)
+ raise
+ return wrap_new_cppobject_nocast(
+ self.space, self.space.w_None, self.scope, newthis, isref=False, python_owns=True)
+
+ def __repr__(self):
+ return "CPPConstructor: %s" % self.signature()
+
+
+class W_CPPOverload(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, containing_scope, functions):
+ self.space = space
+ self.scope = containing_scope
+ self.functions = debug.make_sure_not_resized(functions)
+
+ def is_static(self):
+ return self.space.wrap(isinstance(self.functions[0], CPPFunction))
+
+ @jit.unroll_safe
+ @unwrap_spec(args_w='args_w')
+ def call(self, w_cppinstance, args_w):
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+ if cppinstance is not None:
+ cppinstance._nullcheck()
+ cppthis = cppinstance.get_cppthis(self.scope)
+ else:
+ cppthis = capi.C_NULL_OBJECT
+ assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+ # The following code tries out each of the functions in order. If
+ # argument conversion fails (or simply if the number of arguments do
+ # not match, that will lead to an exception, The JIT will snip out
+ # those (always) failing paths, but only if they have no side-effects.
+ # A second loop gathers all exceptions in the case all methods fail
+ # (the exception gathering would otherwise be a side-effect as far as
+ # the JIT is concerned).
+ #
+ # TODO: figure out what happens if a callback into from the C++ call
+ # raises a Python exception.
+ jit.promote(self)
+ for i in range(len(self.functions)):
+ cppyyfunc = self.functions[i]
+ try:
+ return cppyyfunc.call(cppthis, args_w)
+ except Exception:
+ pass
+
+ # only get here if all overloads failed ...
+ errmsg = 'none of the %d overloaded methods succeeded. Full details:' % len(self.functions)
+ if hasattr(self.space, "fake"): # FakeSpace fails errorstr (see below)
+ raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+ for i in range(len(self.functions)):
+ cppyyfunc = self.functions[i]
+ try:
+ return cppyyfunc.call(cppthis, args_w)
+ except OperationError, e:
+ errmsg += '\n '+cppyyfunc.signature()+' =>\n'
+ errmsg += ' '+e.errorstr(self.space)
+ except Exception, e:
+ errmsg += '\n '+cppyyfunc.signature()+' =>\n'
+ errmsg += ' Exception: '+str(e)
+
+ raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+
+ def signature(self):
+ sig = self.functions[0].signature()
+ for i in range(1, len(self.functions)):
+ sig += '\n'+self.functions[i].signature()
+ return self.space.wrap(sig)
+
+ def __repr__(self):
+ return "W_CPPOverload(%s)" % [f.signature() for f in self.functions]
+
+W_CPPOverload.typedef = TypeDef(
+ 'CPPOverload',
+ is_static = interp2app(W_CPPOverload.is_static),
+ call = interp2app(W_CPPOverload.call),
+ signature = interp2app(W_CPPOverload.signature),
+)
+
+
+class W_CPPDataMember(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, containing_scope, type_name, offset, is_static):
+ self.space = space
+ self.scope = containing_scope
+ self.converter = converter.get_converter(self.space, type_name, '')
+ self.offset = offset
+ self._is_static = is_static
+
+ def get_returntype(self):
+ return self.space.wrap(self.converter.name)
+
+ def is_static(self):
+ return self.space.newbool(self._is_static)
+
+ @jit.elidable_promote()
+ def _get_offset(self, cppinstance):
+ if cppinstance:
+ assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle)
+ offset = self.offset + capi.c_base_offset(
+ cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1)
+ else:
+ offset = self.offset
+ return offset
+
+ def get(self, w_cppinstance, w_pycppclass):
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+ offset = self._get_offset(cppinstance)
+ return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset)
+
+ def set(self, w_cppinstance, w_value):
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+ offset = self._get_offset(cppinstance)
+ self.converter.to_memory(self.space, w_cppinstance, w_value, offset)
+ return self.space.w_None
+
+W_CPPDataMember.typedef = TypeDef(
+ 'CPPDataMember',
+ is_static = interp2app(W_CPPDataMember.is_static),
+ get_returntype = interp2app(W_CPPDataMember.get_returntype),
+ get = interp2app(W_CPPDataMember.get),
+ set = interp2app(W_CPPDataMember.set),
+)
+W_CPPDataMember.typedef.acceptable_as_base_class = False
+
+
+class W_CPPScope(Wrappable):
+ _immutable_ = True
+ _immutable_fields_ = ["methods[*]", "datamembers[*]"]
+
+ kind = "scope"
+
+ def __init__(self, space, name, opaque_handle):
+ self.space = space
+ self.name = name
+ assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+ self.handle = opaque_handle
+ self.methods = {}
+ # Do not call "self._find_methods()" here, so that a distinction can
+ # be made between testing for existence (i.e. existence in the cache
+ # of classes) and actual use. Point being that a class can use itself,
+ # e.g. as a return type or an argument to one of its methods.
+
+ self.datamembers = {}
+ # Idem self.methods: a type could hold itself by pointer.
+
+ def _find_methods(self):
+ num_methods = capi.c_num_methods(self)
+ args_temp = {}
+ for i in range(num_methods):
+ method_name = capi.c_method_name(self, i)
+ pymethod_name = helper.map_operator_name(
+ method_name, capi.c_method_num_args(self, i),
+ capi.c_method_result_type(self, i))
+ if not pymethod_name in self.methods:
+ cppfunction = self._make_cppfunction(i)
+ overload = args_temp.setdefault(pymethod_name, [])
+ overload.append(cppfunction)
+ for name, functions in args_temp.iteritems():
+ overload = W_CPPOverload(self.space, self, functions[:])
+ self.methods[name] = overload
+
+ def get_method_names(self):
+ return self.space.newlist([self.space.wrap(name) for name in self.methods])
+
+ @jit.elidable_promote('0')
+ def get_overload(self, name):
+ try:
+ return self.methods[name]
+ except KeyError:
+ pass
+ new_method = self.find_overload(name)
+ self.methods[name] = new_method
+ return new_method
+
+ def get_datamember_names(self):
+ return self.space.newlist([self.space.wrap(name) for name in self.datamembers])
+
+ @jit.elidable_promote('0')
+ def get_datamember(self, name):
+ try:
+ return self.datamembers[name]
+ except KeyError:
+ pass
+ new_dm = self.find_datamember(name)
+ self.datamembers[name] = new_dm
+ return new_dm
+
+ @jit.elidable_promote('0')
+ def dispatch(self, name, signature):
+ overload = self.get_overload(name)
+ sig = '(%s)' % signature
+ for f in overload.functions:
+ if 0 < f.signature().find(sig):
+ return W_CPPOverload(self.space, self, [f])
+ raise OperationError(self.space.w_TypeError, self.space.wrap("no overload matches signature"))
+
+ def missing_attribute_error(self, name):
+ return OperationError(
+ self.space.w_AttributeError,
+ self.space.wrap("%s '%s' has no attribute %s" % (self.kind, self.name, name)))
+
+ def __eq__(self, other):
+ return self.handle == other.handle
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class W_CPPNamespace(W_CPPScope):
+ _immutable_ = True
+ kind = "namespace"
+
+ def _make_cppfunction(self, method_index):
+ num_args = capi.c_method_num_args(self, method_index)
+ args_required = capi.c_method_req_args(self, method_index)
+ arg_defs = []
+ for i in range(num_args):
+ arg_type = capi.c_method_arg_type(self, method_index, i)
+ arg_dflt = capi.c_method_arg_default(self, method_index, i)
+ arg_defs.append((arg_type, arg_dflt))
+ return CPPFunction(self.space, self, method_index, arg_defs, args_required)
+
+ def _make_datamember(self, dm_name, dm_idx):
+ type_name = capi.c_datamember_type(self, dm_idx)
+ offset = capi.c_datamember_offset(self, dm_idx)
+ datamember = W_CPPDataMember(self.space, self, type_name, offset, True)
+ self.datamembers[dm_name] = datamember
+ return datamember
+
+ def _find_datamembers(self):
+ num_datamembers = capi.c_num_datamembers(self)
+ for i in range(num_datamembers):
+ if not capi.c_is_publicdata(self, i):
+ continue
+ datamember_name = capi.c_datamember_name(self, i)
+ if not datamember_name in self.datamembers:
+ self._make_datamember(datamember_name, i)
+
+ def find_overload(self, meth_name):
+ # TODO: collect all overloads, not just the non-overloaded version
+ meth_idx = capi.c_method_index(self, meth_name)
+ if meth_idx < 0:
+ raise self.missing_attribute_error(meth_name)
+ cppfunction = self._make_cppfunction(meth_idx)
+ overload = W_CPPOverload(self.space, self, [cppfunction])
+ return overload
+
+ def find_datamember(self, dm_name):
+ dm_idx = capi.c_datamember_index(self, dm_name)
+ if dm_idx < 0:
+ raise self.missing_attribute_error(dm_name)
+ datamember = self._make_datamember(dm_name, dm_idx)
+ return datamember
+
+ def update(self):
+ self._find_methods()
+ self._find_datamembers()
+
+ def is_namespace(self):
+ return self.space.w_True
+
+W_CPPNamespace.typedef = TypeDef(
+ 'CPPNamespace',
+ update = interp2app(W_CPPNamespace.update),
+ get_method_names = interp2app(W_CPPNamespace.get_method_names),
+ get_overload = interp2app(W_CPPNamespace.get_overload, unwrap_spec=['self', str]),
+ get_datamember_names = interp2app(W_CPPNamespace.get_datamember_names),
+ get_datamember = interp2app(W_CPPNamespace.get_datamember, unwrap_spec=['self', str]),
+ is_namespace = interp2app(W_CPPNamespace.is_namespace),
+)
+W_CPPNamespace.typedef.acceptable_as_base_class = False
+
+
+class W_CPPClass(W_CPPScope):
+ _immutable_ = True
+ kind = "class"
+
+ def _make_cppfunction(self, method_index):
+ num_args = capi.c_method_num_args(self, method_index)
+ args_required = capi.c_method_req_args(self, method_index)
+ arg_defs = []
+ for i in range(num_args):
+ arg_type = capi.c_method_arg_type(self, method_index, i)
+ arg_dflt = capi.c_method_arg_default(self, method_index, i)
+ arg_defs.append((arg_type, arg_dflt))
+ if capi.c_is_constructor(self, method_index):
+ cls = CPPConstructor
+ elif capi.c_is_staticmethod(self, method_index):
+ cls = CPPFunction
+ else:
+ cls = CPPMethod
+ return cls(self.space, self, method_index, arg_defs, args_required)
+
+ def _find_datamembers(self):
+ num_datamembers = capi.c_num_datamembers(self)
+ for i in range(num_datamembers):
+ if not capi.c_is_publicdata(self, i):
+ continue
+ datamember_name = capi.c_datamember_name(self, i)
+ type_name = capi.c_datamember_type(self, i)
+ offset = capi.c_datamember_offset(self, i)
+ is_static = bool(capi.c_is_staticdata(self, i))
+ datamember = W_CPPDataMember(self.space, self, type_name, offset, is_static)
+ self.datamembers[datamember_name] = datamember
+
+ def find_overload(self, name):
+ raise self.missing_attribute_error(name)
+
+ def find_datamember(self, name):
+ raise self.missing_attribute_error(name)
+
+ def get_cppthis(self, cppinstance, calling_scope):
+ assert self == cppinstance.cppclass
+ return cppinstance.get_rawobject()
+
+ def is_namespace(self):
+ return self.space.w_False
+
+ def get_base_names(self):
+ bases = []
+ num_bases = capi.c_num_bases(self)
+ for i in range(num_bases):
+ base_name = capi.c_base_name(self, i)
+ bases.append(self.space.wrap(base_name))
+ return self.space.newlist(bases)
+
+W_CPPClass.typedef = TypeDef(
+ 'CPPClass',
+ type_name = interp_attrproperty('name', W_CPPClass),
+ get_base_names = interp2app(W_CPPClass.get_base_names),
+ get_method_names = interp2app(W_CPPClass.get_method_names),
+ get_overload = interp2app(W_CPPClass.get_overload, unwrap_spec=['self', str]),
+ get_datamember_names = interp2app(W_CPPClass.get_datamember_names),
+ get_datamember = interp2app(W_CPPClass.get_datamember, unwrap_spec=['self', str]),
+ is_namespace = interp2app(W_CPPClass.is_namespace),
+ dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_CPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_ComplexCPPClass(W_CPPClass):
+ _immutable_ = True
+
+ def get_cppthis(self, cppinstance, calling_scope):
+ assert self == cppinstance.cppclass
+ offset = capi.c_base_offset(self, calling_scope, cppinstance.get_rawobject(), 1)
+ return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
+
+W_ComplexCPPClass.typedef = TypeDef(
+ 'ComplexCPPClass',
+ type_name = interp_attrproperty('name', W_CPPClass),
+ get_base_names = interp2app(W_ComplexCPPClass.get_base_names),
+ get_method_names = interp2app(W_ComplexCPPClass.get_method_names),
+ get_overload = interp2app(W_ComplexCPPClass.get_overload, unwrap_spec=['self', str]),
+ get_datamember_names = interp2app(W_ComplexCPPClass.get_datamember_names),
+ get_datamember = interp2app(W_ComplexCPPClass.get_datamember, unwrap_spec=['self', str]),
+ is_namespace = interp2app(W_ComplexCPPClass.is_namespace),
+ dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_ComplexCPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_CPPTemplateType(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, name, opaque_handle):
+ self.space = space
+ self.name = name
+ assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+ self.handle = opaque_handle
+
+ @unwrap_spec(args_w='args_w')
+ def __call__(self, args_w):
+ # TODO: this is broken but unused (see pythonify.py)
+ fullname = "".join([self.name, '<', self.space.str_w(args_w[0]), '>'])
+ return scope_byname(self.space, fullname)
+
+W_CPPTemplateType.typedef = TypeDef(
+ 'CPPTemplateType',
+ __call__ = interp2app(W_CPPTemplateType.__call__),
+)
+W_CPPTemplateType.typedef.acceptable_as_base_class = False
+
+
+class W_CPPInstance(Wrappable):
+ _immutable_fields_ = ["cppclass", "isref"]
+
+ def __init__(self, space, cppclass, rawobject, isref, python_owns):
+ self.space = space
+ self.cppclass = cppclass
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ assert not isref or rawobject
+ self._rawobject = rawobject
+ assert not isref or not python_owns
+ self.isref = isref
+ self.python_owns = python_owns
+
+ def _nullcheck(self):
+ if not self._rawobject or (self.isref and not self.get_rawobject()):
+ raise OperationError(self.space.w_ReferenceError,
+ self.space.wrap("trying to access a NULL pointer"))
+
+ # allow user to determine ownership rules on a per object level
+ def fget_python_owns(self, space):
+ return space.wrap(self.python_owns)
+
+ @unwrap_spec(value=bool)
+ def fset_python_owns(self, space, value):
+ self.python_owns = space.is_true(value)
+
+ def get_cppthis(self, calling_scope):
+ return self.cppclass.get_cppthis(self, calling_scope)
+
+ def get_rawobject(self):
+ if not self.isref:
+ return self._rawobject
+ else:
+ ptrptr = rffi.cast(rffi.VOIDPP, self._rawobject)
+ return rffi.cast(capi.C_OBJECT, ptrptr[0])
+
+ def instance__eq__(self, w_other):
+ other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
+ iseq = self._rawobject == other._rawobject
+ return self.space.wrap(iseq)
+
+ def instance__ne__(self, w_other):
+ return self.space.not_(self.instance__eq__(w_other))
+
+ def instance__nonzero__(self):
+ if not self._rawobject or (self.isref and not self.get_rawobject()):
+ return self.space.w_False
+ return self.space.w_True
+
+ def destruct(self):
+ assert isinstance(self, W_CPPInstance)
+ if self._rawobject and not self.isref:
+ memory_regulator.unregister(self)
+ capi.c_destruct(self.cppclass, self._rawobject)
+ self._rawobject = capi.C_NULL_OBJECT
+
+ def __del__(self):
+ if self.python_owns:
+ self.enqueue_for_destruction(self.space, W_CPPInstance.destruct,
+ '__del__() method of ')
+
+W_CPPInstance.typedef = TypeDef(
+ 'CPPInstance',
+ cppclass = interp_attrproperty('cppclass', cls=W_CPPInstance),
+ _python_owns = GetSetProperty(W_CPPInstance.fget_python_owns, W_CPPInstance.fset_python_owns),
+ __eq__ = interp2app(W_CPPInstance.instance__eq__),
+ __ne__ = interp2app(W_CPPInstance.instance__ne__),
+ __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__),
+ destruct = interp2app(W_CPPInstance.destruct),
+)
+W_CPPInstance.typedef.acceptable_as_base_class = True
+
+
+class MemoryRegulator:
+ # TODO: (?) An object address is not unique if e.g. the class has a
+ # public data member of class type at the start of its definition and
+ # has no virtual functions. A _key class that hashes on address and
+ # type would be better, but my attempt failed in the rtyper, claiming
+ # a call on None ("None()") and needed a default ctor. (??)
+ # Note that for now, the associated test carries an m_padding to make
+ # a difference in the addresses.
+ def __init__(self):
+ self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+
+ def register(self, obj):
+ int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
+ self.objects.set(int_address, obj)
+
+ def unregister(self, obj):
+ int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
+ self.objects.set(int_address, None)
+
+ def retrieve(self, address):
+ int_address = int(rffi.cast(rffi.LONG, address))
+ return self.objects.get(int_address)
+
+memory_regulator = MemoryRegulator()
+
+
+def get_pythonized_cppclass(space, handle):
+ state = space.fromcache(State)
+ try:
+ w_pycppclass = state.cppclass_registry[handle]
+ except KeyError:
+ final_name = capi.c_scoped_final_name(handle)
+ w_pycppclass = space.call_function(state.w_clgen_callback, space.wrap(final_name))
+ return w_pycppclass
+
+def wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+ if space.is_w(w_pycppclass, space.w_None):
+ w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
+ w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass)
+ cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
+ W_CPPInstance.__init__(cppinstance, space, cppclass, rawobject, isref, python_owns)
+ memory_regulator.register(cppinstance)
+ return w_cppinstance
+
+def wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+ obj = memory_regulator.retrieve(rawobject)
+ if obj and obj.cppclass == cppclass:
+ return obj
+ return wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+def wrap_cppobject(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+ if rawobject:
+ actual = capi.c_actual_class(cppclass, rawobject)
+ if actual != cppclass.handle:
+ offset = capi._c_base_offset(actual, cppclass.handle, rawobject, -1)
+ rawobject = capi.direct_ptradd(rawobject, offset)
+ w_pycppclass = get_pythonized_cppclass(space, actual)
+ w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+ cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+ return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+ at unwrap_spec(cppinstance=W_CPPInstance)
+def addressof(space, cppinstance):
+ address = rffi.cast(rffi.LONG, cppinstance.get_rawobject())
+ return space.wrap(address)
+
+ at unwrap_spec(address=int, owns=bool)
+def bind_object(space, address, w_pycppclass, owns=False):
+ rawobject = rffi.cast(capi.C_OBJECT, address)
+ w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+ cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+ return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, False, owns)
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/pythonify.py
@@ -0,0 +1,388 @@
+# NOT_RPYTHON
+import cppyy
+import types
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class CppyyScopeMeta(type):
+ def __getattr__(self, name):
+ try:
+ return get_pycppitem(self, name) # will cache on self
+ except TypeError, t:
+ raise AttributeError("%s object has no attribute '%s'" % (self, name))
+
+class CppyyNamespaceMeta(CppyyScopeMeta):
+ pass
+
+class CppyyClass(CppyyScopeMeta):
+ pass
+
+class CPPObject(cppyy.CPPInstance):
+ __metaclass__ = CppyyClass
+
+
+class CppyyTemplateType(object):
+ def __init__(self, scope, name):
+ self._scope = scope
+ self._name = name
+
+ def _arg_to_str(self, arg):
+ if type(arg) != str:
+ arg = arg.__name__
+ return arg
+
+ def __call__(self, *args):
+ fullname = ''.join(
+ [self._name, '<', ','.join(map(self._arg_to_str, args))])
+ if fullname[-1] == '>':
+ fullname += ' >'
+ else:
+ fullname += '>'
+ return getattr(self._scope, fullname)
+
+
+def clgen_callback(name):
+ return get_pycppclass(name)
+cppyy._set_class_generator(clgen_callback)
+
+def make_static_function(func_name, cppol):
+ def function(*args):
+ return cppol.call(None, *args)
+ function.__name__ = func_name
+ function.__doc__ = cppol.signature()
+ return staticmethod(function)
+
+def make_method(meth_name, cppol):
+ def method(self, *args):
+ return cppol.call(self, *args)
+ method.__name__ = meth_name
+ method.__doc__ = cppol.signature()
+ return method
+
+
+def make_datamember(cppdm):
+ rettype = cppdm.get_returntype()
+ if not rettype: # return builtin type
+ cppclass = None
+ else: # return instance
+ try:
+ cppclass = get_pycppclass(rettype)
+ except AttributeError:
+ import warnings
+ warnings.warn("class %s unknown: no data member access" % rettype,
+ RuntimeWarning)
+ cppclass = None
+ if cppdm.is_static():
+ def binder(obj):
+ return cppdm.get(None, cppclass)
+ def setter(obj, value):
+ return cppdm.set(None, value)
+ else:
+ def binder(obj):
+ return cppdm.get(obj, cppclass)
+ setter = cppdm.set
+ return property(binder, setter)
+
+
+def make_cppnamespace(scope, namespace_name, cppns, build_in_full=True):
+ # build up a representation of a C++ namespace (namespaces are classes)
+
+ # create a meta class to allow properties (for static data write access)
+ metans = type(CppyyNamespaceMeta)(namespace_name+'_meta', (CppyyNamespaceMeta,), {})
+
+ if cppns:
+ d = {"_cpp_proxy" : cppns}
+ else:
+ d = dict()
+ def cpp_proxy_loader(cls):
+ cpp_proxy = cppyy._scope_byname(cls.__name__ != '::' and cls.__name__ or '')
+ del cls.__class__._cpp_proxy
+ cls._cpp_proxy = cpp_proxy
+ return cpp_proxy
+ metans._cpp_proxy = property(cpp_proxy_loader)
+
+ # create the python-side C++ namespace representation, cache in scope if given
+ pycppns = metans(namespace_name, (object,), d)
+ if scope:
+ setattr(scope, namespace_name, pycppns)
+
+ if build_in_full: # if False, rely on lazy build-up
+ # insert static methods into the "namespace" dictionary
+ for func_name in cppns.get_method_names():
+ cppol = cppns.get_overload(func_name)
+ pyfunc = make_static_function(func_name, cppol)
+ setattr(pycppns, func_name, pyfunc)
+
+ # add all data members to the dictionary of the class to be created, and
+ # static ones also to the meta class (needed for property setters)
+ for dm in cppns.get_datamember_names():
+ cppdm = cppns.get_datamember(dm)
+ pydm = make_datamember(cppdm)
+ setattr(pycppns, dm, pydm)
+ setattr(metans, dm, pydm)
+
+ return pycppns
+
+def _drop_cycles(bases):
+ # TODO: figure this out, as it seems to be a PyPy bug?!
+ for b1 in bases:
+ for b2 in bases:
+ if not (b1 is b2) and issubclass(b2, b1):
+ bases.remove(b1) # removes lateral class
+ break
+ return tuple(bases)
+
+def make_new(class_name, cppclass):
+ try:
+ constructor_overload = cppclass.get_overload(cppclass.type_name)
+ except AttributeError:
+ msg = "cannot instantiate abstract class '%s'" % class_name
+ def __new__(cls, *args):
+ raise TypeError(msg)
+ else:
+ def __new__(cls, *args):
+ return constructor_overload.call(None, *args)
+ return __new__
+
+def make_pycppclass(scope, class_name, final_class_name, cppclass):
+
+ # get a list of base classes for class creation
+ bases = [get_pycppclass(base) for base in cppclass.get_base_names()]
+ if not bases:
+ bases = [CPPObject,]
+ else:
+ # it's technically possible that the required class now has been built
+ # if one of the base classes uses it in e.g. a function interface
+ try:
+ return scope.__dict__[final_class_name]
+ except KeyError:
+ pass
+
+ # create a meta class to allow properties (for static data write access)
+ metabases = [type(base) for base in bases]
+ metacpp = type(CppyyClass)(class_name+'_meta', _drop_cycles(metabases), {})
+
+ # create the python-side C++ class representation
+ def dispatch(self, name, signature):
+ cppol = cppclass.dispatch(name, signature)
+ return types.MethodType(make_method(name, cppol), self, type(self))
+ d = {"_cpp_proxy" : cppclass,
+ "__dispatch__" : dispatch,
+ "__new__" : make_new(class_name, cppclass),
+ }
+ pycppclass = metacpp(class_name, _drop_cycles(bases), d)
+
+ # cache result early so that the class methods can find the class itself
+ setattr(scope, final_class_name, pycppclass)
+
+ # insert (static) methods into the class dictionary
+ for meth_name in cppclass.get_method_names():
+ cppol = cppclass.get_overload(meth_name)
+ if cppol.is_static():
+ setattr(pycppclass, meth_name, make_static_function(meth_name, cppol))
+ else:
+ setattr(pycppclass, meth_name, make_method(meth_name, cppol))
+
+ # add all data members to the dictionary of the class to be created, and
+ # static ones also to the meta class (needed for property setters)
+ for dm_name in cppclass.get_datamember_names():
+ cppdm = cppclass.get_datamember(dm_name)
+ pydm = make_datamember(cppdm)
+
+ setattr(pycppclass, dm_name, pydm)
+ if cppdm.is_static():
+ setattr(metacpp, dm_name, pydm)
+
+ _pythonize(pycppclass)
+ cppyy._register_class(pycppclass)
+ return pycppclass
+
+def make_cpptemplatetype(scope, template_name):
+ return CppyyTemplateType(scope, template_name)
+
+
+def get_pycppitem(scope, name):
+ # resolve typedefs/aliases
+ full_name = (scope == gbl) and name or (scope.__name__+'::'+name)
+ true_name = cppyy._resolve_name(full_name)
+ if true_name != full_name:
+ return get_pycppclass(true_name)
+
+ pycppitem = None
+
+ # classes
+ cppitem = cppyy._scope_byname(true_name)
+ if cppitem:
+ if cppitem.is_namespace():
+ pycppitem = make_cppnamespace(scope, true_name, cppitem)
+ setattr(scope, name, pycppitem)
+ else:
+ pycppitem = make_pycppclass(scope, true_name, name, cppitem)
+
+ # templates
+ if not cppitem:
+ cppitem = cppyy._template_byname(true_name)
+ if cppitem:
+ pycppitem = make_cpptemplatetype(scope, name)
+ setattr(scope, name, pycppitem)
+
+ # functions
+ if not cppitem:
+ try:
+ cppitem = scope._cpp_proxy.get_overload(name)
+ pycppitem = make_static_function(name, cppitem)
+ setattr(scope.__class__, name, pycppitem)
+ pycppitem = getattr(scope, name) # binds function as needed
+ except AttributeError:
+ pass
+
+ # data
+ if not cppitem:
+ try:
+ cppitem = scope._cpp_proxy.get_datamember(name)
+ pycppitem = make_datamember(cppitem)
+ setattr(scope, name, pycppitem)
+ if cppitem.is_static():
+ setattr(scope.__class__, name, pycppitem)
+ pycppitem = getattr(scope, name) # gets actual property value
+ except AttributeError:
+ pass
+
+ if not (pycppitem is None): # pycppitem could be a bound C++ NULL, so check explicitly for Py_None
+ return pycppitem
+
+ raise AttributeError("'%s' has no attribute '%s'" % (str(scope), name))
+
+
+def scope_splitter(name):
+ is_open_template, scope = 0, ""
+ for c in name:
+ if c == ':' and not is_open_template:
+ if scope:
+ yield scope
+ scope = ""
+ continue
+ elif c == '<':
+ is_open_template += 1
+ elif c == '>':
+ is_open_template -= 1
+ scope += c
+ yield scope
+
+def get_pycppclass(name):
+ # break up the name, to walk the scopes and get the class recursively
+ scope = gbl
+ for part in scope_splitter(name):
+ scope = getattr(scope, part)
+ return scope
+
+
+# pythonization by decoration (move to their own file?)
+def python_style_getitem(self, idx):
+ # python-style indexing: check for size and allow indexing from the back
+ sz = len(self)
+ if idx < 0: idx = sz + idx
+ if idx < sz:
+ return self._getitem__unchecked(idx)
+ raise IndexError('index out of range: %d requested for %s of size %d' % (idx, str(self), sz))
+
+def python_style_sliceable_getitem(self, slice_or_idx):
+ if type(slice_or_idx) == types.SliceType:
+ nseq = self.__class__()
+ nseq += [python_style_getitem(self, i) \
+ for i in range(*slice_or_idx.indices(len(self)))]
+ return nseq
+ else:
+ return python_style_getitem(self, slice_or_idx)
+
+_pythonizations = {}
+def _pythonize(pyclass):
+
+ try:
+ _pythonizations[pyclass.__name__](pyclass)
+ except KeyError:
+ pass
+
+ # map size -> __len__ (generally true for STL)
+ if hasattr(pyclass, 'size') and \
+ not hasattr(pyclass, '__len__') and callable(pyclass.size):
+ pyclass.__len__ = pyclass.size
+
+ # map push_back -> __iadd__ (generally true for STL)
+ if hasattr(pyclass, 'push_back') and not hasattr(pyclass, '__iadd__'):
+ def __iadd__(self, ll):
+ [self.push_back(x) for x in ll]
+ return self
+ pyclass.__iadd__ = __iadd__
+
+ # for STL iterators, whose comparison functions live globally for gcc
+ # TODO: this needs to be solved fundamentally for all classes
+ if 'iterator' in pyclass.__name__:
+ if hasattr(gbl, '__gnu_cxx'):
+ if hasattr(gbl.__gnu_cxx, '__eq__'):
+ setattr(pyclass, '__eq__', gbl.__gnu_cxx.__eq__)
+ if hasattr(gbl.__gnu_cxx, '__ne__'):
+ setattr(pyclass, '__ne__', gbl.__gnu_cxx.__ne__)
+
+ # map begin()/end() protocol to iter protocol
+ if hasattr(pyclass, 'begin') and hasattr(pyclass, 'end'):
+ # TODO: make gnu-independent
+ def __iter__(self):
+ iter = self.begin()
+ while gbl.__gnu_cxx.__ne__(iter, self.end()):
+ yield iter.__deref__()
+ iter.__preinc__()
+ iter.destruct()
+ raise StopIteration
+ pyclass.__iter__ = __iter__
+
+ # combine __getitem__ and __len__ to make a pythonized __getitem__
+ if hasattr(pyclass, '__getitem__') and hasattr(pyclass, '__len__'):
+ pyclass._getitem__unchecked = pyclass.__getitem__
+ if hasattr(pyclass, '__setitem__') and hasattr(pyclass, '__iadd__'):
+ pyclass.__getitem__ = python_style_sliceable_getitem
+ else:
+ pyclass.__getitem__ = python_style_getitem
+
+ # string comparisons (note: CINT backend requires the simple name 'string')
+ if pyclass.__name__ == 'std::basic_string<char>' or pyclass.__name__ == 'string':
+ def eq(self, other):
+ if type(other) == pyclass:
+ return self.c_str() == other.c_str()
+ else:
+ return self.c_str() == other
+ pyclass.__eq__ = eq
+ pyclass.__str__ = pyclass.c_str
+
+ # TODO: clean this up
+ # fixup lack of __getitem__ if no const return
+ if hasattr(pyclass, '__setitem__') and not hasattr(pyclass, '__getitem__'):
+ pyclass.__getitem__ = pyclass.__setitem__
+
+_loaded_dictionaries = {}
+def load_reflection_info(name):
+ try:
+ return _loaded_dictionaries[name]
+ except KeyError:
+ dct = cppyy._load_dictionary(name)
+ _loaded_dictionaries[name] = dct
+ return dct
+
+
+# user interface objects (note the two-step of not calling scope_byname here:
+# creation of global functions may cause the creation of classes in the global
+# namespace, so gbl must exist at that point to cache them)
+gbl = make_cppnamespace(None, "::", None, False) # global C++ namespace
+
+# mostly for the benefit of the CINT backend, which treats std as special
+gbl.std = make_cppnamespace(None, "std", None, False)
+
+# user-defined pythonizations interface
+_pythonizations = {}
+def add_pythonization(class_name, callback):
+ if not callable(callback):
+ raise TypeError("given '%s' object is not callable" % str(callback))
+ _pythonizations[class_name] = callback
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -0,0 +1,791 @@
+#include "cppyy.h"
+#include "cintcwrapper.h"
+
+#include "Api.h"
+
+#include "TROOT.h"
+#include "TError.h"
+#include "TList.h"
+#include "TSystem.h"
+
+#include "TApplication.h"
+#include "TInterpreter.h"
+#include "Getline.h"
+
+#include "TBaseClass.h"
+#include "TClass.h"
+#include "TClassEdit.h"
+#include "TClassRef.h"
+#include "TDataMember.h"
+#include "TFunction.h"
+#include "TGlobal.h"
+#include "TMethod.h"
+#include "TMethodArg.h"
+
+#include <assert.h>
+#include <string.h>
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+
+
+/* CINT internals (some won't work on Windows) -------------------------- */
+extern long G__store_struct_offset;
+extern "C" void* G__SetShlHandle(char*);
+extern "C" void G__LockCriticalSection();
+extern "C" void G__UnlockCriticalSection();
+
+#define G__SETMEMFUNCENV (long)0x7fff0035
+#define G__NOP (long)0x7fff00ff
+
+namespace {
+
+class Cppyy_OpenedTClass : public TDictionary {
+public:
+ mutable TObjArray* fStreamerInfo; //Array of TVirtualStreamerInfo
+ mutable std::map<std::string, TObjArray*>* fConversionStreamerInfo; //Array of the streamer infos derived from another class.
+ TList* fRealData; //linked list for persistent members including base classes
+ TList* fBase; //linked list for base classes
+ TList* fData; //linked list for data members
+ TList* fMethod; //linked list for methods
+ TList* fAllPubData; //all public data members (including from base classes)
+ TList* fAllPubMethod; //all public methods (including from base classes)
+};
+
+} // unnamed namespace
+
+
+/* data for life time management ------------------------------------------ */
+#define GLOBAL_HANDLE 1l
+
+typedef std::vector<TClassRef> ClassRefs_t;
+static ClassRefs_t g_classrefs(1);
+
+typedef std::map<std::string, ClassRefs_t::size_type> ClassRefIndices_t;
+static ClassRefIndices_t g_classref_indices;
+
+class ClassRefsInit {
+public:
+ ClassRefsInit() { // setup dummy holders for global and std namespaces
+ assert(g_classrefs.size() == (ClassRefs_t::size_type)GLOBAL_HANDLE);
+ g_classref_indices[""] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+ g_classrefs.push_back(TClassRef(""));
+ g_classref_indices["std"] = g_classrefs.size();
+ g_classrefs.push_back(TClassRef("")); // CINT ignores std
+ g_classref_indices["::std"] = g_classrefs.size();
+ g_classrefs.push_back(TClassRef("")); // id.
+ }
+};
+static ClassRefsInit _classrefs_init;
+
+typedef std::vector<TFunction> GlobalFuncs_t;
+static GlobalFuncs_t g_globalfuncs;
+
+typedef std::vector<TGlobal> GlobalVars_t;
+static GlobalVars_t g_globalvars;
+
+
+/* initialization of the ROOT system (debatable ... ) --------------------- */
+namespace {
+
+class TCppyyApplication : public TApplication {
+public:
+ TCppyyApplication(const char* acn, Int_t* argc, char** argv, Bool_t do_load = kTRUE)
+ : TApplication(acn, argc, argv) {
+
+ // Explicitly load libMathCore as CINT will not auto load it when using one
+ // of its globals. Once moved to Cling, which should work correctly, we
+ // can remove this statement.
+ gSystem->Load("libMathCore");
+
+ if (do_load) {
+ // follow TRint to minimize differences with CINT
+ ProcessLine("#include <iostream>", kTRUE);
+ ProcessLine("#include <_string>", kTRUE); // for std::string iostream.
+ ProcessLine("#include <DllImport.h>", kTRUE);// Defined R__EXTERN
+ ProcessLine("#include <vector>", kTRUE); // needed because they're used within the
+ ProcessLine("#include <pair>", kTRUE); // core ROOT dicts and CINT won't be able
+ // to properly unload these files
+ }
+
+ // save current interpreter context
+ gInterpreter->SaveContext();
+ gInterpreter->SaveGlobalsContext();
+
+ // prevent crashes on accessing history
+ Gl_histinit((char*)"-");
+
+ // prevent ROOT from exiting python
+ SetReturnFromRun(kTRUE);
+
+ // enable auto-loader
+ gInterpreter->EnableAutoLoading();
+ }
+};
+
+static const char* appname = "pypy-cppyy";
+
+class ApplicationStarter {
+public:
+ ApplicationStarter() {
+ if (!gApplication) {
+ int argc = 1;
+ char* argv[1]; argv[0] = (char*)appname;
+ gApplication = new TCppyyApplication(appname, &argc, argv, kTRUE);
+ }
+ }
+} _applicationStarter;
+
+} // unnamed namespace
+
+
+/* local helpers ---------------------------------------------------------- */
+static inline char* cppstring_to_cstring(const std::string& name) {
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
+
+static inline char* type_cppstring_to_cstring(const std::string& tname) {
+ G__TypeInfo ti(tname.c_str());
+ std::string true_name = ti.IsValid() ? ti.TrueName() : tname;
+ return cppstring_to_cstring(true_name);
+}
+
+static inline TClassRef type_from_handle(cppyy_type_t handle) {
+ return g_classrefs[(ClassRefs_t::size_type)handle];
+}
+
+static inline TFunction* type_get_method(cppyy_type_t handle, int method_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass())
+ return (TFunction*)cr->GetListOfMethods()->At(method_index);
+ return &g_globalfuncs[method_index];
+}
+
+
+static inline void fixup_args(G__param* libp) {
+ for (int i = 0; i < libp->paran; ++i) {
+ libp->para[i].ref = libp->para[i].obj.i;
+ const char partype = libp->para[i].type;
+ switch (partype) {
+ case 'p': {
+ libp->para[i].obj.i = (long)&libp->para[i].ref;
+ break;
+ }
+ case 'r': {
+ libp->para[i].ref = (long)&libp->para[i].obj.i;
+ break;
+ }
+ case 'f': {
+ assert(sizeof(float) <= sizeof(long));
+ long val = libp->para[i].obj.i;
+ void* pval = (void*)&val;
+ libp->para[i].obj.d = *(float*)pval;
+ break;
+ }
+ case 'F': {
+ libp->para[i].ref = (long)&libp->para[i].obj.i;
+ libp->para[i].type = 'f';
+ break;
+ }
+ case 'D': {
+ libp->para[i].ref = (long)&libp->para[i].obj.i;
+ libp->para[i].type = 'd';
+ break;
+
+ }
+ }
+ }
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+char* cppyy_resolve_name(const char* cppitem_name) {
+ if (strcmp(cppitem_name, "") == 0)
+ return cppstring_to_cstring(cppitem_name);
+ G__TypeInfo ti(cppitem_name);
+ if (ti.IsValid()) {
+ if (ti.Property() & G__BIT_ISENUM)
+ return cppstring_to_cstring("unsigned int");
+ return cppstring_to_cstring(ti.TrueName());
+ }
+ return cppstring_to_cstring(cppitem_name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+ ClassRefIndices_t::iterator icr = g_classref_indices.find(scope_name);
+ if (icr != g_classref_indices.end())
+ return (cppyy_type_t)icr->second;
+
+ // use TClass directly, to enable auto-loading
+ TClassRef cr(TClass::GetClass(scope_name, kTRUE, kTRUE));
+ if (!cr.GetClass())
+ return (cppyy_type_t)NULL;
+
+ if (!cr->GetClassInfo())
+ return (cppyy_type_t)NULL;
+
+ if (!G__TypeInfo(scope_name).IsValid())
+ return (cppyy_type_t)NULL;
+
+ ClassRefs_t::size_type sz = g_classrefs.size();
+ g_classref_indices[scope_name] = sz;
+ g_classrefs.push_back(TClassRef(scope_name));
+ return (cppyy_scope_t)sz;
+}
+
+cppyy_type_t cppyy_get_template(const char* template_name) {
+ ClassRefIndices_t::iterator icr = g_classref_indices.find(template_name);
+ if (icr != g_classref_indices.end())
+ return (cppyy_type_t)icr->second;
+
+ if (!G__defined_templateclass((char*)template_name))
+ return (cppyy_type_t)NULL;
+
+ // the following yields a dummy TClassRef, but its name can be queried
+ ClassRefs_t::size_type sz = g_classrefs.size();
+ g_classref_indices[template_name] = sz;
+ g_classrefs.push_back(TClassRef(template_name));
+ return (cppyy_type_t)sz;
+}
+
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+ TClassRef cr = type_from_handle(klass);
+ TClass* clActual = cr->GetActualClass( (void*)obj );
+ if (clActual && clActual != cr.GetClass()) {
+ // TODO: lookup through name should not be needed
+ return (cppyy_type_t)cppyy_get_scope(clActual->GetName());
+ }
+ return klass;
+}
+
+/* memory management ------------------------------------------------------ */
+cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ return (cppyy_object_t)malloc(cr->Size());
+}
+
+void cppyy_deallocate(cppyy_type_t /*handle*/, cppyy_object_t instance) {
+ free((void*)instance);
+}
+
+void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+ TClassRef cr = type_from_handle(handle);
+ cr->Destructor((void*)self, true);
+}
+
+
+/* method/function dispatching -------------------------------------------- */
+static inline G__value cppyy_call_T(cppyy_method_t method,
+ cppyy_object_t self, int nargs, void* args) {
+
+ G__InterfaceMethod meth = (G__InterfaceMethod)method;
+ G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
+ assert(libp->paran == nargs);
+ fixup_args(libp);
+
+ G__value result;
+ G__setnull(&result);
+
+ G__LockCriticalSection(); // CINT-level lock, is recursive
+ G__settemplevel(1);
+
+ long index = (long)&method;
+ G__CurrentCall(G__SETMEMFUNCENV, 0, &index);
+
+ // TODO: access to store_struct_offset won't work on Windows
+ long store_struct_offset = G__store_struct_offset;
+ if (self)
+ G__store_struct_offset = (long)self;
+
+ meth(&result, 0, libp, 0);
+ if (self)
+ G__store_struct_offset = store_struct_offset;
+
+ if (G__get_return(0) > G__RETURN_NORMAL)
+ G__security_recover(0); // 0 ensures silence
+
+ G__CurrentCall(G__NOP, 0, 0);
+ G__settemplevel(-1);
+ G__UnlockCriticalSection();
+
+ return result;
+}
+
+void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ cppyy_call_T(method, self, nargs, args);
+}
+
+int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (bool)G__int(result);
+}
+
+char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (char)G__int(result);
+}
+
+short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (short)G__int(result);
+}
+
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (int)G__int(result);
+}
+
+long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__int(result);
+}
+
+long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__Longlong(result);
+}
+
+double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__double(result);
+}
+
+double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__double(result);
+}
+
+void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (void*)result.ref;
+}
+
+char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ G__pop_tempobject_nodel();
+ if (result.ref && *(long*)result.ref) {
+ char* charp = cppstring_to_cstring(*(std::string*)result.ref);
+ delete (std::string*)result.ref;
+ return charp;
+ }
+ return cppstring_to_cstring("");
+}
+
+void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__setgvp((long)self);
+ cppyy_call_T(method, self, nargs, args);
+ G__setgvp((long)G__PVOID);
+}
+
+cppyy_object_t cppyy_call_o(cppyy_type_t method, cppyy_object_t self, int nargs, void* args,
+ cppyy_type_t /*result_type*/ ) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ G__pop_tempobject_nodel();
+ return G__int(result);
+}
+
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /*handle*/, int /*method_index*/) {
+ return (cppyy_methptrgetter_t)NULL;
+}
+
+
+/* handling of function argument buffer ----------------------------------- */
+void* cppyy_allocate_function_args(size_t nargs) {
+ assert(sizeof(CPPYY_G__value) == sizeof(G__value));
+ G__param* libp = (G__param*)malloc(
+ offsetof(G__param, para) + nargs*sizeof(CPPYY_G__value));
+ libp->paran = (int)nargs;
+ for (size_t i = 0; i < nargs; ++i)
+ libp->para[i].type = 'l';
+ return (void*)libp->para;
+}
+
+void cppyy_deallocate_function_args(void* args) {
+ free((char*)args - offsetof(G__param, para));
+}
+
+size_t cppyy_function_arg_sizeof() {
+ return sizeof(CPPYY_G__value);
+}
+
+size_t cppyy_function_arg_typeoffset() {
+ return offsetof(CPPYY_G__value, type);
+}
+
+
+/* scope reflection information ------------------------------------------- */
+int cppyy_is_namespace(cppyy_scope_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetClassInfo())
+ return cr->Property() & G__BIT_ISNAMESPACE;
+ if (strcmp(cr.GetClassName(), "") == 0)
+ return true;
+ return false;
+}
+
+int cppyy_is_enum(const char* type_name) {
+ G__TypeInfo ti(type_name);
+ return (ti.Property() & G__BIT_ISENUM);
+}
+
+
+/* type/class reflection information -------------------------------------- */
+char* cppyy_final_name(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetClassInfo()) {
+ std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
+ std::string::size_type pos = true_name.rfind("::");
+ if (pos != std::string::npos)
+ return cppstring_to_cstring(true_name.substr(pos+2, std::string::npos));
+ return cppstring_to_cstring(true_name);
+ }
+ return cppstring_to_cstring(cr.GetClassName());
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetClassInfo()) {
+ std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
+ return cppstring_to_cstring(true_name);
+ }
+ return cppstring_to_cstring(cr.GetClassName());
+}
+
+int cppyy_has_complex_hierarchy(cppyy_type_t handle) {
+// as long as no fast path is supported for CINT, calculating offsets (which
+// are cached by the JIT) is not going to hurt
+ return 1;
+}
+
+int cppyy_num_bases(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetListOfBases() != 0)
+ return cr->GetListOfBases()->GetSize();
+ return 0;
+}
+
+char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+ TClassRef cr = type_from_handle(handle);
+ TBaseClass* b = (TBaseClass*)cr->GetListOfBases()->At(base_index);
+ return type_cppstring_to_cstring(b->GetName());
+}
+
+int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+ TClassRef derived_type = type_from_handle(derived_handle);
+ TClassRef base_type = type_from_handle(base_handle);
+ return derived_type->GetBaseClass(base_type) != 0;
+}
+
+size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+ cppyy_object_t address, int /* direction */) {
+ // WARNING: CINT can not handle actual dynamic casts!
+ TClassRef derived_type = type_from_handle(derived_handle);
+ TClassRef base_type = type_from_handle(base_handle);
+
+ long offset = 0;
+
+ if (derived_type && base_type) {
+ G__ClassInfo* base_ci = (G__ClassInfo*)base_type->GetClassInfo();
+ G__ClassInfo* derived_ci = (G__ClassInfo*)derived_type->GetClassInfo();
+
+ if (base_ci && derived_ci) {
+#ifdef WIN32
+ // Windows cannot cast-to-derived for virtual inheritance
+ // with CINT's (or Reflex's) interfaces.
+ long baseprop = derived_ci->IsBase(*base_ci);
+ if (!baseprop || (baseprop & G__BIT_ISVIRTUALBASE))
+ offset = derived_type->GetBaseClassOffset(base_type);
+ else
+#endif
+ offset = G__isanybase(base_ci->Tagnum(), derived_ci->Tagnum(), (long)address);
+ } else {
+ offset = derived_type->GetBaseClassOffset(base_type);
+ }
+ }
+
+ return (size_t) offset; // may be negative (will roll over)
+}
+
+
+/* method/function reflection information --------------------------------- */
+int cppyy_num_methods(cppyy_scope_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetListOfMethods())
+ return cr->GetListOfMethods()->GetSize();
+ else if (strcmp(cr.GetClassName(), "") == 0) {
+ // NOTE: the updated list of global funcs grows with 5 "G__ateval"'s just
+ // because it is being updated => infinite loop! Apply offset to correct ...
+ static int ateval_offset = 0;
+ TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
+ ateval_offset += 5;
+ if (g_globalfuncs.size() <= (GlobalFuncs_t::size_type)funcs->GetSize() - ateval_offset) {
+ g_globalfuncs.clear();
+ g_globalfuncs.reserve(funcs->GetSize());
+
+ TIter ifunc(funcs);
+
+ TFunction* func = 0;
+ while ((func = (TFunction*)ifunc.Next())) {
+ if (strcmp(func->GetName(), "G__ateval") == 0)
+ ateval_offset += 1;
+ else
+ g_globalfuncs.push_back(*func);
+ }
+ }
+ return (int)g_globalfuncs.size();
+ }
+ return 0;
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return cppstring_to_cstring(f->GetName());
+}
+
+char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
+ TFunction* f = 0;
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ if (cppyy_is_constructor(handle, method_index))
+ return cppstring_to_cstring("constructor");
+ f = (TFunction*)cr->GetListOfMethods()->At(method_index);
+ } else
+ f = &g_globalfuncs[method_index];
+ return type_cppstring_to_cstring(f->GetReturnTypeName());
+}
+
+int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return f->GetNargs();
+}
+
+int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return f->GetNargs() - f->GetNargsOpt();
+}
+
+char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(arg_index);
+ return type_cppstring_to_cstring(arg->GetFullTypeName());
+}
+
+char* cppyy_method_arg_default(cppyy_scope_t, int, int) {
+ /* unused: libffi does not work with CINT back-end */
+ return cppstring_to_cstring("");
+}
+
+char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ TClassRef cr = type_from_handle(handle);
+ std::ostringstream sig;
+ if (cr.GetClass() && cr->GetClassInfo()
+ && strcmp(f->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) != 0)
+ sig << f->GetReturnTypeName() << " ";
+ sig << cr.GetClassName() << "::" << f->GetName() << "(";
+ int nArgs = f->GetNargs();
+ for (int iarg = 0; iarg < nArgs; ++iarg) {
+ sig << ((TMethodArg*)f->GetListOfMethodArgs()->At(iarg))->GetFullTypeName();
+ if (iarg != nArgs-1)
+ sig << ", ";
+ }
+ sig << ")" << std::ends;
+ return cppstring_to_cstring(sig.str());
+}
+
+int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ gInterpreter->UpdateListOfMethods(cr.GetClass());
+ int imeth = 0;
+ TFunction* func;
+ TIter next(cr->GetListOfMethods());
+ while ((func = (TFunction*)next())) {
+ if (strcmp(name, func->GetName()) == 0) {
+ if (func->Property() & G__BIT_ISPUBLIC)
+ return imeth;
+ return -1;
+ }
+ ++imeth;
+ }
+ }
+ TFunction* func = gROOT->GetGlobalFunction(name, NULL, kTRUE);
+ if (!func)
+ return -1;
+ int idx = g_globalfuncs.size();
+ g_globalfuncs.push_back(*func);
+ return idx;
+}
+
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return (cppyy_method_t)f->InterfaceMethod();
+}
+
+
+/* method properties ----------------------------------------------------- */
+int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+ TClassRef cr = type_from_handle(handle);
+ TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+ return strcmp(m->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) == 0;
+}
+
+int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+ TClassRef cr = type_from_handle(handle);
+ TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+ return m->Property() & G__BIT_ISSTATIC;
+}
+
+
+/* data member reflection information ------------------------------------- */
+int cppyy_num_datamembers(cppyy_scope_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetListOfDataMembers())
+ return cr->GetListOfDataMembers()->GetSize();
+ else if (strcmp(cr.GetClassName(), "") == 0) {
+ TCollection* vars = gROOT->GetListOfGlobals(kTRUE);
+ if (g_globalvars.size() != (GlobalVars_t::size_type)vars->GetSize()) {
+ g_globalvars.clear();
+ g_globalvars.reserve(vars->GetSize());
+
+ TIter ivar(vars);
+
+ TGlobal* var = 0;
+ while ((var = (TGlobal*)ivar.Next()))
+ g_globalvars.push_back(*var);
+
+ }
+ return (int)g_globalvars.size();
+ }
+ return 0;
+}
+
+char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return cppstring_to_cstring(m->GetName());
+ }
+ TGlobal& gbl = g_globalvars[datamember_index];
+ return cppstring_to_cstring(gbl.GetName());
+}
+
+char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ std::string fullType = m->GetFullTypeName();
+ if ((int)m->GetArrayDim() > 1 || (!m->IsBasic() && m->IsaPointer()))
+ fullType.append("*");
+ else if ((int)m->GetArrayDim() == 1) {
+ std::ostringstream s;
+ s << '[' << m->GetMaxIndex(0) << ']' << std::ends;
+ fullType.append(s.str());
+ }
+ return cppstring_to_cstring(fullType);
+ }
+ TGlobal& gbl = g_globalvars[datamember_index];
+ return cppstring_to_cstring(gbl.GetFullTypeName());
+}
+
+size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return (size_t)m->GetOffsetCint();
+ }
+ TGlobal& gbl = g_globalvars[datamember_index];
+ return (size_t)gbl.GetAddress();
+}
+
+int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ // called from updates; add a hard reset as the code itself caches in
+ // Class (TODO: by-pass ROOT/meta)
+ Cppyy_OpenedTClass* c = (Cppyy_OpenedTClass*)cr.GetClass();
+ if (c->fData) {
+ c->fData->Delete();
+ delete c->fData; c->fData = 0;
+ delete c->fAllPubData; c->fAllPubData = 0;
+ }
+ // the following appears dumb, but TClass::GetDataMember() does a linear
+ // search itself, so there is no gain
+ int idm = 0;
+ TDataMember* dm;
+ TIter next(cr->GetListOfDataMembers());
+ while ((dm = (TDataMember*)next())) {
+ if (strcmp(name, dm->GetName()) == 0) {
+ if (dm->Property() & G__BIT_ISPUBLIC)
+ return idm;
+ return -1;
+ }
+ ++idm;
+ }
+ }
+ TGlobal* gbl = (TGlobal*)gROOT->GetListOfGlobals(kTRUE)->FindObject(name);
+ if (!gbl)
+ return -1;
+ int idx = g_globalvars.size();
+ g_globalvars.push_back(*gbl);
+ return idx;
+}
+
+
+/* data member properties ------------------------------------------------ */
+int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return m->Property() & G__BIT_ISPUBLIC;
+ }
+ return 1; // global data is always public
+}
+
+int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return m->Property() & G__BIT_ISSTATIC;
+ }
+ return 1; // global data is always static
+}
+
+
+/* misc helpers ----------------------------------------------------------- */
+long long cppyy_strtoll(const char* str) {
+ return strtoll(str, NULL, 0);
+}
+
+extern "C" unsigned long long cppyy_strtoull(const char* str) {
+ return strtoull(str, NULL, 0);
+}
+
+void cppyy_free(void* ptr) {
+ free(ptr);
+}
+
+cppyy_object_t cppyy_charp2stdstring(const char* str) {
+ return (cppyy_object_t)new std::string(str);
+}
+
+cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) {
+ return (cppyy_object_t)new std::string(*(std::string*)ptr);
+}
+
+void cppyy_free_stdstring(cppyy_object_t ptr) {
+ delete (std::string*)ptr;
+}
+
+void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
+ *((std::string*)ptr) = str;
+}
+
+void* cppyy_load_dictionary(const char* lib_name) {
+ if (0 <= gSystem->Load(lib_name))
+ return (void*)1;
+ return (void*)0;
+}
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -0,0 +1,541 @@
+#include "cppyy.h"
+#include "reflexcwrapper.h"
+
+#include "Reflex/Kernel.h"
+#include "Reflex/Type.h"
+#include "Reflex/Base.h"
+#include "Reflex/Member.h"
+#include "Reflex/Object.h"
+#include "Reflex/Builder/TypeBuilder.h"
+#include "Reflex/PropertyList.h"
+#include "Reflex/TypeTemplate.h"
+
+#define private public
+#include "Reflex/PluginService.h"
+#undef private
+
+#include <string>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <assert.h>
+#include <stdlib.h>
+
+
+/* local helpers ---------------------------------------------------------- */
+static inline char* cppstring_to_cstring(const std::string& name) {
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
+
+static inline Reflex::Scope scope_from_handle(cppyy_type_t handle) {
+ return Reflex::Scope((Reflex::ScopeName*)handle);
+}
+
+static inline Reflex::Type type_from_handle(cppyy_type_t handle) {
+ return Reflex::Scope((Reflex::ScopeName*)handle);
+}
+
+static inline std::vector<void*> build_args(int nargs, void* args) {
+ std::vector<void*> arguments;
+ arguments.reserve(nargs);
+ for (int i = 0; i < nargs; ++i) {
+ char tc = ((CPPYY_G__value*)args)[i].type;
+ if (tc != 'a' && tc != 'o')
+ arguments.push_back(&((CPPYY_G__value*)args)[i]);
+ else
+ arguments.push_back((void*)(*(long*)&((CPPYY_G__value*)args)[i]));
+ }
+ return arguments;
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+char* cppyy_resolve_name(const char* cppitem_name) {
+ Reflex::Scope s = Reflex::Scope::ByName(cppitem_name);
+ if (s.IsEnum())
+ return cppstring_to_cstring("unsigned int");
+ const std::string& name = s.Name(Reflex::SCOPED|Reflex::QUALIFIED|Reflex::FINAL);
+ if (name.empty())
+ return cppstring_to_cstring(cppitem_name);
+ return cppstring_to_cstring(name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+ Reflex::Scope s = Reflex::Scope::ByName(scope_name);
+ if (!s) Reflex::PluginService::Instance().LoadFactoryLib(scope_name);
+ s = Reflex::Scope::ByName(scope_name);
+ if (s.IsEnum()) // pretend to be builtin by returning 0
+ return (cppyy_type_t)0;
+ return (cppyy_type_t)s.Id();
+}
+
+cppyy_type_t cppyy_get_template(const char* template_name) {
+ Reflex::TypeTemplate tt = Reflex::TypeTemplate::ByName(template_name);
+ return (cppyy_type_t)tt.Id();
+}
+
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+ Reflex::Type t = type_from_handle(klass);
+ Reflex::Type tActual = t.DynamicType(Reflex::Object(t, (void*)obj));
+ if (tActual && tActual != t) {
+ // TODO: lookup through name should not be needed (but tActual.Id()
+ // does not return a singular Id for the system :( )
+ return (cppyy_type_t)cppyy_get_scope(tActual.Name().c_str());
+ }
+ return klass;
+}
+
+
+/* memory management ------------------------------------------------------ */
+cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+ Reflex::Type t = type_from_handle(handle);
+ return (cppyy_object_t)t.Allocate();
+}
+
+void cppyy_deallocate(cppyy_type_t handle, cppyy_object_t instance) {
+ Reflex::Type t = type_from_handle(handle);
+ t.Deallocate((void*)instance);
+}
+
+void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+ Reflex::Type t = type_from_handle(handle);
+ t.Destruct((void*)self, true);
+}
+
+
+/* method/function dispatching -------------------------------------------- */
+void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(NULL /* return address */, (void*)self, arguments, NULL /* stub context */);
+}
+
+template<typename T>
+static inline T cppyy_call_T(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ T result;
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(&result, (void*)self, arguments, NULL /* stub context */);
+ return result;
+}
+
+int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return (int)cppyy_call_T<bool>(method, self, nargs, args);
+}
+
+char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<char>(method, self, nargs, args);
+}
+
+short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<short>(method, self, nargs, args);
+}
+
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<int>(method, self, nargs, args);
+}
+
+long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<long>(method, self, nargs, args);
+}
+
+long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<long long>(method, self, nargs, args);
+}
+
+double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<float>(method, self, nargs, args);
+}
+
+double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<double>(method, self, nargs, args);
+}
+
+void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return (void*)cppyy_call_T<long>(method, self, nargs, args);
+}
+
+char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::string result("");
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(&result, (void*)self, arguments, NULL /* stub context */);
+ return cppstring_to_cstring(result);
+}
+
+void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ cppyy_call_v(method, self, nargs, args);
+}
+
+cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args,
+ cppyy_type_t result_type) {
+ void* result = (void*)cppyy_allocate(result_type);
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(result, (void*)self, arguments, NULL /* stub context */);
+ return (cppyy_object_t)result;
+}
+
+static cppyy_methptrgetter_t get_methptr_getter(Reflex::Member m) {
+ Reflex::PropertyList plist = m.Properties();
+ if (plist.HasProperty("MethPtrGetter")) {
+ Reflex::Any& value = plist.PropertyValue("MethPtrGetter");
+ return (cppyy_methptrgetter_t)Reflex::any_cast<void*>(value);
+ }
+ return 0;
+}
+
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return get_methptr_getter(m);
+}
+
+
+/* handling of function argument buffer ----------------------------------- */
+void* cppyy_allocate_function_args(size_t nargs) {
+ CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value));
+ for (size_t i = 0; i < nargs; ++i)
+ args[i].type = 'l';
+ return (void*)args;
+}
+
+void cppyy_deallocate_function_args(void* args) {
+ free(args);
+}
+
+size_t cppyy_function_arg_sizeof() {
+ return sizeof(CPPYY_G__value);
+}
+
+size_t cppyy_function_arg_typeoffset() {
+ return offsetof(CPPYY_G__value, type);
+}
+
+
+/* scope reflection information ------------------------------------------- */
+int cppyy_is_namespace(cppyy_scope_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ return s.IsNamespace();
+}
+
+int cppyy_is_enum(const char* type_name) {
+ Reflex::Type t = Reflex::Type::ByName(type_name);
+ return t.IsEnum();
+}
+
+
+/* class reflection information ------------------------------------------- */
+char* cppyy_final_name(cppyy_type_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ if (s.IsEnum())
+ return cppstring_to_cstring("unsigned int");
+ std::string name = s.Name(Reflex::FINAL);
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ if (s.IsEnum())
+ return cppstring_to_cstring("unsigned int");
+ std::string name = s.Name(Reflex::SCOPED | Reflex::FINAL);
+ return cppstring_to_cstring(name);
+}
+
+static int cppyy_has_complex_hierarchy(const Reflex::Type& t) {
+ int is_complex = 1;
+
+ size_t nbases = t.BaseSize();
+ if (1 < nbases)
+ is_complex = 1;
+ else if (nbases == 0)
+ is_complex = 0;
+ else { // one base class only
+ Reflex::Base b = t.BaseAt(0);
+ if (b.IsVirtual())
+ is_complex = 1; // TODO: verify; can be complex, need not be.
+ else
+ is_complex = cppyy_has_complex_hierarchy(t.BaseAt(0).ToType());
+ }
+
+ return is_complex;
+}
+
+int cppyy_has_complex_hierarchy(cppyy_type_t handle) {
+ Reflex::Type t = type_from_handle(handle);
+ return cppyy_has_complex_hierarchy(t);
+}
+
+int cppyy_num_bases(cppyy_type_t handle) {
+ Reflex::Type t = type_from_handle(handle);
+ return t.BaseSize();
+}
+
+char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+ Reflex::Type t = type_from_handle(handle);
+ Reflex::Base b = t.BaseAt(base_index);
+ std::string name = b.Name(Reflex::FINAL|Reflex::SCOPED);
+ return cppstring_to_cstring(name);
+}
+
+int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+ Reflex::Type derived_type = type_from_handle(derived_handle);
+ Reflex::Type base_type = type_from_handle(base_handle);
+ return (int)derived_type.HasBase(base_type);
+}
+
+size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+ cppyy_object_t address, int direction) {
+ Reflex::Type derived_type = type_from_handle(derived_handle);
+ Reflex::Type base_type = type_from_handle(base_handle);
+
+ // when dealing with virtual inheritance the only (reasonably) well-defined info is
+ // in a Reflex internal base table, that contains all offsets within the hierarchy
+ Reflex::Member getbases = derived_type.FunctionMemberByName(
+ "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF);
+ if (getbases) {
+ typedef std::vector<std::pair<Reflex::Base, int> > Bases_t;
+ Bases_t* bases;
+ Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases);
+ getbases.Invoke(&bases_holder);
+
+ // if direction is down-cast, perform the cast in C++ first in order to ensure
+ // we have a derived object for accessing internal offset pointers
+ if (direction < 0) {
+ Reflex::Object o(base_type, (void*)address);
+ address = (cppyy_object_t)o.CastObject(derived_type).Address();
+ }
+
+ for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) {
+ if (ibase->first.ToType() == base_type) {
+ long offset = (long)ibase->first.Offset((void*)address);
+ if (direction < 0)
+ return (size_t) -offset; // note negative; rolls over
+ return (size_t)offset;
+ }
+ }
+
+ // contrary to typical invoke()s, the result of the internal getbases function
+ // is a pointer to a function static, so no delete
+ }
+
+ return 0;
+}
+
+
+/* method/function reflection information --------------------------------- */
+int cppyy_num_methods(cppyy_scope_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ return s.FunctionMemberSize();
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ std::string name;
+ if (m.IsConstructor())
+ name = s.Name(Reflex::FINAL); // to get proper name for templates
+ else
+ name = m.Name();
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ if (m.IsConstructor())
+ return cppstring_to_cstring("constructor");
+ Reflex::Type rt = m.TypeOf().ReturnType();
+ std::string name = rt.Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+ return cppstring_to_cstring(name);
+}
+
+int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.FunctionParameterSize();
+}
+
+int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.FunctionParameterSize(true);
+}
+
+char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ Reflex::Type at = m.TypeOf().FunctionParameterAt(arg_index);
+ std::string name = at.Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_method_arg_default(cppyy_scope_t handle, int method_index, int arg_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ std::string dflt = m.FunctionParameterDefaultAt(arg_index);
+ return cppstring_to_cstring(dflt);
+}
+
+char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ Reflex::Type mt = m.TypeOf();
+ std::ostringstream sig;
+ if (!m.IsConstructor())
+ sig << mt.ReturnType().Name() << " ";
+ sig << s.Name(Reflex::SCOPED) << "::" << m.Name() << "(";
+ int nArgs = m.FunctionParameterSize();
+ for (int iarg = 0; iarg < nArgs; ++iarg) {
+ sig << mt.FunctionParameterAt(iarg).Name(Reflex::SCOPED|Reflex::QUALIFIED);
+ if (iarg != nArgs-1)
+ sig << ", ";
+ }
+ sig << ")" << std::ends;
+ return cppstring_to_cstring(sig.str());
+}
+
+int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // the following appears dumb, but the internal storage for Reflex is an
+ // unsorted std::vector anyway, so there's no gain to be had in using the
+ // Scope::FunctionMemberByName() function
+ int num_meth = s.FunctionMemberSize();
+ for (int imeth = 0; imeth < num_meth; ++imeth) {
+ Reflex::Member m = s.FunctionMemberAt(imeth);
+ if (m.Name() == name) {
+ if (m.IsPublic())
+ return imeth;
+ return -1;
+ }
+ }
+ return -1;
+}
+
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ assert(m.IsFunctionMember());
+ return (cppyy_method_t)m.Stubfunction();
+}
+
+
+/* method properties ----------------------------------------------------- */
+int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.IsConstructor();
+}
+
+int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.IsStatic();
+}
+
+
+/* data member reflection information ------------------------------------- */
+int cppyy_num_datamembers(cppyy_scope_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // fix enum representation by adding them to the containing scope as per C++
+ // TODO: this (relatively harmlessly) dupes data members when updating in the
+ // case s is a namespace
+ for (int isub = 0; isub < (int)s.ScopeSize(); ++isub) {
+ Reflex::Scope sub = s.SubScopeAt(isub);
+ if (sub.IsEnum()) {
+ for (int idata = 0; idata < (int)sub.DataMemberSize(); ++idata) {
+ Reflex::Member m = sub.DataMemberAt(idata);
+ s.AddDataMember(m.Name().c_str(), sub, 0,
+ Reflex::PUBLIC|Reflex::STATIC|Reflex::ARTIFICIAL,
+ (char*)m.Offset());
+ }
+ }
+ }
+ return s.DataMemberSize();
+}
+
+char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ std::string name = m.Name();
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ std::string name = m.TypeOf().Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+ return cppstring_to_cstring(name);
+}
+
+size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ if (m.IsArtificial() && m.TypeOf().IsEnum())
+ return (size_t)&m.InterpreterOffset();
+ return m.Offset();
+}
+
+int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // the following appears dumb, but the internal storage for Reflex is an
+ // unsorted std::vector anyway, so there's no gain to be had in using the
+ // Scope::DataMemberByName() function (which returns Member, not an index)
+ int num_dm = cppyy_num_datamembers(handle);
+ for (int idm = 0; idm < num_dm; ++idm) {
+ Reflex::Member m = s.DataMemberAt(idm);
+ if (m.Name() == name || m.Name(Reflex::FINAL) == name) {
+ if (m.IsPublic())
+ return idm;
+ return -1;
+ }
+ }
+ return -1;
+}
+
+
+/* data member properties ------------------------------------------------ */
+int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ return m.IsPublic();
+}
+
+int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ return m.IsStatic();
+}
+
+
+/* misc helpers ----------------------------------------------------------- */
+long long cppyy_strtoll(const char* str) {
+ return strtoll(str, NULL, 0);
+}
+
+extern "C" unsigned long long cppyy_strtoull(const char* str) {
+ return strtoull(str, NULL, 0);
+}
+
+void cppyy_free(void* ptr) {
+ free(ptr);
+}
+
+cppyy_object_t cppyy_charp2stdstring(const char* str) {
+ return (cppyy_object_t)new std::string(str);
+}
+
+cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) {
+ return (cppyy_object_t)new std::string(*(std::string*)ptr);
+}
+
+void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
+ *((std::string*)ptr) = str;
+}
+
+void cppyy_free_stdstring(cppyy_object_t ptr) {
+ delete (std::string*)ptr;
+}
diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/Makefile
@@ -0,0 +1,62 @@
+dicts = example01Dict.so datatypesDict.so advancedcppDict.so advancedcpp2Dict.so \
+overloadsDict.so stltypesDict.so operatorsDict.so fragileDict.so crossingDict.so \
+std_streamsDict.so
+all : $(dicts)
+
+ROOTSYS := ${ROOTSYS}
+
+ifeq ($(ROOTSYS),)
+ genreflex=genreflex
+ cppflags=
+else
+ genreflex=$(ROOTSYS)/bin/genreflex
+ ifeq ($(wildcard $(ROOTSYS)/include),) # standard locations used?
+ cppflags=-I$(shell root-config --incdir) -L$(shell root-config --libdir)
+ else
+ cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib64 -L$(ROOTSYS)/lib
+ endif
+endif
+
+PLATFORM := $(shell uname -s)
+ifeq ($(PLATFORM),Darwin)
+ cppflags+=-dynamiclib -single_module -arch x86_64
+endif
+
+ifeq ($(CINT),)
+ ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),)
+ genreflexflags=
+ cppflags2=-O3 -fPIC
+ else
+ genreflexflags=--with-methptrgetter
+ cppflags2=-Wno-pmf-conversions -O3 -fPIC
+ endif
+else
+ cppflags2=-O3 -fPIC -rdynamic
+endif
+
+ifeq ($(CINT),)
+%Dict.so: %_rflx.cpp %.cxx
+ echo $(cppflags)
+ g++ -o $@ $^ -shared -lReflex $(cppflags) $(cppflags2)
+
+%_rflx.cpp: %.h %.xml
+ $(genreflex) $< $(genreflexflags) --selection=$*.xml --rootmap=$*Dict.rootmap --rootmap-lib=$*Dict.so
+else
+%Dict.so: %_cint.cxx %.cxx
+ g++ -o $@ $^ -shared $(cppflags) $(cppflags2)
+ rlibmap -f -o $*Dict.rootmap -l $@ -c $*_LinkDef.h
+
+%_cint.cxx: %.h %_LinkDef.h
+ rootcint -f $@ -c $*.h $*_LinkDef.h
+endif
+
+ifeq ($(CINT),)
+# TODO: methptrgetter causes these tests to crash, so don't use it for now
+std_streamsDict.so: std_streams.cxx std_streams.h std_streams.xml
+ $(genreflex) std_streams.h --selection=std_streams.xml
+ g++ -o $@ std_streams_rflx.cpp std_streams.cxx -shared -lReflex $(cppflags) $(cppflags2)
+endif
+
+.PHONY: clean
+clean:
+ -rm -f $(dicts) $(subst .so,.rootmap,$(dicts)) $(wildcard *_cint.h)
diff --git a/pypy/module/cppyy/test/__init__.py b/pypy/module/cppyy/test/__init__.py
new file mode 100644
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx b/pypy/module/cppyy/test/advancedcpp.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -0,0 +1,76 @@
+#include "advancedcpp.h"
+
+
+// for testing of default arguments
+defaulter::defaulter(int a, int b, int c ) {
+ m_a = a;
+ m_b = b;
+ m_c = c;
+}
+
+
+// for esoteric inheritance testing
+a_class* create_c1() { return new c_class_1; }
+a_class* create_c2() { return new c_class_2; }
+
+int get_a( a_class& a ) { return a.m_a; }
+int get_b( b_class& b ) { return b.m_b; }
+int get_c( c_class& c ) { return c.m_c; }
+int get_d( d_class& d ) { return d.m_d; }
+
+
+// for namespace testing
+int a_ns::g_a = 11;
+int a_ns::b_class::s_b = 22;
+int a_ns::b_class::c_class::s_c = 33;
+int a_ns::d_ns::g_d = 44;
+int a_ns::d_ns::e_class::s_e = 55;
+int a_ns::d_ns::e_class::f_class::s_f = 66;
+
+int a_ns::get_g_a() { return g_a; }
+int a_ns::d_ns::get_g_d() { return g_d; }
+
+
+// for template testing
+template class T1<int>;
+template class T2<T1<int> >;
+template class T3<int, double>;
+template class T3<T1<int>, T2<T1<int> > >;
+template class a_ns::T4<int>;
+template class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+
+// helpers for checking pass-by-ref
+void set_int_through_ref(int& i, int val) { i = val; }
+int pass_int_through_const_ref(const int& i) { return i; }
+void set_long_through_ref(long& l, long val) { l = val; }
+long pass_long_through_const_ref(const long& l) { return l; }
+void set_double_through_ref(double& d, double val) { d = val; }
+double pass_double_through_const_ref(const double& d) { return d; }
+
+
+// for math conversions testing
+bool operator==(const some_comparable& c1, const some_comparable& c2 )
+{
+ return &c1 != &c2; // the opposite of a pointer comparison
+}
+
+bool operator!=( const some_comparable& c1, const some_comparable& c2 )
+{
+ return &c1 == &c2; // the opposite of a pointer comparison
+}
+
+
+// a couple of globals for access testing
+double my_global_double = 12.;
+double my_global_array[500];
+
+
+// for life-line and identity testing
+int some_class_with_data::some_data::s_num_data = 0;
+
+
+// for testing multiple inheritance
+multi1::~multi1() {}
+multi2::~multi2() {}
+multi::~multi() {}
diff --git a/pypy/module/cppyy/test/advancedcpp.h b/pypy/module/cppyy/test/advancedcpp.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.h
@@ -0,0 +1,339 @@
+#include <vector>
+
+
+//===========================================================================
+class defaulter { // for testing of default arguments
+public:
+ defaulter(int a = 11, int b = 22, int c = 33 );
+
+public:
+ int m_a, m_b, m_c;
+};
+
+
+//===========================================================================
+class base_class { // for simple inheritance testing
+public:
+ base_class() { m_b = 1; m_db = 1.1; }
+ virtual ~base_class() {}
+ virtual int get_value() { return m_b; }
+ double get_base_value() { return m_db; }
+
+ virtual base_class* cycle(base_class* b) { return b; }
+ virtual base_class* clone() { return new base_class; }
+
+public:
+ int m_b;
+ double m_db;
+};
+
+class derived_class : public base_class {
+public:
+ derived_class() { m_d = 2; m_dd = 2.2;}
+ virtual int get_value() { return m_d; }
+ double get_derived_value() { return m_dd; }
+ virtual base_class* clone() { return new derived_class; }
+
+public:
+ int m_d;
+ double m_dd;
+};
+
+
+//===========================================================================
+class a_class { // for esoteric inheritance testing
+public:
+ a_class() { m_a = 1; m_da = 1.1; }
+ ~a_class() {}
+ virtual int get_value() = 0;
+
+public:
+ int m_a;
+ double m_da;
+};
+
+class b_class : public virtual a_class {
+public:
+ b_class() { m_b = 2; m_db = 2.2;}
+ virtual int get_value() { return m_b; }
+
+public:
+ int m_b;
+ double m_db;
+};
+
+class c_class_1 : public virtual a_class, public virtual b_class {
+public:
+ c_class_1() { m_c = 3; }
+ virtual int get_value() { return m_c; }
+
+public:
+ int m_c;
+};
+
+class c_class_2 : public virtual b_class, public virtual a_class {
+public:
+ c_class_2() { m_c = 3; }
+ virtual int get_value() { return m_c; }
+
+public:
+ int m_c;
+};
+
+typedef c_class_2 c_class;
+
+class d_class : public virtual c_class, public virtual a_class {
+public:
+ d_class() { m_d = 4; }
+ virtual int get_value() { return m_d; }
+
+public:
+ int m_d;
+};
+
+a_class* create_c1();
+a_class* create_c2();
+
+int get_a(a_class& a);
+int get_b(b_class& b);
+int get_c(c_class& c);
+int get_d(d_class& d);
+
+
+//===========================================================================
+namespace a_ns { // for namespace testing
+ extern int g_a;
+ int get_g_a();
+
+ struct b_class {
+ b_class() { m_b = -2; }
+ int m_b;
+ static int s_b;
+
+ struct c_class {
+ c_class() { m_c = -3; }
+ int m_c;
+ static int s_c;
+ };
+ };
+
+ namespace d_ns {
+ extern int g_d;
+ int get_g_d();
+
+ struct e_class {
+ e_class() { m_e = -5; }
+ int m_e;
+ static int s_e;
+
+ struct f_class {
+ f_class() { m_f = -6; }
+ int m_f;
+ static int s_f;
+ };
+ };
+
+ } // namespace d_ns
+
+} // namespace a_ns
+
+
+//===========================================================================
+template<typename T> // for template testing
+class T1 {
+public:
+ T1(T t = T(1)) : m_t1(t) {}
+ T value() { return m_t1; }
+
+public:
+ T m_t1;
+};
+
+template<typename T>
+class T2 {
+public:
+ T2(T t = T(2)) : m_t2(t) {}
+ T value() { return m_t2; }
+
+public:
+ T m_t2;
+};
+
+template<typename T, typename U>
+class T3 {
+public:
+ T3(T t = T(3), U u = U(33)) : m_t3(t), m_u3(u) {}
+ T value_t() { return m_t3; }
+ U value_u() { return m_u3; }
+
+public:
+ T m_t3;
+ U m_u3;
+};
+
+namespace a_ns {
+
+ template<typename T>
+ class T4 {
+ public:
+ T4(T t = T(4)) : m_t4(t) {}
+ T value() { return m_t4; }
+
+ public:
+ T m_t4;
+ };
+
+} // namespace a_ns
+
+extern template class T1<int>;
+extern template class T2<T1<int> >;
+extern template class T3<int, double>;
+extern template class T3<T1<int>, T2<T1<int> > >;
+extern template class a_ns::T4<int>;
+extern template class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+
+//===========================================================================
+// for checking pass-by-reference of builtin types
+void set_int_through_ref(int& i, int val);
+int pass_int_through_const_ref(const int& i);
+void set_long_through_ref(long& l, long val);
+long pass_long_through_const_ref(const long& l);
+void set_double_through_ref(double& d, double val);
+double pass_double_through_const_ref(const double& d);
+
+
+//===========================================================================
+class some_abstract_class { // to test abstract class handling
+public:
+ virtual void a_virtual_method() = 0;
+};
+
+class some_concrete_class : public some_abstract_class {
+public:
+ virtual void a_virtual_method() {}
+};
+
+
+//===========================================================================
+/*
+TODO: methptrgetter support for std::vector<>
+class ref_tester { // for assignment by-ref testing
+public:
+ ref_tester() : m_i(-99) {}
+ ref_tester(int i) : m_i(i) {}
+ ref_tester(const ref_tester& s) : m_i(s.m_i) {}
+ ref_tester& operator=(const ref_tester& s) {
+ if (&s != this) m_i = s.m_i;
+ return *this;
+ }
+ ~ref_tester() {}
+
+public:
+ int m_i;
+};
+
+template class std::vector< ref_tester >;
+*/
+
+
+//===========================================================================
+class some_convertible { // for math conversions testing
+public:
+ some_convertible() : m_i(-99), m_d(-99.) {}
+
+ operator int() { return m_i; }
+ operator long() { return m_i; }
+ operator double() { return m_d; }
+
+public:
+ int m_i;
+ double m_d;
+};
+
+
+class some_comparable {
+};
+
+bool operator==(const some_comparable& c1, const some_comparable& c2 );
+bool operator!=( const some_comparable& c1, const some_comparable& c2 );
+
+
+//===========================================================================
+extern double my_global_double; // a couple of globals for access testing
+extern double my_global_array[500];
+
+
+//===========================================================================
+class some_class_with_data { // for life-line and identity testing
+public:
+ class some_data {
+ public:
+ some_data() { ++s_num_data; }
+ some_data(const some_data&) { ++s_num_data; }
+ ~some_data() { --s_num_data; }
+
+ static int s_num_data;
+ };
+
+ some_class_with_data gime_copy() {
+ return *this;
+ }
+
+ const some_data& gime_data() { /* TODO: methptrgetter const support */
+ return m_data;
+ }
+
+ int m_padding;
+ some_data m_data;
+};
+
+
+//===========================================================================
+class pointer_pass { // for testing passing of void*'s
+public:
+ long gime_address_ptr(void* obj) {
+ return (long)obj;
+ }
+
+ long gime_address_ptr_ptr(void** obj) {
+ return (long)*((long**)obj);
+ }
+
+ long gime_address_ptr_ref(void*& obj) {
+ return (long)obj;
+ }
+};
+
+
+//===========================================================================
+class multi1 { // for testing multiple inheritance
+public:
+ multi1(int val) : m_int(val) {}
+ virtual ~multi1();
+ int get_multi1_int() { return m_int; }
+
+private:
+ int m_int;
+};
+
+class multi2 {
+public:
+ multi2(int val) : m_int(val) {}
+ virtual ~multi2();
+ int get_multi2_int() { return m_int; }
+
+private:
+ int m_int;
+};
+
+class multi : public multi1, public multi2 {
+public:
+ multi(int val1, int val2, int val3) :
+ multi1(val1), multi2(val2), m_int(val3) {}
+ virtual ~multi();
+ int get_my_own_int() { return m_int; }
+
+private:
+ int m_int;
+};
diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -0,0 +1,40 @@
+<lcgdict>
+
+ <class name="defaulter" />
+
+ <class name="base_class" />
+ <class name="derived_class" />
+
+ <class name="a_class" />
+ <class name="b_class" />
+ <class name="c_class" />
+ <class name="c_class_1" />
+ <class name="c_class_2" />
+ <class name="d_class" />
+
+ <function pattern="create_*" />
+ <function pattern="get_*" />
+
+ <class pattern="T1<*>" />
+ <class pattern="T2<*>" />
+ <class pattern="T3<*>" />
+
+ <namespace name="a_ns" />
+ <namespace pattern="a_ns::*" />
+ <class pattern="a_ns::*" />
+ <variable name="a_ns::g_a" />
+ <function name="a_ns::get_g_a" />
+ <variable name="a_ns::d_ns::g_d" />
+ <function name="a_ns::d_ns::get_g_d" />
+
+ <class name="some_abstract_class" />
+ <class name="some_concrete_class" />
+ <class name="some_convertible" />
+ <class name="some_class_with_data" />
+ <class name="some_class_with_data::some_data" />
+
+ <class name="pointer_pass" />
+
+ <class pattern="multi*" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/advancedcpp2.cxx b/pypy/module/cppyy/test/advancedcpp2.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.cxx
@@ -0,0 +1,13 @@
+#include "advancedcpp2.h"
+
+
+// for namespace testing
+int a_ns::g_g = 77;
+int a_ns::g_class::s_g = 88;
+int a_ns::g_class::h_class::s_h = 99;
+int a_ns::d_ns::g_i = 111;
+int a_ns::d_ns::i_class::s_i = 222;
+int a_ns::d_ns::i_class::j_class::s_j = 333;
+
+int a_ns::get_g_g() { return g_g; }
+int a_ns::d_ns::get_g_i() { return g_i; }
diff --git a/pypy/module/cppyy/test/advancedcpp2.h b/pypy/module/cppyy/test/advancedcpp2.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.h
@@ -0,0 +1,36 @@
+//===========================================================================
+namespace a_ns { // for namespace testing
+ extern int g_g;
+ int get_g_g();
+
+ struct g_class {
+ g_class() { m_g = -7; }
+ int m_g;
+ static int s_g;
+
+ struct h_class {
+ h_class() { m_h = -8; }
+ int m_h;
+ static int s_h;
+ };
+ };
+
+ namespace d_ns {
+ extern int g_i;
+ int get_g_i();
+
+ struct i_class {
+ i_class() { m_i = -9; }
+ int m_i;
+ static int s_i;
+
+ struct j_class {
+ j_class() { m_j = -10; }
+ int m_j;
+ static int s_j;
+ };
+ };
+
+ } // namespace d_ns
+
+} // namespace a_ns
diff --git a/pypy/module/cppyy/test/advancedcpp2.xml b/pypy/module/cppyy/test/advancedcpp2.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.xml
@@ -0,0 +1,11 @@
+<lcgdict>
+
+ <namespace name="a_ns" />
+ <namespace pattern="a_ns::*" />
+ <class pattern="a_ns::*" />
+ <variable name="a_ns::g_g" />
+ <function name="a_ns::get_g_g" />
+ <variable name="a_ns::d_ns::g_i" />
+ <function name="a_ns::d_ns::get_g_i" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/advancedcpp2_LinkDef.h b/pypy/module/cppyy/test/advancedcpp2_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2_LinkDef.h
@@ -0,0 +1,18 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ namespace a_ns;
+#pragma link C++ namespace a_ns::d_ns;
+#pragma link C++ struct a_ns::g_class;
+#pragma link C++ struct a_ns::g_class::h_class;
+#pragma link C++ struct a_ns::d_ns::i_class;
+#pragma link C++ struct a_ns::d_ns::i_class::j_class;
+#pragma link C++ variable a_ns::g_g;
+#pragma link C++ function a_ns::get_g_g;
+#pragma link C++ variable a_ns::d_ns::g_i;
+#pragma link C++ function a_ns::d_ns::get_g_i;
+
+#endif
diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
@@ -0,0 +1,58 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class defaulter;
+
+#pragma link C++ class base_class;
+#pragma link C++ class derived_class;
+
+#pragma link C++ class a_class;
+#pragma link C++ class b_class;
+#pragma link C++ class c_class;
+#pragma link C++ class c_class_1;
+#pragma link C++ class c_class_2;
+#pragma link C++ class d_class;
+
+#pragma link C++ function create_c1();
+#pragma link C++ function create_c2();
+
+#pragma link C++ function get_a(a_class&);
+#pragma link C++ function get_b(b_class&);
+#pragma link C++ function get_c(c_class&);
+#pragma link C++ function get_d(d_class&);
+
+#pragma link C++ class T1<int>;
+#pragma link C++ class T2<T1<int> >;
+#pragma link C++ class T3<int, double>;
+#pragma link C++ class T3<T1<int>, T2<T1<int> > >;
+#pragma link C++ class a_ns::T4<int>;
+#pragma link C++ class a_ns::T4<T3<int,double> >;
+#pragma link C++ class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+#pragma link C++ namespace a_ns;
+#pragma link C++ namespace a_ns::d_ns;
+#pragma link C++ struct a_ns::b_class;
+#pragma link C++ struct a_ns::b_class::c_class;
+#pragma link C++ struct a_ns::d_ns::e_class;
+#pragma link C++ struct a_ns::d_ns::e_class::f_class;
+#pragma link C++ variable a_ns::g_a;
+#pragma link C++ function a_ns::get_g_a;
+#pragma link C++ variable a_ns::d_ns::g_d;
+#pragma link C++ function a_ns::d_ns::get_g_d;
+
+#pragma link C++ class some_abstract_class;
+#pragma link C++ class some_concrete_class;
+#pragma link C++ class some_convertible;
+#pragma link C++ class some_class_with_data;
+#pragma link C++ class some_class_with_data::some_data;
+
+#pragma link C++ class pointer_pass;
+
+#pragma link C++ class multi1;
+#pragma link C++ class multi2;
+#pragma link C++ class multi;
+
+#endif
diff --git a/pypy/module/cppyy/test/bench1.cxx b/pypy/module/cppyy/test/bench1.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/bench1.cxx
@@ -0,0 +1,39 @@
+#include <iostream>
+#include <iomanip>
+#include <time.h>
+#include <unistd.h>
+
+#include "example01.h"
+
+static const int NNN = 10000000;
+
+
+int cpp_loop_offset() {
+ int i = 0;
+ for ( ; i < NNN*10; ++i)
+ ;
+ return i;
+}
+
+int cpp_bench1() {
+ int i = 0;
+ example01 e;
+ for ( ; i < NNN*10; ++i)
+ e.addDataToInt(i);
+ return i;
+}
+
+
+int main() {
+
+ clock_t t1 = clock();
+ cpp_loop_offset();
+ clock_t t2 = clock();
+ cpp_bench1();
+ clock_t t3 = clock();
+
+ std::cout << std::setprecision(8)
+ << ((t3-t2) - (t2-t1))/((double)CLOCKS_PER_SEC*10.) << std::endl;
+
+ return 0;
+}
diff --git a/pypy/module/cppyy/test/bench1.py b/pypy/module/cppyy/test/bench1.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/bench1.py
@@ -0,0 +1,147 @@
+import commands, os, sys, time
+
+NNN = 10000000
+
+
+def run_bench(bench):
+ global t_loop_offset
+
+ t1 = time.time()
+ bench()
+ t2 = time.time()
+
+ t_bench = (t2-t1)-t_loop_offset
+ return bench.scale*t_bench
+
+def print_bench(name, t_bench):
+ global t_cppref
+ print ':::: %s cost: %#6.3fs (%#4.1fx)' % (name, t_bench, float(t_bench)/t_cppref)
+
+def python_loop_offset():
+ for i in range(NNN):
+ i
+ return i
+
+class PyCintexBench1(object):
+ scale = 10
+ def __init__(self):
+ import PyCintex
+ self.lib = PyCintex.gbl.gSystem.Load("./example01Dict.so")
+
+ self.cls = PyCintex.gbl.example01
+ self.inst = self.cls(0)
+
+ def __call__(self):
+ # note that PyCintex calls don't actually scale linearly, but worse
+ # than linear (leak or wrong filling of a cache??)
+ instance = self.inst
+ niter = NNN/self.scale
+ for i in range(niter):
+ instance.addDataToInt(i)
+ return i
+
+class PyROOTBench1(PyCintexBench1):
+ def __init__(self):
+ import ROOT
+ self.lib = ROOT.gSystem.Load("./example01Dict_cint.so")
+
+ self.cls = ROOT.example01
+ self.inst = self.cls(0)
+
+class CppyyInterpBench1(object):
+ scale = 1
+ def __init__(self):
+ import cppyy
+ self.lib = cppyy.load_reflection_info("./example01Dict.so")
+
+ self.cls = cppyy._scope_byname("example01")
+ self.inst = self.cls.get_overload(self.cls.type_name).call(None, 0)
+
+ def __call__(self):
+ addDataToInt = self.cls.get_overload("addDataToInt")
+ instance = self.inst
+ for i in range(NNN):
+ addDataToInt.call(instance, i)
+ return i
+
+class CppyyInterpBench2(CppyyInterpBench1):
+ def __call__(self):
+ addDataToInt = self.cls.get_overload("overloadedAddDataToInt")
+ instance = self.inst
+ for i in range(NNN):
+ addDataToInt.call(instance, i)
+ return i
+
+class CppyyInterpBench3(CppyyInterpBench1):
+ def __call__(self):
+ addDataToInt = self.cls.get_overload("addDataToIntConstRef")
+ instance = self.inst
+ for i in range(NNN):
+ addDataToInt.call(instance, i)
+ return i
+
+class CppyyPythonBench1(object):
+ scale = 1
+ def __init__(self):
+ import cppyy
+ self.lib = cppyy.load_reflection_info("./example01Dict.so")
+
+ self.cls = cppyy.gbl.example01
+ self.inst = self.cls(0)
+
+ def __call__(self):
+ instance = self.inst
+ for i in range(NNN):
+ instance.addDataToInt(i)
+ return i
+
+
+if __name__ == '__main__':
+ python_loop_offset();
+
+ # time python loop offset
+ t1 = time.time()
+ python_loop_offset()
+ t2 = time.time()
+ t_loop_offset = t2-t1
+
+ # special case for PyCintex (run under python, not pypy-c)
+ if '--pycintex' in sys.argv:
+ cintex_bench1 = PyCintexBench1()
+ print run_bench(cintex_bench1)
+ sys.exit(0)
+
+ # special case for PyCintex (run under python, not pypy-c)
+ if '--pyroot' in sys.argv:
+ pyroot_bench1 = PyROOTBench1()
+ print run_bench(pyroot_bench1)
+ sys.exit(0)
+
+ # get C++ reference point
+ if not os.path.exists("bench1.exe") or\
+ os.stat("bench1.exe").st_mtime < os.stat("bench1.cxx").st_mtime:
+ print "rebuilding bench1.exe ... "
+ os.system( "g++ -O2 bench1.cxx example01.cxx -o bench1.exe" )
+ stat, cppref = commands.getstatusoutput("./bench1.exe")
+ t_cppref = float(cppref)
+
+ # warm-up
+ print "warming up ... "
+ interp_bench1 = CppyyInterpBench1()
+ interp_bench2 = CppyyInterpBench2()
+ interp_bench3 = CppyyInterpBench3()
+ python_bench1 = CppyyPythonBench1()
+ interp_bench1(); interp_bench2(); python_bench1()
+
+ # to allow some consistency checking
+ print "C++ reference uses %.3fs" % t_cppref
+
+ # test runs ...
+ print_bench("cppyy interp", run_bench(interp_bench1))
+ print_bench("... overload", run_bench(interp_bench2))
+ print_bench("... constref", run_bench(interp_bench3))
+ print_bench("cppyy python", run_bench(python_bench1))
+ stat, t_cintex = commands.getstatusoutput("python bench1.py --pycintex")
+ print_bench("pycintex ", float(t_cintex))
+ #stat, t_pyroot = commands.getstatusoutput("python bench1.py --pyroot")
+ #print_bench("pyroot ", float(t_pyroot))
diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/conftest.py
@@ -0,0 +1,5 @@
+import py
+
+def pytest_runtest_setup(item):
+ if py.path.local.sysfind('genreflex') is None:
+ py.test.skip("genreflex is not installed")
diff --git a/pypy/module/cppyy/test/crossing.cxx b/pypy/module/cppyy/test/crossing.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.cxx
@@ -0,0 +1,16 @@
+#include "crossing.h"
+#include <stdlib.h>
+
+extern "C" long bar_unwrap(PyObject*);
+extern "C" PyObject* bar_wrap(long);
+
+
+long crossing::A::unwrap(PyObject* pyobj)
+{
+ return bar_unwrap(pyobj);
+}
+
+PyObject* crossing::A::wrap(long l)
+{
+ return bar_wrap(l);
+}
diff --git a/pypy/module/cppyy/test/crossing.h b/pypy/module/cppyy/test/crossing.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.h
@@ -0,0 +1,12 @@
+struct _object;
+typedef _object PyObject;
+
+namespace crossing {
+
+class A {
+public:
+ long unwrap(PyObject* pyobj);
+ PyObject* wrap(long l);
+};
+
+} // namespace crossing
diff --git a/pypy/module/cppyy/test/crossing.xml b/pypy/module/cppyy/test/crossing.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.xml
@@ -0,0 +1,7 @@
+<lcgdict>
+
+ <namespace name="crossing" />
+
+ <class pattern="crossing::[A-Z]" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/crossing_LinkDef.h b/pypy/module/cppyy/test/crossing_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing_LinkDef.h
@@ -0,0 +1,11 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ namespace crossing;
+
+#pragma link C++ class crossing::A;
+
+#endif
diff --git a/pypy/module/cppyy/test/datatypes.cxx b/pypy/module/cppyy/test/datatypes.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.cxx
@@ -0,0 +1,211 @@
+#include "datatypes.h"
+
+#include <iostream>
+
+
+//===========================================================================
+cppyy_test_data::cppyy_test_data() : m_owns_arrays(false)
+{
+ m_bool = false;
+ m_char = 'a';
+ m_uchar = 'c';
+ m_short = -11;
+ m_ushort = 11u;
+ m_int = -22;
+ m_uint = 22u;
+ m_long = -33l;
+ m_ulong = 33ul;
+ m_llong = -44ll;
+ m_ullong = 55ull;
+ m_float = -66.f;
+ m_double = -77.;
+ m_enum = kNothing;
+
+ m_short_array2 = new short[N];
+ m_ushort_array2 = new unsigned short[N];
+ m_int_array2 = new int[N];
+ m_uint_array2 = new unsigned int[N];
+ m_long_array2 = new long[N];
+ m_ulong_array2 = new unsigned long[N];
+
+ m_float_array2 = new float[N];
+ m_double_array2 = new double[N];
+
+ for (int i = 0; i < N; ++i) {
+ m_short_array[i] = -1*i;
+ m_short_array2[i] = -2*i;
+ m_ushort_array[i] = 3u*i;
+ m_ushort_array2[i] = 4u*i;
+ m_int_array[i] = -5*i;
+ m_int_array2[i] = -6*i;
+ m_uint_array[i] = 7u*i;
+ m_uint_array2[i] = 8u*i;
+ m_long_array[i] = -9l*i;
+ m_long_array2[i] = -10l*i;
+ m_ulong_array[i] = 11ul*i;
+ m_ulong_array2[i] = 12ul*i;
+
+ m_float_array[i] = -13.f*i;
+ m_float_array2[i] = -14.f*i;
+ m_double_array[i] = -15.*i;
+ m_double_array2[i] = -16.*i;
+ }
+
+ m_owns_arrays = true;
+
+ m_pod.m_int = 888;
+ m_pod.m_double = 3.14;
+
+ m_ppod = &m_pod;
+};
+
+cppyy_test_data::~cppyy_test_data()
+{
+ destroy_arrays();
+}
+
+void cppyy_test_data::destroy_arrays() {
+ if (m_owns_arrays == true) {
+ delete[] m_short_array2;
+ delete[] m_ushort_array2;
+ delete[] m_int_array2;
+ delete[] m_uint_array2;
+ delete[] m_long_array2;
+ delete[] m_ulong_array2;
+
+ delete[] m_float_array2;
+ delete[] m_double_array2;
+
+ m_owns_arrays = false;
+ }
+}
+
+//- getters -----------------------------------------------------------------
+bool cppyy_test_data::get_bool() { return m_bool; }
+char cppyy_test_data::get_char() { return m_char; }
+unsigned char cppyy_test_data::get_uchar() { return m_uchar; }
+short cppyy_test_data::get_short() { return m_short; }
+unsigned short cppyy_test_data::get_ushort() { return m_ushort; }
+int cppyy_test_data::get_int() { return m_int; }
+unsigned int cppyy_test_data::get_uint() { return m_uint; }
+long cppyy_test_data::get_long() { return m_long; }
+unsigned long cppyy_test_data::get_ulong() { return m_ulong; }
+long long cppyy_test_data::get_llong() { return m_llong; }
+unsigned long long cppyy_test_data::get_ullong() { return m_ullong; }
+float cppyy_test_data::get_float() { return m_float; }
+double cppyy_test_data::get_double() { return m_double; }
+cppyy_test_data::what cppyy_test_data::get_enum() { return m_enum; }
+
+short* cppyy_test_data::get_short_array() { return m_short_array; }
+short* cppyy_test_data::get_short_array2() { return m_short_array2; }
+unsigned short* cppyy_test_data::get_ushort_array() { return m_ushort_array; }
+unsigned short* cppyy_test_data::get_ushort_array2() { return m_ushort_array2; }
+int* cppyy_test_data::get_int_array() { return m_int_array; }
+int* cppyy_test_data::get_int_array2() { return m_int_array2; }
+unsigned int* cppyy_test_data::get_uint_array() { return m_uint_array; }
+unsigned int* cppyy_test_data::get_uint_array2() { return m_uint_array2; }
+long* cppyy_test_data::get_long_array() { return m_long_array; }
+long* cppyy_test_data::get_long_array2() { return m_long_array2; }
+unsigned long* cppyy_test_data::get_ulong_array() { return m_ulong_array; }
+unsigned long* cppyy_test_data::get_ulong_array2() { return m_ulong_array2; }
+
+float* cppyy_test_data::get_float_array() { return m_float_array; }
+float* cppyy_test_data::get_float_array2() { return m_float_array2; }
+double* cppyy_test_data::get_double_array() { return m_double_array; }
+double* cppyy_test_data::get_double_array2() { return m_double_array2; }
+
+cppyy_test_pod cppyy_test_data::get_pod_val() { return m_pod; }
+cppyy_test_pod* cppyy_test_data::get_pod_ptr() { return &m_pod; }
+cppyy_test_pod& cppyy_test_data::get_pod_ref() { return m_pod; }
+cppyy_test_pod*& cppyy_test_data::get_pod_ptrref() { return m_ppod; }
+
+//- setters -----------------------------------------------------------------
+void cppyy_test_data::set_bool(bool b) { m_bool = b; }
+void cppyy_test_data::set_char(char c) { m_char = c; }
+void cppyy_test_data::set_uchar(unsigned char uc) { m_uchar = uc; }
+void cppyy_test_data::set_short(short s) { m_short = s; }
+void cppyy_test_data::set_short_c(const short& s) { m_short = s; }
+void cppyy_test_data::set_ushort(unsigned short us) { m_ushort = us; }
+void cppyy_test_data::set_ushort_c(const unsigned short& us) { m_ushort = us; }
+void cppyy_test_data::set_int(int i) { m_int = i; }
+void cppyy_test_data::set_int_c(const int& i) { m_int = i; }
+void cppyy_test_data::set_uint(unsigned int ui) { m_uint = ui; }
+void cppyy_test_data::set_uint_c(const unsigned int& ui) { m_uint = ui; }
+void cppyy_test_data::set_long(long l) { m_long = l; }
+void cppyy_test_data::set_long_c(const long& l) { m_long = l; }
+void cppyy_test_data::set_ulong(unsigned long ul) { m_ulong = ul; }
+void cppyy_test_data::set_ulong_c(const unsigned long& ul) { m_ulong = ul; }
+void cppyy_test_data::set_llong(long long ll) { m_llong = ll; }
+void cppyy_test_data::set_llong_c(const long long& ll) { m_llong = ll; }
+void cppyy_test_data::set_ullong(unsigned long long ull) { m_ullong = ull; }
+void cppyy_test_data::set_ullong_c(const unsigned long long& ull) { m_ullong = ull; }
+void cppyy_test_data::set_float(float f) { m_float = f; }
+void cppyy_test_data::set_float_c(const float& f) { m_float = f; }
+void cppyy_test_data::set_double(double d) { m_double = d; }
+void cppyy_test_data::set_double_c(const double& d) { m_double = d; }
+void cppyy_test_data::set_enum(what w) { m_enum = w; }
+
+void cppyy_test_data::set_pod_val(cppyy_test_pod p) { m_pod = p; }
+void cppyy_test_data::set_pod_ptr_in(cppyy_test_pod* pp) { m_pod = *pp; }
+void cppyy_test_data::set_pod_ptr_out(cppyy_test_pod* pp) { *pp = m_pod; }
+void cppyy_test_data::set_pod_ref(const cppyy_test_pod& rp) { m_pod = rp; }
+void cppyy_test_data::set_pod_ptrptr_in(cppyy_test_pod** ppp) { m_pod = **ppp; }
+void cppyy_test_data::set_pod_void_ptrptr_in(void** pp) { m_pod = **((cppyy_test_pod**)pp); }
+void cppyy_test_data::set_pod_ptrptr_out(cppyy_test_pod** ppp) { *ppp = &m_pod; }
+void cppyy_test_data::set_pod_void_ptrptr_out(void** pp) { *((cppyy_test_pod**)pp) = &m_pod; }
+
+char cppyy_test_data::s_char = 's';
+unsigned char cppyy_test_data::s_uchar = 'u';
+short cppyy_test_data::s_short = -101;
+unsigned short cppyy_test_data::s_ushort = 255u;
+int cppyy_test_data::s_int = -202;
+unsigned int cppyy_test_data::s_uint = 202u;
+long cppyy_test_data::s_long = -303l;
+unsigned long cppyy_test_data::s_ulong = 303ul;
+long long cppyy_test_data::s_llong = -404ll;
+unsigned long long cppyy_test_data::s_ullong = 505ull;
+float cppyy_test_data::s_float = -606.f;
+double cppyy_test_data::s_double = -707.;
+cppyy_test_data::what cppyy_test_data::s_enum = cppyy_test_data::kNothing;
+
+
+//= global functions ========================================================
+long get_pod_address(cppyy_test_data& c)
+{
+ return (long)&c.m_pod;
+}
+
+long get_int_address(cppyy_test_data& c)
+{
+ return (long)&c.m_pod.m_int;
+}
+
+long get_double_address(cppyy_test_data& c)
+{
+ return (long)&c.m_pod.m_double;
+}
+
+//= global variables/pointers ===============================================
+int g_int = 42;
+
+void set_global_int(int i) {
+ g_int = i;
+}
+
+int get_global_int() {
+ return g_int;
+}
+
+cppyy_test_pod* g_pod = (cppyy_test_pod*)0;
+
+bool is_global_pod(cppyy_test_pod* t) {
+ return t == g_pod;
+}
+
+void set_global_pod(cppyy_test_pod* t) {
+ g_pod = t;
+}
+
+cppyy_test_pod* get_global_pod() {
+ return g_pod;
+}
diff --git a/pypy/module/cppyy/test/datatypes.h b/pypy/module/cppyy/test/datatypes.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.h
@@ -0,0 +1,171 @@
+const int N = 5;
+
+
+//===========================================================================
+struct cppyy_test_pod {
+ int m_int;
+ double m_double;
+};
+
+
+//===========================================================================
+class cppyy_test_data {
+public:
+ cppyy_test_data();
+ ~cppyy_test_data();
+
+// special cases
+ enum what { kNothing=6, kSomething=111, kLots=42 };
+
+// helper
+ void destroy_arrays();
+
+// getters
+ bool get_bool();
+ char get_char();
+ unsigned char get_uchar();
+ short get_short();
+ unsigned short get_ushort();
+ int get_int();
+ unsigned int get_uint();
+ long get_long();
+ unsigned long get_ulong();
+ long long get_llong();
+ unsigned long long get_ullong();
+ float get_float();
+ double get_double();
+ what get_enum();
+
+ short* get_short_array();
+ short* get_short_array2();
+ unsigned short* get_ushort_array();
+ unsigned short* get_ushort_array2();
+ int* get_int_array();
+ int* get_int_array2();
+ unsigned int* get_uint_array();
+ unsigned int* get_uint_array2();
+ long* get_long_array();
+ long* get_long_array2();
+ unsigned long* get_ulong_array();
+ unsigned long* get_ulong_array2();
+
+ float* get_float_array();
+ float* get_float_array2();
+ double* get_double_array();
+ double* get_double_array2();
+
+ cppyy_test_pod get_pod_val();
+ cppyy_test_pod* get_pod_ptr();
+ cppyy_test_pod& get_pod_ref();
+ cppyy_test_pod*& get_pod_ptrref();
+
+// setters
+ void set_bool(bool b);
+ void set_char(char c);
+ void set_uchar(unsigned char uc);
+ void set_short(short s);
+ void set_short_c(const short& s);
+ void set_ushort(unsigned short us);
+ void set_ushort_c(const unsigned short& us);
+ void set_int(int i);
+ void set_int_c(const int& i);
+ void set_uint(unsigned int ui);
+ void set_uint_c(const unsigned int& ui);
+ void set_long(long l);
+ void set_long_c(const long& l);
+ void set_llong(long long ll);
+ void set_llong_c(const long long& ll);
+ void set_ulong(unsigned long ul);
+ void set_ulong_c(const unsigned long& ul);
+ void set_ullong(unsigned long long ll);
+ void set_ullong_c(const unsigned long long& ll);
+ void set_float(float f);
+ void set_float_c(const float& f);
+ void set_double(double d);
+ void set_double_c(const double& d);
+ void set_enum(what w);
+
+ void set_pod_val(cppyy_test_pod);
+ void set_pod_ptr_in(cppyy_test_pod*);
+ void set_pod_ptr_out(cppyy_test_pod*);
+ void set_pod_ref(const cppyy_test_pod&);
+ void set_pod_ptrptr_in(cppyy_test_pod**);
+ void set_pod_void_ptrptr_in(void**);
+ void set_pod_ptrptr_out(cppyy_test_pod**);
+ void set_pod_void_ptrptr_out(void**);
+
+public:
+// basic types
+ bool m_bool;
+ char m_char;
+ unsigned char m_uchar;
+ short m_short;
+ unsigned short m_ushort;
+ int m_int;
+ unsigned int m_uint;
+ long m_long;
+ unsigned long m_ulong;
+ long long m_llong;
+ unsigned long long m_ullong;
+ float m_float;
+ double m_double;
+ what m_enum;
+
+// array types
+ short m_short_array[N];
+ short* m_short_array2;
+ unsigned short m_ushort_array[N];
+ unsigned short* m_ushort_array2;
+ int m_int_array[N];
+ int* m_int_array2;
+ unsigned int m_uint_array[N];
+ unsigned int* m_uint_array2;
+ long m_long_array[N];
+ long* m_long_array2;
+ unsigned long m_ulong_array[N];
+ unsigned long* m_ulong_array2;
+
+ float m_float_array[N];
+ float* m_float_array2;
+ double m_double_array[N];
+ double* m_double_array2;
+
+// object types
+ cppyy_test_pod m_pod;
+ cppyy_test_pod* m_ppod;
+
+public:
+ static char s_char;
+ static unsigned char s_uchar;
+ static short s_short;
+ static unsigned short s_ushort;
+ static int s_int;
+ static unsigned int s_uint;
+ static long s_long;
+ static unsigned long s_ulong;
+ static long long s_llong;
+ static unsigned long long s_ullong;
+ static float s_float;
+ static double s_double;
+ static what s_enum;
+
+private:
+ bool m_owns_arrays;
+};
+
+
+//= global functions ========================================================
+long get_pod_address(cppyy_test_data& c);
+long get_int_address(cppyy_test_data& c);
+long get_double_address(cppyy_test_data& c);
+
+
+//= global variables/pointers ===============================================
+extern int g_int;
+void set_global_int(int i);
+int get_global_int();
+
+extern cppyy_test_pod* g_pod;
+bool is_global_pod(cppyy_test_pod* t);
+void set_global_pod(cppyy_test_pod* t);
+cppyy_test_pod* get_global_pod();
diff --git a/pypy/module/cppyy/test/datatypes.xml b/pypy/module/cppyy/test/datatypes.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.xml
@@ -0,0 +1,14 @@
+<lcgdict>
+
+ <class pattern="cppyy_test_*" />
+
+ <function pattern="get_*" />
+ <function pattern="set_*" />
+ <function pattern="is_*" />
+
+ <variable name="N" />
+
+ <variable name="g_int" />
+ <variable name="g_pod" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/datatypes_LinkDef.h b/pypy/module/cppyy/test/datatypes_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes_LinkDef.h
@@ -0,0 +1,24 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ struct cppyy_test_pod;
+#pragma link C++ class cppyy_test_data;
+
+#pragma link C++ function get_pod_address(cppyy_test_data&);
+#pragma link C++ function get_int_address(cppyy_test_data&);
+#pragma link C++ function get_double_address(cppyy_test_data&);
+#pragma link C++ function set_global_int(int);
+#pragma link C++ function get_global_int();
+
+#pragma link C++ function is_global_pod(cppyy_test_pod*);
+#pragma link C++ function set_global_pod(cppyy_test_pod*);
+#pragma link C++ function get_global_pod();
+
+#pragma link C++ global N;
+#pragma link C++ global g_int;
+#pragma link C++ global g_pod;
+
+#endif
diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01.cxx
@@ -0,0 +1,209 @@
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <stdlib.h>
+#include <string.h>
+
+#include "example01.h"
+
+//===========================================================================
+payload::payload(double d) : m_data(d) {
+ count++;
+}
+payload::payload(const payload& p) : m_data(p.m_data) {
+ count++;
+}
+payload& payload::operator=(const payload& p) {
+ if (this != &p) {
+ m_data = p.m_data;
+ }
+ return *this;
+}
+payload::~payload() {
+ count--;
+}
+
+double payload::getData() { return m_data; }
+void payload::setData(double d) { m_data = d; }
+
+// class-level data
+int payload::count = 0;
+
+
+//===========================================================================
+example01::example01() : m_somedata(-99) {
+ count++;
+}
+example01::example01(int a) : m_somedata(a) {
+ count++;
+}
+example01::example01(const example01& e) : m_somedata(e.m_somedata) {
+ count++;
+}
+example01& example01::operator=(const example01& e) {
+ if (this != &e) {
+ m_somedata = e.m_somedata;
+ }
+ return *this;
+}
+example01::~example01() {
+ count--;
+}
+
+// class-level methods
+int example01::staticAddOneToInt(int a) {
+ return a + 1;
+}
+int example01::staticAddOneToInt(int a, int b) {
+ return a + b + 1;
+}
+double example01::staticAddToDouble(double a) {
+ return a + 0.01;
+}
+int example01::staticAtoi(const char* str) {
+ return ::atoi(str);
+}
+char* example01::staticStrcpy(const char* strin) {
+ char* strout = (char*)malloc(::strlen(strin)+1);
+ ::strcpy(strout, strin);
+ return strout;
+}
+void example01::staticSetPayload(payload* p, double d) {
+ p->setData(d);
+}
+
+payload* example01::staticCyclePayload(payload* p, double d) {
+ staticSetPayload(p, d);
+ return p;
+}
+
+payload example01::staticCopyCyclePayload(payload* p, double d) {
+ staticSetPayload(p, d);
+ return *p;
+}
+
+int example01::getCount() {
+ return count;
+}
+
+void example01::setCount(int value) {
+ count = value;
+}
+
+// instance methods
+int example01::addDataToInt(int a) {
+ return m_somedata + a;
+}
+
+int example01::addDataToIntConstRef(const int& a) {
+ return m_somedata + a;
+}
+
+int example01::overloadedAddDataToInt(int a, int b) {
+ return m_somedata + a + b;
+}
+
+int example01::overloadedAddDataToInt(int a) {
+ return m_somedata + a;
+}
+
+int example01::overloadedAddDataToInt(int a, int b, int c) {
+ return m_somedata + a + b + c;
+}
+
+double example01::addDataToDouble(double a) {
+ return m_somedata + a;
+}
+
+int example01::addDataToAtoi(const char* str) {
+ return ::atoi(str) + m_somedata;
+}
+
+char* example01::addToStringValue(const char* str) {
+ int out = ::atoi(str) + m_somedata;
+ std::ostringstream ss;
+ ss << out << std::ends;
+ std::string result = ss.str();
+ char* cresult = (char*)malloc(result.size()+1);
+ ::strcpy(cresult, result.c_str());
+ return cresult;
+}
+
+void example01::setPayload(payload* p) {
+ p->setData(m_somedata);
+}
+
+payload* example01::cyclePayload(payload* p) {
+ setPayload(p);
+ return p;
+}
+
+payload example01::copyCyclePayload(payload* p) {
+ setPayload(p);
+ return *p;
+}
+
+// class-level data
+int example01::count = 0;
+
+
+// global
+int globalAddOneToInt(int a) {
+ return a + 1;
+}
+
+int ns_example01::globalAddOneToInt(int a) {
+ return ::globalAddOneToInt(a);
+}
+
+
+// argument passing
+#define typeValueImp(itype, tname) \
+itype ArgPasser::tname##Value(itype arg0, int argn, itype arg1, itype arg2) \
+{ \
+ switch (argn) { \
+ case 0: \
+ return arg0; \
+ case 1: \
+ return arg1; \
+ case 2: \
+ return arg2; \
+ default: \
+ break; \
+ } \
+ \
+ return (itype)-1; \
+}
+
+typeValueImp(short, short)
+typeValueImp(unsigned short, ushort)
+typeValueImp(int, int)
+typeValueImp(unsigned int, uint)
+typeValueImp(long, long)
+typeValueImp(unsigned long, ulong)
+
+typeValueImp(float, float)
+typeValueImp(double, double)
+
+std::string ArgPasser::stringValue(std::string arg0, int argn, std::string arg1)
+{
+ switch (argn) {
+ case 0:
+ return arg0;
+ case 1:
+ return arg1;
+ default:
+ break;
+ }
+
+ return "argn invalid";
+}
+
+std::string ArgPasser::stringRef(const std::string& arg0, int argn, const std::string& arg1)
+{
+ return stringValue(arg0, argn, arg1);
+}
+
+
+// special case naming
+z_& z_::gime_z_(z_& z) { return z; }
diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01.h
@@ -0,0 +1,111 @@
+#include <string>
+
+class payload {
+public:
+ payload(double d = 0.);
+ payload(const payload& p);
+ payload& operator=(const payload& e);
+ ~payload();
+
+ double getData();
+ void setData(double d);
+
+public: // class-level data
+ static int count;
+
+private:
+ double m_data;
+};
+
+
+class example01 {
+public:
+ example01();
+ example01(int a);
+ example01(const example01& e);
+ example01& operator=(const example01& e);
+ virtual ~example01();
+
+public: // class-level methods
+ static int staticAddOneToInt(int a);
+ static int staticAddOneToInt(int a, int b);
+ static double staticAddToDouble(double a);
+ static int staticAtoi(const char* str);
+ static char* staticStrcpy(const char* strin);
+ static void staticSetPayload(payload* p, double d);
+ static payload* staticCyclePayload(payload* p, double d);
+ static payload staticCopyCyclePayload(payload* p, double d);
+ static int getCount();
+ static void setCount(int);
+
+public: // instance methods
+ int addDataToInt(int a);
+ int addDataToIntConstRef(const int& a);
+ int overloadedAddDataToInt(int a, int b);
+ int overloadedAddDataToInt(int a);
+ int overloadedAddDataToInt(int a, int b, int c);
+ double addDataToDouble(double a);
+ int addDataToAtoi(const char* str);
+ char* addToStringValue(const char* str);
+
+ void setPayload(payload* p);
+ payload* cyclePayload(payload* p);
+ payload copyCyclePayload(payload* p);
+
+public: // class-level data
+ static int count;
+
+public: // instance data
+ int m_somedata;
+};
+
+
+// global functions
+int globalAddOneToInt(int a);
+namespace ns_example01 {
+ int globalAddOneToInt(int a);
+}
+
+#define itypeValue(itype, tname) \
+ itype tname##Value(itype arg0, int argn=0, itype arg1=1, itype arg2=2)
+
+#define ftypeValue(ftype) \
+ ftype ftype##Value(ftype arg0, int argn=0, ftype arg1=1., ftype arg2=2.)
+
+// argument passing
+class ArgPasser { // use a class for now as methptrgetter not
+public: // implemented for global functions
+ itypeValue(short, short);
+ itypeValue(unsigned short, ushort);
+ itypeValue(int, int);
+ itypeValue(unsigned int, uint);
+ itypeValue(long, long);
+ itypeValue(unsigned long, ulong);
+
+ ftypeValue(float);
+ ftypeValue(double);
+
+ std::string stringValue(
+ std::string arg0, int argn=0, std::string arg1 = "default");
+
+ std::string stringRef(
+ const std::string& arg0, int argn=0, const std::string& arg1="default");
+};
+
+
+// typedefs
+typedef example01 example01_t;
+
+
+// special case naming
+class z_ {
+public:
+ z_& gime_z_(z_& z);
+ int myint;
+};
+
+// for pythonization checking
+class example01a : public example01 {
+public:
+ example01a(int a) : example01(a) {}
+};
diff --git a/pypy/module/cppyy/test/example01.xml b/pypy/module/cppyy/test/example01.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01.xml
@@ -0,0 +1,17 @@
+<lcgdict>
+
+ <class name="payload" />
+ <class name="example01" />
+ <class name="example01_t" />
+ <class name="example01a" />
+ <class name="std::string" />
+ <class name="z_" />
+
+ <function name="globalAddOneToInt" />
+
+ <namespace name="ns_example01" />
+ <function name="ns_example01::globalAddOneToInt" />
+
+ <class name="ArgPasser" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/example01_LinkDef.h b/pypy/module/cppyy/test/example01_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01_LinkDef.h
@@ -0,0 +1,19 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class example01;
+#pragma link C++ typedef example01_t;
+#pragma link C++ class example01a;
+#pragma link C++ class payload;
+#pragma link C++ class ArgPasser;
+#pragma link C++ class z_;
+
+#pragma link C++ function globalAddOneToInt(int);
+
+#pragma link C++ namespace ns_example01;
+#pragma link C++ function ns_example01::globalAddOneToInt(int);
+
+#endif
diff --git a/pypy/module/cppyy/test/fragile.cxx b/pypy/module/cppyy/test/fragile.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile.cxx
@@ -0,0 +1,11 @@
+#include "fragile.h"
+
+fragile::H::HH* fragile::H::HH::copy() {
+ return (HH*)0;
+}
+
+fragile::I fragile::gI;
+
+void fragile::fglobal(int, double, char) {
+ /* empty; only used for doc-string testing */
+}
diff --git a/pypy/module/cppyy/test/fragile.h b/pypy/module/cppyy/test/fragile.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile.h
@@ -0,0 +1,80 @@
+namespace fragile {
+
+class no_such_class;
+
+class A {
+public:
+ virtual int check() { return (int)'A'; }
+ virtual A* gime_null() { return (A*)0; }
+};
+
+class B {
+public:
+ virtual int check() { return (int)'B'; }
+ no_such_class* gime_no_such() { return 0; }
+};
+
+class C {
+public:
+ virtual int check() { return (int)'C'; }
+ void use_no_such(no_such_class*) {}
+};
+
+class D {
+public:
+ virtual int check() { return (int)'D'; }
+ void overload() {}
+ void overload(no_such_class*) {}
+ void overload(char, int i = 0) {} // Reflex requires a named arg
+ void overload(int, no_such_class* p = 0) {}
+};
+
+class E {
+public:
+ E() : m_pp_no_such(0), m_pp_a(0) {}
+
+ virtual int check() { return (int)'E'; }
+ void overload(no_such_class**) {}
+
+ no_such_class** m_pp_no_such;
+ A** m_pp_a;
+};
+
+class F {
+public:
+ F() : m_int(0) {}
+ virtual int check() { return (int)'F'; }
+ int m_int;
+};
+
+class G {
+public:
+ enum { unnamed1=24, unnamed2=96 };
+
+ class GG {};
+};
+
+class H {
+public:
+ class HH {
+ public:
+ HH* copy();
+ };
+ HH* m_h;
+};
+
+class I {
+public:
+ operator bool() { return 0; }
+};
+
+extern I gI;
+
+class J {
+public:
+ int method1(int, double) { return 0; }
+};
+
+void fglobal(int, double, char);
+
+} // namespace fragile
diff --git a/pypy/module/cppyy/test/fragile.xml b/pypy/module/cppyy/test/fragile.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile.xml
@@ -0,0 +1,11 @@
+<lcgdict>
+
+ <namespace name="fragile" />
+
+ <class pattern="fragile::[A-Z]" />
+
+ <variable name="fragile::gI" />
+
+ <function pattern="fragile::f*" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/fragile_LinkDef.h b/pypy/module/cppyy/test/fragile_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/fragile_LinkDef.h
@@ -0,0 +1,24 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ namespace fragile;
+
+#pragma link C++ class fragile::A;
+#pragma link C++ class fragile::B;
+#pragma link C++ class fragile::C;
+#pragma link C++ class fragile::D;
+#pragma link C++ class fragile::E;
+#pragma link C++ class fragile::F;
+#pragma link C++ class fragile::G;
+#pragma link C++ class fragile::H;
+#pragma link C++ class fragile::I;
+#pragma link C++ class fragile::J;
+
+#pragma link C++ variable fragile::gI;
+
+#pragma link C++ function fragile::fglobal;
+
+#endif
diff --git a/pypy/module/cppyy/test/operators.cxx b/pypy/module/cppyy/test/operators.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators.cxx
@@ -0,0 +1,1 @@
+#include "operators.h"
diff --git a/pypy/module/cppyy/test/operators.h b/pypy/module/cppyy/test/operators.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators.h
@@ -0,0 +1,95 @@
+class number {
+public:
+ number() { m_int = 0; }
+ number(int i) { m_int = i; }
+
+ number operator+(const number& n) const { return number(m_int + n.m_int); }
+ number operator+(int n) const { return number(m_int + n); }
+ number operator-(const number& n) const { return number(m_int - n.m_int); }
+ number operator-(int n) const { return number(m_int - n); }
+ number operator*(const number& n) const { return number(m_int * n.m_int); }
+ number operator*(int n) const { return number(m_int * n); }
+ number operator/(const number& n) const { return number(m_int / n.m_int); }
+ number operator/(int n) const { return number(m_int / n); }
+ number operator%(const number& n) const { return number(m_int % n.m_int); }
+ number operator%(int n) const { return number(m_int % n); }
+
+ number& operator+=(const number& n) { m_int += n.m_int; return *this; }
+ number& operator-=(const number& n) { m_int -= n.m_int; return *this; }
+ number& operator*=(const number& n) { m_int *= n.m_int; return *this; }
+ number& operator/=(const number& n) { m_int /= n.m_int; return *this; }
+ number& operator%=(const number& n) { m_int %= n.m_int; return *this; }
+
+ number operator-() { return number( -m_int ); }
+
+ bool operator<(const number& n) const { return m_int < n.m_int; }
+ bool operator>(const number& n) const { return m_int > n.m_int; }
+ bool operator<=(const number& n) const { return m_int <= n.m_int; }
+ bool operator>=(const number& n) const { return m_int >= n.m_int; }
+ bool operator!=(const number& n) const { return m_int != n.m_int; }
+ bool operator==(const number& n) const { return m_int == n.m_int; }
+
+ operator bool() { return m_int != 0; }
+
+ number operator&(const number& n) const { return number(m_int & n.m_int); }
+ number operator|(const number& n) const { return number(m_int | n.m_int); }
+ number operator^(const number& n) const { return number(m_int ^ n.m_int); }
+
+ number& operator&=(const number& n) { m_int &= n.m_int; return *this; }
+ number& operator|=(const number& n) { m_int |= n.m_int; return *this; }
+ number& operator^=(const number& n) { m_int ^= n.m_int; return *this; }
+
+ number operator<<(int i) const { return number(m_int << i); }
+ number operator>>(int i) const { return number(m_int >> i); }
+
+private:
+ int m_int;
+};
+
+//----------------------------------------------------------------------------
+struct operator_char_star { // for testing user-defined implicit casts
+ operator_char_star() : m_str((char*)"operator_char_star") {}
+ operator char*() { return m_str; }
+ char* m_str;
+};
+
+struct operator_const_char_star {
+ operator_const_char_star() : m_str("operator_const_char_star" ) {}
+ operator const char*() { return m_str; }
+ const char* m_str;
+};
+
+struct operator_int {
+ operator int() { return m_int; }
+ int m_int;
+};
+
+struct operator_long {
+ operator long() { return m_long; }
+ long m_long;
+};
+
+struct operator_double {
+ operator double() { return m_double; }
+ double m_double;
+};
+
+struct operator_short {
+ operator short() { return m_short; }
+ unsigned short m_short;
+};
+
+struct operator_unsigned_int {
+ operator unsigned int() { return m_uint; }
+ unsigned int m_uint;
+};
+
+struct operator_unsigned_long {
+ operator unsigned long() { return m_ulong; }
+ unsigned long m_ulong;
+};
+
+struct operator_float {
+ operator float() { return m_float; }
+ float m_float;
+};
diff --git a/pypy/module/cppyy/test/operators.xml b/pypy/module/cppyy/test/operators.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators.xml
@@ -0,0 +1,6 @@
+<lcgdict>
+
+ <class name="number" />
+ <class pattern="operator_*" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/operators_LinkDef.h b/pypy/module/cppyy/test/operators_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/operators_LinkDef.h
@@ -0,0 +1,19 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class number;
+
+#pragma link C++ struct operator_char_star;
+#pragma link C++ struct operator_const_char_star;
+#pragma link C++ struct operator_int;
+#pragma link C++ struct operator_long;
+#pragma link C++ struct operator_double;
+#pragma link C++ struct operator_short;
+#pragma link C++ struct operator_unsigned_int;
+#pragma link C++ struct operator_unsigned_long;
+#pragma link C++ struct operator_float;
+
+#endif
diff --git a/pypy/module/cppyy/test/overloads.cxx b/pypy/module/cppyy/test/overloads.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads.cxx
@@ -0,0 +1,49 @@
+#include "overloads.h"
+
+
+a_overload::a_overload() { i1 = 42; i2 = -1; }
+
+ns_a_overload::a_overload::a_overload() { i1 = 88; i2 = -34; }
+int ns_a_overload::b_overload::f(const std::vector<int>* v) { return (*v)[0]; }
+
+ns_b_overload::a_overload::a_overload() { i1 = -33; i2 = 89; }
+
+b_overload::b_overload() { i1 = -2; i2 = 13; }
+
+c_overload::c_overload() {}
+int c_overload::get_int(a_overload* a) { return a->i1; }
+int c_overload::get_int(ns_a_overload::a_overload* a) { return a->i1; }
+int c_overload::get_int(ns_b_overload::a_overload* a) { return a->i1; }
+int c_overload::get_int(short* p) { return *p; }
+int c_overload::get_int(b_overload* b) { return b->i2; }
+int c_overload::get_int(int* p) { return *p; }
+
+d_overload::d_overload() {}
+int d_overload::get_int(int* p) { return *p; }
+int d_overload::get_int(b_overload* b) { return b->i2; }
+int d_overload::get_int(short* p) { return *p; }
+int d_overload::get_int(ns_b_overload::a_overload* a) { return a->i1; }
+int d_overload::get_int(ns_a_overload::a_overload* a) { return a->i1; }
+int d_overload::get_int(a_overload* a) { return a->i1; }
+
+
+more_overloads::more_overloads() {}
+std::string more_overloads::call(const aa_ol&) { return "aa_ol"; }
+std::string more_overloads::call(const bb_ol&, void* n) { n = 0; return "bb_ol"; }
+std::string more_overloads::call(const cc_ol&) { return "cc_ol"; }
+std::string more_overloads::call(const dd_ol&) { return "dd_ol"; }
+
+std::string more_overloads::call_unknown(const dd_ol&) { return "dd_ol"; }
+
+std::string more_overloads::call(double) { return "double"; }
+std::string more_overloads::call(int) { return "int"; }
+std::string more_overloads::call1(int) { return "int"; }
+std::string more_overloads::call1(double) { return "double"; }
+
+
+more_overloads2::more_overloads2() {}
+std::string more_overloads2::call(const bb_ol&) { return "bb_olref"; }
+std::string more_overloads2::call(const bb_ol*) { return "bb_olptr"; }
+
+std::string more_overloads2::call(const dd_ol*, int) { return "dd_olptr"; }
+std::string more_overloads2::call(const dd_ol&, int) { return "dd_olref"; }
diff --git a/pypy/module/cppyy/test/overloads.h b/pypy/module/cppyy/test/overloads.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads.h
@@ -0,0 +1,90 @@
+#include <string>
+#include <vector>
+
+class a_overload {
+public:
+ a_overload();
+ int i1, i2;
+};
+
+namespace ns_a_overload {
+ class a_overload {
+ public:
+ a_overload();
+ int i1, i2;
+ };
+
+ class b_overload {
+ public:
+ int f(const std::vector<int>* v);
+ };
+}
+
+namespace ns_b_overload {
+ class a_overload {
+ public:
+ a_overload();
+ int i1, i2;
+ };
+}
+
+class b_overload {
+public:
+ b_overload();
+ int i1, i2;
+};
+
+class c_overload {
+public:
+ c_overload();
+ int get_int(a_overload* a);
+ int get_int(ns_a_overload::a_overload* a);
+ int get_int(ns_b_overload::a_overload* a);
+ int get_int(short* p);
+ int get_int(b_overload* b);
+ int get_int(int* p);
+};
+
+class d_overload {
+public:
+ d_overload();
+// int get_int(void* p) { return *(int*)p; }
+ int get_int(int* p);
+ int get_int(b_overload* b);
+ int get_int(short* p);
+ int get_int(ns_b_overload::a_overload* a);
+ int get_int(ns_a_overload::a_overload* a);
+ int get_int(a_overload* a);
+};
+
+
+class aa_ol {};
+class bb_ol;
+class cc_ol {};
+class dd_ol;
+
+class more_overloads {
+public:
+ more_overloads();
+ std::string call(const aa_ol&);
+ std::string call(const bb_ol&, void* n=0);
+ std::string call(const cc_ol&);
+ std::string call(const dd_ol&);
+
+ std::string call_unknown(const dd_ol&);
+
+ std::string call(double);
+ std::string call(int);
+ std::string call1(int);
+ std::string call1(double);
+};
+
+class more_overloads2 {
+public:
+ more_overloads2();
+ std::string call(const bb_ol&);
+ std::string call(const bb_ol*);
+
+ std::string call(const dd_ol*, int);
+ std::string call(const dd_ol&, int);
+};
diff --git a/pypy/module/cppyy/test/overloads.xml b/pypy/module/cppyy/test/overloads.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads.xml
@@ -0,0 +1,14 @@
+<lcgdict>
+
+ <class name="std::string" />
+
+ <class pattern="*_overload" />
+
+ <namespace pattern="ns_*_overload" />
+ <class pattern="ns_*_overload::*_overload" />
+
+ <class pattern="*_ol" />
+ <class name="more_overloads" />
+ <class name="more_overloads2" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/overloads_LinkDef.h b/pypy/module/cppyy/test/overloads_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/overloads_LinkDef.h
@@ -0,0 +1,25 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class a_overload;
+#pragma link C++ class b_overload;
+#pragma link C++ class c_overload;
+#pragma link C++ class d_overload;
+
+#pragma link C++ namespace ns_a_overload;
+#pragma link C++ class ns_a_overload::a_overload;
+#pragma link C++ class ns_a_overload::b_overload;
+
+#pragma link C++ class ns_b_overload;
+#pragma link C++ class ns_b_overload::a_overload;
+
+#pragma link C++ class aa_ol;
+#pragma link C++ class cc_ol;
+
+#pragma link C++ class more_overloads;
+#pragma link C++ class more_overloads2;
+
+#endif
diff --git a/pypy/module/cppyy/test/std_streams.cxx b/pypy/module/cppyy/test/std_streams.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams.cxx
@@ -0,0 +1,3 @@
+#include "std_streams.h"
+
+template class std::basic_ios<char,std::char_traits<char> >;
diff --git a/pypy/module/cppyy/test/std_streams.h b/pypy/module/cppyy/test/std_streams.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams.h
@@ -0,0 +1,13 @@
+#ifndef STD_STREAMS_H
+#define STD_STREAMS_H 1
+
+#ifndef __CINT__
+#include <ios>
+#endif
+#include <iostream>
+
+#ifndef __CINT__
+extern template class std::basic_ios<char,std::char_traits<char> >;
+#endif
+
+#endif // STD_STREAMS_H
diff --git a/pypy/module/cppyy/test/std_streams.xml b/pypy/module/cppyy/test/std_streams.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams.xml
@@ -0,0 +1,7 @@
+<lcgdict>
+
+ <class name = "std::ostream"/>
+ <class name = "std::ios_base"/>
+ <class name = "std::basic_ios<char,std::char_traits<char> >"/>
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/std_streams_LinkDef.h b/pypy/module/cppyy/test/std_streams_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/std_streams_LinkDef.h
@@ -0,0 +1,9 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class std::ostream;
+
+#endif
diff --git a/pypy/module/cppyy/test/stltypes.cxx b/pypy/module/cppyy/test/stltypes.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes.cxx
@@ -0,0 +1,26 @@
+#include "stltypes.h"
+
+#define STLTYPES_EXPLICIT_INSTANTIATION(STLTYPE, TTYPE) \
+template class std::STLTYPE< TTYPE >; \
+template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >; \
+template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
+namespace __gnu_cxx { \
+template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \
+ const std::STLTYPE< TTYPE >::iterator&); \
+template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \
+ const std::STLTYPE< TTYPE >::iterator&); \
+}
+
+
+//- explicit instantiations of used types
+STLTYPES_EXPLICIT_INSTANTIATION(vector, int)
+STLTYPES_EXPLICIT_INSTANTIATION(vector, just_a_class)
+
+//- class with lots of std::string handling
+stringy_class::stringy_class(const char* s) : m_string(s) {}
+
+std::string stringy_class::get_string1() { return m_string; }
+void stringy_class::get_string2(std::string& s) { s = m_string; }
+
+void stringy_class::set_string1(const std::string& s) { m_string = s; }
+void stringy_class::set_string2(std::string s) { m_string = s; }
diff --git a/pypy/module/cppyy/test/stltypes.h b/pypy/module/cppyy/test/stltypes.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes.h
@@ -0,0 +1,44 @@
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE) \
+extern template class std::STLTYPE< TTYPE >; \
+extern template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >;\
+extern template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
+namespace __gnu_cxx { \
+extern template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \
+ const std::STLTYPE< TTYPE >::iterator&); \
+extern template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \
+ const std::STLTYPE< TTYPE >::iterator&); \
+}
+
+
+//- basic example class
+class just_a_class {
+public:
+ int m_i;
+};
+
+
+#ifndef __CINT__
+//- explicit instantiations of used types
+STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, int)
+STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, just_a_class)
+#endif
+
+
+//- class with lots of std::string handling
+class stringy_class {
+public:
+ stringy_class(const char* s);
+
+ std::string get_string1();
+ void get_string2(std::string& s);
+
+ void set_string1(const std::string& s);
+ void set_string2(std::string s);
+
+ std::string m_string;
+};
diff --git a/pypy/module/cppyy/test/stltypes.xml b/pypy/module/cppyy/test/stltypes.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes.xml
@@ -0,0 +1,20 @@
+<lcgdict>
+
+ <namespace name="std" />
+
+ <class pattern="std::vector<*>" />
+ <class pattern="__gnu_cxx::__normal_iterator<*>" />
+ <class pattern="__gnu_cxx::new_allocator<*>" />
+ <class pattern="std::_Vector_base<*>" />
+ <class pattern="std::_Vector_base<*>::_Vector_impl" />
+ <class pattern="std::allocator<*>" />
+
+ <function name="__gnu_cxx::operator=="/>
+ <function name="__gnu_cxx::operator!="/>
+
+ <class name="just_a_class" />
+
+ <class name="std::string" />
+ <class name="stringy_class" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/stltypes_LinkDef.h b/pypy/module/cppyy/test/stltypes_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/stltypes_LinkDef.h
@@ -0,0 +1,14 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class std::vector<just_a_class>;
+#pragma link C++ class std::vector<just_a_class>::iterator;
+#pragma link C++ class std::vector<just_a_class>::const_iterator;
+
+#pragma link C++ class just_a_class;
+#pragma link C++ class stringy_class;
+
+#endif
diff --git a/pypy/module/cppyy/test/test_aclassloader.py b/pypy/module/cppyy/test/test_aclassloader.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_aclassloader.py
@@ -0,0 +1,26 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ err = os.system("cd '%s' && make example01Dict.so" % currpath)
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+
+class AppTestACLASSLOADER:
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=['cppyy'])
+
+ def test01_class_autoloading(self):
+ """Test whether a class can be found through .rootmap."""
+ import cppyy
+ example01_class = cppyy.gbl.example01
+ assert example01_class
+ cl2 = cppyy.gbl.example01
+ assert cl2
+ assert example01_class is cl2
diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_advancedcpp.py
@@ -0,0 +1,489 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+from pypy.module.cppyy import capi
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("advancedcppDict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ for refl_dict in ["advancedcppDict.so", "advancedcpp2Dict.so"]:
+ err = os.system("cd '%s' && make %s" % (currpath, refl_dict))
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+class AppTestADVANCEDCPP:
+ def setup_class(cls):
+ cls.space = space
+ env = os.environ
+ cls.w_test_dct = space.wrap(test_dct)
+ cls.w_capi_identity = space.wrap(capi.identify())
+ cls.w_advanced = cls.space.appexec([], """():
+ import cppyy
+ return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+ def test01_default_arguments(self):
+ """Test usage of default arguments"""
+
+ import cppyy
+ defaulter = cppyy.gbl.defaulter
+
+ d = defaulter()
+ assert d.m_a == 11
+ assert d.m_b == 22
+ assert d.m_c == 33
+ d.destruct()
+
+ d = defaulter(0)
+ assert d.m_a == 0
+ assert d.m_b == 22
+ assert d.m_c == 33
+ d.destruct()
+
+ d = defaulter(1, 2)
+ assert d.m_a == 1
+ assert d.m_b == 2
+ assert d.m_c == 33
+ d.destruct()
+
+ d = defaulter(3, 4, 5)
+ assert d.m_a == 3
+ assert d.m_b == 4
+ assert d.m_c == 5
+ d.destruct()
+
+ def test02_simple_inheritance(self):
+ """Test binding of a basic inheritance structure"""
+
+ import cppyy
+ base_class = cppyy.gbl.base_class
+ derived_class = cppyy.gbl.derived_class
+
+ assert issubclass(derived_class, base_class)
+ assert not issubclass(base_class, derived_class)
+
+ b = base_class()
+ assert isinstance(b, base_class)
+ assert not isinstance(b, derived_class)
+
+ assert b.m_b == 1
+ assert b.get_value() == 1
+ assert b.m_db == 1.1
+ assert b.get_base_value() == 1.1
+
+ b.m_b, b.m_db = 11, 11.11
+ assert b.m_b == 11
+ assert b.get_value() == 11
+ assert b.m_db == 11.11
+ assert b.get_base_value() == 11.11
+
+ b.destruct()
+
+ d = derived_class()
+ assert isinstance(d, derived_class)
+ assert isinstance(d, base_class)
+
+ assert d.m_d == 2
+ assert d.get_value() == 2
+ assert d.m_dd == 2.2
+ assert d.get_derived_value() == 2.2
+
+ assert d.m_b == 1
+ assert d.m_db == 1.1
+ assert d.get_base_value() == 1.1
+
+ d.m_b, d.m_db = 11, 11.11
+ d.m_d, d.m_dd = 22, 22.22
+
+ assert d.m_d == 22
+ assert d.get_value() == 22
+ assert d.m_dd == 22.22
+ assert d.get_derived_value() == 22.22
+
+ assert d.m_b == 11
+ assert d.m_db == 11.11
+ assert d.get_base_value() == 11.11
+
+ d.destruct()
+
+ def test03_namespaces(self):
+ """Test access to namespaces and inner classes"""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ assert gbl.a_ns is gbl.a_ns
+ assert gbl.a_ns.d_ns is gbl.a_ns.d_ns
+
+ assert gbl.a_ns.b_class is gbl.a_ns.b_class
+ assert gbl.a_ns.b_class.c_class is gbl.a_ns.b_class.c_class
+ assert gbl.a_ns.d_ns.e_class is gbl.a_ns.d_ns.e_class
+ assert gbl.a_ns.d_ns.e_class.f_class is gbl.a_ns.d_ns.e_class.f_class
+
+ assert gbl.a_ns.g_a == 11
+ assert gbl.a_ns.get_g_a() == 11
+ assert gbl.a_ns.b_class.s_b == 22
+ assert gbl.a_ns.b_class().m_b == -2
+ assert gbl.a_ns.b_class.c_class.s_c == 33
+ assert gbl.a_ns.b_class.c_class().m_c == -3
+ assert gbl.a_ns.d_ns.g_d == 44
+ assert gbl.a_ns.d_ns.get_g_d() == 44
+ assert gbl.a_ns.d_ns.e_class.s_e == 55
+ assert gbl.a_ns.d_ns.e_class().m_e == -5
+ assert gbl.a_ns.d_ns.e_class.f_class.s_f == 66
+ assert gbl.a_ns.d_ns.e_class.f_class().m_f == -6
+
+ def test03a_namespace_lookup_on_update(self):
+ """Test whether namespaces can be shared across dictionaries."""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ lib2 = cppyy.load_reflection_info("advancedcpp2Dict.so")
+
+ assert gbl.a_ns is gbl.a_ns
+ assert gbl.a_ns.d_ns is gbl.a_ns.d_ns
+
+ assert gbl.a_ns.g_class is gbl.a_ns.g_class
+ assert gbl.a_ns.g_class.h_class is gbl.a_ns.g_class.h_class
+ assert gbl.a_ns.d_ns.i_class is gbl.a_ns.d_ns.i_class
+ assert gbl.a_ns.d_ns.i_class.j_class is gbl.a_ns.d_ns.i_class.j_class
+
+ assert gbl.a_ns.g_g == 77
+ assert gbl.a_ns.get_g_g() == 77
+ assert gbl.a_ns.g_class.s_g == 88
+ assert gbl.a_ns.g_class().m_g == -7
+ assert gbl.a_ns.g_class.h_class.s_h == 99
+ assert gbl.a_ns.g_class.h_class().m_h == -8
+ assert gbl.a_ns.d_ns.g_i == 111
+ assert gbl.a_ns.d_ns.get_g_i() == 111
+ assert gbl.a_ns.d_ns.i_class.s_i == 222
+ assert gbl.a_ns.d_ns.i_class().m_i == -9
+ assert gbl.a_ns.d_ns.i_class.j_class.s_j == 333
+ assert gbl.a_ns.d_ns.i_class.j_class().m_j == -10
+
+ def test04_template_types(self):
+ """Test bindings of templated types"""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ assert gbl.T1 is gbl.T1
+ assert gbl.T2 is gbl.T2
+ assert gbl.T3 is gbl.T3
+ assert not gbl.T1 is gbl.T2
+ assert not gbl.T2 is gbl.T3
+
+ assert gbl.T1('int') is gbl.T1('int')
+ assert gbl.T1(int) is gbl.T1('int')
+ assert gbl.T2('T1<int>') is gbl.T2('T1<int>')
+ assert gbl.T2(gbl.T1('int')) is gbl.T2('T1<int>')
+ assert gbl.T2(gbl.T1(int)) is gbl.T2('T1<int>')
+ assert gbl.T3('int,double') is gbl.T3('int,double')
+ assert gbl.T3('int', 'double') is gbl.T3('int,double')
+ assert gbl.T3(int, 'double') is gbl.T3('int,double')
+ assert gbl.T3('T1<int>,T2<T1<int> >') is gbl.T3('T1<int>,T2<T1<int> >')
+ assert gbl.T3('T1<int>', gbl.T2(gbl.T1(int))) is gbl.T3('T1<int>,T2<T1<int> >')
+
+ assert gbl.a_ns.T4(int) is gbl.a_ns.T4('int')
+ assert gbl.a_ns.T4('a_ns::T4<T3<int,double> >')\
+ is gbl.a_ns.T4(gbl.a_ns.T4(gbl.T3(int, 'double')))
+
+ #-----
+ t1 = gbl.T1(int)()
+ assert t1.m_t1 == 1
+ assert t1.value() == 1
+ t1.destruct()
+
+ #-----
+ t1 = gbl.T1(int)(11)
+ assert t1.m_t1 == 11
+ assert t1.value() == 11
+ t1.m_t1 = 111
+ assert t1.value() == 111
+ assert t1.m_t1 == 111
+ t1.destruct()
+
+ #-----
+ t2 = gbl.T2(gbl.T1(int))(gbl.T1(int)(32))
+ t2.m_t2.m_t1 = 32
+ assert t2.m_t2.value() == 32
+ assert t2.m_t2.m_t1 == 32
+ t2.destruct()
+
+ def test05_abstract_classes(self):
+ """Test non-instatiatability of abstract classes"""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ raises(TypeError, gbl.a_class)
+ raises(TypeError, gbl.some_abstract_class)
+
+ assert issubclass(gbl.some_concrete_class, gbl.some_abstract_class)
+
+ c = gbl.some_concrete_class()
+ assert isinstance(c, gbl.some_concrete_class)
+ assert isinstance(c, gbl.some_abstract_class)
+
+ def test06_datamembers(self):
+ """Test data member access when using virtual inheritence"""
+
+ import cppyy
+ a_class = cppyy.gbl.a_class
+ b_class = cppyy.gbl.b_class
+ c_class_1 = cppyy.gbl.c_class_1
+ c_class_2 = cppyy.gbl.c_class_2
+ d_class = cppyy.gbl.d_class
+
+ assert issubclass(b_class, a_class)
+ assert issubclass(c_class_1, a_class)
+ assert issubclass(c_class_1, b_class)
+ assert issubclass(c_class_2, a_class)
+ assert issubclass(c_class_2, b_class)
+ assert issubclass(d_class, a_class)
+ assert issubclass(d_class, b_class)
+ assert issubclass(d_class, c_class_2)
+
+ #-----
+ b = b_class()
+ assert b.m_a == 1
+ assert b.m_da == 1.1
+ assert b.m_b == 2
+ assert b.m_db == 2.2
+
+ b.m_a = 11
+ assert b.m_a == 11
+ assert b.m_b == 2
+
+ b.m_da = 11.11
+ assert b.m_da == 11.11
+ assert b.m_db == 2.2
+
+ b.m_b = 22
+ assert b.m_a == 11
+ assert b.m_da == 11.11
+ assert b.m_b == 22
+ assert b.get_value() == 22
+
+ b.m_db = 22.22
+ assert b.m_db == 22.22
+
+ b.destruct()
+
+ #-----
+ c1 = c_class_1()
+ assert c1.m_a == 1
+ assert c1.m_b == 2
+ assert c1.m_c == 3
+
+ c1.m_a = 11
+ assert c1.m_a == 11
+
+ c1.m_b = 22
+ assert c1.m_a == 11
+ assert c1.m_b == 22
+
+ c1.m_c = 33
+ assert c1.m_a == 11
+ assert c1.m_b == 22
+ assert c1.m_c == 33
+ assert c1.get_value() == 33
+
+ c1.destruct()
+
+ #-----
+ d = d_class()
+ assert d.m_a == 1
+ assert d.m_b == 2
+ assert d.m_c == 3
+ assert d.m_d == 4
+
+ d.m_a = 11
+ assert d.m_a == 11
+
+ d.m_b = 22
+ assert d.m_a == 11
+ assert d.m_b == 22
+
+ d.m_c = 33
+ assert d.m_a == 11
+ assert d.m_b == 22
+ assert d.m_c == 33
+
+ d.m_d = 44
+ assert d.m_a == 11
+ assert d.m_b == 22
+ assert d.m_c == 33
+ assert d.m_d == 44
+ assert d.get_value() == 44
+
+ d.destruct()
+
+ def test07_pass_by_reference(self):
+ """Test reference passing when using virtual inheritance"""
+
+ import cppyy
+ gbl = cppyy.gbl
+ b_class = gbl.b_class
+ c_class = gbl.c_class_2
+ d_class = gbl.d_class
+
+ #-----
+ b = b_class()
+ b.m_a, b.m_b = 11, 22
+ assert gbl.get_a(b) == 11
+ assert gbl.get_b(b) == 22
+ b.destruct()
+
+ #-----
+ c = c_class()
+ c.m_a, c.m_b, c.m_c = 11, 22, 33
+ assert gbl.get_a(c) == 11
+ assert gbl.get_b(c) == 22
+ assert gbl.get_c(c) == 33
+ c.destruct()
+
+ #-----
+ d = d_class()
+ d.m_a, d.m_b, d.m_c, d.m_d = 11, 22, 33, 44
+ assert gbl.get_a(d) == 11
+ assert gbl.get_b(d) == 22
+ assert gbl.get_c(d) == 33
+ assert gbl.get_d(d) == 44
+ d.destruct()
+
+ def test08_void_pointer_passing(self):
+ """Test passing of variants of void pointer arguments"""
+
+ import cppyy
+ pointer_pass = cppyy.gbl.pointer_pass
+ some_concrete_class = cppyy.gbl.some_concrete_class
+
+ pp = pointer_pass()
+ o = some_concrete_class()
+
+ assert cppyy.addressof(o) == pp.gime_address_ptr(o)
+ assert cppyy.addressof(o) == pp.gime_address_ptr_ptr(o)
+ assert cppyy.addressof(o) == pp.gime_address_ptr_ref(o)
+
+ def test09_opaque_pointer_assing(self):
+ """Test passing around of opaque pointers"""
+
+ import cppyy
+ some_concrete_class = cppyy.gbl.some_concrete_class
+
+ o = some_concrete_class()
+
+ #cobj = cppyy.as_cobject(o)
+ addr = cppyy.addressof(o)
+
+ #assert o == cppyy.bind_object(cobj, some_concrete_class)
+ #assert o == cppyy.bind_object(cobj, type(o))
+ #assert o == cppyy.bind_object(cobj, o.__class__)
+ #assert o == cppyy.bind_object(cobj, "some_concrete_class")
+ assert cppyy.addressof(o) == cppyy.addressof(cppyy.bind_object(addr, some_concrete_class))
+ assert o == cppyy.bind_object(addr, some_concrete_class)
+ assert o == cppyy.bind_object(addr, type(o))
+ assert o == cppyy.bind_object(addr, o.__class__)
+ #assert o == cppyy.bind_object(addr, "some_concrete_class")
+
+ def test10_object_identity(self):
+ """Test object identity"""
+
+ import cppyy
+ some_concrete_class = cppyy.gbl.some_concrete_class
+ some_class_with_data = cppyy.gbl.some_class_with_data
+
+ o = some_concrete_class()
+ addr = cppyy.addressof(o)
+
+ o2 = cppyy.bind_object(addr, some_concrete_class)
+ assert o is o2
+
+ o3 = cppyy.bind_object(addr, some_class_with_data)
+ assert not o is o3
+
+ d1 = some_class_with_data()
+ d2 = d1.gime_copy()
+ assert not d1 is d2
+
+ dd1a = d1.gime_data()
+ dd1b = d1.gime_data()
+ assert dd1a is dd1b
+
+ dd2 = d2.gime_data()
+ assert not dd1a is dd2
+ assert not dd1b is dd2
+
+ d2.destruct()
+ d1.destruct()
+
+ def test11_multi_methods(self):
+ """Test calling of methods from multiple inheritance"""
+
+ import cppyy
+ multi = cppyy.gbl.multi
+
+ assert cppyy.gbl.multi1 is multi.__bases__[0]
+ assert cppyy.gbl.multi2 is multi.__bases__[1]
+
+ dict_keys = multi.__dict__.keys()
+ assert dict_keys.count('get_my_own_int') == 1
+ assert dict_keys.count('get_multi1_int') == 0
+ assert dict_keys.count('get_multi2_int') == 0
+
+ m = multi(1, 2, 3)
+ assert m.get_multi1_int() == 1
+ assert m.get_multi2_int() == 2
+ assert m.get_my_own_int() == 3
+
+ def test12_actual_type(self):
+ """Test that a pointer to base return does an auto-downcast"""
+
+ import cppyy
+ base_class = cppyy.gbl.base_class
+ derived_class = cppyy.gbl.derived_class
+
+ b = base_class()
+ d = derived_class()
+
+ assert b == b.cycle(b)
+ assert id(b) == id(b.cycle(b))
+ assert b == d.cycle(b)
+ assert id(b) == id(d.cycle(b))
+ assert d == b.cycle(d)
+ assert id(d) == id(b.cycle(d))
+ assert d == d.cycle(d)
+ assert id(d) == id(d.cycle(d))
+
+ assert isinstance(b.cycle(b), base_class)
+ assert isinstance(d.cycle(b), base_class)
+ assert isinstance(b.cycle(d), derived_class)
+ assert isinstance(d.cycle(d), derived_class)
+
+ assert isinstance(b.clone(), base_class) # TODO: clone() leaks
+ assert isinstance(d.clone(), derived_class) # TODO: clone() leaks
+
+ def test13_actual_type_virtual_multi(self):
+ """Test auto-downcast in adverse inheritance situation"""
+
+ import cppyy
+
+ c1 = cppyy.gbl.create_c1()
+ assert type(c1) == cppyy.gbl.c_class_1
+ assert c1.m_c == 3
+ c1.destruct()
+
+ if self.capi_identity == 'CINT': # CINT does not support dynamic casts
+ return
+
+ c2 = cppyy.gbl.create_c2()
+ assert type(c2) == cppyy.gbl.c_class_2
+ assert c2.m_c == 3
+ c2.destruct()
diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_cppyy.py
@@ -0,0 +1,248 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+from pypy.module.cppyy import interp_cppyy, executor
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("example01Dict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ err = os.system("cd '%s' && make example01Dict.so" % currpath)
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+class TestCPPYYImplementation:
+ def test01_class_query(self):
+ # NOTE: this test needs to run before test_pythonify.py
+ dct = interp_cppyy.load_dictionary(space, test_dct)
+ w_cppyyclass = interp_cppyy.scope_byname(space, "example01")
+ w_cppyyclass2 = interp_cppyy.scope_byname(space, "example01")
+ assert space.is_w(w_cppyyclass, w_cppyyclass2)
+ adddouble = w_cppyyclass.methods["staticAddToDouble"]
+ func, = adddouble.functions
+ assert func.executor is None
+ func._setup(None) # creates executor
+ assert isinstance(func.executor, executor.DoubleExecutor)
+ assert func.arg_defs == [("double", "")]
+
+
+class AppTestCPPYY:
+ def setup_class(cls):
+ cls.space = space
+ env = os.environ
+ cls.w_example01, cls.w_payload = cls.space.unpackiterable(cls.space.appexec([], """():
+ import cppyy
+ cppyy.load_reflection_info(%r)
+ return cppyy._scope_byname('example01'), cppyy._scope_byname('payload')""" % (test_dct, )))
+
+ def test01_static_int(self):
+ """Test passing of an int, returning of an int, and overloading on a
+ differening number of arguments."""
+
+ import sys, math
+ t = self.example01
+
+ res = t.get_overload("staticAddOneToInt").call(None, 1)
+ assert res == 2
+ res = t.get_overload("staticAddOneToInt").call(None, 1L)
+ assert res == 2
+ res = t.get_overload("staticAddOneToInt").call(None, 1, 2)
+ assert res == 4
+ res = t.get_overload("staticAddOneToInt").call(None, -1)
+ assert res == 0
+ maxint32 = int(2 ** 31 - 1)
+ res = t.get_overload("staticAddOneToInt").call(None, maxint32-1)
+ assert res == maxint32
+ res = t.get_overload("staticAddOneToInt").call(None, maxint32)
+ assert res == -maxint32-1
+
+ raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, 1, [])')
+ raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, 1.)')
+ raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, maxint32+1)')
+
+ def test02_static_double(self):
+ """Test passing of a double and returning of a double on a static function."""
+
+ t = self.example01
+
+ res = t.get_overload("staticAddToDouble").call(None, 0.09)
+ assert res == 0.09 + 0.01
+
+ def test03_static_constcharp(self):
+ """Test passing of a C string and returning of a C string on a static
+ function."""
+
+ t = self.example01
+
+ res = t.get_overload("staticAtoi").call(None, "1")
+ assert res == 1
+ res = t.get_overload("staticStrcpy").call(None, "aap") # TODO: this leaks
+ assert res == "aap"
+ res = t.get_overload("staticStrcpy").call(None, u"aap") # TODO: this leaks
+ assert res == "aap"
+
+ raises(TypeError, 't.get_overload("staticStrcpy").call(None, 1.)') # TODO: this leaks
+
+ def test04_method_int(self):
+ """Test passing of a int, returning of a int, and memory cleanup, on
+ a method."""
+ import cppyy
+
+ t = self.example01
+
+ assert t.get_overload("getCount").call(None) == 0
+
+ e1 = t.get_overload(t.type_name).call(None, 7)
+ assert t.get_overload("getCount").call(None) == 1
+ res = t.get_overload("addDataToInt").call(e1, 4)
+ assert res == 11
+ res = t.get_overload("addDataToInt").call(e1, -4)
+ assert res == 3
+ e1.destruct()
+ assert t.get_overload("getCount").call(None) == 0
+ raises(ReferenceError, 't.get_overload("addDataToInt").call(e1, 4)')
+
+ e1 = t.get_overload(t.type_name).call(None, 7)
+ e2 = t.get_overload(t.type_name).call(None, 8)
+ assert t.get_overload("getCount").call(None) == 2
+ e1.destruct()
+ assert t.get_overload("getCount").call(None) == 1
+ e2.destruct()
+ assert t.get_overload("getCount").call(None) == 0
+
+ e2.destruct()
+ assert t.get_overload("getCount").call(None) == 0
+
+ raises(TypeError, t.get_overload("addDataToInt").call, 41, 4)
+
+ def test05_memory(self):
+ """Test memory destruction and integrity."""
+
+ import gc
+ import cppyy
+
+ t = self.example01
+
+ assert t.get_overload("getCount").call(None) == 0
+
+ e1 = t.get_overload(t.type_name).call(None, 7)
+ assert t.get_overload("getCount").call(None) == 1
+ res = t.get_overload("addDataToInt").call(e1, 4)
+ assert res == 11
+ res = t.get_overload("addDataToInt").call(e1, -4)
+ assert res == 3
+ e1 = None
+ gc.collect()
+ assert t.get_overload("getCount").call(None) == 0
+
+ e1 = t.get_overload(t.type_name).call(None, 7)
+ e2 = t.get_overload(t.type_name).call(None, 8)
+ assert t.get_overload("getCount").call(None) == 2
+ e1 = None
+ gc.collect()
+ assert t.get_overload("getCount").call(None) == 1
+ e2.destruct()
+ assert t.get_overload("getCount").call(None) == 0
+ e2 = None
+ gc.collect()
+ assert t.get_overload("getCount").call(None) == 0
+
+ def test05a_memory2(self):
+ """Test ownership control."""
+
+ import gc, cppyy
+
+ t = self.example01
+
+ assert t.get_overload("getCount").call(None) == 0
+
+ e1 = t.get_overload(t.type_name).call(None, 7)
+ assert t.get_overload("getCount").call(None) == 1
+ assert e1._python_owns == True
+ e1._python_owns = False
+ e1 = None
+ gc.collect()
+ assert t.get_overload("getCount").call(None) == 1
+
+ # forced fix-up of object count for later tests
+ t.get_overload("setCount").call(None, 0)
+
+
+ def test06_method_double(self):
+ """Test passing of a double and returning of double on a method."""
+
+ import cppyy
+
+ t = self.example01
+
+ e = t.get_overload(t.type_name).call(None, 13)
+ res = t.get_overload("addDataToDouble").call(e, 16)
+ assert round(res-29, 8) == 0.
+ e.destruct()
+
+ e = t.get_overload(t.type_name).call(None, -13)
+ res = t.get_overload("addDataToDouble").call(e, 16)
+ assert round(res-3, 8) == 0.
+ e.destruct()
+ assert t.get_overload("getCount").call(None) == 0
+
+ def test07_method_constcharp(self):
+ """Test passing of a C string and returning of a C string on a
+ method."""
+ import cppyy
+
+ t = self.example01
+
+ e = t.get_overload(t.type_name).call(None, 42)
+ res = t.get_overload("addDataToAtoi").call(e, "13")
+ assert res == 55
+ res = t.get_overload("addToStringValue").call(e, "12") # TODO: this leaks
+ assert res == "54"
+ res = t.get_overload("addToStringValue").call(e, "-12") # TODO: this leaks
+ assert res == "30"
+ e.destruct()
+ assert t.get_overload("getCount").call(None) == 0
+
+ def test08_pass_object_by_pointer(self):
+ """Test passing of an instance as an argument."""
+ import cppyy
+
+ t1 = self.example01
+ t2 = self.payload
+
+ pl = t2.get_overload(t2.type_name).call(None, 3.14)
+ assert round(t2.get_overload("getData").call(pl)-3.14, 8) == 0
+ t1.get_overload("staticSetPayload").call(None, pl, 41.) # now pl is a CPPInstance
+ assert t2.get_overload("getData").call(pl) == 41.
+
+ e = t1.get_overload(t1.type_name).call(None, 50)
+ t1.get_overload("setPayload").call(e, pl);
+ assert round(t2.get_overload("getData").call(pl)-50., 8) == 0
+
+ e.destruct()
+ pl.destruct()
+ assert t1.get_overload("getCount").call(None) == 0
+
+ def test09_return_object_by_pointer(self):
+ """Test returning of an instance as an argument."""
+ import cppyy
+
+ t1 = self.example01
+ t2 = self.payload
+
+ pl1 = t2.get_overload(t2.type_name).call(None, 3.14)
+ assert round(t2.get_overload("getData").call(pl1)-3.14, 8) == 0
+ pl2 = t1.get_overload("staticCyclePayload").call(None, pl1, 38.)
+ assert t2.get_overload("getData").call(pl2) == 38.
+
+ e = t1.get_overload(t1.type_name).call(None, 50)
+ pl2 = t1.get_overload("cyclePayload").call(e, pl1);
+ assert round(t2.get_overload("getData").call(pl2)-50., 8) == 0
+
+ e.destruct()
+ pl1.destruct()
+ assert t1.get_overload("getCount").call(None) == 0
diff --git a/pypy/module/cppyy/test/test_crossing.py b/pypy/module/cppyy/test/test_crossing.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_crossing.py
@@ -0,0 +1,104 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("crossingDict.so"))
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ err = os.system("cd '%s' && make crossingDict.so" % currpath)
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+
+class AppTestCrossing(AppTestCpythonExtensionBase):
+ def setup_class(cls):
+ # following from AppTestCpythonExtensionBase, with cppyy added
+ cls.space = gettestobjspace(usemodules=['cpyext', 'cppyy', 'thread', '_rawffi', '_ffi', 'array'])
+ cls.space.getbuiltinmodule("cpyext")
+ from pypy.module.imp.importing import importhook
+ importhook(cls.space, "os") # warm up reference counts
+ from pypy.module.cpyext.pyobject import RefcountState
+ state = cls.space.fromcache(RefcountState)
+ state.non_heaptypes_w[:] = []
+
+ # cppyy specific additions (not that the test_dct is loaded late
+ # to allow the generated extension module be loaded first)
+ cls.w_test_dct = cls.space.wrap(test_dct)
+ cls.w_datatypes = cls.space.appexec([], """():
+ import cppyy, cpyext""")
+
+ def setup_method(self, func):
+ AppTestCpythonExtensionBase.setup_method(self, func)
+
+ if hasattr(self, 'cmodule'):
+ return
+
+ import os, ctypes
+
+ init = """
+ if (Py_IsInitialized())
+ Py_InitModule("bar", methods);
+ """
+ body = """
+ long bar_unwrap(PyObject* arg)
+ {
+ return PyLong_AsLong(arg);
+ }
+ PyObject* bar_wrap(long l)
+ {
+ return PyLong_FromLong(l);
+ }
+ static PyMethodDef methods[] = {
+ { NULL }
+ };
+ """
+
+ modname = self.import_module(name='bar', init=init, body=body, load_it=False)
+ from pypy.module.imp.importing import get_so_extension
+ soext = get_so_extension(self.space)
+ fullmodname = os.path.join(modname, 'bar' + soext)
+ self.cmodule = ctypes.CDLL(fullmodname, ctypes.RTLD_GLOBAL)
+
+ def test00_base_class(self):
+ """Test from cpyext; only here to see whether the imported class works"""
+
+ import sys
+ init = """
+ if (Py_IsInitialized())
+ Py_InitModule("foo", NULL);
+ """
+ self.import_module(name='foo', init=init)
+ assert 'foo' in sys.modules
+
+ def test01_crossing_dict(self):
+ """Test availability of all needed classes in the dict"""
+
+ import cppyy
+ cppyy.load_reflection_info(self.test_dct)
+
+ assert cppyy.gbl.crossing == cppyy.gbl.crossing
+ crossing = cppyy.gbl.crossing
+
+ assert crossing.A == crossing.A
+
+ def test02_send_pyobject(self):
+ """Test sending a true pyobject to C++"""
+
+ import cppyy
+ crossing = cppyy.gbl.crossing
+
+ a = crossing.A()
+ assert a.unwrap(13) == 13
+
+ def test03_send_and_receive_pyobject(self):
+ """Test receiving a true pyobject from C++"""
+
+ import cppyy
+ crossing = cppyy.gbl.crossing
+
+ a = crossing.A()
+
+ assert a.wrap(41) == 41
diff --git a/pypy/module/cppyy/test/test_datatypes.py b/pypy/module/cppyy/test/test_datatypes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_datatypes.py
@@ -0,0 +1,526 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("datatypesDict.so"))
+
+space = gettestobjspace(usemodules=['cppyy', 'array'])
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ err = os.system("cd '%s' && make datatypesDict.so" % currpath)
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+class AppTestDATATYPES:
+ def setup_class(cls):
+ cls.space = space
+ env = os.environ
+ cls.w_N = space.wrap(5) # should be imported from the dictionary
+ cls.w_test_dct = space.wrap(test_dct)
+ cls.w_datatypes = cls.space.appexec([], """():
+ import cppyy
+ return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+ def test01_load_reflection_cache(self):
+ """Test whether loading a refl. info twice results in the same object."""
+ import cppyy
+ lib2 = cppyy.load_reflection_info(self.test_dct)
+ assert self.datatypes is lib2
+
+ def test02_instance_data_read_access(self):
+ """Test read access to instance public data and verify values"""
+
+ import cppyy, sys
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ # reading boolean type
+ assert c.m_bool == False
+
+ # reading char types
+ assert c.m_char == 'a'
+ assert c.m_uchar == 'c'
+
+ # reading integer types
+ assert c.m_short == -11
+ assert c.m_ushort == 11
+ assert c.m_int == -22
+ assert c.m_uint == 22
+ assert c.m_long == -33
+ assert c.m_ulong == 33
+ assert c.m_llong == -44
+ assert c.m_ullong == 55
+
+ # reading floating point types
+ assert round(c.m_float + 66., 5) == 0
+ assert round(c.m_double + 77., 8) == 0
+
+ # reding of array types
+ for i in range(self.N):
+ # reading of integer array types
+ assert c.m_short_array[i] == -1*i
+ assert c.get_short_array()[i] == -1*i
+ assert c.m_short_array2[i] == -2*i
+ assert c.get_short_array2()[i] == -2*i
+ assert c.m_ushort_array[i] == 3*i
+ assert c.get_ushort_array()[i] == 3*i
+ assert c.m_ushort_array2[i] == 4*i
+ assert c.get_ushort_array2()[i] == 4*i
+ assert c.m_int_array[i] == -5*i
+ assert c.get_int_array()[i] == -5*i
+ assert c.m_int_array2[i] == -6*i
+ assert c.get_int_array2()[i] == -6*i
+ assert c.m_uint_array[i] == 7*i
+ assert c.get_uint_array()[i] == 7*i
+ assert c.m_uint_array2[i] == 8*i
+ assert c.get_uint_array2()[i] == 8*i
+
+ assert c.m_long_array[i] == -9*i
+ assert c.get_long_array()[i] == -9*i
+ assert c.m_long_array2[i] == -10*i
+ assert c.get_long_array2()[i] == -10*i
+ assert c.m_ulong_array[i] == 11*i
+ assert c.get_ulong_array()[i] == 11*i
+ assert c.m_ulong_array2[i] == 12*i
+ assert c.get_ulong_array2()[i] == 12*i
+
+ assert round(c.m_float_array[i] + 13.*i, 5) == 0
+ assert round(c.m_float_array2[i] + 14.*i, 5) == 0
+ assert round(c.m_double_array[i] + 15.*i, 8) == 0
+ assert round(c.m_double_array2[i] + 16.*i, 8) == 0
+
+ # out-of-bounds checks
+ raises(IndexError, c.m_short_array.__getitem__, self.N)
+ raises(IndexError, c.m_ushort_array.__getitem__, self.N)
+ raises(IndexError, c.m_int_array.__getitem__, self.N)
+ raises(IndexError, c.m_uint_array.__getitem__, self.N)
+ raises(IndexError, c.m_long_array.__getitem__, self.N)
+ raises(IndexError, c.m_ulong_array.__getitem__, self.N)
+ raises(IndexError, c.m_float_array.__getitem__, self.N)
+ raises(IndexError, c.m_double_array.__getitem__, self.N)
+
+ c.destruct()
+
+ def test03_instance_data_write_access(self):
+ """Test write access to instance public data and verify values"""
+
+ import cppyy, sys
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ # boolean types through functions
+ c.set_bool(True);
+ assert c.get_bool() == True
+ c.set_bool(0); assert c.get_bool() == False
+
+ # boolean types through data members
+ c.m_bool = True; assert c.get_bool() == True
+ c.set_bool(True); assert c.m_bool == True
+ c.m_bool = 0; assert c.get_bool() == False
+ c.set_bool(0); assert c.m_bool == False
+
+ raises(TypeError, 'c.set_bool(10)')
+
+ # char types through functions
+ c.set_char('c'); assert c.get_char() == 'c'
+ c.set_uchar('e'); assert c.get_uchar() == 'e'
+
+ # char types through data members
+ c.m_char = 'b'; assert c.get_char() == 'b'
+ c.m_char = 40; assert c.get_char() == chr(40)
+ c.set_char('c'); assert c.m_char == 'c'
+ c.set_char(41); assert c.m_char == chr(41)
+ c.m_uchar = 'd'; assert c.get_uchar() == 'd'
+ c.m_uchar = 42; assert c.get_uchar() == chr(42)
+ c.set_uchar('e'); assert c.m_uchar == 'e'
+ c.set_uchar(43); assert c.m_uchar == chr(43)
+
+ raises(TypeError, 'c.set_char("string")')
+ raises(TypeError, 'c.set_char(500)')
+ raises(TypeError, 'c.set_uchar("string")')
+# TODO: raises(TypeError, 'c.set_uchar(-1)')
+
+ # integer types
+ names = ['short', 'ushort', 'int', 'uint', 'long', 'ulong', 'llong', 'ullong']
+ for i in range(len(names)):
+ exec 'c.m_%s = %d' % (names[i],i)
+ assert eval('c.get_%s()' % names[i]) == i
+
+ for i in range(len(names)):
+ exec 'c.set_%s(%d)' % (names[i],2*i)
+ assert eval('c.m_%s' % names[i]) == 2*i
+
+ for i in range(len(names)):
+ exec 'c.set_%s_c(%d)' % (names[i],3*i)
+ assert eval('c.m_%s' % names[i]) == 3*i
+
+ # float types through functions
+ c.set_float( 0.123 ); assert round(c.get_float() - 0.123, 5) == 0
+ c.set_double( 0.456 ); assert round(c.get_double() - 0.456, 8) == 0
+
+ # float types through data members
+ c.m_float = 0.123; assert round(c.get_float() - 0.123, 5) == 0
+ c.set_float(0.234); assert round(c.m_float - 0.234, 5) == 0
+ c.set_float_c(0.456); assert round(c.m_float - 0.456, 5) == 0
+ c.m_double = 0.678; assert round(c.get_double() - 0.678, 8) == 0
+ c.set_double(0.890); assert round(c.m_double - 0.890, 8) == 0
+ c.set_double_c(0.012); assert round(c.m_double - 0.012, 8) == 0
+
+ # arrays; there will be pointer copies, so destroy the current ones
+ c.destroy_arrays()
+
+ # integer arrays
+ names = ['short', 'ushort', 'int', 'uint', 'long', 'ulong']
+ import array
+ a = range(self.N)
+ atypes = ['h', 'H', 'i', 'I', 'l', 'L' ]
+ for j in range(len(names)):
+ b = array.array(atypes[j], a)
+ exec 'c.m_%s_array = b' % names[j] # buffer copies
+ for i in range(self.N):
+ assert eval('c.m_%s_array[i]' % names[j]) == b[i]
+
+ exec 'c.m_%s_array2 = b' % names[j] # pointer copies
+ b[i] = 28
+ for i in range(self.N):
+ assert eval('c.m_%s_array2[i]' % names[j]) == b[i]
+
+ c.destruct()
+
+ def test04_respect_privacy(self):
+ """Test that privacy settings are respected"""
+
+ import cppyy
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ raises(AttributeError, getattr, c, 'm_owns_arrays')
+
+ c.destruct()
+
+ def test05_class_read_access(self):
+ """Test read access to class public data and verify values"""
+
+ import cppyy, sys
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ # char types
+ assert cppyy_test_data.s_char == 's'
+ assert c.s_char == 's'
+ assert c.s_uchar == 'u'
+ assert cppyy_test_data.s_uchar == 'u'
+
+ # integer types
+ assert cppyy_test_data.s_short == -101
+ assert c.s_short == -101
+ assert c.s_ushort == 255
+ assert cppyy_test_data.s_ushort == 255
+ assert cppyy_test_data.s_int == -202
+ assert c.s_int == -202
+ assert c.s_uint == 202
+ assert cppyy_test_data.s_uint == 202
+ assert cppyy_test_data.s_long == -303L
+ assert c.s_long == -303L
+ assert c.s_ulong == 303L
+ assert cppyy_test_data.s_ulong == 303L
+ assert cppyy_test_data.s_llong == -404L
+ assert c.s_llong == -404L
+ assert c.s_ullong == 505L
+ assert cppyy_test_data.s_ullong == 505L
+
+ # floating point types
+ assert round(cppyy_test_data.s_float + 606., 5) == 0
+ assert round(c.s_float + 606., 5) == 0
+ assert round(cppyy_test_data.s_double + 707., 8) == 0
+ assert round(c.s_double + 707., 8) == 0
+
+ c.destruct()
+
+ def test06_class_data_write_access(self):
+ """Test write access to class public data and verify values"""
+
+ import cppyy, sys
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ # char types
+ cppyy_test_data.s_char = 'a'
+ assert c.s_char == 'a'
+ c.s_char = 'b'
+ assert cppyy_test_data.s_char == 'b'
+ cppyy_test_data.s_uchar = 'c'
+ assert c.s_uchar == 'c'
+ c.s_uchar = 'd'
+ assert cppyy_test_data.s_uchar == 'd'
+ raises(ValueError, setattr, cppyy_test_data, 's_uchar', -1)
+ raises(ValueError, setattr, c, 's_uchar', -1)
+
+ # integer types
+ c.s_short = -102
+ assert cppyy_test_data.s_short == -102
+ cppyy_test_data.s_short = -203
+ assert c.s_short == -203
+ c.s_ushort = 127
+ assert cppyy_test_data.s_ushort == 127
+ cppyy_test_data.s_ushort = 227
+ assert c.s_ushort == 227
+ cppyy_test_data.s_int = -234
+ assert c.s_int == -234
+ c.s_int = -321
+ assert cppyy_test_data.s_int == -321
+ cppyy_test_data.s_uint = 1234
+ assert c.s_uint == 1234
+ c.s_uint = 4321
+ assert cppyy_test_data.s_uint == 4321
+ raises(ValueError, setattr, c, 's_uint', -1)
+ raises(ValueError, setattr, cppyy_test_data, 's_uint', -1)
+ cppyy_test_data.s_long = -87L
+ assert c.s_long == -87L
+ c.s_long = 876L
+ assert cppyy_test_data.s_long == 876L
+ cppyy_test_data.s_ulong = 876L
+ assert c.s_ulong == 876L
+ c.s_ulong = 678L
+ assert cppyy_test_data.s_ulong == 678L
+ raises(ValueError, setattr, cppyy_test_data, 's_ulong', -1)
+ raises(ValueError, setattr, c, 's_ulong', -1)
+
+ # floating point types
+ cppyy_test_data.s_float = -3.1415
+ assert round(c.s_float, 5 ) == -3.1415
+ c.s_float = 3.1415
+ assert round(cppyy_test_data.s_float, 5 ) == 3.1415
+ import math
+ c.s_double = -math.pi
+ assert cppyy_test_data.s_double == -math.pi
+ cppyy_test_data.s_double = math.pi
+ assert c.s_double == math.pi
+
+ c.destruct()
+
+ def test07_range_access(self):
+ """Test the ranges of integer types"""
+
+ import cppyy, sys
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ # TODO: should these be TypeErrors, or should char/bool raise
+ # ValueErrors? In any case, consistency is needed ...
+ raises(ValueError, setattr, c, 'm_uint', -1)
+ raises(ValueError, setattr, c, 'm_ulong', -1)
+
+ c.destruct()
+
+ def test08_type_conversions(self):
+ """Test conversions between builtin types"""
+
+ import cppyy, sys
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ c.m_double = -1
+ assert round(c.m_double + 1.0, 8) == 0
+
+ raises(TypeError, c.m_double, 'c')
+ raises(TypeError, c.m_int, -1.)
+ raises(TypeError, c.m_int, 1.)
+
+ c.destruct()
+
+ def test09_global_builtin_type(self):
+ """Test access to a global builtin type"""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ assert gbl.g_int == gbl.get_global_int()
+
+ gbl.set_global_int(32)
+ assert gbl.get_global_int() == 32
+ assert gbl.g_int == 32
+
+ gbl.g_int = 22
+ assert gbl.get_global_int() == 22
+ assert gbl.g_int == 22
+
+ def test10_global_ptr(self):
+ """Test access of global objects through a pointer"""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ raises(ReferenceError, 'gbl.g_pod.m_int')
+
+ c = gbl.cppyy_test_pod()
+ c.m_int = 42
+ c.m_double = 3.14
+
+ gbl.set_global_pod(c)
+ assert gbl.is_global_pod(c)
+ assert gbl.g_pod.m_int == 42
+ assert gbl.g_pod.m_double == 3.14
+
+ d = gbl.get_global_pod()
+ assert gbl.is_global_pod(d)
+ assert c == d
+ assert id(c) == id(d)
+
+ e = gbl.cppyy_test_pod()
+ e.m_int = 43
+ e.m_double = 2.14
+
+ gbl.g_pod = e
+ assert gbl.is_global_pod(e)
+ assert gbl.g_pod.m_int == 43
+ assert gbl.g_pod.m_double == 2.14
+
+ def test11_enum(self):
+ """Test access to enums"""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ # TODO: test that the enum is accessible as a type
+
+ assert cppyy_test_data.kNothing == 6
+ assert cppyy_test_data.kSomething == 111
+ assert cppyy_test_data.kLots == 42
+
+ assert c.get_enum() == cppyy_test_data.kNothing
+ assert c.m_enum == cppyy_test_data.kNothing
+
+ c.m_enum = cppyy_test_data.kSomething
+ assert c.get_enum() == cppyy_test_data.kSomething
+ assert c.m_enum == cppyy_test_data.kSomething
+
+ c.set_enum(cppyy_test_data.kLots)
+ assert c.get_enum() == cppyy_test_data.kLots
+ assert c.m_enum == cppyy_test_data.kLots
+
+ assert c.s_enum == cppyy_test_data.s_enum
+ assert c.s_enum == cppyy_test_data.kNothing
+ assert cppyy_test_data.s_enum == cppyy_test_data.kNothing
+
+ c.s_enum = cppyy_test_data.kSomething
+ assert c.s_enum == cppyy_test_data.s_enum
+ assert c.s_enum == cppyy_test_data.kSomething
+ assert cppyy_test_data.s_enum == cppyy_test_data.kSomething
+
+ def test12_object_returns(self):
+ """Test access to and return of PODs"""
+
+ import cppyy
+
+ c = cppyy.gbl.cppyy_test_data()
+
+ assert c.m_pod.m_int == 888
+ assert c.m_pod.m_double == 3.14
+
+ pod = c.get_pod_val()
+ assert pod.m_int == 888
+ assert pod.m_double == 3.14
+
+ assert c.get_pod_ptr().m_int == 888
+ assert c.get_pod_ptr().m_double == 3.14
+ c.get_pod_ptr().m_int = 777
+ assert c.get_pod_ptr().m_int == 777
+
+ assert c.get_pod_ref().m_int == 777
+ assert c.get_pod_ref().m_double == 3.14
+ c.get_pod_ref().m_int = 666
+ assert c.get_pod_ref().m_int == 666
+
+ assert c.get_pod_ptrref().m_int == 666
+ assert c.get_pod_ptrref().m_double == 3.14
+
+ def test13_object_arguments(self):
+ """Test setting and returning of a POD through arguments"""
+
+ import cppyy
+
+ c = cppyy.gbl.cppyy_test_data()
+ assert c.m_pod.m_int == 888
+ assert c.m_pod.m_double == 3.14
+
+ p = cppyy.gbl.cppyy_test_pod()
+ p.m_int = 123
+ assert p.m_int == 123
+ p.m_double = 321.
+ assert p.m_double == 321.
+
+ c.set_pod_val(p)
+ assert c.m_pod.m_int == 123
+ assert c.m_pod.m_double == 321.
+
+ c = cppyy.gbl.cppyy_test_data()
+ c.set_pod_ptr_in(p)
+ assert c.m_pod.m_int == 123
+ assert c.m_pod.m_double == 321.
+
+ c = cppyy.gbl.cppyy_test_data()
+ c.set_pod_ptr_out(p)
+ assert p.m_int == 888
+ assert p.m_double == 3.14
+
+ p.m_int = 555
+ p.m_double = 666.
+
+ c = cppyy.gbl.cppyy_test_data()
+ c.set_pod_ref(p)
+ assert c.m_pod.m_int == 555
+ assert c.m_pod.m_double == 666.
+
+ c = cppyy.gbl.cppyy_test_data()
+ c.set_pod_ptrptr_in(p)
+ assert c.m_pod.m_int == 555
+ assert c.m_pod.m_double == 666.
+ assert p.m_int == 555
+ assert p.m_double == 666.
+
+ c = cppyy.gbl.cppyy_test_data()
+ c.set_pod_void_ptrptr_in(p)
+ assert c.m_pod.m_int == 555
+ assert c.m_pod.m_double == 666.
+ assert p.m_int == 555
+ assert p.m_double == 666.
+
+ c = cppyy.gbl.cppyy_test_data()
+ c.set_pod_ptrptr_out(p)
+ assert c.m_pod.m_int == 888
+ assert c.m_pod.m_double == 3.14
+ assert p.m_int == 888
+ assert p.m_double == 3.14
+
+ p.m_int = 777
+ p.m_double = 888.
+
+ c = cppyy.gbl.cppyy_test_data()
+ c.set_pod_void_ptrptr_out(p)
+ assert c.m_pod.m_int == 888
+ assert c.m_pod.m_double == 3.14
+ assert p.m_int == 888
+ assert p.m_double == 3.14
diff --git a/pypy/module/cppyy/test/test_fragile.py b/pypy/module/cppyy/test/test_fragile.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_fragile.py
@@ -0,0 +1,196 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("fragileDict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ err = os.system("cd '%s' && make fragileDict.so" % currpath)
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+class AppTestFRAGILE:
+ def setup_class(cls):
+ cls.space = space
+ env = os.environ
+ cls.w_test_dct = space.wrap(test_dct)
+ cls.w_datatypes = cls.space.appexec([], """():
+ import cppyy
+ return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+ def test01_load_failure(self):
+ """Test failure to load dictionary"""
+
+ import cppyy
+ raises(RuntimeError, cppyy.load_reflection_info, "does_not_exist.so")
+
+ def test02_missing_classes(self):
+ """Test (non-)access to missing classes"""
+
+ import cppyy
+
+ raises(AttributeError, getattr, cppyy.gbl, "no_such_class")
+
+ assert cppyy.gbl.fragile == cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+
+ raises(AttributeError, getattr, fragile, "no_such_class")
+
+ assert fragile.C == fragile.C
+ assert fragile.C().check() == ord('C')
+
+ assert fragile.B == fragile.B
+ assert fragile.B().check() == ord('B')
+ raises(TypeError, fragile.B().gime_no_such)
+
+ assert fragile.C == fragile.C
+ assert fragile.C().check() == ord('C')
+ raises(TypeError, fragile.C().use_no_such, None)
+
+ def test03_arguments(self):
+ """Test reporting when providing wrong arguments"""
+
+ import cppyy
+
+ assert cppyy.gbl.fragile == cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+
+ assert fragile.D == fragile.D
+ assert fragile.D().check() == ord('D')
+
+ d = fragile.D()
+ raises(TypeError, d.overload, None)
+ raises(TypeError, d.overload, None, None, None)
+
+ d.overload('a')
+ d.overload(1)
+
+ def test04_unsupported_arguments(self):
+ """Test arguments that are yet unsupported"""
+
+ import cppyy
+
+ assert cppyy.gbl.fragile == cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+
+ assert fragile.E == fragile.E
+ assert fragile.E().check() == ord('E')
+
+ e = fragile.E()
+ raises(TypeError, e.overload, None)
+ raises(TypeError, getattr, e, 'm_pp_no_such')
+
+ def test05_wrong_arg_addressof(self):
+ """Test addressof() error reporting"""
+
+ import cppyy
+
+ assert cppyy.gbl.fragile == cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+
+ assert fragile.F == fragile.F
+ assert fragile.F().check() == ord('F')
+
+ f = fragile.F()
+ o = object()
+
+ cppyy.addressof(f)
+ raises(TypeError, cppyy.addressof, o)
+ raises(TypeError, cppyy.addressof, 0)
+ raises(TypeError, cppyy.addressof, 1)
+ raises(TypeError, cppyy.addressof, None)
+
+ def test06_wrong_this(self):
+ """Test that using an incorrect self argument raises"""
+
+ import cppyy
+
+ assert cppyy.gbl.fragile == cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+
+ a = fragile.A()
+ assert fragile.A.check(a) == ord('A')
+
+ b = fragile.B()
+ assert fragile.B.check(b) == ord('B')
+ raises(TypeError, fragile.A.check, b)
+ raises(TypeError, fragile.B.check, a)
+
+ assert not a.gime_null()
+
+ assert isinstance(a.gime_null(), fragile.A)
+ raises(ReferenceError, fragile.A.check, a.gime_null())
+
+ def test07_unnamed_enum(self):
+ """Test that an unnamed enum does not cause infinite recursion"""
+
+ import cppyy
+
+ assert cppyy.gbl.fragile is cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+ assert cppyy.gbl.fragile is fragile
+
+ g = fragile.G()
+
+ def test08_unhandled_scoped_datamember(self):
+ """Test that an unhandled scoped data member does not cause infinite recursion"""
+
+ import cppyy
+
+ assert cppyy.gbl.fragile is cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+ assert cppyy.gbl.fragile is fragile
+
+ h = fragile.H()
+
+ def test09_operator_bool(self):
+ """Access to global vars with an operator bool() returning False"""
+
+ import cppyy
+
+ i = cppyy.gbl.fragile.I()
+ assert not i
+
+ g = cppyy.gbl.fragile.gI
+ assert not g
+
+ def test10_documentation(self):
+ """Check contents of documentation"""
+
+ import cppyy
+
+ assert cppyy.gbl.fragile == cppyy.gbl.fragile
+ fragile = cppyy.gbl.fragile
+
+ d = fragile.D()
+ try:
+ d.check(None) # raises TypeError
+ assert 0
+ except TypeError, e:
+ assert "fragile::D::check()" in str(e)
+ assert "TypeError: wrong number of arguments" in str(e)
+
+ try:
+ d.overload(None) # raises TypeError
+ assert 0
+ except TypeError, e:
+ assert "fragile::D::overload()" in str(e)
+ assert "TypeError: wrong number of arguments" in str(e)
+ assert "fragile::D::overload(fragile::no_such_class*)" in str(e)
+ assert "TypeError: no converter available for type \"fragile::no_such_class*\"" in str(e)
+ assert "fragile::D::overload(char, int)" in str(e)
+ assert "TypeError: expected string, got NoneType object" in str(e)
+ assert "fragile::D::overload(int, fragile::no_such_class*)" in str(e)
+ assert "TypeError: unsupported operand type for int(): 'NoneType'" in str(e)
+
+ j = fragile.J()
+ assert fragile.J.method1.__doc__ == j.method1.__doc__
+ assert j.method1.__doc__ == "int fragile::J::method1(int, double)"
+
+ f = fragile.fglobal
+ assert f.__doc__ == "void fragile::fglobal(int, double, char)"
diff --git a/pypy/module/cppyy/test/test_helper.py b/pypy/module/cppyy/test/test_helper.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_helper.py
@@ -0,0 +1,44 @@
+from pypy.module.cppyy import helper
+
+def test_remove_const():
+ assert helper.remove_const("const int") == "int"
+
+def test_compound():
+ assert helper.compound("int*") == "*"
+ assert helper.compound("int* const *&") == "**&"
+ assert helper.compound("std::vector<int>*") == "*"
+ assert helper.compound("unsigned long int[5]") == "[]"
+ assert helper.array_size("unsigned long int[5]") == 5
+
+
+def test_array_size():
+ assert helper.array_size("int[5]") == 5
+
+
+def test_clean_type():
+ assert helper.clean_type(" int***") == "int"
+ assert helper.clean_type("int* const *&") == "int"
+ assert helper.clean_type("std::vector<int>&") == "std::vector<int>"
+ assert helper.clean_type("const std::vector<int>&") == "std::vector<int>"
+ assert helper.clean_type("std::vector<std::vector<int> >" ) == "std::vector<std::vector<int> >"
+ assert helper.clean_type("unsigned short int[3]") == "unsigned short int"
+
+
+def test_operator_mapping():
+ assert helper.map_operator_name("operator[]", 1, "const int&") == "__getitem__"
+ assert helper.map_operator_name("operator[]", 1, "int&") == "__setitem__"
+
+ assert helper.map_operator_name("operator()", 1, "") == "__call__"
+ assert helper.map_operator_name("operator%", 1, "") == "__mod__"
+ assert helper.map_operator_name("operator**", 1, "") == "__pow__"
+ assert helper.map_operator_name("operator<<", 1, "") == "__lshift__"
+ assert helper.map_operator_name("operator|", 1, "") == "__or__"
+
+ assert helper.map_operator_name("operator*", 1, "") == "__mul__"
+ assert helper.map_operator_name("operator*", 0, "") == "__deref__"
+
+ assert helper.map_operator_name("operator+", 1, "") == "__add__"
+ assert helper.map_operator_name("operator+", 0, "") == "__pos__"
+
+ assert helper.map_operator_name("func", 0, "") == "func"
+ assert helper.map_operator_name("some_method", 0, "") == "some_method"
diff --git a/pypy/module/cppyy/test/test_operators.py b/pypy/module/cppyy/test/test_operators.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_operators.py
@@ -0,0 +1,141 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("operatorsDict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ err = os.system("cd '%s' && make operatorsDict.so" % currpath)
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+class AppTestOPERATORS:
+ def setup_class(cls):
+ cls.space = space
+ env = os.environ
+ cls.w_N = space.wrap(5) # should be imported from the dictionary
+ cls.w_test_dct = space.wrap(test_dct)
+ cls.w_operators = cls.space.appexec([], """():
+ import cppyy
+ return cppyy.load_reflection_info(%r)""" % (test_dct, ))
+
+ def teardown_method(self, meth):
+ import gc
+ gc.collect()
+
+ def test01_math_operators(self):
+ """Test overloading of math operators"""
+
+ import cppyy
+ number = cppyy.gbl.number
+
+ assert (number(20) + number(10)) == number(30)
+ assert (number(20) + 10 ) == number(30)
+ assert (number(20) - number(10)) == number(10)
+ assert (number(20) - 10 ) == number(10)
+ assert (number(20) / number(10)) == number(2)
+ assert (number(20) / 10 ) == number(2)
+ assert (number(20) * number(10)) == number(200)
+ assert (number(20) * 10 ) == number(200)
+ assert (number(20) % 10 ) == number(0)
+ assert (number(20) % number(10)) == number(0)
+ assert (number(5) & number(14)) == number(4)
+ assert (number(5) | number(14)) == number(15)
+ assert (number(5) ^ number(14)) == number(11)
+ assert (number(5) << 2) == number(20)
+ assert (number(20) >> 2) == number(5)
+
+ def test02_unary_math_operators(self):
+ """Test overloading of unary math operators"""
+
+ import cppyy
+ number = cppyy.gbl.number
+
+ n = number(20)
+ n += number(10)
+ n -= number(10)
+ n *= number(10)
+ n /= number(2)
+ assert n == number(100)
+
+ nn = -n;
+ assert nn == number(-100)
+
+ def test03_comparison_operators(self):
+ """Test overloading of comparison operators"""
+
+ import cppyy
+ number = cppyy.gbl.number
+
+ assert (number(20) > number(10)) == True
+ assert (number(20) < number(10)) == False
+ assert (number(20) >= number(20)) == True
+ assert (number(20) <= number(10)) == False
+ assert (number(20) != number(10)) == True
+ assert (number(20) == number(10)) == False
+
+ def test04_boolean_operator(self):
+ """Test implementation of operator bool"""
+
+ import cppyy
+ number = cppyy.gbl.number
+
+ n = number(20)
+ assert n
+
+ n = number(0)
+ assert not n
+
+ def test05_exact_types(self):
+ """Test converter operators of exact types"""
+
+ import cppyy
+ gbl = cppyy.gbl
+
+ o = gbl.operator_char_star()
+ assert o.m_str == 'operator_char_star'
+ assert str(o) == 'operator_char_star'
+
+ o = gbl.operator_const_char_star()
+ assert o.m_str == 'operator_const_char_star'
+ assert str(o) == 'operator_const_char_star'
+
+ o = gbl.operator_int(); o.m_int = -13
+ assert o.m_int == -13
+ assert int(o) == -13
+
+ o = gbl.operator_long(); o.m_long = 42
More information about the pypy-commit
mailing list