Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-bitarray for openSUSE:Factory checked in at 2023-02-11 21:57:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-bitarray (Old) and /work/SRC/openSUSE:Factory/.python-bitarray.new.1848 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-bitarray" Sat Feb 11 21:57:12 2023 rev:15 rq:1064329 version:2.7.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-bitarray/python-bitarray.changes 2023-02-10 14:36:13.786246585 +0100 +++ /work/SRC/openSUSE:Factory/.python-bitarray.new.1848/python-bitarray.changes 2023-02-11 21:57:50.223814417 +0100 @@ -1,0 +2,6 @@ +Fri Feb 10 17:42:13 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 2.7.1: + * optimize ``util.sc_encode()`` + +------------------------------------------------------------------- Old: ---- bitarray-2.7.0.tar.gz New: ---- bitarray-2.7.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-bitarray.spec ++++++ --- /var/tmp/diff_new_pack.dr6evN/_old 2023-02-11 21:57:50.575816609 +0100 +++ /var/tmp/diff_new_pack.dr6evN/_new 2023-02-11 21:57:50.583816659 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-bitarray -Version: 2.7.0 +Version: 2.7.1 Release: 0 Summary: Efficient Arrays of Booleans License: Python-2.0 ++++++ bitarray-2.7.0.tar.gz -> bitarray-2.7.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/CHANGE_LOG new/bitarray-2.7.1/CHANGE_LOG --- old/bitarray-2.7.0/CHANGE_LOG 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/CHANGE_LOG 2023-02-10 16:30:12.000000000 +0100 @@ -1,3 +1,8 @@ +2023-02-10 2.7.1: +------------------- + * optimize `util.sc_encode()` + + 2023-02-05 2.7.0: ------------------- * add `util.sc_encode()` and `util.sc_decode()` for diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/README.rst new/bitarray-2.7.1/README.rst --- old/bitarray-2.7.0/README.rst 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/README.rst 2023-02-10 16:30:12.000000000 +0100 @@ -63,7 +63,7 @@ $ python -c 'import bitarray; bitarray.test()' bitarray is installed in: /Users/ilan/bitarray/bitarray - bitarray version: 2.7.0 + bitarray version: 2.7.1 sys.version: 3.11.0 (main, Oct 25 2022) [Clang 14.0.4] sys.prefix: /Users/ilan/Mini3/envs/py311 pointer size: 64 bit @@ -401,7 +401,7 @@ Reference ========= -bitarray version: 2.7.0 -- `change log <https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__ +bitarray version: 2.7.1 -- `change log <https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__ In the following, ``item`` and ``value`` are usually a single bit - an integer 0 or 1. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/bitarray/_util.c new/bitarray-2.7.1/bitarray/_util.c --- old/bitarray-2.7.0/bitarray/_util.c 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/bitarray/_util.c 2023-02-10 16:30:12.000000000 +0100 @@ -32,7 +32,7 @@ return 0; } -/* return new bitarray of length 'nbits' (with uninitialized buffer) and +/* return new bitarray of length `nbits` (with uninitialized buffer) and endianness given by the PyObject 'endian' */ static bitarrayobject * new_bitarray(Py_ssize_t nbits, PyObject *endian) @@ -639,8 +639,8 @@ return 0; } -/* Return new reference to bytes object from either str (unicode) or bytes. - On failure, set exception and return NULL. */ +/* Return new reference to bytes object from either ASCII str (unicode) or + bytes. On failure, set exception and return NULL. */ static PyObject * anystr_to_bytes(PyObject *obj) { @@ -669,14 +669,14 @@ { static char *kwlist[] = {"", "endian", NULL}; PyObject *obj, *bytes, *endian = Py_None; - bitarrayobject *a = NULL; + bitarrayobject *a; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:hex2ba", kwlist, &obj, &endian)) return NULL; if ((bytes = anystr_to_bytes(obj)) == NULL) - goto error; + return NULL; a = new_bitarray(4 * PyBytes_GET_SIZE(bytes), endian); if (a == NULL) @@ -688,7 +688,7 @@ Py_DECREF(bytes); return (PyObject *) a; error: - Py_XDECREF(bytes); + Py_DECREF(bytes); Py_XDECREF((PyObject *) a); return NULL; } @@ -854,7 +854,7 @@ { static char *kwlist[] = {"", "", "endian", NULL}; PyObject *obj, *bytes, *endian = Py_None; - bitarrayobject *a = NULL; + bitarrayobject *a; int n, m; /* n = 2^m */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "iO|O:base2ba", kwlist, @@ -865,7 +865,7 @@ return NULL; if ((bytes = anystr_to_bytes(obj)) == NULL) - goto error; + return NULL; a = new_bitarray(m * PyBytes_GET_SIZE(bytes), endian); if (a == NULL) @@ -877,7 +877,7 @@ Py_DECREF(bytes); return (PyObject *) a; error: - Py_XDECREF(bytes); + Py_DECREF(bytes); Py_XDECREF((PyObject *) a); return NULL; } @@ -1030,28 +1030,9 @@ return n; } -/* ---------------------- sparse compressed bitarray ------------------- */ - -/* Bitarray buffer size (in bytes) that can be indexed by n bytes. E.g.: - with 1 byte you can index 256 bits which have a buffer size of 32 bytes, - so BSI(1) = 32, BSI(2) = 8192, ... */ -#define BSI(n) (((Py_ssize_t) 1) << (8 * (n) - 3)) - -static int -sc_encode_header(char *str, bitarrayobject *a) -{ - int len; - - len = byte_length(a->nbits); - *str = (IS_BE(a) ? 0x10 : 0x00) | ((char) len); - write_n(str + 1, len, a->nbits); - - return 1 + len; -} - -/* starting at byte index 'i' count the remaining bits */ +/* starting from byte i count the remaining population in bitarray buffer */ static Py_ssize_t -count_final(bitarrayobject *a, Py_ssize_t i) +count_from(bitarrayobject *a, Py_ssize_t i) { Py_ssize_t cnt = 0; @@ -1064,12 +1045,21 @@ return cnt; } -/* segment size in bytes - although of little practical value, the code +/* ---------------------- sparse compressed bitarray ------------------- + * + * see also: doc/sparse_compression.rst + */ + +/* Bitarray buffer size (in bytes) that can be indexed by n bytes. E.g.: + with 1 byte you can index 256 bits which have a buffer size of 32 bytes. + BSI(1) = 32, BSI(2) = 8_192, BSI(3) = 2_097_152, BSI(4) = 536_870_912 */ +#define BSI(n) (((Py_ssize_t) 1) << (8 * (n) - 3)) + +/* segment size in bytes - Although of little practical value, the code below will also work when changing SEGSIZE to 1, 2, 4, 8 or 16, as long as a multiple of SEGSIZE is 32. The size 32 is rooted in the fact that a bitarray of 32 bytes (256 bits) can be indexed with one index byte - (BSI(0) = 32). Our entire 'sc' format is constructed around this. - */ + (BSI(1) = 32). Our entire 'sc' format is constructed around this. */ #define SEGSIZE 32 /* number of 256 bit segments given nbits */ @@ -1079,44 +1069,44 @@ Note that we call these "segments", as opposed to "blocks", in order to avoid confusion with encode blocks. - 0 1 2 3 4 5 6 index into rts array, i - +-------+-------+-------+-------+-------+----+ - | 5 | 7 | 0 | 11 | 6 | 4 | count per segment - +-------+-------+-------+-------+-------+----+ - 0 5 12 12 23 29 33 running totals, rts[i] - - In this example we have a bitarray with 6 segments, e.g. with 1407 bits. - Note that: - - * Here we have 6 segments, but the rts array has a size - of 7 elements: 0 .. 6 - The rts array has always NSEG(nbits) + 1 elements, such that the - last element is always indexed by NSEG(nbits). Here, NSEG(1407) = 6 - - * The zeroth element rts[0] is always zero. - - * The last last element rts[NSEG(nbits)] is always the total count. - Here: rts[NSEG(nbits)] = rts[NSEG(1407)] = rts[6] = 33 - - * The last segment may be partial. Here, spanning 127 bits, that - is a[1280:1407]. The count of this segment is 4: - a[1280:].count() = a.count(1, 1280) = 4 - - * The segment a[512:768] has a count of zero, such that: rts[2] = rts[3] - - As each segment covers 256 bits (32 bytes), and each element in the - running totals array takes up 8 bytes (on a 64-bit machine at least) the - additional memory to accommodate the rts array is 1/4 of the bitarrays - memory. However, calculating this array upfront allows count_block() to + 0 1 2 3 4 index in rts array, i + +-----------+-----------+-----------+-----------+ + | 5 | 0 | 3 | 4 | segment population + | | | | | + | [0:256] | [256:512] | [512:768] | [768:987] | bitarray slice + +-----------+-----------+-----------+-----------+ + 0 5 5 8 12 running totals, rts[i] + + In this example we have a bitarray of length nbits = 987. Note that: + + * The number of segments is given by NSEG(nbits). + Here we have 4 segments: NSEG(nbits) = NSEG(987) = 4 + + * The rts array has always NSEG(nbits) + 1 elements, such that + last element is always indexed by NSEG(nbits). + + * The element rts[0] is always zero. + + * The last element rts[NSEG(nbits)] is always the total count. + Here: rts[NSEG(nbits)] = rts[NSEG(987)] = rts[4] = 12 + + * The last segment may be partial. In that case, it's size it given + by nbits % 256. Here: nbits % 256 = 987 % 256 = 219 + + As each segment (at large) covers 256 bits (32 bytes), and each element + in the running totals array takes up 8 bytes (on a 64-bit machine) the + additional memory to accommodate the rts array is therefore 1/4 of the + bitarray's memory. + However, calculating this array upfront allows sc_count() to simply look up two entries from the array and take their difference. - Thus, the speedup we get can be significant. + Thus, the speedup is significant. - The function write_sparse_block() also takes advantage of the running - totals array, as it can quickly check for segments that only contain - only zeros to skip. + The function sc_write_indices() also takes advantage of the running + totals array. It loops over segments and skips to the next segment as + soon as the count the current segment is reached. */ static Py_ssize_t * -calc_rts(bitarrayobject *a) +sc_calc_rts(bitarrayobject *a) { const Py_ssize_t n_seg = NSEG(a->nbits); /* number of segments */ const Py_ssize_t c_seg = a->nbits / (8 * SEGSIZE); /* complete segs */ @@ -1125,6 +1115,7 @@ char *buff; Py_ssize_t *res, i, j; + assert(n_seg == c_seg || n_seg == c_seg + 1); memset(zeros, 0x00, SEGSIZE); res = (Py_ssize_t *) PyMem_Malloc((size_t) sizeof(Py_ssize_t) * (n_seg + 1)); @@ -1144,11 +1135,10 @@ res[c_seg] = cnt; if (n_seg > c_seg) { /* we have a final partial segment */ - assert(n_seg == c_seg + 1); assert(Py_SIZE(a) <= SEGSIZE * n_seg); assert(a->nbits && a->nbits < 8 * SEGSIZE * n_seg); - cnt += count_final(a, SEGSIZE * c_seg); + cnt += count_from(a, SEGSIZE * c_seg); res[n_seg] = cnt; } return res; @@ -1161,7 +1151,7 @@ The offset is required to be multiple of 32 (the segment size), as this functions makes use of running totals (stored in Py_ssize_t array rts). */ static Py_ssize_t -count_block(bitarrayobject *a, Py_ssize_t *rts, Py_ssize_t offset, int n) +sc_count(bitarrayobject *a, Py_ssize_t *rts, Py_ssize_t offset, int n) { Py_ssize_t nbits; @@ -1178,8 +1168,7 @@ is 1 << 32. This is problematic, as 32-bit machines can address at least partially filled type 4 blocks). Therefore, we first limit BSI(n) by the buffer size before multiplying 8. */ - nbits = Py_MIN(8 * Py_MIN(BSI(n), Py_SIZE(a)), - a->nbits - 8 * offset); + nbits = Py_MIN(8 * Py_MIN(BSI(n), Py_SIZE(a)), a->nbits - 8 * offset); assert(nbits >= 0); offset /= SEGSIZE; /* offset in terms of segments now */ @@ -1193,10 +1182,9 @@ buffer str), and return the number of raw bytes. Note that the encoded block size is the return value + 1. */ static int -write_raw_block(char *str, bitarrayobject *a, Py_ssize_t *rts, - Py_ssize_t offset) +sc_write_raw(char *str, bitarrayobject *a, Py_ssize_t *rts, Py_ssize_t offset) { - Py_ssize_t nbytes = Py_SIZE(a) - offset; /* remaining bytes */ + const Py_ssize_t nbytes = Py_SIZE(a) - offset; /* remaining bytes */ Py_ssize_t k = Py_MIN(32, nbytes); assert(nbytes > 0); @@ -1205,8 +1193,10 @@ raw bytes (otherwise this function wouldn't have been called). Now also check the next 3 segments. */ while (k < 128 && - Py_MIN(32, nbytes - k) <= count_block(a, rts, offset + k, 1)) + Py_MIN(32, nbytes - k) <= sc_count(a, rts, offset + k, 1)) k += 32; + + assert(k % SEGSIZE == 0); } k = Py_MIN(k, nbytes); assert(0 < k && k <= 128 && k <= nbytes); @@ -1221,56 +1211,87 @@ return (int) k; } -/* Encode one sparse block (from offset, and up to k one bits). - Return number of bytes written to buffer str (encoded block size). */ +/* Write `k` indices (of `n` bytes each) into buffer `str`. + Note that `n` (which is also the block type) has been selected + (in sc_encode_block()) such that: + + k = sc_count(a, rts, offset, n) < 256 +*/ +static void +sc_write_indices(char *str, bitarrayobject *a, Py_ssize_t *rts, + Py_ssize_t offset, int n, int k) +{ + const char *str_stop = str + n * k; /* stop position in buffer `str` */ + const char *buff = a->ob_item + offset; + Py_ssize_t m, i; + + assert(1 <= n && n <= 4); + assert(0 < k && k < 256); /* note that k cannot be 0 in this function */ + assert(k == sc_count(a, rts, offset, n)); /* see above */ + assert(offset % SEGSIZE == 0); + + rts += offset / SEGSIZE; /* rts index relative to offset now */ + + for (m = 0;;) { /* loop segments */ + int j, ni; + + assert(m + offset / SEGSIZE < NSEG(a->nbits)); + ni = (int) (rts[m + 1] - rts[m]); /* indices in this segment */ + if (ni == 0) + goto next_segment; + + for (i = m * SEGSIZE;; i++) { /* loop bytes in segment */ + assert(i < (m + 1) * SEGSIZE && i + offset < Py_SIZE(a)); + if (buff[i] == 0) + continue; + + for (j = 0; j < 8; j++) /* loop bits */ + if (buff[i] & BITMASK(a, j)) { + write_n(str, n, 8 * i + j); + str += n; + if (--ni == 0) { + /* we have encountered all indices in this segment */ + if (str == str_stop) + return; + goto next_segment; + } + } + } + next_segment: + m++; + } + Py_UNREACHABLE(); +} + +#undef SEGSIZE +#undef NSEG + +/* Write one sparse block (from `offset`, and up to `k` one bits). + Return number of bytes written to buffer `str` (encoded block size). */ static Py_ssize_t -write_sparse_block(char *str, bitarrayobject *a, Py_ssize_t *rts, - Py_ssize_t offset, int n, int k) +sc_write_sparse(char *str, bitarrayobject *a, Py_ssize_t *rts, + Py_ssize_t offset, int n, int k) { - /* bytes to encode limited by remaining buffer size */ - Py_ssize_t na = Py_MIN(BSI(n), Py_SIZE(a) - offset); - Py_ssize_t i, j, outsize, len = 0; - char *buff = a->ob_item + offset; + int len = 0; - assert(offset % SEGSIZE == 0); - assert(1 <= n && n <= 4 && 0 <= k && k < 256); - assert(na > 0 && offset + na <= Py_SIZE(a)); + assert(1 <= n && n <= 4); + assert(0 <= k && k < 256); - /* block header */ + /* write block header */ if (n == 1) { /* type 1 - single byte for each position */ assert(k < 32); - str[len++] = 0xa0 + k; + str[len++] = (char) (0xa0 + k); } - else { /* type 2, 3, 4 - multiple bytes for each positions */ - str[len++] = 0xc0 + n; - str[len++] = k; + else { /* type 2, 3, 4 - `n` bytes for each positions */ + str[len++] = (char) (0xc0 + n); + str[len++] = (char) k; } if (k == 0) /* no index bytes */ return len; - /* block data */ - outsize = len + n * k; - for (i = 0; i < na; i++) { - if (i % SEGSIZE == 0) { - j = (i + offset) / SEGSIZE; /* running total index */ - assert(j < NSEG(a->nbits)); - if (rts[j] == rts[j + 1]) { /* the segment has only zeros */ - i += SEGSIZE - 1; /* skip ahead */ - continue; - } - } - assert(offset + i < Py_SIZE(a)); - if (buff[i]) - for (j = 0; j < 8; j++) - if (buff[i] & BITMASK(a, j)) { - write_n(str + len, n, 8 * i + j); - len += n; - if (len == outsize) /* final index reached */ - return len; - } - } - Py_FatalError("internal sc_encode() error"); - return -1; /* cannot happen - silence compiler warning */ + /* write block data - `k` indices, `n` bytes per index */ + sc_write_indices(str + len, a, rts, offset, n, k); + return len + n * k; } /* Encode one block (starting at offset) and return offset increment. @@ -1312,15 +1333,15 @@ sc_encode_block(char *str, Py_ssize_t *len, bitarrayobject *a, Py_ssize_t *rts, Py_ssize_t offset) { - Py_ssize_t nbytes = Py_SIZE(a) - offset; /* remaining bytes */ + const Py_ssize_t nbytes = Py_SIZE(a) - offset; /* remaining bytes */ int count, n; assert(nbytes > 0); - count = (int) count_block(a, rts, offset, 1); + count = (int) sc_count(a, rts, offset, 1); /* are there fewer or equal raw bytes than index bytes */ if (Py_MIN(32, nbytes) <= count) { /* type 0 - raw bytes */ - int k = write_raw_block(str + *len, a, rts, offset); + int k = sc_write_raw(str + *len, a, rts, offset); *len += 1 + k; return k; } @@ -1329,7 +1350,7 @@ Py_ssize_t next_count, size_a, size_b; /* population for next block type n+1 */ - next_count = count_block(a, rts, offset, n + 1); + next_count = sc_count(a, rts, offset, n + 1); if (next_count >= 256) /* too many index bytes for next block type n+1 */ break; @@ -1347,12 +1368,21 @@ count = (int) next_count; } - *len += write_sparse_block(str + *len, a, rts, offset, n, count); + *len += sc_write_sparse(str + *len, a, rts, offset, n, count); return BSI(n); } -#undef SEGSIZE -#undef NSEG +static int +sc_encode_header(char *str, bitarrayobject *a) +{ + int len; + + len = byte_length(a->nbits); + *str = (IS_BE(a) ? 0x10 : 0x00) | ((char) len); + write_n(str + 1, len, a->nbits); + + return 1 + len; +} static PyObject * sc_encode(PyObject *module, PyObject *obj) @@ -1361,14 +1391,15 @@ char *str; /* output buffer */ Py_ssize_t len = 0; /* bytes written into output buffer */ bitarrayobject *a; - Py_ssize_t offset = 0; /* block offset into bitarray a in bytes */ + Py_ssize_t offset = 0; /* block offset into bitarray `a` in bytes */ Py_ssize_t *rts; /* running totals for 256 bit segments */ if (ensure_bitarray(obj) < 0) return NULL; a = (bitarrayobject *) obj; - if ((rts = calc_rts(a)) == NULL) + set_padbits(a); + if ((rts = sc_calc_rts(a)) == NULL) return NULL; out = PyBytes_FromStringAndSize(NULL, 32768); @@ -1383,7 +1414,7 @@ /* Make sure we have enough space in output buffer for next block. The largest block possible is a type 4 block with 255 indices. - It's site is: 2 header bytes + 4 * 255 index bytes */ + It's size is: 2 header bytes + 4 * 255 index bytes */ allocated = PyBytes_GET_SIZE(out); if (allocated < len + 2 + 4 * 255) { /* increase allocation */ if (_PyBytes_Resize(&out, allocated + 32768) < 0) @@ -1440,10 +1471,10 @@ /* Read k bytes from iter and set elements in bitarray. Return the size of the offset increment in bytes (i.e. just k), or -1 on failure. */ static Py_ssize_t -read_raw_block(bitarrayobject *a, Py_ssize_t offset, PyObject *iter, int k) +sc_read_raw(bitarrayobject *a, Py_ssize_t offset, PyObject *iter, int k) { - Py_ssize_t i; char *buff = a->ob_item + offset; + Py_ssize_t i; if (offset + k > Py_SIZE(a)) { PyErr_Format(PyExc_ValueError, "decode error (raw): %zd + %d > %zd", @@ -1463,8 +1494,8 @@ /* Read n * k bytes from iter and set elements in bitarray. Return size of offset increment in bytes, or -1 on failure. */ static Py_ssize_t -read_sparse_block(bitarrayobject *a, Py_ssize_t offset, PyObject *iter, - int n, int k) +sc_read_sparse(bitarrayobject *a, Py_ssize_t offset, PyObject *iter, + int n, int k) { assert(1 <= n && n <= 4 && k >= 0); while (k--) { @@ -1499,10 +1530,10 @@ return 0; if (head <= 0x80) /* type 0 - 0x01 .. 0x80 */ - return read_raw_block(a, offset, iter, head); + return sc_read_raw(a, offset, iter, head); if (0xa0 <= head && head < 0xc0) /* type 1 - 0xa0 .. 0xbf */ - return read_sparse_block(a, offset, iter, 1, head - 0xa0); + return sc_read_sparse(a, offset, iter, 1, head - 0xa0); if (0xc2 <= head && head <= 0xc4) { /* type 2 .. 4 - 0xc2 .. 0xc4 */ int k; @@ -1510,7 +1541,7 @@ if ((k = next_char(iter)) < 0) return -1; - return read_sparse_block(a, offset, iter, head - 0xc0, k); + return sc_read_sparse(a, offset, iter, head - 0xc0, k); } PyErr_Format(PyExc_ValueError, "invalid block head: 0x%02x", head); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/bitarray/bitarray.h new/bitarray-2.7.1/bitarray/bitarray.h --- old/bitarray-2.7.0/bitarray/bitarray.h 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/bitarray/bitarray.h 2023-02-10 16:30:12.000000000 +0100 @@ -4,7 +4,7 @@ Author: Ilan Schnell */ -#define BITARRAY_VERSION "2.7.0" +#define BITARRAY_VERSION "2.7.1" #ifdef STDC_HEADERS #include <stddef.h> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/bitarray/test_bitarray.py new/bitarray-2.7.1/bitarray/test_bitarray.py --- old/bitarray-2.7.0/bitarray/test_bitarray.py 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/bitarray/test_bitarray.py 2023-02-10 16:30:12.000000000 +0100 @@ -1142,6 +1142,21 @@ a[2:5] = bitarray('0') # remove self.assertEqual(a, bitarray('11011')) + def test_setslice_frozenbitarray(self): + a = bitarray('11111111 1111') + b = frozenbitarray('0000') + a[2:6] = b + self.assertEqual(a, bitarray('11000011 1111')) + self.assertIsType(b, 'frozenbitarray') + self.assertEqual(b, bitarray('0000')) + + b = frozenbitarray('011100') + a[::2] = b + self.assertEqual(a, bitarray('01101011 0101')) + self.check_obj(a) + self.assertIsType(b, 'frozenbitarray') + self.assertEqual(b, bitarray('011100')) + def test_setslice_bitarray_random_same_length(self): for endian in 'little', 'big': for _ in range(100): @@ -2750,22 +2765,6 @@ self.assertRaises(IndexError, a.bytereverse, 5) self.assertRaises(IndexError, a.bytereverse, 0, 5) - @skipIf(sys.version_info[0] == 2) - def test_bytereverse_part(self): - a = bitarray(5, 'big') - memoryview(a)[0] = 0x13 # 0001 0011 - self.assertEqual(a, bitarray('0001 0')) - # the padbits (011) are not treated as zeros - a.bytereverse() - self.assertEqual(a, bitarray('1100 1')) - - a = bitarray(12, 'little') - memoryview(a)[1] = 0xd4 # .... .... 0010 1011 - self.assertEqual(a[8:], bitarray('0010')) - # the padbits (1011) are not treated as zeros - a.bytereverse(1) - self.assertEqual(a[8:], bitarray('1101')) - def test_bytereverse_byte(self): for i in range(256): a = bitarray() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/bitarray/test_util.py new/bitarray-2.7.1/bitarray/test_util.py --- old/bitarray-2.7.0/bitarray/test_util.py 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/bitarray/test_util.py 2023-02-10 16:30:12.000000000 +0100 @@ -948,21 +948,22 @@ self.assertEqual(ba2hex(a_be), hex_be) self.assertEqual(ba2hex(a_le), hex_le) - def test_round_trip(self): - s = ''.join(choice(hexdigits) for _ in range(randint(20, 100))) + def test_hexdigits(self): for default_endian in 'big', 'little': _set_default_endian(default_endian) - a = hex2ba(s) - self.check_obj(a) + a = hex2ba(hexdigits) self.assertEqual(len(a) % 4, 0) self.assertEqual(a.endian(), default_endian) + self.assertIsType(a, 'bitarray') + self.check_obj(a) + t = ba2hex(a) - self.assertEqual(t, s.lower()) - b = hex2ba(t, default_endian) - self.assertEQUAL(a, b) + self.assertEqual(t, hexdigits.lower()) + self.assertIsInstance(t, str) + self.assertEQUAL(a, hex2ba(t, default_endian)) def test_binascii(self): - a = urandom(800, 'big') + a = urandom(80, 'big') s = binascii.hexlify(a.tobytes()).decode() self.assertEqual(ba2hex(a), s) b = bitarray(endian='big') @@ -1145,8 +1146,7 @@ (b'\x11\x09\xa1\x08\0', '00000000 1', 'big'), (b'\x01E\xa3ABD\0', 65 * '0' + '1101', 'little'), ]: - # the padbits in a frozenbitarray are guaranteed to be zero - a = frozenbitarray(bits, endian) + a = bitarray(bits, endian) self.assertEqual(sc_encode(a), b) self.assertEqual(sc_decode(b), a) @@ -1345,16 +1345,16 @@ for a in bitarray('1', 'big'), frozenbitarray('1', 'big'): b = sc_encode(a) self.assertIsInstance(b, bytes) - self.assertEqual(len(b), 5) + self.assertEqual(b, b'\x11\x01\x01\x80\0') for a in None, [], 0, 123, b'', b'\x00', 3.14: self.assertRaises(TypeError, sc_encode, a) def round_trip(self, a): - b = sc_encode(a) - c = sc_decode(b) - self.assertEqual(a, c) - self.assertEqual(a.endian(), c.endian()) + c = a.copy() + b = sc_decode(sc_encode(a)) + self.assertTrue(a == b == c) + self.assertTrue(a.endian() == b.endian() == c.endian()) def test_encode_zeros(self): for i in range(18): @@ -1523,10 +1523,10 @@ self.assertEqual(vl_decode(s), a) def round_trip(self, a): + c = a.copy() s = vl_encode(a) b = vl_decode(s) - self.check_obj(b) - self.assertEqual(a, b) + self.assertTrue(a == b == c) LEN_PAD_BITS = 3 self.assertEqual(len(s), (len(a) + LEN_PAD_BITS + 6) // 7) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/doc/changelog.rst new/bitarray-2.7.1/doc/changelog.rst --- old/bitarray-2.7.0/doc/changelog.rst 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/doc/changelog.rst 2023-02-10 16:30:12.000000000 +0100 @@ -1,6 +1,11 @@ Change log ========== +**2.7.1** (2023-02-10): + +* optimize ``util.sc_encode()`` + + **2.7.0** (2023-02-05): * add ``util.sc_encode()`` and ``util.sc_decode()`` for diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/doc/reference.rst new/bitarray-2.7.1/doc/reference.rst --- old/bitarray-2.7.0/doc/reference.rst 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/doc/reference.rst 2023-02-10 16:30:12.000000000 +0100 @@ -1,7 +1,7 @@ Reference ========= -bitarray version: 2.7.0 -- `change log <https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__ +bitarray version: 2.7.1 -- `change log <https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__ In the following, ``item`` and ``value`` are usually a single bit - an integer 0 or 1. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitarray-2.7.0/doc/sparse_compression.rst new/bitarray-2.7.1/doc/sparse_compression.rst --- old/bitarray-2.7.0/doc/sparse_compression.rst 2023-02-05 17:58:14.000000000 +0100 +++ new/bitarray-2.7.1/doc/sparse_compression.rst 2023-02-10 16:30:12.000000000 +0100 @@ -48,7 +48,7 @@ compress (ms) decompress (ms) ratio ---------------------------------------------------------- serialize 4.562 1.188 1.0000 - sc 7.864 2.680 0.0158 + sc 6.069 2.680 0.0158 gzip 920.343 16.161 0.0169 bz2 59.580 33.435 0.0117