1 /****************************************************************************
2  * Copyright (C) 2012 by Matteo Franchin                                    *
3  *                                                                          *
4  * This file is part of Box.                                                *
5  *                                                                          *
6  *   Box is free software: you can redistribute it and/or modify it         *
7  *   under the terms of the GNU Lesser General Public License as published  *
8  *   by the Free Software Foundation, either version 3 of the License, or   *
9  *   (at your option) any later version.                                    *
10  *                                                                          *
11  *   Box is distributed in the hope that it will be useful,                 *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14  *   GNU Lesser General Public License for more details.                    *
15  *                                                                          *
16  *   You should have received a copy of the GNU Lesser General Public       *
17  *   License along with Box.  If not, see <http://www.gnu.org/licenses/>.   *
18  ****************************************************************************/
19 
20 /**
21  * @file obj.h
22  * @brief Definition of object allocation and managig functions.
23  *
24  * This module defines basic functions to allocate Box objects and manage
25  * them.
26  */
27 
28 #ifndef _BOX_OBJ_H
29 #  define _BOX_OBJ_H
30 
31 #include <box/types.h>
32 #include <box/exception.h>
33 
34 /**
35  * @brief Initialize a subtype.
36  *
37  * @param st Pointer to a region of memory ready to contain a #BoxSubtype
38  *   object.
39  */
40 BOXEXPORT void
41 BoxSubtype_Init(BoxSubtype *st);
42 
43 /**
44  * @brief Finalize a subtype.
45  *
46  * @param Pointer to the subtype.
47  */
48 BOXEXPORT void
49 BoxSubtype_Finish(BoxSubtype *st);
50 
51 /**
52  * A pointer to a target object decorated with the type of the target.
53  * This is using for boxing/unboxing objects.
54  */
55 typedef struct {
56   BoxType *type;
57   BoxPtr  ptr;
58 } BoxAny;
59 
60 #  define BoxAny_Init(obj) \
61   do {(obj)->type = NULL; BoxPtr_Init(& (obj)->ptr);} while(0)
62 
63 /**
64  * @brief Get the type of the object stored inside the #BoxAny object.
65  */
66 #  define BoxAny_Get_Type(obj) \
67   ((obj)->type)
68 
69 /**
70  * @brief Get the pointer to the object stored inside the #BoxAny object.
71  */
72 #  define BoxAny_Get_Obj(obj) \
73   (& (obj)->ptr)
74 
75 /**
76  * Finalize an Any object.
77  */
78 BOXEXPORT void
79 BoxAny_Finish(BoxAny *any);
80 
81 /**
82  * @brief Copy an #Any object.
83  *
84  * @param dst An uninitialized region of memory which can contain a #BoxAny
85  *   object.
86  * @param src The initialized #BoxAny object to copy.
87  */
88 BOXEXPORT void
89 BoxAny_Copy(BoxAny *dst, BoxAny *src);
90 
91 /**
92  * @brief Change the boxed object stored inside the given any object.
93  *
94  * @param any The ANY object which should be changed to reference @p obj.
95  * @param obj The object which should be put inside @p any.
96  * @param t The type of @p obj.
97  * @param safe If this is @c BOXBOOL_TRUE, then the object in @p obj is copied
98  *   whenever it is a NULL-block pointer. Otherwise, the object is not copied
99  *   which is unsafe as the Any object may survive even after @p obj is
100  *   deallocated.
101  * @return Whether the boxing operation was successful.
102  */
103 BOXEXPORT BoxBool
104 BoxAny_Box(BoxPtr *any, BoxPtr *obj, BoxType *t, BoxBool weak);
105 
106 /**
107  * @brief Retrieve the boxed object stored inside the given any object.
108  *
109  * @param obj An unitialised pointer which will be set with a fresh reference
110  *   to the object contained inside @p any.
111  * @param any The @c ANY object containing the boxed object.
112  * @param t The type of the boxed object.
113  * @return Whether the unboxing operation was successful. Unboxing @p any can
114  *   be done only if the contained object has a type which matches @p t.
115  */
116 BOXEXPORT BoxBool
117 BoxAny_Unbox(BOXOUT BoxPtr *obj, BoxPtr *any, BoxType *t);
118 
119 /**
120  * @brief C counterpart of the Box Set type, used to set items in containers.
121  */
122 typedef struct {
123   BoxAny index, /**< Index for the set operation. */
124          value; /**< Value for the set operation. */
125 } BoxSet;
126 
127 /**
128  * Object header. Every object allocation includes some extra space to contain
129  * This structure, which contains the type of the object and the number of
130  * references that other objects make to it.
131  */
132 typedef struct BoxObjHeader_struct {
133   size_t  num_refs;
134   BoxType *type;
135 } BoxObjHeader;
136 
137 /**
138  * Single Pointer to a Box object.
139  */
140 typedef void *BoxSPtr;
141 
142 /**
143  * @brief Allocate space for an object of the given type.
144  *
145  * This is an internal function which is not meant to be used externally.
146  */
147 BOXEXPORT BoxSPtr
148 BoxSPtr_Alloc(BoxType *t);
149 
150 /**
151  * @brief Raw allocation function.
152  *
153  * This is an internal function which is not meant to be used externally.
154  */
155 BOXEXPORT BoxSPtr
156 BoxSPtr_Raw_Alloc(BoxType *t, size_t obj_size);
157 
158 /**
159  * @brief Add a reference to an object and return it.
160  *
161  * @param src The object to reference.
162  * @return Return its argument, src.
163  */
164 BOXEXPORT BoxSPtr
165 BoxSPtr_Link(BoxSPtr src);
166 
167 /**
168  * This function, which should be used in conjunction with BoxSPtr_Unlink_End,
169  * allows unlinking an object and performing some extra operations before
170  * object destruction. It should be used in the following way:
171  * @code
172  * if (BoxSPtr_Unlink_Begin(src)) {
173  *   // do something
174  *   BoxSPtr_Unlink_End(src);
175  * }
176  * @endcode
177  * The function BoxSPtr_Unlink_Begin checks the reference counts of src. If
178  * this is greater than one, then the reference count is decreased and
179  * BOXBOOL_FALSE is returned. If the reference count is one, then the function
180  * does not change the reference count, but rather returns BOXBOOL_TRUE.
181  * The function BoxSPtr_Unlink_End does finally increase the reference count
182  * and destroy the object.
183  * @param src Object to unlink.
184  * @return BOXBOOL_TRUE if the object has just one reference, otherwise return
185  *   BOXBOOL_FALSE.
186  * @see BoxSPtr_Unlink
187  */
188 BOXEXPORT BoxBool
189 BoxSPtr_Unlink_Begin(BoxSPtr src);
190 
191 /**
192  * @brief Function to be used in conjunction with BoxSPtr_Unlink_Begin.
193  *
194  * @see BoxSPtr_Unlink_Begin
195  */
196 BOXEXPORT void
197 BoxSPtr_Unlink_End(BoxSPtr src);
198 
199 /**
200  * @brief Remove a reference to an object, destroying it, if unreferenced.
201  *
202  * @param src Object to unreference.
203  * @return src if the object was unreferenced but not destroyed, NULL if the
204  *   object was unreferenced and destroyed.
205  */
206 BOXEXPORT BoxSPtr
207 BoxSPtr_Unlink(BoxSPtr src);
208 
209 /**
210  * @brief Get the type of the allocated object.
211  *
212  * @param obj An object allocated with BoxSPtr_Alloc() or BoxSPtr_Raw_Alloc().
213  * @return The type of @p obj.
214  */
215 BOXEXPORT BoxType *
216 BoxSPtr_Get_Type(BoxSPtr obj);
217 
218 /**
219  * @brief Reference the given object.
220  *
221  * @param src Object to reference.
222  * @return @p src is returned.
223  */
224 BOXEXPORT BoxPtr *
225 BoxPtr_Link(BoxPtr *src);
226 
227 /**
228  * @brief Remove a reference to an object, destroying it, if unreferenced.
229  *
230  * @param src Object to unreference.
231  * @return @c BOXBOOL_TRUE if the object was unreferenced but not destroyed,
232  *   @c BOXBOOL_FALSE if the object was unreferenced and also destroyed.
233  */
234 BOXEXPORT BoxBool
235 BoxPtr_Unlink(BoxPtr *src);
236 
237 /**
238  * @brief Create a new object of the given type and return a pointer to it.
239  *
240  * @param ptr Location where to put the pointer to the object.
241  * @param t The type descriptor.
242  * @return Whether the operation was successful.
243  */
244 BOXEXPORT BoxBool
245 BoxPtr_Create_Obj(BOXOUT BoxPtr *ptr, BoxType *t);
246 
247 /**
248  * @brief Copy an object of the given type.
249  *
250  * @param dst Pointer to the destination.
251  * @param src Pointer to the source.
252  * @param t The type descriptor.
253  * @return Whether the operation was successful.
254  */
255 BOXEXPORT BoxBool
256 BoxPtr_Copy_Obj(BoxPtr *dst, BoxPtr *src, BoxType *t);
257 
258 /**
259  * @brief Try to convert a BoxPtr object to a simple single pointer.
260  *
261  * This function returns the a pointer @c sptr, if a pointer @c src exists such
262  * that @p src can be obtained from <tt>BoxPtr_Init_From_SPtr(src, sptr)</tt>.
263  *
264  * @param src The input double pointer.
265  * @return The single pointer corresponding to @p src, or @c NULL if such
266  *   @c src cannot be expressed by using a single pointer.
267  */
268 BOXEXPORT void *
269 BoxPtr_Get_SPtr(const BoxPtr *src);
270 
271 /**
272  * @brief Combine two objects from their types and pointers.
273  *
274  * @see Box_Combine_Any
275  */
276 BOXEXPORT BoxBool
277 Box_Combine(BoxType *t_parent, BoxPtr *parent,
278             BoxType *t_child, BoxPtr *child, BoxException **except);
279 
280 /**
281  * @brief Combine two objects boxed as #BoxAny objects.
282  *
283  * @param parent A #BoxAny object containing the parent.
284  * @param child A #BoxAny object containing the child.
285  * @param except Pointer where to store a #BoxException, in case the
286  *   combination is found and returns with failure.
287  * @return @c BOXBOOL_TRUE if the combination was found, else @c BOXBOOL_FALSE.
288  *
289  * @note <tt>*except</tt> is set only when the function returns @c BOXBOOL_TRUE.
290  * @see Box_Combine
291  */
292 BOXEXPORT BoxBool
293 Box_Combine_Any(BoxAny *parent, BoxAny *child, BoxException **except);
294 
295 #endif /* _BOX_OBJ_H */
296