1 /* Copyright 2002 The gtkmm Development Team
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #ifndef _GLIBMM_VALUE_CUSTOM_H
18 #define _GLIBMM_VALUE_CUSTOM_H
19 
20 #ifndef DOXYGEN_SHOULD_SKIP_THIS
21 #ifndef _GLIBMM_VALUE_H_INCLUDE_VALUE_CUSTOM_H
22 #error "glibmm/value_custom.h cannot be included directly"
23 #endif
24 #endif
25 
26 #include <glibmmconfig.h>
27 #include <new>
28 #include <typeinfo>
29 
30 namespace Glib
31 {
32 
33 #ifndef DOXYGEN_SHOULD_SKIP_THIS
34 
35 extern "C" {
36 typedef void (*ValueInitFunc)(GValue*);
37 typedef void (*ValueFreeFunc)(GValue*);
38 typedef void (*ValueCopyFunc)(const GValue*, GValue*);
39 }
40 
41 /* When using Glib::Value<T> with custom types, each T will be registered
42  * as subtype of G_TYPE_BOXED, via this function.  The type_name argument
43  * should be the C++ RTTI name.
44  */
45 
46 GLIBMM_API
47 GType custom_boxed_type_register(
48   const char* type_name, ValueInitFunc init_func, ValueFreeFunc free_func, ValueCopyFunc copy_func);
49 
50 /* When using Glib::Value<T*> or Glib::Value<const T*> with custom types,
51  * each T* or const T* will be registered as a subtype of G_TYPE_POINTER,
52  * via this function.  The type_name argument should be the C++ RTTI name.
53  */
54 GLIBMM_API
55 GType custom_pointer_type_register(const char* type_name);
56 
57 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
58 
59 /**
60  * @ingroup glibmmValue
61  */
62 template <class T, class PtrT>
63 class Value_Pointer : public ValueBase_Object
64 {
65 public:
66   using CppType = PtrT;
67   using CType = void*;
68 
69   static inline GType value_type() G_GNUC_CONST;
70 
71   inline void set(CppType data);
72   inline CppType get() const;
73 
74 private:
75   inline static GType value_type_(Glib::Object*);
76   static GType value_type_(void*);
77 
78   inline void set_(CppType data, Glib::Object*);
79   inline void set_(CppType data, void*);
80 
81   inline CppType get_(Glib::Object*) const;
82   inline CppType get_(void*) const;
83 };
84 
85 /** Generic value implementation for custom types.
86  * @ingroup glibmmValue
87  * Any type to be used with this template must implement:
88  * - default constructor
89  * - copy constructor
90  * - assignment operator
91  * - destructor
92  *
93  * Compiler-generated implementations are OK, provided they do the
94  * right thing for the type.  In other words, any type that works with
95  * <tt>std::vector</tt> will work with Glib::Value<>.
96  *
97  * @note None of the operations listed above are allowed to throw.  If you
98  * cannot ensure that no exceptions will be thrown, consider using either
99  * a normal pointer or a smart pointer to hold your objects indirectly.
100  */
101 template <class T>
102 class Value : public ValueBase_Boxed
103 {
104 public:
105   using CppType = T;
106   using CType = T*;
107 
108   static GType value_type() G_GNUC_CONST;
109 
110   inline void set(const CppType& data);
111   inline CppType get() const;
112 
113 private:
114   static GType custom_type_;
115 
116   static void value_init_func(GValue* value);
117   static void value_free_func(GValue* value);
118   static void value_copy_func(const GValue* src_value, GValue* dest_value);
119 };
120 
121 /** Specialization for pointers to instances of any type.
122  * @ingroup glibmmValue
123  * No attempt is made to manage the memory associated with the
124  * pointer, you must take care of that yourself.
125  */
126 template <class T>
127 class Value<T*> : public Value_Pointer<T, T*>
128 {
129 };
130 
131 /** Specialization for pointers to const instances of any type.
132  * @ingroup glibmmValue
133  * No attempt is made to manage the memory associated with the
134  * pointer, you must take care of that yourself.
135  */
136 template <class T>
137 class Value<const T*> : public Value_Pointer<T, const T*>
138 {
139 };
140 
141 #ifndef DOXYGEN_SHOULD_SKIP_THIS
142 
143 /**** Glib::Value_Pointer<T, PtrT> *****************************************/
144 
145 /** Implementation for Glib::Object pointers **/
146 
147 // static
148 template <class T, class PtrT>
149 inline GType
value_type_(Glib::Object *)150 Value_Pointer<T, PtrT>::value_type_(Glib::Object*)
151 {
152   return T::get_base_type();
153 }
154 
155 template <class T, class PtrT>
156 inline void
set_(PtrT data,Glib::Object *)157 Value_Pointer<T, PtrT>::set_(PtrT data, Glib::Object*)
158 {
159   set_object(const_cast<T*>(data));
160 }
161 
162 // More spec-compliant compilers (such as Tru64) need this to be near Glib::Object instead.
163 #ifdef GLIBMM_CAN_USE_DYNAMIC_CAST_IN_UNUSED_TEMPLATE_WITHOUT_DEFINITION
164 template <class T, class PtrT>
165 inline PtrT
get_(Glib::Object *)166 Value_Pointer<T, PtrT>::get_(Glib::Object*) const
167 {
168   return dynamic_cast<T*>(get_object());
169 }
170 #endif // GLIBMM_CAN_USE_DYNAMIC_CAST_IN_UNUSED_TEMPLATE_WITHOUT_DEFINITION
171 
172 /** Implementation for custom pointers **/
173 
174 // static
175 template <class T, class PtrT>
176 GType
value_type_(void *)177 Value_Pointer<T, PtrT>::value_type_(void*)
178 {
179   static GType custom_type = 0;
180 
181   if (!custom_type)
182     custom_type = Glib::custom_pointer_type_register(typeid(PtrT).name());
183 
184   return custom_type;
185 }
186 
187 template <class T, class PtrT>
188 inline void
set_(PtrT data,void *)189 Value_Pointer<T, PtrT>::set_(PtrT data, void*)
190 {
191   gobject_.data[0].v_pointer = const_cast<T*>(data);
192 }
193 
194 template <class T, class PtrT>
195 inline PtrT
get_(void *)196 Value_Pointer<T, PtrT>::get_(void*) const
197 {
198   return static_cast<T*>(gobject_.data[0].v_pointer);
199 }
200 
201 /** Public forwarding interface **/
202 
203 // static
204 template <class T, class PtrT>
205 inline GType
value_type()206 Value_Pointer<T, PtrT>::value_type()
207 {
208   // Dispatch to the specific value_type_() overload.
209   return Value_Pointer<T, PtrT>::value_type_(static_cast<T*>(nullptr));
210 }
211 
212 template <class T, class PtrT>
213 inline void
set(PtrT data)214 Value_Pointer<T, PtrT>::set(PtrT data)
215 {
216   // Dispatch to the specific set_() overload.
217   this->set_(data, static_cast<T*>(nullptr));
218 }
219 
220 template <class T, class PtrT>
221 inline PtrT
get()222 Value_Pointer<T, PtrT>::get() const
223 {
224   // Dispatch to the specific get_() overload.
225   return this->get_(static_cast<T*>(nullptr));
226 }
227 
228 /**** Glib::Value<T> *******************************************************/
229 
230 // Static data, specific to each template instantiation.
231 template <class T>
232 GType Value<T>::custom_type_ = 0;
233 
234 template <class T>
235 inline void
set(const typename Value<T>::CppType & data)236 Value<T>::set(const typename Value<T>::CppType& data)
237 {
238   // Assume the value is already default-initialized.  See value_init_func().
239   *static_cast<T*>(gobject_.data[0].v_pointer) = data;
240 }
241 
242 template <class T>
243 inline typename Value<T>::CppType
get()244 Value<T>::get() const
245 {
246   // Assume the pointer is not NULL.  See value_init_func().
247   return *static_cast<T*>(gobject_.data[0].v_pointer);
248 }
249 
250 // static
251 template <class T>
252 GType
value_type()253 Value<T>::value_type()
254 {
255   if (!custom_type_)
256   {
257     custom_type_ = Glib::custom_boxed_type_register(typeid(CppType).name(),
258       &Value<T>::value_init_func, &Value<T>::value_free_func, &Value<T>::value_copy_func);
259   }
260   return custom_type_;
261 }
262 
263 // static
264 template <class T>
265 void
value_init_func(GValue * value)266 Value<T>::value_init_func(GValue* value)
267 {
268   // Never store a NULL pointer (unless we're out of memory).
269   value->data[0].v_pointer = new (std::nothrow) T();
270 }
271 
272 // static
273 template <class T>
274 void
value_free_func(GValue * value)275 Value<T>::value_free_func(GValue* value)
276 {
277   delete static_cast<T*>(value->data[0].v_pointer);
278 }
279 
280 // static
281 template <class T>
282 void
value_copy_func(const GValue * src_value,GValue * dest_value)283 Value<T>::value_copy_func(const GValue* src_value, GValue* dest_value)
284 {
285   // Assume the source is not NULL.  See value_init_func().
286   const T& source = *static_cast<T*>(src_value->data[0].v_pointer);
287   dest_value->data[0].v_pointer = new (std::nothrow) T(source);
288 }
289 
290 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
291 
292 } // namespace Glib
293 
294 #endif //_GLIBMM_VALUE_CUSTOM_H
295