2   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 
    5 #ifndef ASGTOOLS_TPROPERTY_ICC
 
    6 #define ASGTOOLS_TPROPERTY_ICC
 
    8 #include <AsgTools/MessageCheckAsgTools.h>
 
   12 #include <type_traits>
 
   18     /// \brief pack a single string into a property string
 
   19     StatusCode packStringSingle (const std::string& value,
 
   22     /// \brief pack a vector of strings into a property string
 
   23     StatusCode packStringVector (const std::vector<std::string>& value,
 
   26     /// \brief pack a vector of strings into a property string
 
   27     StatusCode packStringMap (const std::map<std::string,std::string>& value,
 
   30     /// \brief unpack a single string from a property string
 
   31     StatusCode unpackStringSingle (const std::string& value,
 
   34     /// \brief unpack a vector of strings from a property string
 
   35     StatusCode unpackStringVector (const std::string& value,
 
   36                    std::vector<std::string>& result);
 
   38     /// \brief unpack a vector of strings from a property string
 
   39     StatusCode unpackStringMap (const std::string& value,
 
   40                                 std::map<std::string,std::string>& result);
 
   42     /// \brief check for the existence of an output streamer
 
   49       template <typename C> static one test( decltype(&(*(std::ostream*)0 << *(C*)0)));
 
   50       template <typename C> static two test(...);    
 
   53       enum { value = sizeof(test<T>(0)) == sizeof(char) };
 
   56     /// \brief check for the existence of conversion to string
 
   58     class HasOStringConvert
 
   63       template <typename C> static one test( decltype((std::string (*(C*)0)))*);
 
   64       template <typename C> static two test(...);    
 
   67       enum { value = sizeof(test<T>(0)) == sizeof(char) };
 
   71     /// \brief base class for getting the string content using
 
   72     /// streamers/default conversions
 
   74          bool hasOStreamer = HasOStreamer<T>::value,
 
   75          bool hasOConvert = HasOStringConvert<T>::value>
 
   76     struct GetStringHelperBase
 
   78       static StatusCode get (const T& /*value*/, std::string& /*result*/) {
 
   79     using namespace msgProperty;
 
   80     ANA_MSG_ERROR ("GetStringHelper: not implemented for " << typeid (T).name());
 
   81     return StatusCode::FAILURE;
 
   85     template<typename T> struct GetStringHelperBase<T,true,false>
 
   87       static StatusCode get (const T& value, std::string& result) {
 
   88     using namespace msgProperty;
 
   89     std::ostringstream str;
 
   93       return StatusCode::SUCCESS;
 
   96       ANA_MSG_ERROR ("failed to write type " << typeid(T).name() << " to string");
 
   97       return StatusCode::FAILURE;
 
  102     template<typename T,bool X> struct GetStringHelperBase<T,X,true>
 
  104       static StatusCode get (const T& value, std::string& result) {
 
  105         return packStringSingle (std::string (value), result);
 
  109     /// \brief helper class for converting properties to strings
 
  110     template<typename T> struct GetStringHelper : GetStringHelperBase<T>
 
  114     template<typename T> struct GetStringHelper<std::vector<T> >
 
  116       static StatusCode get (const std::vector<T>& value,
 
  117                  std::string& result) {
 
  118     using namespace msgProperty;
 
  119     std::vector<std::string> subresult;
 
  120     for (const auto& subvalue : value) {
 
  121       std::string myresult;
 
  122       ANA_CHECK (GetStringHelper<T>::get (subvalue, myresult));
 
  123       subresult.push_back (myresult);
 
  125     ANA_CHECK (packStringVector (subresult, result));
 
  126     return StatusCode::SUCCESS;
 
  130     template<typename T1,typename T2> struct GetStringHelper<std::map<T1,T2> >
 
  132       static StatusCode get (const std::map<T1,T2>& value,
 
  133                  std::string& result) {
 
  134     using namespace msgProperty;
 
  135     std::map<std::string,std::string> subresult;
 
  136     for (const auto& subvalue : value) {
 
  137       std::string myresult1, myresult2;
 
  138       ANA_CHECK (GetStringHelper<T1>::get (subvalue.first, myresult1));
 
  139       ANA_CHECK (GetStringHelper<T2>::get (subvalue.second, myresult2));
 
  140       subresult.emplace (myresult1, myresult2);
 
  142     ANA_CHECK (packStringMap (subresult, result));
 
  143     return StatusCode::SUCCESS;
 
  149     /// \brief the template overloads for \ref TProperty::getCastString
 
  150     template <typename T>
 
  151     struct GetCastStringHelper
 
  153       static inline StatusCode get (const T& value, std::string& result) {
 
  154         return GetStringHelper<T>::get (value, result);}
 
  158     struct GetCastStringHelper<std::string>
 
  160       static inline StatusCode get (const std::string& value, std::string& result) {
 
  161         result = value; return StatusCode::SUCCESS;}
 
  167     /// \brief check for the existence of an output streamer
 
  168     template <typename T>
 
  174       template <typename C> static one test( decltype(&(*(std::istream*)0 >> *(C*)0)));
 
  175       template <typename C> static two test(...);    
 
  178       enum { value = sizeof(test<T>(0)) == sizeof(char) };
 
  181     /// \brief check for the existence of conversion to string
 
  182     template <typename T>
 
  183     class HasIStringConvert
 
  188       template <typename C> static one test( decltype(C (std::string ()))*);
 
  189       template <typename C> static two test(...);    
 
  192       enum { value = sizeof(test<T>(0)) == sizeof(char) };
 
  196     /// \brief base class for setting the string content using
 
  197     /// streamers/default conversions
 
  199          bool hasIStreamer = HasIStreamer<T>::value,
 
  200          bool hasOConvert = HasIStringConvert<T>::value,
 
  201              bool isEnum = std::is_enum<T>::value>
 
  202     struct SetStringHelperBase
 
  204       static StatusCode set (const std::string& /*value*/, T& /*result*/) {
 
  205     using namespace msgProperty;
 
  206     ANA_MSG_ERROR ("SetStringHelper: not implemented for " << typeid (T).name());
 
  207     return StatusCode::FAILURE;
 
  211     template<typename T> struct SetStringHelperBase<T,true,false,false>
 
  213       static StatusCode set (const std::string& value, T& result) {
 
  214     using namespace msgProperty;
 
  215     std::istringstream str (value);
 
  216     if (str >> result && str.eof())
 
  218       return StatusCode::SUCCESS;
 
  221       ANA_MSG_ERROR ("failed to read type " << typeid(T).name() << " from string " << value);
 
  222       return StatusCode::FAILURE;
 
  227     template<typename T,bool X> struct SetStringHelperBase<T,X,true,false>
 
  229       static StatusCode set (const std::string& value, T& result) {
 
  230     using namespace msgProperty;
 
  231         std::string subvalue;
 
  232         if (unpackStringSingle (value, subvalue).isFailure())
 
  233           return StatusCode::FAILURE;
 
  235         return StatusCode::SUCCESS;
 
  239     template<typename T,bool X,bool Y> struct SetStringHelperBase<T,X,Y,true>
 
  241       static StatusCode set (const std::string& value, T& result) {
 
  242     using namespace msgProperty;
 
  244         if (SetStringHelperBase<int>::set (value, subvalue).isFailure())
 
  245           return StatusCode::FAILURE;
 
  246         result = T (subvalue);
 
  247         return StatusCode::SUCCESS;
 
  251     /// \brief helper class for getting property values from strings
 
  252     template<typename T> struct SetStringHelper : SetStringHelperBase<T>
 
  256     template<typename T> struct SetStringHelper<std::vector<T> >
 
  258       static StatusCode set (const std::string& value, std::vector<T>& result) {
 
  259     using namespace msgProperty;
 
  260     std::vector<std::string> myvalue;
 
  261     ANA_CHECK (unpackStringVector (value, myvalue));
 
  262     std::vector<T> myresult;
 
  263     for (const std::string& subvalue : myvalue) {
 
  265       ANA_CHECK (SetStringHelper<T>::set (subvalue, subresult));
 
  266       myresult.push_back (subresult);
 
  268     swap (myresult, result);
 
  269     return StatusCode::SUCCESS;
 
  273     template<typename T1,typename T2> struct SetStringHelper<std::map<T1,T2> >
 
  275       static StatusCode set (const std::string& value, std::map<T1,T2>& result) {
 
  276     using namespace msgProperty;
 
  277     std::map<std::string,std::string> myvalue;
 
  278     ANA_CHECK (unpackStringMap (value, myvalue));
 
  279     std::map<T1,T2> myresult;
 
  280     for (const auto& subvalue : myvalue) {
 
  283       ANA_CHECK (SetStringHelper<T1>::set (subvalue.first, subresult1));
 
  284       ANA_CHECK (SetStringHelper<T2>::set (subvalue.second, subresult2));
 
  285       myresult.emplace (subresult1, subresult2);
 
  287     swap (myresult, result);
 
  288     return StatusCode::SUCCESS;
 
  294 template< typename T >
 
  295 TProperty< T >::TProperty( T& val, Type type )
 
  296    : Property( type ), m_ptr( &val ) {
 
  300 template< typename T >
 
  301 const T* TProperty< T >::pointer() const {
 
  306 template< typename T >
 
  307 int TProperty< T >::setFrom( const Property& rhs ) {
 
  309    // Check that we have a valid pointer:
 
  310    if( ! this->pointer() ) {
 
  314    // Check if the other object is of the same type:
 
  315    const TProperty< T >* pprop = dynamic_cast< const TProperty< T >* >( &rhs );
 
  317      // Check that the other object has a valid pointer:
 
  318      if( ! pprop->pointer() ) {
 
  322      // Do the assignment:
 
  323      *m_ptr = *( pprop->pointer() );
 
  326      std::string asString;
 
  327      if (rhs.getCastString (asString).isFailure())
 
  329      return this->setString (asString).isFailure();
 
  333 template< typename T >
 
  334 StatusCode TProperty< T >::getString (std::string& result) const {
 
  335   using namespace asg::msgProperty;
 
  336   if( ! this->pointer() ) {
 
  337     ANA_MSG_ERROR ("property does not have a pointer associated");
 
  338     return StatusCode::FAILURE;
 
  340   ANA_CHECK (asg::detail::GetStringHelper<T>::get (*m_ptr, result));
 
  341   return StatusCode::SUCCESS;
 
  344 template< typename T >
 
  345 StatusCode TProperty< T >::getCastString (std::string& result) const {
 
  346   using namespace asg::msgProperty;
 
  347   if( ! this->pointer() ) {
 
  348     ANA_MSG_ERROR ("property does not have a pointer associated");
 
  349     return StatusCode::FAILURE;
 
  351   ANA_CHECK (asg::detail::GetCastStringHelper<T>::get (*m_ptr, result));
 
  352   return StatusCode::SUCCESS;
 
  355 template< typename T >
 
  356 StatusCode TProperty< T >::setString (const std::string& value) {
 
  357   using namespace asg::msgProperty;
 
  358   if( ! this->pointer() ) {
 
  359     ANA_MSG_ERROR ("property does not have a pointer associated");
 
  360     return StatusCode::FAILURE;
 
  362   ANA_CHECK (asg::detail::SetStringHelper<T>::set (value, *m_ptr));
 
  363   return StatusCode::SUCCESS;
 
  366 template< typename T >
 
  367 Property* createProperty( const T& rval ) {
 
  369    return new TProperty< T >( const_cast< T& >( rval ), Property::UNKNOWNTYPE );
 
  372 #endif // ASGTOOLS_TPROPERTY_ICC