Skip to content

Commit 42782b8

Browse files
committed
Convert dict_content to take Py_buffer
1 parent cf8941c commit 42782b8

File tree

5 files changed

+87
-55
lines changed

5 files changed

+87
-55
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ _get_CDict(ZstdDict *self, int compressionLevel)
173173
}
174174
if (capsule == NULL) {
175175
/* Create ZSTD_CDict instance */
176-
char *dict_buffer = PyBytes_AS_STRING(self->dict_content);
177-
Py_ssize_t dict_len = Py_SIZE(self->dict_content);
176+
char *dict_buffer = self->dict_buffer;
177+
Py_ssize_t dict_len = self->dict_len;
178178
Py_BEGIN_ALLOW_THREADS
179179
cdict = ZSTD_createCDict(dict_buffer,
180180
dict_len,

Modules/_zstd/decompressor.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +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);
71+
char *dict_buffer = self->dict_buffer;
72+
Py_ssize_t dict_len = self->dict_len;
7373
Py_BEGIN_ALLOW_THREADS
7474
ret = ZSTD_createDDict(dict_buffer, dict_len);
7575
Py_END_ALLOW_THREADS
@@ -160,17 +160,13 @@ _zstd_load_impl(ZstdDecompressor *self, ZstdDict *zd,
160160
}
161161
else if (type == DICT_TYPE_UNDIGESTED) {
162162
/* Load a dictionary */
163-
zstd_ret = ZSTD_DCtx_loadDictionary(
164-
self->dctx,
165-
PyBytes_AS_STRING(zd->dict_content),
166-
Py_SIZE(zd->dict_content));
163+
zstd_ret = ZSTD_DCtx_loadDictionary(self->dctx, zd->dict_buffer,
164+
zd->dict_len);
167165
}
168166
else if (type == DICT_TYPE_PREFIX) {
169167
/* Load a prefix */
170-
zstd_ret = ZSTD_DCtx_refPrefix(
171-
self->dctx,
172-
PyBytes_AS_STRING(zd->dict_content),
173-
Py_SIZE(zd->dict_content));
168+
zstd_ret = ZSTD_DCtx_refPrefix(self->dctx, zd->dict_buffer,
169+
zd->dict_len);
174170
}
175171
else {
176172
/* Impossible code path */

Modules/_zstd/zstddict.c

Lines changed: 37 additions & 36 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,16 +42,15 @@ 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
{
4949
ZstdDict* self = PyObject_GC_New(ZstdDict, type);
5050
if (self == NULL) {
51-
goto error;
51+
return NULL;
5252
}
5353

54-
self->dict_content = NULL;
5554
self->d_dict = NULL;
5655
self->dict_id = 0;
5756
self->lock = (PyMutex){0};
@@ -63,16 +62,21 @@ _zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
6362
}
6463

6564
/* Check dict_content's type */
66-
self->dict_content = PyBytes_FromObject(dict_content);
67-
if (self->dict_content == NULL) {
65+
if (dict_content == NULL) {
6866
PyErr_SetString(PyExc_TypeError,
6967
"dict_content argument should be bytes-like object.");
7068
goto error;
7169
}
7270

73-
/* Both ordinary dictionary and "raw content" dictionary should
74-
at least 8 bytes */
75-
if (Py_SIZE(self->dict_content) < 8) {
71+
self->dict_buffer = PyMem_RawMalloc(dict_content->len);
72+
if (!self->dict_buffer) {
73+
return PyErr_NoMemory();
74+
}
75+
memcpy(self->dict_buffer, dict_content->buf, dict_content->len);
76+
self->dict_len = dict_content->len;
77+
78+
/* Both ordinary and "raw content" dictionaries must be 8 bytes minimum */
79+
if (self->dict_len < 8) {
7680
PyErr_SetString(PyExc_ValueError,
7781
"Zstandard dictionary content should at least "
7882
"8 bytes.");
@@ -81,8 +85,7 @@ _zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
8185

8286
/* Get dict_id, 0 means "raw content" dictionary. */
8387
self->dict_id = ZSTD_getDictID_fromDict(
84-
PyBytes_AS_STRING(self->dict_content),
85-
Py_SIZE(self->dict_content));
88+
self->dict_buffer, self->dict_len);
8689

8790
/* Check validity for ordinary dictionary */
8891
if (!is_raw && self->dict_id == 0) {
@@ -91,13 +94,13 @@ _zstd_ZstdDict_new_impl(PyTypeObject *type, PyObject *dict_content,
9194
goto error;
9295
}
9396

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

9799
return (PyObject*)self;
98100

99101
error:
100102
Py_XDECREF(self);
103+
PyObject_GC_Del(self);
101104
return NULL;
102105
}
103106

@@ -115,12 +118,12 @@ ZstdDict_dealloc(PyObject *ob)
115118

116119
assert(!PyMutex_IsLocked(&self->lock));
117120

118-
/* Release dict_content after Free ZSTD_CDict/ZSTD_DDict instances */
119-
Py_CLEAR(self->dict_content);
121+
/* Release dict_buffer after Free ZSTD_CDict/ZSTD_DDict instances */
122+
PyMem_RawFree(self->dict_buffer);
120123
Py_CLEAR(self->c_dicts);
121124

122125
PyTypeObject *tp = Py_TYPE(self);
123-
PyObject_GC_Del(ob);
126+
tp->tp_free(self);
124127
Py_DECREF(tp);
125128
}
126129

@@ -131,25 +134,33 @@ PyDoc_STRVAR(ZstdDict_dictid_doc,
131134
"The special value '0' means a 'raw content' dictionary,"
132135
"without any restrictions on format or content.");
133136

134-
PyDoc_STRVAR(ZstdDict_dictcontent_doc,
135-
"The content of a Zstandard dictionary, as a bytes object.");
136-
137137
static PyObject *
138138
ZstdDict_str(PyObject *ob)
139139
{
140140
ZstdDict *dict = ZstdDict_CAST(ob);
141141
return PyUnicode_FromFormat("<ZstdDict dict_id=%u dict_size=%zd>",
142-
dict->dict_id, Py_SIZE(dict->dict_content));
142+
dict->dict_id, dict->dict_len);
143143
}
144144

145145
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},
146+
{"dict_id", Py_T_UINT, offsetof(ZstdDict, dict_id), Py_READONLY, ZstdDict_dictid_doc},
150147
{NULL}
151148
};
152149

150+
/*[clinic input]
151+
@getter
152+
_zstd.ZstdDict.dict_content
153+
154+
The content of a Zstandard dictionary, as a bytes object.
155+
[clinic start generated code]*/
156+
157+
static PyObject *
158+
_zstd_ZstdDict_dict_content_get_impl(ZstdDict *self)
159+
/*[clinic end generated code: output=0d05caa5b550eabb input=4ed526d1c151c596]*/
160+
{
161+
return PyBytes_FromStringAndSize(self->dict_buffer, self->dict_len);
162+
}
163+
153164
/*[clinic input]
154165
@getter
155166
_zstd.ZstdDict.as_digested_dict
@@ -219,6 +230,7 @@ _zstd_ZstdDict_as_prefix_get_impl(ZstdDict *self)
219230
}
220231

221232
static PyGetSetDef ZstdDict_getset[] = {
233+
_ZSTD_ZSTDDICT_DICT_CONTENT_GETSETDEF
222234
_ZSTD_ZSTDDICT_AS_DIGESTED_DICT_GETSETDEF
223235
_ZSTD_ZSTDDICT_AS_UNDIGESTED_DICT_GETSETDEF
224236
_ZSTD_ZSTDDICT_AS_PREFIX_GETSETDEF
@@ -229,24 +241,14 @@ static Py_ssize_t
229241
ZstdDict_length(PyObject *ob)
230242
{
231243
ZstdDict *self = ZstdDict_CAST(ob);
232-
assert(PyBytes_Check(self->dict_content));
233-
return Py_SIZE(self->dict_content);
244+
return self->dict_len;
234245
}
235246

236247
static int
237248
ZstdDict_traverse(PyObject *ob, visitproc visit, void *arg)
238249
{
239250
ZstdDict *self = ZstdDict_CAST(ob);
240251
Py_VISIT(self->c_dicts);
241-
Py_VISIT(self->dict_content);
242-
return 0;
243-
}
244-
245-
static int
246-
ZstdDict_clear(PyObject *ob)
247-
{
248-
ZstdDict *self = ZstdDict_CAST(ob);
249-
Py_CLEAR(self->dict_content);
250252
return 0;
251253
}
252254

@@ -259,7 +261,6 @@ static PyType_Slot zstddict_slots[] = {
259261
{Py_tp_doc, (void *)_zstd_ZstdDict_new__doc__},
260262
{Py_sq_length, ZstdDict_length},
261263
{Py_tp_traverse, ZstdDict_traverse},
262-
{Py_tp_clear, ZstdDict_clear},
263264
{0, 0}
264265
};
265266

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)