124 |
struct sort_criteria *sort; /* Sort criteria. */ |
struct sort_criteria *sort; /* Sort criteria. */ |
125 |
struct variable **break_vars; /* Break variables. */ |
struct variable **break_vars; /* Break variables. */ |
126 |
size_t break_var_cnt; /* Number of break variables. */ |
size_t break_var_cnt; /* Number of break variables. */ |
127 |
union value *prev_break; /* Last values of break variables. */ |
struct ccase break_case; /* Last values of break variables. */ |
128 |
|
|
129 |
enum missing_treatment missing; /* How to treat missing values. */ |
enum missing_treatment missing; /* How to treat missing values. */ |
130 |
struct agr_var *agr_vars; /* First aggregate variable. */ |
struct agr_var *agr_vars; /* First aggregate variable. */ |
133 |
struct ccase agr_case; /* Aggregate case for output. */ |
struct ccase agr_case; /* Aggregate case for output. */ |
134 |
}; |
}; |
135 |
|
|
136 |
static void initialize_aggregate_info (struct agr_proc *); |
static void initialize_aggregate_info (struct agr_proc *, |
137 |
|
const struct ccase *); |
138 |
|
|
139 |
/* Prototypes. */ |
/* Prototypes. */ |
140 |
static int parse_aggregate_functions (struct agr_proc *); |
static int parse_aggregate_functions (struct agr_proc *); |
165 |
|
|
166 |
memset(&agr, 0 , sizeof (agr)); |
memset(&agr, 0 , sizeof (agr)); |
167 |
agr.missing = ITEMWISE; |
agr.missing = ITEMWISE; |
168 |
|
case_nullify (&agr.break_case); |
169 |
|
|
170 |
agr.dict = dict_create (); |
agr.dict = dict_create (); |
171 |
dict_set_label (agr.dict, dict_get_label (default_dict)); |
dict_set_label (agr.dict, dict_get_label (default_dict)); |
250 |
/* Initialize. */ |
/* Initialize. */ |
251 |
agr.case_cnt = 0; |
agr.case_cnt = 0; |
252 |
case_create (&agr.agr_case, dict_get_next_value_idx (agr.dict)); |
case_create (&agr.agr_case, dict_get_next_value_idx (agr.dict)); |
|
initialize_aggregate_info (&agr); |
|
253 |
|
|
254 |
/* Output to active file or external file? */ |
/* Output to active file or external file? */ |
255 |
if (out_file == NULL) |
if (out_file == NULL) |
656 |
if (agr->sort != NULL) |
if (agr->sort != NULL) |
657 |
sort_destroy_criteria (agr->sort); |
sort_destroy_criteria (agr->sort); |
658 |
free (agr->break_vars); |
free (agr->break_vars); |
659 |
free (agr->prev_break); |
case_destroy (&agr->break_case); |
660 |
for (iter = agr->agr_vars; iter; iter = next) |
for (iter = agr->agr_vars; iter; iter = next) |
661 |
{ |
{ |
662 |
next = iter->next; |
next = iter->next; |
694 |
aggregate_single_case (struct agr_proc *agr, |
aggregate_single_case (struct agr_proc *agr, |
695 |
const struct ccase *input, struct ccase *output) |
const struct ccase *input, struct ccase *output) |
696 |
{ |
{ |
697 |
/* The first case always begins a new break group. We also need to |
bool finished_group = false; |
698 |
preserve the values of the case for later comparison. */ |
|
699 |
if (agr->case_cnt++ == 0) |
if (agr->case_cnt++ == 0) |
700 |
|
initialize_aggregate_info (agr, input); |
701 |
|
else if (case_compare (&agr->break_case, input, |
702 |
|
agr->break_vars, agr->break_var_cnt)) |
703 |
{ |
{ |
704 |
int n_elem = 0; |
dump_aggregate_info (agr, output); |
705 |
|
finished_group = true; |
|
{ |
|
|
int i; |
|
|
|
|
|
for (i = 0; i < agr->break_var_cnt; i++) |
|
|
n_elem += agr->break_vars[i]->nv; |
|
|
} |
|
|
|
|
|
agr->prev_break = xmalloc (sizeof *agr->prev_break * n_elem); |
|
|
|
|
|
/* Copy INPUT into prev_break. */ |
|
|
{ |
|
|
union value *iter = agr->prev_break; |
|
|
int i; |
|
706 |
|
|
707 |
for (i = 0; i < agr->break_var_cnt; i++) |
initialize_aggregate_info (agr, input); |
|
{ |
|
|
struct variable *v = agr->break_vars[i]; |
|
|
|
|
|
if (v->type == NUMERIC) |
|
|
(iter++)->f = case_num (input, v->fv); |
|
|
else |
|
|
{ |
|
|
memcpy (iter->s, case_str (input, v->fv), v->width); |
|
|
iter += v->nv; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
accumulate_aggregate_info (agr, input); |
|
|
|
|
|
return 0; |
|
708 |
} |
} |
|
|
|
|
/* Compare the value of each break variable to the values on the |
|
|
previous case. */ |
|
|
{ |
|
|
union value *iter = agr->prev_break; |
|
|
int i; |
|
|
|
|
|
for (i = 0; i < agr->break_var_cnt; i++) |
|
|
{ |
|
|
struct variable *v = agr->break_vars[i]; |
|
|
|
|
|
switch (v->type) |
|
|
{ |
|
|
case NUMERIC: |
|
|
if (case_num (input, v->fv) != iter->f) |
|
|
goto not_equal; |
|
|
iter++; |
|
|
break; |
|
|
case ALPHA: |
|
|
if (memcmp (case_str (input, v->fv), iter->s, v->width)) |
|
|
goto not_equal; |
|
|
iter += v->nv; |
|
|
break; |
|
|
default: |
|
|
assert (0); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
accumulate_aggregate_info (agr, input); |
|
709 |
|
|
|
return 0; |
|
|
|
|
|
not_equal: |
|
|
/* The values of the break variable are different from the values on |
|
|
the previous case. That means that it's time to dump aggregate |
|
|
info. */ |
|
|
dump_aggregate_info (agr, output); |
|
|
initialize_aggregate_info (agr); |
|
710 |
accumulate_aggregate_info (agr, input); |
accumulate_aggregate_info (agr, input); |
711 |
|
return finished_group; |
|
/* Copy INPUT into prev_break. */ |
|
|
{ |
|
|
union value *iter = agr->prev_break; |
|
|
int i; |
|
|
|
|
|
for (i = 0; i < agr->break_var_cnt; i++) |
|
|
{ |
|
|
struct variable *v = agr->break_vars[i]; |
|
|
|
|
|
if (v->type == NUMERIC) |
|
|
(iter++)->f = case_num (input, v->fv); |
|
|
else |
|
|
{ |
|
|
memcpy (iter->s, case_str (input, v->fv), v->width); |
|
|
iter += v->nv; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return 1; |
|
712 |
} |
} |
713 |
|
|
714 |
/* Accumulates aggregation data from the case INPUT. */ |
/* Accumulates aggregation data from the case INPUT. */ |
895 |
|
|
896 |
for (i = 0; i < agr->break_var_cnt; i++) |
for (i = 0; i < agr->break_var_cnt; i++) |
897 |
{ |
{ |
898 |
int nv = agr->break_vars[i]->nv; |
struct variable *v = agr->break_vars[i]; |
899 |
memcpy (case_data_rw (output, value_idx), |
memcpy (case_data_rw (output, value_idx), |
900 |
&agr->prev_break[value_idx], |
case_data (&agr->break_case, v->fv), |
901 |
sizeof (union value) * nv); |
sizeof (union value) * v->nv); |
902 |
value_idx += nv; |
value_idx += v->nv; |
903 |
} |
} |
904 |
} |
} |
905 |
|
|
1015 |
|
|
1016 |
/* Resets the state for all the aggregate functions. */ |
/* Resets the state for all the aggregate functions. */ |
1017 |
static void |
static void |
1018 |
initialize_aggregate_info (struct agr_proc *agr) |
initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) |
1019 |
{ |
{ |
1020 |
struct agr_var *iter; |
struct agr_var *iter; |
1021 |
|
|
1022 |
|
case_destroy (&agr->break_case); |
1023 |
|
case_clone (&agr->break_case, input); |
1024 |
|
|
1025 |
for (iter = agr->agr_vars; iter; iter = iter->next) |
for (iter = agr->agr_vars; iter; iter = iter->next) |
1026 |
{ |
{ |
1027 |
iter->missing = 0; |
iter->missing = 0; |