/* * Created by Phil on 8/5/2012. * Copyright 2012 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED #include "catch_common.h" #include "catch_sfinae.hpp" #include <sstream> #include <iomanip> #include <limits> #include <vector> #include <cstddef> #ifdef __OBJC__ #include "catch_objc_arc.hpp" #endif namespace Catch { namespace Detail { // SFINAE is currently disabled by default for all compilers. // If the non SFINAE version of IsStreamInsertable is ambiguous for you // and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE #ifdef CATCH_CONFIG_SFINAE template<typename T> class IsStreamInsertableHelper { template<int N> struct TrueIfSizeable : TrueType {}; template<typename T2> static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*); static FalseType dummy(...); public: typedef SizedIf<sizeof(dummy((T*)0))> type; }; template<typename T> struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {}; #else struct BorgType { template<typename T> BorgType( T const& ); }; TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); FalseType operator<<( std::ostream const&, BorgType const& ); template<typename T> struct IsStreamInsertable { static std::ostream &s; static T const&t; enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; #endif template<bool C> struct StringMakerBase { template<typename T> static std::string convert( T const& ) { return "{?}"; } }; template<> struct StringMakerBase<true> { template<typename T> static std::string convert( T const& _value ) { std::ostringstream oss; oss << _value; return oss.str(); } }; std::string rawMemoryToString( const void *object, std::size_t size ); template<typename T> inline std::string rawMemoryToString( const T& object ) { return rawMemoryToString( &object, sizeof(object) ); } } // end namespace Detail template<typename T> std::string toString( T const& value ); template<typename T> struct StringMaker : Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; template<typename T> struct StringMaker<T*> { template<typename U> static std::string convert( U* p ) { if( !p ) return INTERNAL_CATCH_STRINGIFY( NULL ); else return Detail::rawMemoryToString( p ); } }; template<typename R, typename C> struct StringMaker<R C::*> { static std::string convert( R C::* p ) { if( !p ) return INTERNAL_CATCH_STRINGIFY( NULL ); else return Detail::rawMemoryToString( p ); } }; namespace Detail { template<typename InputIterator> std::string rangeToString( InputIterator first, InputIterator last ); } template<typename T, typename Allocator> struct StringMaker<std::vector<T, Allocator> > { static std::string convert( std::vector<T,Allocator> const& v ) { return Detail::rangeToString( v.begin(), v.end() ); } }; namespace Detail { template<typename T> std::string makeString( T const& value ) { return StringMaker<T>::convert( value ); } } // end namespace Detail /// \brief converts any type to a string /// /// The default template forwards on to ostringstream - except when an /// ostringstream overload does not exist - in which case it attempts to detect /// that and writes {?}. /// Overload (not specialise) this template for custom typs that you don't want /// to provide an ostream overload for. template<typename T> std::string toString( T const& value ) { return StringMaker<T>::convert( value ); } // Built in overloads std::string toString( std::string const& value ); std::string toString( std::wstring const& value ); std::string toString( const char* const value ); std::string toString( char* const value ); std::string toString( const wchar_t* const value ); std::string toString( wchar_t* const value ); std::string toString( int value ); std::string toString( unsigned long value ); std::string toString( unsigned int value ); std::string toString( const double value ); std::string toString( const float value ); std::string toString( bool value ); std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif #ifdef __OBJC__ std::string toString( NSString const * const& nsstring ); std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); std::string toString( NSObject* const& nsObject ); #endif namespace Detail { template<typename InputIterator> std::string rangeToString( InputIterator first, InputIterator last ) { std::ostringstream oss; oss << "{ "; if( first != last ) { oss << toString( *first ); for( ++first ; first != last ; ++first ) { oss << ", " << toString( *first ); } } oss << " }"; return oss.str(); } } } // end namespace Catch #endif // TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED