Skip to content

Commit 8fd58b5

Browse files
committed
initial commit
0 parents  commit 8fd58b5

14 files changed

+744
-0
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "ext/robin_map"]
2+
path = ext/robin_map
3+
url = https://github.com/Tessil/robin-map

CMakeLists.txt

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
cmake_minimum_required(VERSION 3.17...3.22)
2+
project(nanobind)
3+
4+
find_package(Python COMPONENTS Interpreter Development)
5+
6+
add_library(nanobind-core STATIC
7+
src/module.cpp
8+
src/func.cpp
9+
)
10+
target_compile_features(nanobind-core INTERFACE cxx_std_17)
11+
set_target_properties(nanobind-core PROPERTIES
12+
CXX_VISIBILITY_PRESET hidden
13+
POSITION_INDEPENDENT_CODE ON
14+
)
15+
target_compile_features(nanobind-core PRIVATE cxx_std_17)
16+
target_include_directories(nanobind-core PRIVATE
17+
${CMAKE_CURRENT_SOURCE_DIR}/include
18+
${Python_INCLUDE_DIRS})
19+
20+
function(nanobind_add_module name)
21+
if (MSVC)
22+
set(NB_OPT_SIZE /Os)
23+
else()
24+
set(NB_OPT_SIZE -Os)
25+
endif()
26+
27+
set(NB_SUFFIX ".so")
28+
set(NB_COMPILE_OPTIONS
29+
$<$<CONFIG:Release>:${NB_OPT_SIZE}>
30+
$<$<CONFIG:MinSizeRel>:${NB_OPT_SIZE}>
31+
$<$<CONFIG:RelWithDebInfo>:${NB_OPT_SIZE}>)
32+
33+
if(MSVC)
34+
set(NB_COMPILE_OPTIONS ${NB_COMPILE_OPTIONS} /bigobj /MP)
35+
set(NB_SUFFIX ".pyd")
36+
endif()
37+
38+
add_library(${name} MODULE ${ARGV1})
39+
set_target_properties(${name} PROPERTIES CXX_VISIBILITY_PRESET hidden)
40+
target_compile_features(${name} PRIVATE cxx_std_17)
41+
target_compile_options(${name} PRIVATE ${NB_COMPILE_OPTIONS})
42+
target_link_libraries(${name} nanobind-core)
43+
set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".${Python_SOABI}${NB_SUFFIX}")
44+
target_include_directories(${name} PRIVATE
45+
${CMAKE_CURRENT_SOURCE_DIR}/include
46+
${Python_INCLUDE_DIRS})
47+
48+
if (APPLE)
49+
target_link_options(${name} PRIVATE -undefined dynamic_lookup)
50+
endif()
51+
endfunction()
52+
53+
nanobind_add_module(
54+
nbtest
55+
nbtest.cpp
56+
)

ext/robin_map

Submodule robin_map added at a603419

include/nanobind/nanobind.h

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#if __cplusplus < 201703L
2+
# error NanoBind requires C++17
3+
#endif
4+
5+
#include <stdexcept>
6+
#include <type_traits>
7+
#include <new>
8+
9+
#include "nb_python.h"
10+
#include "nb_defs.h"
11+
#include "nb_lib.h"
12+
#include "nb_types.h"
13+
#include "nb_attr.h"
14+
#include "nb_func.h"

include/nanobind/nb_attr.h

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
NAMESPACE_BEGIN(nanobind)
2+
3+
struct scope {
4+
handle value;
5+
scope(handle value) : value(value) { }
6+
};
7+
8+
struct pred {
9+
handle value;
10+
pred(handle value) : value(value) { }
11+
};
12+
13+
struct name {
14+
const char *value;
15+
name(const char *value) : value(value) { }
16+
};
17+
18+
NAMESPACE_BEGIN(detail)
19+
20+
inline void func_apply(void *func_rec, const pred &pred) {
21+
func_set_pred(func_rec, pred.value.ptr());
22+
}
23+
24+
inline void func_apply(void *func_rec, const scope &scope) {
25+
func_set_scope(func_rec, scope.value.ptr());
26+
}
27+
28+
inline void func_apply(void *func_rec, const name &name) {
29+
func_set_name(func_rec, name.value);
30+
}
31+
32+
inline void func_apply(void *func_rec, const char *docstr) {
33+
func_set_docstr(func_rec, docstr);
34+
}
35+
36+
NAMESPACE_END(detail)
37+
38+
NAMESPACE_END(nanobind)

include/nanobind/nb_defs.h

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#define NB_STRINGIFY(x) #x
2+
#define NB_TOSTRING(x) NB_STRINGIFY(x)
3+
#define NB_CONCAT(first, second) first##second
4+
5+
#if !defined(NAMESPACE_BEGIN)
6+
# define NAMESPACE_BEGIN(name) namespace name {
7+
#endif
8+
9+
#if !defined(NAMESPACE_END)
10+
# define NAMESPACE_END(name) }
11+
#endif
12+
13+
#if !defined(NB_EXPORT)
14+
# if defined(_WIN32)
15+
# define NB_EXPORT __declspec(dllexport)
16+
# else
17+
# define NB_EXPORT __attribute__ ((visibility("default")))
18+
# endif
19+
#endif
20+
21+
#define NB_MODULE(name, variable) \
22+
extern "C" [[maybe_unused]] NB_EXPORT PyObject *PyInit_##name(); \
23+
static PyModuleDef NB_CONCAT(nanobind_module_def_, name); \
24+
[[maybe_unused]] static void NB_CONCAT(nanobind_init_, \
25+
name)(::nanobind::module_ &); \
26+
extern "C" NB_EXPORT PyObject *PyInit_##name() { \
27+
nanobind::module_ m = nanobind::reinterpret_borrow<nanobind::module_>( \
28+
nanobind::detail::module_new( \
29+
NB_TOSTRING(name), &NB_CONCAT(nanobind_module_def_, name))); \
30+
try { \
31+
NB_CONCAT(nanobind_init_, name)(m); \
32+
return m.ptr(); \
33+
} catch (const std::exception &e) { \
34+
PyErr_SetString(PyExc_ImportError, e.what()); \
35+
return nullptr; \
36+
} \
37+
} \
38+
void NB_CONCAT(nanobind_init_, name)(::nanobind::module_ & (variable))

include/nanobind/nb_func.h

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
NAMESPACE_BEGIN(nanobind)
2+
NAMESPACE_BEGIN(detail)
3+
4+
template <typename Func, typename Return, typename... Args, typename... Extra>
5+
object func_create(Func &&f, Return (*)(Args...), const Extra &...extra) {
6+
struct capture {
7+
std::remove_reference_t<Func> f;
8+
};
9+
10+
// Store the capture object in the function record if there is space
11+
constexpr bool IsSmall = sizeof(capture) <= sizeof(void *) * 3;
12+
constexpr bool IsTrivial = std::is_trivially_destructible_v<capture>;
13+
14+
void *func_rec = func_alloc();
15+
void (*free_capture)(void *ptr) = nullptr;
16+
17+
if constexpr (IsSmall) {
18+
capture *cap = std::launder((capture *) func_rec);
19+
new (cap) capture{ std::forward<Func>(f) };
20+
21+
if constexpr (!IsTrivial) {
22+
free_capture = [](void *func_rec_2) {
23+
capture *cap_2 = std::launder((capture *) func_rec_2);
24+
cap_2->~capture();
25+
};
26+
}
27+
} else {
28+
void **cap = std::launder((void **) func_rec);
29+
cap[0] = new capture{ std::forward<Func>(f) };
30+
31+
free_capture = [](void *func_rec_2) {
32+
void **cap_2 = std::launder((void **) func_rec_2);
33+
delete (capture *) cap_2[0];
34+
};
35+
}
36+
37+
auto impl = [](void *func_rec_2) -> PyObject * {
38+
capture *cap;
39+
if constexpr (IsSmall)
40+
cap = std::launder((capture *) func_rec_2);
41+
else
42+
cap = std::launder((void **) func_rec_2)[0];
43+
44+
cap->f();
45+
46+
return nullptr;
47+
};
48+
49+
(detail::func_apply(func_rec, extra), ...);
50+
51+
return reinterpret_steal<object>(func_init(func_rec, free_capture, impl));
52+
}
53+
54+
template <typename T>
55+
constexpr bool is_lambda_v = !std::is_function_v<T> && !std::is_pointer_v<T> &&
56+
!std::is_member_pointer_v<T>;
57+
58+
59+
/// Strip the class from a method type
60+
template <typename T> struct remove_class { };
61+
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { using type = R (A...); };
62+
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { using type = R (A...); };
63+
64+
NAMESPACE_END(detail)
65+
66+
template <bool V> using enable_if_t = std::enable_if_t<V, int>;
67+
68+
template <typename Return, typename... Args, typename... Extra>
69+
object cpp_function(Return (*f)(Args...), const Extra&... extra) {
70+
return detail::func_create(f, f, extra...);
71+
}
72+
73+
/// Construct a cpp_function from a lambda function (possibly with internal state)
74+
template <typename Func, typename... Extra,
75+
enable_if_t<detail::is_lambda_v<std::remove_reference_t<Func>>> = 0>
76+
object cpp_function(Func &&f, const Extra &...extra) {
77+
using RawFunc =
78+
typename detail::remove_class<decltype(&Func::operator())>::type;
79+
return detail::func_create(std::forward<Func>(f), (RawFunc *) nullptr,
80+
extra...);
81+
}
82+
83+
/// Construct a cpp_function from a class method (non-const, no ref-qualifier)
84+
template <typename Return, typename Class, typename... Args, typename... Extra>
85+
object cpp_function(Return (Class::*f)(Args...), const Extra&... extra) {
86+
return detail::func_create(
87+
[f](Class *c, Args... args) -> Return {
88+
return (c->*f)(std::forward<Args>(args)...);
89+
},
90+
(Return(*)(Class *, Args...)) nullptr, extra...);
91+
}
92+
93+
/// Construct a cpp_function from a class method (const, no ref-qualifier)
94+
template <typename Return, typename Class, typename... Args, typename... Extra>
95+
object cpp_function(Return (Class::*f)(Args...) const, const Extra &...extra) {
96+
return detail::func_create(
97+
[f](const Class *c, Args... args) -> Return {
98+
return (c->*f)(std::forward<Args>(args)...);
99+
},
100+
(Return(*)(const Class *, Args...)) nullptr, extra...);
101+
}
102+
103+
template <typename Func, typename... Extra>
104+
module_ &module_::def(const char *name_, Func &&f, const Extra &...extra) {
105+
object func = cpp_function(std::forward<Func>(f), name(name_), scope(*this),
106+
pred(getattr(*this, name_, none())), extra...);
107+
if (PyModule_AddObject(m_ptr, name_, func.release().ptr()))
108+
detail::fail("module::def(): could not add object!");
109+
return *this;
110+
}
111+
112+
NAMESPACE_END(nanobind)

include/nanobind/nb_lib.h

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
NAMESPACE_BEGIN(nanobind)
2+
NAMESPACE_BEGIN(detail)
3+
4+
// ========================================================================
5+
6+
/// Raise a std::runtime_error with the given message
7+
#if defined(__GNUC__)
8+
__attribute__((noreturn, __format__ (__printf__, 1, 2)))
9+
#else
10+
[[noreturn]]
11+
#endif
12+
extern void raise(const char *fmt, ...);
13+
14+
/// Abort the process with a fatal error
15+
#if defined(__GNUC__)
16+
__attribute__((noreturn, nothrow, __format__ (__printf__, 1, 2)))
17+
#else
18+
[[noreturn, noexcept]]
19+
#endif
20+
extern void fail(const char *fmt, ...);
21+
22+
// ========================================================================
23+
24+
/// Create a new capsule object
25+
extern PyObject *capsule_new(const void *ptr, void (*free)(void *)) noexcept;
26+
27+
/// Create a new extension module with the given name
28+
extern PyObject *module_new(const char *name, PyModuleDef *def) noexcept;
29+
30+
// ========================================================================
31+
32+
/// Create a new handle for a function to be bound
33+
extern void *func_alloc() noexcept;
34+
35+
/// Free all memory associated with a function handle
36+
extern void func_free(void *handle) noexcept;
37+
38+
/// Annotate a function handle with the given flag
39+
extern void func_set_flag(void *handle, uint32_t flag) noexcept;
40+
41+
/// Set the function name
42+
extern void func_set_name(void *handle, const char *name) noexcept;
43+
44+
/// Set the function docstring
45+
extern void func_set_docstr(void *handle, const char *docstr) noexcept;
46+
47+
/// Set the function scope
48+
extern void func_set_scope(void *handle, PyObject *scope) noexcept;
49+
50+
/// Set the predecessor of a overload chain
51+
extern void func_set_pred(void *handle, PyObject *pred) noexcept;
52+
53+
/// Create a Python function object for the given function handle
54+
extern PyObject *func_init(void *handle, void (*free_captured)(void *),
55+
PyObject *(*impl)(void *)) noexcept;
56+
57+
NAMESPACE_END(detail)
58+
NAMESPACE_END(nanobind)

include/nanobind/nb_python.h

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
2+
#if defined(_MSC_VER)
3+
# pragma warning(push)
4+
// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only)
5+
# pragma warning(disable: 4505)
6+
# if defined(_DEBUG) && !defined(Py_DEBUG)
7+
# define PYBIND11_DEBUG_MARKER
8+
# undef _DEBUG
9+
# endif
10+
#endif
11+
12+
#include <Python.h>
13+
#include <frameobject.h>
14+
#include <pythread.h>
15+
16+
/* Python #defines overrides on all sorts of core functions, which
17+
tends to weak havok in C++ codebases that expect these to work
18+
like regular functions (potentially with several overloads) */
19+
#if defined(isalnum)
20+
# undef isalnum
21+
# undef isalpha
22+
# undef islower
23+
# undef isspace
24+
# undef isupper
25+
# undef tolower
26+
# undef toupper
27+
#endif
28+
29+
#if defined(copysign)
30+
# undef copysign
31+
#endif
32+
33+
#if defined(_MSC_VER)
34+
# if defined(PYBIND11_DEBUG_MARKER)
35+
# define _DEBUG
36+
# undef PYBIND11_DEBUG_MARKER
37+
# endif
38+
# pragma warning(pop)
39+
#endif

0 commit comments

Comments
 (0)