Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / UserData.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/UserData.h
10  */
11 #ifndef ZYPP_USERDATA_H
12 #define ZYPP_USERDATA_H
13
14 #include <iosfwd>
15 #include <string>
16 #include <map>
17 #include <boost/any.hpp>
18
19 #include "zypp/base/PtrTypes.h"
20 #include "zypp/ContentType.h"
21
22 ///////////////////////////////////////////////////////////////////
23 namespace zypp
24 {
25   ///////////////////////////////////////////////////////////////////
26   namespace callback
27   {
28     ///////////////////////////////////////////////////////////////////
29     /// \class UserData
30     /// \brief Typesafe passing of user data via callbacks
31     ///
32     /// Basically a <tt>std::map<std::string,AnyType></tt> plus
33     /// associated \ref ContentType.
34     ///
35     /// Constness protects non-empty values from being modified.
36     /// It is possible to overwrite empty values or to add new ones.
37     ///////////////////////////////////////////////////////////////////
38     class UserData
39     {
40     public:
41       typedef boost::any                        AnyType;
42       typedef boost::bad_any_cast               bad_AnyType_cast;
43
44       typedef std::map<std::string,AnyType>     DataType;
45       typedef DataType::size_type               size_type;
46       typedef DataType::key_type                key_type;
47       typedef DataType::value_type              value_type;
48       typedef DataType::const_iterator          const_iterator;
49
50       typedef zypp::ContentType                 ContentType;
51
52     public:
53       /** Default ctor. */
54       UserData()
55       {}
56
57       /** Ctor taking ContentType. */
58       explicit UserData( ContentType type_r )
59       : _type( std::move(type_r) )
60       {}
61       /** Ctor taking ContentType. */
62       explicit UserData( std::string type_r )
63       : UserData( ContentType( std::move(type_r) ) )
64       {}
65       /** Ctor taking ContentType. */
66       UserData( std::string type_r, std::string subtype_r )
67       : UserData( ContentType( std::move(type_r), std::move(subtype_r) ) )
68       {}
69
70     public:
71       /** Get type. */
72       const ContentType & type() const
73       { return _type; }
74
75       /** Set type. */
76       void type( ContentType type_r )
77       { _type = std::move(type_r); }
78
79     public:
80        /**  Validate object in a boolean context: has data */
81       explicit operator bool() const
82       { return !empty(); }
83
84       /** Whether \ref data is empty. */
85       bool empty() const
86       { return !_dataP || _dataP->empty(); }
87
88       /** Size of \ref data. */
89       size_type size() const
90       { return _dataP ? _dataP->size() : 0;  }
91
92       /** The \ref data. */
93       const DataType & data() const
94       { return dataRef(); }
95
96       /** Whether \a key_r is in \ref data. */
97       bool haskey( const std::string & key_r ) const
98       { return _dataP && _dataP->find( key_r ) != _dataP->end(); }
99
100       /** Whether \a key_r is in \ref data and value is not empty. */
101       bool hasvalue( const std::string & key_r ) const
102       {
103         bool ret = false;
104         if ( _dataP )
105         {
106           const_iterator it = _dataP->find( key_r );
107           if ( it != _dataP->end() && ! it->second.empty() )
108           {
109             ret = true;
110           }
111         }
112         return ret;
113       }
114
115       /** Set the value for key (nonconst version always returns true).
116        * Const version is allowed to set empty values or to add new ones only.
117        */
118       bool set( const std::string & key_r, AnyType val_r )
119       { dataRef()[key_r] = std::move(val_r); return true; }
120       /** \overload const version */
121       bool set( const std::string & key_r, AnyType val_r ) const
122       {
123         bool ret = false;
124         AnyType & val( dataRef()[key_r] );
125         if ( val.empty() )
126         {
127           val = std::move(val_r);
128           ret = true;
129         }
130         return ret;
131       }
132
133       /** Set an empty value for \a key_r (if possible). */
134       bool reset( const std::string & key_r )
135       { return set( key_r, AnyType() ); }
136       /** \overload const version */
137       bool reset( const std::string & key_r ) const
138       { return set( key_r, AnyType() ); }
139
140       /** Remove key from data.*/
141       void erase( const std::string & key_r )
142       { if ( _dataP ) _dataP->erase( key_r ); }
143
144       /** \ref get helper returning the keys AnyType value or an empty value if key does not exist. */
145       const AnyType & getvalue( const std::string & key_r ) const
146       {
147         if ( _dataP )
148         {
149           const_iterator it = _dataP->find( key_r );
150           if ( it != _dataP->end() )
151           {
152             return it->second;
153           }
154         }
155         static const AnyType none;
156         return none;
157       }
158
159       /** Pass back a <tt>const Tp &</tt> reference to \a key_r value.
160        * \throws bad_AnyType_cast if key is not set or value is not of appropriate type
161        * \code
162        *   UserData data;
163        *   std::string value( "defaultvalue" );
164        *   try
165        *   {
166        *     value = data.get<std::string>( "mykey" );
167        *   }
168        *   catch ( const UserData::bad_AnyType_cast & )
169        *   {
170        *     // no "mykey" or not a std::sting
171        *   }
172        * \endcode
173        */
174       template <class Tp>
175       const Tp & get( const std::string & key_r ) const
176       { return boost::any_cast<const Tp &>( getvalue( key_r ) ); }
177
178       /** Pass back a \a Tp copy of \a key_r value.
179        * \throws bad_AnyType_cast if key is not set or value is not of appropriate type
180        * \code
181        *   UserData data;
182        *   std::string value = data.get<std::string>( "mykey", "defaultvalue" );
183        * \endcode
184        */
185       template <class Tp>
186       Tp get( const std::string & key_r, const Tp & default_r ) const
187       { Tp ret( default_r ); get( key_r, ret ); return ret; }
188
189       /** If the value for \a key_r is of the same type as \a ret_r, pass it back in \a ret_r and return \c true;.
190        * \code
191        *   UserData data;
192        *   std::string value( "defaultvalue" );
193        *   if ( ! data.get<std::string>( "mykey", value )
194        *   {
195        *      // no "mykey" or not a std::sting
196        *   }
197        * \endcode
198        */
199       template <class Tp>
200       bool get( const std::string & key_r, Tp & ret_r ) const
201       {
202         bool ret = false;
203         if ( _dataP )
204         {
205           const_iterator it = _dataP->find( key_r );
206           if ( it != _dataP->end() )
207           {
208             auto ptr = boost::any_cast<const Tp>(&it->second);
209             if ( ptr )
210             {
211               ret_r = *ptr;
212               ret = true;
213             }
214           }
215         }
216         return ret;
217       }
218
219     private:
220       DataType & dataRef() const
221       { if ( ! _dataP ) _dataP.reset( new DataType ); return *_dataP; }
222
223     private:
224       ContentType _type;
225       mutable shared_ptr<DataType> _dataP;
226     };
227
228     /** \relates UserData Stream output */
229     inline std::ostream & operator<<( std::ostream & str, const UserData & obj )
230     { return str << "UserData(" << obj.type() << ":" << obj.size() << ")";}
231
232   } // namespace callback
233   ///////////////////////////////////////////////////////////////////
234 } // namespace zypp
235 ///////////////////////////////////////////////////////////////////
236 #endif // ZYPP_USERDATA_H