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