|
8 | 8 | #define START_SIZE 512 |
9 | 9 | #define MAX_SHORT_INT_TAGGED (255 << 1) |
10 | 10 |
|
| 11 | +#define MAX_SHORT_LEN 127 |
| 12 | +#define LONG_STR_TAG 1 |
| 13 | + |
| 14 | +#define MIN_SHORT_INT (-10) |
| 15 | +#define MAX_SHORT_INT 117 |
| 16 | +#define MEDIUM_INT_TAG 1 |
| 17 | +#define LONG_INT_TAG 3 |
| 18 | + |
11 | 19 | typedef struct { |
12 | 20 | PyObject_HEAD |
13 | 21 | Py_ssize_t pos; |
@@ -230,15 +238,22 @@ read_str_internal(PyObject *data) { |
230 | 238 | if (_check_buffer(data) == 2) |
231 | 239 | return NULL; |
232 | 240 |
|
233 | | - if (_check_read((BufferObject *)data, sizeof(Py_ssize_t)) == 2) |
234 | | - return NULL; |
| 241 | + Py_ssize_t size; |
235 | 242 | char *buf = ((BufferObject *)data)->buf; |
236 | 243 | // Read string length. |
237 | | - Py_ssize_t size = *(Py_ssize_t *)(buf + ((BufferObject *)data)->pos); |
238 | | - ((BufferObject *)data)->pos += sizeof(Py_ssize_t); |
239 | | - if (_check_read((BufferObject *)data, size) == 2) |
| 244 | + if (_check_read((BufferObject *)data, 1) == 2) |
240 | 245 | return NULL; |
| 246 | + uint8_t first = *(uint8_t *)(buf + ((BufferObject *)data)->pos); |
| 247 | + ((BufferObject *)data)->pos += 1; |
| 248 | + if (first != LONG_STR_TAG) { |
| 249 | + size = (Py_ssize_t)(first >> 1); |
| 250 | + } else { |
| 251 | + size = *(Py_ssize_t *)(buf + ((BufferObject *)data)->pos); |
| 252 | + ((BufferObject *)data)->pos += sizeof(Py_ssize_t); |
| 253 | + } |
241 | 254 | // Read string content. |
| 255 | + if (_check_read((BufferObject *)data, size) == 2) |
| 256 | + return NULL; |
242 | 257 | PyObject *res = PyUnicode_FromStringAndSize( |
243 | 258 | buf + ((BufferObject *)data)->pos, (Py_ssize_t)size |
244 | 259 | ); |
@@ -266,14 +281,28 @@ write_str_internal(PyObject *data, PyObject *value) { |
266 | 281 | const char *chunk = PyUnicode_AsUTF8AndSize(value, &size); |
267 | 282 | if (!chunk) |
268 | 283 | return 2; |
269 | | - Py_ssize_t need = size + sizeof(Py_ssize_t); |
270 | | - if (_check_size((BufferObject *)data, need) == 2) |
271 | | - return 2; |
272 | 284 |
|
273 | | - char *buf = ((BufferObject *)data)->buf; |
| 285 | + Py_ssize_t need; |
| 286 | + char *buf; |
274 | 287 | // Write string length. |
275 | | - *(Py_ssize_t *)(buf + ((BufferObject *)data)->pos) = size; |
276 | | - ((BufferObject *)data)->pos += sizeof(Py_ssize_t); |
| 288 | + if (size <= MAX_SHORT_LEN) { |
| 289 | + // Common case: short string (len <= 127) store as single byte. |
| 290 | + need = size + 1; |
| 291 | + if (_check_size((BufferObject *)data, need) == 2) |
| 292 | + return 2; |
| 293 | + buf = ((BufferObject *)data)->buf; |
| 294 | + *(uint8_t *)(buf + ((BufferObject *)data)->pos) = (uint8_t)size << 1; |
| 295 | + ((BufferObject *)data)->pos += 1; |
| 296 | + } else { |
| 297 | + need = size + sizeof(Py_ssize_t) + 1; |
| 298 | + if (_check_size((BufferObject *)data, need) == 2) |
| 299 | + return 2; |
| 300 | + buf = ((BufferObject *)data)->buf; |
| 301 | + *(uint8_t *)(buf + ((BufferObject *)data)->pos) = LONG_STR_TAG; |
| 302 | + ((BufferObject *)data)->pos += 1; |
| 303 | + *(Py_ssize_t *)(buf + ((BufferObject *)data)->pos) = size; |
| 304 | + ((BufferObject *)data)->pos += sizeof(Py_ssize_t); |
| 305 | + } |
277 | 306 | // Write string content. |
278 | 307 | memcpy(buf + ((BufferObject *)data)->pos, chunk, size); |
279 | 308 | ((BufferObject *)data)->pos += size; |
|
0 commit comments