Skip to content

Commit 94ab248

Browse files
committed
Convert dict_content to take Py_buffer
1 parent 27ed645 commit 94ab248

File tree

5 files changed

+90
-63
lines changed

5 files changed

+90
-63
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: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ _get_CDict(ZstdDict *self, int compressionLevel)
170170
}
171171

172172
/* Create ZSTD_CDict instance */
173-
char *dict_buffer = PyBytes_AS_STRING(self->dict_content);
174-
Py_ssize_t dict_len = Py_SIZE(self->dict_content);
173+
char *dict_buffer = self->dict_buffer;
174+
Py_ssize_t dict_len = self->dict_len;
175175
Py_BEGIN_ALLOW_THREADS
176176
cdict = ZSTD_createCDict(dict_buffer,
177177
dict_len,
@@ -284,19 +284,15 @@ _zstd_load_c_dict(ZstdCompressor *self, PyObject *dict)
284284
/* Load a dictionary.
285285
It doesn't override compression context's parameters. */
286286
Py_BEGIN_CRITICAL_SECTION2(self, zd);
287-
zstd_ret = ZSTD_CCtx_loadDictionary(
288-
self->cctx,
289-
PyBytes_AS_STRING(zd->dict_content),
290-
Py_SIZE(zd->dict_content));
287+
zstd_ret = ZSTD_CCtx_loadDictionary(self->cctx, zd->dict_buffer,
288+
zd->dict_len);
291289
Py_END_CRITICAL_SECTION2();
292290
}
293291
else if (type == DICT_TYPE_PREFIX) {
294292
/* Load a prefix */
295293
Py_BEGIN_CRITICAL_SECTION2(self, zd);
296-
zstd_ret = ZSTD_CCtx_refPrefix(
297-
self->cctx,
298-
PyBytes_AS_STRING(zd->dict_content),
299-
Py_SIZE(zd->dict_content));
294+
zstd_ret = ZSTD_CCtx_refPrefix(self->cctx, zd->dict_buffer,
295+
zd->dict_len);
300296
Py_END_CRITICAL_SECTION2();
301297
}
302298
else {

Modules/_zstd/decompressor.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ _get_DDict(ZstdDict *self)
6464
Py_BEGIN_CRITICAL_SECTION(self);
6565
if (self->d_dict == NULL) {
6666
/* Create ZSTD_DDict instance from dictionary content */
67-
char *dict_buffer = PyBytes_AS_STRING(self->dict_content);
68-
Py_ssize_t dict_len = Py_SIZE(self->dict_content);
67+
char *dict_buffer = self->dict_buffer;
68+
Py_ssize_t dict_len = self->dict_len;
6969
Py_BEGIN_ALLOW_THREADS
7070
self->d_dict = ZSTD_createDDict(dict_buffer,
7171
dict_len);
@@ -213,19 +213,15 @@ _zstd_load_d_dict(ZstdDecompressor *self, PyObject *dict)
213213
else if (type == DICT_TYPE_UNDIGESTED) {
214214
/* Load a dictionary */
215215
Py_BEGIN_CRITICAL_SECTION2(self, zd);
216-
zstd_ret = ZSTD_DCtx_loadDictionary(
217-
self->dctx,
218-
PyBytes_AS_STRING(zd->dict_content),
219-
Py_SIZE(zd->dict_content));
216+
zstd_ret = ZSTD_DCtx_loadDictionary(self->dctx, zd->dict_buffer,
217+
zd->dict_len);
220218
Py_END_CRITICAL_SECTION2();
221219
}
222220
else if (type == DICT_TYPE_PREFIX) {
223221
/* Load a prefix */
224222
Py_BEGIN_CRITICAL_SECTION2(self, zd);
225-
zstd_ret = ZSTD_DCtx_refPrefix(
226-
self->dctx,
227-
PyBytes_AS_STRING(zd->dict_content),
228-
Py_SIZE(zd->dict_content));
223+
zstd_ret = ZSTD_DCtx_refPrefix(self->dctx, zd->dict_buffer,
224+
zd->dict_len);
229225
Py_END_CRITICAL_SECTION2();
230226
}
231227
else {

Modules/_zstd/zstddict.c

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class _zstd.ZstdDict "ZstdDict *" "&zstd_dict_type_spec"
2525
/*[clinic input]
2626
@classmethod
2727
_zstd.ZstdDict.__new__ as _zstd_ZstdDict_new
28-
dict_content: object
28+
dict_content: Py_buffer
2929
The content of a Zstandard dictionary as a bytes-like object.
3030
/
3131
*
@@ -41,16 +41,15 @@ by multiple ZstdCompressor or ZstdDecompressor objects.
4141
[clinic start generated code]*/
4242

4343
static PyObject *
44-
_zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
44+
_zstd_ZstdDict_new_impl(PyTypeObject *type, Py_buffer *dict_content,
4545
int is_raw)
46-
/*[clinic end generated code: output=3ebff839cb3be6d7 input=6b5de413869ae878]*/
46+
/*[clinic end generated code: output=685b7406a48b0949 input=9e8c493e31c98383]*/
4747
{
4848
ZstdDict* self = PyObject_GC_New(ZstdDict, type);
4949
if (self == NULL) {
50-
goto error;
50+
return NULL;
5151
}
5252

53-
self->dict_content = NULL;
5453
self->d_dict = NULL;
5554

5655
/* ZSTD_CDict dict */
@@ -60,24 +59,28 @@ _zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
6059
}
6160

6261
/* Check dict_content's type */
63-
self->dict_content = PyBytes_FromObject(dict_content);
64-
if (self->dict_content == NULL) {
62+
if (dict_content == NULL) {
6563
PyErr_SetString(PyExc_TypeError,
6664
"dict_content argument should be bytes-like object.");
6765
goto error;
6866
}
6967

70-
/* Both ordinary dictionary and "raw content" dictionary should
71-
at least 8 bytes */
72-
if (Py_SIZE(self->dict_content) < 8) {
68+
self->dict_buffer = PyMem_RawMalloc(dict_content->len);
69+
if (!self->dict_buffer) {
70+
return PyErr_NoMemory();
71+
}
72+
memcpy(self->dict_buffer, dict_content->buf, dict_content->len);
73+
self->dict_len = dict_content->len;
74+
75+
/* Both ordinary and "raw content" dictionaries must be 8 bytes minimum */
76+
if (self->dict_len < 8) {
7377
PyErr_SetString(PyExc_ValueError,
7478
"Zstandard dictionary content should at least 8 bytes.");
7579
goto error;
7680
}
7781

7882
/* Get dict_id, 0 means "raw content" dictionary. */
79-
self->dict_id = ZSTD_getDictID_fromDict(PyBytes_AS_STRING(self->dict_content),
80-
Py_SIZE(self->dict_content));
83+
self->dict_id = ZSTD_getDictID_fromDict(self->dict_buffer, self->dict_len);
8184

8285
/* Check validity for ordinary dictionary */
8386
if (!is_raw && self->dict_id == 0) {
@@ -86,15 +89,12 @@ _zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
8689
goto error;
8790
}
8891

89-
// Can only track self once self->dict_content is included
9092
PyObject_GC_Track(self);
9193

9294
return (PyObject*)self;
9395

9496
error:
95-
if (self != NULL) {
96-
PyObject_GC_Del(self);
97-
}
97+
PyObject_GC_Del(self);
9898
return NULL;
9999
}
100100

@@ -108,12 +108,12 @@ ZstdDict_dealloc(PyObject *ob)
108108
/* Free ZSTD_DDict instance */
109109
ZSTD_freeDDict(self->d_dict);
110110

111-
/* Release dict_content after Free ZSTD_CDict/ZSTD_DDict instances */
112-
Py_CLEAR(self->dict_content);
111+
/* Release dict_buffer after Free ZSTD_CDict/ZSTD_DDict instances */
112+
PyMem_RawFree(self->dict_buffer);
113113
Py_CLEAR(self->c_dicts);
114114

115115
PyTypeObject *tp = Py_TYPE(self);
116-
PyObject_GC_Del(ob);
116+
tp->tp_free(self);
117117
Py_DECREF(tp);
118118
}
119119

@@ -124,23 +124,33 @@ PyDoc_STRVAR(ZstdDict_dictid_doc,
124124
"The special value '0' means a 'raw content' dictionary,"
125125
"without any restrictions on format or content.");
126126

127-
PyDoc_STRVAR(ZstdDict_dictcontent_doc,
128-
"The content of a Zstandard dictionary, as a bytes object.");
129-
130127
static PyObject *
131128
ZstdDict_str(PyObject *ob)
132129
{
133130
ZstdDict *dict = ZstdDict_CAST(ob);
134131
return PyUnicode_FromFormat("<ZstdDict dict_id=%u dict_size=%zd>",
135-
dict->dict_id, Py_SIZE(dict->dict_content));
132+
dict->dict_id, dict->dict_len);
136133
}
137134

138135
static PyMemberDef ZstdDict_members[] = {
139136
{"dict_id", Py_T_UINT, offsetof(ZstdDict, dict_id), Py_READONLY, ZstdDict_dictid_doc},
140-
{"dict_content", Py_T_OBJECT_EX, offsetof(ZstdDict, dict_content), Py_READONLY, ZstdDict_dictcontent_doc},
141137
{NULL}
142138
};
143139

140+
/*[clinic input]
141+
@getter
142+
_zstd.ZstdDict.dict_content
143+
144+
The content of a Zstandard dictionary, as a bytes object.
145+
[clinic start generated code]*/
146+
147+
static PyObject *
148+
_zstd_ZstdDict_dict_content_get_impl(ZstdDict *self)
149+
/*[clinic end generated code: output=0d05caa5b550eabb input=4ed526d1c151c596]*/
150+
{
151+
return PyBytes_FromStringAndSize(self->dict_buffer, self->dict_len);
152+
}
153+
144154
/*[clinic input]
145155
@critical_section
146156
@getter
@@ -207,6 +217,7 @@ _zstd_ZstdDict_as_prefix_get_impl(ZstdDict *self)
207217
}
208218

209219
static PyGetSetDef ZstdDict_getset[] = {
220+
_ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF
210221
_ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF
211222
_ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF
212223
_ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF
@@ -217,24 +228,14 @@ static Py_ssize_t
217228
ZstdDict_length(PyObject *ob)
218229
{
219230
ZstdDict *self = ZstdDict_CAST(ob);
220-
assert(PyBytes_Check(self->dict_content));
221-
return Py_SIZE(self->dict_content);
231+
return self->dict_len;
222232
}
223233

224234
static int
225235
ZstdDict_traverse(PyObject *ob, visitproc visit, void *arg)
226236
{
227237
ZstdDict *self = ZstdDict_CAST(ob);
228238
Py_VISIT(self->c_dicts);
229-
Py_VISIT(self->dict_content);
230-
return 0;
231-
}
232-
233-
static int
234-
ZstdDict_clear(PyObject *ob)
235-
{
236-
ZstdDict *self = ZstdDict_CAST(ob);
237-
Py_CLEAR(self->dict_content);
238239
return 0;
239240
}
240241

@@ -247,7 +248,6 @@ static PyType_Slot zstddict_slots[] = {
247248
{Py_tp_doc, (void *)_zstd_ZstdDict_new__doc__},
248249
{Py_sq_length, ZstdDict_length},
249250
{Py_tp_traverse, ZstdDict_traverse},
250-
{Py_tp_clear, ZstdDict_clear},
251251
{0, 0}
252252
};
253253

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
} ZstdDict;

0 commit comments

Comments
 (0)