From a1fa0ecf5dd9255226f619b6ae3f933304e7d440 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 4 Jul 2022 13:19:11 -0700 Subject: [PATCH] pcompute string ranges --- src/language/stats/ctables.c | 47 ++++++++++++++++++++++----------- tests/language/stats/ctables.at | 9 ++++--- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index 5df2435b7b..e745794781 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -294,7 +294,8 @@ struct ctables_pcexpr CTPO_CONSTANT, /* 5 */ CTPO_CAT_NUMBER, /* [5] */ CTPO_CAT_STRING, /* ["STRING"] */ - CTPO_CAT_RANGE, /* [LO THRU 5] */ + CTPO_CAT_NRANGE, /* [LO THRU 5] */ + CTPO_CAT_SRANGE, /* ["A" THRU "B"] */ CTPO_CAT_MISSING, /* MISSING */ CTPO_CAT_OTHERNM, /* OTHERNM */ CTPO_CAT_SUBTOTAL, /* SUBTOTAL */ @@ -318,8 +319,11 @@ struct ctables_pcexpr /* CTPO_CAT_STRING, in dictionary encoding. */ struct substring string; - /* CTPO_CAT_RANGE. */ - double range[2]; + /* CTPO_CAT_NRANGE. */ + double nrange[2]; + + /* CTPO_CAT_SRANGE. */ + struct substring srange[2]; /* CTPO_CAT_SUBTOTAL. */ size_t subtotal_index; @@ -1599,10 +1603,17 @@ ctables_find_category_for_postcompute (const struct ctables_categories *cats, best = cat; break; - case CTPO_CAT_RANGE: + case CTPO_CAT_NRANGE: if (cat->type == CCT_NRANGE - && cat->nrange[0] == e->range[0] - && cat->nrange[1] == e->range[1]) + && cat->nrange[0] == e->nrange[0] + && cat->nrange[1] == e->nrange[1]) + best = cat; + break; + + case CTPO_CAT_SRANGE: + if (cat->type == CCT_SRANGE + && nullable_substring_equal (&cat->srange[0], &e->srange[0]) + && nullable_substring_equal (&cat->srange[1], &e->srange[1])) best = cat; break; @@ -1657,7 +1668,7 @@ ctables_recursive_check_postcompute (const struct ctables_pcexpr *e, { case CTPO_CAT_NUMBER: case CTPO_CAT_STRING: - case CTPO_CAT_RANGE: + case CTPO_CAT_NRANGE: case CTPO_CAT_MISSING: case CTPO_CAT_OTHERNM: case CTPO_CAT_SUBTOTAL: @@ -3640,7 +3651,8 @@ ctables_pcexpr_evaluate (const struct ctables_pcexpr_evaluate_ctx *ctx, case CTPO_CONSTANT: return e->number; - case CTPO_CAT_RANGE: + case CTPO_CAT_NRANGE: + case CTPO_CAT_SRANGE: { struct ctables_cell_value cv = { .category = ctables_find_category_for_postcompute (ctx->cats, e) @@ -4666,6 +4678,11 @@ ctables_pcexpr_destroy (struct ctables_pcexpr *e) ss_dealloc (&e->string); break; + case CTPO_CAT_SRANGE: + for (size_t i = 0; i < 2; i++) + ss_dealloc (&e->srange[i]); + break; + case CTPO_ADD: case CTPO_SUB: case CTPO_MUL: @@ -4678,7 +4695,7 @@ ctables_pcexpr_destroy (struct ctables_pcexpr *e) case CTPO_CONSTANT: case CTPO_CAT_NUMBER: - case CTPO_CAT_RANGE: + case CTPO_CAT_NRANGE: case CTPO_CAT_MISSING: case CTPO_CAT_OTHERNM: case CTPO_CAT_SUBTOTAL: @@ -4778,11 +4795,11 @@ static struct ctables_pcexpr *ctable_pcexpr_parse_add (struct lexer *, struct dictionary *); static struct ctables_pcexpr -ctpo_cat_range (double low, double high) +ctpo_cat_nrange (double low, double high) { return (struct ctables_pcexpr) { - .op = CTPO_CAT_RANGE, - .range = { low, high }, + .op = CTPO_CAT_NRANGE, + .nrange = { low, high }, }; } @@ -4824,7 +4841,7 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict) { if (!lex_force_match_id (lexer, "THRU") || lex_force_num (lexer)) return false; - e = ctpo_cat_range (-DBL_MAX, lex_number (lexer)); + e = ctpo_cat_nrange (-DBL_MAX, lex_number (lexer)); lex_get (lexer); } else if (lex_is_number (lexer)) @@ -4834,12 +4851,12 @@ ctable_pcexpr_parse_primary (struct lexer *lexer, struct dictionary *dict) if (lex_match_id (lexer, "THRU")) { if (lex_match_id (lexer, "HI")) - e = ctpo_cat_range (number, DBL_MAX); + e = ctpo_cat_nrange (number, DBL_MAX); else { if (!lex_force_num (lexer)) return false; - e = ctpo_cat_range (number, lex_number (lexer)); + e = ctpo_cat_nrange (number, lex_number (lexer)); lex_get (lexer); } } diff --git a/tests/language/stats/ctables.at b/tests/language/stats/ctables.at index 124b73938f..3b20068144 100644 --- a/tests/language/stats/ctables.at +++ b/tests/language/stats/ctables.at @@ -15,8 +15,7 @@ dnl - CATEGORIES: dnl * Data-dependent sorting. dnl - PCOMPUTE: dnl * multi-dimensional (multiple CCT_POSTCOMPUTE in one cell -dnl * MISSING, OTHERNM -dnl * strings +dnl * dates dnl dnl Features not yet tested: dnl - Parsing (positive and negative) @@ -25,8 +24,6 @@ dnl - Testing details of missing value handling in summaries. dnl - test CLABELS ROWLABELS=LAYER. dnl - Test VLABELS. dnl - Test WEIGHT and adjustment weights. -dnl - Test PCOMPUTE and PPROPERTIES. -dnl * PCOMPUTE for more than one kind of summary (e.g. [COUNT, ROWPCT]). dnl - EMPTY=INCLUDE For string ranges. dnl - Summary functions: dnl * Separate summary functions for totals and subtotals. @@ -44,6 +41,10 @@ dnl - HIDESMALLCOUNTS. dnl - Date/time variables and values dnl - Special formats for summary functions: NEGPAREN, NEQUAL, PAREN, PCTPAREN. dnl - TITLES: )DATE, )TIME, )TABLE. +dnl - Test PCOMPUTE: +dnl * PCOMPUTE for more than one kind of summary (e.g. [COUNT, ROWPCT]). +dnl * MISSING, OTHERNM +dnl * strings and string ranges dnl - PPROPERTIES: dnl * )LABEL[N]. dnl -- 2.30.2