#include <map>
#include <boost/any.hpp>
-#include "zypp/base/PtrTypes.h"
-#include "zypp/ContentType.h"
+#include <zypp/base/PtrTypes.h>
+#include <zypp/ContentType.h>
///////////////////////////////////////////////////////////////////
namespace zypp
/// \class UserData
/// \brief Typesafe passing of user data via callbacks
///
- /// Basically a <tt>std::map<std::string,boost::any></tt> plus
+ /// Basically a <tt>std::map<std::string,AnyType></tt> plus
/// associated \ref ContentType.
+ ///
+ /// Constness protects non-empty values from being modified.
+ /// It is possible to overwrite empty values or to add new ones.
///////////////////////////////////////////////////////////////////
class UserData
{
- typedef std::map<std::string,boost::any> DataType;
public:
- /** Default ctor */
+ typedef boost::any AnyType;
+ typedef boost::bad_any_cast bad_AnyType_cast;
+
+ typedef std::map<std::string,AnyType> DataType;
+ typedef DataType::size_type size_type;
+ typedef DataType::key_type key_type;
+ typedef DataType::value_type value_type;
+ typedef DataType::const_iterator const_iterator;
+
+ typedef zypp::ContentType ContentType;
+
+ public:
+ /** Default ctor. */
UserData()
{}
+ /** Ctor taking ContentType. */
+ explicit UserData( ContentType type_r )
+ : _type( std::move(type_r) )
+ {}
+ /** Ctor taking ContentType. */
+ explicit UserData( std::string type_r )
+ : UserData( ContentType( std::move(type_r) ) )
+ {}
+ /** Ctor taking ContentType. */
+ UserData( std::string type_r, std::string subtype_r )
+ : UserData( ContentType( std::move(type_r), std::move(subtype_r) ) )
+ {}
+
public:
- /** Get type */
+ /** Get type. */
const ContentType & type() const
{ return _type; }
- /** Set type */
- void type( const ContentType & type_r )
- { _type = type_r; }
+ /** Set type. */
+ void type( ContentType type_r )
+ { _type = std::move(type_r); }
public:
- /** Validate object in a boolean context: has data */
+ /** Validate object in a boolean context: has data */
explicit operator bool() const
- { return ! ( _dataP == nullptr || _dataP->empty() ); }
+ { return !empty(); }
+
+ /** Whether \ref data is empty. */
+ bool empty() const
+ { return !_dataP || _dataP->empty(); }
+
+ /** Size of \ref data. */
+ size_type size() const
+ { return _dataP ? _dataP->size() : 0; }
+
+ /** The \ref data. */
+ const DataType & data() const
+ { return dataRef(); }
+
+ /** Whether \a key_r is in \ref data. */
+ bool haskey( const std::string & key_r ) const
+ { return _dataP && _dataP->find( key_r ) != _dataP->end(); }
+
+ /** Whether \a key_r is in \ref data and value is not empty. */
+ bool hasvalue( const std::string & key_r ) const
+ {
+ bool ret = false;
+ if ( _dataP )
+ {
+ const_iterator it = _dataP->find( key_r );
+ if ( it != _dataP->end() && ! it->second.empty() )
+ {
+ ret = true;
+ }
+ }
+ return ret;
+ }
+
+ /** Set the value for key (nonconst version always returns true).
+ * Const version is allowed to set empty values or to add new ones only.
+ */
+ bool set( const std::string & key_r, AnyType val_r )
+ { dataRef()[key_r] = std::move(val_r); return true; }
+ /** \overload const version */
+ bool set( const std::string & key_r, AnyType val_r ) const
+ {
+ bool ret = false;
+ AnyType & val( dataRef()[key_r] );
+ if ( val.empty() )
+ {
+ val = std::move(val_r);
+ ret = true;
+ }
+ return ret;
+ }
+
+ /** Set an empty value for \a key_r (if possible). */
+ bool reset( const std::string & key_r )
+ { return set( key_r, AnyType() ); }
+ /** \overload const version */
+ bool reset( const std::string & key_r ) const
+ { return set( key_r, AnyType() ); }
+
+ /** Remove key from data.*/
+ void erase( const std::string & key_r )
+ { if ( _dataP ) _dataP->erase( key_r ); }
+
+ /** \ref get helper returning the keys AnyType value or an empty value if key does not exist. */
+ const AnyType & getvalue( const std::string & key_r ) const
+ {
+ if ( _dataP )
+ {
+ const_iterator it = _dataP->find( key_r );
+ if ( it != _dataP->end() )
+ {
+ return it->second;
+ }
+ }
+ static const AnyType none;
+ return none;
+ }
+
+ /** Pass back a <tt>const Tp &</tt> reference to \a key_r value.
+ * \throws bad_AnyType_cast if key is not set or value is not of appropriate type
+ * \code
+ * UserData data;
+ * std::string value( "defaultvalue" );
+ * try
+ * {
+ * value = data.get<std::string>( "mykey" );
+ * }
+ * catch ( const UserData::bad_AnyType_cast & )
+ * {
+ * // no "mykey" or not a std::sting
+ * }
+ * \endcode
+ */
+ template <class Tp>
+ const Tp & get( const std::string & key_r ) const
+ { return boost::any_cast<const Tp &>( getvalue( key_r ) ); }
+
+ /** Pass back a \a Tp copy of \a key_r value.
+ * \throws bad_AnyType_cast if key is not set or value is not of appropriate type
+ * \code
+ * UserData data;
+ * std::string value = data.get<std::string>( "mykey", "defaultvalue" );
+ * \endcode
+ */
+ template <class Tp>
+ Tp get( const std::string & key_r, const Tp & default_r ) const
+ { Tp ret( default_r ); get( key_r, ret ); return ret; }
+
+ /** 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;.
+ * \code
+ * UserData data;
+ * std::string value( "defaultvalue" );
+ * if ( ! data.get<std::string>( "mykey", value )
+ * {
+ * // no "mykey" or not a std::sting
+ * }
+ * \endcode
+ */
+ template <class Tp>
+ bool get( const std::string & key_r, Tp & ret_r ) const
+ {
+ bool ret = false;
+ if ( _dataP )
+ {
+ const_iterator it = _dataP->find( key_r );
+ if ( it != _dataP->end() )
+ {
+ auto ptr = boost::any_cast<const Tp>(&it->second);
+ if ( ptr )
+ {
+ ret_r = *ptr;
+ ret = true;
+ }
+ }
+ }
+ return ret;
+ }
+
+ private:
+ DataType & dataRef() const
+ { if ( ! _dataP ) _dataP.reset( new DataType ); return *_dataP; }
private:
- ContentType _type;
- shared_ptr<DataType> _dataP;
+ ContentType _type;
+ mutable shared_ptr<DataType> _dataP;
};
/** \relates UserData Stream output */
inline std::ostream & operator<<( std::ostream & str, const UserData & obj )
- { return str << "UserData(" << obj.type() << ")";}
+ { return str << "UserData(" << obj.type() << ":" << obj.size() << ")";}
} // namespace callback
///////////////////////////////////////////////////////////////////