NEURON
pybind_utils.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #pragma once
9 
10 #include <memory>
11 #include <pybind11/iostream.h>
12 #include <pybind11/pybind11.h>
13 #include <pybind11/stl.h>
14 
15 
16 namespace pybind11 {
17 namespace detail {
18 
19 template <typename StringType>
21  void operator()(char* start, size_t n, StringType data) {
22  char* buffer;
23  ssize_t length;
24  if (PYBIND11_BYTES_AS_STRING_AND_SIZE(data.ptr(), &buffer, &length))
25  pybind11_fail("Unable to extract string contents! (invalid type)");
26  std::memcpy(start, buffer, n);
27  }
28 };
29 
30 
31 template <>
32 struct CopyFromPython<str> {
33  void operator()(char* start, size_t n, str data) {
34  if (PyUnicode_Check(data.ptr())) {
35  data = reinterpret_steal<object>(PyUnicode_AsUTF8String(data.ptr()));
36  if (!data)
37  pybind11_fail("Unable to extract string contents! (encoding issue)");
38  }
39  CopyFromPython<bytes>()(start, n, data);
40  }
41 };
42 
43 
44 template <typename StringType>
45 class pythonibuf: public std::streambuf {
46  private:
47  using traits_type = std::streambuf::traits_type;
48 
49  const static std::size_t put_back_ = 1;
50  const static std::size_t buf_sz = 1024 + put_back_;
52 
53  object pyistream;
54  object pyread;
55 
56  // copy ctor and assignment not implemented;
57  // copying not allowed
60 
61  int_type underflow() {
62  if (gptr() < egptr()) { // buffer not exhausted
63  return traits_type::to_int_type(*gptr());
64  }
65 
66  char* base = d_buffer;
67  char* start = base;
68  if (eback() == base) {
69  std::memmove(base, egptr() - put_back_, put_back_);
70  start += put_back_;
71  }
72  StringType data = pyread(buf_sz - (start - base));
73  size_t n = len(data);
74  if (n == 0) {
75  return traits_type::eof();
76  }
78  setg(base, start, start + n);
79  return traits_type::to_int_type(*gptr());
80  }
81 
82 
83  public:
86  , pyread(pyistream.attr("read")) {
87  char* end = d_buffer + buf_sz;
88  setg(end, end, end);
89  }
90 };
91 } // namespace detail
92 } // namespace pybind11
93 
95  protected:
96  std::unique_ptr<pybind11::detail::pythonbuf> buf;
97  std::unique_ptr<std::ostream> ostream;
98 
99  public:
101  VisitorOStreamResources(pybind11::object object)
102  : buf(new pybind11::detail::pythonbuf(object))
103  , ostream(new std::ostream(buf.get())) {}
104  void flush() {
105  ostream->flush();
106  }
107 };
VisitorOStreamResources()=default
std::unique_ptr< std::ostream > ostream
std::unique_ptr< pybind11::detail::pythonbuf > buf
VisitorOStreamResources(pybind11::object object)
pythonibuf & operator=(const pythonibuf &)
std::streambuf::traits_type traits_type
pythonibuf(object pyistream)
pythonibuf(const pythonibuf &)
static const std::size_t buf_sz
static const std::size_t put_back_
#define data
Definition: md1redef.h:36
int const size_t const size_t n
Definition: nrngsl.h:10
int get()
Definition: units.cpp:918
void operator()(char *start, size_t n, str data)
void operator()(char *start, size_t n, StringType data)