new type tab_t and rebuild of stack
[calc.git] / tabular.c
diff --git a/tabular.c b/tabular.c
new file mode 100644 (file)
index 0000000..0252a8e
--- /dev/null
+++ b/tabular.c
@@ -0,0 +1,180 @@
+#include <malloc.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "debug.h"
+#include "alloc.h"
+
+#include "tabular.h"
+
+/* management function */
+
+/* allocate a tab of N elements */
+
+tab_t *alloc_tab (int nb)
+{
+    tab_t *tab = (tab_t *) callocordie (1, sizeof (tab_t));
+    if (nb > 0) {
+        tab->data = (double *) callocordie (nb, sizeof (double));
+        tab->size = nb;
+    }
+    return (tab);
+}
+
+/* resize a tab to size N */
+
+tab_t *resize_tab (tab_t *tab, int nb)
+{
+    double *tmp = NULL;
+    tab = (tab) ? tab : (tab_t *) callocordie (1, sizeof (tab_t));
+    nb = (nb > 0) ? nb : 0;
+    if (nb > 0) {
+        tmp = (double *) callocordie (nb, sizeof (double));
+        memcpy (tmp, tab->data, ((tab->size < nb) ? tab->size : nb) * sizeof (double));
+    }
+    free (tab->data);
+    tab->data = tmp;
+    tab->size = nb;
+    return tab;
+}
+
+/* copy a tab */
+
+tab_t *copy_tab (tab_t *tab)
+{
+    tab_t *new = alloc_tab (tab->size);
+    memcpy (new->data, tab->data, tab->size * sizeof (double));
+    return new;
+}
+
+/* free a tab */
+
+void free_tab (tab_t *tab)
+{
+    if (tab) {
+        if (tab->data) {
+            free (tab->data);
+        }
+        free (tab);
+    }
+}    
+
+/* get table size */
+
+int size_tab (tab_t *tab)
+{
+    int ret = 0;
+    if (tab) {
+        ret = tab->size;
+    }
+    return ret;
+}
+
+/* set an element into a tab at position id [1..N] */
+
+double set_tab (tab_t *tab, int id, double val)
+{
+    double ret = NAN;
+    if ((!tab) || (id < 1) || (id > tab->size)) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+        ret = tab->data[id - 1] = val;
+    }
+    return ret;
+}
+
+/* get an element from a tab at position id [1..N] */
+
+double get_tab (tab_t *tab, int id)
+{
+    double ret = NAN;
+    if ((!tab) || (id < 1) || (id > tab->size)) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+        ret = tab->data[id - 1];
+    }
+    return ret;
+}
+
+/* push an element into a tab at position id [1.. N](-1 means end) resulting to a tab of N+1 elements */
+
+double push_tab (tab_t *tab, int id, double val)
+{
+    double ret = NAN;
+    if ((!tab) || (((id < 1) || (id > tab->size + 1)) && (id != -1))) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+
+        /* special case for inserting an element at the end */
+        id = (id == -1) ? tab->size + 1 : id;
+
+        /* create larger tab */
+        double *tmp = (double *) callocordie (tab->size + 1, sizeof (double));
+        memcpy (tmp, tab->data, (id - 1) * sizeof (double));
+        ret = tmp[id - 1] = val;
+        memcpy (tmp + id , tab->data + id - 1, (tab->size - id + 1) * sizeof (double));
+
+        /* update structure */
+        free (tab->data);
+        tab->data = tmp;
+        tab->size++;
+    }
+    return ret;
+}
+
+/* pop an element from a tab at position id [1.. N](-1 means last) resulting to a tab of N-1 elements */
+
+double pop_tab (tab_t *tab, int id)
+{
+    double ret = NAN;
+    if ((!tab) || (((id < 1) || (id > tab->size)) && (id != -1))) {
+        VERBOSE (WARNING, fprintf (stdout, "error out of bounds (%d/%d)\n", id, (tab) ? tab->size : 0));
+    } else {
+        ret = tab->data[id - 1];
+
+        /* special case for inserting an element at the end */
+        id = (id == -1) ? tab->size : id;
+
+        /* create larger tab */
+        double *tmp = (double *) callocordie (tab->size - 1, sizeof (double));
+        memcpy (tmp, tab->data, (id - 1) * sizeof (double));
+        memcpy (tmp + id - 1, tab->data + id, (tab->size - id) * sizeof (double));
+
+        /* update structure */
+        free (tab->data);
+        tab->data = tmp;
+        tab->size--;
+    }
+    return ret;
+}
+
+/* sort tab */
+
+void order_tab (tab_t *tab)
+{
+    int i, j;
+    if ((!tab) || (tab->size < 3)) {
+        VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", tab->size));
+        return;
+    }
+
+    /* buble sort */
+    for (i = 0; i < tab->size - 1; i++) {
+        int done = 0;
+        for (j = 0; j < tab->size - 1; j++) {
+            double tab_j = tab->data[j];
+            double tab_jp1 = tab->data[j + 1];
+            if (tab_j > tab_jp1) {
+                tab->data[j] = tab_jp1;
+                tab->data[j + 1] = tab_j;
+                done = 1;
+            }
+        }
+        if (done == 0) {
+            break;
+        }
+    }
+}
+
+/* vim: set ts=4 sw=4 et: */