/* * 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 <sstream> #include <iomanip> #include <limits> #include <vector> #include <cstddef> #ifdef __OBJC__ #include "catch_objc_arc.hpp" #endif #ifdef CATCH_CONFIG_CPP11_TUPLE #include <tuple> #endif #ifdef CATCH_CONFIG_CPP11_IS_ENUM #include <type_traits> #endif namespace Catch { // Why we're here. template<typename T> std::string toString( T const& 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_LONG_LONG std::string toString( long long value ); std::string toString( unsigned long long value ); #endif #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 { extern const std::string unprintableString; struct BorgType { template<typename T> BorgType( T const& ); }; struct TrueType { char sizer[1]; }; struct FalseType { char sizer[2]; }; 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 ) }; }; #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template<typename T, bool IsEnum = std::is_enum<T>::value > struct EnumStringMaker { static std::string convert( T const& ) { return unprintableString; } }; template<typename T> struct EnumStringMaker<T,true> { static std::string convert( T const& v ) { return ::Catch::toString( static_cast<typename std::underlying_type<T>::type>(v) ); } }; #endif template<bool C> struct StringMakerBase { #if defined(CATCH_CONFIG_CPP11_IS_ENUM) template<typename T> static std::string convert( T const& v ) { return EnumStringMaker<T>::convert( v ); } #else template<typename T> static std::string convert( T const& ) { return unprintableString; } #endif }; 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> 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 "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 "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() ); // } //}; template<typename T, typename Allocator> std::string toString( std::vector<T,Allocator> const& v ) { return Detail::rangeToString( v.begin(), v.end() ); } #ifdef CATCH_CONFIG_CPP11_TUPLE // toString for tuples namespace TupleDetail { template< typename Tuple, std::size_t N = 0, bool = (N < std::tuple_size<Tuple>::value) > struct ElementPrinter { static void print( const Tuple& tuple, std::ostream& os ) { os << ( N ? ", " : " " ) << Catch::toString(std::get<N>(tuple)); ElementPrinter<Tuple,N+1>::print(tuple,os); } }; template< typename Tuple, std::size_t N > struct ElementPrinter<Tuple,N,false> { static void print( const Tuple&, std::ostream& ) {} }; } template<typename ...Types> struct StringMaker<std::tuple<Types...>> { static std::string convert( const std::tuple<Types...>& tuple ) { std::ostringstream os; os << '{'; TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os ); os << " }"; return os.str(); } }; #endif // CATCH_CONFIG_CPP11_TUPLE 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 ); } namespace Detail { template<typename InputIterator> std::string rangeToString( InputIterator first, InputIterator last ) { std::ostringstream oss; oss << "{ "; if( first != last ) { oss << Catch::toString( *first ); for( ++first ; first != last ; ++first ) oss << ", " << Catch::toString( *first ); } oss << " }"; return oss.str(); } } } // end namespace Catch #endif // TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED