1/*
2Copyright (C) 2011-2014, Parrot Foundation.
3
4=head1 NAME
5
6src/pmc/ptrobj.pmc - PtrObj PMC
7
8=head1 DESCRIPTION
9
10C<PtrObj> is for object-ish pointers. These augment C<PtrBuf> to afford
11memory management.
12
13=head2 VTABLEs
14
15=over 4
16
17=cut
18
19*/
20
21/* HEADERIZER HFILE: none */
22/* HEADERIZER BEGIN: static */
23/* HEADERIZER END: static */
24
25BEGIN_PMC_HEADER_PREAMBLE
26typedef PMC *(*ptrobj_clone_func_t)(PARROT_INTERP, ARGIN(PMC *), ARGIN(void *));
27typedef void (*ptrobj_mark_func_t)(PARROT_INTERP, ARGIN(PMC *), ARGIN(void *));
28typedef void (*ptrobj_destroy_func_t)(PARROT_INTERP, ARGIN(PMC *), ARGIN(void *));
29
30#define PTROBJ_SET_CLONE(i, p, c) do { \
31    SETATTR_PtrObj_clone((i), (p), (c)); \
32} while (0)
33
34#define PTROBJ_SET_MARK(i, p, m) do { \
35    SETATTR_PtrObj_mark((i), (p), (m)); \
36    if (m) \
37        PObj_custom_mark_SET(p); \
38    else \
39        PObj_custom_mark_CLEAR(p); \
40} while (0)
41
42#define PTROBJ_SET_DESTROY(i, p, d) do { \
43    SETATTR_PtrObj_destroy((i), (p), (d)); \
44    if (d) \
45        PObj_custom_destroy_SET(p); \
46    else \
47        PObj_custom_destroy_CLEAR(p); \
48} while (0)
49END_PMC_HEADER_PREAMBLE
50
51pmclass PtrObj extends PtrBuf auto_attrs {
52    ATTR ptrobj_clone_func_t   clone;
53    ATTR ptrobj_mark_func_t    mark;
54    ATTR ptrobj_destroy_func_t destroy;
55
56/*
57
58=item C<PMC *clone()>
59
60Invoke the custom C<clone> function, if one has been provided. Otherwise, cloning is an error.
61
62=item C<METHOD clone_func(func :optional)>
63
64Get or set the custom C<clone> function.
65
66=cut
67
68*/
69
70
71    VTABLE PMC *clone() :no_wb {
72        void                *ptr;
73        ptrobj_clone_func_t  clone;
74        GET_ATTR_ptr(INTERP, SELF, ptr);
75        GET_ATTR_clone(INTERP, SELF, clone);
76        if (clone)
77            return clone(INTERP, SELF, ptr);
78        else
79            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_METHOD_NOT_FOUND,
80                    "clone not implemented for PtrObj %p", ptr);
81    }
82
83    METHOD clone_func(PMC *func :optional, INTVAL has_func :opt_flag) :manual_wb {
84        if (has_func) {
85            void * const f = VTABLE_get_pointer(INTERP, func);
86            PTROBJ_SET_CLONE(INTERP, SELF, (ptrobj_clone_func_t)f);
87            PARROT_GC_WRITE_BARRIER(INTERP, SELF);
88            RETURN();
89        }
90        else {
91            ptrobj_clone_func_t f;
92            GET_ATTR_clone(INTERP, SELF, f);
93            func = Parrot_pmc_new_init_int(INTERP, enum_class_Ptr, PTR2INTVAL(f));
94            RETURN(PMC func);
95        }
96    }
97
98/*
99
100=item C<void mark()>
101
102Invoke the custom C<mark> function, if one has been provided.
103
104=item C<METHOD mark_func(func :optional)>
105
106Get or set the custom C<mark> function.
107
108=cut
109
110*/
111
112    VTABLE void mark() :no_wb {
113        void               *ptr;
114        ptrobj_mark_func_t  mark;
115        GET_ATTR_ptr(INTERP, SELF, ptr);
116        GET_ATTR_mark(INTERP, SELF, mark);
117        /* invariant: custom mark flag only set when a custom mark function has been provided */
118        PARROT_ASSERT(mark);
119        mark(INTERP, SELF, ptr);
120    }
121
122    METHOD mark_func(PMC *func :optional, INTVAL has_func :opt_flag) :manual_wb {
123        if (has_func) {
124            void * const f = VTABLE_get_pointer(INTERP, func);
125            PTROBJ_SET_MARK(INTERP, SELF, (ptrobj_mark_func_t)f);
126            PARROT_GC_WRITE_BARRIER(INTERP, SELF);
127            RETURN();
128        }
129        else {
130            ptrobj_mark_func_t f;
131            GET_ATTR_mark(INTERP, SELF, f);
132            func = Parrot_pmc_new_init_int(INTERP, enum_class_Ptr, PTR2ULONG(f));
133            RETURN(PMC func);
134        }
135    }
136
137/*
138
139=item C<void destroy()>
140
141Invoke the custom C<destroy> function if one has been provided.
142
143=item C<METHOD destroy_func(func :optional)>
144
145Get or set the custom C<destroy> function.
146
147=cut
148
149*/
150
151    VTABLE void destroy() :no_wb {
152        void                  *ptr;
153        ptrobj_destroy_func_t  destroy;
154        GET_ATTR_ptr(INTERP, SELF, ptr);
155        GET_ATTR_destroy(INTERP, SELF, destroy);
156        /* invariant: custom destroy flag only set when a destroy function has been provided */
157        PARROT_ASSERT(destroy);
158        destroy(INTERP, SELF, ptr);
159    }
160
161    METHOD destroy_func(PMC *func :optional, INTVAL has_func :opt_flag) :manual_wb {
162        if (has_func) {
163            void * const f = VTABLE_get_pointer(INTERP, func);
164            PTROBJ_SET_DESTROY(INTERP, SELF, (ptrobj_destroy_func_t)f);
165            PARROT_GC_WRITE_BARRIER(INTERP, SELF);
166            RETURN();
167        }
168        else {
169            ptrobj_destroy_func_t f;
170            GET_ATTR_destroy(INTERP, SELF, f);
171            func = Parrot_pmc_new_init_int(INTERP, enum_class_Ptr, PTR2ULONG(f));
172            RETURN(PMC func);
173        }
174    }
175}
176
177/*
178
179=back
180
181=cut
182
183*/
184
185/*
186 * Local variables:
187 *   c-file-style: "parrot"
188 * End:
189 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
190 */
191