waitq.h watchdog.h workq.h \
parse_conf.h ini.h \
worker.h lockmgr.h devlock.h output.h bwlimit.h \
- collect.h event.h
+ collect.h event.h ilist.h
#
# libbac
util.c var.c watchdog.c workq.c btimers.c \
worker.c flist.c bcollector.c collect.c \
address_conf.c breg.c htable.c lockmgr.c devlock.c output.c bwlimit.c \
- bsock_meeting.c bcrc32.c events.c $(EXTRA_SRCS)
+ bsock_meeting.c bcrc32.c events.c ilist.c $(EXTRA_SRCS)
LIBBAC_OBJS_TMP = $(LIBBAC_SRCS:.c=.o)
LIBBAC_OBJS = $(LIBBAC_OBJS_TMP:.cc=.o)
$(RMF) alist.o
$(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) alist.c
+ilist_test: Makefile libbac.la ilist.c unittests.o
+ $(RMF) ilist.o
+ $(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) ilist.c
+ $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L. -o $@ ilist.o unittests.o $(DLIB) -lbac -lm $(LIBS) $(OPENSSL_LIBS)
+ $(LIBTOOL_INSTALL) $(INSTALL_PROGRAM) $@ $(DESTDIR)$(sbindir)/
+ $(RMF) ilist.o
+ $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) ilist.c
+
dlist_test: Makefile libbac.la dlist.c unittests.o
$(RMF) dlist.o
$(CXX) -DTEST_PROGRAM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) dlist.c
int new_max_items;
/* put() can insert and item anywhere in the list so
- it's important to allocate at least last_item+1 items */
+ * it's important to allocate at least last_item+1 items
+ */
int min_grow = MAX(10, last_item+1);
if (num_grow < min_grow) {
num_grow = min_grow; /* default if not initialized */
last_item++;
}
-
/*
* Append an item to the list
*/
num_items++;
}
-/*
- * Put an item at a particular index
- */
-void ilist::put(int index, void *item)
-{
- if (index > last_item) {
- last_item = index;
- }
- grow_list();
- if (items[index] == NULL) {
- num_items++;
- }
- items[index] = item;
-}
-
-
/*
* Remove an item from the list
* Note: you must free the item when
alist mylist;
};
-void check_all_alist_contents(alist *mlist)
+void check_all_alist_indexes2(alist *mlist)
{
bool check_cont = true;
- char buf[30];
- int i;
+ char *bp;
+ int i = 0;
+ int nb;
- for (i = 0; i < mlist->size(); i++) {
- sprintf(buf, "This is item %d", i);
- if (strcmp(buf, (char*)mlist->get(i)) != 0){
+ foreach_alist_index(i, bp, mlist) {
+ nb = atoi(bp);
+ if (nb != i){
+ Dmsg2(0, "nb=%d != i=%d\n", nb, i);
check_cont = false;
}
}
- ok(check_cont, "Checking alist contents");
+ ok(check_cont, "Check all alist indexes 2");
};
-void check_all_ilist_contents(ilist *vlist, int start)
+void check_all_alist_contents(alist *mlist)
{
bool check_cont = true;
char buf[30];
int i;
- for (i = start; i< vlist->size(); i++) {
+ for (i = 0; i < mlist->size(); i++) {
sprintf(buf, "This is item %d", i);
- if (strcmp(buf, (char*)vlist->get(i)) != 0){
+ if (strcmp(buf, (char*)mlist->get(i)) != 0){
check_cont = false;
}
}
- ok(check_cont, "Checking ilist contents");
+ ok(check_cont, "Checking alist contents");
};
void check_all_alist_indexes(alist *mlist)
delete mlist;
};
-void check_ilist_destroy_delete(ilist *vlist)
-{
- vlist->destroy();
- ok(vlist->size() == 0, "Check ilist size after destroy");
- delete vlist;
-}
-
int main()
{
Unittests alist_test("alist_test");
FILESET *fileset;
char buf[30];
alist *mlist;
- ilist *vlist;
char *bp;
int i;
bool check_cont;
bool check_indx;
- Pmsg0(0, "Initialize tests ...\n");
+ log("Initialize tests ...");
fileset = (FILESET *)malloc(sizeof(FILESET));
bmemzero(fileset, sizeof(FILESET));
fileset->mylist.init();
ok(fileset && fileset->mylist.empty() && fileset->mylist.max_size() == 0,
"Default initialization");
- Pmsg0(0, "Automatic allocation/destruction of alist:\n");
+ log("Automatic allocation/destruction of alist:");
for (int i = 0; i < NUMITEMS; i++) {
sprintf(buf, "This is item %d", i);
ok(fileset->mylist.size() == NUMITEMS, "Checking size");
check_all_alist_contents(&fileset->mylist);
+
fileset->mylist.destroy();
ok(fileset->mylist.size() == 0, "Check size after delete");
ok(fileset->mylist.last() == NULL, "Check last after delete");
free(fileset);
- Pmsg0(0, "Allocation/destruction using new delete\n");
+ log("Allocation/destruction using new delete");
mlist = New(alist(50));
ok(mlist && mlist->empty() && mlist->max_size() == 0,
check_all_alist_contents(mlist);
check_alist_destroy_and_delete(mlist);
- Pmsg0(0, "Test alist::remove(0)\n");
+ log("Test alist::remove(0)");
mlist = New(alist(10, owned_by_alist));
mlist->append(bstrdup("trash"));
mlist->append(bstrdup("0"));
check_all_alist_indexes(mlist);
check_alist_destroy_and_delete(mlist);
- Pmsg0(0, "Test alist::remove(3)\n");
+ log("Test alist::remove(3)");
mlist = New(alist(10, owned_by_alist));
mlist->append(bstrdup("0"));
mlist->append(bstrdup("1"));
check_all_alist_indexes(mlist);
check_alist_destroy_and_delete(mlist);
- Pmsg0(0, "Test alist::remove(last)\n");
+ log("Test alist::remove(last)");
mlist = New(alist(10, owned_by_alist));
mlist->append(bstrdup("0"));
mlist->append(bstrdup("1"));
check_all_alist_indexes(mlist);
check_alist_destroy_and_delete(mlist);
- Pmsg0(0, "Test alist::remove(last+1)\n");
+ log("Test alist::remove(last+1)");
mlist = New(alist(10, owned_by_alist));
mlist->append(bstrdup("0"));
mlist->append(bstrdup("1"));
mlist->append(bstrdup("2"));
mlist->append(bstrdup("3"));
mlist->append(bstrdup("4"));
+ check_all_alist_indexes2(mlist);
ok(mlist && mlist->size() == 5, "Checking size");
ok(mlist->last_index() == 5, "Check last_index");
ok(mlist->remove(5) == NULL, "Check remove returns null");
ok(mlist->size() == 5, "Remove test size");
check_all_alist_indexes(mlist);
+ check_all_alist_indexes2(mlist);
check_alist_destroy_and_delete(mlist);
- Pmsg0(0, "Test alist::pop()\n");
+ log("Test alist::pop()");
mlist = New(alist(10, owned_by_alist));
mlist->append(bstrdup("0"));
mlist->append(bstrdup("1"));
check_all_alist_indexes(mlist);
check_alist_destroy_and_delete(mlist);
- Pmsg0(0, "Test ilist::put()\n");
- vlist = New(ilist(10, owned_by_alist));
- sprintf(buf, "This is item 10");
- vlist->put(10, bstrdup(buf));
- ok(vlist && vlist->size() == 1, "Checking size after put()");
- ok(vlist->last_index() == 10, "Check last_index");
- check_ilist_destroy_delete(vlist);
-
- Pmsg0(0, "Test ilist with multiple put()\n");
- vlist = New(ilist(50, owned_by_alist));
- sprintf(buf, "This is item 10");
- vlist->put(10, bstrdup(buf));
- ok(vlist && vlist->size() == 1, "Checking size after put()");
- ok(vlist->last_index() == 10, "Check last_index");
- sprintf(buf, "This is item 15");
- vlist->put(15, bstrdup(buf));
- ok(vlist->size() == 2, "Checking size after put()");
- ok(vlist->last_index() == 15, "Check last_index");
- for (i = NUMITEMS; i < NUMITEMS + MORENUMITEMS; i++) {
- sprintf(buf, "This is item %d", i);
- vlist->put(i, bstrdup(buf));
- }
- ok(vlist->size() == 2 + MORENUMITEMS, "Checking size after put()");
- ok(vlist->last_index() == NUMITEMS + MORENUMITEMS - 1, "Check last_index");
- /* check contents, first two sparse elements */
- ok(strcmp("This is item 10", (char *)vlist->get(10)) == 0, "Check ilist content at 10");
- ok(strcmp("This is item 15", (char *)vlist->get(15)) == 0, "Check ilist content at 15");
- check_all_ilist_contents(vlist, NUMITEMS);
- check_ilist_destroy_delete(vlist);
-
- Pmsg0(0, "Test alist::push()\n");
+ log("Test alist::push()");
mlist = New(alist(10, owned_by_alist));
check_cont = true;
check_indx = true;
}
ok(check_cont, "Check all sizes after push");
ok(check_indx, "Check all last_indexes after push");
- Pmsg0(0, "Test alist::pop()\n");
+ log("Test alist::pop()");
check_cont = true;
for (i = NUMITEMS-1; (bp = (char *)mlist->pop()); i--) {
sprintf(buf, "This is item %d", i);
ok(check_cont, "Check get() after pop() contents.");
check_alist_destroy_and_delete(mlist);
+ log("Test alist::foreach_alist_index()");
+ mlist = New(alist(10, owned_by_alist));
+ mlist->append(bstrdup("0"));
+ mlist->append(bstrdup("1"));
+ mlist->append(bstrdup("2"));
+ mlist->append(bstrdup("3"));
+ mlist->append(bstrdup("4"));
+ mlist->append(bstrdup("5"));
+ mlist->append(bstrdup("6"));
+ mlist->append(bstrdup("7"));
+ mlist->append(bstrdup("8"));
+ mlist->append(bstrdup("9"));
+ check_all_alist_indexes2(mlist);
+ ok(mlist && mlist->size() == 10, "Checking size");
+ ok(mlist->last_index() == 10, "Check last_index");
+ foreach_alist_index(i, bp, mlist) {
+ ok(i < mlist->size(), "check index");
+ ok(bp != NULL, "check element of alist");
+ }
+ check_alist_destroy_and_delete(mlist);
return report();
}
#endif
* Kern Sibbald, June MMIII
*/
+#ifndef ALIST_H
+#define ALIST_H
extern bool is_null(const void *ptr);
protected:
void **items; /* from 0..n-1 */
int num_items; /* from 1..n */
- int last_item; /* maximum item index (1..n) */
+
+ int last_item; /* maximum item index (1..n). */
+
int max_items; /* maximum possible items (array size) (1..n) */
int num_grow;
int cur_item; /* from 1..n */
void *remove(int index) { return remove_item(index);};
};
-/*
- * Indexed list -- much like a simplified STL vector
- * array of pointers to inserted items
- */
-class ilist : public baselist {
-public:
- ilist(int num = 100, bool own=true): baselist(num, own) {};
- /* put() is not compatible with remove(), prepend() or foreach_alist */
- void put(int index, void *item);
-};
-
/*
* Define index operator []
*/
{
num_grow = num;
}
+
+#endif // ALIST_H
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2020 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+*/
+/*
+ * Bacula array list routines
+ *
+ * ilist is a simple malloc'ed array of pointers. For the moment,
+ * it simply malloc's a bigger array controlled by num_grow.
+ * Default is to realloc the pointer array for each new member.
+ *
+ * Note: the list can have holes (empty items). This is done by
+ * using get() and put().
+ *
+ * From alist.c
+ *
+ */
+
+#include "bacula.h"
+
+/*
+ * Private grow list function. Used to insure that
+ * at least one more "slot" is available.
+ */
+void ilist::grow_list()
+{
+ int i;
+ int new_max_items;
+
+ /* put() can insert and item anywhere in the list so
+ * it's important to allocate at least last_item+1 items
+ */
+ int min_grow = MAX(10, last_item+1);
+ if (num_grow < min_grow) {
+ num_grow = min_grow; /* default if not initialized */
+ }
+
+ if (items == NULL) {
+ items = (void **)malloc(num_grow * sizeof(void *));
+ for (i=0; i<num_grow; i++) {
+ items[i] = NULL;
+ }
+ max_items = num_grow;
+ } else if (last_item >= max_items) {
+ new_max_items = last_item + num_grow;
+ items = (void **)realloc(items, new_max_items * sizeof(void *));
+ for (i=max_items; i<new_max_items; i++) {
+ items[i] = NULL;
+ }
+ max_items = new_max_items;
+ }
+}
+
+void ilist::append(void *item)
+{
+ grow_list();
+ items[last_item++] = item;
+ num_items++;
+}
+
+/*
+ * Put an item at a particular index
+ */
+void ilist::put(int index, void *item)
+{
+ if (index > last_item) {
+ last_item = index; // FIXME: On alist, last_item is pointing after the last item
+ }
+ grow_list();
+ if (items[index] == NULL) {
+ num_items++;
+ }
+ items[index] = item;
+}
+
+
+/*
+ * Remove an item from the list
+ * Note: you must free the item when
+ * you are done with it.
+ */
+void * ilist::remove_item(int index)
+{
+ void *item;
+ if (index < 0 || index >= last_item) {
+ return NULL;
+ }
+ item = items[index];
+
+ /* last_item is from 1..n, we work from 0..n-1 */
+ for (int i=index; i < (last_item-1); i++) {
+ items[i] = items[i+1];
+ }
+
+ items[last_item-1] = NULL; /* The last item is shifted by one, the last slot is always free */
+
+ last_item--; /* We have shifted all items by 1 */
+ num_items--; /* We have 1 item less */
+
+ return item;
+}
+
+
+/* Get the index item -- we should probably allow real indexing here */
+void * ilist::get(int index)
+{
+ if (items == NULL || index < 0 || index > last_item) { // Difference with alist here
+ return NULL;
+ }
+ return items[index];
+}
+
+/* Destroy the list and its contents */
+void ilist::destroy()
+{
+ if (items) {
+ if (own_items) {
+ for (int i=0; i<max_items; i++) {
+ if (items[i]) {
+ bfree(items[i]);
+ items[i] = NULL;
+ }
+ }
+ }
+ bfree(items);
+ items = NULL;
+ }
+ num_items = 0;
+ last_item = 0;
+ max_items = 0;
+ num_grow = 0;
+}
+
+#ifdef TEST_PROGRAM
+#include "unittests.h"
+
+#define NUMITEMS 20
+#define MORENUMITEMS 115
+
+void check_all_ilist_contents(ilist *vlist, int start)
+{
+ bool check_cont = true;
+ char buf[30];
+ int i;
+
+ for (i = start; i< vlist->size(); i++) {
+ sprintf(buf, "This is item %d", i);
+ if (strcmp(buf, (char*)vlist->get(i)) != 0){
+ check_cont = false;
+ }
+ }
+ ok(check_cont, "Checking ilist contents");
+};
+
+void check_ilist_destroy_delete(ilist *vlist)
+{
+ vlist->destroy();
+ ok(vlist->size() == 0, "Check ilist size after destroy");
+ delete vlist;
+}
+
+int main()
+{
+ Unittests ilist_test("ilist_test");
+ char buf[30];
+ ilist *vlist;
+ char *bp;
+ int i;
+ bool check_cont;
+ bool check_indx;
+
+ log("Initialize tests ...");
+ log("Test ilist::put()");
+ vlist = New(ilist(10, owned_by_ilist));
+ sprintf(buf, "This is item 10");
+ vlist->put(10, bstrdup(buf));
+ ok(vlist && vlist->size() == 1, "Checking size after put()");
+ ok(vlist->last_index() == 10, "Check last_index");
+ check_ilist_destroy_delete(vlist);
+
+ log("Test ilist with multiple put()");
+ vlist = New(ilist(50, owned_by_ilist));
+ sprintf(buf, "This is item 10");
+ vlist->put(10, bstrdup(buf));
+ ok(vlist && vlist->size() == 1, "Checking size after put()");
+ ok(vlist->last_index() == 10, "Check last_index");
+ sprintf(buf, "This is item 15");
+ vlist->put(15, bstrdup(buf));
+ ok(vlist->size() == 2, "Checking size after put()");
+ ok(vlist->last_index() == 15, "Check last_index");
+ for (i = NUMITEMS; i < NUMITEMS + MORENUMITEMS; i++) {
+ sprintf(buf, "This is item %d", i);
+ vlist->put(i, bstrdup(buf));
+ }
+ ok(vlist->size() == 2 + MORENUMITEMS, "Checking size after put()");
+ ok(vlist->last_index() == NUMITEMS + MORENUMITEMS - 1, "Check last_index");
+ /* check contents, first two sparse elements */
+ ok(strcmp("This is item 10", (char *)vlist->get(10)) == 0, "Check ilist content at 10");
+ ok(strcmp("This is item 15", (char *)vlist->get(15)) == 0, "Check ilist content at 15");
+ check_all_ilist_contents(vlist, NUMITEMS);
+ check_ilist_destroy_delete(vlist);
+
+ return report();
+}
+#endif
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2020 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+*/
+
+#ifndef ILIST_H
+#define ILIST_H
+
+extern bool is_null(const void *ptr);
+
+/* Second arg of init */
+enum {
+ owned_by_ilist = true,
+ not_owned_by_ilist = false
+};
+
+/*
+ * Array list -- much like a simplified STL vector
+ * array of pointers to inserted items.
+ */
+class ilist : public SMARTALLOC {
+protected:
+ void **items; /* from 0..n-1 */
+ int num_items; /* from 1..n */
+
+ int last_item; /* maximum item index (1..n). */
+
+ int max_items; /* maximum possible items (array size) (1..n) */
+ int num_grow;
+ int cur_item; /* from 1..n */
+ bool own_items;
+ void grow_list(void);
+ void *remove_item(int index);
+
+public:
+ ilist(int num = 100, bool own=true);
+ ~ilist();
+ void init(int num = 100, bool own=true);
+ void append(void *item);
+ void *get(int index);
+ bool empty() const;
+ int last_index() const { return last_item; };
+ int max_size() const { return max_items; };
+ void * operator [](int index) const;
+ int size() const;
+ void destroy();
+ void grow(int num);
+
+ void put(int index, void *item);
+};
+
+inline bool ilist::empty() const
+{
+ return num_items == 0;
+}
+
+/*
+ * This allows us to do explicit initialization,
+ * allowing us to mix C++ classes inside malloc'ed
+ * C structures. Define before called in constructor.
+ */
+inline void ilist::init(int num, bool own)
+{
+ items = NULL;
+ num_items = 0;
+ last_item = 0;
+ max_items = 0;
+ num_grow = num;
+ own_items = own;
+}
+
+/*
+ * Define index operator []
+ */
+inline void * ilist::operator [](int index) const {
+ if (index < 0 || index >= max_items) {
+ return NULL;
+ }
+ return items[index];
+}
+
+/* Constructor */
+inline ilist::ilist(int num, bool own)
+{
+ init(num, own);
+}
+
+/* Destructor */
+inline ilist::~ilist()
+{
+ destroy();
+}
+
+/* Current size of list */
+inline int ilist::size() const
+{
+ return num_items;
+}
+
+/* How much to grow by each time */
+inline void ilist::grow(int num)
+{
+ num_grow = num;
+}
+
+#endif // ILIST_H
#include "smartall.h"
#include "lockmgr.h"
+#include "ilist.h"
#include "alist.h"
#include "dlist.h"
#include "flist.h"