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