1 /* 2 * Created by Phil on 8/5/2012. 3 * Copyright 2012 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 #ifndef TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED 9 #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED 10 11 #include "catch_common.h" 12 13 #include <sstream> 14 #include <iomanip> 15 #include <limits> 16 #include <vector> 17 #include <cstddef> 18 19 #ifdef __OBJC__ 20 #include "catch_objc_arc.hpp" 21 #endif 22 23 #ifdef CATCH_CONFIG_CPP11_TUPLE 24 #include <tuple> 25 #endif 26 27 #ifdef CATCH_CONFIG_CPP11_IS_ENUM 28 #include <type_traits> 29 #endif 30 31 namespace Catch { 32 33 // Why we're here. 34 template<typename T> 35 std::string toString( T const& value ); 36 37 // Built in overloads 38 39 std::string toString( std::string const& value ); 40 std::string toString( std::wstring const& value ); 41 std::string toString( const char* const value ); 42 std::string toString( char* const value ); 43 std::string toString( const wchar_t* const value ); 44 std::string toString( wchar_t* const value ); 45 std::string toString( int value ); 46 std::string toString( unsigned long value ); 47 std::string toString( unsigned int value ); 48 std::string toString( const double value ); 49 std::string toString( const float value ); 50 std::string toString( bool value ); 51 std::string toString( char value ); 52 std::string toString( signed char value ); 53 std::string toString( unsigned char value ); 54 55 #ifdef CATCH_CONFIG_CPP11_LONG_LONG 56 std::string toString( long long value ); 57 std::string toString( unsigned long long value ); 58 #endif 59 60 #ifdef CATCH_CONFIG_CPP11_NULLPTR 61 std::string toString( std::nullptr_t ); 62 #endif 63 64 #ifdef __OBJC__ 65 std::string toString( NSString const * const& nsstring ); 66 std::string toString( NSString * CATCH_ARC_STRONG & nsstring ); 67 std::string toString( NSObject* const& nsObject ); 68 #endif 69 70 71 namespace Detail { 72 73 extern const std::string unprintableString; 74 75 #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) 76 struct BorgType { 77 template<typename T> BorgType( T const& ); 78 }; 79 80 struct TrueType { char sizer[1]; }; 81 struct FalseType { char sizer[2]; }; 82 83 TrueType& testStreamable( std::ostream& ); 84 FalseType testStreamable( FalseType ); 85 86 FalseType operator<<( std::ostream const&, BorgType const& ); 87 88 template<typename T> 89 struct IsStreamInsertable { 90 static std::ostream &s; 91 static T const&t; 92 enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; 93 }; 94 #else 95 template<typename T> 96 class IsStreamInsertable { 97 template<typename SS, typename TT> 98 static auto test(int) 99 -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() ); 100 101 template<typename, typename> 102 static auto test(...) -> std::false_type; 103 104 public: 105 static const bool value = decltype(test<std::ostream,const T&>(0))::value; 106 }; 107 #endif 108 109 #if defined(CATCH_CONFIG_CPP11_IS_ENUM) 110 template<typename T, 111 bool IsEnum = std::is_enum<T>::value 112 > 113 struct EnumStringMaker 114 { convertEnumStringMaker115 static std::string convert( T const& ) { return unprintableString; } 116 }; 117 118 template<typename T> 119 struct EnumStringMaker<T,true> 120 { 121 static std::string convert( T const& v ) 122 { 123 return ::Catch::toString( 124 static_cast<typename std::underlying_type<T>::type>(v) 125 ); 126 } 127 }; 128 #endif 129 template<bool C> 130 struct StringMakerBase { 131 #if defined(CATCH_CONFIG_CPP11_IS_ENUM) 132 template<typename T> 133 static std::string convert( T const& v ) 134 { 135 return EnumStringMaker<T>::convert( v ); 136 } 137 #else 138 template<typename T> 139 static std::string convert( T const& ) { return unprintableString; } 140 #endif 141 }; 142 143 template<> 144 struct StringMakerBase<true> { 145 template<typename T> 146 static std::string convert( T const& _value ) { 147 std::ostringstream oss; 148 oss << _value; 149 return oss.str(); 150 } 151 }; 152 153 std::string rawMemoryToString( const void *object, std::size_t size ); 154 155 template<typename T> 156 std::string rawMemoryToString( const T& object ) { 157 return rawMemoryToString( &object, sizeof(object) ); 158 } 159 160 } // end namespace Detail 161 162 template<typename T> 163 struct StringMaker : 164 Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; 165 166 template<typename T> 167 struct StringMaker<T*> { 168 template<typename U> 169 static std::string convert( U* p ) { 170 if( !p ) 171 return "NULL"; 172 else 173 return Detail::rawMemoryToString( p ); 174 } 175 }; 176 177 template<typename R, typename C> 178 struct StringMaker<R C::*> { 179 static std::string convert( R C::* p ) { 180 if( !p ) 181 return "NULL"; 182 else 183 return Detail::rawMemoryToString( p ); 184 } 185 }; 186 187 namespace Detail { 188 template<typename InputIterator> 189 std::string rangeToString( InputIterator first, InputIterator last ); 190 } 191 192 //template<typename T, typename Allocator> 193 //struct StringMaker<std::vector<T, Allocator> > { 194 // static std::string convert( std::vector<T,Allocator> const& v ) { 195 // return Detail::rangeToString( v.begin(), v.end() ); 196 // } 197 //}; 198 199 template<typename T, typename Allocator> 200 std::string toString( std::vector<T,Allocator> const& v ) { 201 return Detail::rangeToString( v.begin(), v.end() ); 202 } 203 204 205 #ifdef CATCH_CONFIG_CPP11_TUPLE 206 207 // toString for tuples 208 namespace TupleDetail { 209 template< 210 typename Tuple, 211 std::size_t N = 0, 212 bool = (N < std::tuple_size<Tuple>::value) 213 > 214 struct ElementPrinter { 215 static void print( const Tuple& tuple, std::ostream& os ) 216 { 217 os << ( N ? ", " : " " ) 218 << Catch::toString(std::get<N>(tuple)); 219 ElementPrinter<Tuple,N+1>::print(tuple,os); 220 } 221 }; 222 223 template< 224 typename Tuple, 225 std::size_t N 226 > 227 struct ElementPrinter<Tuple,N,false> { 228 static void print( const Tuple&, std::ostream& ) {} 229 }; 230 231 } 232 233 template<typename ...Types> 234 struct StringMaker<std::tuple<Types...>> { 235 236 static std::string convert( const std::tuple<Types...>& tuple ) 237 { 238 std::ostringstream os; 239 os << '{'; 240 TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os ); 241 os << " }"; 242 return os.str(); 243 } 244 }; 245 #endif // CATCH_CONFIG_CPP11_TUPLE 246 247 namespace Detail { 248 template<typename T> 249 std::string makeString( T const& value ) { 250 return StringMaker<T>::convert( value ); 251 } 252 } // end namespace Detail 253 254 /// \brief converts any type to a string 255 /// 256 /// The default template forwards on to ostringstream - except when an 257 /// ostringstream overload does not exist - in which case it attempts to detect 258 /// that and writes {?}. 259 /// Overload (not specialise) this template for custom typs that you don't want 260 /// to provide an ostream overload for. 261 template<typename T> 262 std::string toString( T const& value ) { 263 return StringMaker<T>::convert( value ); 264 } 265 266 267 namespace Detail { 268 template<typename InputIterator> 269 std::string rangeToString( InputIterator first, InputIterator last ) { 270 std::ostringstream oss; 271 oss << "{ "; 272 if( first != last ) { 273 oss << Catch::toString( *first ); 274 for( ++first ; first != last ; ++first ) 275 oss << ", " << Catch::toString( *first ); 276 } 277 oss << " }"; 278 return oss.str(); 279 } 280 } 281 282 } // end namespace Catch 283 284 #endif // TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED 285