mirror of
https://github.com/python/cpython.git
synced 2025-11-10 02:21:40 +00:00
338 lines
7.6 KiB
C
338 lines
7.6 KiB
C
// Use pycore_bytes.h
|
|
#define PYTESTCAPI_NEED_INTERNAL_API
|
|
|
|
#include "parts.h"
|
|
#include "util.h"
|
|
|
|
#include "pycore_bytesobject.h" // _PyBytesWriter_CreateByteArray()
|
|
|
|
|
|
/* Test _PyBytes_Resize() */
|
|
static PyObject *
|
|
bytes_resize(PyObject *Py_UNUSED(module), PyObject *args)
|
|
{
|
|
PyObject *obj;
|
|
Py_ssize_t newsize;
|
|
int new;
|
|
|
|
if (!PyArg_ParseTuple(args, "Onp", &obj, &newsize, &new))
|
|
return NULL;
|
|
|
|
NULLABLE(obj);
|
|
if (new) {
|
|
assert(obj != NULL);
|
|
assert(PyBytes_CheckExact(obj));
|
|
PyObject *newobj = PyBytes_FromStringAndSize(NULL, PyBytes_Size(obj));
|
|
if (newobj == NULL) {
|
|
return NULL;
|
|
}
|
|
memcpy(PyBytes_AsString(newobj), PyBytes_AsString(obj), PyBytes_Size(obj));
|
|
obj = newobj;
|
|
}
|
|
else {
|
|
Py_XINCREF(obj);
|
|
}
|
|
if (_PyBytes_Resize(&obj, newsize) < 0) {
|
|
assert(obj == NULL);
|
|
}
|
|
else {
|
|
assert(obj != NULL);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
|
|
/* Test PyBytes_Join() */
|
|
static PyObject *
|
|
bytes_join(PyObject *Py_UNUSED(module), PyObject *args)
|
|
{
|
|
PyObject *sep, *iterable;
|
|
if (!PyArg_ParseTuple(args, "OO", &sep, &iterable)) {
|
|
return NULL;
|
|
}
|
|
NULLABLE(sep);
|
|
NULLABLE(iterable);
|
|
return PyBytes_Join(sep, iterable);
|
|
}
|
|
|
|
|
|
// --- PyBytesWriter type ---------------------------------------------------
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
PyBytesWriter *writer;
|
|
} WriterObject;
|
|
|
|
|
|
static PyObject *
|
|
writer_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
|
{
|
|
WriterObject *self = (WriterObject *)type->tp_alloc(type, 0);
|
|
if (!self) {
|
|
return NULL;
|
|
}
|
|
self->writer = NULL;
|
|
return (PyObject*)self;
|
|
}
|
|
|
|
|
|
static int
|
|
writer_init(PyObject *self_raw, PyObject *args, PyObject *kwargs)
|
|
{
|
|
WriterObject *self = (WriterObject *)self_raw;
|
|
if (self->writer) {
|
|
PyBytesWriter_Discard(self->writer);
|
|
}
|
|
|
|
if (kwargs && PyDict_GET_SIZE(kwargs)) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"PyBytesWriter() takes exactly no keyword arguments");
|
|
return -1;
|
|
}
|
|
|
|
Py_ssize_t alloc;
|
|
char *str;
|
|
Py_ssize_t str_size;
|
|
int use_bytearray;
|
|
if (!PyArg_ParseTuple(args, "ny#i",
|
|
&alloc, &str, &str_size, &use_bytearray)) {
|
|
return -1;
|
|
}
|
|
|
|
if (use_bytearray) {
|
|
self->writer = _PyBytesWriter_CreateByteArray(alloc);
|
|
}
|
|
else {
|
|
self->writer = PyBytesWriter_Create(alloc);
|
|
}
|
|
if (self->writer == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (str_size) {
|
|
char *buf = PyBytesWriter_GetData(self->writer);
|
|
memcpy(buf, str, str_size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
writer_dealloc(PyObject *self_raw)
|
|
{
|
|
WriterObject *self = (WriterObject *)self_raw;
|
|
PyTypeObject *tp = Py_TYPE(self);
|
|
if (self->writer) {
|
|
PyBytesWriter_Discard(self->writer);
|
|
}
|
|
tp->tp_free(self);
|
|
Py_DECREF(tp);
|
|
}
|
|
|
|
|
|
static inline int
|
|
writer_check(WriterObject *self)
|
|
{
|
|
if (self->writer == NULL) {
|
|
PyErr_SetString(PyExc_ValueError, "operation on finished writer");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static PyObject*
|
|
writer_write_bytes(PyObject *self_raw, PyObject *args)
|
|
{
|
|
WriterObject *self = (WriterObject *)self_raw;
|
|
if (writer_check(self) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
char *bytes;
|
|
Py_ssize_t size;
|
|
if (!PyArg_ParseTuple(args, "yn", &bytes, &size)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (PyBytesWriter_WriteBytes(self->writer, bytes, size) < 0) {
|
|
return NULL;
|
|
}
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
static PyObject*
|
|
writer_resize(PyObject *self_raw, PyObject *args)
|
|
{
|
|
WriterObject *self = (WriterObject *)self_raw;
|
|
if (writer_check(self) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
Py_ssize_t size;
|
|
char *str;
|
|
Py_ssize_t str_size;
|
|
if (!PyArg_ParseTuple(args,
|
|
"ny#",
|
|
&size, &str, &str_size)) {
|
|
return NULL;
|
|
}
|
|
assert(size >= str_size);
|
|
|
|
Py_ssize_t pos = PyBytesWriter_GetSize(self->writer);
|
|
if (PyBytesWriter_Resize(self->writer, size) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
char *buf = PyBytesWriter_GetData(self->writer);
|
|
memcpy(buf + pos, str, str_size);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
|
|
static PyObject*
|
|
writer_get_size(PyObject *self_raw, PyObject *Py_UNUSED(args))
|
|
{
|
|
WriterObject *self = (WriterObject *)self_raw;
|
|
if (writer_check(self) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
Py_ssize_t alloc = PyBytesWriter_GetSize(self->writer);
|
|
return PyLong_FromSsize_t(alloc);
|
|
}
|
|
|
|
|
|
static PyObject*
|
|
writer_finish(PyObject *self_raw, PyObject *Py_UNUSED(args))
|
|
{
|
|
WriterObject *self = (WriterObject *)self_raw;
|
|
if (writer_check(self) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
PyObject *str = PyBytesWriter_Finish(self->writer);
|
|
self->writer = NULL;
|
|
return str;
|
|
}
|
|
|
|
|
|
static PyObject*
|
|
writer_finish_with_size(PyObject *self_raw, PyObject *args)
|
|
{
|
|
WriterObject *self = (WriterObject *)self_raw;
|
|
if (writer_check(self) < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
Py_ssize_t size;
|
|
if (!PyArg_ParseTuple(args, "n", &size)) {
|
|
return NULL;
|
|
}
|
|
|
|
PyObject *str = PyBytesWriter_FinishWithSize(self->writer, size);
|
|
self->writer = NULL;
|
|
return str;
|
|
}
|
|
|
|
|
|
static PyMethodDef writer_methods[] = {
|
|
{"write_bytes", _PyCFunction_CAST(writer_write_bytes), METH_VARARGS},
|
|
{"resize", _PyCFunction_CAST(writer_resize), METH_VARARGS},
|
|
{"get_size", _PyCFunction_CAST(writer_get_size), METH_NOARGS},
|
|
{"finish", _PyCFunction_CAST(writer_finish), METH_NOARGS},
|
|
{"finish_with_size", _PyCFunction_CAST(writer_finish_with_size), METH_VARARGS},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static PyType_Slot Writer_Type_slots[] = {
|
|
{Py_tp_new, writer_new},
|
|
{Py_tp_init, writer_init},
|
|
{Py_tp_dealloc, writer_dealloc},
|
|
{Py_tp_methods, writer_methods},
|
|
{0, 0}, /* sentinel */
|
|
};
|
|
|
|
static PyType_Spec Writer_spec = {
|
|
.name = "_testcapi.PyBytesWriter",
|
|
.basicsize = sizeof(WriterObject),
|
|
.flags = Py_TPFLAGS_DEFAULT,
|
|
.slots = Writer_Type_slots,
|
|
};
|
|
|
|
|
|
static PyObject *
|
|
byteswriter_abc(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
|
{
|
|
PyBytesWriter *writer = PyBytesWriter_Create(3);
|
|
if (writer == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
char *str = PyBytesWriter_GetData(writer);
|
|
memcpy(str, "abc", 3);
|
|
|
|
return PyBytesWriter_Finish(writer);
|
|
}
|
|
|
|
|
|
static PyObject *
|
|
byteswriter_resize(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
|
|
{
|
|
// Allocate 10 bytes
|
|
PyBytesWriter *writer = PyBytesWriter_Create(10);
|
|
if (writer == NULL) {
|
|
return NULL;
|
|
}
|
|
char *buf = PyBytesWriter_GetData(writer);
|
|
|
|
// Write some bytes
|
|
memcpy(buf, "Hello ", strlen("Hello "));
|
|
buf += strlen("Hello ");
|
|
|
|
// Allocate 10 more bytes
|
|
buf = PyBytesWriter_GrowAndUpdatePointer(writer, 10, buf);
|
|
if (buf == NULL) {
|
|
PyBytesWriter_Discard(writer);
|
|
return NULL;
|
|
}
|
|
|
|
// Write more bytes
|
|
memcpy(buf, "World", strlen("World"));
|
|
buf += strlen("World");
|
|
|
|
// Truncate to the exact size and create a bytes object
|
|
return PyBytesWriter_FinishWithPointer(writer, buf);
|
|
}
|
|
|
|
|
|
static PyMethodDef test_methods[] = {
|
|
{"bytes_resize", bytes_resize, METH_VARARGS},
|
|
{"bytes_join", bytes_join, METH_VARARGS},
|
|
{"byteswriter_abc", byteswriter_abc, METH_NOARGS},
|
|
{"byteswriter_resize", byteswriter_resize, METH_NOARGS},
|
|
{NULL},
|
|
};
|
|
|
|
int
|
|
_PyTestCapi_Init_Bytes(PyObject *m)
|
|
{
|
|
if (PyModule_AddFunctions(m, test_methods) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
PyTypeObject *writer_type = (PyTypeObject *)PyType_FromSpec(&Writer_spec);
|
|
if (writer_type == NULL) {
|
|
return -1;
|
|
}
|
|
if (PyModule_AddType(m, writer_type) < 0) {
|
|
Py_DECREF(writer_type);
|
|
return -1;
|
|
}
|
|
Py_DECREF(writer_type);
|
|
|
|
return 0;
|
|
}
|