Date: prev next · Thread: first prev next last
2011 Archives by date, by thread · List index


On Wednesday 23 of November 2011, Lubos Lunak wrote:
 I expect it would be even possible to achieve such single in-place call
even for the LOG( "P is " << p << " and b is " << b ) case, or even do this
for string+string operation, which would turn it into the even
better-looking LOG( "P is " + p + " and b is " b ) or LOG( "P is %1 and b
is %2", p, b ), whichever would suit one's fancy (as in, both would be
possible at the same time). It would require getting a bit more creative
with argument and return types for the operator overloads, but that'd be
hidden behind the scenes.

 Oh well, I guess I couldn't resist the temptation to try at least a proof of 
concept. The attached testapp (depending on #define OPT) compiles things like 
string1 + "foo" + string2 + "bar" + string3 into a call to a single function 
which allocates just a single string object for the result of the operation, 
no intermediate string objects or allocations are required.

 So it indeed looks doable and we can have efficient and at the same time not 
ackward to use string operations. Something for the next Hackweek or so.

 Could somebody try that it works with the Windows compiler as well?

-- 
 Lubos Lunak
 l.lunak@suse.cz
#include <stdio.h>
#include <string.h>

class string
    {
    public:
        string( const char* str = NULL );
        string( const string& );
        string( char* data, int len );
        string& operator=( const string& );
        string& operator+=( const string& );
        ~string();
        const char* str() const;
//    private:
        int len;
        char* data;
    };

#define OPT

inline string::string( char* data, int len )
    : len( len )
    , data( data )
    {
    }

#ifndef OPT
inline string operator+( const string& str1, const string& str2 )
    {
    return string( str1 ) += str2;
    }
#else
template< typename T1, typename T2 >
class stringplus
    {
    public:
        stringplus( const T1& s1, const T2& s2 );
        operator string() const;
//    private:
        const T1& str1;
        const T2& str2;
    };

template< typename T1, typename T2 >
inline stringplus< T1, T2 >::stringplus( const T1& s1, const T2& s2 )
    : str1( s1 )
    , str2( s2 )
    {
    }

template< typename T1, typename T2 >
inline stringplus< T1, T2 > operator+( const T1& str1, const T2& str2 )
    {
    return stringplus< T1, T2 >( str1, str2 );
    }

template< typename T >
static int len( const T& s );
template< typename T >
static void copydata( char* dest, const T& s );

inline int len( const char* s )
    {
    return strlen( s );
    }
inline void copydata( char* dest, const char* s )
    {
    strcpy( dest, s );
    }

template<>
inline int len( const string& s )
    {
    return s.len;
    }
template<>
inline void copydata( char* dest, const string& s )
    {
    strcpy( dest, s.data );
    }

template< typename T1, typename T2 >
inline int len( const stringplus< T1, T2 >& str )
    {
    return len( str.str1 ) + len( str.str2 );
    }
template< typename T1, typename T2 >
inline void copydata( char* dest, const stringplus< T1, T2 >& str )
    {
    int len1 = len( str.str1 );
    copydata( dest, str.str1 );
    copydata( dest + len1, str.str2 );
    }

template< typename T1, typename T2 >
string concat( const T1& str1, const T2& str2 )
    {
    int len1 = len( str1 );
    int len2 = len( str2 );
    char* newdata = new char[ len1 + len2 + 1 ];
    copydata( newdata, str1 );
    copydata( newdata + len1, str2 );
    printf( "ALLOC %s\n", newdata );
    return string( newdata, len1 + len2 );
    }

template< typename T1, typename T2 >
inline string make_concat( const stringplus< T1, T2 >& str )
    {
    return concat( str.str1, str.str2 );
    }

// A helper function is needed, because the compiler does not like
// a template that recursively refers to itself, i.e. this:
// template< typename T1, typename T2, typename T3 >
// inline stringplus< stringplus< T1, T2 >, T3 >::operator string() const .
// Not sure whether maybe I'm doing something wrong, but this easily solves it.
template< typename T1, typename T2, typename T3 >
inline string make_concat( const stringplus< T1, T2 >& str1, const T2& str2 )
    {
    return concat( str1.str1, str1.str2, str2 );
    }

template< typename T1, typename T2 >
inline stringplus< T1, T2 >::operator string() const
    {
    return make_concat( *this );
    }
#endif

inline const char* string::str() const
    {
    return data;
    }


string::string( const char* str )
    : len( str != NULL ? strlen( str ) : 0 )
    , data( new char[ len + 1 ] )
    {
    if( str != NULL )
        strcpy( data, str );
    else
        *data = '\0';
    printf( "ALLOC %s\n", data );
    }

string::string( const string& str )
    : len( str.len )
    , data( new char[ len + 1 ] )
    {
    strcpy( data, str.data );
    printf( "ALLOC %s\n", data );
    }

string& string::operator=( const string& str )
    {
    if( data == str.data )
        return *this;
    delete[] data;
    data = new char[ str.len + 1 ];
    strcpy( data, str.data );
    len = str.len;
    printf( "ALLOC %s\n", data );
    return *this;
    }

string& string::operator+=( const string& str )
    {
    char* newdata = new char[ len + str.len + 1 ];
    strcpy( newdata, data );
    strcat( newdata, str.data );
    delete[] data;
    data = newdata;
    len += str.len;
    printf( "ALLOC %s\n", data );
    return *this;
    }

string::~string()
    {
    delete[] data;
    }

string test2( const string& s1, const string& s2 )
    {
    return s1 + "-" + s2 + "-" + s1;
    }

void test()
    {
    string s1( "test" );
    string s2( "this" );
    string s3 = test2( s1, s2 );
    printf( "%s\n", s3.str());
    }

int main()
    {
    test();
    }

Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.