StringIO_defs.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "StringIO.hpp"
4 #include "RuntimeId.hpp"
5 #include "Context.hpp"
6 #include "SS.hpp"
7 
8 namespace iv
9 {
10 
11 //------------- default definition -----------------------
12 template< class Type, typename Enabled >
13 struct StringIO
14 {
15  Type Read( const char * source, Context const * context ) const
16  {
17  std::stringstream in( source );
18 
19  Type type;
20  in >> type;
21 
22  // peek next character to trigger EOF flag without triggering fail flag
23  if( !in.eof() )
24  in.peek();
25 
26  if( in.fail() || !in.eof() )
27  {
28  std::string rest(std::istreambuf_iterator<char>(in), {});
29  context->log( SRC_INFO, iv::Defs::Log::Warning, "String '", source, "' can not be read as type ", typeid( Type ).name(), " using stream operator >>. Rest: '", rest, "'." );
30  return Type();
31  }
32 
33  return type;
34  }
35 
36  std::string Write( Type const & value, Context const * context ) const
37  {
38  std::stringstream ss;
39  ss << value;
40  return ss.str();
41  }
42 };
43 
44 //------ bool specialization --------------
45 template<>
46 struct StringIO< bool >
47 {
48  bool Read( const char * source, Context const * context ) const
49  {
50  std::string val( source );
51  return val == "true" || val == "1";
52  }
53 
54  std::string Write( bool const & value, Context const * context ) const
55  {
56  return value ? "true" : "false";
57  }
58 };
59 
60 //---------- string specialization ----------------------
61 template<>
62 struct StringIO< std::string >
63 {
64  std::string Read( const char * source, Context const * context ) const
65  {
66  return source;
67  }
68 
69  std::string Write( std::string const & value, Context const * context ) const
70  {
71  return value;
72  }
73 };
74 
75 //---------- cstring specialization ----------------------
76 template<>
77 struct StringIO< const char * >
78 {
79  std::string Write( const char * const & value, Context const * context ) const
80  {
81  return value;
82  }
83 };
84 
85 //--------- pointer specialization -------------
86 template< class T >
87 struct StringIO< T * >
88 {
89  T * Read( const char * source, Context const * context ) const
90  {
91  return nullptr;
92  }
93 
94  std::string Write( T * const & value, Context const * context ) const
95  {
96  return SS() << value << SS::str();
97  }
98 };
99 
100 //------------------- nullptr --------------------
101 template<>
102 struct StringIO< std::nullptr_t >
103 {
104  std::nullptr_t Read( const char * source, Context const * context ) const
105  {
106  return nullptr;
107  }
108 
109  std::string Write( std::nullptr_t const &, Context const * context ) const
110  {
111  return "nullptr";
112  }
113 };
114 
115 //---------------------- std::optional ----------------------------
116 template< class T >
117 struct StringIO< std::optional< T > >
118 {
119  static constexpr const char * NIL = "nil";
120 
121  std::optional< T > Read( const char * name, Context const * context )
122  {
123  if( strcmp( name, NIL ) == 0 )
124  return std::optional< T >( {} );
125  else
126  return StringIO< T >().Read( name, context );
127  }
128 
129  std::string Write( std::optional< T > const & value, Context const * context ) const
130  {
131  if( value.has_value() )
132  return StringIO< T >().Write( value.value(), context );
133  else
134  return std::string( NIL );
135  }
136 };
137 
138 //------------- std::pair -------------------
139 template< class T, class U >
140 struct StringIO< std::pair< T, U > >
141 {
142  std::pair< T, U > Read( const char * name, Context const * context )
143  {
144  std::string first;
145  std::string second;
146 
147  size_t i = 0;
148  size_t len = strlen( name );
149  while( i < len && name[ i ] != '(' )
150  i++;
151  i++;
152 
153  while( i < len && i != ',' )
154  first += name[ i++ ];
155  i++;
156 
157  while( i < len && i != ')' )
158  second += name[ i++ ];
159 
160  T t = StringIO_Read< T >( first.c_str(), context );
161  U u = StringIO_Read< U >( second.c_str(), context );
162  return std::pair( t, u );
163  }
164 
165  std::string Write( std::pair< T, U > const & value, Context const * context ) const
166  {
167  std::stringstream ss;
168  ss << "( " << StringIO_Write< T >( value.first, context ) << ", " << StringIO_Write< U >( value.second, context ) << " )";
169  return ss.str();
170  }
171 };
172 
173 
174 
175 //-------------- floating point values ---------------------------
176 template< class Float >
177 struct StringIO< Float, std::enable_if_t< std::is_floating_point< Float >::value > >
178 {
179  Float Read( const char * source, Context const * context ) const
180  {
181  //------- special values -----------
182  if( strcmp( source, "inf" ) == 0 )
183  return std::numeric_limits< Float >::infinity();
184  else if( strcmp( source, "+inf" ) == 0 )
185  return std::numeric_limits< Float >::infinity();
186  else if( strcmp( source, "-inf" ) == 0 )
187  return - std::numeric_limits< Float >::infinity();
188  else if( strcmp( source, "nan" ) == 0 )
189  return - std::numeric_limits< Float >::quiet_NaN();
190  else if( strcmp( source, "NaN" ) == 0 )
191  return - std::numeric_limits< Float >::quiet_NaN();
192 
193  //-------- normal read ------------
194  std::stringstream in( source );
195 
196  Float type;
197  in >> type;
198 
199  // peek next character to trigger EOF flag without triggering fail flag
200  if( !in.eof() )
201  in.peek();
202 
203  if( in.fail() || !in.eof() )
204  {
205  std::string rest(std::istreambuf_iterator<char>(in), {});
206  context->warning( SRC_INFO, "String '", source, "' can not be read as float using stream operator >>. Rest: '", rest, "'." );
207  return Float();
208  }
209 
210  return type;
211  }
212 
213  std::string Write( Float const & value, Context const * context ) const
214  {
215  return std::to_string( value );
216  }
217 };
218 
219 
220 //-------------------- RuntimeId -------------------------------
221 template< class TypedRuntimeId >
222 struct StringIO< TypedRuntimeId, std::enable_if_t< std::is_base_of< RuntimeId< TypedRuntimeId >, TypedRuntimeId >::value > >
223 {
224  TypedRuntimeId Read( const char * source, Context const * context ) const
225  {
226  auto result = TypedRuntimeId( source );
227  if( !result.valid() )
228  context->warning( SRC_INFO, "Can not read string '", source, "' as RuntimeId ", typeid( TypedRuntimeId ).name(), "." );
229 
230  return result;
231  };
232 
233  std::string Write( TypedRuntimeId const & value, Context const * context ) const
234  {
235  return value.persistent_value();
236  }
237 };
238 
239 }
240 
241 #include "StringIOIndex.hpp" // Include this just to make sure that StringIO< std::any > is defined - it is defined there and we otherwise could get into situation where both std::any and StringIO are defined but StringIO< std::any > is not.