From 90184484440afd7bc4b85587f450c1b9ccd6e8de Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 30 Jun 2020 23:55:41 +0200
Subject: Updated the Python API for bitfields.

---
 plugins/pychrysalide/common/bits.c   | 238 ++++++++++++++++++++++-------------
 plugins/pychrysalide/common/bits.h   |   4 +-
 plugins/pychrysalide/common/packed.c |   4 +-
 tests/common/bitfield.py             |  60 ++++-----
 4 files changed, 180 insertions(+), 126 deletions(-)

diff --git a/plugins/pychrysalide/common/bits.c b/plugins/pychrysalide/common/bits.c
index 236bcd6..73fd55b 100644
--- a/plugins/pychrysalide/common/bits.c
+++ b/plugins/pychrysalide/common/bits.c
@@ -47,9 +47,6 @@ static void py_bitfield_dealloc(py_bitfield_t *);
 /* Initialise un objet Python de type 'bitfield_t'. */
 static int py_bitfield_init(py_bitfield_t *, PyObject *, PyObject *);
 
-/* Crée une copie d'un champ de bits classique. */
-static PyObject *py_bitfield_dup(PyObject *, PyObject *);
-
 /* Effectue une opération de type 'and' avec le type 'bitfield'. */
 static PyObject *py_bitfield_nb_and(PyObject *, PyObject *);
 
@@ -65,6 +62,9 @@ static PyObject *py_bitfield_sequence_item(PyObject *, Py_ssize_t);
 /* Effectue une comparaison avec un objet Python 'bitfield'. */
 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 *);
+
 /* Bascule à 0 un champ de bits dans son intégralité. */
 static PyObject *py_bitfield_reset_all(PyObject *, PyObject *);
 
@@ -90,7 +90,7 @@ static PyObject *py_bitfield_test_all(PyObject *, PyObject *);
 static PyObject *py_bitfield_get_size(PyObject *, void *);
 
 /* Détermine le nombre de bits à 1 dans un champ. */
-static PyObject *py_bitfield_popcount(PyObject *, void *);
+static PyObject *py_bitfield_get_popcount(PyObject *, void *);
 
 
 
@@ -136,6 +136,17 @@ static int py_bitfield_init(py_bitfield_t *self, PyObject *args, PyObject *kwds)
     int state;                              /* Initialisation par défaut   */
     int ret;                                /* Bilan de lecture des args.  */
 
+#define BITFIELD_DOC                                                \
+    "The BitField object describes a group of bits and provides"    \
+    " operations on it.\n"                                          \
+    "\n"                                                            \
+    "Instances can be created using the following constructor:\n"   \
+    "\n"                                                            \
+    "    BitField(length, state)"                                   \
+    "\n"                                                            \
+    "Where *length* is the size of the bitfield and *state*"        \
+    " defines the initial state of each bits."                      \
+
     result = -1;
 
     ret = PyArg_ParseTuple(args, "kp", &length, &state);
@@ -154,33 +165,6 @@ static int py_bitfield_init(py_bitfield_t *self, PyObject *args, PyObject *kwds)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = champ de bits à dupliquer.                            *
-*                args = non utilisé ici.                                      *
-*                                                                             *
-*  Description : Crée une copie d'un champ de bits classique.                 *
-*                                                                             *
-*  Retour      : Champ de bits mis en place.                                  *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static PyObject *py_bitfield_dup(PyObject *self, PyObject *args)
-{
-    PyObject *result;                       /* Instance à retourner        */
-    py_bitfield_t *bf;                      /* Instance à manipuler        */
-
-    bf = (py_bitfield_t *)self;
-
-    result = build_from_internal_bitfield(bf->native);;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : o1 = premier élément concerné par l'opération.               *
 *                o2 = second élément concerné par l'opération.                *
 *                                                                             *
@@ -378,6 +362,43 @@ static PyObject *py_bitfield_richcompare(PyObject *a, PyObject *b, int op)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : self = champ de bits à dupliquer.                            *
+*                args = non utilisé ici.                                      *
+*                                                                             *
+*  Description : Crée une copie d'un champ de bits classique.                 *
+*                                                                             *
+*  Retour      : Champ de bits mis en place.                                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_bitfield_dup(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Instance à retourner        */
+    py_bitfield_t *bf;                      /* Instance à manipuler        */
+
+#define BITFIELD_DUP_METHOD PYTHON_METHOD_DEF                           \
+(                                                                       \
+    dup, "$self, /",                                                    \
+    METH_NOARGS, py_bitfield,                                           \
+    "Duplicate a bitfield.\n"                                           \
+    "\n"                                                                \
+    "The result is a new pychrysalide.common.BitField with the same"    \
+    " content."                                                         \
+)
+
+    bf = (py_bitfield_t *)self;
+
+    result = build_from_internal_bitfield(bf->native);;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : self = champ de bits à modifier.                             *
 *                args = non utilisé ici.                                      *
 *                                                                             *
@@ -393,6 +414,13 @@ static PyObject *py_bitfield_reset_all(PyObject *self, PyObject *args)
 {
     py_bitfield_t *bf;                      /* Instance à manipuler        */
 
+#define BITFIELD_RESET_ALL_METHOD PYTHON_METHOD_DEF \
+(                                                   \
+    reset_all, "$self, /",                          \
+    METH_NOARGS, py_bitfield,                       \
+    "Switch to 0 all bits in a bitfield."           \
+)
+
     bf = (py_bitfield_t *)self;
 
     reset_all_in_bit_field(bf->native);
@@ -419,6 +447,13 @@ static PyObject *py_bitfield_set_all(PyObject *self, PyObject *args)
 {
     py_bitfield_t *bf;                      /* Instance à manipuler        */
 
+#define BITFIELD_SET_ALL_METHOD PYTHON_METHOD_DEF   \
+(                                                   \
+    set_all, "$self, /",                            \
+    METH_NOARGS, py_bitfield,                       \
+    "Switch to 1 all bits in a bitfield."           \
+)
+
     bf = (py_bitfield_t *)self;
 
     set_all_in_bit_field(bf->native);
@@ -448,6 +483,16 @@ static PyObject *py_bitfield_reset(PyObject *self, PyObject *args)
     int ret;                                /* Bilan de lecture des args.  */
     py_bitfield_t *bf;                      /* Instance à manipuler        */
 
+#define BITFIELD_RESET_METHOD PYTHON_METHOD_DEF             \
+(                                                           \
+    reset, "$self, first, count, /",                        \
+    METH_VARARGS, py_bitfield,                              \
+    "Switch to 0 a part of bits in a bitfield.\n"           \
+    "\n"                                                    \
+    "The area to process starts at bit *first* and has a"   \
+    " size of *count* bits."                                \
+)
+
     ret = PyArg_ParseTuple(args, "kk", &first, &count);
     if (!ret) return NULL;
 
@@ -480,6 +525,16 @@ static PyObject *py_bitfield_set(PyObject *self, PyObject *args)
     int ret;                                /* Bilan de lecture des args.  */
     py_bitfield_t *bf;                      /* Instance à manipuler        */
 
+#define BITFIELD_SET_METHOD PYTHON_METHOD_DEF               \
+(                                                           \
+    set, "$self, first, count, /",                          \
+    METH_VARARGS, py_bitfield,                              \
+    "Switch to 1 a part of bits in a bitfield.\n"           \
+    "\n"                                                    \
+    "The area to process starts at bit *first* and has a"   \
+    " size of *count* bits."                                \
+)
+
     ret = PyArg_ParseTuple(args, "kk", &first, &count);
     if (!ret) return NULL;
 
@@ -513,6 +568,16 @@ static PyObject *py_bitfield_test(PyObject *self, PyObject *args)
     py_bitfield_t *bf;                      /* Instance à manipuler        */
     bool status;                            /* Bilan d'analyse             */
 
+#define BITFIELD_TEST_METHOD PYTHON_METHOD_DEF              \
+(                                                           \
+    test, "$self, n, /",                                    \
+    METH_VARARGS, py_bitfield,                              \
+    "Test if a given bit is set in a bitfield.\n"           \
+    "\n"                                                    \
+    "The result is a boolean value: True if the tested"     \
+    " *n* bit is set, False otherwise."                     \
+)
+
     ret = PyArg_ParseTuple(args, "k", &n);
     if (!ret) return NULL;
 
@@ -521,7 +586,6 @@ static PyObject *py_bitfield_test(PyObject *self, PyObject *args)
     status = test_in_bit_field(bf->native, n);
 
     result = status ? Py_True : Py_False;
-
     Py_INCREF(result);
 
     return result;
@@ -551,6 +615,19 @@ static PyObject *py_bitfield_test_none(PyObject *self, PyObject *args)
     py_bitfield_t *bf;                      /* Instance à manipuler        */
     bool status;                            /* Bilan d'analyse             */
 
+#define BITFIELD_TEST_NONE_METHOD PYTHON_METHOD_DEF         \
+(                                                           \
+    test_none, "$self, first, count, /",                    \
+    METH_VARARGS, py_bitfield,                              \
+    "Test a range of bits against 0.\n"                     \
+    "\n"                                                    \
+    "The area to process starts at bit *first* and has a"   \
+    " size of *count* bits."                                \
+    "\n"                                                    \
+    "The result is a boolean value: True if all tested"     \
+    " bits are unset, False otherwise."                     \
+)
+
     ret = PyArg_ParseTuple(args, "kk", &first, &count);
     if (!ret) return NULL;
 
@@ -559,7 +636,6 @@ static PyObject *py_bitfield_test_none(PyObject *self, PyObject *args)
     status = test_none_in_bit_field(bf->native, first, count);
 
     result = status ? Py_True : Py_False;
-
     Py_INCREF(result);
 
     return result;
@@ -589,6 +665,19 @@ static PyObject *py_bitfield_test_all(PyObject *self, PyObject *args)
     py_bitfield_t *bf;                      /* Instance à manipuler        */
     bool status;                            /* Bilan d'analyse             */
 
+#define BITFIELD_TEST_ALL_METHOD PYTHON_METHOD_DEF          \
+(                                                           \
+    test_all, "$self, first, count, /",                     \
+    METH_VARARGS, py_bitfield,                              \
+    "Test a range of bits against 1.\n"                     \
+    "\n"                                                    \
+    "The area to process starts at bit *first* and has a"   \
+    " size of *count* bits."                                \
+    "\n"                                                    \
+    "The result is a boolean value: True if all tested"     \
+    " bits are set, False otherwise."                       \
+)
+
     ret = PyArg_ParseTuple(args, "kk", &first, &count);
     if (!ret) return NULL;
 
@@ -597,7 +686,6 @@ static PyObject *py_bitfield_test_all(PyObject *self, PyObject *args)
     status = test_all_in_bit_field(bf->native, first, count);
 
     result = status ? Py_True : Py_False;
-
     Py_INCREF(result);
 
     return result;
@@ -624,6 +712,12 @@ static PyObject *py_bitfield_get_size(PyObject *self, void *closure)
     py_bitfield_t *bf;                      /* Instance à manipuler        */
     size_t size;                            /* Taille du champs de bits    */
 
+#define BITFIELD_SIZE_ATTRIB PYTHON_GET_DEF_FULL    \
+(                                                   \
+    size, py_bitfield,                              \
+    "Provide the size of the bitfield."             \
+)
+
     bf = (py_bitfield_t *)self;
 
     size = get_bit_field_size(bf->native);
@@ -648,12 +742,18 @@ static PyObject *py_bitfield_get_size(PyObject *self, void *closure)
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_bitfield_popcount(PyObject *self, void *closure)
+static PyObject *py_bitfield_get_popcount(PyObject *self, void *closure)
 {
     PyObject *result;                       /* Conversion à retourner      */
     py_bitfield_t *bf;                      /* Instance à manipuler        */
     size_t count;                           /* Quantité de bits à 1        */
 
+#define BITFIELD_POPCOUNT_ATTRIB PYTHON_GET_DEF_FULL    \
+(                                                       \
+    popcount, py_bitfield,                              \
+    "Get the number of bits set to 1 in the bitfield."  \
+)
+
     bf = (py_bitfield_t *)self;
 
     count = popcount_for_bit_field(bf->native);
@@ -680,10 +780,8 @@ static PyObject *py_bitfield_popcount(PyObject *self, void *closure)
 PyTypeObject *get_python_bitfield_type(void)
 {
     static PyNumberMethods py_bitfield_nb_proto = {
-
         .nb_and = py_bitfield_nb_and,
         .nb_or  = py_bitfield_nb_or
-
     };
 
     static PySequenceMethods py_bitfield_sequence_proto = {
@@ -692,58 +790,20 @@ PyTypeObject *get_python_bitfield_type(void)
     };
 
     static PyMethodDef py_bitfield_methods[] = {
-        {
-            "dup", py_bitfield_dup,
-            METH_NOARGS,
-            "dup(self, /)\n--\n\nDuplicate a bitfield."
-        },
-        {
-            "reset_all", py_bitfield_reset_all,
-            METH_NOARGS,
-            "reset_all(self, /)\n--\n\nSwitch to 0 all bits in a bitfield."
-        },
-        {
-            "set_all", py_bitfield_set_all,
-            METH_NOARGS,
-            "set_all(self, /)\n--\n\nSwitch to 1 all bits in a bitfield."
-        },
-        {
-            "reset", py_bitfield_reset,
-            METH_VARARGS,
-            "reset(self, first, count, /)\n--\n\nSwitch to 0 a part of bits in a bitfield."
-        },
-        {
-            "set", py_bitfield_set,
-            METH_VARARGS,
-            "set(self, first, count, /)\n--\n\nSwitch to 1 a part of bits in a bitfield."
-        },
-        {
-            "test", py_bitfield_test,
-            METH_VARARGS,
-            "test(self, n, /)\n--\n\nTest if a given bit is set in a bitfield."
-        },
-        {
-            "test_none", py_bitfield_test_none,
-            METH_VARARGS,
-            "test_none(self, first, count, /)\n--\n\nTest a range of bits to 0."
-        },
-        {
-            "test_all", py_bitfield_test_all,
-            METH_VARARGS,
-            "test_all(self, first, count, /)\n--\n\nTest a range of bits to 1."
-        },
+        BITFIELD_DUP_METHOD,
+        BITFIELD_RESET_ALL_METHOD,
+        BITFIELD_SET_ALL_METHOD,
+        BITFIELD_RESET_METHOD,
+        BITFIELD_SET_METHOD,
+        BITFIELD_TEST_METHOD,
+        BITFIELD_TEST_NONE_METHOD,
+        BITFIELD_TEST_ALL_METHOD,
         { NULL }
     };
 
     static PyGetSetDef py_bitfield_getseters[] = {
-        {
-            "size", py_bitfield_get_size, NULL,
-            "Provide the size of the bitfield.", NULL
-        },
-        {
-            "popcount", py_bitfield_popcount, NULL,
-            "Get the number of bits set to 1 in the bitfield.", NULL
-        },
+        BITFIELD_SIZE_ATTRIB,
+        BITFIELD_POPCOUNT_ATTRIB,
         { NULL }
     };
 
@@ -751,7 +811,7 @@ PyTypeObject *get_python_bitfield_type(void)
 
         PyVarObject_HEAD_INIT(NULL, 0)
 
-        .tp_name        = "pychrysalide.common.bitfield",
+        .tp_name        = "pychrysalide.common.BitField",
         .tp_basicsize   = sizeof(py_bitfield_t),
 
         .tp_dealloc     = (destructor)py_bitfield_dealloc,
@@ -761,7 +821,7 @@ PyTypeObject *get_python_bitfield_type(void)
 
         .tp_flags       = Py_TPFLAGS_DEFAULT,
 
-        .tp_doc         = "Python object for bitfield_t.",
+        .tp_doc         = BITFIELD_DOC,
 
         .tp_richcompare = py_bitfield_richcompare,
 
@@ -782,7 +842,7 @@ PyTypeObject *get_python_bitfield_type(void)
 *                                                                             *
 *  Paramètres  : module = module dont la définition est à compléter.          *
 *                                                                             *
-*  Description : Prend en charge l'objet 'pychrysalide.common.bitfield'.      *
+*  Description : Prend en charge l'objet 'pychrysalide.common.BitField'.      *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -818,7 +878,7 @@ bool ensure_python_bitfield_is_registered(void)
 *                                                                             *
 *  Paramètres  : field = structure interne à copier en objet Python.          *
 *                                                                             *
-*  Description : Convertit une structure de type 'bitfield' en objet Python.  *
+*  Description : Convertit une structure de type 'bitfield_t' en objet Python.*
 *                                                                             *
 *  Retour      : Object Python résultant de la conversion opérée.             *
 *                                                                             *
diff --git a/plugins/pychrysalide/common/bits.h b/plugins/pychrysalide/common/bits.h
index 4a3b90b..6ddaaa5 100644
--- a/plugins/pychrysalide/common/bits.h
+++ b/plugins/pychrysalide/common/bits.h
@@ -37,10 +37,10 @@
 /* Fournit un accès à une définition de type à diffuser. */
 PyTypeObject *get_python_bitfield_type(void);
 
-/* Prend en charge l'objet 'pychrysalide.common.bitfield'. */
+/* Prend en charge l'objet 'pychrysalide.common.BitField'. */
 bool ensure_python_bitfield_is_registered(void);
 
-/* Convertit une structure de type 'bitfield' en objet Python. */
+/* Convertit une structure de type 'bitfield_t' en objet Python. */
 PyObject *build_from_internal_bitfield(const bitfield_t *);
 
 
diff --git a/plugins/pychrysalide/common/packed.c b/plugins/pychrysalide/common/packed.c
index c7fa296..405e241 100644
--- a/plugins/pychrysalide/common/packed.c
+++ b/plugins/pychrysalide/common/packed.c
@@ -112,8 +112,8 @@ static int py_packed_buffer_init(py_packed_buffer_t *self, PyObject *args, PyObj
     int result;                             /* Bilan à retourner           */
 
 #define PACKED_BUFFER_DOC                                               \
-    "The PackedBuffer is mainly used as helper for the storage of GLib" \
-    " objects over the network or into files.\n"                        \
+    "The PackedBuffer object is mainly used as helper for the storage"  \
+    " of GLib objects over the network or into files.\n"                \
     "\n"                                                                \
     "The same kind of features as the Python *struct* module are"       \
     " provided to store and retrieve data.\n"                           \
diff --git a/tests/common/bitfield.py b/tests/common/bitfield.py
index 717181c..e014111 100644
--- a/tests/common/bitfield.py
+++ b/tests/common/bitfield.py
@@ -1,21 +1,15 @@
-#!/usr/bin/python3-dbg
-# -*- coding: utf-8 -*-
-
-
-# Tests pour valider la manipulation des champs de bits.
-
 
 from chrysacase import ChrysalideTestCase
-from pychrysalide.common import bitfield
+from pychrysalide.common import BitField
 
 
-class TestBitfields(ChrysalideTestCase):
-    """TestCase for common.bitfield*"""
+class TestBitFields(ChrysalideTestCase):
+    """TestCase for common.BitField*"""
 
-    def testDuplicateBitfield(self):
+    def testDuplicateBitField(self):
         """Check duplicated bitfield value."""
 
-        bf = bitfield(10, 0)
+        bf = BitField(10, 0)
 
         bf2 = bf.dup()
 
@@ -26,40 +20,40 @@ class TestBitfields(ChrysalideTestCase):
         self.assertEqual(bf.popcount, bf2.popcount)
 
 
-    def testBitfieldValues(self):
+    def testBitFieldValues(self):
         """Evaluate bitfields basic values."""
 
-        bf_a = bitfield(75, 1)
+        bf_a = BitField(75, 1)
 
-        bf_b = bitfield(75, 0)
+        bf_b = BitField(75, 0)
 
         self.assertNotEqual(bf_a, bf_b)
 
-        bf_a = bitfield(75, 1)
+        bf_a = BitField(75, 1)
 
-        bf_b = bitfield(75, 0)
+        bf_b = BitField(75, 0)
         bf_b.set_all()
 
         self.assertEqual(bf_a, bf_b)
 
         self.assertEqual(bf_a.popcount, bf_b.popcount)
 
-        bf_a = bitfield(75, 1)
+        bf_a = BitField(75, 1)
         bf_a.reset_all()
 
-        bf_b = bitfield(75, 0)
+        bf_b = BitField(75, 0)
 
         self.assertEqual(bf_a, bf_b)
 
         self.assertEqual(bf_a.popcount, bf_b.popcount)
 
 
-    def testBitfieldLogicalOperations(self):
+    def testBitFieldLogicalOperations(self):
         """Perform logical operations on bitfields."""
 
-        bf_a = bitfield(75, 1)
+        bf_a = BitField(75, 1)
 
-        bf_b = bitfield(75, 0)
+        bf_b = BitField(75, 0)
 
         self.assertEqual(bf_a.size, bf_b.size)
 
@@ -76,14 +70,14 @@ class TestBitfields(ChrysalideTestCase):
         self.assertEqual(bf_f.popcount, bf_a.popcount)
 
 
-    def testBitfieldSwitch(self):
+    def testBitFieldSwitch(self):
         """Switch various bits in bitfields."""
 
-        bf_1 = bitfield(75, 1)
+        bf_1 = BitField(75, 1)
 
-        bf_0 = bitfield(75, 0)
+        bf_0 = BitField(75, 0)
 
-        bf_t = bitfield(75, 0)
+        bf_t = BitField(75, 0)
 
         for i in range(75):
             bf_t.set(i, 1)
@@ -100,10 +94,10 @@ class TestBitfields(ChrysalideTestCase):
         self.assertEqual(bf_t.popcount, bf_0.popcount)
 
 
-    def testBitfieldBits(self):
+    def testBitFieldBits(self):
         """Test bits in bitfields."""
 
-        bf = bitfield(54, 1)
+        bf = BitField(54, 1)
 
         self.assertTrue(bf.test(0))
 
@@ -113,7 +107,7 @@ class TestBitfields(ChrysalideTestCase):
 
         self.assertFalse(bf.test_none(0, 54))
 
-        bf = bitfield(54, 0)
+        bf = BitField(54, 0)
 
         self.assertFalse(bf.test(0))
 
@@ -124,23 +118,23 @@ class TestBitfields(ChrysalideTestCase):
         self.assertTrue(bf.test_none(0, 54))
 
 
-    def testPopCountForBitfield(self):
+    def testPopCountForBitField(self):
         """Count bits set to 1 in bitfield."""
 
-        bf = bitfield(65, 1)
+        bf = BitField(65, 1)
 
         self.assertEqual(bf.size, 65)
 
         self.assertEqual(bf.popcount, 65)
 
 
-    def testBitfieldComparison(self):
+    def testBitFieldComparison(self):
         """Check bitfield comparison."""
 
-        bf_a = bitfield(9, 0)
+        bf_a = BitField(9, 0)
         bf_a.set(0, 1)
         bf_a.set(5, 1)
 
-        bf_b = bitfield(9, 1)
+        bf_b = BitField(9, 1)
 
         self.assertNotEqual(bf_a, bf_b)
-- 
cgit v0.11.2-87-g4458