@@ -2295,6 +2295,260 @@ PySys_GetOptionalAttr(PyObject *name, PyObject **value)
22952295#endif // PY_VERSION_HEX < 0x030F00A1
22962296
22972297
2298+ #if PY_VERSION_HEX < 0x030F00A1
2299+ typedef struct PyBytesWriter {
2300+ char small_buffer[256 ];
2301+ PyObject *obj;
2302+ Py_ssize_t size;
2303+ } PyBytesWriter;
2304+
2305+ static inline Py_ssize_t
2306+ _PyBytesWriter_GetAllocated (PyBytesWriter *writer)
2307+ {
2308+ if (writer->obj == NULL ) {
2309+ return sizeof (writer->small_buffer );
2310+ }
2311+ else {
2312+ return PyBytes_GET_SIZE (writer->obj );
2313+ }
2314+ }
2315+
2316+
2317+ static inline int
2318+ _PyBytesWriter_Resize_impl (PyBytesWriter *writer, Py_ssize_t size,
2319+ int resize)
2320+ {
2321+ int overallocate = resize;
2322+ assert (size >= 0 );
2323+
2324+ if (size <= _PyBytesWriter_GetAllocated (writer)) {
2325+ return 0 ;
2326+ }
2327+
2328+ if (overallocate) {
2329+ #ifdef MS_WINDOWS
2330+ /* On Windows, overallocate by 50% is the best factor */
2331+ if (size <= (PY_SSIZE_T_MAX - size / 2 )) {
2332+ size += size / 2 ;
2333+ }
2334+ #else
2335+ /* On Linux, overallocate by 25% is the best factor */
2336+ if (size <= (PY_SSIZE_T_MAX - size / 4 )) {
2337+ size += size / 4 ;
2338+ }
2339+ #endif
2340+ }
2341+
2342+ if (writer->obj != NULL ) {
2343+ if (_PyBytes_Resize (&writer->obj , size)) {
2344+ return -1 ;
2345+ }
2346+ assert (writer->obj != NULL );
2347+ }
2348+ else {
2349+ writer->obj = PyBytes_FromStringAndSize (NULL , size);
2350+ if (writer->obj == NULL ) {
2351+ return -1 ;
2352+ }
2353+
2354+ if (resize) {
2355+ assert ((size_t )size > sizeof (writer->small_buffer ));
2356+ memcpy (PyBytes_AS_STRING (writer->obj ),
2357+ writer->small_buffer ,
2358+ sizeof (writer->small_buffer ));
2359+ }
2360+ }
2361+ return 0 ;
2362+ }
2363+
2364+ static inline void *
2365+ PyBytesWriter_GetData (PyBytesWriter *writer)
2366+ {
2367+ if (writer->obj == NULL ) {
2368+ return writer->small_buffer ;
2369+ }
2370+ else {
2371+ return PyBytes_AS_STRING (writer->obj );
2372+ }
2373+ }
2374+
2375+ static inline Py_ssize_t
2376+ PyBytesWriter_GetSize (PyBytesWriter *writer)
2377+ {
2378+ return writer->size ;
2379+ }
2380+
2381+ static inline void
2382+ PyBytesWriter_Discard (PyBytesWriter *writer)
2383+ {
2384+ if (writer == NULL ) {
2385+ return ;
2386+ }
2387+
2388+ Py_XDECREF (writer->obj );
2389+ PyMem_Free (writer);
2390+ }
2391+
2392+ static inline PyBytesWriter*
2393+ PyBytesWriter_Create (Py_ssize_t size)
2394+ {
2395+ if (size < 0 ) {
2396+ PyErr_SetString (PyExc_ValueError, " size must be >= 0" );
2397+ return NULL ;
2398+ }
2399+
2400+ PyBytesWriter *writer = (PyBytesWriter*)PyMem_Malloc (sizeof (PyBytesWriter));
2401+ if (writer == NULL ) {
2402+ PyErr_NoMemory ();
2403+ return NULL ;
2404+ }
2405+
2406+ writer->obj = NULL ;
2407+ writer->size = 0 ;
2408+
2409+ if (size >= 1 ) {
2410+ if (_PyBytesWriter_Resize_impl (writer, size, 0 ) < 0 ) {
2411+ PyBytesWriter_Discard (writer);
2412+ return NULL ;
2413+ }
2414+ writer->size = size;
2415+ }
2416+ return writer;
2417+ }
2418+
2419+ static inline PyObject*
2420+ PyBytesWriter_FinishWithSize (PyBytesWriter *writer, Py_ssize_t size)
2421+ {
2422+ PyObject *result;
2423+ if (size == 0 ) {
2424+ result = PyBytes_FromStringAndSize (" " , 0 );
2425+ }
2426+ else if (writer->obj != NULL ) {
2427+ if (size != PyBytes_GET_SIZE (writer->obj )) {
2428+ if (_PyBytes_Resize (&writer->obj , size)) {
2429+ goto error;
2430+ }
2431+ }
2432+ result = writer->obj ;
2433+ writer->obj = NULL ;
2434+ }
2435+ else {
2436+ result = PyBytes_FromStringAndSize (writer->small_buffer , size);
2437+ }
2438+ PyBytesWriter_Discard (writer);
2439+ return result;
2440+
2441+ error:
2442+ PyBytesWriter_Discard (writer);
2443+ return NULL ;
2444+ }
2445+
2446+ static inline PyObject*
2447+ PyBytesWriter_Finish (PyBytesWriter *writer)
2448+ {
2449+ return PyBytesWriter_FinishWithSize (writer, writer->size );
2450+ }
2451+
2452+ static inline PyObject*
2453+ PyBytesWriter_FinishWithPointer (PyBytesWriter *writer, void *buf)
2454+ {
2455+ Py_ssize_t size = (char *)buf - (char *)PyBytesWriter_GetData (writer);
2456+ if (size < 0 || size > _PyBytesWriter_GetAllocated (writer)) {
2457+ PyBytesWriter_Discard (writer);
2458+ PyErr_SetString (PyExc_ValueError, " invalid end pointer" );
2459+ return NULL ;
2460+ }
2461+
2462+ return PyBytesWriter_FinishWithSize (writer, size);
2463+ }
2464+
2465+ static inline int
2466+ PyBytesWriter_Resize (PyBytesWriter *writer, Py_ssize_t size)
2467+ {
2468+ if (size < 0 ) {
2469+ PyErr_SetString (PyExc_ValueError, " size must be >= 0" );
2470+ return -1 ;
2471+ }
2472+ if (_PyBytesWriter_Resize_impl (writer, size, 1 ) < 0 ) {
2473+ return -1 ;
2474+ }
2475+ writer->size = size;
2476+ return 0 ;
2477+ }
2478+
2479+ static inline int
2480+ PyBytesWriter_Grow (PyBytesWriter *writer, Py_ssize_t size)
2481+ {
2482+ if (size < 0 && writer->size + size < 0 ) {
2483+ PyErr_SetString (PyExc_ValueError, " invalid size" );
2484+ return -1 ;
2485+ }
2486+ if (size > PY_SSIZE_T_MAX - writer->size ) {
2487+ PyErr_NoMemory ();
2488+ return -1 ;
2489+ }
2490+ size = writer->size + size;
2491+
2492+ if (_PyBytesWriter_Resize_impl (writer, size, 1 ) < 0 ) {
2493+ return -1 ;
2494+ }
2495+ writer->size = size;
2496+ return 0 ;
2497+ }
2498+
2499+ static inline void *
2500+ PyBytesWriter_GrowAndUpdatePointer (PyBytesWriter *writer,
2501+ Py_ssize_t size, void *buf)
2502+ {
2503+ Py_ssize_t pos = (char *)buf - (char *)PyBytesWriter_GetData (writer);
2504+ if (PyBytesWriter_Grow (writer, size) < 0 ) {
2505+ return NULL ;
2506+ }
2507+ return (char *)PyBytesWriter_GetData (writer) + pos;
2508+ }
2509+
2510+ static inline int
2511+ PyBytesWriter_WriteBytes (PyBytesWriter *writer,
2512+ const void *bytes, Py_ssize_t size)
2513+ {
2514+ if (size < 0 ) {
2515+ size_t len = strlen ((const char *)bytes);
2516+ if (len > (size_t )PY_SSIZE_T_MAX) {
2517+ PyErr_NoMemory ();
2518+ return -1 ;
2519+ }
2520+ size = (Py_ssize_t)len;
2521+ }
2522+
2523+ Py_ssize_t pos = writer->size ;
2524+ if (PyBytesWriter_Grow (writer, size) < 0 ) {
2525+ return -1 ;
2526+ }
2527+ char *buf = (char *)PyBytesWriter_GetData (writer);
2528+ memcpy (buf + pos, bytes, (size_t )size);
2529+ return 0 ;
2530+ }
2531+
2532+ static inline int
2533+ PyBytesWriter_Format (PyBytesWriter *writer, const char *format, ...)
2534+ {
2535+ va_list vargs;
2536+ va_start (vargs, format);
2537+ PyObject *str = PyBytes_FromFormatV (format, vargs);
2538+ va_end (vargs);
2539+
2540+ if (str == NULL ) {
2541+ return -1 ;
2542+ }
2543+ int res = PyBytesWriter_WriteBytes (writer,
2544+ PyBytes_AS_STRING (str),
2545+ PyBytes_GET_SIZE (str));
2546+ Py_DECREF (str);
2547+ return res;
2548+ }
2549+ #endif // PY_VERSION_HEX < 0x030F00A1
2550+
2551+
22982552#ifdef __cplusplus
22992553}
23002554#endif
0 commit comments