Delete trailing whitespace at end of lines.
[pspp-builds.git] / src / data / case-ordering.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20
21 #include <data/case-ordering.h>
22
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <data/dictionary.h>
28 #include <data/variable.h>
29
30 #include "xalloc.h"
31
32 /* One key used for sorting. */
33 struct sort_key
34   {
35     const struct variable *var;       /* Variable. */
36     enum sort_direction dir;    /* Sort direction. */
37   };
38
39 /* A set of criteria for ordering cases. */
40 struct case_ordering
41   {
42     size_t value_cnt;           /* Number of `union value's per case. */
43
44     /* Sort keys. */
45     struct sort_key *keys;
46     size_t key_cnt;
47   };
48
49 struct case_ordering *
50 case_ordering_create (const struct dictionary *dict)
51 {
52   struct case_ordering *co = xmalloc (sizeof *co);
53   co->value_cnt = dict_get_next_value_idx (dict);
54   co->keys = NULL;
55   co->key_cnt = 0;
56   return co;
57 }
58
59 struct case_ordering *
60 case_ordering_clone (const struct case_ordering *orig)
61 {
62   struct case_ordering *co = xmalloc (sizeof *co);
63   co->value_cnt = orig->value_cnt;
64   co->keys = xmemdup (orig->keys, orig->key_cnt * sizeof *orig->keys);
65   co->key_cnt = orig->key_cnt;
66   return co;
67 }
68
69 void
70 case_ordering_destroy (struct case_ordering *co)
71 {
72   if (co != NULL)
73     {
74       free (co->keys);
75       free (co);
76     }
77 }
78
79 size_t
80 case_ordering_get_value_cnt (const struct case_ordering *co)
81 {
82   return co->value_cnt;
83 }
84
85 int
86 case_ordering_compare_cases (const struct ccase *a, const struct ccase *b,
87                              const struct case_ordering *co)
88 {
89   size_t i;
90
91   for (i = 0; i < co->key_cnt; i++)
92     {
93       const struct sort_key *key = &co->keys[i];
94       int width = var_get_width (key->var);
95       int cmp;
96
97       if (width == 0)
98         {
99           double af = case_num (a, key->var);
100           double bf = case_num (b, key->var);
101           if (af == bf)
102             continue;
103           cmp = af > bf ? 1 : -1;
104         }
105       else
106         {
107           const char *as = case_str (a, key->var);
108           const char *bs = case_str (b, key->var);
109           cmp = memcmp (as, bs, width);
110           if (cmp == 0)
111             continue;
112         }
113
114       return key->dir == SRT_ASCEND ? cmp : -cmp;
115     }
116   return 0;
117 }
118
119 bool
120 case_ordering_add_var (struct case_ordering *co,
121                        const struct variable *var, enum sort_direction dir)
122 {
123   struct sort_key *key;
124   size_t i;
125
126   for (i = 0; i < co->key_cnt; i++)
127     if (var_get_case_index (co->keys[i].var) == var_get_case_index (var))
128       return false;
129
130   co->keys = xnrealloc (co->keys, co->key_cnt + 1, sizeof *co->keys);
131   key = &co->keys[co->key_cnt++];
132   key->var = var;
133   key->dir = dir;
134   return true;
135 }
136
137 size_t
138 case_ordering_get_var_cnt (const struct case_ordering *co)
139 {
140   return co->key_cnt;
141 }
142
143 const struct variable *
144 case_ordering_get_var (const struct case_ordering *co, size_t idx)
145 {
146   assert (idx < co->key_cnt);
147   return co->keys[idx].var;
148 }
149
150 enum sort_direction
151 case_ordering_get_direction (const struct case_ordering *co, size_t idx)
152 {
153   assert (idx < co->key_cnt);
154   return co->keys[idx].dir;
155 }
156
157 void
158 case_ordering_get_vars (const struct case_ordering *co,
159                         const struct variable ***vars, size_t *var_cnt)
160 {
161   size_t i;
162
163   *var_cnt = co->key_cnt;
164   *vars = xnmalloc (*var_cnt, sizeof **vars);
165   for (i = 0; i < co->key_cnt; i++)
166     (*vars)[i] = co->keys[i].var;
167 }
168