pxd: initial work
[pspp] / src / data / vector.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2006, 2010, 2011, 2012  Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU 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, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "data/vector.h"
20
21 #include <stdlib.h>
22
23 #include "data/dictionary.h"
24 #include "data/identifier.h"
25 #include "data/variable.h"
26 #include "libpspp/assertion.h"
27 #include "libpspp/i18n.h"
28 #include "libpspp/pxd.h"
29 #include "libpspp/str.h"
30
31 #include "gl/xalloc.h"
32
33 /* Vector of variables. */
34 struct vector
35   {
36     char *name;                         /* Name. */
37     struct variable **vars;             /* Set of variables. */
38     size_t var_cnt;                     /* Number of variables. */
39   };
40
41 /* Checks that all the variables in VECTOR have consistent
42    width. */
43 static void
44 check_widths (const struct vector *vector)
45 {
46   int width = var_get_width (vector->vars[0]);
47   size_t i;
48
49   for (i = 1; i < vector->var_cnt; i++)
50     assert (width == var_get_width (vector->vars[i]));
51 }
52
53 /* Creates and returns a new vector with the given UTF-8 encoded NAME
54    that contains the VAR_CNT variables in VARS.
55    All variables in VARS must have the same type and width. */
56 struct vector *
57 vector_create (const char *name, struct variable **vars, size_t var_cnt)
58 {
59   struct vector *vector = xmalloc (sizeof *vector);
60
61   assert (var_cnt > 0);
62   assert (id_is_plausible (name, false));
63   vector->name = xstrdup (name);
64
65   vector->name = xstrdup (name);
66   vector->vars = xmemdup (vars, var_cnt * sizeof *vector->vars);
67   vector->var_cnt = var_cnt;
68   check_widths (vector);
69
70   return vector;
71 }
72
73 /* Creates and returns a new vector as a clone of OLD, but that
74    contains variables from NEW_DICT that are in the same position
75    as those in OLD are in OLD_DICT.
76    All variables in the new vector must have the same type and
77    width. */
78 struct vector *
79 vector_clone (const struct vector *old,
80               const struct dictionary *old_dict,
81               const struct dictionary *new_dict)
82 {
83   struct vector *new = xmalloc (sizeof *new);
84   size_t i;
85
86   new->name = xstrdup (old->name);
87   new->vars = xnmalloc (old->var_cnt, sizeof *new->vars);
88   new->var_cnt = old->var_cnt;
89   for (i = 0; i < new->var_cnt; i++)
90     {
91       assert (dict_contains_var (old_dict, old->vars[i]));
92       new->vars[i] = dict_get_var (new_dict,
93                                    var_get_dict_index (old->vars[i]));
94     }
95   check_widths (new);
96
97   return new;
98 }
99
100 /* Destroys VECTOR. */
101 void
102 vector_destroy (struct vector *vector)
103 {
104   free (vector->name);
105   free (vector->vars);
106   free (vector);
107 }
108
109 /* Returns VECTOR's name, as a UTF-8 encoded string. */
110 const char *
111 vector_get_name (const struct vector *vector)
112 {
113   return vector->name;
114 }
115
116 /* Returns the type of the variables in VECTOR. */
117 enum val_type vector_get_type (const struct vector *vector)
118 {
119   return var_get_type (vector->vars[0]);
120 }
121
122 /* Returns the variable in VECTOR with the given INDEX. */
123 struct variable *
124 vector_get_var (const struct vector *vector, size_t index)
125 {
126   assert (index < vector->var_cnt);
127   return vector->vars[index];
128 }
129
130 /* Returns the number of variables in VECTOR. */
131 size_t
132 vector_get_var_cnt (const struct vector *vector)
133 {
134   return vector->var_cnt;
135 }
136
137 /* Compares two pointers to vectors represented by A and B and
138    returns a strcmp()-type result. */
139 int
140 compare_vector_ptrs_by_name (const void *a_, const void *b_)
141 {
142   struct vector *const *pa = a_;
143   struct vector *const *pb = b_;
144   struct vector *a = *pa;
145   struct vector *b = *pb;
146
147   return utf8_strcasecmp (a->name, b->name);
148 }
149
150 struct pxd_object *
151 vector_save (const struct vector *vector, struct pxd *pxd)
152 {
153   struct pxd_builder b;
154   size_t i;
155
156   pxd_builder_init (&b, pxd);
157
158   pxd_builder_put_string (&b, vector->name);
159
160   pxd_builder_put_size_t (&b, vector->var_cnt);
161   for (i = 0; i < vector->var_cnt; i++)
162     pxd_builder_put_size_t (&b, var_get_dict_index (vector->vars[i]));
163
164   return pxd_builder_commit (&b);
165 }
166
167 struct vector *
168 vector_load (struct pxd_object *object, const struct pxd *pxd,
169              const struct dictionary *dict)
170 {
171   struct pxd_parser p;
172   struct vector *vector;
173   size_t i;
174
175   vector = xzalloc (sizeof *vector);
176
177   pxd_parser_init (&p, object, pxd);
178
179   vector->name = pxd_parser_get_string (&p);
180
181   vector->var_cnt = pxd_parser_get_size_t (&p);
182   vector->vars = xmalloc (vector->var_cnt * sizeof *vector->vars);
183   for (i = 0; i < vector->var_cnt; i++)
184     vector->vars[i] = dict_get_var (dict, pxd_parser_get_size_t (&p));
185
186   return vector;
187 }