Skip to content

Commit

Permalink
Merge pull request #171 from ilanschnell/copy_n1
Browse files Browse the repository at this point in the history
avoid loops in copy_n
  • Loading branch information
ilanschnell authored Mar 20, 2022
2 parents ac4f11a + 14655cf commit 84f0a33
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 31 deletions.
29 changes: 15 additions & 14 deletions bitarray/_bitarray.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ shift_r8(bitarrayobject *self, Py_ssize_t a, Py_ssize_t b, int n, int bebr)

/* as the big-endian representation has reversed bit order in each
byte, we reverse each byte, and (re-) reverse again below */
if (bebr && self->endian == ENDIAN_BIG)
if (bebr && IS_BE(self))
bytereverse(self, a, b);
#define ucb ((unsigned char *) (self)->ob_item)

Expand Down Expand Up @@ -262,7 +262,7 @@ shift_r8(bitarrayobject *self, Py_ssize_t a, Py_ssize_t b, int n, int bebr)
}
}
#undef ucb
if (bebr && self->endian == ENDIAN_BIG) /* (re-) reverse bytes */
if (bebr && IS_BE(self)) /* (re-) reverse bytes */
bytereverse(self, a, b);
}

Expand Down Expand Up @@ -309,13 +309,15 @@ copy_n(bitarrayobject *self, Py_ssize_t a,
const Py_ssize_t p2 = (a + n - 1) / 8;
const Py_ssize_t p3 = b / 8;
int sa = a % 8;
int sb = 8 - b % 8;
int sb = -(b % 8);
char t1, t2, t3;
char m1 = ones_table[IS_BE(self)][sa];
char m2 = ones_table[IS_BE(self)][(a + n) % 8];
Py_ssize_t i;

assert(n >= 8);
assert(b + sb == 8 * (p3 + 1)); /* useful equations */
assert(a - sa == 8 * p1);
assert(a - sa == 8 * p1); /* useful equations */
assert(b + sb == 8 * p3);
assert(a + n > 8 * p2);

assert_byte_in_range(self, p1);
Expand All @@ -325,18 +327,17 @@ copy_n(bitarrayobject *self, Py_ssize_t a,
t2 = self->ob_item[p2];
t3 = other->ob_item[p3];

if (sa + sb >= 8)
sb -= 8;
if (sa + sb < 0)
sb += 8;
copy_n(self, 8 * p1, other, b + sb, n - sb); /* aligned copy */
shift_r8(self, p1, p2 + 1, sa + sb, 1); /* right shift */

for (i = 8 * p1; i < a; i++) /* restore bits at p1 */
setbit(self, i, t1 & BITMASK(self, i));
if (sa) /* restore bits at p1 */
self->ob_item[p1] = (self->ob_item[p1] & ~m1) | (t1 & m1);

if (sa + sb != 0 && m2) /* if shifted, restore bits at p2 */
self->ob_item[p2] = (self->ob_item[p2] & m2) | (t2 & ~m2);

if (sa + sb != 0) { /* if shifted, restore bits at p2 */
for (i = a + n; i < 8 * p2 + 8 && i < self->nbits; i++)
setbit(self, i, t2 & BITMASK(self, i));
}
for (i = 0; i < sb; i++) /* copy first bits missed by copy_n() */
setbit(self, i + a, t3 & BITMASK(other, i + b));
}
Expand Down Expand Up @@ -2069,7 +2070,7 @@ setslice_bool(bitarrayobject *self, PyObject *slice, PyObject *value)
setrange(self, start, stop, vi);
}
else {
const char *table = bitmask_table[self->endian == ENDIAN_BIG];
const char *table = bitmask_table[IS_BE(self)];
Py_ssize_t i;

assert(step > 1);
Expand Down
3 changes: 0 additions & 3 deletions bitarray/_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
#include "pythoncapi_compat.h"
#include "bitarray.h"

#define IS_LE(a) ((a)->endian == ENDIAN_LITTLE)
#define IS_BE(a) ((a)->endian == ENDIAN_BIG)

/* set using the Python module function _set_bato() */
static PyObject *bitarray_type_obj = NULL;

Expand Down
25 changes: 15 additions & 10 deletions bitarray/bitarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ typedef struct {
#define ENDIAN_LITTLE 0
#define ENDIAN_BIG 1

#define IS_LE(self) ((self)->endian == ENDIAN_LITTLE)
#define IS_BE(self) ((self)->endian == ENDIAN_BIG)

/* the endianness string */
#define ENDIAN_STR(endian) ((endian) == ENDIAN_LITTLE ? "little" : "big")

Expand Down Expand Up @@ -102,21 +105,28 @@ setbit(bitarrayobject *self, Py_ssize_t i, int vi)
*cp &= ~mask;
}

static const char bitmask_table[2][8] = {
{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* little endian */
{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* big endian */
};

/* character with n leading ones is: ones_table[endian][n] */
static const char ones_table[2][8] = {
{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f}, /* little endian */
{0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe}, /* big endian */
};

/* Return the (padded with zeros) last byte of the buffer. When called with
a bitarray whose number of bits is a multiple of 8, return a NUL byte. */
static inline char
zeroed_last_byte(bitarrayobject *self)
{
static const char mask_table[2][8] = {
{0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f}, /* little endian */
{0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe}, /* big endian */
};
const int r = self->nbits % 8; /* index into mask table */

assert_nbits(self);
if (r == 0)
return 0x00;
return mask_table[self->endian == ENDIAN_BIG][r] &
return ones_table[self->endian == ENDIAN_BIG][r] &
self->ob_item[Py_SIZE(self) - 1];
}

Expand All @@ -134,11 +144,6 @@ setunused(bitarrayobject *self)
return 8 - r;
}

static const char bitmask_table[2][8] = {
{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* little endian */
{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* big endian */
};

static const unsigned char bitcount_lookup[256] = {
#define B2(n) n, n + 1, n + 1, n + 2
#define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2)
Expand Down
8 changes: 4 additions & 4 deletions examples/copy_n.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ def copy_n(self, a, other, b, n):
p2 = (a + n - 1) // 8
p3 = b // 8
sa = a % 8
sb = 8 - b % 8
sb = -(b % 8)

assert n >= 8
assert b + sb == 8 * (p3 + 1)
assert a - sa == 8 * p1
assert b + sb == 8 * p3
assert a + n >= 8 * p2

if verbose:
Expand All @@ -92,8 +92,8 @@ def copy_n(self, a, other, b, n):
t2 = self[8 * p2: 8 * p2 + 8]
t3 = other[8 * p3: 8 * p3 + 8]

if sa + sb >= 8:
sb -= 8
if sa + sb < 0:
sb += 8
if verbose:
print(' -> sb =', sb)

Expand Down

0 comments on commit 84f0a33

Please sign in to comment.