bt, abt: Add initialization and iteration macros.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 25 Dec 2018 03:32:17 +0000 (19:32 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 25 Dec 2018 17:44:35 +0000 (09:44 -0800)
src/language/stats/kruskal-wallis.c
src/libpspp/abt.h
src/libpspp/bt.h
src/libpspp/range-map.c
src/libpspp/range-set.h
src/libpspp/range-tower.c
src/libpspp/range-tower.h
src/libpspp/tower.c
tests/libpspp/abt-test.c
tests/libpspp/bt-test.c
tests/libpspp/range-tower-test.c

index 65ce0868ad722cdc0184183ca0fac94f2a30056f..24c369a93b7fd69051adff5967ef9418f2bbe954 100644 (file)
@@ -74,8 +74,8 @@ compare_rank_entries_3way (const struct bt_node *a,
                            const void *aux)
 {
   const struct variable *var = aux;
-  const struct rank_entry *rea = bt_data (a, struct rank_entry, btn);
-  const struct rank_entry *reb = bt_data (b, struct rank_entry, btn);
+  const struct rank_entry *rea = BT_DATA (a, struct rank_entry, btn);
+  const struct rank_entry *reb = BT_DATA (b, struct rank_entry, btn);
 
   return value_compare_3way (&rea->group, &reb->group, var_get_width (var));
 }
@@ -281,7 +281,6 @@ show_ranks_box (const struct n_sample_test *nst, const struct kw *kw, int n_grou
     {
       int tot = 0;
       struct rank_entry *re_x;
-      struct bt_node *bt_n = NULL;
       struct bt bt;
 
       if (i > 0)
@@ -299,13 +298,9 @@ show_ranks_box (const struct n_sample_test *nst, const struct kw *kw, int n_grou
         }
 
       /* Report the rank entries in sorted order. */
-      for (bt_n = bt_first (&bt);
-           bt_n != NULL;
-           bt_n = bt_next (&bt, bt_n) )
+      const struct rank_entry *re;
+      BT_FOR_EACH (re, struct rank_entry, btn, &bt)
         {
-          const struct rank_entry *re =
-            bt_data (bt_n, const struct rank_entry, btn);
-
          struct string str;
          ds_init_empty (&str);
 
index f97d957e5251c70aeb55190f4b313b6eefea0799..fced0179ae6a71c688c49d0c061721fe06ad29d9 100644 (file)
@@ -87,7 +87,7 @@
      static struct element *
      node_to_element (const struct abt_node *node)
      {
-       return abt_data (node, struct element, node);
+       return ABT_DATA (node, struct element, node);
      }
 
      // Compares the DATA values in A and B and returns a
 #include <stddef.h>
 #include "libpspp/cast.h"
 
-/* Returns the data structure corresponding to the given NODE,
-   assuming that NODE is embedded as the given MEMBER name in
-   data type STRUCT. */
-#define abt_data(NODE, STRUCT, MEMBER)                          \
-        (CHECK_POINTER_HAS_TYPE (NODE, struct abt_node *),      \
-         UP_CAST (NODE, STRUCT, MEMBER))
+/* Returns the data structure corresponding to the given NODE, assuming that
+   NODE is embedded as the given MEMBER name in data type STRUCT.  NODE must
+   not be a null pointer. */
+#define ABT_DATA(NODE, STRUCT, MEMBER)                   \
+  (CHECK_POINTER_HAS_TYPE (NODE, struct abt_node *),     \
+   UP_CAST (NODE, STRUCT, MEMBER))
+
+/* Like ABT_DATA, except that a null NODE yields a null pointer result. */
+#define ABT_NULLABLE_DATA(NODE, STRUCT, MEMBER) \
+  ((STRUCT *) abt_nullable_data__ (NODE, offsetof (STRUCT, MEMBER)))
 
 /* Node in an augmented binary tree. */
 struct abt_node
@@ -183,6 +187,8 @@ struct abt
     abt_reaugment_func *reaugment; /* To augment a node using its children. */
     const void *aux;               /* Auxiliary data. */
   };
+#define ABT_INITIALIZER(COMPARE, REAUGMENT, AUX) \
+  { .compare = COMPARE, .reaugment = REAUGMENT, .aux = AUX }
 
 void abt_init (struct abt *, abt_compare_func *, abt_reaugment_func *,
                const void *aux);
@@ -206,6 +212,28 @@ void abt_reaugmented (const struct abt *, struct abt_node *);
 struct abt_node *abt_changed (struct abt *, struct abt_node *);
 void abt_moved (struct abt *, struct abt_node *);
 
+/* Convenience macros for iteration.
+
+   These macros automatically use ABT_DATA to obtain the data elements that
+   encapsulate abt nodes, which often saves typing and can make code easier to
+   read.  Refer to the large comment near the top of this file for an example.
+
+   These macros evaluate their arguments many times. */
+#define ABT_FIRST(STRUCT, MEMBER, ABT)                        \
+  ABT_NULLABLE_DATA (abt_first (ABT), STRUCT, MEMBER)
+#define ABT_NEXT(DATA, STRUCT, MEMBER, ABT)                           \
+  ABT_NULLABLE_DATA (abt_next (ABT, &(DATA)->MEMBER), STRUCT, MEMBER)
+#define ABT_FOR_EACH(DATA, STRUCT, MEMBER, ABT)       \
+  for ((DATA) = ABT_FIRST (STRUCT, MEMBER, ABT);      \
+       (DATA) != NULL;                                  \
+       (DATA) = ABT_NEXT (DATA, STRUCT, MEMBER, ABT))
+#define ABT_FOR_EACH_SAFE(DATA, NEXT, STRUCT, MEMBER, ABT)    \
+  for ((DATA) = ABT_FIRST (STRUCT, MEMBER, ABT);              \
+       ((DATA) != NULL                                          \
+        ? ((NEXT) = ABT_NEXT (DATA, STRUCT, MEMBER, ABT), 1)  \
+        : 0);                                                   \
+       (DATA) = (NEXT))
+
 /* Returns true if ABT contains no nodes, false if ABT contains at least one
    node. */
 static inline bool
@@ -214,4 +242,12 @@ abt_is_empty (const struct abt *abt)
   return abt->root == NULL;
 }
 
+/* Helper for ABT_NULLABLE_DATA (to avoid evaluating its NODE argument more
+   than once).  */
+static inline void *
+abt_nullable_data__ (struct abt_node *node, size_t member_offset)
+{
+  return node != NULL ? (char *) node - member_offset : NULL;
+}
+
 #endif /* libpspp/abt.h */
index 41fc5d44b0a3bc27ee23277ea2fc5abb27764398..7faed67a5df56c022d6abcdad4f4e7ff981b5c02 100644 (file)
 #include <stddef.h>
 #include "libpspp/cast.h"
 
-/* Returns the data structure corresponding to the given NODE,
-   assuming that NODE is embedded as the given MEMBER name in
-   data type STRUCT. */
-#define bt_data(NODE, STRUCT, MEMBER)                           \
-        (CHECK_POINTER_HAS_TYPE (NODE, struct bt_node *),       \
-         UP_CAST (NODE, STRUCT, MEMBER))
+/* Returns the data structure corresponding to the given NODE, assuming that
+   NODE is embedded as the given MEMBER name in data type STRUCT.  NODE must
+   not be a null pointer. */
+#define BT_DATA(NODE, STRUCT, MEMBER)                   \
+  (CHECK_POINTER_HAS_TYPE (NODE, struct bt_node *),     \
+   UP_CAST (NODE, STRUCT, MEMBER))
+
+/* Like BT_DATA, except that a null NODE yields a null pointer result. */
+#define BT_NULLABLE_DATA(NODE, STRUCT, MEMBER) \
+  ((STRUCT *) bt_nullable_data__ (NODE, offsetof (STRUCT, MEMBER)))
 
 /* Node in a balanced binary tree. */
 struct bt_node
@@ -56,6 +60,7 @@ struct bt
     size_t size;                /* Current node count. */
     size_t max_size;            /* Max size since last complete rebalance. */
   };
+#define BT_INITIALIZER(COMPARE, AUX) { .compare = COMPARE, .aux = AUX }
 
 void bt_init (struct bt *, bt_compare_func *, const void *aux);
 
@@ -75,6 +80,28 @@ struct bt_node *bt_prev (const struct bt *, const struct bt_node *);
 struct bt_node *bt_changed (struct bt *, struct bt_node *);
 void bt_moved (struct bt *, struct bt_node *);
 
+/* Convenience macros for iteration.
+
+   These macros automatically use BT_DATA to obtain the data elements that
+   encapsulate bt nodes, which often saves typing and can make code easier to
+   read.  Refer to the large comment near the top of this file for an example.
+
+   These macros evaluate their arguments many times. */
+#define BT_FIRST(STRUCT, MEMBER, BT)                        \
+  BT_NULLABLE_DATA (bt_first (BT), STRUCT, MEMBER)
+#define BT_NEXT(DATA, STRUCT, MEMBER, BT)                           \
+  BT_NULLABLE_DATA (bt_next (BT, &(DATA)->MEMBER), STRUCT, MEMBER)
+#define BT_FOR_EACH(DATA, STRUCT, MEMBER, BT)       \
+  for ((DATA) = BT_FIRST (STRUCT, MEMBER, BT);      \
+       (DATA) != NULL;                                  \
+       (DATA) = BT_NEXT (DATA, STRUCT, MEMBER, BT))
+#define BT_FOR_EACH_SAFE(DATA, NEXT, STRUCT, MEMBER, BT)    \
+  for ((DATA) = BT_FIRST (STRUCT, MEMBER, BT);              \
+       ((DATA) != NULL                                          \
+        ? ((NEXT) = BT_NEXT (DATA, STRUCT, MEMBER, BT), 1)  \
+        : 0);                                                   \
+       (DATA) = (NEXT))
+
 /* Returns the number of nodes currently in BT. */
 static inline size_t bt_count (const struct bt *bt)
 {
@@ -88,4 +115,12 @@ static inline bool bt_is_empty (const struct bt *bt)
   return bt->size == 0;
 }
 
+/* Helper for BT_NULLABLE_DATA (to avoid evaluating its NODE argument more than
+   once).  */
+static inline void *
+bt_nullable_data__ (struct bt_node *node, size_t member_offset)
+{
+  return node != NULL ? (char *) node - member_offset : NULL;
+}
+
 #endif /* libpspp/bt.h */
index 2af9405a869393e2ca7a7ab852348a98e2d5ab7d..104566bca8e2463469dc36805af77ce85e8bf98d 100644 (file)
@@ -114,7 +114,7 @@ static struct range_map_node *
 bt_to_range_map_node (const struct bt_node *bt_node)
 {
   return (bt_node != NULL
-          ? bt_data (bt_node, struct range_map_node, bt_node)
+          ? BT_DATA (bt_node, struct range_map_node, bt_node)
           : NULL);
 }
 
index 64d888f7f2cc316b2259062369b3793b5c624137..636fba8166c1b146cb1ed246352cdba1f30a9d24 100644 (file)
@@ -185,7 +185,7 @@ range_set_node_get_width (const struct range_set_node *node)
 static inline struct range_set_node *
 range_set_node_from_bt__ (const struct bt_node *bt_node)
 {
-  return bt_node ? bt_data (bt_node, struct range_set_node, bt_node) : NULL;
+  return bt_node ? BT_DATA (bt_node, struct range_set_node, bt_node) : NULL;
 }
 
 /* Returns the next range_set_node in RS after NODE,
index 8f77317ad1f23b066b563091bddc35ed28de1271..60b6cd1666afad9a108011b2c8af6dfae589ae30 100644 (file)
@@ -47,7 +47,7 @@ print_structure (const struct abt_node *node_)
 
   if (node_ == NULL)
     return;
-  node = abt_data (node_, struct range_tower_node, abt_node);
+  node = ABT_DATA (node_, struct range_tower_node, abt_node);
   printf ("%lu+%lu/%d", node->n_zeros, node->n_ones, node->abt_node.level);
   if (node->abt_node.down[0] || node->abt_node.down[1])
     {
@@ -78,7 +78,7 @@ print_regions (const char *title, const struct range_tower *rt)
 static struct range_tower_node *
 range_tower_node_from_abt_node (const struct abt_node *abt_node)
 {
-  return abt_data (abt_node, struct range_tower_node, abt_node);
+  return ABT_DATA (abt_node, struct range_tower_node, abt_node);
 }
 
 /* Returns the total width (zeros and ones) of the nodes in the subtree rooted
index 98c25183b5ade504c5a4f4a96c07bb100c017826..7e335714d148374cdfe010b59b35523bee650edd 100644 (file)
@@ -129,7 +129,7 @@ static inline bool
 range_tower_is_empty (const struct range_tower *rs)
 {
   const struct range_tower_node *node =
-    abt_data (rs->abt.root, struct range_tower_node, abt_node);
+    ABT_DATA (rs->abt.root, struct range_tower_node, abt_node);
 
   return node->n_zeros == ULONG_MAX;
 }
@@ -205,7 +205,7 @@ static inline struct range_tower_node *
 range_tower_node_from_abt__ (const struct abt_node *abt_node)
 {
   return (abt_node
-          ? abt_data (abt_node, struct range_tower_node, abt_node)
+          ? ABT_DATA (abt_node, struct range_tower_node, abt_node)
           : NULL);
 }
 
index c7c36ab16de922ca8771de967c66dc76f1c0674b..39f9d23ce7a36d51fc959c218b0153fc5b83008f 100644 (file)
@@ -294,7 +294,7 @@ tower_prev (const struct tower *t, const struct tower_node *node)
 static struct tower_node *
 abt_to_tower_node (const struct abt_node *abt_node)
 {
-  return abt_data (abt_node, struct tower_node, abt_node);
+  return ABT_DATA (abt_node, struct tower_node, abt_node);
 }
 
 /* Returns the tower node corresponding to the given ABT_NODE. */
index 3e68637a5bee3b38eec64011d5f7df87d43bccf2..8088f19cd93dcc188c7be9cf345fde40b1620eee 100644 (file)
@@ -119,7 +119,7 @@ static int aux_data;
 static struct element *
 abt_node_to_element (const struct abt_node *node)
 {
-  return abt_data (node, struct element, node);
+  return ABT_DATA (node, struct element, node);
 }
 
 /* Compares the `x' values in A and B and returns a strcmp-type
index 42cfbeabef429044095ceeeb41b277065fb59aff..35fbad653586e534737e382b1123242a5aacac88 100644 (file)
@@ -118,7 +118,7 @@ static int aux_data;
 static struct element *
 bt_node_to_element (const struct bt_node *node)
 {
-  return bt_data (node, struct element, node);
+  return BT_DATA (node, struct element, node);
 }
 
 /* Compares the `x' values in A and B and returns a strcmp-type
index 3939725cc208022c73f45094ece1ed5507ca76ae..dce8f8b1e10bca9717c7a907c0a8bd72c3fdf9f0 100644 (file)
@@ -165,7 +165,7 @@ print_structure (const struct abt_node *node_)
 
   if (node_ == NULL)
     return;
-  node = abt_data (node_, struct range_tower_node, abt_node);
+  node = ABT_DATA (node_, struct range_tower_node, abt_node);
   printf ("%lu+%lu/%d", node->n_zeros, node->n_ones, node->abt_node.level);
   if (node->abt_node.down[0] || node->abt_node.down[1])
     {