15
15
16
16
#ifdef HAVE_PYTHON
17
17
18
+ #include " vector_string.h"
19
+
18
20
/* *
19
21
* Extracts the indicated number of bytes in the stream and returns them as a
20
22
* string (or bytes, in Python 3). Returns empty string at end-of-file.
@@ -23,13 +25,25 @@ PyObject *Extension<StreamReader>::
23
25
extract_bytes (size_t size) {
24
26
std::istream *in = _this->get_istream ();
25
27
if (in->eof () || in->fail () || size == 0 ) {
28
+ // Note that this is only safe to call with size 0 while the GIL is held.
26
29
return PyBytes_FromStringAndSize (nullptr , 0 );
27
30
}
28
31
29
32
PyObject *bytes = PyBytes_FromStringAndSize (nullptr , size);
30
- in->read (PyBytes_AS_STRING (bytes), size);
33
+ char *buffer = (char *)PyBytes_AS_STRING (bytes);
34
+
35
+ #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
36
+ PyThreadState *_save;
37
+ Py_UNBLOCK_THREADS
38
+ #endif // HAVE_THREADS && !SIMPLE_THREADS
39
+
40
+ in->read (buffer, size);
31
41
size_t read_bytes = in->gcount ();
32
42
43
+ #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
44
+ Py_BLOCK_THREADS
45
+ #endif // HAVE_THREADS && !SIMPLE_THREADS
46
+
33
47
if (read_bytes == size || _PyBytes_Resize (&bytes, read_bytes) == 0 ) {
34
48
return bytes;
35
49
} else {
@@ -47,6 +61,11 @@ extract_bytes(size_t size) {
47
61
*/
48
62
PyObject *Extension<StreamReader>::
49
63
readline () {
64
+ #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
65
+ PyThreadState *_save;
66
+ Py_UNBLOCK_THREADS
67
+ #endif // HAVE_THREADS && !SIMPLE_THREADS
68
+
50
69
std::istream *in = _this->get_istream ();
51
70
52
71
std::string line;
@@ -60,6 +79,10 @@ readline() {
60
79
ch = in->get ();
61
80
}
62
81
82
+ #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
83
+ Py_BLOCK_THREADS
84
+ #endif // HAVE_THREADS && !SIMPLE_THREADS
85
+
63
86
#if PY_MAJOR_VERSION >= 3
64
87
return PyBytes_FromStringAndSize (line.data (), line.size ());
65
88
#else
@@ -73,22 +96,50 @@ readline() {
73
96
*/
74
97
PyObject *Extension<StreamReader>::
75
98
readlines () {
76
- PyObject *lst = PyList_New (0 );
99
+ #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
100
+ PyThreadState *_save;
101
+ Py_UNBLOCK_THREADS
102
+ #endif // HAVE_THREADS && !SIMPLE_THREADS
103
+
104
+ std::istream *in = _this->get_istream ();
105
+ vector_string lines;
106
+
107
+ while (true ) {
108
+ std::string line;
109
+ int ch = in->get ();
110
+ while (ch != EOF && !in->fail ()) {
111
+ line += ch;
112
+ if (ch == ' \n ' || in->eof ()) {
113
+ // Here's the newline character.
114
+ break ;
115
+ }
116
+ ch = in->get ();
117
+ }
118
+
119
+ if (line.empty ()) {
120
+ break ;
121
+ }
122
+
123
+ lines.push_back (std::move (line));
124
+ }
125
+
126
+ #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
127
+ Py_BLOCK_THREADS
128
+ #endif // HAVE_THREADS && !SIMPLE_THREADS
129
+
130
+ PyObject *lst = PyList_New (lines.size ());
77
131
if (lst == nullptr ) {
78
132
return nullptr ;
79
133
}
80
134
81
- PyObject *py_line = readline () ;
82
-
135
+ Py_ssize_t i = 0 ;
136
+ for ( const std::string &line : lines) {
83
137
#if PY_MAJOR_VERSION >= 3
84
- while ( PyBytes_GET_SIZE ( py_line) > 0 ) {
138
+ PyObject * py_line = PyBytes_FromStringAndSize (line. data (), line. size ());
85
139
#else
86
- while ( PyString_GET_SIZE ( py_line) > 0 ) {
140
+ PyObject * py_line = PyString_FromStringAndSize (line. data (), line. size ());
87
141
#endif
88
- PyList_Append (lst, py_line);
89
- Py_DECREF (py_line);
90
-
91
- py_line = readline ();
142
+ PyList_SET_ITEM (lst, i++, py_line);
92
143
}
93
144
94
145
return lst;
0 commit comments