Skip to content

Commit 4841201

Browse files
[3.14] gh-132983: Convert dict_content to take Py_buffer in ZstdDict() (GH-133924) (#134723)
gh-132983: Convert dict_content to take Py_buffer in ``ZstdDict()`` (GH-133924) (cherry picked from commit f2ce4bb) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
1 parent 117bb29 commit 4841201

File tree

5 files changed

+97
-73
lines changed

5 files changed

+97
-73
lines changed

Modules/_zstd/clinic/zstddict.c.h

Lines changed: 38 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_zstd/compressor.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,8 @@ _get_CDict(ZstdDict *self, int compressionLevel)
181181
}
182182
if (capsule == NULL) {
183183
/* Create ZSTD_CDict instance */
184-
char *dict_buffer = PyBytes_AS_STRING(self->dict_content);
185-
Py_ssize_t dict_len = Py_SIZE(self->dict_content);
186184
Py_BEGIN_ALLOW_THREADS
187-
cdict = ZSTD_createCDict(dict_buffer,
188-
dict_len,
185+
cdict = ZSTD_createCDict(self->dict_buffer, self->dict_len,
189186
compressionLevel);
190187
Py_END_ALLOW_THREADS
191188

@@ -244,17 +241,13 @@ _zstd_load_impl(ZstdCompressor *self, ZstdDict *zd,
244241
else if (type == DICT_TYPE_UNDIGESTED) {
245242
/* Load a dictionary.
246243
It doesn't override compression context's parameters. */
247-
zstd_ret = ZSTD_CCtx_loadDictionary(
248-
self->cctx,
249-
PyBytes_AS_STRING(zd->dict_content),
250-
Py_SIZE(zd->dict_content));
244+
zstd_ret = ZSTD_CCtx_loadDictionary(self->cctx, zd->dict_buffer,
245+
zd->dict_len);
251246
}
252247
else if (type == DICT_TYPE_PREFIX) {
253248
/* Load a prefix */
254-
zstd_ret = ZSTD_CCtx_refPrefix(
255-
self->cctx,
256-
PyBytes_AS_STRING(zd->dict_content),
257-
Py_SIZE(zd->dict_content));
249+
zstd_ret = ZSTD_CCtx_refPrefix(self->cctx, zd->dict_buffer,
250+
zd->dict_len);
258251
}
259252
else {
260253
Py_UNREACHABLE();

Modules/_zstd/decompressor.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,8 @@ _get_DDict(ZstdDict *self)
6868

6969
if (self->d_dict == NULL) {
7070
/* Create ZSTD_DDict instance from dictionary content */
71-
char *dict_buffer = PyBytes_AS_STRING(self->dict_content);
72-
Py_ssize_t dict_len = Py_SIZE(self->dict_content);
7371
Py_BEGIN_ALLOW_THREADS
74-
ret = ZSTD_createDDict(dict_buffer, dict_len);
72+
ret = ZSTD_createDDict(self->dict_buffer, self->dict_len);
7573
Py_END_ALLOW_THREADS
7674
self->d_dict = ret;
7775

@@ -156,17 +154,13 @@ _zstd_load_impl(ZstdDecompressor *self, ZstdDict *zd,
156154
}
157155
else if (type == DICT_TYPE_UNDIGESTED) {
158156
/* Load a dictionary */
159-
zstd_ret = ZSTD_DCtx_loadDictionary(
160-
self->dctx,
161-
PyBytes_AS_STRING(zd->dict_content),
162-
Py_SIZE(zd->dict_content));
157+
zstd_ret = ZSTD_DCtx_loadDictionary(self->dctx, zd->dict_buffer,
158+
zd->dict_len);
163159
}
164160
else if (type == DICT_TYPE_PREFIX) {
165161
/* Load a prefix */
166-
zstd_ret = ZSTD_DCtx_refPrefix(
167-
self->dctx,
168-
PyBytes_AS_STRING(zd->dict_content),
169-
Py_SIZE(zd->dict_content));
162+
zstd_ret = ZSTD_DCtx_refPrefix(self->dctx, zd->dict_buffer,
163+
zd->dict_len);
170164
}
171165
else {
172166
/* Impossible code path */

Modules/_zstd/zstddict.c

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class _zstd.ZstdDict "ZstdDict *" "&zstd_dict_type_spec"
2626
/*[clinic input]
2727
@classmethod
2828
_zstd.ZstdDict.__new__ as _zstd_ZstdDict_new
29-
dict_content: object
29+
dict_content: Py_buffer
3030
The content of a Zstandard dictionary as a bytes-like object.
3131
/
3232
*
@@ -42,17 +42,25 @@ by multiple ZstdCompressor or ZstdDecompressor objects.
4242
[clinic start generated code]*/
4343

4444
static PyObject *
45-
_zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
45+
_zstd_ZstdDict_new_impl(PyTypeObject *type, Py_buffer *dict_content,
4646
int is_raw)
47-
/*[clinic end generated code: output=3ebff839cb3be6d7 input=6b5de413869ae878]*/
47+
/*[clinic end generated code: output=685b7406a48b0949 input=9e8c493e31c98383]*/
4848
{
49+
/* All dictionaries must be at least 8 bytes */
50+
if (dict_content->len < 8) {
51+
PyErr_SetString(PyExc_ValueError,
52+
"Zstandard dictionary content too short "
53+
"(must have at least eight bytes)");
54+
return NULL;
55+
}
56+
4957
ZstdDict* self = PyObject_GC_New(ZstdDict, type);
5058
if (self == NULL) {
51-
goto error;
59+
return NULL;
5260
}
5361

54-
self->dict_content = NULL;
5562
self->d_dict = NULL;
63+
self->dict_buffer = NULL;
5664
self->dict_id = 0;
5765
self->lock = (PyMutex){0};
5866

@@ -62,39 +70,26 @@ _zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
6270
goto error;
6371
}
6472

65-
/* Check dict_content's type */
66-
self->dict_content = PyBytes_FromObject(dict_content);
67-
if (self->dict_content == NULL) {
68-
PyErr_SetString(PyExc_TypeError,
69-
"dict_content argument should be bytes-like object.");
70-
goto error;
71-
}
72-
73-
/* Both ordinary dictionary and "raw content" dictionary should
74-
at least 8 bytes */
75-
if (Py_SIZE(self->dict_content) < 8) {
76-
PyErr_SetString(PyExc_ValueError,
77-
"Zstandard dictionary content should at least "
78-
"8 bytes.");
73+
self->dict_buffer = PyMem_Malloc(dict_content->len);
74+
if (!self->dict_buffer) {
75+
PyErr_NoMemory();
7976
goto error;
8077
}
78+
memcpy(self->dict_buffer, dict_content->buf, dict_content->len);
79+
self->dict_len = dict_content->len;
8180

8281
/* Get dict_id, 0 means "raw content" dictionary. */
83-
self->dict_id = ZSTD_getDictID_fromDict(
84-
PyBytes_AS_STRING(self->dict_content),
85-
Py_SIZE(self->dict_content));
82+
self->dict_id = ZSTD_getDictID_fromDict(self->dict_buffer, self->dict_len);
8683

8784
/* Check validity for ordinary dictionary */
8885
if (!is_raw && self->dict_id == 0) {
89-
char *msg = "Invalid Zstandard dictionary and is_raw not set.\n";
90-
PyErr_SetString(PyExc_ValueError, msg);
86+
PyErr_SetString(PyExc_ValueError, "invalid Zstandard dictionary");
9187
goto error;
9288
}
9389

94-
// Can only track self once self->dict_content is included
9590
PyObject_GC_Track(self);
9691

97-
return (PyObject*)self;
92+
return (PyObject *)self;
9893

9994
error:
10095
Py_XDECREF(self);
@@ -115,12 +110,12 @@ ZstdDict_dealloc(PyObject *ob)
115110

116111
assert(!PyMutex_IsLocked(&self->lock));
117112

118-
/* Release dict_content after Free ZSTD_CDict/ZSTD_DDict instances */
119-
Py_CLEAR(self->dict_content);
113+
/* Release dict_buffer after freeing ZSTD_CDict/ZSTD_DDict instances */
114+
PyMem_Free(self->dict_buffer);
120115
Py_CLEAR(self->c_dicts);
121116

122117
PyTypeObject *tp = Py_TYPE(self);
123-
PyObject_GC_Del(ob);
118+
tp->tp_free(self);
124119
Py_DECREF(tp);
125120
}
126121

@@ -131,25 +126,33 @@ PyDoc_STRVAR(ZstdDict_dictid_doc,
131126
"The special value '0' means a 'raw content' dictionary,"
132127
"without any restrictions on format or content.");
133128

134-
PyDoc_STRVAR(ZstdDict_dictcontent_doc,
135-
"The content of a Zstandard dictionary, as a bytes object.");
136-
137129
static PyObject *
138-
ZstdDict_str(PyObject *ob)
130+
ZstdDict_repr(PyObject *ob)
139131
{
140132
ZstdDict *dict = ZstdDict_CAST(ob);
141133
return PyUnicode_FromFormat("<ZstdDict dict_id=%u dict_size=%zd>",
142-
dict->dict_id, Py_SIZE(dict->dict_content));
134+
(unsigned int)dict->dict_id, dict->dict_len);
143135
}
144136

145137
static PyMemberDef ZstdDict_members[] = {
146-
{"dict_id", Py_T_UINT, offsetof(ZstdDict, dict_id), Py_READONLY,
147-
ZstdDict_dictid_doc},
148-
{"dict_content", Py_T_OBJECT_EX, offsetof(ZstdDict, dict_content),
149-
Py_READONLY, ZstdDict_dictcontent_doc},
138+
{"dict_id", Py_T_UINT, offsetof(ZstdDict, dict_id), Py_READONLY, ZstdDict_dictid_doc},
150139
{NULL}
151140
};
152141

142+
/*[clinic input]
143+
@getter
144+
_zstd.ZstdDict.dict_content
145+
146+
The content of a Zstandard dictionary, as a bytes object.
147+
[clinic start generated code]*/
148+
149+
static PyObject *
150+
_zstd_ZstdDict_dict_content_get_impl(ZstdDict *self)
151+
/*[clinic end generated code: output=0d05caa5b550eabb input=4ed526d1c151c596]*/
152+
{
153+
return PyBytes_FromStringAndSize(self->dict_buffer, self->dict_len);
154+
}
155+
153156
/*[clinic input]
154157
@getter
155158
_zstd.ZstdDict.as_digested_dict
@@ -219,6 +222,7 @@ _zstd_ZstdDict_as_prefix_get_impl(ZstdDict *self)
219222
}
220223

221224
static PyGetSetDef ZstdDict_getset[] = {
225+
_ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF
222226
_ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF
223227
_ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF
224228
_ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF
@@ -229,24 +233,22 @@ static Py_ssize_t
229233
ZstdDict_length(PyObject *ob)
230234
{
231235
ZstdDict *self = ZstdDict_CAST(ob);
232-
assert(PyBytes_Check(self->dict_content));
233-
return Py_SIZE(self->dict_content);
236+
return self->dict_len;
234237
}
235238

236239
static int
237240
ZstdDict_traverse(PyObject *ob, visitproc visit, void *arg)
238241
{
239242
ZstdDict *self = ZstdDict_CAST(ob);
240243
Py_VISIT(self->c_dicts);
241-
Py_VISIT(self->dict_content);
242244
return 0;
243245
}
244246

245247
static int
246248
ZstdDict_clear(PyObject *ob)
247249
{
248250
ZstdDict *self = ZstdDict_CAST(ob);
249-
Py_CLEAR(self->dict_content);
251+
Py_CLEAR(self->c_dicts);
250252
return 0;
251253
}
252254

@@ -255,7 +257,7 @@ static PyType_Slot zstddict_slots[] = {
255257
{Py_tp_getset, ZstdDict_getset},
256258
{Py_tp_new, _zstd_ZstdDict_new},
257259
{Py_tp_dealloc, ZstdDict_dealloc},
258-
{Py_tp_str, ZstdDict_str},
260+
{Py_tp_repr, ZstdDict_repr},
259261
{Py_tp_doc, (void *)_zstd_ZstdDict_new__doc__},
260262
{Py_sq_length, ZstdDict_length},
261263
{Py_tp_traverse, ZstdDict_traverse},

Modules/_zstd/zstddict.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ typedef struct {
1515
ZSTD_DDict *d_dict;
1616
PyObject *c_dicts;
1717

18-
/* Content of the dictionary, bytes object. */
19-
PyObject *dict_content;
18+
/* Dictionary content. */
19+
char *dict_buffer;
20+
Py_ssize_t dict_len;
21+
2022
/* Dictionary id */
2123
uint32_t dict_id;
2224

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy