Skip to content

Commit 0fd042e

Browse files
committed
Add lshift() and rshift().
Based on https://bitbucket.org/quiark/bitarray.
1 parent 214cf07 commit 0fd042e

1 file changed

Lines changed: 156 additions & 2 deletions

File tree

bitarray/_bitarray.c

Lines changed: 156 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ static PyTypeObject Bitarraytype;
9494
#define GETBIT(self, i) \
9595
((self)->ob_item[(i) / 8] & BITMASK((self)->endian, i) ? 1 : 0)
9696

97+
#define ckb(i) assert(!(((i) < 0) || ((i) >= Py_SIZE(res))))
98+
9799
static void
98100
setbit(bitarrayobject *self, idx_t i, int bit)
99101
{
@@ -270,8 +272,10 @@ delete_n(bitarrayobject *self, idx_t start, idx_t n)
270272
assert(0 <= n && n <= self->nbits - start);
271273
if (n == 0)
272274
return 0;
273-
274-
copy_n(self, start, self, start + n, self->nbits - start - n);
275+
if (start != self->nbits + 1) {
276+
/* default pop() wihtout index, in that case no copying is needed */
277+
copy_n(self, start, self, start + n, self->nbits - start - n);
278+
}
275279
return resize(self, self->nbits - n);
276280
}
277281

@@ -371,6 +375,7 @@ bitwise(bitarrayobject *self, PyObject *arg, enum op_type oper)
371375
return 0;
372376
}
373377

378+
374379
/* set the bits from start to stop (excluding) in self to val */
375380
static void
376381
setrange(bitarrayobject *self, idx_t start, idx_t stop, int val)
@@ -1780,6 +1785,7 @@ bitarray_pop(bitarrayobject *self, PyObject *args)
17801785
return NULL;
17811786
}
17821787
vi = GETBIT(self, i);
1788+
17831789
if (delete_n(self, i, 1) < 0)
17841790
return NULL;
17851791
return PyBool_FromLong(vi);
@@ -2376,6 +2382,150 @@ searchiter_dealloc(searchiterobject *it)
23762382
PyObject_GC_Del(it);
23772383
}
23782384

2385+
static PyObject *
2386+
bitarray_lshift(bitarrayobject *self, PyObject *other)
2387+
{
2388+
if (self->endian != 1) {
2389+
PyErr_SetString(PyExc_ValueError, "Only implemented for bigendian.");
2390+
return NULL;
2391+
}
2392+
2393+
if (!IS_INDEX(other)) {
2394+
PyErr_SetString(PyExc_TypeError, "integer argument to lshift expected");
2395+
return NULL;
2396+
}
2397+
idx_t count = 0;
2398+
getIndex(other, &count);
2399+
2400+
bitarrayobject *res = (bitarrayobject *)bitarray_copy(self);
2401+
2402+
Py_ssize_t i;
2403+
2404+
/* too much */
2405+
if (count > res->nbits) {
2406+
memset(res->ob_item, 0, Py_SIZE(res));
2407+
2408+
} else if (count > 0) {
2409+
Py_ssize_t bytes = count / 8;
2410+
2411+
/* move bytes around first */
2412+
if (bytes > 0) {
2413+
for (i = 0; (i + bytes) < Py_SIZE(res); i++) {
2414+
ckb(i);
2415+
ckb(i + bytes);
2416+
res->ob_item[i] = res->ob_item[i + bytes];
2417+
}
2418+
2419+
/* clear bytes on the right */
2420+
for (i = 0; i < bytes; i++) {
2421+
ckb(Py_SIZE(res) - 1 - i);
2422+
res->ob_item[Py_SIZE(res) - 1 - i] = 0;
2423+
}
2424+
2425+
}
2426+
2427+
/* perform shift smaller than 8 */
2428+
idx_t small_shift = count % 8;
2429+
if (small_shift > 0) {
2430+
for (i = 0; i < Py_SIZE(res) - bytes; i++) {
2431+
ckb(i);
2432+
res->ob_item[i] <<= small_shift;
2433+
2434+
if ((i + 1) < Py_SIZE(res)) {
2435+
ckb(i);
2436+
ckb(i + 1);
2437+
res->ob_item[i] |= (unsigned char)((unsigned char)(res->ob_item[i + 1]) >> (8 - small_shift));
2438+
}
2439+
}
2440+
}
2441+
2442+
/* clear right edge */
2443+
idx_t border_bit = (res->nbits - count) % 8;
2444+
idx_t border_byte = (res->nbits - count) / 8;
2445+
ckb(border_byte);
2446+
res->ob_item[border_byte] &= (unsigned char)(0xff << (8 - border_bit));
2447+
if (border_byte + 1 < Py_SIZE(res)) {
2448+
ckb(border_byte + 1);
2449+
res->ob_item[border_byte + 1] = 0;
2450+
}
2451+
2452+
}
2453+
return (PyObject *)res;
2454+
}
2455+
PyDoc_STRVAR(lshift_doc,
2456+
"lshift([i]) -> item\n\
2457+
\n\
2458+
Shifts all bits i positions to the left and returns a new bitarray.\n\
2459+
It works only on bigendian machines.");
2460+
2461+
2462+
static PyObject *
2463+
bitarray_rshift(bitarrayobject *self, PyObject *other)
2464+
{
2465+
if (self->endian != 1) {
2466+
PyErr_SetString(PyExc_ValueError, "Only implemented for bigendian.");
2467+
return NULL;
2468+
}
2469+
if (!IS_INDEX(other)) {
2470+
PyErr_SetString(PyExc_TypeError, "integer argument to rshift expected");
2471+
return NULL;
2472+
}
2473+
idx_t count = 0;
2474+
getIndex(other, &count);
2475+
2476+
bitarrayobject *res = (bitarrayobject *)bitarray_copy(self);
2477+
2478+
idx_t i;
2479+
2480+
/* too much */
2481+
if (count > res->nbits) {
2482+
memset(res->ob_item, 0, Py_SIZE(res));
2483+
2484+
} else if (count > 0) {
2485+
idx_t bytes = count / 8;
2486+
2487+
/* move bytes around first */
2488+
if (bytes > 0) {
2489+
for (i = Py_SIZE(res) - 1; i >= bytes; i--) {
2490+
ckb(i);
2491+
ckb(i - bytes);
2492+
res->ob_item[i] = res->ob_item[i - bytes];
2493+
}
2494+
2495+
/* clear bytes on the right */
2496+
for (i = 0; i < bytes; i++) {
2497+
ckb(i);
2498+
res->ob_item[i] = 0;
2499+
}
2500+
2501+
}
2502+
2503+
/* perform shift smaller than 8 */
2504+
idx_t small_shift = count % 8;
2505+
if (small_shift > 0) {
2506+
for (i = Py_SIZE(res) - 1; i >= bytes; i--) {
2507+
ckb(i);
2508+
res->ob_item[i] = ((unsigned char)res->ob_item[i]) >> small_shift;
2509+
2510+
if (i >= 1) {
2511+
ckb(i - 1);
2512+
unsigned char from_left = ((unsigned char)(res->ob_item[i - 1]) << (8 - small_shift));
2513+
ckb(i);
2514+
res->ob_item[i] |= from_left;
2515+
}
2516+
}
2517+
}
2518+
}
2519+
2520+
return (PyObject*)res;
2521+
}
2522+
PyDoc_STRVAR(rshift_doc,
2523+
"rshift([i]) -> item\n\
2524+
\n\
2525+
Shifts all bits i positions to the right and returns a new bitarray.\n\
2526+
It works only on bigendian machines.");
2527+
2528+
23792529
static int
23802530
searchiter_traverse(searchiterobject *it, visitproc visit, void *arg)
23812531
{
@@ -2466,6 +2616,10 @@ bitarray_methods[] = {
24662616
pack_doc},
24672617
{"pop", (PyCFunction) bitarray_pop, METH_VARARGS,
24682618
pop_doc},
2619+
{"lshift", (PyCFunction) bitarray_lshift, METH_O,
2620+
lshift_doc},
2621+
{"rshift", (PyCFunction) bitarray_rshift, METH_O,
2622+
rshift_doc},
24692623
{"remove", (PyCFunction) bitarray_remove, METH_O,
24702624
remove_doc},
24712625
{"reverse", (PyCFunction) bitarray_reverse, METH_NOARGS,

0 commit comments

Comments
 (0)