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