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 #include <base/memory/scoped_ptr.h> 14 15 #include <algorithm> 16 #include <cstddef> 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 33 explicit ResetHelper(T* x) 34 : ptr_(nullptr), 35 scoped_(x) { 36 } 37 ~ResetHelper() { 38 scoped_->reset(ptr_); 39 } 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 // scoped_ptr<int> x; 65 // function(Resetter(x).lvalue()); 66 // 67 // \end_example 68 69 template <typename T> // T models ScopedPtr 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 ::scoped_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 ::scoped_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