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