6f53772688c3c1f29ba15cc0475735d0803762e4
[pspp-builds.git] / src / data / case.h
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2004, 2007, 2009 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_CASE_H
18 #define DATA_CASE_H 1
19
20 #include <limits.h>
21 #include <stddef.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <libpspp/compiler.h>
25 #include "value.h"
26
27 struct variable;
28
29 /* A count of cases or the index of a case within a collection of
30    them. */
31 #define CASENUMBER_MAX LONG_MAX
32 typedef long int casenumber;
33
34 /* Reference-counted case implementation.
35
36    A newly created case has a single owner (the code that created
37    it), represented by an initial reference count of 1.  Other
38    code that receives the case may keep a virtual copy of it by
39    calling case_ref, which increments the case's reference count.
40    When this is done, the case becomes shared between its
41    original owner and each piece of code that incremented the
42    reference count.
43
44    A shared case (one whose reference count is greater than 1)
45    must not be modified, because this would make the case change
46    in the view of every reference count holder, not just the one
47    that intended to change the case.  Because the purpose of
48    keeping the reference count is to make a virtual copy of the
49    case, this is undesirable behavior.  The case_unshare function
50    provides a solution, by making a new, unshared copy of a
51    shared case. */
52 struct ccase
53   {
54     size_t n_values;            /* Number of values. */
55     size_t ref_cnt;             /* Reference count. */
56     union value values[1];      /* Values. */
57   };
58
59 struct ccase *case_create (size_t n_values) MALLOC_LIKE;
60 struct ccase *case_try_create (size_t n_values) MALLOC_LIKE;
61
62 static inline struct ccase *case_unshare (struct ccase *) WARN_UNUSED_RESULT;
63 static inline struct ccase *case_ref (const struct ccase *);
64 static inline void case_unref (struct ccase *);
65 static inline bool case_is_shared (const struct ccase *);
66
67 static inline size_t case_get_value_cnt (const struct ccase *);
68
69 struct ccase *case_resize (struct ccase *, size_t new_cnt) WARN_UNUSED_RESULT;
70 struct ccase *case_unshare_and_resize (struct ccase *, size_t new_cnt)
71   WARN_UNUSED_RESULT;
72
73 void case_copy (struct ccase *dst, size_t dst_idx,
74                 const struct ccase *src, size_t src_idx,
75                 size_t cnt);
76
77 void case_copy_out (const struct ccase *,
78                     size_t start_idx, union value *, size_t n_values);
79 void case_copy_in (struct ccase *,
80                    size_t start_idx, const union value *, size_t n_values);
81
82 const union value *case_data (const struct ccase *, const struct variable *);
83 const union value *case_data_idx (const struct ccase *, size_t idx);
84 union value *case_data_rw (struct ccase *, const struct variable *);
85 union value *case_data_rw_idx (struct ccase *, size_t idx);
86
87 double case_num (const struct ccase *, const struct variable *);
88 double case_num_idx (const struct ccase *, size_t idx);
89
90 const char *case_str (const struct ccase *, const struct variable *);
91 const char *case_str_idx (const struct ccase *, size_t idx);
92
93 int case_compare (const struct ccase *, const struct ccase *,
94                   const struct variable *const *, size_t n_vars);
95 int case_compare_2dict (const struct ccase *, const struct ccase *,
96                         const struct variable *const *,
97                         const struct variable *const *,
98                         size_t n_vars);
99
100 const union value *case_data_all (const struct ccase *);
101 union value *case_data_all_rw (struct ccase *);
102 \f
103 struct ccase *case_unshare__ (struct ccase *);
104
105 /* If C is a shared case, that is, if it has a reference count
106    greater than 1, makes a new unshared copy and returns it,
107    decrementing C's reference count.  If C is not shared (its
108    reference count is 1), returns C.
109
110    This function should be used before attempting to modify any
111    of the data in a case that might be shared, e.g.:
112         c = case_unshare (c);              // Make sure that C is not shared.
113         case_data_rw (c, myvar)->f = 1;    // Modify data in C.
114 */
115 static inline struct ccase *
116 case_unshare (struct ccase *c)
117 {
118   if (case_is_shared (c))
119     c = case_unshare__ (c);
120   return c;
121 }
122
123 /* Increments case C's reference count and returns C.  Afterward,
124    case C is shared among its reference count holders. */
125 static inline struct ccase *
126 case_ref (const struct ccase *c_)
127 {
128   struct ccase *c = (struct ccase *) c_;
129   c->ref_cnt++;
130   return c;
131 }
132
133 /* Decrements case C's reference count.  Frees C if its
134    reference count drops to 0.
135
136    If C is a null pointer, this function has no effect. */
137 static inline void
138 case_unref (struct ccase *c)
139 {
140   if (c != NULL && !--c->ref_cnt)
141     free (c);
142 }
143
144 /* Returns true if case C is shared.  A case that is shared
145    cannot be modified directly.  Instead, an unshared copy must
146    first be made with case_unshare(). */
147 static inline bool
148 case_is_shared (const struct ccase *c)
149 {
150   return c->ref_cnt > 1;
151 }
152
153 /* Returns the number of union values in C. */
154 static inline size_t
155 case_get_value_cnt (const struct ccase *c)
156 {
157   return c->n_values;
158 }
159
160 #endif /* data/case.h */