• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIBBRILLO_BRILLO_GLIB_OBJECT_H_
6 #define LIBBRILLO_BRILLO_GLIB_OBJECT_H_
7 
8 #include <glib-object.h>
9 #include <stdint.h>
10 
11 #include <base/logging.h>
12 #include <base/macros.h>
13 
14 #include <algorithm>
15 #include <cstddef>
16 #include <memory>
17 #include <string>
18 
19 namespace brillo {
20 
21 namespace details {  // NOLINT
22 
23 // \brief ResetHelper is a private class for use with Resetter().
24 //
25 // ResetHelper passes ownership of a pointer to a scoped pointer type with reset
26 // on destruction.
27 
28 template <typename T>  // T models ScopedPtr
29 class ResetHelper {
30  public:
31   typedef typename T::element_type element_type;
32 
ResetHelper(T * x)33   explicit ResetHelper(T* x)
34       : ptr_(nullptr),
35         scoped_(x) {
36   }
~ResetHelper()37   ~ResetHelper() {
38     scoped_->reset(ptr_);
39   }
lvalue()40   element_type*& lvalue() {
41     return ptr_;
42   }
43 
44  private:
45   element_type* ptr_;
46   T* scoped_;
47 };
48 
49 }  // namespace details
50 
51 // \brief Resetter() is a utility function for passing pointers to
52 //  scoped pointers.
53 //
54 // The Resetter() function return a temporary object containing an lvalue of
55 // \code T::element_type which can be assigned to. When the temporary object
56 // destructs, the associated scoped pointer is reset with the lvalue. It is of
57 // general use when a pointer is returned as an out-argument.
58 //
59 // \example
60 // void function(int** x) {
61 //   *x = new int(10);
62 // }
63 // ...
64 // std::unique_ptr<int> x;
65 // function(Resetter(x).lvalue());
66 //
67 // \end_example
68 
69 template <typename T>  // T models ScopedPtr
Resetter(T * x)70 details::ResetHelper<T> Resetter(T* x) {
71   return details::ResetHelper<T>(x);
72 }
73 
74 // \precondition No functions in the glib namespace can be called before
75 // ::g_type_init();
76 
77 namespace glib {
78 
79 // \brief type_to_gtypeid is a type function mapping from a canonical type to
80 // the GType typeid for the associated GType (see type_to_gtype).
81 
82 template <typename T> ::GType type_to_gtypeid();
83 
84 template < >
85 inline ::GType type_to_gtypeid<const char*>() {
86   return G_TYPE_STRING;
87 }
88 template < >
89 inline ::GType type_to_gtypeid<char*>() {
90   return G_TYPE_STRING;
91 }
92 template < >
93 inline ::GType type_to_gtypeid< ::uint8_t>() {
94   return G_TYPE_UCHAR;
95 }
96 template < >
97 inline ::GType type_to_gtypeid<double>() {
98   return G_TYPE_DOUBLE;
99 }
100 template < >
101 inline ::GType type_to_gtypeid<bool>() {
102   return G_TYPE_BOOLEAN;
103 }
104 class Value;
105 template < >
106 inline ::GType type_to_gtypeid<const Value*>() {
107   return G_TYPE_VALUE;
108 }
109 
110 template < >
111 inline ::GType type_to_gtypeid< ::uint32_t>() {
112   // REVISIT (seanparent) : There currently isn't any G_TYPE_UINT32, this code
113   // assumes sizeof(guint) == sizeof(guint32). Need a static_assert to assert
114   // that.
115   return G_TYPE_UINT;
116 }
117 
118 template < >
119 inline ::GType type_to_gtypeid< ::int64_t>() {
120   return G_TYPE_INT64;
121 }
122 
123 template < >
124 inline ::GType type_to_gtypeid< ::int32_t>() {
125   return G_TYPE_INT;
126 }
127 
128 // \brief Value (and Retrieve) support using std::string as well as const char*
129 // by promoting from const char* to the string. promote_from provides a mapping
130 // for this promotion (and possibly others in the future).
131 
132 template <typename T> struct promotes_from {
133   typedef T type;
134 };
135 template < > struct promotes_from<std::string> {
136   typedef const char* type;
137 };
138 
139 // \brief RawCast converts from a GValue to a value of a canonical type.
140 //
141 // RawCast is a low level function. Generally, use Cast() instead.
142 //
143 // \precondition \param x contains a value of type \param T.
144 
145 template <typename T>
146 inline T RawCast(const ::GValue& x) {
147   // Use static_assert() to issue a meaningful compile-time error.
148   // To prevent this from happening for all references to RawCast, use sizeof(T)
149   // to make static_assert depend on type T and therefore prevent binding it
150   // unconditionally until the actual RawCast<T> instantiation happens.
151   static_assert(sizeof(T) == 0, "Using RawCast on unsupported type");
152   return T();
153 }
154 
155 template < >
156 inline const char* RawCast<const char*>(const ::GValue& x) {
157   return static_cast<const char*>(::g_value_get_string(&x));
158 }
159 template < >
160 inline double RawCast<double>(const ::GValue& x) {
161   return static_cast<double>(::g_value_get_double(&x));
162 }
163 template < >
164 inline bool RawCast<bool>(const ::GValue& x) {
165   return static_cast<bool>(::g_value_get_boolean(&x));
166 }
167 template < >
168 inline ::uint32_t RawCast< ::uint32_t>(const ::GValue& x) {
169   return static_cast< ::uint32_t>(::g_value_get_uint(&x));
170 }
171 template < >
172 inline ::uint8_t RawCast< ::uint8_t>(const ::GValue& x) {
173   return static_cast< ::uint8_t>(::g_value_get_uchar(&x));
174 }
175 template < >
176 inline ::int64_t RawCast< ::int64_t>(const ::GValue& x) {
177   return static_cast< ::int64_t>(::g_value_get_int64(&x));
178 }
179 template < >
180 inline ::int32_t RawCast< ::int32_t>(const ::GValue& x) {
181   return static_cast< ::int32_t>(::g_value_get_int(&x));
182 }
183 
184 inline void RawSet(GValue* x, const std::string& v) {
185   ::g_value_set_string(x, v.c_str());
186 }
187 inline void RawSet(GValue* x, const char* v) {
188   ::g_value_set_string(x, v);
189 }
190 inline void RawSet(GValue* x, double v) {
191   ::g_value_set_double(x, v);
192 }
193 inline void RawSet(GValue* x, bool v) {
194   ::g_value_set_boolean(x, v);
195 }
196 inline void RawSet(GValue* x, ::uint32_t v) {
197   ::g_value_set_uint(x, v);
198 }
199 inline void RawSet(GValue* x, ::uint8_t v) {
200   ::g_value_set_uchar(x, v);
201 }
202 inline void RawSet(GValue* x, ::int64_t v) {
203   ::g_value_set_int64(x, v);
204 }
205 inline void RawSet(GValue* x, ::int32_t v) {
206   ::g_value_set_int(x, v);
207 }
208 
209 // \brief Value is a data type for managing GValues.
210 //
211 // A Value is a polymorphic container holding at most a single value.
212 //
213 // The Value wrapper ensures proper initialization, copies, and assignment of
214 // GValues.
215 //
216 // \note GValues are equationally incomplete and so can't support proper
217 // equality. The semantics of copy are verified with equality of retrieved
218 // values.
219 
220 class Value : public ::GValue {
221  public:
222   Value()
223       : GValue() {
224   }
225   explicit Value(const ::GValue& x)
226       : GValue() {
227     *this = *static_cast<const Value*>(&x);
228   }
229   template <typename T>
230   explicit Value(T x)
231       : GValue() {
232     ::g_value_init(this,
233         type_to_gtypeid<typename promotes_from<T>::type>());
234     RawSet(this, x);
235   }
236   Value(const Value& x)
237       : GValue() {
238     if (x.empty())
239       return;
240     ::g_value_init(this, G_VALUE_TYPE(&x));
241     ::g_value_copy(&x, this);
242   }
243   ~Value() {
244     clear();
245   }
246   Value& operator=(const Value& x) {
247     if (this == &x)
248       return *this;
249     clear();
250     if (x.empty())
251       return *this;
252     ::g_value_init(this, G_VALUE_TYPE(&x));
253     ::g_value_copy(&x, this);
254     return *this;
255   }
256   template <typename T>
257   Value& operator=(const T& x) {
258     clear();
259     ::g_value_init(this,
260                    type_to_gtypeid<typename promotes_from<T>::type>());
261     RawSet(this, x);
262     return *this;
263   }
264 
265   // Lower-case names to follow STL container conventions.
266 
267   void clear() {
268     if (!empty())
269       ::g_value_unset(this);
270   }
271 
272   bool empty() const {
273     return G_VALUE_TYPE(this) == G_TYPE_INVALID;
274   }
275 };
276 
277 template < >
278 inline const Value* RawCast<const Value*>(const ::GValue& x) {
279   return static_cast<const Value*>(&x);
280 }
281 
282 // \brief Retrieve gets a value from a GValue.
283 //
284 // \postcondition If \param x contains a value of type \param T, then the
285 //  value is copied to \param result and \true is returned. Otherwise, \param
286 //  result is unchanged and \false is returned.
287 //
288 // \precondition \param result is not \nullptr.
289 
290 template <typename T>
291 bool Retrieve(const ::GValue& x, T* result) {
292   if (!G_VALUE_HOLDS(&x, type_to_gtypeid<typename promotes_from<T>::type>())) {
293     LOG(WARNING) << "GValue retrieve failed. Expected: "
294         << g_type_name(type_to_gtypeid<typename promotes_from<T>::type>())
295         << ", Found: " << g_type_name(G_VALUE_TYPE(&x));
296     return false;
297   }
298 
299   *result = RawCast<typename promotes_from<T>::type>(x);
300   return true;
301 }
302 
303 inline bool Retrieve(const ::GValue& x, Value* result) {
304   *result = Value(x);
305   return true;
306 }
307 
308 // \brief ScopedError holds a ::GError* and deletes it on destruction.
309 
310 struct FreeError {
311   void operator()(::GError* x) const {
312     if (x)
313       ::g_error_free(x);
314   }
315 };
316 
317 typedef std::unique_ptr< ::GError, FreeError> ScopedError;
318 
319 // \brief ScopedArray holds a ::GArray* and deletes both the container and the
320 // segment containing the elements on destruction.
321 
322 struct FreeArray {
323   void operator()(::GArray* x) const {
324     if (x)
325       ::g_array_free(x, TRUE);
326   }
327 };
328 
329 typedef std::unique_ptr< ::GArray, FreeArray> ScopedArray;
330 
331 // \brief ScopedPtrArray adapts ::GPtrArray* to conform to the standard
332 //  container requirements.
333 //
334 // \note ScopedPtrArray is only partially implemented and is being fleshed out
335 //  as needed.
336 //
337 // \models Random Access Container, Back Insertion Sequence, ScopedPtrArray is
338 //  not copyable and equationally incomplete.
339 
340 template <typename T>  // T models pointer
341 class ScopedPtrArray {
342  public:
343   typedef ::GPtrArray element_type;
344 
345   typedef T value_type;
346   typedef const value_type& const_reference;
347   typedef value_type* iterator;
348   typedef const value_type* const_iterator;
349 
350   ScopedPtrArray()
351       : object_(0) {
352   }
353 
354   explicit ScopedPtrArray(::GPtrArray* x)
355       : object_(x) {
356   }
357 
358   ~ScopedPtrArray() {
359     clear();
360   }
361 
362   iterator begin() {
363     return iterator(object_ ? object_->pdata : nullptr);
364   }
365   iterator end() {
366     return begin() + size();
367   }
368   const_iterator begin() const {
369     return const_iterator(object_ ? object_->pdata : nullptr);
370   }
371   const_iterator end() const {
372     return begin() + size();
373   }
374 
375   // \precondition x is a pointer to an object allocated with g_new().
376 
377   void push_back(T x) {
378     if (!object_)
379       object_ = ::g_ptr_array_sized_new(1);
380     ::g_ptr_array_add(object_, ::gpointer(x));
381   }
382 
383   T& operator[](std::size_t n) {
384     DCHECK(!(size() < n)) << "ScopedPtrArray index out-of-bound.";
385     return *(begin() + n);
386   }
387 
388   std::size_t size() const {
389     return object_ ? object_->len : 0;
390   }
391 
392   void clear() {
393     if (object_) {
394       std::for_each(begin(), end(), FreeHelper());
395       ::g_ptr_array_free(object_, true);
396       object_ = nullptr;
397     }
398   }
399 
400   void reset(::GPtrArray* p = nullptr) {
401     if (p != object_) {
402       clear();
403       object_ = p;
404     }
405   }
406 
407  private:
408   struct FreeHelper {
409     void operator()(T x) const {
410       ::g_free(::gpointer(x));
411     }
412   };
413 
414   template <typename U>
415   friend void swap(ScopedPtrArray<U>& x, ScopedPtrArray<U>& y);
416 
417   ::GPtrArray* object_;
418 
419   DISALLOW_COPY_AND_ASSIGN(ScopedPtrArray);
420 };
421 
422 template <typename U>
423 inline void swap(ScopedPtrArray<U>& x, ScopedPtrArray<U>& y) {
424   std::swap(x.object_, y.object_);
425 }
426 
427 // \brief ScopedHashTable manages the lifetime of a ::GHashTable* with an
428 // interface compatibitle with a scoped ptr.
429 //
430 // The ScopedHashTable is also the start of an adaptor to model a standard
431 // Container. The standard for an associative container would have an iterator
432 // returning a key value pair. However, that isn't possible with
433 // ::GHashTable because there is no interface returning a reference to the
434 // key value pair, only to retrieve the keys and values and individual elements.
435 //
436 // So the standard interface of find() wouldn't work. I considered implementing
437 // operator[] and count() - operator []. So retrieving a value would look like:
438 //
439 // if (table.count(key))
440 //   success = Retrieve(table[key], &value);
441 //
442 // But that requires hashing the key twice.
443 // For now I implemented a Retrieve member function to follow the pattern
444 // developed elsewhere in the code.
445 //
446 // bool success = Retrieve(key, &x);
447 //
448 // This is also a template to retrieve the corect type from the stored GValue
449 // type.
450 //
451 // I may revisit this and use scoped_ptr_malloc and a non-member function
452 // Retrieve() in the future. The Retrieve pattern is becoming common enough
453 // that I want to give some thought as to how to generalize it further.
454 
455 class ScopedHashTable {
456  public:
457   typedef ::GHashTable element_type;
458 
459   ScopedHashTable()
460       : object_(nullptr) {
461   }
462 
463   explicit ScopedHashTable(::GHashTable* p)
464       : object_(p) {
465   }
466 
467   ~ScopedHashTable() {
468     clear();
469   }
470 
471   template <typename T>
472   bool Retrieve(const char* key, T* result) const {
473     DCHECK(object_) << "Retrieve on empty ScopedHashTable.";
474     if (!object_)
475       return false;
476 
477     ::gpointer ptr = ::g_hash_table_lookup(object_, key);
478     if (!ptr)
479       return false;
480     return glib::Retrieve(*static_cast< ::GValue*>(ptr), result);
481   }
482 
483   void clear() {
484     if (object_) {
485       ::g_hash_table_unref(object_);
486       object_ = nullptr;
487     }
488   }
489 
490   GHashTable* get() {
491     return object_;
492   }
493 
494   void reset(::GHashTable* p = nullptr) {
495     if (p != object_) {
496       clear();
497       object_ = p;
498     }
499   }
500 
501  private:
502   ::GHashTable* object_;
503 };
504 
505 }  // namespace glib
506 }  // namespace brillo
507 
508 #endif  // LIBBRILLO_BRILLO_GLIB_OBJECT_H_
509