/* ///////////////////////////////////////////////////////////////////////////// * File: fast_string_concatenator_test.cpp * * Purpose: Implementation file for the fast_string_concatenator_test project. * * Created: 30th August 2003 * Updated: 1st September 2004 * * Status: Wizard-generated * * License: (Licensed under the Synesis Software Open License) * * Copyright (C) 1999-2003, Synesis Software Pty Ltd. * All rights reserved. * * www: http://www.synesis.com.au/software * * email: software@synesis.com.au * * This source code is placed into the public domain 2003 * by Synesis Software Pty Ltd. There are no restrictions * whatsoever to your use of the software. * * This source code is provided by Synesis Software Pty Ltd "as is" * and any warranties, whether expressed or implied, including, but * not limited to, the implied warranties of merchantability and * fitness for a particular purpose are disclaimed. In no event * shall the Synesis Software Pty Ltd be liable for any direct, * indirect, incidental, special, exemplary, or consequential * damages (including, but not limited to, procurement of * substitute goods or services; loss of use, data, or profits; or * business interruption) however caused and on any theory of * liability, whether in contract, strict liability, or tort * (including negligence or otherwise) arising in any way out of * the use of this software, even if advised of the possibility of * such damage. * * Neither the name of Synesis Software Pty Ltd nor the names of * any subdivisions, employees or agents of Synesis Software Pty * Ltd, nor the names of any other contributors to this software * may be used to endorse or promote products derived from this * software without specific prior written permission. * * ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ //#define STLSOFT_FAST_STRING_CONCATENATION_ASSUME_CONTIGUOUS_STORAGE ////#define USE_SS_SIMPLE_STRING ////#define USE_FAST_CONCAT //#define USE_STD_STRING //#define USE_SS_SIMPLE_STRING //#define USE_SS_FRAME_STRING //#define USE_OWN_STRING //#define USE_SYNESIS_STRING //#define USE_FAST_CONCAT #ifdef _DEBUG const int DEF_ITERATIONS = 1000; #else /* ? _DEBUG */ const int DEF_ITERATIONS = 200000; #endif /* _DEBUG */ #ifdef USE_SEED # error USE_SEED cannot be specified. It is now a command-line argument #endif /* USE_SEED */ #ifndef USE_FAST_CONCAT # define STLSOFT_STD_STRING_NO_USE_FAST_CONCATENATOR #endif /* USE_FAST_CONCAT */ /* ////////////////////////////////////////////////////////////////////////// */ static void usage(int bExit); static int do_test(int iterations, int multiplier, int cConcats, bool bUseSeed, bool bPathologicalBracing); /* ////////////////////////////////////////////////////////////////////////// */ #include #include #include #include #if defined(USE_STD_STRING) # include #elif defined(USE_SS_SIMPLE_STRING) # include #elif defined(USE_SS_FRAME_STRING) # include #elif defined(USE_SYNESIS_STRING) # ifndef USE_FAST_CONCAT # define _SYNSOFT_SYSTRING_NO_USE_FAST_CONCATENATOR # endif /* USE_FAST_CONCAT */ # include #endif /* string */ #ifdef USE_FAST_CONCAT # if defined(STLSOFT_STD_STRING_USE_FAST_CONCATENATOR) # ifndef _STLSOFT_INCL_H_STLSOFT_FAST_STRING_CONCATENATOR # error stlsoft_fast_string_concatenator.h is not included in the standard library # endif /* _STLSOFT_INCL_H_STLSOFT_FAST_STRING_CONCATENATOR */ # else # include # endif /* !USE_STD_STRING || (!__MWERKS__ && !__DMC__) */ #else /* ? USE_FAST_CONCAT */ #endif /* USE_FAST_CONCAT */ #if defined(WIN32) || \ defined(_WIN32) # include # if defined(_MSC_VER) && \ _MSC_VER < 1100 # include typedef winstl_ns_qual(tick_counter) performance_counter; # else # include winstl_ns_using(performance_counter) # endif /* _MSC_VER < 1100 */ #else // Assuming UNIX # include # include unixstl_ns_using(performance_counter) #endif /* platform */ #ifdef USE_WCHAR # include typedef wchar_t char_t; # define CHAR_TYPE "wchar_t" # define C_T(x) L ## x # define string_len wcslen # define string_ncpy wcsncpy # define string_cpy wcscpy # define string_cat wcscat #else typedef char char_t; # define CHAR_TYPE "char" # define C_T(x) x # define string_len strlen # define string_ncpy strncpy # define string_cpy strcpy # define string_cat strcat #endif /* USE_WCHAR */ /* ////////////////////////////////////////////////////////////////////////// */ #if defined(USE_STD_STRING) # define STRING_TYPE "std::string" # ifdef USE_WCHAR # ifdef __GNUC__ # include typedef stlsoft_ns_qual_std(basic_string) > String; # else /* ? __GNUC__ */ typedef stlsoft_ns_qual_std(wstring) String; # endif /* __GNUC__ */ # else typedef stlsoft_ns_qual_std(string) String; # endif /* USE_WCHAR */ #elif defined(USE_SS_SIMPLE_STRING) # define STRING_TYPE "stlsoft::simple_string" typedef stlsoft::basic_simple_string String; #elif defined(USE_SS_FRAMEE_STRING) # define STRING_TYPE "stlsoft::frame_string" typedef stlsoft::basic_frame_string String; #elif defined(USE_SYNESIS_STRING) # define STRING_TYPE "SynesisDev::string" # ifdef USE_WCHAR typedef SynesisDev::stringw String; # else typedef SynesisDev::stringa String; # endif /* USE_WCHAR */ #elif defined(USE_OWN_STRING) # define STRING_TYPE "String" namespace fc_test { class trivial_string { public: typedef char_t char_type; typedef char_type value_type; typedef trivial_string class_type; public: explicit trivial_string(char_type const *s); trivial_string(char_type const *s, size_t cch); trivial_string(size_t cch, char_type ch); trivial_string(class_type const &s); ~trivial_string(); public: class_type &operator +=(class_type const &s); class_type &operator +=(char_type const *s); class_type &operator +=(char_type const ch); public: char_type *begin(); char_type *end(); char_type const *begin() const; char_type const *end() const; public: char_type const *c_str() const; char_type const *data() const; char_type &operator [](size_t ); char_type const &operator [](size_t ) const; size_t length() const; private: static char_type *_make_string(char_type const *s, size_t &len); static char_type *_make_string(char_type const *s, size_t cch, size_t &len); private: char_type *m_s; size_t m_len; }; # ifndef USE_FAST_CONCAT trivial_string operator +(trivial_string const &lhs, trivial_string const &rhs) { trivial_string res(lhs); res += rhs; return res; } trivial_string operator +(trivial_string const &lhs, trivial_string::char_type const *rhs) { trivial_string res(lhs); res += rhs; return res; } trivial_string operator +(trivial_string const &lhs, trivial_string::char_type const rhs) { trivial_string res(lhs); res += rhs; return res; } trivial_string operator +(trivial_string::char_type const *lhs, trivial_string const &rhs) { trivial_string res(lhs); res += rhs; return res; } trivial_string operator +(trivial_string::char_type const lhs, trivial_string const &rhs) { trivial_string res(1, lhs); res += rhs; return res; } # endif /* !USE_FAST_CONCAT */ } // namespace fc_test typedef fc_test::trivial_string String; #else /* ? USE_OWN_STRING */ # error Must define a string type; one of USE_STD_STRING, USE_SS_SIMPLE_STRING, USE_OWN_STRING, USE_SYNESIS_STRING (Internal Synesis Software string) #endif /* USE_OWN_STRING */ /* ////////////////////////////////////////////////////////////////////////// */ /* ////////////////////////////////////////////////////////////////////////// */ #if defined(USE_STD_STRING) #elif defined(USE_SS_SIMPLE_STRING) #elif defined(USE_OWN_STRING) namespace fc_test { /* static */ trivial_string::char_type *trivial_string::_make_string(trivial_string::char_type const *s, size_t &len) { len = string_len(s); char_type *news = string_ncpy(new char_type[1 + len], s, len); news[len] = '\0'; return news; } /* static */ trivial_string::char_type *trivial_string::_make_string(trivial_string::char_type const *s, size_t cch, size_t &len) { len = string_len(s); if(cch < len) { len = cch; } char_type *news = string_ncpy(new char_type[1 + cch], s, len); news[len] = '\0'; return news; } /* explicit */ trivial_string::trivial_string(trivial_string::char_type const *s) : m_s(_make_string(s, m_len)) {} trivial_string::trivial_string(trivial_string::char_type const *s, size_t cch) : m_s(_make_string(s, cch, m_len)) {} trivial_string::trivial_string(size_t cch, trivial_string::char_type ch) : m_s(_make_string(C_T(""), cch, m_len)) { m_len = cch; memset(m_s, ch, m_len); // This is wrong! It needs to be m_s[m_len] = '\0'; } trivial_string::trivial_string(trivial_string const &s) : m_s(_make_string(s.m_s, s.m_len, m_len)) {} trivial_string::~trivial_string() { delete [] m_s; } trivial_string::char_type *trivial_string::begin() { return m_s; } trivial_string &trivial_string::operator +=(trivial_string::char_type const *s) { size_t len = string_len(s); size_t new_len = len + m_len; char_type *new_s = new char_type[1 + new_len]; string_cpy(new_s, m_s); string_cat(new_s, s); delete [] m_s; m_s = new_s; m_len = new_len; return *this; } trivial_string &trivial_string::operator +=(trivial_string::char_type const ch) { char_type sz[2]; sz[0] = ch; sz[1] = 0; return operator +=(sz); } trivial_string &trivial_string::operator +=(trivial_string const &s) { return operator +=(s.c_str()); } trivial_string::char_type *trivial_string::end() { return m_s + m_len; } trivial_string::char_type const *trivial_string::begin() const { return m_s; } trivial_string::char_type const *trivial_string::end() const { return m_s + m_len; } trivial_string::char_type const *trivial_string::c_str() const { return m_s; } trivial_string::char_type const *trivial_string::data() const { return m_s; } trivial_string::char_type &trivial_string::operator [](size_t index) { return m_s[index]; } trivial_string::char_type const &trivial_string::operator [](size_t index) const { return m_s[index]; } size_t trivial_string::length() const { return m_len; } } // namespace fc_test #endif // USE_OWN_STRING /* ////////////////////////////////////////////////////////////////////////// */ #ifdef USE_FAST_CONCAT #define CONCAT_SCHEME_STRING " + fast concat" //#if defined(USE_SS_SIMPLE_STRING) //typedef stlsoft::fast_string_concatenator > fast_concat_t; //#else #if defined(USE_STD_STRING) && \ !defined(__STLSOFT_COMPILER_IS_DMC) && \ !defined(__STLSOFT_COMPILER_IS_GCC) typedef stlsoft::fast_string_concatenator > fast_concat_t; #else /* ? USE_STD_STRING */ typedef stlsoft::fast_string_concatenator fast_concat_t; #endif /* USE_STD_STRING */ //#endif /* 0 */ #if defined(USE_OWN_STRING) || \ defined(USE_STD_STRING) || \ defined(USE_SS_SIMPLE_STRING) inline fast_concat_t operator +(stlsoft::fsc_seed const &lhs, String const &rhs) { return fast_concat_t(lhs, rhs); } #endif /* USE_OWN_STRING */ #if ( !defined(STLSOFT_STD_STRING_USE_FAST_CONCATENATOR) || \ !defined(USE_STD_STRING)) && \ ( !defined(_SYNSOFT_SYSTRING_USE_FAST_CONCATENATOR) || \ !defined(USE_SYNESIS_STRING)) inline fast_concat_t operator +(String const &lhs, String const &rhs) { return fast_concat_t(lhs, rhs); } inline fast_concat_t operator +(String const &lhs, String::value_type const *rhs) { return fast_concat_t(lhs, rhs); } inline fast_concat_t operator +(String const &lhs, String::value_type const rhs) { return fast_concat_t(lhs, rhs); } inline fast_concat_t operator +(String::value_type const *lhs, String const &rhs) { return fast_concat_t(lhs, rhs); } inline fast_concat_t operator +(String::value_type const lhs, String const &rhs) { return fast_concat_t(lhs, rhs); } #endif /* !STLSOFT_STD_STRING_USE_FAST_CONCATENATOR && !USE_STD_STRING */ #else #define CONCAT_SCHEME_STRING "" #endif /* USE_FAST_CONCAT */ /* ////////////////////////////////////////////////////////////////////////// */ int main(int argc, char **argv) { int ITERATIONS = 0; bool bUseSeed = false; bool bPathologicalBracing = false; bool bUseFastConcat = false; int i; for(i = 1; i < argc; ++i) { const char *arg = argv[i]; if(arg[0] == '-') { if(arg[1] == '-') { /* -- arguments */ } else { /* - arguments */ switch(arg[1]) { case 's': bUseSeed = true; break; case 'p': bPathologicalBracing = true; break; case 'f': /* Find files */ bUseFastConcat = true; break; case 'i': /* Find directories */ ITERATIONS = atoi(arg + 3); break; default: usage(1); break; } } } else { /* other arguments */ { usage(1); } } } STLSOFT_SUPPRESS_UNUSED(bUseFastConcat); if(ITERATIONS < 100) { ITERATIONS = DEF_ITERATIONS; } printf("fast_string_concatenator_test: %s(%s)%s%s%s; %s (%d iterations)\n", STRING_TYPE, CHAR_TYPE, bUseSeed ? " + seed" : "", bPathologicalBracing ? " + pathological bracing" : " + no bracing", CONCAT_SCHEME_STRING, __STLSOFT_COMPILER_LABEL_STRING, ITERATIONS); #if defined(WIN32) && \ !defined(_DEBUG) ::SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); #endif /* WIN32 && _DEBUG */ #ifndef _DEBUG do_test(ITERATIONS, 8, 1, bUseSeed, bPathologicalBracing); do_test(ITERATIONS, 4, 2, bUseSeed, bPathologicalBracing); do_test(ITERATIONS, 2, 3, bUseSeed, bPathologicalBracing); #endif /* !_DEBUG */ do_test(ITERATIONS, 1, 4, bUseSeed, bPathologicalBracing); #if 1 #if 1 do_test(ITERATIONS, 1, 8, bUseSeed, bPathologicalBracing); do_test(ITERATIONS, 1, 16, bUseSeed, bPathologicalBracing); do_test(ITERATIONS, 1, 32, bUseSeed, bPathologicalBracing); #else /* ? 0 */ do_test(ITERATIONS, 1, 5, bUseSeed, bPathologicalBracing); do_test(ITERATIONS, 1, 8, bUseSeed, bPathologicalBracing); do_test(ITERATIONS, 1, 12, bUseSeed, bPathologicalBracing); #endif /* 0 */ #endif /* 0 */ puts(""); return 0; } /* ////////////////////////////////////////////////////////////////////////// */ void usage(int bExit) { fprintf(stderr, "Usage: [-i=] [-f] [-p] [-s]\n"); fprintf(stderr, "\t-i - Specify iterations. Default is 200000\n"); fprintf(stderr, "\t-f - Use fast concatenation\n"); fprintf(stderr, "\t-p - Pathological bracing\n"); fprintf(stderr, "\t-s - Seed the concatenation\n"); if(bExit) { exit(1); } } int do_test(int iterations, int multiplier, int cConcats, bool bUseSeed, bool bPathologicalBracing) { performance_counter counter; #ifndef USE_FAST_CONCAT STLSOFT_SUPPRESS_UNUSED(bUseSeed); #endif /* USE_FAST_CONCAT */ #if defined(WIN32) && \ !defined(_DEBUG) ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST); #endif /* WIN32 */ int i; size_t total; for(int WARMUPS = 2; WARMUPS > 0; --WARMUPS) { #if 1 String s0(C_T("String number0")); char_t const *s1 = C_T("String number1"); String s2(C_T("String number2")); char_t const *s3 = C_T("String number3"); String s4(C_T("String number4")); char_t const *s5 = C_T("String number5"); String s6(C_T("String number6")); char_t const *s7 = C_T("String number7"); String s8(C_T("String number8")); #else /* ? 0 */ #if 0 String s0(C_T("S0")); char_t const *s1 = C_T("S1"); String s2(C_T("S2")); char_t const *s3 = C_T("S3"); String s4(C_T("S4")); char_t const *s5 = C_T("S5"); String s6(C_T("S6")); char_t const *s7 = C_T("S7"); String s8(C_T("S8")); #else /* ? 0 */ String s0(C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number0")); char_t const *s1 = C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number1"); String s2(C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number2")); char_t const *s3 = C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number3"); String s4(C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number4")); char_t const *s5 = C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number5"); String s6(C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number6")); char_t const *s7 = C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number7"); String s8(C_T("String xxxxxxxxxxxxxxxxxxxxxxxxxxx number8")); #endif /* 0 */ #endif /* 0 */ counter.start(); for(i = 0, total = 0; i < iterations * multiplier; ++i) { /* . */ #define SEP_1 C_T(' ') //#define SEP_1 C_T(" ") #define SEP_2 C_T(" ") switch(cConcats) { case 1: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + s1; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { String s = s0 + s1; total += s.length(); } break; case 2: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = s0 + (SEP_1 + s1); total += s.length(); } else { String s = s0 + SEP_1 + s1; total += s.length(); } } break; case 3: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1 + SEP_2; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = ((s0 + SEP_1) + s1) + SEP_2; total += s.length(); } else { String s = s0 + SEP_1 + s1 + SEP_2; total += s.length(); } } break; case 4: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1 + SEP_2 + s2; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = s0 + (SEP_1 + (s1 + (SEP_2 + s2))); total += s.length(); } else { String s = s0 + SEP_1 + s1 + SEP_2 + s2; total += s.length(); } } break; case 5: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = s0 + (SEP_1 + (s1 + (SEP_2 + s2))) + SEP_1; total += s.length(); } else { String s = s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1; total += s.length(); } } break; case 8: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = s0 + (SEP_1 + (s1 + (SEP_2 + (s2 + (SEP_1 + (s3 + (SEP_2 + s4))))))); total += s.length(); } else { String s = s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1; total += s.length(); } } break; case 12: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = s0 + (SEP_1 + (s1 + (SEP_2 + (s2 + (SEP_1 + (s3 + (SEP_2 + (s4 + (SEP_1 + (s5 + (SEP_2 + s6))))))))))); total += s.length(); } else { String s = s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6; total += s.length(); } } break; case 16: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6 + SEP_1 + s7 + SEP_2 + s8; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = s0 + (SEP_1 + (s1 + (SEP_2 + (s2 + (SEP_1 + (s3 + (SEP_2 + (s4 + (SEP_1 + (s5 + (SEP_2 + (s6 + (SEP_1 + (s7 + (SEP_2 + s8))))))))))))))); total += s.length(); } else { String s = s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6 + SEP_1 + s7 + SEP_2 + s8; total += s.length(); } } break; case 32: #ifdef USE_FAST_CONCAT if(bUseSeed) { String s = stlsoft::fsc_seed() + s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6 + SEP_1 + s7 + SEP_2 + s8 + s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6 + SEP_1 + s7 + SEP_2 + s8; total += s.length(); } else #endif /* USE_FAST_CONCAT */ { if(bPathologicalBracing) { String s = s0 + (SEP_1 + (s1 + (SEP_2 + (s2 + (SEP_1 + (s3 + (SEP_2 + (s4 + (SEP_1 + (s5 + (SEP_2 + (s6 + (SEP_1 + (s7 + (SEP_2 + (s8 + (s0 + (SEP_1 + (s1 + (SEP_2 + (s2 + (SEP_1 + (s3 + (SEP_2 + (s4 + (SEP_1 + (s5 + (SEP_2 + (s6 + (SEP_1 + (s7 + (SEP_2 + s8)))))))))))))))))))))))))))))))); total += s.length(); } else { String s = s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6 + SEP_1 + s7 + SEP_2 + s8 + s0 + SEP_1 + s1 + SEP_2 + s2 + SEP_1 + s3 + SEP_2 + s4 + SEP_1 + s5 + SEP_2 + s6 + SEP_1 + s7 + SEP_2 + s8; total += s.length(); } } break; } } counter.stop(); } #if 0 printf("%d iterations, total: %d, concats: %d, time (ms): %d\n", ITERATIONS, total / multiplier, cConcats, (long)counter.get_milliseconds() / multiplier); #else /* ? 0 */ printf("%d\t%d\n", cConcats, (long)counter.get_milliseconds() / multiplier); #endif /* 0 */ return total; } /* ////////////////////////////////////////////////////////////////////////// */