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  template<typename T> struct SetStringHelper : SetStringHelperBase<T>
253  {
254  };
255 
256  template<typename T> struct SetStringHelper<std::vector<T> >
257  {
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) {
264  T subresult {};
265  ANA_CHECK (SetStringHelper<T>::set (subvalue, subresult));
266  myresult.push_back (subresult);
267  }
268  swap (myresult, result);
269  return StatusCode::SUCCESS;
270  }
271  };
272 
273  template<typename T1,typename T2> struct SetStringHelper<std::map<T1,T2> >
274  {
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) {
281  T1 subresult1 {};
282  T2 subresult2 {};
283  ANA_CHECK (SetStringHelper<T1>::set (subvalue.first, subresult1));
284  ANA_CHECK (SetStringHelper<T2>::set (subvalue.second, subresult2));
285  myresult.emplace (subresult1, subresult2);
286  }
287  swap (myresult, result);
288  return StatusCode::SUCCESS;
289  }
290  };
291  }
292 }
293 
294 template< typename T >
295 TProperty< T >::TProperty( T& val, Type type )
296  : Property( type ), m_ptr( &val ) {
297 
298 }
299 
300 template< typename T >
301 const T* TProperty< T >::pointer() const {
302 
303  return m_ptr;
304 }
305 
306 template< typename T >
307 int TProperty< T >::setFrom( const Property& rhs ) {
308 
309  // Check that we have a valid pointer:
310  if( ! this->pointer() ) {
311  return 1;
312  }
313 
314  // Check if the other object is of the same type:
315  const TProperty< T >* pprop = dynamic_cast< const TProperty< T >* >( &rhs );
316  if( pprop ) {
317  // Check that the other object has a valid pointer:
318  if( ! pprop->pointer() ) {
319  return 1;
320  }
321 
322  // Do the assignment:
323  *m_ptr = *( pprop->pointer() );
324  return 0;
325  } else {
326  std::string asString;
327  if (rhs.getCastString (asString).isFailure())
328  return 1;
329  return this->setString (asString).isFailure();
330  }
331 }
332 
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;
339  }
340  ANA_CHECK (asg::detail::GetStringHelper<T>::get (*m_ptr, result));
341  return StatusCode::SUCCESS;
342 }
343 
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;
350  }
351  ANA_CHECK (asg::detail::GetCastStringHelper<T>::get (*m_ptr, result));
352  return StatusCode::SUCCESS;
353 }
354 
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;
361  }
362  ANA_CHECK (asg::detail::SetStringHelper<T>::set (value, *m_ptr));
363  return StatusCode::SUCCESS;
364 }
365 
366 template< typename T >
367 Property* createProperty( const T& rval ) {
368 
369  return new TProperty< T >( const_cast< T& >( rval ), Property::UNKNOWNTYPE );
370 }
371 
372 #endif // ASGTOOLS_TPROPERTY_ICC