From: Ben Pfaff Date: Tue, 25 Dec 2018 03:32:17 +0000 (-0800) Subject: bt, abt: Add initialization and iteration macros. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=46d36a11d006a565caf073f825016360cd74f5a4;p=pspp bt, abt: Add initialization and iteration macros. --- diff --git a/src/language/stats/kruskal-wallis.c b/src/language/stats/kruskal-wallis.c index 65ce0868ad..24c369a93b 100644 --- a/src/language/stats/kruskal-wallis.c +++ b/src/language/stats/kruskal-wallis.c @@ -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); diff --git a/src/libpspp/abt.h b/src/libpspp/abt.h index f97d957e52..fced0179ae 100644 --- a/src/libpspp/abt.h +++ b/src/libpspp/abt.h @@ -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 @@ -149,12 +149,16 @@ #include #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 */ diff --git a/src/libpspp/bt.h b/src/libpspp/bt.h index 41fc5d44b0..7faed67a5d 100644 --- a/src/libpspp/bt.h +++ b/src/libpspp/bt.h @@ -27,12 +27,16 @@ #include #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 */ diff --git a/src/libpspp/range-map.c b/src/libpspp/range-map.c index 2af9405a86..104566bca8 100644 --- a/src/libpspp/range-map.c +++ b/src/libpspp/range-map.c @@ -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); } diff --git a/src/libpspp/range-set.h b/src/libpspp/range-set.h index 64d888f7f2..636fba8166 100644 --- a/src/libpspp/range-set.h +++ b/src/libpspp/range-set.h @@ -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, diff --git a/src/libpspp/range-tower.c b/src/libpspp/range-tower.c index 8f77317ad1..60b6cd1666 100644 --- a/src/libpspp/range-tower.c +++ b/src/libpspp/range-tower.c @@ -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 diff --git a/src/libpspp/range-tower.h b/src/libpspp/range-tower.h index 98c25183b5..7e335714d1 100644 --- a/src/libpspp/range-tower.h +++ b/src/libpspp/range-tower.h @@ -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); } diff --git a/src/libpspp/tower.c b/src/libpspp/tower.c index c7c36ab16d..39f9d23ce7 100644 --- a/src/libpspp/tower.c +++ b/src/libpspp/tower.c @@ -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. */ diff --git a/tests/libpspp/abt-test.c b/tests/libpspp/abt-test.c index 3e68637a5b..8088f19cd9 100644 --- a/tests/libpspp/abt-test.c +++ b/tests/libpspp/abt-test.c @@ -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 diff --git a/tests/libpspp/bt-test.c b/tests/libpspp/bt-test.c index 42cfbeabef..35fbad6535 100644 --- a/tests/libpspp/bt-test.c +++ b/tests/libpspp/bt-test.c @@ -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 diff --git a/tests/libpspp/range-tower-test.c b/tests/libpspp/range-tower-test.c index 3939725cc2..dce8f8b1e1 100644 --- a/tests/libpspp/range-tower-test.c +++ b/tests/libpspp/range-tower-test.c @@ -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]) {