]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/alist.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / lib / alist.c
index ff88cf5866e50f4218d5244fc6e868763108dbb0..d947c5631826b5654fca8c5e26ee65469fdbff10 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2016 Kern Sibbald
+   Copyright (C) 2000-2017 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.
  *      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().  If you are using this kind of indexed
+ *      list, you cannot use: prepend() and remove() as they will
+ *      reorder the list. So, in the ilist array, these functions are
+ *      disabled and the put method is defined.
+ *
  *   Kern Sibbald, June MMIII
  *
  */
  * Private grow list function. Used to insure that
  *   at least one more "slot" is available.
  */
-void alist::grow_list()
+void baselist::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) {
-      if (num_grow == 0) {
-         num_grow = 1;                /* default if not initialized */
-      }
       items = (void **)malloc(num_grow * sizeof(void *));
+      for (i=0; i<num_grow; i++) {
+         items[i] = NULL;
+      }
       max_items = num_grow;
-   } else if (num_items == max_items) {
-      max_items += num_grow;
-      items = (void **)realloc(items, max_items * sizeof(void *));
+   } 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;
    }
 }
 
@@ -62,14 +82,14 @@ void *alist::last()
    if (num_items == 0) {
       return NULL;
    } else {
-      cur_item = num_items;
-      return items[num_items-1];
+      cur_item = last_item;
+      return items[last_item-1];
    }
 }
 
 void *alist::next()
 {
-   if (cur_item >= num_items) {
+   if (cur_item >= last_item) {
       return NULL;
    } else {
       return items[cur_item++];
@@ -88,67 +108,104 @@ void *alist::prev()
 /*
  * prepend an item to the list -- i.e. add to beginning
  */
-void alist::prepend(void *item) {
+void alist::prepend(void *item)
+{
    grow_list();
    if (num_items == 0) {
       items[num_items++] = item;
+      if (num_items > last_item) {
+         last_item = num_items;
+      }
       return;
    }
-   for (int i=num_items; i > 0; i--) {
+   for (int i=last_item; i > 0; i--) {
       items[i] = items[i-1];
    }
    items[0] = item;
    num_items++;
+   last_item++;
 }
 
 
 /*
  * Append an item to the list
  */
-void alist::append(void *item) {
+void baselist::append(void *item)
+{
    grow_list();
-   items[num_items++] = item;
+   items[last_item++] = item;
+   num_items++;
 }
 
-/* Remove an item from the list */
-void * alist::remove(int index)
+/*
+ * 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
+ *   you are done with it.
+ */
+void * baselist::remove_item(int index)
 {
    void *item;
-   if (index < 0 || index >= num_items) {
+   if (index < 0 || index >= last_item) {
       return NULL;
    }
    item = items[index];
-   num_items--;
-   for (int i=index; i < num_items; i++) {
+
+   /* 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 * alist::get(int index)
+void * baselist::get(int index)
 {
-   if (index < 0 || index >= num_items) {
+   if (items == NULL || index < 0 || index > last_item) {
       return NULL;
    }
    return items[index];
 }
 
 /* Destroy the list and its contents */
-void alist::destroy()
+void baselist::destroy()
 {
    if (items) {
       if (own_items) {
-         for (int i=0; i<num_items; i++) {
-            free(items[i]);
-            items[i] = NULL;
+         for (int i=0; i<max_items; i++) {
+            if (items[i]) {
+               free(items[i]);
+               items[i] = NULL;
+            }
          }
       }
       free(items);
       items = NULL;
    }
    num_items = 0;
+   last_item = 0;
    max_items = 0;
    num_grow = 0;
 }
@@ -165,9 +222,10 @@ int main()
    FILESET *fileset;
    char buf[30];
    alist *mlist;
+   char *bp;
 
    fileset = (FILESET *)malloc(sizeof(FILESET));
-   memset(fileset, 0, sizeof(FILESET));
+   bmemzero(fileset, sizeof(FILESET));
    fileset->mylist.init();
 
    printf("Manual allocation/destruction of list:\n");
@@ -183,7 +241,7 @@ int main()
    free(fileset);
 
    printf("Allocation/destruction using new delete\n");
-   mlist = new alist(10);
+   mlist = New(alist(50));
 
    for (int i=0; i<20; i++) {
       sprintf(buf, "This is item %d", i);
@@ -192,11 +250,181 @@ int main()
    for (int i=0; i< mlist->size(); i++) {
       printf("Item %d = %s\n", i, (char *)mlist->get(i));
    }
+   printf("\nIndexed test. Insert 210 items.\n");
+   /* Test indexed list */
+   mlist->destroy();
+   delete mlist;
+
+   {
+      printf("Test remove()\n");
+      char *elt;
+      int i=0;
+      alist *alst = New(alist(10, owned_by_alist));
+      alst->append(bstrdup("trash"));
+      alst->append(bstrdup("0"));
+      alst->append(bstrdup("1"));
+      alst->append(bstrdup("2"));
+      alst->append(bstrdup("3"));
+      free(alst->remove(0));
+      foreach_alist(elt, alst) {
+         int nb = atoi(elt);
+         ASSERT(nb == i);
+         printf("%d %s\n", i++, elt);
+      }
+      delete alst;
+   }
+
+   {
+      char *elt;
+      int i=0;
+      alist *alst = New(alist(10, owned_by_alist));
+      alst->append(bstrdup("0"));
+      alst->append(bstrdup("1"));
+      alst->append(bstrdup("2"));
+      alst->append(bstrdup("trash"));
+      alst->append(bstrdup("3"));
+      free(alst->remove(3));
+      foreach_alist(elt, alst) {
+         int nb = atoi(elt);
+         ASSERT(nb == i);
+         printf("%d %s\n", i++, elt);
+      }
+      delete alst;
+   }
+
+   {
+      char *elt;
+      int i=0;
+      alist *alst = New(alist(10, owned_by_alist));
+      alst->append(bstrdup("0"));
+      alst->append(bstrdup("1"));
+      alst->append(bstrdup("2"));
+      alst->append(bstrdup("3"));
+      alst->append(bstrdup("trash"));
+      free(alst->remove(4));
+      foreach_alist(elt, alst) {
+         int nb = atoi(elt);
+         ASSERT(nb == i);
+         printf("%d %s\n", i++, elt);
+      }
+      delete alst;
+   }
+
+   {
+      char *elt;
+      int i=0;
+      alist *alst = New(alist(10, owned_by_alist));
+      alst->append(bstrdup("0"));
+      alst->append(bstrdup("1"));
+      alst->append(bstrdup("2"));
+      alst->append(bstrdup("3"));
+      alst->append(bstrdup("4"));
+      ASSERT(alst->remove(5) == NULL);
+      foreach_alist(elt, alst) {
+         int nb = atoi(elt);
+         ASSERT(nb == i);
+         printf("%d %s\n", i++, elt);
+      }
+      delete alst;
+   }
+
+   {
+      printf("Test pop()\n");
+      char *elt;
+      int i=0;
+      alist *alst = New(alist(10, owned_by_alist));
+      alst->append(bstrdup("0"));
+      alst->append(bstrdup("1"));
+      alst->append(bstrdup("2"));
+      alst->append(bstrdup("3"));
+      alst->append(bstrdup("trash"));
+      ASSERT(alst->last_index() == 5);
+      free(alst->pop());
+      ASSERT(alst->last_index() == 4);
+      foreach_alist(elt, alst) {
+         int nb = atoi(elt);
+         ASSERT(nb == i);
+         printf("%d %s\n", i++, elt);
+      }
+      delete alst;
+   }
+   {
+      ilist *ilst = New(ilist(10, owned_by_alist));
+      sprintf(buf, "This is item 10");
+      ilst->put(10, bstrdup(buf));
+      printf("ilst size is %d. last_item=%d.  max_items=%d\n",
+         ilst->size(), ilst->last_index(), ilst->max_size());
+      ASSERT(ilst->size() == 1);
+      delete ilst;
+   }
+
+   {
+      ilist *ilst = New(ilist(10, not_owned_by_alist));
+      ilst->put(15, (char *)"something");
+      printf("ilst size is %d. last_item=%d.  max_items=%d\n",
+         ilst->size(), ilst->last_index(), ilst->max_size());
+      ASSERT(ilst->size() == 1);
+      ASSERT(ilst->last_index() == 15);
+      delete ilst;
+   }
+
+   ilist *ilst = New(ilist(50));
+   for (int i=0; i<115; i++) {
+      sprintf(buf, "This is item %d", i);
+      ilst->put(i, bstrdup(buf));
+      printf("%s\n", buf);
+   }
+   printf("ilst size is %d. last_item=%d.  max_items=%d\n",
+       ilst->size(), ilst->last_index(), ilst->max_size());
+   for (int i=0; i< ilst->size(); i++) {
+      printf("Item %d = %s\n", i, (char *)ilst->get(i));
+   }
+
+   delete ilst;
+
+   printf("Test alist push().\n");
+   mlist = New(alist(10));
+
+   printf("mlist size is %d. last_item=%d.  max_items=%d\n",
+       mlist->size(), mlist->last_index(), mlist->max_size());
+   for (int i=0; i<20; i++) {
+      sprintf(buf, "This is item %d", i);
+      mlist->push(bstrdup(buf));
+      printf("mlist size is %d. last_item=%d.  max_items=%d\n",
+          mlist->size(), mlist->last_index(), mlist->max_size());
+   }
+   printf("Test alist pop()\n");
+   for (int i=0; (bp=(char *)mlist->pop()); i++) {
+      printf("Item %d = %s\n", i, bp);
+      free(bp);
+   }
+   printf("mlist size is %d. last_item=%d.  max_items=%d\n",
+       mlist->size(), mlist->last_index(), mlist->max_size());
+
+   for (int i=0; i<mlist->max_size(); i++) {
+      bp = (char *) mlist->get(i);
+      if (bp != NULL) {
+         printf("Big problem. Item %d item=%p, but should be NULL\n", i, bp);
+      }
+   }
+   printf("Done push() pop() tests\n");
 
    delete mlist;
 
+   ilst = New(ilist(10, not_owned_by_alist));
+   ilst->put(1, ilst);
+   ilst->append((void*)1);
+   //ilist->first();
+   //ilist->remove(1);
+   delete ilst;
+   {
+      ilist a(4, not_owned_by_alist);
+      a.append((void*)"test1");
 
+      ilist b(4, not_owned_by_alist);
+      bmemzero(&b, sizeof b);
+      b.append((void*)"test1");
+   }
    sm_dump(false);       /* test program */
-
 }
 #endif