Index: Modules/cPickle.c =================================================================== --- Modules/cPickle.c (revision 71100) +++ Modules/cPickle.c (working copy) @@ -332,8 +332,6 @@ typedef struct Picklerobject { PyObject_HEAD - FILE *fp; - PyObject *write; PyObject *file; PyObject *memo; PyObject *arg; @@ -346,10 +344,14 @@ /* bool, true if proto > 0 */ int bin; + /* Write into a local buffer before flushing out to file. output_len + tracks the current size; when output_len >= max_output_len, we + realloc. */ + Py_ssize_t max_output_len; + Py_ssize_t output_len; + char *output_buffer; + int fast; /* Fast mode doesn't save in memo, don't use if circ ref */ - int (*write_func)(struct Picklerobject *, const char *, Py_ssize_t); - char *write_buf; - int buf_size; PyObject *dispatch_table; int fast_container; /* count nested container dumps */ PyObject *fast_memo; @@ -425,106 +427,46 @@ } static int -write_file(Picklerobject *self, const char *s, Py_ssize_t n) +_Pickler_Write(Picklerobject *self, const char *s, Py_ssize_t n) { - size_t nbyteswritten; + Py_ssize_t i; - if (s == NULL) { - return 0; + if (self->output_len + n > self->max_output_len) { + self->max_output_len = (self->output_len + n) * 2; + self->output_buffer = realloc(self->output_buffer, + self->max_output_len); } - - if (n > INT_MAX) { - /* String too large */ - return -1; + for (i = 0; i < n; i++) { + self->output_buffer[self->output_len + i] = s[i]; } - - PyFile_IncUseCount((PyFileObject *)self->file); - Py_BEGIN_ALLOW_THREADS - nbyteswritten = fwrite(s, sizeof(char), n, self->fp); - Py_END_ALLOW_THREADS - PyFile_DecUseCount((PyFileObject *)self->file); - if (nbyteswritten != (size_t)n) { - PyErr_SetFromErrno(PyExc_IOError); - return -1; - } - - return (int)n; + self->output_len += n; + return n; } -static int -write_cStringIO(Picklerobject *self, const char *s, Py_ssize_t n) +static PyObject * +_Pickler_GetString(Picklerobject *self) { - if (s == NULL) { - return 0; - } - - if (PycStringIO->cwrite((PyObject *)self->file, s, n) != n) { - return -1; - } - - return (int)n; + return PyString_FromStringAndSize(self->output_buffer, + self->output_len); } static int -write_none(Picklerobject *self, const char *s, Py_ssize_t n) +_Pickler_FlushToFile(Picklerobject *self) { - if (s == NULL) return 0; - if (n > INT_MAX) return -1; - return (int)n; -} + PyObject *output, *ret; -static int -write_other(Picklerobject *self, const char *s, Py_ssize_t _n) -{ - PyObject *py_str = 0, *junk = 0; - int n; + assert(self->file != NULL); - if (_n > INT_MAX) + output = _Pickler_GetString(self); + if (output == NULL) return -1; - n = (int)_n; - if (s == NULL) { - if (!( self->buf_size )) return 0; - py_str = PyString_FromStringAndSize(self->write_buf, - self->buf_size); - if (!py_str) - return -1; - } - else { - if (self->buf_size && (n + self->buf_size) > WRITE_BUF_SIZE) { - if (write_other(self, NULL, 0) < 0) - return -1; - } - if (n > WRITE_BUF_SIZE) { - if (!( py_str = - PyString_FromStringAndSize(s, n))) - return -1; - } - else { - memcpy(self->write_buf + self->buf_size, s, n); - self->buf_size += n; - return n; - } - } - - if (self->write) { - /* object with write method */ - ARG_TUP(self, py_str); - if (self->arg) { - junk = PyObject_Call(self->write, self->arg, NULL); - FREE_ARG_TUP(self); - } - if (junk) Py_DECREF(junk); - else return -1; - } - else - PDATA_PUSH(self->file, py_str, -1); - - self->buf_size = 0; - return n; + ret = PyObject_CallMethod(self->file, "write", "O", output); + Py_DECREF(output); + Py_XDECREF(ret); + return (ret == NULL) ? -1 : 0; } - static Py_ssize_t read_file(Unpicklerobject *self, char **s, Py_ssize_t n) { @@ -732,11 +674,6 @@ PyOS_snprintf(s + 1, sizeof(s) - 1, "%ld\n", c_value); len = strlen(s); } - else if (Pdata_Check(self->file)) { - if (write_other(self, NULL, 0) < 0) return -1; - PDATA_APPEND(self->file, mv, -1); - return 0; - } else { if (c_value < 256) { s[0] = BINGET; @@ -753,7 +690,7 @@ } } - if (self->write_func(self, s, len) < 0) + if (_Pickler_Write(self, s, len) < 0) return -1; return 0; @@ -815,12 +752,6 @@ PyOS_snprintf(c_str + 1, sizeof(c_str) - 1, "%d\n", p); len = strlen(c_str); } - else if (Pdata_Check(self->file)) { - if (write_other(self, NULL, 0) < 0) return -1; - PDATA_APPEND(self->file, memo_len, -1); - res=0; /* Job well done ;) */ - goto finally; - } else { if (p >= 256) { c_str[0] = LONG_BINPUT; @@ -837,7 +768,7 @@ } } - if (self->write_func(self, c_str, len) < 0) + if (_Pickler_Write(self, c_str, len) < 0) goto finally; res = 0; @@ -961,7 +892,7 @@ save_none(Picklerobject *self, PyObject *args) { static char none = NONE; - if (self->write_func(self, &none, 1) < 0) + if (_Pickler_Write(self, &none, 1) < 0) return -1; return 0; @@ -976,10 +907,10 @@ if (self->proto >= 2) { char opcode = l ? NEWTRUE : NEWFALSE; - if (self->write_func(self, &opcode, 1) < 0) + if (_Pickler_Write(self, &opcode, 1) < 0) return -1; } - else if (self->write_func(self, buf[l], len[l]) < 0) + else if (_Pickler_Write(self, buf[l], len[l]) < 0) return -1; return 0; } @@ -1002,7 +933,7 @@ */ c_str[0] = INT; PyOS_snprintf(c_str + 1, sizeof(c_str) - 1, "%ld\n", l); - if (self->write_func(self, c_str, strlen(c_str)) < 0) + if (_Pickler_Write(self, c_str, strlen(c_str)) < 0) return -1; } else { @@ -1027,7 +958,7 @@ len = 5; } - if (self->write_func(self, c_str, len) < 0) + if (_Pickler_Write(self, c_str, len) < 0) return -1; } @@ -1057,7 +988,7 @@ /* It's 0 -- an empty bytestring. */ c_str[0] = LONG1; c_str[1] = 0; - i = self->write_func(self, c_str, 2); + i = _Pickler_Write(self, c_str, 2); if (i < 0) goto finally; res = 0; goto finally; @@ -1114,9 +1045,9 @@ } size = 5; } - i = self->write_func(self, c_str, size); + i = _Pickler_Write(self, c_str, size); if (i < 0) goto finally; - i = self->write_func(self, (char *)pdata, (int)nbytes); + i = _Pickler_Write(self, (char *)pdata, (int)nbytes); if (i < 0) goto finally; res = 0; goto finally; @@ -1131,15 +1062,15 @@ if ((size = PyString_Size(repr)) < 0) goto finally; - if (self->write_func(self, &l, 1) < 0) + if (_Pickler_Write(self, &l, 1) < 0) goto finally; - if (self->write_func(self, - PyString_AS_STRING((PyStringObject *)repr), - size) < 0) + if (_Pickler_Write(self, + PyString_AS_STRING((PyStringObject *)repr), + size) < 0) goto finally; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto finally; res = 0; @@ -1160,7 +1091,7 @@ str[0] = BINFLOAT; if (_PyFloat_Pack8(x, (unsigned char *)&str[1], 0) < 0) return -1; - if (self->write_func(self, str, 9) < 0) + if (_Pickler_Write(self, str, 9) < 0) return -1; } else { @@ -1170,7 +1101,7 @@ /* Extend the formatted string with a newline character */ strcat(c_str, "\n"); - if (self->write_func(self, c_str, strlen(c_str)) < 0) + if (_Pickler_Write(self, c_str, strlen(c_str)) < 0) return -1; } @@ -1199,13 +1130,13 @@ goto err; repr_str = PyString_AS_STRING((PyStringObject *)repr); - if (self->write_func(self, &string, 1) < 0) + if (_Pickler_Write(self, &string, 1) < 0) goto err; - if (self->write_func(self, repr_str, len) < 0) + if (_Pickler_Write(self, repr_str, len) < 0) goto err; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto err; Py_XDECREF(repr); @@ -1231,20 +1162,14 @@ else return -1; /* string too large */ - if (self->write_func(self, c_str, len) < 0) + if (_Pickler_Write(self, c_str, len) < 0) return -1; - if (size > 128 && Pdata_Check(self->file)) { - if (write_other(self, NULL, 0) < 0) return -1; - PDATA_APPEND(self->file, args, -1); - } - else { - if (self->write_func(self, - PyString_AS_STRING( - (PyStringObject *)args), - size) < 0) - return -1; - } + if (_Pickler_Write(self, + PyString_AS_STRING( + (PyStringObject *)args), + size) < 0) + return -1; } if (doput) @@ -1370,13 +1295,13 @@ goto err; repr_str = PyString_AS_STRING((PyStringObject *)repr); - if (self->write_func(self, &string, 1) < 0) + if (_Pickler_Write(self, &string, 1) < 0) goto err; - if (self->write_func(self, repr_str, len) < 0) + if (_Pickler_Write(self, repr_str, len) < 0) goto err; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto err; Py_XDECREF(repr); @@ -1398,19 +1323,11 @@ c_str[i] = (int)(size >> ((i - 1) * 8)); len = 5; - if (self->write_func(self, c_str, len) < 0) + if (_Pickler_Write(self, c_str, len) < 0) goto err; - if (size > 128 && Pdata_Check(self->file)) { - if (write_other(self, NULL, 0) < 0) - goto err; - PDATA_APPEND(self->file, repr, -1); - } - else { - if (self->write_func(self, PyString_AS_STRING(repr), - size) < 0) - goto err; - } + if (_Pickler_Write(self, PyString_AS_STRING(repr), size) < 0) + goto err; Py_DECREF(repr); } @@ -1483,7 +1400,7 @@ c_str[1] = TUPLE; len = 2; } - if (self->write_func(self, c_str, len) >= 0) + if (_Pickler_Write(self, c_str, len) >= 0) res = 0; /* Don't memoize an empty tuple. */ goto finally; @@ -1507,7 +1424,7 @@ if (PyDict_GetItem(self->memo, py_tuple_id)) { /* pop the len elements */ for (i = 0; i < len; ++i) - if (self->write_func(self, &pop, 1) < 0) + if (_Pickler_Write(self, &pop, 1) < 0) goto finally; /* fetch from memo */ if (get(self, py_tuple_id) < 0) @@ -1516,7 +1433,7 @@ goto finally; } /* Not recursive. */ - if (self->write_func(self, len2opcode + len, 1) < 0) + if (_Pickler_Write(self, len2opcode + len, 1) < 0) goto finally; goto memoize; } @@ -1524,7 +1441,7 @@ /* proto < 2 and len > 0, or proto >= 2 and len > 3. * Generate MARK elt1 elt2 ... TUPLE */ - if (self->write_func(self, &MARKv, 1) < 0) + if (_Pickler_Write(self, &MARKv, 1) < 0) goto finally; if (store_tuple_elements(self, args, len) < 0) @@ -1533,7 +1450,7 @@ if (PyDict_GetItem(self->memo, py_tuple_id)) { /* pop the stack stuff we pushed */ if (self->bin) { - if (self->write_func(self, &pop_mark, 1) < 0) + if (_Pickler_Write(self, &pop_mark, 1) < 0) goto finally; } else { @@ -1541,7 +1458,7 @@ * the MARK too. */ for (i = 0; i <= len; i++) - if (self->write_func(self, &pop, 1) < 0) + if (_Pickler_Write(self, &pop, 1) < 0) goto finally; } /* fetch from memo */ @@ -1551,7 +1468,7 @@ } /* Not recursive. */ - if (self->write_func(self, &tuple, 1) < 0) + if (_Pickler_Write(self, &tuple, 1) < 0) goto finally; memoize: @@ -1594,7 +1511,7 @@ Py_DECREF(obj); if (i < 0) return -1; - if (self->write_func(self, &append, 1) < 0) + if (_Pickler_Write(self, &append, 1) < 0) return -1; } return 0; @@ -1621,7 +1538,7 @@ /* Only one item to write */ if (save(self, firstitem, 0) < 0) goto BatchFailed; - if (self->write_func(self, &append, 1) < 0) + if (_Pickler_Write(self, &append, 1) < 0) goto BatchFailed; Py_CLEAR(firstitem); break; @@ -1630,7 +1547,7 @@ /* More than one item to write */ /* Pump out MARK, items, APPENDS. */ - if (self->write_func(self, &MARKv, 1) < 0) + if (_Pickler_Write(self, &MARKv, 1) < 0) goto BatchFailed; if (save(self, firstitem, 0) < 0) @@ -1656,7 +1573,7 @@ } } - if (self->write_func(self, &appends, 1) < 0) + if (_Pickler_Write(self, &appends, 1) < 0) goto BatchFailed; } while (n == BATCHSIZE); @@ -1690,7 +1607,7 @@ len = 2; } - if (self->write_func(self, s, len) < 0) + if (_Pickler_Write(self, s, len) < 0) goto finally; /* Get list length, and bow out early if empty. */ @@ -1769,7 +1686,7 @@ Py_DECREF(p); if (i < 0) return -1; - if (self->write_func(self, &setitem, 1) < 0) + if (_Pickler_Write(self, &setitem, 1) < 0) return -1; } return 0; @@ -1803,7 +1720,7 @@ goto BatchFailed; if (save(self, PyTuple_GET_ITEM(firstitem, 1), 0) < 0) goto BatchFailed; - if (self->write_func(self, &setitem, 1) < 0) + if (_Pickler_Write(self, &setitem, 1) < 0) goto BatchFailed; Py_CLEAR(firstitem); break; @@ -1812,7 +1729,7 @@ /* More than one item to write */ /* Pump out MARK, items, SETITEMS. */ - if (self->write_func(self, &MARKv, 1) < 0) + if (_Pickler_Write(self, &MARKv, 1) < 0) goto BatchFailed; if (save(self, PyTuple_GET_ITEM(firstitem, 0), 0) < 0) @@ -1847,7 +1764,7 @@ } } - if (self->write_func(self, &setitems, 1) < 0) + if (_Pickler_Write(self, &setitems, 1) < 0) goto BatchFailed; } while (n == BATCHSIZE); @@ -1881,7 +1798,7 @@ len = 2; } - if (self->write_func(self, s, len) < 0) + if (_Pickler_Write(self, s, len) < 0) goto finally; /* Get dict size, and bow out early if empty. */ @@ -1928,7 +1845,7 @@ if (self->fast && !fast_save_enter(self, args)) goto finally; - if (self->write_func(self, &MARKv, 1) < 0) + if (_Pickler_Write(self, &MARKv, 1) < 0) goto finally; if (!( class = PyObject_GetAttr(args, __class___str))) @@ -1986,22 +1903,22 @@ module_str = PyString_AS_STRING((PyStringObject *)module); name_str = PyString_AS_STRING((PyStringObject *)name); - if (self->write_func(self, &inst, 1) < 0) + if (_Pickler_Write(self, &inst, 1) < 0) goto finally; - if (self->write_func(self, module_str, module_size) < 0) + if (_Pickler_Write(self, module_str, module_size) < 0) goto finally; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto finally; - if (self->write_func(self, name_str, name_size) < 0) + if (_Pickler_Write(self, name_str, name_size) < 0) goto finally; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto finally; } - else if (self->write_func(self, &obj, 1) < 0) { + else if (_Pickler_Write(self, &obj, 1) < 0) { goto finally; } @@ -2038,7 +1955,7 @@ if (save(self, state, 0) < 0) goto finally; - if (self->write_func(self, &build, 1) < 0) + if (_Pickler_Write(self, &build, 1) < 0) goto finally; res = 0; @@ -2165,25 +2082,25 @@ n = 5; } - if (self->write_func(self, c_str, n) >= 0) + if (_Pickler_Write(self, c_str, n) >= 0) res = 0; goto finally; /* and don't memoize */ } gen_global: - if (self->write_func(self, &global, 1) < 0) + if (_Pickler_Write(self, &global, 1) < 0) goto finally; - if (self->write_func(self, module_str, module_size) < 0) + if (_Pickler_Write(self, module_str, module_size) < 0) goto finally; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto finally; - if (self->write_func(self, name_str, name_size) < 0) + if (_Pickler_Write(self, name_str, name_size) < 0) goto finally; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto finally; if (put(self, args) < 0) @@ -2223,26 +2140,26 @@ goto finally; } - if (self->write_func(self, &persid, 1) < 0) + if (_Pickler_Write(self, &persid, 1) < 0) goto finally; if ((size = PyString_Size(pid)) < 0) goto finally; - if (self->write_func(self, - PyString_AS_STRING( - (PyStringObject *)pid), - size) < 0) + if (_Pickler_Write(self, + PyString_AS_STRING( + (PyStringObject *)pid), + size) < 0) goto finally; - if (self->write_func(self, "\n", 1) < 0) + if (_Pickler_Write(self, "\n", 1) < 0) goto finally; res = 1; goto finally; } else if (save(self, pid, 1) >= 0) { - if (self->write_func(self, &binpersid, 1) < 0) + if (_Pickler_Write(self, &binpersid, 1) < 0) res = -1; else res = 1; @@ -2401,14 +2318,14 @@ return -1; /* Add NEWOBJ opcode. */ - if (self->write_func(self, &newobj, 1) < 0) + if (_Pickler_Write(self, &newobj, 1) < 0) return -1; } else { /* Not using NEWOBJ. */ if (save(self, callable, 0) < 0 || save(self, argtup, 0) < 0 || - self->write_func(self, &reduce, 1) < 0) + _Pickler_Write(self, &reduce, 1) < 0) return -1; } @@ -2432,7 +2349,7 @@ if (state) { if (save(self, state, 0) < 0 || - self->write_func(self, &build, 1) < 0) + _Pickler_Write(self, &build, 1) < 0) return -1; } @@ -2701,24 +2618,32 @@ bytes[0] = PROTO; assert(self->proto >= 0 && self->proto < 256); bytes[1] = (char)self->proto; - if (self->write_func(self, bytes, 2) < 0) + if (_Pickler_Write(self, bytes, 2) < 0) return -1; } if (save(self, args, 0) < 0) return -1; - if (self->write_func(self, &stop, 1) < 0) + if (_Pickler_Write(self, &stop, 1) < 0) return -1; - if (self->write_func(self, NULL, 0) < 0) + if (_Pickler_Write(self, NULL, 0) < 0) return -1; return 0; } +static int +_Pickler_ClearBuffer(Picklerobject *self) +{ + memset(self->output_buffer, 0, sizeof(char) * self->output_len); + self->output_len = 0; + return 0; +} + static PyObject * -Pickle_clear_memo(Picklerobject *self, PyObject *args) +Pickler_clear_memo(Picklerobject *self, PyObject *args) { if (self->memo) PyDict_Clear(self->memo); @@ -2727,140 +2652,30 @@ } static PyObject * -Pickle_getvalue(Picklerobject *self, PyObject *args) +Pickler_getvalue(Picklerobject *self, PyObject *args) { - int l, i, rsize, ssize, clear=1, lm; - long ik; - PyObject *k, *r; - char *s, *p, *have_get; - Pdata *data; + int clear = 1; + PyObject *value; /* Can be called by Python code or C code */ if (args && !PyArg_ParseTuple(args, "|i:getvalue", &clear)) return NULL; /* Check to make sure we are based on a list */ - if (! Pdata_Check(self->file)) { - PyErr_SetString(PicklingError, - "Attempt to getvalue() a non-list-based pickler"); + if (self->file != NULL) { + PyErr_SetString( + PicklingError, + "Attempt to getvalue() a non-list-based pickler"); return NULL; } - /* flush write buffer */ - if (write_other(self, NULL, 0) < 0) return NULL; + value = _Pickler_GetString(self); + if (value == NULL) + return NULL; - data=(Pdata*)self->file; - l=data->length; - - /* set up an array to hold get/put status */ - lm = PyDict_Size(self->memo); - if (lm < 0) return NULL; - lm++; - have_get = malloc(lm); - if (have_get == NULL) return PyErr_NoMemory(); - memset(have_get, 0, lm); - - /* Scan for gets. */ - for (rsize = 0, i = l; --i >= 0; ) { - k = data->data[i]; - - if (PyString_Check(k)) - rsize += PyString_GET_SIZE(k); - - else if (PyInt_Check(k)) { /* put */ - ik = PyInt_AS_LONG((PyIntObject*)k); - if (ik >= lm || ik == 0) { - PyErr_SetString(PicklingError, - "Invalid get data"); - goto err; - } - if (have_get[ik]) /* with matching get */ - rsize += ik < 256 ? 2 : 5; - } - - else if (! (PyTuple_Check(k) && - PyTuple_GET_SIZE(k) == 2 && - PyInt_Check((k = PyTuple_GET_ITEM(k, 0)))) - ) { - PyErr_SetString(PicklingError, - "Unexpected data in internal list"); - goto err; - } - - else { /* put */ - ik = PyInt_AS_LONG((PyIntObject *)k); - if (ik >= lm || ik == 0) { - PyErr_SetString(PicklingError, - "Invalid get data"); - return NULL; - } - have_get[ik] = 1; - rsize += ik < 256 ? 2 : 5; - } - } - - /* Now generate the result */ - r = PyString_FromStringAndSize(NULL, rsize); - if (r == NULL) goto err; - s = PyString_AS_STRING((PyStringObject *)r); - - for (i = 0; i < l; i++) { - k = data->data[i]; - - if (PyString_Check(k)) { - ssize = PyString_GET_SIZE(k); - if (ssize) { - p=PyString_AS_STRING((PyStringObject *)k); - while (--ssize >= 0) - *s++ = *p++; - } - } - - else if (PyTuple_Check(k)) { /* get */ - ik = PyInt_AS_LONG((PyIntObject *) - PyTuple_GET_ITEM(k, 0)); - if (ik < 256) { - *s++ = BINGET; - *s++ = (int)(ik & 0xff); - } - else { - *s++ = LONG_BINGET; - *s++ = (int)(ik & 0xff); - *s++ = (int)((ik >> 8) & 0xff); - *s++ = (int)((ik >> 16) & 0xff); - *s++ = (int)((ik >> 24) & 0xff); - } - } - - else { /* put */ - ik = PyInt_AS_LONG((PyIntObject*)k); - - if (have_get[ik]) { /* with matching get */ - if (ik < 256) { - *s++ = BINPUT; - *s++ = (int)(ik & 0xff); - } - else { - *s++ = LONG_BINPUT; - *s++ = (int)(ik & 0xff); - *s++ = (int)((ik >> 8) & 0xff); - *s++ = (int)((ik >> 16) & 0xff); - *s++ = (int)((ik >> 24) & 0xff); - } - } - } - } - - if (clear) { - PyDict_Clear(self->memo); - Pdata_clear(data, 0); - } - - free(have_get); - return r; - err: - free(have_get); - return NULL; + if (clear) + self->output_len = 0; + return value; } static PyObject * @@ -2872,11 +2687,17 @@ if (!( PyArg_ParseTuple(args, "O|i:dump", &ob, &get))) return NULL; + if (_Pickler_ClearBuffer(self) < 0) + return NULL; if (dump(self, ob) < 0) return NULL; - if (get) return Pickle_getvalue(self, NULL); + if (self->file && _Pickler_FlushToFile(self) < 0) + return NULL; + if (get) + return Pickler_getvalue(self, NULL); + /* XXX Why does dump() return self? */ Py_INCREF(self); return (PyObject*)self; @@ -2888,9 +2709,9 @@ {"dump", (PyCFunction)Pickler_dump, METH_VARARGS, PyDoc_STR("dump(object) -- " "Write an object in pickle format to the object's pickle stream")}, - {"clear_memo", (PyCFunction)Pickle_clear_memo, METH_NOARGS, + {"clear_memo", (PyCFunction)Pickler_clear_memo, METH_NOARGS, PyDoc_STR("clear_memo() -- Clear the picklers memo")}, - {"getvalue", (PyCFunction)Pickle_getvalue, METH_VARARGS, + {"getvalue", (PyCFunction)Pickler_getvalue, METH_VARARGS, PyDoc_STR("getvalue() -- Finish picking a list-based pickle")}, {NULL, NULL} /* sentinel */ }; @@ -2915,68 +2736,26 @@ return NULL; self->proto = proto; self->bin = proto > 0; - self->fp = NULL; - self->write = NULL; self->memo = NULL; self->arg = NULL; self->pers_func = NULL; self->inst_pers_func = NULL; - self->write_buf = NULL; self->fast = 0; self->fast_container = 0; self->fast_memo = NULL; - self->buf_size = 0; self->dispatch_table = NULL; - self->file = NULL; - if (file) - Py_INCREF(file); - else { - file = Pdata_New(); - if (file == NULL) - goto err; - } + /* Use this buffer internally, flushing to file only when + necessary. */ + self->max_output_len = 4096; + self->output_buffer = (char *)malloc(4096 * sizeof(char)); + self->output_len = 0; self->file = file; + Py_XINCREF(self->file); if (!( self->memo = PyDict_New())) goto err; - if (PyFile_Check(file)) { - self->fp = PyFile_AsFile(file); - if (self->fp == NULL) { - PyErr_SetString(PyExc_ValueError, - "I/O operation on closed file"); - goto err; - } - self->write_func = write_file; - } - else if (PycStringIO_OutputCheck(file)) { - self->write_func = write_cStringIO; - } - else if (file == Py_None) { - self->write_func = write_none; - } - else { - self->write_func = write_other; - - if (! Pdata_Check(file)) { - self->write = PyObject_GetAttr(file, write_str); - if (!self->write) { - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, - "argument must have 'write' " - "attribute"); - goto err; - } - } - - self->write_buf = (char *)PyMem_Malloc(WRITE_BUF_SIZE); - if (self->write_buf == NULL) { - PyErr_NoMemory(); - goto err; - } - } - if (PyEval_GetRestricted()) { /* Restricted execution, get private tables */ PyObject *m = PyImport_Import(copyreg_str); @@ -3031,7 +2810,6 @@ Pickler_dealloc(Picklerobject *self) { PyObject_GC_UnTrack(self); - Py_XDECREF(self->write); Py_XDECREF(self->memo); Py_XDECREF(self->fast_memo); Py_XDECREF(self->arg); @@ -3039,14 +2817,15 @@ Py_XDECREF(self->pers_func); Py_XDECREF(self->inst_pers_func); Py_XDECREF(self->dispatch_table); - PyMem_Free(self->write_buf); + if (self->output_buffer != NULL) + free(self->output_buffer); + self->output_buffer = NULL; Py_TYPE(self)->tp_free((PyObject *)self); } static int Pickler_traverse(Picklerobject *self, visitproc visit, void *arg) { - Py_VISIT(self->write); Py_VISIT(self->memo); Py_VISIT(self->fast_memo); Py_VISIT(self->arg); @@ -3060,7 +2839,6 @@ static int Pickler_clear(Picklerobject *self) { - Py_CLEAR(self->write); Py_CLEAR(self->memo); Py_CLEAR(self->fast_memo); Py_CLEAR(self->arg); @@ -3068,6 +2846,9 @@ Py_CLEAR(self->pers_func); Py_CLEAR(self->inst_pers_func); Py_CLEAR(self->dispatch_table); + if (self->output_buffer != NULL) + free(self->output_buffer); + self->output_buffer = NULL; return 0; } @@ -3165,15 +2946,15 @@ static PyTypeObject Picklertype = { PyVarObject_HEAD_INIT(NULL, 0) - "cPickle.Pickler", /*tp_name*/ + "cPickle.Pickler", /*tp_name*/ sizeof(Picklerobject), /*tp_basicsize*/ 0, (destructor)Pickler_dealloc, /* tp_dealloc */ 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ 0, /* tp_compare */ - 0, /* tp_repr */ + 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -5535,6 +5316,9 @@ if (dump(pickler, ob) < 0) goto finally; + if (_Pickler_FlushToFile(pickler) < 0) + goto finally; + Py_INCREF(Py_None); res = Py_None; @@ -5550,29 +5334,24 @@ cpm_dumps(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"obj", "protocol", NULL}; - PyObject *ob, *file = 0, *res = NULL; - Picklerobject *pickler = 0; + PyObject *ob, *res = NULL; + Picklerobject *pickler = NULL; int proto = 0; if (!( PyArg_ParseTupleAndKeywords(args, kwds, "O|i:dumps", kwlist, &ob, &proto))) goto finally; - if (!( file = PycStringIO->NewOutput(128))) + if ((pickler = newPicklerobject(NULL, proto)) == NULL) goto finally; - if (!( pickler = newPicklerobject(file, proto))) - goto finally; - if (dump(pickler, ob) < 0) goto finally; - res = PycStringIO->cgetvalue(file); + res = _Pickler_GetString(pickler); - finally: +finally: Py_XDECREF(pickler); - Py_XDECREF(file); - return res; }