llist: Add a C++ wrapper for linux_list
This commit adds the LListHead class which is a wrapper around the linuxlist. It adds an additional member to refer to the container, since the container_of macro doesn't work properly with C++ classes. All functions and macros from linuxlist.h are support except for the entry macros (e.g. llist_entry, llist_for_each_entry, ...). To access the container (entry), an entry() method is provided instead: llist_for_each(pos, &elems) { pos->entry()->do_something(); } Sponsored-by: On-Waves ehf
This commit is contained in:
parent
67c385046d
commit
dfef28de88
|
@ -37,6 +37,7 @@ tests/rlcmac/RLCMACTest
|
|||
tests/tbf/TbfTest
|
||||
tests/types/TypesTest
|
||||
tests/ms/MsTest
|
||||
tests/llist/LListTest
|
||||
tests/emu/pcu_emu
|
||||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
|
|
|
@ -95,7 +95,8 @@ noinst_HEADERS = \
|
|||
rlc.h \
|
||||
decoding.h \
|
||||
llc.h \
|
||||
pcu_utils.h
|
||||
pcu_utils.h \
|
||||
cxx_linuxlist.h
|
||||
|
||||
osmo_pcu_SOURCES = pcu_main.cpp
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/* cxx_linuxlist.h
|
||||
*
|
||||
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
|
||||
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct LListHead {
|
||||
typedef T entry_t;
|
||||
|
||||
/* This must match the declaration of struct llist_head */
|
||||
LListHead<T> *next;
|
||||
LListHead<T> *prev;
|
||||
|
||||
LListHead() : m_back(0) { INIT_LLIST_HEAD(this); }
|
||||
LListHead(T* entry) : m_back(entry) {
|
||||
next = (LListHead<T> *)LLIST_POISON1;
|
||||
prev = (LListHead<T> *)LLIST_POISON2;
|
||||
}
|
||||
|
||||
T *entry() {return m_back;}
|
||||
const T *entry() const {return m_back;}
|
||||
|
||||
llist_head &llist() {
|
||||
return *static_cast<llist_head *>(static_cast<void *>(this));
|
||||
}
|
||||
const llist_head &llist() const {
|
||||
return *static_cast<llist_head *>(static_cast<void *>(this));
|
||||
}
|
||||
|
||||
private:
|
||||
T *const m_back;
|
||||
};
|
||||
|
||||
/* Define a family of casting functions */
|
||||
template <typename T>
|
||||
llist_head &llist(LListHead<T> &l)
|
||||
{
|
||||
return l->llist();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const llist_head &llist(const LListHead<T> &l)
|
||||
{
|
||||
return l->llist();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
llist_head *llptr(LListHead<T> *l)
|
||||
{
|
||||
return &(l->llist());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const llist_head *llptr(const LListHead<T> *l)
|
||||
{
|
||||
return &(l->llist());
|
||||
}
|
||||
|
||||
/* Define type-safe wrapper for the existing linux_list.h functions */
|
||||
template <typename T>
|
||||
inline void llist_add(LListHead<T> *new_, LListHead<T> *head)
|
||||
{
|
||||
llist_add(llptr(new_), llptr(head));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void llist_add_tail(LListHead<T> *new_, LListHead<T> *head)
|
||||
{
|
||||
llist_add_tail(llptr(new_), llptr(head));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void llist_del(LListHead<T> *entry)
|
||||
{
|
||||
llist_del(llptr(entry));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void llist_del_init(LListHead<T> *entry)
|
||||
{
|
||||
llist_del_init(llptr(entry));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void llist_move(LListHead<T> *list, LListHead<T> *head)
|
||||
{
|
||||
llist_move(llptr(list), llptr(head));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void llist_move_tail(LListHead<T> *list, LListHead<T> *head)
|
||||
{
|
||||
llist_move_tail(llptr(list), llptr(head));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int llist_empty(const LListHead<T> *head)
|
||||
{
|
||||
return llist_empty(llptr(head));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void llist_splice(LListHead<T> *list, LListHead<T> *head)
|
||||
{
|
||||
llist_splice(llptr(list), llptr(head));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void llist_splice_init(LListHead<T> *list, LListHead<T> *head)
|
||||
{
|
||||
llist_splice_init(llptr(list), llptr(head));
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/
|
||||
|
||||
check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest
|
||||
check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest
|
||||
noinst_PROGRAMS = emu/pcu_emu
|
||||
|
||||
rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp
|
||||
|
@ -54,6 +54,14 @@ ms_MsTest_LDADD = \
|
|||
ms_MsTest_LDFLAGS = \
|
||||
-Wl,-u,bssgp_prim_cb
|
||||
|
||||
llist_LListTest_SOURCES = llist/LListTest.cpp
|
||||
llist_LListTest_LDADD = \
|
||||
$(top_builddir)/src/libgprs.la \
|
||||
$(LIBOSMOGB_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(COMMON_LA)
|
||||
|
||||
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
|
||||
$(srcdir)/package.m4: $(top_srcdir)/configure.ac
|
||||
:;{ \
|
||||
|
@ -78,7 +86,8 @@ EXTRA_DIST = \
|
|||
alloc/AllocTest.ok alloc/AllocTest.err \
|
||||
tbf/TbfTest.ok tbf/TbfTest.err \
|
||||
types/TypesTest.ok types/TypesTest.err \
|
||||
ms/MsTest.ok ms/MsTest.err
|
||||
ms/MsTest.ok ms/MsTest.err \
|
||||
llist/LListTest.ok llist/LListTest.err
|
||||
|
||||
DISTCLEANFILES = atconfig
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* LListTest.cpp
|
||||
*
|
||||
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cxx_linuxlist.h"
|
||||
|
||||
extern "C" {
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
struct TestElem {
|
||||
const char *str;
|
||||
LListHead<TestElem> list;
|
||||
|
||||
TestElem(const char *s) : str(s), list(this) {};
|
||||
};
|
||||
|
||||
static void test_linux_list()
|
||||
{
|
||||
LListHead<TestElem> elems, *pos, *tmp;
|
||||
TestElem elem1("number one");
|
||||
TestElem elem2("number two");
|
||||
TestElem elem3("number three");
|
||||
int count = 0;
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
|
||||
llist_add_tail(&elem1.list, &elems);
|
||||
llist_add_tail(&elem2.list, &elems);
|
||||
llist_add_tail(&elem3.list, &elems);
|
||||
|
||||
llist_for_each(pos, &elems) {
|
||||
count += 1;
|
||||
printf(" %i -> %s\n", count, pos->entry()->str);
|
||||
}
|
||||
OSMO_ASSERT(count == 3);
|
||||
|
||||
count = 0;
|
||||
llist_for_each_safe(pos, tmp, &elems) {
|
||||
count += 1;
|
||||
if (count == 2)
|
||||
llist_del(pos);
|
||||
|
||||
printf(" %i -> %s\n", count, pos->entry()->str);
|
||||
}
|
||||
OSMO_ASSERT(count == 3);
|
||||
|
||||
count = 0;
|
||||
llist_for_each(pos, &elems) {
|
||||
count += 1;
|
||||
OSMO_ASSERT(pos != &elem2.list);
|
||||
printf(" %i -> %s\n", count, pos->entry()->str);
|
||||
}
|
||||
OSMO_ASSERT(count == 2);
|
||||
|
||||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_linux_list();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
=== start test_linux_list ===
|
||||
1 -> number one
|
||||
2 -> number two
|
||||
3 -> number three
|
||||
1 -> number one
|
||||
2 -> number two
|
||||
3 -> number three
|
||||
1 -> number one
|
||||
2 -> number three
|
||||
=== end test_linux_list ===
|
|
@ -231,7 +231,6 @@ static void test_ms_replace_tbf()
|
|||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
|
||||
static const struct log_info_cat default_categories[] = {
|
||||
{"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1},
|
||||
};
|
||||
|
|
|
@ -36,3 +36,10 @@ cat $abs_srcdir/ms/MsTest.ok > expout
|
|||
cat $abs_srcdir/ms/MsTest.err > experr
|
||||
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/ms/MsTest], [0], [expout], [experr])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([llist])
|
||||
AT_KEYWORDS([llist])
|
||||
cat $abs_srcdir/llist/LListTest.ok > expout
|
||||
cat $abs_srcdir/llist/LListTest.err > experr
|
||||
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/llist/LListTest], [0], [expout], [experr])
|
||||
AT_CLEANUP
|
||||
|
|
Loading…
Reference in New Issue