case, caseproto: Implement save and load.
[pspp] / src / data / caseproto.h
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009, 2011, 2013 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 #ifndef DATA_CASEPROTO_H
18 #define DATA_CASEPROTO_H 1
19
20 #include <assert.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdlib.h>
24
25 #include "data/value.h"
26 #include "libpspp/cast.h"
27 #include "libpspp/compiler.h"
28 #include "libpspp/pxd.h"
29
30 /* Case prototype.
31
32    A case prototype specifies the number and type of the values
33    in a case.  It is essentially an array of integers, where the
34    array index is an index into a case and each element
35    represents the width of a value in a case.  Valid widths are:
36
37        * 0, indicating a numeric value.
38
39        * A positive integer between 1 and 32767, indicating the
40          size in bytes of a string value.
41
42        * -1, indicating that the value at this index in the case
43          is not used at all.  (This is rarely useful.)
44
45    Case prototypes are reference counted.  A newly created case
46    prototype has a single owner (the code that created it),
47    represented by an initial reference count of 1.  Other code
48    that receives the case prototype may keep a virtual copy of it
49    by calling caseproto_ref, which increments the case
50    prototype's reference count.  When this is done, the case
51    prototype becomes shared between its original owner and each
52    piece of code that incremented the reference count.
53
54    Functions that modifying case prototypes automatically unshare
55    them as necessary.  All of these functions potentially move
56    the caseproto around in memory even when the case prototype is
57    not shared.  Thus it is very important that every caller of a
58    function that modifies a case prototype thereafter uses the returned
59    caseproto instead of the one passed in as an argument.
60
61    Only the case prototype code should refer to caseproto members
62    directly.  Other code should use the provided helper
63    functions. */
64 struct caseproto
65   {
66     size_t ref_cnt;             /* Reference count. */
67
68     /* Tracking of long string widths.  Lazily maintained: when
69        'long_strings' is null and 'n_long_strings' is nonzero,
70        the former must be regenerated. */
71     size_t *long_strings;       /* Array of indexes of long string widths. */
72     size_t n_long_strings;      /* Number of long string widths. */
73     struct pxd_object *pxd;     /* Saved copy. */
74
75     /* Widths. */
76     size_t n_widths;            /* Number of widths. */
77     size_t allocated_widths;    /* Space allocated for 'widths' array. */
78     short int widths[1];        /* Width of each case value. */
79   };
80
81 struct pool;
82
83 /* Creation and destruction. */
84 struct caseproto *caseproto_create (void) MALLOC_LIKE;
85 static inline struct caseproto *caseproto_ref (const struct caseproto *);
86 struct caseproto *caseproto_ref_pool (const struct caseproto *, struct pool *);
87 static inline void caseproto_unref (struct caseproto *);
88
89 /* Inspecting stored widths.  */
90 static inline int caseproto_get_width (const struct caseproto *, size_t idx);
91 static inline size_t caseproto_get_n_widths (const struct caseproto *);
92
93 /* Adding and removing widths. */
94 struct caseproto *caseproto_reserve (struct caseproto *, size_t n_widths)
95   WARN_UNUSED_RESULT;
96 struct caseproto *caseproto_add_width (struct caseproto *, int width)
97   WARN_UNUSED_RESULT;
98 struct caseproto *caseproto_set_width (struct caseproto *,
99                                        size_t idx, int width)
100   WARN_UNUSED_RESULT;
101 struct caseproto *caseproto_insert_width (struct caseproto *,
102                                           size_t before, int width)
103   WARN_UNUSED_RESULT;
104 struct caseproto *caseproto_remove_widths (struct caseproto *,
105                                            size_t idx, size_t cnt)
106   WARN_UNUSED_RESULT;
107 struct caseproto *caseproto_move_widths (struct caseproto *,
108                                          size_t old_start, size_t new_start,
109                                          size_t cnt)
110   WARN_UNUSED_RESULT;
111
112 /* Working with "union value" arrays. */
113 bool caseproto_needs_init_values (const struct caseproto *);
114 void caseproto_init_values (const struct caseproto *, union value[]);
115 bool caseproto_try_init_values (const struct caseproto *, union value[]);
116 void caseproto_reinit_values (const struct caseproto *old,
117                               const struct caseproto *new, union value[]);
118 void caseproto_destroy_values (const struct caseproto *, union value[]);
119
120 void caseproto_copy (const struct caseproto *, size_t idx, size_t count,
121                      union value *dst, const union value *src);
122
123 /* Inspecting the cache of long string widths.
124
125    (These functions are useful for allocating cases, which
126    requires allocating a block memory for each long string value
127    in the case.) */
128 static inline size_t caseproto_get_n_long_strings (const struct caseproto *);
129 static inline size_t caseproto_get_long_string_idx (const struct caseproto *,
130                                                     size_t idx1);
131
132 /* For use in assertions. */
133 bool caseproto_range_is_valid (const struct caseproto *,
134                                size_t ofs, size_t count);
135 bool caseproto_is_conformable (const struct caseproto *a,
136                                const struct caseproto *b);
137 bool caseproto_equal (const struct caseproto *a, size_t a_start,
138                       const struct caseproto *b, size_t b_start,
139                       size_t n);
140
141 /* Save and load. */
142 struct pxd_object *caseproto_save (const struct caseproto *, struct pxd *);
143 struct caseproto *caseproto_load (struct pxd_object *, const struct pxd *);
144 \f
145 /* Creation and destruction. */
146
147 void caseproto_free__ (struct caseproto *);
148
149 /* Increments case prototype PROTO's reference count and returns
150    PROTO.  Afterward, PROTO is shared among its reference count
151    holders. */
152 static inline struct caseproto *
153 caseproto_ref (const struct caseproto *proto_)
154 {
155   struct caseproto *proto = CONST_CAST (struct caseproto *, proto_);
156   proto->ref_cnt++;
157   return proto;
158 }
159
160 /* Decrements case prototype PROTO's reference count.  Frees
161    PROTO if its reference count drops to 0.
162
163    If PROTO is a null pointer, this function has no effect. */
164 static inline void
165 caseproto_unref (struct caseproto *proto)
166 {
167   if (proto != NULL && !--proto->ref_cnt)
168     caseproto_free__ (proto);
169 }
170 \f
171 /* Inspecting stored widths.  */
172
173 /* Returns case prototype PROTO's width with the given IDX.  IDX
174    must be less than caseproto_get_n_widths(PROTO). */
175 static inline int
176 caseproto_get_width (const struct caseproto *proto, size_t idx)
177 {
178   assert (idx < proto->n_widths);
179   return proto->widths[idx];
180 }
181
182 /* Returns the number of widths in case prototype PROTO. */
183 static inline size_t
184 caseproto_get_n_widths (const struct caseproto *proto)
185 {
186   return proto->n_widths;
187 }
188 \f
189 /* Inspecting the cache of long string widths. */
190
191 void caseproto_refresh_long_string_cache__ (const struct caseproto *);
192
193 /* Returns the number of long string widths in PROTO; that is,
194    the number of widths in PROTO that are greater than to
195    MAX_SHORT_STRING. */
196 static inline size_t
197 caseproto_get_n_long_strings (const struct caseproto *proto)
198 {
199   return proto->n_long_strings;
200 }
201
202 /* Given long string width IDX1, returns a value IDX2 for which
203    caseproto_get_width(PROTO, IDX2) will return a value greater
204    than MAX_SHORT_STRING.  IDX1 must be less than
205    caseproto_get_n_long_strings(PROTO), and IDX2 will be less
206    than caseproto_get_n_widths(PROTO). */
207 static inline size_t
208 caseproto_get_long_string_idx (const struct caseproto *proto, size_t idx1)
209 {
210   if (proto->long_strings == NULL)
211     caseproto_refresh_long_string_cache__ (proto);
212
213   assert (idx1 < proto->n_long_strings);
214   return proto->long_strings[idx1];
215 }
216
217 #endif /* data/caseproto.h */