Skip to content

Commit 444af65

Browse files
committed
WIP optimize append and write
1 parent f2db975 commit 444af65

4 files changed

Lines changed: 67 additions & 17 deletions

File tree

mypyc/lib-rt/librt_strings.c

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,11 @@
77
#include "librt_strings.h"
88

99
#define CPY_BOOL_ERROR 2
10-
#define CPY_NONE_ERROR 2
11-
#define CPY_NONE 1
1210

1311
//
1412
// BytesWriter
1513
//
1614

17-
// Length of the default buffer embedded directly in a BytesWriter object
18-
#define WRITER_EMBEDDED_BUF_LEN 512
19-
20-
typedef struct {
21-
PyObject_HEAD
22-
char *buf; // Beginning of the buffer
23-
Py_ssize_t len; // Current length (number of bytes written)
24-
Py_ssize_t capacity; // Total capacity of the buffer
25-
char data[WRITER_EMBEDDED_BUF_LEN]; // Default buffer
26-
} BytesWriterObject;
27-
2815
#define _WRITE(data, type, v) \
2916
do { \
3017
*(type *)(((BytesWriterObject *)data)->buf + ((BytesWriterObject *)data)->len) = v; \
@@ -426,7 +413,7 @@ librt_strings_module_exec(PyObject *m)
426413
(void *)BytesWriter_internal,
427414
(void *)BytesWriter_getvalue_internal,
428415
(void *)BytesWriter_append_internal,
429-
(void *)BytesWriter_write_internal,
416+
(void *)_grow_buffer,
430417
(void *)BytesWriter_type_internal,
431418
(void *)BytesWriter_len_internal,
432419
(void *)BytesWriter_truncate_internal,

mypyc/lib-rt/librt_strings.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,23 @@ import_librt_strings(void)
2828

2929
static void *LibRTStrings_API[LIBRT_STRINGS_API_LEN];
3030

31+
// Length of the default buffer embedded directly in a BytesWriter object
32+
#define WRITER_EMBEDDED_BUF_LEN 512
33+
34+
typedef struct {
35+
PyObject_HEAD
36+
char *buf; // Beginning of the buffer
37+
Py_ssize_t len; // Current length (number of bytes written)
38+
Py_ssize_t capacity; // Total capacity of the buffer
39+
char data[WRITER_EMBEDDED_BUF_LEN]; // Default buffer
40+
} BytesWriterObject;
41+
3142
#define LibRTStrings_ABIVersion (*(int (*)(void)) LibRTStrings_API[0])
3243
#define LibRTStrings_APIVersion (*(int (*)(void)) LibRTStrings_API[1])
3344
#define LibRTStrings_BytesWriter_internal (*(PyObject* (*)(void)) LibRTStrings_API[2])
3445
#define LibRTStrings_BytesWriter_getvalue_internal (*(PyObject* (*)(PyObject *source)) LibRTStrings_API[3])
3546
#define LibRTStrings_BytesWriter_append_internal (*(char (*)(PyObject *source, uint8_t value)) LibRTStrings_API[4])
36-
#define LibRTStrings_BytesWriter_write_internal (*(char (*)(PyObject *source, PyObject *value)) LibRTStrings_API[5])
47+
#define LibRTStrings_ByteWriter_grow_buffer_internal (*(bool (*)(BytesWriterObject *obj, Py_ssize_t size)) LibRTStrings_API[5])
3748
#define LibRTStrings_BytesWriter_type_internal (*(PyTypeObject* (*)(void)) LibRTStrings_API[6])
3849
#define LibRTStrings_BytesWriter_len_internal (*(CPyTagged (*)(PyObject *self)) LibRTStrings_API[7])
3950
#define LibRTStrings_BytesWriter_truncate_internal (*(char (*)(PyObject *self, int64_t size)) LibRTStrings_API[8])
@@ -75,6 +86,54 @@ static inline bool CPyBytesWriter_Check(PyObject *obj) {
7586
return Py_TYPE(obj) == LibRTStrings_BytesWriter_type_internal();
7687
}
7788

89+
static inline bool
90+
CPyBytesWriter_EnsureSize(BytesWriterObject *data, Py_ssize_t n) {
91+
if (likely(data->capacity - data->len >= n)) {
92+
return true;
93+
} else {
94+
return LibRTStrings_ByteWriter_grow_buffer_internal(data, n);
95+
}
96+
}
97+
98+
static inline char
99+
CPyBytesWriter_Append(PyObject *obj, uint8_t value) {
100+
BytesWriterObject *self = (BytesWriterObject *)obj;
101+
// Store length in a local variable to enable additional optimizations
102+
Py_ssize_t len = self->len;
103+
if (!CPyBytesWriter_EnsureSize(self, 1))
104+
return CPY_NONE_ERROR;
105+
self->buf[len] = value;
106+
self->len = len + 1;
107+
return CPY_NONE;
108+
}
109+
110+
static char
111+
CPyBytesWriter_Write(PyObject *obj, PyObject *value) {
112+
BytesWriterObject *self = (BytesWriterObject *)obj;
113+
const char *data;
114+
Py_ssize_t size;
115+
if (likely(PyBytes_Check(value))) {
116+
data = PyBytes_AS_STRING(value);
117+
size = PyBytes_GET_SIZE(value);
118+
} else {
119+
data = PyByteArray_AS_STRING(value);
120+
size = PyByteArray_GET_SIZE(value);
121+
}
122+
// Write bytes content.
123+
if (!CPyBytesWriter_EnsureSize(self, size))
124+
return CPY_NONE_ERROR;
125+
if (size < 8) {
126+
char *p = self->buf + self->len;
127+
for (Py_ssize_t i = 0; i < size; i++) {
128+
p[i] = data[i];
129+
}
130+
} else {
131+
memcpy(self->buf + self->len, data, size);
132+
}
133+
self->len += size;
134+
return CPY_NONE;
135+
}
136+
78137
#endif // MYPYC_EXPERIMENTAL
79138

80139
#endif // LIBRT_STRINGS_H

mypyc/lib-rt/mypyc_util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ typedef PyObject CPyModule;
142142
// Error value for floats
143143
#define CPY_FLOAT_ERROR -113.0
144144

145+
// Value for 'None' primitive type
146+
#define CPY_NONE_ERROR 2
147+
#define CPY_NONE 1
148+
145149
typedef void (*CPyVTableItem)(void);
146150

147151
static inline CPyTagged CPyTagged_ShortFromInt(int x) {

mypyc/primitives/librt_strings_ops.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
name="write",
3939
arg_types=[bytes_writer_rprimitive, bytes_rprimitive],
4040
return_type=none_rprimitive,
41-
c_function_name="LibRTStrings_BytesWriter_write_internal",
41+
c_function_name="CPyBytesWriter_Write",
4242
error_kind=ERR_MAGIC,
4343
experimental=True,
4444
dependencies=[LIBRT_STRINGS],
@@ -48,7 +48,7 @@
4848
name="append",
4949
arg_types=[bytes_writer_rprimitive, uint8_rprimitive],
5050
return_type=none_rprimitive,
51-
c_function_name="LibRTStrings_BytesWriter_append_internal",
51+
c_function_name="CPyBytesWriter_Append",
5252
error_kind=ERR_MAGIC,
5353
experimental=True,
5454
dependencies=[LIBRT_STRINGS],

0 commit comments

Comments
 (0)