The structure for control element ID is compound one. It means that it's not possible to decide single algorithm to find order of a pair of control element IDs. For convenience of application developers, it's better to produce API to decide the order by useful algorithm. This commit adds API for one of comparison algorithms. The fields except for numid are used for the algorithm. The iface, device, subdevice, name, and index fields are compared in the order, by arithmetic way. I note that the structure includes some 'unsigned integer' type of fields. The subtraction of the fields brings integer overflow as long as the calculation is done in the same storage size of the type itself. Signed-off-by: Takashi Sakamoto <o-takashi@xxxxxxxxxxxxx> --- include/control.h | 1 + src/control/control.c | 45 ++++++++++++++++- test/lsb/ctl-elem-id.c | 111 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) diff --git a/include/control.h b/include/control.h index 36953423..1b2cc0c6 100644 --- a/include/control.h +++ b/include/control.h @@ -427,6 +427,7 @@ void snd_ctl_elem_id_copy(snd_ctl_elem_id_t *dst, const snd_ctl_elem_id_t *src); int snd_ctl_elem_id_equal_by_numid(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r); int snd_ctl_elem_id_equal_by_tuple(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r); int snd_ctl_elem_id_compare_by_numid(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r); +int snd_ctl_elem_id_compare_by_tuple_arithmetic(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r); int snd_ctl_elem_id_compare(snd_ctl_elem_id_t *id1, const snd_ctl_elem_id_t *id2); unsigned int snd_ctl_elem_id_get_numid(const snd_ctl_elem_id_t *obj); snd_ctl_elem_iface_t snd_ctl_elem_id_get_interface(const snd_ctl_elem_id_t *obj); diff --git a/src/control/control.c b/src/control/control.c index 00009614..fbc6aeb7 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -90,7 +90,9 @@ is available. Many algorithms can be defined to find ordered pair of #snd_ctl_elem_id_t. For one of the comparison algorithms according to the numid, -snd_ctl_elem_id_compare_by_numid() is available. +snd_ctl_elem_id_compare_by_numid() is available. For one of the comparison +algorithms according to the tuple, snd_ctl_elem_id_compare_by_tuple_arithmetic() +is available. They are useful for qsort(3). \section element_lists Element Lists @@ -1893,6 +1895,47 @@ int snd_ctl_elem_id_compare_by_numid(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) return compare_unsigned_integer(l->numid, r->numid); } +/** + * \brief compare two arguments as ordered pair by one of algorithms according + * to iface, device, subdevice, name, index fields. + * \param l opaque pointer to element ID structure. + * \param r opaque pointer to another element ID structure. + * \retval positive if left is greater than right, negative if left is less + * than right, zero if they equal. + * + * The structure underlying #snd_ctl_elem_id_t is compound one. The comparison + * algorithm for it is not single and unique. The API implements one of + * algorithm to find order in a pair of control element IDs, according to the + * values of iface, device, subdevice, name, and index fields, by below logic: + * + * - find order in iface field by this order; card, hwdep, mixer, pcm, rawmidi, + * timer, and sequencer. + * - find order in device field by arithmetic comparison of its value. + * - find order in subdevice field by arithmetic comparison of its value. + * - find order in name field by using unsigned characters, implemented in strcmp(3). + * - find order in index field by arithmetic comparison of its value. + */ +int snd_ctl_elem_id_compare_by_tuple_arithmetic(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + int res; + + assert(l && r); + + res = l->iface - r->iface; + if (res != 0) + return res; + res = compare_unsigned_integer(l->device, r->device); + if (res != 0) + return res; + res = compare_unsigned_integer(l->subdevice, r->subdevice); + if (res != 0) + return res; + res = strcmp((const char *)l->name, (const char *)r->name); + if (res != 0) + return res; + return compare_unsigned_integer(l->index, r->index); +} + /** * \brief compare one #snd_ctl_elem_id_t to another * \param id1 pointer to first id diff --git a/test/lsb/ctl-elem-id.c b/test/lsb/ctl-elem-id.c index 670ec252..02eb24fc 100644 --- a/test/lsb/ctl-elem-id.c +++ b/test/lsb/ctl-elem-id.c @@ -135,6 +135,106 @@ static void comparison_by_numid_3(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) assert(snd_ctl_elem_id_compare_by_numid(l, r) < 0); } +// Case 3.0. The left object with lesser entry in iface field than right object +// should result in negative. +static void comparison_by_tuple_arithmetic_0(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_CARD, 0, 1, "A", 2); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_HWDEP, 0, 1, "A", 2); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) < 0); +} + +// Case 3.1. The left object with greater entry in iface field than right object +// should result in positive. +static void comparison_by_tuple_arithmetic_1(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_SEQUENCER, 3, 4, "B", 5); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_TIMER, 3, 4, "B", 5); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) > 0); +} + +// Case 3.2. The left object with lesser value in device field than right object +// should result in negative. +static void comparison_by_tuple_arithmetic_2(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_CARD, 1, 7, "C", 8); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_CARD, 6, 7, "C", 8); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) < 0); +} + + +// Case 3.3. The left object with greater value in device field than right object +// should result in positive. +static void comparison_by_tuple_arithmetic_3(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_HWDEP, 9, 10, "D", 11); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_HWDEP, 1, 10, "D", 11); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) > 0); +} + +// Case 3.3. The left object with lesser value in subdevice field than right object +// should result in negative. +static void comparison_by_tuple_arithmetic_4(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_MIXER, 12, 1, "E", 14); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_MIXER, 12, 13, "E", 14); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) < 0); +} + +// Case 3.4. The left object with greater value in subdevice field than right object +// should result in positive. +static void comparison_by_tuple_arithmetic_5(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_PCM, 15, 16, "F", 17); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_PCM, 15, 1, "F", 17); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) > 0); +} + +// Case 3.5. The left object with name beginning lesser character in name field +// than right object should result in negative. +static void comparison_by_tuple_arithmetic_6(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_RAWMIDI, 18, 19, "A", 20); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_RAWMIDI, 18, 19, "H", 20); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) < 0); +} + +// Case 3.6. The left object with name beginning greater character in name field +// than right object should result in positive. +static void comparison_by_tuple_arithmetic_7(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_TIMER, 21, 22, "I", 23); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_TIMER, 21, 22, "A", 23); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) > 0); +} + +// Case 3.7. The left object with lesser value in index field than right object +// should result in negative. +static void comparison_by_tuple_arithmetic_8(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_SEQUENCER, 24, 25, "J", 1); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_SEQUENCER, 24, 25, "J", 26); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) < 0); +} + +// Case 3.8. The left object with greater value in index field than right object +// should result in positive. +static void comparison_by_tuple_arithmetic_9(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_CARD, 27, 28, "K", 29); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_CARD, 27, 28, "K", 1); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) > 0); +} + +// Case 3.9. The left object with the same values in iface, device, subdevice, +// name, and index fields as right object should result in zero. +static void comparison_by_tuple_arithmetic_10(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) +{ + set_elem_id_by_tuple(l, SND_CTL_ELEM_IFACE_HWDEP, 30, 31, "L", 32); + set_elem_id_by_tuple(r, SND_CTL_ELEM_IFACE_HWDEP, 30, 31, "L", 32); + assert(snd_ctl_elem_id_compare_by_tuple_arithmetic(l, r) == 0); +} + int main() { void (*entries[])(snd_ctl_elem_id_t *l, snd_ctl_elem_id_t *r) = { @@ -150,6 +250,17 @@ int main() comparison_by_numid_1, comparison_by_numid_2, comparison_by_numid_3, + comparison_by_tuple_arithmetic_0, + comparison_by_tuple_arithmetic_1, + comparison_by_tuple_arithmetic_2, + comparison_by_tuple_arithmetic_3, + comparison_by_tuple_arithmetic_4, + comparison_by_tuple_arithmetic_5, + comparison_by_tuple_arithmetic_6, + comparison_by_tuple_arithmetic_7, + comparison_by_tuple_arithmetic_8, + comparison_by_tuple_arithmetic_9, + comparison_by_tuple_arithmetic_10, }; int count = sizeof(entries) / sizeof(*entries); int fd; -- 2.27.0