Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update supported versions: add newer CPython and PyPy, drop 3.7 #112

Merged
merged 8 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ on:
release:
types: [published, created, edited]


jobs:
build_wheels:
name: "${{ matrix.wheel-selector }} wheel on ${{ matrix.os }}"
Expand All @@ -35,7 +34,7 @@ jobs:
# Python versions in sync with the ones in test.yml.
matrix:
os:
- "macos-11"
- "macos-12"
Comment on lines -38 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's good to know... assuming we can build a wheel that works on older macOS. Which cibuildwheel might automate. Or not.

- "ubuntu-22.04"
- "windows-2022"
wheel-selector:
Expand All @@ -44,9 +43,10 @@ jobs:
- "cp310-*"
- "cp311-*"
- "cp312-*"
- "pp37-*"
- "cp313-*"
- "pp38-*"
- "pp39-*"
- "pp310-*"

steps:
- name: Check out zfec sources
Expand All @@ -57,7 +57,7 @@ jobs:
fetch-depth: 0

- name: Build wheels
uses: pypa/cibuildwheel@v2.16.2
uses: pypa/cibuildwheel@v2.20.0
with:
output-dir: wheelhouse
env:
Expand All @@ -71,7 +71,6 @@ jobs:
CIBW_ARCHS_MACOS: "x86_64 universal2 arm64"
# Skip testing arm64 builds on Intel Macs.
CIBW_TEST_SKIP: "*-macosx_arm64 *-macosx_universal2:arm64"

- uses: actions/upload-artifact@v3
name: Upload artifacts
with:
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@ jobs:
# Python versions in sync with the ones in build.yml.
matrix:
os:
- "macos-11"
- "macos-latest"
- "ubuntu-22.04"
- "windows-2022"
python-version:
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "pypy-3.7"
- "3.12"
- "3.13-dev"
- "pypy-3.8"
- "pypy-3.9"
- "pypy-3.10"

steps:

Expand Down
75 changes: 49 additions & 26 deletions zfec/_fecmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ Encoder_encode(Encoder *self, PyObject *args) {
PyObject** pystrs_produced = (PyObject**)alloca((self->mm - self->kk) * sizeof(PyObject*)); /* This is an upper bound -- we will actually use only num_check_blocks_produced of these elements (see below). */
unsigned num_check_blocks_produced = 0; /* The first num_check_blocks_produced elements of the check_blocks_produced array and of the pystrs_produced array will be used. */
const gf** incblocks = (const gf**)alloca(self->kk * sizeof(const gf*));
Py_buffer *pybufs = (Py_buffer *)alloca(self->kk * sizeof(Py_buffer));
for (int i = 0; i < self->kk; i++) {
pybufs[i].buf = NULL;
}
size_t num_desired_blocks;
PyObject* fast_desired_blocks_nums = NULL;
PyObject** fast_desired_blocks_nums_items;
Expand All @@ -131,7 +135,7 @@ Encoder_encode(Encoder *self, PyObject *args) {
size_t i;
PyObject* fastinblocks = NULL;
PyObject** fastinblocksitems;
Py_ssize_t sz, oldsz = 0;
Py_ssize_t oldsz = 0;
unsigned char check_block_index = 0; /* index into the check_blocks_produced and (parallel) pystrs_produced arrays */

if (!PyArg_ParseTuple(args, "O|O:Encoder.encode", &inblocks, &desired_blocks_nums))
Expand Down Expand Up @@ -180,25 +184,29 @@ Encoder_encode(Encoder *self, PyObject *args) {
goto err;

for (i = 0; i < self->kk; i++) {
if (!PyObject_CheckReadBuffer(fastinblocksitems[i])) {
PyErr_Format(py_fec_error, "Precondition violation: %zu'th item is required to offer the single-segment read character buffer protocol, but it does not.", i);
goto err;
}
if (PyObject_AsReadBuffer(fastinblocksitems[i], (const void**)&(incblocks[i]), &sz))
goto err;
if (oldsz != 0 && oldsz != sz) {
PyErr_Format(py_fec_error, "Precondition violation: Input blocks are required to be all the same length. length of one block was: %zu, length of another block was: %zu", oldsz, sz);
goto err;
}
oldsz = sz;
if (PyObject_GetBuffer(fastinblocksitems[i], &pybufs[i], 0))
goto err;
if (!PyBuffer_IsContiguous(&pybufs[i], 'C')) {
goto err;
}
if (oldsz != 0 && oldsz != pybufs[i].len) {
PyErr_Format(py_fec_error,
"Precondition violation: Input blocks are required to be "
"all the same length. length of one block was: %zu, "
"length of another block was: %zu",
oldsz, pybufs[i].len);
goto err;
}
incblocks[i] = pybufs[i].buf;
oldsz = pybufs[i].len;
}

/* Allocate space for all of the check blocks. */

for (i = 0; i < num_desired_blocks; i++) {
if (c_desired_blocks_nums[i] >= self->kk) {
c_desired_checkblocks_ids[check_block_index] = c_desired_blocks_nums[i];
pystrs_produced[check_block_index] = PyString_FromStringAndSize(NULL, sz);
pystrs_produced[check_block_index] = PyString_FromStringAndSize(NULL, oldsz);
if (pystrs_produced[check_block_index] == NULL)
goto err;
check_blocks_produced[check_block_index] = (gf*)PyString_AsString(pystrs_produced[check_block_index]);
Expand All @@ -211,7 +219,7 @@ Encoder_encode(Encoder *self, PyObject *args) {

/* Encode any check blocks that are needed. */
Py_BEGIN_ALLOW_THREADS
fec_encode(self->fec_matrix, incblocks, check_blocks_produced, c_desired_checkblocks_ids, num_check_blocks_produced, sz);
fec_encode(self->fec_matrix, incblocks, check_blocks_produced, c_desired_checkblocks_ids, num_check_blocks_produced, oldsz);
Py_END_ALLOW_THREADS

/* Wrap all requested blocks up into a Python list of Python strings. */
Expand Down Expand Up @@ -240,8 +248,15 @@ Encoder_encode(Encoder *self, PyObject *args) {
Py_XDECREF(pystrs_produced[i]);
Py_XDECREF(result); result = NULL;
cleanup:
Py_XDECREF(fastinblocks); fastinblocks=NULL;
Py_XDECREF(fast_desired_blocks_nums); fast_desired_blocks_nums=NULL;
for (i = 0; i < self->kk; i++) {
if (pybufs[i].buf != NULL) {
PyBuffer_Release(&pybufs[i]);
}
}
Py_XDECREF(fastinblocks);
fastinblocks = NULL;
Py_XDECREF(fast_desired_blocks_nums);
fast_desired_blocks_nums = NULL;
return result;
}

Expand Down Expand Up @@ -390,6 +405,10 @@ Decoder_decode(Decoder *self, PyObject *args) {
PyObject* result = NULL;

const gf**restrict cblocks = (const gf**restrict)alloca(self->kk * sizeof(const gf*));
Py_buffer *pybufs = (Py_buffer *)alloca(self->kk * sizeof(Py_buffer));
for (int i = 0; i < self->kk; i++) {
pybufs[i].buf = NULL;
}
unsigned* cblocknums = (unsigned*)alloca(self->kk * sizeof(unsigned));
gf**restrict recoveredcstrs = (gf**)alloca(self->kk * sizeof(gf*)); /* self->kk is actually an upper bound -- we probably won't need all of this space. */
PyObject**restrict recoveredpystrs = (PyObject**restrict)alloca(self->kk * sizeof(PyObject*)); /* self->kk is actually an upper bound -- we probably won't need all of this space. */
Expand All @@ -399,7 +418,7 @@ Decoder_decode(Decoder *self, PyObject *args) {
unsigned needtorecover=0;
PyObject** fastblocksitems;
PyObject** fastblocknumsitems;
Py_ssize_t sz, oldsz = 0;
Py_ssize_t oldsz = 0;
long tmpl;
unsigned nextrecoveredix=0;

Expand Down Expand Up @@ -446,17 +465,16 @@ Decoder_decode(Decoder *self, PyObject *args) {
if (cblocknums[i] >= self->kk)
needtorecover+=1;

if (!PyObject_CheckReadBuffer(fastblocksitems[i])) {
PyErr_Format(py_fec_error, "Precondition violation: %u'th item is required to offer the single-segment read character buffer protocol, but it does not.\n", i);
if (PyObject_GetBuffer(fastblocksitems[i], &pybufs[i], 0)) {
pybufs[i].buf = NULL;
goto err;
}
if (PyObject_AsReadBuffer(fastblocksitems[i], (const void**)&(cblocks[i]), &sz))
goto err;
if (oldsz != 0 && oldsz != sz) {
PyErr_Format(py_fec_error, "Precondition violation: Input blocks are required to be all the same length. length of one block was: %zu, length of another block was: %zu\n", oldsz, sz);
if (oldsz != 0 && oldsz != pybufs[i].len) {
PyErr_Format(py_fec_error, "Precondition violation: Input blocks are required to be all the same length. length of one block was: %zu, length of another block was: %zu\n", oldsz, pybufs[i].len);
goto err;
}
oldsz = sz;
cblocks[i] = pybufs[i].buf;
oldsz = pybufs[i].len;
}

/* Move src packets into position. At the end of this loop we want the i'th
Expand All @@ -477,7 +495,7 @@ Decoder_decode(Decoder *self, PyObject *args) {

/* Allocate space for all of the recovered blocks. */
for (i=0; i<needtorecover; i++) {
recoveredpystrs[i] = PyString_FromStringAndSize(NULL, sz);
recoveredpystrs[i] = PyString_FromStringAndSize(NULL, oldsz);
if (recoveredpystrs[i] == NULL)
goto err;
recoveredcstrs[i] = (gf*)PyString_AsString(recoveredpystrs[i]);
Expand All @@ -487,7 +505,7 @@ Decoder_decode(Decoder *self, PyObject *args) {

/* Decode any recovered blocks that are needed. */
Py_BEGIN_ALLOW_THREADS
fec_decode(self->fec_matrix, cblocks, recoveredcstrs, cblocknums, sz);
fec_decode(self->fec_matrix, cblocks, recoveredcstrs, cblocknums, oldsz);
Py_END_ALLOW_THREADS

/* Wrap up both original primary blocks and decoded blocks into a Python list of Python strings. */
Expand Down Expand Up @@ -517,6 +535,11 @@ Decoder_decode(Decoder *self, PyObject *args) {
Py_XDECREF(recoveredpystrs[i]);
Py_XDECREF(result); result = NULL;
cleanup:
for (i = 0; i < self->kk; i++) {
if (pybufs[i].buf != NULL) {
PyBuffer_Release(&pybufs[i]);
}
}
Py_XDECREF(fastblocks); fastblocks=NULL;
Py_XDECREF(fastblocknums); fastblocknums=NULL;
return result;
Expand Down
Loading