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