Merge pull request #237 from MissPenguin/develop
replace python lanms with c++ version, fix infer_det bug, fix test_im…release/1.1
commit
db0aa24b5b
After Width: | Height: | Size: 40 KiB |
@ -0,0 +1 @@
|
||||
adaptor.so
|
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2014 Google Inc.
|
||||
#
|
||||
# This file is part of YouCompleteMe.
|
||||
#
|
||||
# YouCompleteMe is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# YouCompleteMe is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
import ycm_core
|
||||
|
||||
# These are the compilation flags that will be used in case there's no
|
||||
# compilation database set (by default, one is not set).
|
||||
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
from plumbum.cmd import python_config
|
||||
|
||||
|
||||
flags = [
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wnon-virtual-dtor',
|
||||
'-Winvalid-pch',
|
||||
'-Wno-unused-local-typedefs',
|
||||
'-std=c++11',
|
||||
'-x', 'c++',
|
||||
'-Iinclude',
|
||||
] + python_config('--cflags').split()
|
||||
|
||||
|
||||
# Set this to the absolute path to the folder (NOT the file!) containing the
|
||||
# compile_commands.json file to use that instead of 'flags'. See here for
|
||||
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
#
|
||||
# Most projects will NOT need to set this to anything; you can just change the
|
||||
# 'flags' list of compilation flags.
|
||||
compilation_database_folder = ''
|
||||
|
||||
if os.path.exists( compilation_database_folder ):
|
||||
database = ycm_core.CompilationDatabase( compilation_database_folder )
|
||||
else:
|
||||
database = None
|
||||
|
||||
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname( os.path.abspath( __file__ ) )
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
if not working_directory:
|
||||
return list( flags )
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith( '/' ):
|
||||
new_flag = os.path.join( working_directory, flag )
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith( path_flag ):
|
||||
path = flag[ len( path_flag ): ]
|
||||
new_flag = path_flag + os.path.join( working_directory, path )
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append( new_flag )
|
||||
return new_flags
|
||||
|
||||
|
||||
def IsHeaderFile( filename ):
|
||||
extension = os.path.splitext( filename )[ 1 ]
|
||||
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
|
||||
|
||||
|
||||
def GetCompilationInfoForFile( filename ):
|
||||
# The compilation_commands.json file generated by CMake does not have entries
|
||||
# for header files. So we do our best by asking the db for flags for a
|
||||
# corresponding source file, if any. If one exists, the flags for that file
|
||||
# should be good enough.
|
||||
if IsHeaderFile( filename ):
|
||||
basename = os.path.splitext( filename )[ 0 ]
|
||||
for extension in SOURCE_EXTENSIONS:
|
||||
replacement_file = basename + extension
|
||||
if os.path.exists( replacement_file ):
|
||||
compilation_info = database.GetCompilationInfoForFile(
|
||||
replacement_file )
|
||||
if compilation_info.compiler_flags_:
|
||||
return compilation_info
|
||||
return None
|
||||
return database.GetCompilationInfoForFile( filename )
|
||||
|
||||
|
||||
# This is the entry point; this function is called by ycmd to produce flags for
|
||||
# a file.
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if database:
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
compilation_info = GetCompilationInfoForFile( filename )
|
||||
if not compilation_info:
|
||||
return None
|
||||
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute(
|
||||
compilation_info.compiler_flags_,
|
||||
compilation_info.compiler_working_dir_ )
|
||||
else:
|
||||
relative_to = DirectoryOfThisScript()
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
|
||||
|
||||
return {
|
||||
'flags': final_flags,
|
||||
'do_cache': True
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
CXXFLAGS = -I include -std=c++11 -O3 $(shell python3-config --cflags)
|
||||
LDFLAGS = $(shell python3-config --ldflags)
|
||||
|
||||
DEPS = lanms.h $(shell find include -xtype f)
|
||||
CXX_SOURCES = adaptor.cpp include/clipper/clipper.cpp
|
||||
|
||||
LIB_SO = adaptor.so
|
||||
|
||||
$(LIB_SO): $(CXX_SOURCES) $(DEPS)
|
||||
$(CXX) -o $@ $(CXXFLAGS) $(LDFLAGS) $(CXX_SOURCES) --shared -fPIC
|
||||
|
||||
clean:
|
||||
rm -rf $(LIB_SO)
|
@ -0,0 +1,20 @@
|
||||
import subprocess
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
if subprocess.call(['make', '-C', BASE_DIR]) != 0: # return value
|
||||
raise RuntimeError('Cannot compile lanms: {}'.format(BASE_DIR))
|
||||
|
||||
|
||||
def merge_quadrangle_n9(polys, thres=0.3, precision=10000):
|
||||
from .adaptor import merge_quadrangle_n9 as nms_impl
|
||||
if len(polys) == 0:
|
||||
return np.array([], dtype='float32')
|
||||
p = polys.copy()
|
||||
p[:,:8] *= precision
|
||||
ret = np.array(nms_impl(p, thres), dtype='float32')
|
||||
ret[:,:8] /= precision
|
||||
return ret
|
||||
|
@ -0,0 +1,10 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
from . import merge_quadrangle_n9
|
||||
|
||||
if __name__ == '__main__':
|
||||
# unit square with confidence 1
|
||||
q = np.array([0, 0, 0, 1, 1, 1, 1, 0, 1], dtype='float32')
|
||||
|
||||
print(merge_quadrangle_n9(np.array([q, q + 0.1, q + 2])))
|
@ -0,0 +1,61 @@
|
||||
#include "pybind11/pybind11.h"
|
||||
#include "pybind11/numpy.h"
|
||||
#include "pybind11/stl.h"
|
||||
#include "pybind11/stl_bind.h"
|
||||
|
||||
#include "lanms.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
|
||||
namespace lanms_adaptor {
|
||||
|
||||
std::vector<std::vector<float>> polys2floats(const std::vector<lanms::Polygon> &polys) {
|
||||
std::vector<std::vector<float>> ret;
|
||||
for (size_t i = 0; i < polys.size(); i ++) {
|
||||
auto &p = polys[i];
|
||||
auto &poly = p.poly;
|
||||
ret.emplace_back(std::vector<float>{
|
||||
float(poly[0].X), float(poly[0].Y),
|
||||
float(poly[1].X), float(poly[1].Y),
|
||||
float(poly[2].X), float(poly[2].Y),
|
||||
float(poly[3].X), float(poly[3].Y),
|
||||
float(p.score),
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* \param quad_n9 an n-by-9 numpy array, where first 8 numbers denote the
|
||||
* quadrangle, and the last one is the score
|
||||
* \param iou_threshold two quadrangles with iou score above this threshold
|
||||
* will be merged
|
||||
*
|
||||
* \return an n-by-9 numpy array, the merged quadrangles
|
||||
*/
|
||||
std::vector<std::vector<float>> merge_quadrangle_n9(
|
||||
py::array_t<float, py::array::c_style | py::array::forcecast> quad_n9,
|
||||
float iou_threshold) {
|
||||
auto pbuf = quad_n9.request();
|
||||
if (pbuf.ndim != 2 || pbuf.shape[1] != 9)
|
||||
throw std::runtime_error("quadrangles must have a shape of (n, 9)");
|
||||
auto n = pbuf.shape[0];
|
||||
auto ptr = static_cast<float *>(pbuf.ptr);
|
||||
return polys2floats(lanms::merge_quadrangle_n9(ptr, n, iou_threshold));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PYBIND11_PLUGIN(adaptor) {
|
||||
py::module m("adaptor", "NMS");
|
||||
|
||||
m.def("merge_quadrangle_n9", &lanms_adaptor::merge_quadrangle_n9,
|
||||
"merge quadrangels");
|
||||
|
||||
return m.ptr();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,108 @@
|
||||
/*
|
||||
pybind11/buffer_info.h: Python buffer object interface
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
|
||||
/// Information record describing a Python buffer object
|
||||
struct buffer_info {
|
||||
void *ptr = nullptr; // Pointer to the underlying storage
|
||||
ssize_t itemsize = 0; // Size of individual items in bytes
|
||||
ssize_t size = 0; // Total number of entries
|
||||
std::string format; // For homogeneous buffers, this should be set to format_descriptor<T>::format()
|
||||
ssize_t ndim = 0; // Number of dimensions
|
||||
std::vector<ssize_t> shape; // Shape of the tensor (1 entry per dimension)
|
||||
std::vector<ssize_t> strides; // Number of entries between adjacent entries (for each per dimension)
|
||||
|
||||
buffer_info() { }
|
||||
|
||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
||||
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
|
||||
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
|
||||
shape(std::move(shape_in)), strides(std::move(strides_in)) {
|
||||
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size())
|
||||
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
|
||||
for (size_t i = 0; i < (size_t) ndim; ++i)
|
||||
size *= shape[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
buffer_info(T *ptr, detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in)
|
||||
: buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor<T>::format(), static_cast<ssize_t>(shape_in->size()), std::move(shape_in), std::move(strides_in)) { }
|
||||
|
||||
buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size)
|
||||
: buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { }
|
||||
|
||||
template <typename T>
|
||||
buffer_info(T *ptr, ssize_t size)
|
||||
: buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size) { }
|
||||
|
||||
explicit buffer_info(Py_buffer *view, bool ownview = true)
|
||||
: buffer_info(view->buf, view->itemsize, view->format, view->ndim,
|
||||
{view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) {
|
||||
this->view = view;
|
||||
this->ownview = ownview;
|
||||
}
|
||||
|
||||
buffer_info(const buffer_info &) = delete;
|
||||
buffer_info& operator=(const buffer_info &) = delete;
|
||||
|
||||
buffer_info(buffer_info &&other) {
|
||||
(*this) = std::move(other);
|
||||
}
|
||||
|
||||
buffer_info& operator=(buffer_info &&rhs) {
|
||||
ptr = rhs.ptr;
|
||||
itemsize = rhs.itemsize;
|
||||
size = rhs.size;
|
||||
format = std::move(rhs.format);
|
||||
ndim = rhs.ndim;
|
||||
shape = std::move(rhs.shape);
|
||||
strides = std::move(rhs.strides);
|
||||
std::swap(view, rhs.view);
|
||||
std::swap(ownview, rhs.ownview);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~buffer_info() {
|
||||
if (view && ownview) { PyBuffer_Release(view); delete view; }
|
||||
}
|
||||
|
||||
private:
|
||||
struct private_ctr_tag { };
|
||||
|
||||
buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim,
|
||||
detail::any_container<ssize_t> &&shape_in, detail::any_container<ssize_t> &&strides_in)
|
||||
: buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) { }
|
||||
|
||||
Py_buffer *view = nullptr;
|
||||
bool ownview = false;
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename T, typename SFINAE = void> struct compare_buffer_info {
|
||||
static bool compare(const buffer_info& b) {
|
||||
return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
||||
static bool compare(const buffer_info& b) {
|
||||
return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
|
||||
((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
|
||||
((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(pybind11)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,162 @@
|
||||
/*
|
||||
pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime
|
||||
|
||||
Copyright (c) 2016 Trent Houliston <trent@houliston.me> and
|
||||
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <datetime.h>
|
||||
|
||||
// Backport the PyDateTime_DELTA functions from Python3.3 if required
|
||||
#ifndef PyDateTime_DELTA_GET_DAYS
|
||||
#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days)
|
||||
#endif
|
||||
#ifndef PyDateTime_DELTA_GET_SECONDS
|
||||
#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds)
|
||||
#endif
|
||||
#ifndef PyDateTime_DELTA_GET_MICROSECONDS
|
||||
#define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds)
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename type> class duration_caster {
|
||||
public:
|
||||
typedef typename type::rep rep;
|
||||
typedef typename type::period period;
|
||||
|
||||
typedef std::chrono::duration<uint_fast32_t, std::ratio<86400>> days;
|
||||
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
if (!src) return false;
|
||||
// If invoked with datetime.delta object
|
||||
if (PyDelta_Check(src.ptr())) {
|
||||
value = type(duration_cast<duration<rep, period>>(
|
||||
days(PyDateTime_DELTA_GET_DAYS(src.ptr()))
|
||||
+ seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))
|
||||
+ microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));
|
||||
return true;
|
||||
}
|
||||
// If invoked with a float we assume it is seconds and convert
|
||||
else if (PyFloat_Check(src.ptr())) {
|
||||
value = type(duration_cast<duration<rep, period>>(duration<double>(PyFloat_AsDouble(src.ptr()))));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
// If this is a duration just return it back
|
||||
static const std::chrono::duration<rep, period>& get_duration(const std::chrono::duration<rep, period> &src) {
|
||||
return src;
|
||||
}
|
||||
|
||||
// If this is a time_point get the time_since_epoch
|
||||
template <typename Clock> static std::chrono::duration<rep, period> get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {
|
||||
return src.time_since_epoch();
|
||||
}
|
||||
|
||||
static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Use overloaded function to get our duration from our source
|
||||
// Works out if it is a duration or time_point and get the duration
|
||||
auto d = get_duration(src);
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
||||
using dd_t = duration<int, std::ratio<86400>>;
|
||||
using ss_t = duration<int, std::ratio<1>>;
|
||||
using us_t = duration<int, std::micro>;
|
||||
|
||||
auto dd = duration_cast<dd_t>(d);
|
||||
auto subd = d - dd;
|
||||
auto ss = duration_cast<ss_t>(subd);
|
||||
auto us = duration_cast<us_t>(subd - ss);
|
||||
return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
|
||||
};
|
||||
|
||||
// This is for casting times on the system clock into datetime.datetime instances
|
||||
template <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
|
||||
public:
|
||||
typedef std::chrono::time_point<std::chrono::system_clock, Duration> type;
|
||||
bool load(handle src, bool) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
if (!src) return false;
|
||||
if (PyDateTime_Check(src.ptr())) {
|
||||
std::tm cal;
|
||||
cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());
|
||||
cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());
|
||||
cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());
|
||||
cal.tm_mday = PyDateTime_GET_DAY(src.ptr());
|
||||
cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;
|
||||
cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;
|
||||
cal.tm_isdst = -1;
|
||||
|
||||
value = system_clock::from_time_t(std::mktime(&cal)) + microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// Lazy initialise the PyDateTime import
|
||||
if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
|
||||
|
||||
std::time_t tt = system_clock::to_time_t(src);
|
||||
// this function uses static memory so it's best to copy it out asap just in case
|
||||
// otherwise other code that is using localtime may break this (not just python code)
|
||||
std::tm localtime = *std::localtime(&tt);
|
||||
|
||||
// Declare these special duration types so the conversions happen with the correct primitive types (int)
|
||||
using us_t = duration<int, std::micro>;
|
||||
|
||||
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
|
||||
localtime.tm_mon + 1,
|
||||
localtime.tm_mday,
|
||||
localtime.tm_hour,
|
||||
localtime.tm_min,
|
||||
localtime.tm_sec,
|
||||
(duration_cast<us_t>(src.time_since_epoch() % seconds(1))).count());
|
||||
}
|
||||
PYBIND11_TYPE_CASTER(type, _("datetime.datetime"));
|
||||
};
|
||||
|
||||
// Other clocks that are not the system clock are not measured as datetime.datetime objects
|
||||
// since they are not measured on calendar time. So instead we just make them timedeltas
|
||||
// Or if they have passed us a time as a float we convert that
|
||||
template <typename Clock, typename Duration> class type_caster<std::chrono::time_point<Clock, Duration>>
|
||||
: public duration_caster<std::chrono::time_point<Clock, Duration>> {
|
||||
};
|
||||
|
||||
template <typename Rep, typename Period> class type_caster<std::chrono::duration<Rep, Period>>
|
||||
: public duration_caster<std::chrono::duration<Rep, Period>> {
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(pybind11)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,61 @@
|
||||
/*
|
||||
pybind11/complex.h: Complex number support
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
#include <complex>
|
||||
|
||||
/// glibc defines I as a macro which breaks things, e.g., boost template names
|
||||
#ifdef I
|
||||
# undef I
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
|
||||
template <typename T> struct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static constexpr const char c = format_descriptor<T>::c;
|
||||
static constexpr const char value[3] = { 'Z', c, '\0' };
|
||||
static std::string format() { return std::string(value); }
|
||||
};
|
||||
|
||||
template <typename T> constexpr const char format_descriptor<
|
||||
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static constexpr bool value = true;
|
||||
static constexpr int index = is_fmt_numeric<T>::index + 3;
|
||||
};
|
||||
|
||||
template <typename T> class type_caster<std::complex<T>> {
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (!src)
|
||||
return false;
|
||||
if (!convert && !PyComplex_Check(src.ptr()))
|
||||
return false;
|
||||
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
value = std::complex<T>((T) result.real, (T) result.imag);
|
||||
return true;
|
||||
}
|
||||
|
||||
static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(std::complex<T>, _("complex"));
|
||||
};
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(pybind11)
|
@ -0,0 +1,185 @@
|
||||
/*
|
||||
pybind11/descr.h: Helper type for concatenating type signatures
|
||||
either at runtime (C++11) or compile time (C++14)
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
/* Concatenate type signatures at compile time using C++14 */
|
||||
#if defined(PYBIND11_CPP14) && !defined(_MSC_VER)
|
||||
#define PYBIND11_CONSTEXPR_DESCR
|
||||
|
||||
template <size_t Size1, size_t Size2> class descr {
|
||||
template <size_t Size1_, size_t Size2_> friend class descr;
|
||||
public:
|
||||
constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1])
|
||||
: descr(text, types,
|
||||
make_index_sequence<Size1>(),
|
||||
make_index_sequence<Size2>()) { }
|
||||
|
||||
constexpr const char *text() const { return m_text; }
|
||||
constexpr const std::type_info * const * types() const { return m_types; }
|
||||
|
||||
template <size_t OtherSize1, size_t OtherSize2>
|
||||
constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2> operator+(const descr<OtherSize1, OtherSize2> &other) const {
|
||||
return concat(other,
|
||||
make_index_sequence<Size1>(),
|
||||
make_index_sequence<Size2>(),
|
||||
make_index_sequence<OtherSize1>(),
|
||||
make_index_sequence<OtherSize2>());
|
||||
}
|
||||
|
||||
protected:
|
||||
template <size_t... Indices1, size_t... Indices2>
|
||||
constexpr descr(
|
||||
char const (&text) [Size1+1],
|
||||
const std::type_info * const (&types) [Size2+1],
|
||||
index_sequence<Indices1...>, index_sequence<Indices2...>)
|
||||
: m_text{text[Indices1]..., '\0'},
|
||||
m_types{types[Indices2]..., nullptr } {}
|
||||
|
||||
template <size_t OtherSize1, size_t OtherSize2, size_t... Indices1,
|
||||
size_t... Indices2, size_t... OtherIndices1, size_t... OtherIndices2>
|
||||
constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2>
|
||||
concat(const descr<OtherSize1, OtherSize2> &other,
|
||||
index_sequence<Indices1...>, index_sequence<Indices2...>,
|
||||
index_sequence<OtherIndices1...>, index_sequence<OtherIndices2...>) const {
|
||||
return descr<Size1 + OtherSize1, Size2 + OtherSize2>(
|
||||
{ m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' },
|
||||
{ m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr }
|
||||
);
|
||||
}
|
||||
|
||||
protected:
|
||||
char m_text[Size1 + 1];
|
||||
const std::type_info * m_types[Size2 + 1];
|
||||
};
|
||||
|
||||
template <size_t Size> constexpr descr<Size - 1, 0> _(char const(&text)[Size]) {
|
||||
return descr<Size - 1, 0>(text, { nullptr });
|
||||
}
|
||||
|
||||
template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
|
||||
template <size_t...Digits> struct int_to_str<0, Digits...> {
|
||||
static constexpr auto digits = descr<sizeof...(Digits), 0>({ ('0' + Digits)..., '\0' }, { nullptr });
|
||||
};
|
||||
|
||||
// Ternary description (like std::conditional)
|
||||
template <bool B, size_t Size1, size_t Size2>
|
||||
constexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) {
|
||||
return _(text1);
|
||||
}
|
||||
template <bool B, size_t Size1, size_t Size2>
|
||||
constexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) {
|
||||
return _(text2);
|
||||
}
|
||||
template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
|
||||
constexpr enable_if_t<B, descr<SizeA1, SizeA2>> _(descr<SizeA1, SizeA2> d, descr<SizeB1, SizeB2>) { return d; }
|
||||
template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
|
||||
constexpr enable_if_t<!B, descr<SizeB1, SizeB2>> _(descr<SizeA1, SizeA2>, descr<SizeB1, SizeB2> d) { return d; }
|
||||
|
||||
template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
|
||||
return int_to_str<Size / 10, Size % 10>::digits;
|
||||
}
|
||||
|
||||
template <typename Type> constexpr descr<1, 1> _() {
|
||||
return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr });
|
||||
}
|
||||
|
||||
inline constexpr descr<0, 0> concat() { return _(""); }
|
||||
template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; }
|
||||
template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); }
|
||||
template <size_t Size1, size_t Size2> auto constexpr type_descr(descr<Size1, Size2> descr) { return _("{") + descr + _("}"); }
|
||||
|
||||
#define PYBIND11_DESCR constexpr auto
|
||||
|
||||
#else /* Simpler C++11 implementation based on run-time memory allocation and copying */
|
||||
|
||||
class descr {
|
||||
public:
|
||||
PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) {
|
||||
size_t nChars = len(text), nTypes = len(types);
|
||||
m_text = new char[nChars];
|
||||
m_types = new const std::type_info *[nTypes];
|
||||
memcpy(m_text, text, nChars * sizeof(char));
|
||||
memcpy(m_types, types, nTypes * sizeof(const std::type_info *));
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE descr operator+(descr &&d2) && {
|
||||
descr r;
|
||||
|
||||
size_t nChars1 = len(m_text), nTypes1 = len(m_types);
|
||||
size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types);
|
||||
|
||||
r.m_text = new char[nChars1 + nChars2 - 1];
|
||||
r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1];
|
||||
memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char));
|
||||
memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char));
|
||||
memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *));
|
||||
memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *));
|
||||
|
||||
delete[] m_text; delete[] m_types;
|
||||
delete[] d2.m_text; delete[] d2.m_types;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *text() { return m_text; }
|
||||
const std::type_info * * types() { return m_types; }
|
||||
|
||||
protected:
|
||||
PYBIND11_NOINLINE descr() { }
|
||||
|
||||
template <typename T> static size_t len(const T *ptr) { // return length including null termination
|
||||
const T *it = ptr;
|
||||
while (*it++ != (T) 0)
|
||||
;
|
||||
return static_cast<size_t>(it - ptr);
|
||||
}
|
||||
|
||||
const std::type_info **m_types = nullptr;
|
||||
char *m_text = nullptr;
|
||||
};
|
||||
|
||||
/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */
|
||||
|
||||
PYBIND11_NOINLINE inline descr _(const char *text) {
|
||||
const std::type_info *types[1] = { nullptr };
|
||||
return descr(text, types);
|
||||
}
|
||||
|
||||
template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); }
|
||||
template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); }
|
||||
template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; }
|
||||
template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; }
|
||||
|
||||
template <typename Type> PYBIND11_NOINLINE descr _() {
|
||||
const std::type_info *types[2] = { &typeid(Type), nullptr };
|
||||
return descr("%", types);
|
||||
}
|
||||
|
||||
template <size_t Size> PYBIND11_NOINLINE descr _() {
|
||||
const std::type_info *types[1] = { nullptr };
|
||||
return descr(std::to_string(Size).c_str(), types);
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline descr concat() { return _(""); }
|
||||
PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; }
|
||||
template <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); }
|
||||
PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); }
|
||||
|
||||
#define PYBIND11_DESCR ::pybind11::detail::descr
|
||||
#endif
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(pybind11)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,194 @@
|
||||
/*
|
||||
pybind11/embed.h: Support for embedding the interpreter
|
||||
|
||||
Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
#include "eval.h"
|
||||
|
||||
#if defined(PYPY_VERSION)
|
||||
# error Embedding the interpreter is not supported with PyPy
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
extern "C" PyObject *pybind11_init_impl_##name() { \
|
||||
return pybind11_init_wrapper_##name(); \
|
||||
}
|
||||
#else
|
||||
# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
extern "C" void pybind11_init_impl_##name() { \
|
||||
pybind11_init_wrapper_##name(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \rst
|
||||
Add a new module to the table of builtins for the interpreter. Must be
|
||||
defined in global scope. The first macro parameter is the name of the
|
||||
module (without quotes). The second parameter is the variable which will
|
||||
be used as the interface to add functions and classes to the module.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
PYBIND11_EMBEDDED_MODULE(example, m) {
|
||||
// ... initialize functions and classes here
|
||||
m.def("foo", []() {
|
||||
return "Hello, World!";
|
||||
});
|
||||
}
|
||||
\endrst */
|
||||
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
||||
static void pybind11_init_##name(pybind11::module &); \
|
||||
static PyObject *pybind11_init_wrapper_##name() { \
|
||||
auto m = pybind11::module(#name); \
|
||||
try { \
|
||||
pybind11_init_##name(m); \
|
||||
return m.ptr(); \
|
||||
} catch (pybind11::error_already_set &e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
} catch (const std::exception &e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
} \
|
||||
} \
|
||||
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
|
||||
pybind11::detail::embedded_module name(#name, pybind11_init_impl_##name); \
|
||||
void pybind11_init_##name(pybind11::module &variable)
|
||||
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.
|
||||
struct embedded_module {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
using init_t = PyObject *(*)();
|
||||
#else
|
||||
using init_t = void (*)();
|
||||
#endif
|
||||
embedded_module(const char *name, init_t init) {
|
||||
if (Py_IsInitialized())
|
||||
pybind11_fail("Can't add new modules after the interpreter has been initialized");
|
||||
|
||||
auto result = PyImport_AppendInittab(name, init);
|
||||
if (result == -1)
|
||||
pybind11_fail("Insufficient memory to add a new module");
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
/** \rst
|
||||
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
|
||||
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
|
||||
optional parameter can be used to skip the registration of signal handlers (see the
|
||||
Python documentation for details). Calling this function again after the interpreter
|
||||
has already been initialized is a fatal error.
|
||||
\endrst */
|
||||
inline void initialize_interpreter(bool init_signal_handlers = true) {
|
||||
if (Py_IsInitialized())
|
||||
pybind11_fail("The interpreter is already running");
|
||||
|
||||
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
||||
|
||||
// Make .py files in the working directory available by default
|
||||
auto sys_path = reinterpret_borrow<list>(module::import("sys").attr("path"));
|
||||
sys_path.append(".");
|
||||
}
|
||||
|
||||
/** \rst
|
||||
Shut down the Python interpreter. No pybind11 or CPython API functions can be called
|
||||
after this. In addition, pybind11 objects must not outlive the interpreter:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
{ // BAD
|
||||
py::initialize_interpreter();
|
||||
auto hello = py::str("Hello, World!");
|
||||
py::finalize_interpreter();
|
||||
} // <-- BOOM, hello's destructor is called after interpreter shutdown
|
||||
|
||||
{ // GOOD
|
||||
py::initialize_interpreter();
|
||||
{ // scoped
|
||||
auto hello = py::str("Hello, World!");
|
||||
} // <-- OK, hello is cleaned up properly
|
||||
py::finalize_interpreter();
|
||||
}
|
||||
|
||||
{ // BETTER
|
||||
py::scoped_interpreter guard{};
|
||||
auto hello = py::str("Hello, World!");
|
||||
}
|
||||
|
||||
.. warning::
|
||||
|
||||
The interpreter can be restarted by calling `initialize_interpreter` again.
|
||||
Modules created using pybind11 can be safely re-initialized. However, Python
|
||||
itself cannot completely unload binary extension modules and there are several
|
||||
caveats with regard to interpreter restarting. All the details can be found
|
||||
in the CPython documentation. In short, not all interpreter memory may be
|
||||
freed, either due to reference cycles or user-created global data.
|
||||
|
||||
\endrst */
|
||||
inline void finalize_interpreter() {
|
||||
handle builtins(PyEval_GetBuiltins());
|
||||
const char *id = PYBIND11_INTERNALS_ID;
|
||||
|
||||
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the
|
||||
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
|
||||
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
|
||||
detail::internals **internals_ptr_ptr = &detail::get_internals_ptr();
|
||||
// It could also be stashed in builtins, so look there too:
|
||||
if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
|
||||
internals_ptr_ptr = capsule(builtins[id]);
|
||||
|
||||
Py_Finalize();
|
||||
|
||||
if (internals_ptr_ptr) {
|
||||
delete *internals_ptr_ptr;
|
||||
*internals_ptr_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** \rst
|
||||
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
|
||||
This a move-only guard and only a single instance can exist.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <pybind11/embed.h>
|
||||
|
||||
int main() {
|
||||
py::scoped_interpreter guard{};
|
||||
py::print(Hello, World!);
|
||||
} // <-- interpreter shutdown
|
||||
\endrst */
|
||||
class scoped_interpreter {
|
||||
public:
|
||||
scoped_interpreter(bool init_signal_handlers = true) {
|
||||
initialize_interpreter(init_signal_handlers);
|
||||
}
|
||||
|
||||
scoped_interpreter(const scoped_interpreter &) = delete;
|
||||
scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }
|
||||
scoped_interpreter &operator=(const scoped_interpreter &) = delete;
|
||||
scoped_interpreter &operator=(scoped_interpreter &&) = delete;
|
||||
|
||||
~scoped_interpreter() {
|
||||
if (is_valid)
|
||||
finalize_interpreter();
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_valid = true;
|
||||
};
|
||||
|
||||
NAMESPACE_END(pybind11)
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
pybind11/exec.h: Support for evaluating Python expressions and statements
|
||||
from strings and files
|
||||
|
||||
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
|
||||
Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
|
||||
enum eval_mode {
|
||||
/// Evaluate a string containing an isolated expression
|
||||
eval_expr,
|
||||
|
||||
/// Evaluate a string containing a single statement. Returns \c none
|
||||
eval_single_statement,
|
||||
|
||||
/// Evaluate a string containing a sequence of statement. Returns \c none
|
||||
eval_statements
|
||||
};
|
||||
|
||||
template <eval_mode mode = eval_expr>
|
||||
object eval(str expr, object global = globals(), object local = object()) {
|
||||
if (!local)
|
||||
local = global;
|
||||
|
||||
/* PyRun_String does not accept a PyObject / encoding specifier,
|
||||
this seems to be the only alternative */
|
||||
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
||||
|
||||
int start;
|
||||
switch (mode) {
|
||||
case eval_expr: start = Py_eval_input; break;
|
||||
case eval_single_statement: start = Py_single_input; break;
|
||||
case eval_statements: start = Py_file_input; break;
|
||||
default: pybind11_fail("invalid evaluation mode");
|
||||
}
|
||||
|
||||
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return reinterpret_steal<object>(result);
|
||||
}
|
||||
|
||||
template <eval_mode mode = eval_expr, size_t N>
|
||||
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
||||
/* Support raw string literals by removing common leading whitespace */
|
||||
auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s))
|
||||
: str(s);
|
||||
return eval<mode>(expr, global, local);
|
||||
}
|
||||
|
||||
inline void exec(str expr, object global = globals(), object local = object()) {
|
||||
eval<eval_statements>(expr, global, local);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void exec(const char (&s)[N], object global = globals(), object local = object()) {
|
||||
eval<eval_statements>(s, global, local);
|
||||
}
|
||||
|
||||
template <eval_mode mode = eval_statements>
|
||||
object eval_file(str fname, object global = globals(), object local = object()) {
|
||||
if (!local)
|
||||
local = global;
|
||||
|
||||
int start;
|
||||
switch (mode) {
|
||||
case eval_expr: start = Py_eval_input; break;
|
||||
case eval_single_statement: start = Py_single_input; break;
|
||||
case eval_statements: start = Py_file_input; break;
|
||||
default: pybind11_fail("invalid evaluation mode");
|
||||
}
|
||||
|
||||
int closeFile = 1;
|
||||
std::string fname_str = (std::string) fname;
|
||||
#if PY_VERSION_HEX >= 0x03040000
|
||||
FILE *f = _Py_fopen_obj(fname.ptr(), "r");
|
||||
#elif PY_VERSION_HEX >= 0x03000000
|
||||
FILE *f = _Py_fopen(fname.ptr(), "r");
|
||||
#else
|
||||
/* No unicode support in open() :( */
|
||||
auto fobj = reinterpret_steal<object>(PyFile_FromString(
|
||||
const_cast<char *>(fname_str.c_str()),
|
||||
const_cast<char*>("r")));
|
||||
FILE *f = nullptr;
|
||||
if (fobj)
|
||||
f = PyFile_AsFile(fobj.ptr());
|
||||
closeFile = 0;
|
||||
#endif
|
||||
if (!f) {
|
||||
PyErr_Clear();
|
||||
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
|
||||
PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
|
||||
local.ptr());
|
||||
(void) closeFile;
|
||||
#else
|
||||
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
|
||||
local.ptr(), closeFile);
|
||||
#endif
|
||||
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return reinterpret_steal<object>(result);
|
||||
}
|
||||
|
||||
NAMESPACE_END(pybind11)
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
pybind11/functional.h: std::function<> support
|
||||
|
||||
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pybind11.h"
|
||||
#include <functional>
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename Return, typename... Args>
|
||||
struct type_caster<std::function<Return(Args...)>> {
|
||||
using type = std::function<Return(Args...)>;
|
||||
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||
using function_type = Return (*) (Args...);
|
||||
|
||||
public:
|
||||
bool load(handle src, bool convert) {
|
||||
if (src.is_none()) {
|
||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||
if (!convert) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isinstance<function>(src))
|
||||
return false;
|
||||
|
||||
auto func = reinterpret_borrow<function>(src);
|
||||
|
||||
/*
|
||||
When passing a C++ function as an argument to another C++
|
||||
function via Python, every function call would normally involve
|
||||
a full C++ -> Python -> C++ roundtrip, which can be prohibitive.
|
||||
Here, we try to at least detect the case where the function is
|
||||
stateless (i.e. function pointer or lambda function without
|
||||
captured variables), in which case the roundtrip can be avoided.
|
||||
*/
|
||||
if (auto cfunc = func.cpp_function()) {
|
||||
auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
|
||||
auto rec = (function_record *) c;
|
||||
|
||||
if (rec && rec->is_stateless &&
|
||||
same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
|
||||
struct capture { function_type f; };
|
||||
value = ((capture *) &rec->data)->f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
value = [func](Args... args) -> Return {
|
||||
gil_scoped_acquire acq;
|
||||
object retval(func(std::forward<Args>(args)...));
|
||||
/* Visual studio 2015 parser issue: need parentheses around this expression */
|
||||
return (retval.template cast<Return>());
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
||||
if (!f_)
|
||||
return none().inc_ref();
|
||||
|
||||
auto result = f_.template target<function_type>();
|
||||
if (result)
|
||||
return cpp_function(*result, policy).release();
|
||||
else
|
||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("Callable[[") +
|
||||
argument_loader<Args...>::arg_names() + _("], ") +
|
||||
make_caster<retval_type>::name() +
|
||||
_("]"));
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(pybind11)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue