Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fdf95dd

Browse files
committed
Checkin of Jack's buffer mods.
Not really checked, but didn't fail any tests either...
1 parent 8290e07 commit fdf95dd

5 files changed

Lines changed: 232 additions & 27 deletions

File tree

Include/object.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ typedef PyObject *(*intintargfunc) Py_PROTO((PyObject *, int, int));
146146
typedef int(*intobjargproc) Py_PROTO((PyObject *, int, PyObject *));
147147
typedef int(*intintobjargproc) Py_PROTO((PyObject *, int, int, PyObject *));
148148
typedef int(*objobjargproc) Py_PROTO((PyObject *, PyObject *, PyObject *));
149+
typedef int (*getreadbufferproc) Py_PROTO((PyObject *, int, void **));
150+
typedef int (*getwritebufferproc) Py_PROTO((PyObject *, int, void **));
151+
typedef int (*getsegcountproc) Py_PROTO((PyObject *, int *));
149152

150153
typedef struct {
151154
binaryfunc nb_add;
@@ -189,6 +192,13 @@ typedef struct {
189192
objobjargproc mp_ass_subscript;
190193
} PyMappingMethods;
191194

195+
typedef struct {
196+
getreadbufferproc bf_getreadbuffer;
197+
getwritebufferproc bf_getwritebuffer;
198+
getsegcountproc bf_getsegcount;
199+
} PyBufferProcs;
200+
201+
192202
typedef void (*destructor) Py_PROTO((PyObject *));
193203
typedef int (*printfunc) Py_PROTO((PyObject *, FILE *, int));
194204
typedef PyObject *(*getattrfunc) Py_PROTO((PyObject *, char *));
@@ -227,8 +237,10 @@ typedef struct _typeobject {
227237
getattrofunc tp_getattro;
228238
setattrofunc tp_setattro;
229239

240+
/* Functions to access object as input/output buffer */
241+
PyBufferProcs *tp_as_buffer;
242+
230243
/* Space for future expansion */
231-
long tp_xxx3;
232244
long tp_xxx4;
233245

234246
char *tp_doc; /* Documentation string */

Modules/arraymodule.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,44 @@ array_repr(a)
11691169
return s;
11701170
}
11711171

1172+
static int
1173+
array_buffer_getreadbuf(self, index, ptr)
1174+
arrayobject *self;
1175+
int index;
1176+
const void **ptr;
1177+
{
1178+
if ( index != 0 ) {
1179+
PyErr_SetString(PyExc_SystemError, "Accessing non-existent array segment");
1180+
return -1;
1181+
}
1182+
*ptr = (void *)self->ob_item;
1183+
return self->ob_size*self->ob_descr->itemsize;
1184+
}
1185+
1186+
static int
1187+
array_buffer_getwritebuf(self, index, ptr)
1188+
arrayobject *self;
1189+
int index;
1190+
const void **ptr;
1191+
{
1192+
if ( index != 0 ) {
1193+
PyErr_SetString(PyExc_SystemError, "Accessing non-existent array segment");
1194+
return -1;
1195+
}
1196+
*ptr = (void *)self->ob_item;
1197+
return self->ob_size*self->ob_descr->itemsize;
1198+
}
1199+
1200+
static int
1201+
array_buffer_getsegcount(self, lenp)
1202+
arrayobject *self;
1203+
int *lenp;
1204+
{
1205+
if ( lenp )
1206+
*lenp = self->ob_size*self->ob_descr->itemsize;
1207+
return 1;
1208+
}
1209+
11721210
static PySequenceMethods array_as_sequence = {
11731211
(inquiry)array_length, /*sq_length*/
11741212
(binaryfunc)array_concat, /*sq_concat*/
@@ -1179,6 +1217,13 @@ static PySequenceMethods array_as_sequence = {
11791217
(intintobjargproc)array_ass_slice, /*sq_ass_slice*/
11801218
};
11811219

1220+
static PyBufferProcs array_as_buffer = {
1221+
(getreadbufferproc)array_buffer_getreadbuf,
1222+
(getwritebufferproc)array_buffer_getwritebuf,
1223+
(getsegcountproc)array_buffer_getsegcount,
1224+
};
1225+
1226+
11821227
statichere PyTypeObject Arraytype = {
11831228
PyObject_HEAD_INIT(&PyType_Type)
11841229
0,
@@ -1194,6 +1239,14 @@ statichere PyTypeObject Arraytype = {
11941239
0, /*tp_as_number*/
11951240
&array_as_sequence, /*tp_as_sequence*/
11961241
0, /*tp_as_mapping*/
1242+
0, /*tp_hash*/
1243+
0, /*tp_call*/
1244+
0, /*tp_str*/
1245+
0, /*tp_getattro*/
1246+
0, /*tp_setattro*/
1247+
&array_as_buffer, /*tp_as_buffer*/
1248+
0, /*tp_xxx4*/
1249+
0, /*tp_doc*/
11971250
};
11981251

11991252

Objects/fileobject.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,41 @@ file_read(f, args)
419419
return v;
420420
}
421421

422+
static PyObject *
423+
file_readinto(f, args)
424+
PyFileObject *f;
425+
PyObject *args;
426+
{
427+
char *ptr;
428+
int ntodo, ndone, nnow;
429+
430+
if (f->f_fp == NULL)
431+
return err_closed();
432+
if (!PyArg_Parse(args, "w#", &ptr, &ntodo))
433+
return NULL;
434+
ndone = 0;
435+
/*
436+
** XXXX Is this correct? Other threads may see partially-completed
437+
** reads if they look at the object we're reading into...
438+
*/
439+
Py_BEGIN_ALLOW_THREADS
440+
while(ntodo > 0) {
441+
nnow = fread(ptr+ndone, 1, ntodo, f->f_fp);
442+
if (nnow < 0 ) {
443+
PyErr_SetFromErrno(PyExc_IOError);
444+
clearerr(f->f_fp);
445+
return NULL;
446+
}
447+
if (nnow == 0)
448+
break;
449+
ndone += nnow;
450+
ntodo -= nnow;
451+
}
452+
Py_END_ALLOW_THREADS
453+
return PyInt_FromLong(ndone);
454+
}
455+
456+
422457
/* Internal routine to get a line.
423458
Size argument interpretation:
424459
> 0: max length;
@@ -688,6 +723,7 @@ static PyMethodDef file_methods[] = {
688723
{"tell", (PyCFunction)file_tell, 0},
689724
{"write", (PyCFunction)file_write, 0},
690725
{"writelines", (PyCFunction)file_writelines, 0},
726+
{"readinto", (PyCFunction)file_readinto, 0},
691727
{NULL, NULL} /* sentinel */
692728
};
693729

Objects/stringobject.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,40 @@ string_hash(a)
456456
return x;
457457
}
458458

459+
static int
460+
string_buffer_getreadbuf(self, index, ptr)
461+
PyStringObject *self;
462+
int index;
463+
const void **ptr;
464+
{
465+
if ( index != 0 ) {
466+
PyErr_SetString(PyExc_SystemError, "Accessing non-existent string segment");
467+
return -1;
468+
}
469+
*ptr = (void *)self->ob_sval;
470+
return self->ob_size;
471+
}
472+
473+
static int
474+
string_buffer_getwritebuf(self, index, ptr)
475+
PyStringObject *self;
476+
int index;
477+
const void **ptr;
478+
{
479+
PyErr_SetString(PyExc_TypeError, "Cannot use string as modifyable buffer");
480+
return -1;
481+
}
482+
483+
static int
484+
string_buffer_getsegcount(self, lenp)
485+
PyStringObject *self;
486+
int *lenp;
487+
{
488+
if ( lenp )
489+
*lenp = self->ob_size;
490+
return 1;
491+
}
492+
459493
static PySequenceMethods string_as_sequence = {
460494
(inquiry)string_length, /*sq_length*/
461495
(binaryfunc)string_concat, /*sq_concat*/
@@ -466,6 +500,12 @@ static PySequenceMethods string_as_sequence = {
466500
0, /*sq_ass_slice*/
467501
};
468502

503+
static PyBufferProcs string_as_buffer = {
504+
(getreadbufferproc)string_buffer_getreadbuf,
505+
(getwritebufferproc)string_buffer_getwritebuf,
506+
(getsegcountproc)string_buffer_getsegcount,
507+
};
508+
469509
PyTypeObject PyString_Type = {
470510
PyObject_HEAD_INIT(&PyType_Type)
471511
0,
@@ -486,7 +526,7 @@ PyTypeObject PyString_Type = {
486526
0, /*tp_str*/
487527
0, /*tp_getattro*/
488528
0, /*tp_setattro*/
489-
0, /*tp_xxx3*/
529+
&string_as_buffer, /*tp_as_buffer*/
490530
0, /*tp_xxx4*/
491531
0, /*tp_doc*/
492532
};

Python/getargs.c

Lines changed: 89 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -539,41 +539,81 @@ convertsimple1(arg, p_format, p_va)
539539

540540
case 's': /* string */
541541
{
542-
char **p = va_arg(*p_va, char **);
543-
if (PyString_Check(arg))
544-
*p = PyString_AsString(arg);
545-
else
546-
return "string";
547-
if (*format == '#') {
542+
if (*format == '#') { /* any buffer-like object */
543+
void **p = (void **)va_arg(*p_va, char **);
544+
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
548545
int *q = va_arg(*p_va, int *);
549-
*q = PyString_Size(arg);
546+
int count;
547+
548+
if ( pb == NULL ||
549+
pb->bf_getreadbuffer == NULL ||
550+
pb->bf_getsegcount == NULL )
551+
return "read-only buffer";
552+
if ( (*pb->bf_getsegcount)(arg, NULL) != 1 )
553+
return "single-segment read-only buffer";
554+
if ( (count =
555+
(*pb->bf_getreadbuffer)(arg, 0, p)) < 0 )
556+
return "(unspecified)";
557+
*q = count;
550558
format++;
559+
} else {
560+
char **p = va_arg(*p_va, char **);
561+
562+
if (PyString_Check(arg))
563+
*p = PyString_AsString(arg);
564+
else
565+
return "string";
566+
if ((int)strlen(*p) != PyString_Size(arg))
567+
return "string without null bytes";
551568
}
552-
else if ((int)strlen(*p) != PyString_Size(arg))
553-
return "string without null bytes";
554569
break;
555570
}
556-
571+
557572
case 'z': /* string, may be NULL (None) */
558573
{
559-
char **p = va_arg(*p_va, char **);
560-
if (arg == Py_None)
561-
*p = 0;
562-
else if (PyString_Check(arg))
563-
*p = PyString_AsString(arg);
564-
else
565-
return "None or string";
566-
if (*format == '#') {
574+
if (*format == '#') { /* any buffer-like object */
575+
void **p = (void **)va_arg(*p_va, char **);
576+
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
567577
int *q = va_arg(*p_va, int *);
568-
if (arg == Py_None)
569-
*q = 0;
570-
else
571-
*q = PyString_Size(arg);
578+
int count;
579+
580+
if (arg == Py_None) {
581+
*p = 0;
582+
*q = 0;
583+
} else {
584+
if ( pb == NULL ||
585+
pb->bf_getreadbuffer == NULL ||
586+
pb->bf_getsegcount == NULL )
587+
return "read-only buffer";
588+
if ( (*pb->bf_getsegcount)(arg, NULL) != 1 )
589+
return "single-segment read-only buffer";
590+
if ( (count = (*pb->bf_getreadbuffer)
591+
(arg, 0, p)) < 0 )
592+
return "(unspecified)";
593+
*q = count;
594+
}
572595
format++;
596+
} else {
597+
char **p = va_arg(*p_va, char **);
598+
599+
if (arg == Py_None)
600+
*p = 0;
601+
else if (PyString_Check(arg))
602+
*p = PyString_AsString(arg);
603+
else
604+
return "None or string";
605+
if (*format == '#') {
606+
int *q = va_arg(*p_va, int *);
607+
if (arg == Py_None)
608+
*q = 0;
609+
else
610+
*q = PyString_Size(arg);
611+
format++;
612+
}
613+
else if (*p != NULL &&
614+
(int)strlen(*p) != PyString_Size(arg))
615+
return "None or string without null bytes";
573616
}
574-
else if (*p != NULL &&
575-
(int)strlen(*p) != PyString_Size(arg))
576-
return "None or string without null bytes";
577617
break;
578618
}
579619

@@ -624,6 +664,30 @@ convertsimple1(arg, p_format, p_va)
624664
}
625665
break;
626666
}
667+
668+
669+
case 'w': /* memory buffer, read-write access */
670+
{
671+
void **p = va_arg(*p_va, void **);
672+
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
673+
int count;
674+
675+
if ( pb == NULL || pb->bf_getwritebuffer == NULL ||
676+
pb->bf_getsegcount == NULL )
677+
return "read-write buffer";
678+
if ( (*pb->bf_getsegcount)(arg, NULL) != 1 )
679+
return "single-segment read-write buffer";
680+
if ( (count = pb->bf_getwritebuffer(arg, 0, p)) < 0 )
681+
return "(unspecified)";
682+
if (*format == '#') {
683+
int *q = va_arg(*p_va, int *);
684+
685+
*q = count;
686+
format++;
687+
}
688+
break;
689+
}
690+
627691

628692
default:
629693
return "impossible<bad format char>";

0 commit comments

Comments
 (0)