ATLAS Offline Software
TProperty.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #ifndef ASGTOOLS_TPROPERTY_ICC
6 #define ASGTOOLS_TPROPERTY_ICC
7 
8 #include <AsgTools/MessageCheckAsgTools.h>
9 #include <map>
10 #include <sstream>
11 #include <typeinfo>
12 #include <type_traits>
13 
14 namespace asg
15 {
16  namespace detail
17  {
18  /// \brief pack a single string into a property string
19  StatusCode packStringSingle (const std::string& value,
20  std::string& result);
21 
22  /// \brief pack a vector of strings into a property string
23  StatusCode packStringVector (const std::vector<std::string>& value,
24  std::string& result);
25 
26  /// \brief pack a vector of strings into a property string
27  StatusCode packStringMap (const std::map<std::string,std::string>& value,
28  std::string& result);
29 
30  /// \brief unpack a single string from a property string
31  StatusCode unpackStringSingle (const std::string& value,
32  std::string& result);
33 
34  /// \brief unpack a vector of strings from a property string
35  StatusCode unpackStringVector (const std::string& value,
36  std::vector<std::string>& result);
37 
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);
41 
42  /// \brief check for the existence of an output streamer
43  template <typename T>
44  class HasOStreamer
45  {
46  typedef char one;
47  typedef long two;
48 
49  template <typename C> static one test( decltype(&(*(std::ostream*)0 << *(C*)0)));
50  template <typename C> static two test(...);
51 
52  public:
53  enum { value = sizeof(test<T>(0)) == sizeof(char) };
54  };
55 
56  /// \brief check for the existence of conversion to string
57  template <typename T>
58  class HasOStringConvert
59  {
60  typedef char one;
61  typedef long two;
62 
63  template <typename C> static one test( decltype((std::string (*(C*)0)))*);
64  template <typename C> static two test(...);
65 
66  public:
67  enum { value = sizeof(test<T>(0)) == sizeof(char) };
68  };
69 
70 
71  /// \brief base class for getting the string content using
72  /// streamers/default conversions
73  template<typename T,
74  bool hasOStreamer = HasOStreamer<T>::value,
75  bool hasOConvert = HasOStringConvert<T>::value>
76  struct GetStringHelperBase
77  {
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;
82  }
83  };
84 
85  template<typename T> struct GetStringHelperBase<T,true,false>
86  {
87  static StatusCode get (const T& value, std::string& result) {
88  using namespace msgProperty;
89  std::ostringstream str;
90  if (str << value)
91  {
92  result = str.str();
93  return StatusCode::SUCCESS;
94  } else
95  {
96  ANA_MSG_ERROR ("failed to write type " << typeid(T).name() << " to string");
97  return StatusCode::FAILURE;
98  }
99  }
100  };
101 
102  template<typename T,bool X> struct GetStringHelperBase<T,X,true>
103  {
104  static StatusCode get (const T& value, std::string& result) {
105  return packStringSingle (std::string (value), result);
106  }
107  };
108 
109  /// \brief helper class for converting properties to strings
110  template<typename T> struct GetStringHelper : GetStringHelperBase<T>
111  {
112  };
113 
114  template<typename T> struct GetStringHelper<std::vector<T> >
115  {
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);
124  }
125  ANA_CHECK (packStringVector (subresult, result));
126  return StatusCode::SUCCESS;
127  }
128  };
129 
130  template<typename T1,typename T2> struct GetStringHelper<std::map<T1,T2> >
131  {
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);
141  }
142  ANA_CHECK (packStringMap (subresult, result));
143  return StatusCode::SUCCESS;
144  }
145  };
146 
147 
148 
149  /// \brief the template overloads for \ref TProperty::getCastString
150  template <typename T>
151  struct GetCastStringHelper
152  {
153  static inline StatusCode get (const T& value, std::string& result) {
154  return GetStringHelper<T>::get (value, result);}
155  };
156 
157  template <>
158  struct GetCastStringHelper<std::string>
159  {
160  static inline StatusCode get (const std::string& value, std::string& result) {
161  result = value; return StatusCode::SUCCESS;}
162  };
163 
164 
165 
166 
167  /// \brief check for the existence of an output streamer
168  template <typename T>
169  class HasIStreamer
170  {
171  typedef char one;
172  typedef long two;
173 
174  template <typename C> static one test( decltype(&(*(std::istream*)0 >> *(C*)0)));
175  template <typename C> static two test(...);
176 
177  public:
178  enum { value = sizeof(test<T>(0)) == sizeof(char) };
179  };
180 
181  /// \brief check for the existence of conversion to string
182  template <typename T>
183  class HasIStringConvert
184  {
185  typedef char one;
186  typedef long two;
187 
188  template <typename C> static one test( decltype(C (std::string ()))*);
189  template <typename C> static two test(...);
190 
191  public:
192  enum { value = sizeof(test<T>(0)) == sizeof(char) };
193  };
194 
195 
196  /// \brief base class for setting the string content using
197  /// streamers/default conversions
198  template<typename T,
199  bool hasIStreamer = HasIStreamer<T>::value,
200  bool hasOConvert = HasIStringConvert<T>::value,
201  bool isEnum = std::is_enum<T>::value>
202  struct SetStringHelperBase
203  {
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;
208  }
209  };
210 
211  template<typename T> struct SetStringHelperBase<T,true,false,false>
212  {
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())
217  {
218  return StatusCode::SUCCESS;
219  } else
220  {
221  ANA_MSG_ERROR ("failed to read type " << typeid(T).name() << " from string " << value);
222  return StatusCode::FAILURE;
223  }
224  }
225  };
226 
227  template<typename T,bool X> struct SetStringHelperBase<T,X,true,false>
228  {
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;
234  result = subvalue;
235  return StatusCode::SUCCESS;
236  }
237  };
238 
239  template<typename T,bool X,bool Y> struct SetStringHelperBase<T,X,Y,true>
240  {
241  static StatusCode set (const std::string& value, T& result) {
242  using namespace msgProperty;
243  int subvalue = 0;
244  if (SetStringHelperBase<int>::set (value, subvalue).isFailure())
245  return StatusCode::FAILURE;
246  result = T (subvalue);
247  return StatusCode::SUCCESS;
248  }
249  };
250 
251  /// \brief helper class for getting property values from strings
252  // cppcheck-suppress syntaxError
253  template<typename T> struct SetStringHelper : SetStringHelperBase<T>
254  {
255  };
256 
257  template<typename T> struct SetStringHelper<std::vector<T> >
258  {
259  static StatusCode set (const std::string& value, std::vector<T>& result) {
260  using namespace msgProperty;
261  std::vector<std::string> myvalue;
262  ANA_CHECK (unpackStringVector (value, myvalue));
263  std::vector<T> myresult;
264  for (const std::string& subvalue : myvalue) {
265  T subresult {};
266  ANA_CHECK (SetStringHelper<T>::set (subvalue, subresult));
267  myresult.push_back (subresult);
268  }
269  swap (myresult, result);
270  return StatusCode::SUCCESS;
271  }
272  };
273 
274  template<typename T1,typename T2> struct SetStringHelper<std::map<T1,T2> >
275  {
276  static StatusCode set (const std::string& value, std::map<T1,T2>& result) {
277  using namespace msgProperty;
278  std::map<std::string,std::string> myvalue;
279  ANA_CHECK (unpackStringMap (value, myvalue));
280  std::map<T1,T2> myresult;
281  for (const auto& subvalue : myvalue) {
282  T1 subresult1 {};
283  T2 subresult2 {};
284  ANA_CHECK (SetStringHelper<T1>::set (subvalue.first, subresult1));
285  ANA_CHECK (SetStringHelper<T2>::set (subvalue.second, subresult2));
286  myresult.emplace (subresult1, subresult2);
287  }
288  swap (myresult, result);
289  return StatusCode::SUCCESS;
290  }
291  };
292  }
293 }
294 
295 template< typename T >
296 TProperty< T >::TProperty( T& val, Type type )
297  : Property( type ), m_ptr( &val ) {
298 
299 }
300 
301 template< typename T >
302 const T* TProperty< T >::pointer() const {
303 
304  return m_ptr;
305 }
306 
307 template< typename T >
308 int TProperty< T >::setFrom( const Property& rhs ) {
309 
310  // Check that we have a valid pointer:
311  if( ! this->pointer() ) {
312  return 1;
313  }
314 
315  // Check if the other object is of the same type:
316  const TProperty< T >* pprop = dynamic_cast< const TProperty< T >* >( &rhs );
317  if( pprop ) {
318  // Check that the other object has a valid pointer:
319  if( ! pprop->pointer() ) {
320  return 1;
321  }
322 
323  // Do the assignment:
324  *m_ptr = *( pprop->pointer() );
325  return 0;
326  } else {
327  std::string asString;
328  if (rhs.getCastString (asString).isFailure())
329  return 1;
330  return this->setString (asString).isFailure();
331  }
332 }
333 
334 template< typename T >
335 StatusCode TProperty< T >::getString (std::string& result) const {
336  using namespace asg::msgProperty;
337  if( ! this->pointer() ) {
338  ANA_MSG_ERROR ("property does not have a pointer associated");
339  return StatusCode::FAILURE;
340  }
341  ANA_CHECK (asg::detail::GetStringHelper<T>::get (*m_ptr, result));
342  return StatusCode::SUCCESS;
343 }
344 
345 template< typename T >
346 StatusCode TProperty< T >::getCastString (std::string& result) const {
347  using namespace asg::msgProperty;
348  if( ! this->pointer() ) {
349  ANA_MSG_ERROR ("property does not have a pointer associated");
350  return StatusCode::FAILURE;
351  }
352  ANA_CHECK (asg::detail::GetCastStringHelper<T>::get (*m_ptr, result));
353  return StatusCode::SUCCESS;
354 }
355 
356 template< typename T >
357 StatusCode TProperty< T >::setString (const std::string& value) {
358  using namespace asg::msgProperty;
359  if( ! this->pointer() ) {
360  ANA_MSG_ERROR ("property does not have a pointer associated");
361  return StatusCode::FAILURE;
362  }
363  ANA_CHECK (asg::detail::SetStringHelper<T>::set (value, *m_ptr));
364  return StatusCode::SUCCESS;
365 }
366 
367 template< typename T >
368 Property* createProperty( const T& rval ) {
369 
370  return new TProperty< T >( const_cast< T& >( rval ), Property::UNKNOWNTYPE );
371 }
372 
373 #endif // ASGTOOLS_TPROPERTY_ICC