summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2022-12-09 07:57:36 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2022-12-09 07:57:52 (GMT)
commitc27f884ec1d18d9cff0d19d6ba8de1dd54d991c4 (patch)
tree6549b81a21142c6e5ace2ba12039d45b6cd12084
parent6dea5e4fed979cb57f3dbc0c9144f1ff1854b800 (diff)
Allow OR operations in bit fields at a given position.
-rw-r--r--plugins/pychrysalide/common/bits.c92
-rw-r--r--src/common/bits.c138
-rw-r--r--src/common/bits.h6
-rw-r--r--tests/common/bitfield.py37
4 files changed, 272 insertions, 1 deletions
diff --git a/plugins/pychrysalide/common/bits.c b/plugins/pychrysalide/common/bits.c
index e73ce7a..9275996 100644
--- a/plugins/pychrysalide/common/bits.c
+++ b/plugins/pychrysalide/common/bits.c
@@ -65,6 +65,9 @@ static PyObject *py_bitfield_richcompare(PyObject *, PyObject *, int);
/* Crée une copie d'un champ de bits classique. */
static PyObject *py_bitfield_dup(PyObject *, PyObject *);
+/* Redimensionne un champ de bits. */
+static PyObject *py_bitfield_resize(PyObject *, PyObject *);
+
/* Bascule à 0 un champ de bits dans son intégralité. */
static PyObject *py_bitfield_reset_all(PyObject *, PyObject *);
@@ -77,6 +80,9 @@ static PyObject *py_bitfield_reset(PyObject *, PyObject *);
/* Bascule à 1 une partie d'un champ de bits. */
static PyObject *py_bitfield_set(PyObject *, PyObject *);
+/* Réalise une opération OU logique entre deux champs de bits. */
+static PyObject *py_bitfield_or_at(PyObject *, PyObject *);
+
/* Détermine si un bit est à 1 dans un champ de bits. */
static PyObject *py_bitfield_test(PyObject *, PyObject *);
@@ -405,6 +411,47 @@ static PyObject *py_bitfield_dup(PyObject *self, PyObject *args)
/******************************************************************************
* *
+* Paramètres : self = champ de bits à dupliquer. *
+* args = non utilisé ici. *
+* *
+* Description : Redimensionne un champ de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bitfield_resize(PyObject *self, PyObject *args)
+{
+ unsigned long length; /* Nouvelle taille à respecter */
+ int ret; /* Bilan de lecture des args. */
+ py_bitfield_t *bf; /* Instance à manipuler */
+
+#define BITFIELD_RESIZE_METHOD PYTHON_METHOD_DEF \
+( \
+ resize, "$self, length, /", \
+ METH_VARARGS, py_bitfield, \
+ "Resize a bitfield and fix its new size to *length*.\n" \
+ "\n" \
+ "The new bits get initialized to the same state used at the" \
+ " bitfield creation." \
+)
+
+ ret = PyArg_ParseTuple(args, "k", &length);
+ if (!ret) return NULL;
+
+ bf = (py_bitfield_t *)self;
+
+ resize_bit_field(&bf->native, length);
+
+ Py_RETURN_NONE;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : self = champ de bits à modifier. *
* args = non utilisé ici. *
* *
@@ -558,6 +605,49 @@ static PyObject *py_bitfield_set(PyObject *self, PyObject *args)
* Paramètres : self = champ de bits à consulter. *
* args = arguments fournis pour la conduite de l'opération. *
* *
+* Description : Réalise une opération OU logique entre deux champs de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_bitfield_or_at(PyObject *self, PyObject *args)
+{
+ bitfield_t *src; /* Seconde champ de bits */
+ unsigned long first; /* Indice du premier bit testé */
+ int ret; /* Bilan de lecture des args. */
+ py_bitfield_t *bf; /* Instance à manipuler */
+
+#define BITFIELD_OR_AT_METHOD PYTHON_METHOD_DEF \
+( \
+ or_at, "$self, src, first, /", \
+ METH_VARARGS, py_bitfield, \
+ "Perform an OR operation with another bitfield.\n" \
+ "\n" \
+ "The *src* argument is expected to be another" \
+ " pychrysalide.common.BitField instance. The area to" \
+ " process starts at bit *first* from *src*." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&k", convert_to_bitfield, &src, &first);
+ if (!ret) return NULL;
+
+ bf = (py_bitfield_t *)self;
+
+ or_bit_field_at(bf->native, src, first);
+
+ Py_RETURN_NONE;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = champ de bits à consulter. *
+* args = arguments fournis pour la conduite de l'opération. *
+* *
* Description : Détermine si un bit est à 1 dans un champ de bits. *
* *
* Retour : true si le bit correspondant est à l'état haut. *
@@ -897,10 +987,12 @@ PyTypeObject *get_python_bitfield_type(void)
static PyMethodDef py_bitfield_methods[] = {
BITFIELD_DUP_METHOD,
+ BITFIELD_RESIZE_METHOD,
BITFIELD_RESET_ALL_METHOD,
BITFIELD_SET_ALL_METHOD,
BITFIELD_RESET_METHOD,
BITFIELD_SET_METHOD,
+ BITFIELD_OR_AT_METHOD,
BITFIELD_TEST_METHOD,
BITFIELD_TEST_NONE_METHOD,
BITFIELD_TEST_ALL_METHOD,
diff --git a/src/common/bits.c b/src/common/bits.c
index d3b45bb..590c318 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -40,6 +40,8 @@ struct _bitfield_t
size_t length; /* Nombre de bits représentés */
size_t requested; /* Nombre de mots alloués */
+ bool default_state; /* Etat d'initialisation */
+
unsigned long bits[0]; /* Mémoire d'accès associée */
};
@@ -108,6 +110,8 @@ bitfield_t *create_bit_field(size_t length, bool state)
result = _create_bit_field(length);
+ result->default_state = state;
+
if (state)
set_all_in_bit_field(result);
else
@@ -186,6 +190,83 @@ void copy_bit_field(bitfield_t *dest, const bitfield_t *src)
/******************************************************************************
* *
+* Paramètres : field = champ de bits à modifier. [OUT] *
+* length = nouveau nombre de bits du champ à représenter. *
+* *
+* Description : Redimensionne un champ de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void resize_bit_field(bitfield_t **field, size_t length)
+{
+ bitfield_t *_field; /* Commodité d'accès */
+ size_t requested; /* Nombre de mots à allouer */
+ size_t base; /* Allocation de base en octets*/
+ size_t remaining; /* Nombre de derniers bits */
+ size_t last; /* Dernier mot utilisé */
+ unsigned long mask; /* Masque d'initialisation */
+ size_t i; /* Boucle de parcours */
+
+ _field = *field;
+
+ if (_field->length != length)
+ {
+ /* Redimensionnement */
+
+ requested = length / (sizeof(unsigned long) * 8);
+ if (length % (sizeof(unsigned long) * 8) != 0) requested++;
+
+ base = sizeof(bitfield_t) + requested * sizeof(unsigned long);
+
+ *field = realloc(_field, base);
+ _field = *field;
+
+ /* Initialisation, si nécessaire */
+
+ if (_field->length < length)
+ {
+ last = _field->length / (sizeof(unsigned long) * 8);
+ remaining = _field->length % (sizeof(unsigned long) * 8);
+
+ if (remaining != 0)
+ {
+ mask = (1ul << remaining) - 1;
+
+ if (_field->default_state)
+ _field->bits[last] |= ~mask;
+ else
+ _field->bits[last] &= mask;
+
+ last++;
+
+ }
+
+ for (i = last; i < requested; i++)
+ {
+ if (_field->default_state)
+ _field->bits[i] = ~0ul;
+ else
+ _field->bits[i] = 0ul;
+ }
+
+ }
+
+ /* Actualisation des tailles */
+
+ _field->length = length;
+ _field->requested = requested;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : field = champ de bits à consulter. *
* *
* Description : Indique la taille d'un champ de bits donné. *
@@ -435,6 +516,61 @@ void or_bit_field(bitfield_t *dest, const bitfield_t *src)
/******************************************************************************
* *
+* Paramètres : dest = champ de bits à modifier. *
+* src = champ de bits à utiliser pour l'opération. *
+* first = point de départ pour l'opération à réaliser. *
+* *
+* Description : Réalise une opération OU logique entre deux champs de bits. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void or_bit_field_at(bitfield_t *dest, const bitfield_t *src, size_t first)
+{
+ size_t start; /* Mot de départ dans le champ */
+ size_t offset; /* Décalage des mots à basculer*/
+ size_t remaining; /* Taille du dernier tronçon */
+ unsigned long finalcut; /* Limitation du mot final */
+ size_t i; /* Boucle de parcours */
+ unsigned long word; /* Mot reconstituté à tester */
+
+ assert(dest->length <= (first + src->length));
+
+ start = first / (sizeof(unsigned long) * 8);
+ offset = first % (sizeof(unsigned long) * 8);
+
+ remaining = (first + src->length) % (sizeof(unsigned long) * 8);
+
+ if (remaining == 0)
+ finalcut = ~0ul;
+ else
+ finalcut = (1ul << remaining) - 1;
+
+ for (i = 0; i < (src->requested + 1); i++)
+ {
+ if (i < src->requested)
+ word = src->bits[i] << offset;
+ else
+ word = 0;
+
+ if (i > 0)
+ word |= src->bits[i - 1] >> (sizeof(unsigned long) * 8 - offset);
+
+ if (i == src->requested)
+ word &= finalcut;
+
+ dest->bits[start + i] |= word;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : field = champ de bits à consulter. *
* n = indice du bit à traiter. *
* *
@@ -610,7 +746,7 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c
{
word = field->bits[windex] >> offset;
if ((windex + 1) < field->requested)
- word |= field->bits[start + i + 1] << (sizeof(unsigned long) * 8 - offset);
+ word |= field->bits[windex + 1] << (sizeof(unsigned long) * 8 - offset);
}
bitmask = mask->bits[i];
diff --git a/src/common/bits.h b/src/common/bits.h
index fb231d5..58fa0fe 100644
--- a/src/common/bits.h
+++ b/src/common/bits.h
@@ -45,6 +45,9 @@ void delete_bit_field(bitfield_t *);
/* Copie un champ de bits dans un autre. */
void copy_bit_field(bitfield_t *, const bitfield_t *);
+/* Redimensionne un champ de bits. */
+void resize_bit_field(bitfield_t **, size_t);
+
/* Indique la taille d'un champ de bits donné. */
size_t get_bit_field_size(const bitfield_t *);
@@ -69,6 +72,9 @@ void and_bit_field(bitfield_t *, const bitfield_t *);
/* Réalise une opération OU logique entre deux champs de bits. */
void or_bit_field(bitfield_t *, const bitfield_t *);
+/* Réalise une opération OU logique entre deux champs de bits. */
+void or_bit_field_at(bitfield_t *, const bitfield_t *, size_t);
+
/* Détermine si un bit est à 1 dans un champ de bits. */
bool test_in_bit_field(const bitfield_t *, size_t);
diff --git a/tests/common/bitfield.py b/tests/common/bitfield.py
index 7359a8a..8c4a470 100644
--- a/tests/common/bitfield.py
+++ b/tests/common/bitfield.py
@@ -19,6 +19,23 @@ class TestBitFields(ChrysalideTestCase):
self.assertEqual(bf.popcount, bf2.popcount)
+ def testResizeBitField(self):
+ """Resize bitfields."""
+
+ bf_a = BitField(10, 0)
+
+ bf_b = BitField(6, 0)
+ bf_b.resize(10)
+
+ self.assertEqual(bf_a, bf_b)
+
+ bf_a = BitField(133, 1)
+
+ bf_b = BitField(64, 1)
+ bf_b.resize(133)
+
+ self.assertEqual(bf_a, bf_b)
+
def testBitFieldValues(self):
"""Evaluate bitfields basic values."""
@@ -70,6 +87,26 @@ class TestBitFields(ChrysalideTestCase):
self.assertEqual(bf_f.popcount, bf_a.popcount)
+ def testBitFieldLogicalOperationsAt(self):
+ """Perform logical operations on bitfields at a given position."""
+
+ bf_a = BitField(75, 0)
+
+ bf_b = BitField(4, 1)
+ bf_b.reset(2, 1)
+
+ bf_a.or_at(bf_b, 63)
+
+ self.assertFalse(bf_a.test(62))
+
+ self.assertTrue(bf_a.test(63))
+ self.assertTrue(bf_a.test(64))
+ self.assertFalse(bf_a.test(65))
+ self.assertTrue(bf_a.test(66))
+
+ self.assertFalse(bf_a.test(67))
+
+
def testBitFieldSwitch(self):
"""Switch various bits in bitfields."""