commit 83bee109db2f535b1a92b02eef811c1476d9f9cf
Author: Georg Baum <[email protected]>
Date:   Sun Dec 7 13:12:26 2014 +0100

    Make trivstring class ready for use
    
    The interface is now 100% unit tested, and the typedefs depend on the new
    STD_STRING_USES_COW configuration variable. The only missing bit is to 
detect
    clang and disable STD_STRING_USES_COW for clang.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0db64f7..8be95c7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -259,10 +259,13 @@ if(UNIX OR MINGW)
                endif()
                set(LYX_GCC11_MODE "${CXX11_FLAG}")
        endif()
+       set(STD_STRING_USES_COW 1)
 else()
        if(MSVC10)
                set(LYX_USE_TR1 1)
                #set(LYX_USE_TR1_REGEX 1) #TODO should we use it in ECMAScript 
mode?
+       else()
+               set(STD_STRING_USES_COW 1)
        endif()
 endif()
 
diff --git a/config/lyxinclude.m4 b/config/lyxinclude.m4
index 95cb1f0..01d57bc 100644
--- a/config/lyxinclude.m4
+++ b/config/lyxinclude.m4
@@ -297,6 +297,7 @@ if test x$GXX = xyes; then
              ;;
       esac
   fi
+  AC_DEFINE(STD_STRING_USES_COW, 1, [std::string uses copy-on-write])
 fi
 test "$lyx_pch_comp" = yes && lyx_flags="$lyx_flags pch"
 AM_CONDITIONAL(LYX_BUILD_PCH, test "$lyx_pch_comp" = yes)
diff --git a/src/support/Makefile.am b/src/support/Makefile.am
index ac43818..3ba391f 100644
--- a/src/support/Makefile.am
+++ b/src/support/Makefile.am
@@ -101,6 +101,8 @@ liblyxsupport_a_SOURCES = \
        Translator.h \
        Timeout.cpp \
        Timeout.h \
+       trivstring.cpp \
+       trivstring.h \
        types.h \
        userinfo.cpp \
        userinfo.h \
@@ -143,18 +145,21 @@ EXTRA_DIST += \
        tests/test_lstrings \
        tests/regfiles/convert \
        tests/regfiles/filetools \
-       tests/regfiles/lstrings
+       tests/regfiles/lstrings \
+       tests/regfiles/trivstring
 
 
 TESTS = \
        tests/test_convert \
        tests/test_filetools \
-       tests/test_lstrings
+       tests/test_lstrings \
+       tests/test_trivstring
 
 check_PROGRAMS = \
        check_convert \
        check_filetools \
-       check_lstrings
+       check_lstrings \
+       check_trivstring
 
 if INSTALL_MACOSX
 ADD_FRAMEWORKS = -framework QtGui -framework QtCore -framework AppKit 
-framework ApplicationServices
@@ -181,6 +186,13 @@ check_lstrings_SOURCES = \
        tests/dummy_functions.cpp \
        tests/boost.cpp
 
+check_trivstring_LDADD = liblyxsupport.a $(LIBICONV) $(BOOST_LIBS) 
$(QT_CORE_LIBS) $(LIBSHLWAPI) @LIBS@
+check_trivstring_LDFLAGS = $(QT_CORE_LDFLAGS) $(ADD_FRAMEWORKS)
+check_trivstring_SOURCES = \
+       tests/check_trivstring.cpp \
+       tests/dummy_functions.cpp \
+       tests/boost.cpp
+
 makeregfiles: ${check_PROGRAMS}
        for all in ${check_PROGRAMS} ; do \
                ./$$all > ${srcdir}/tests/regfiles/$$all ; \
diff --git a/src/support/strfwd.h b/src/support/strfwd.h
index 10411cd..94f2136 100644
--- a/src/support/strfwd.h
+++ b/src/support/strfwd.h
@@ -95,6 +95,15 @@ std::string const & empty_string();
 // defined in docstring.cpp
 bool operator==(docstring const &, char const *);
 
+#ifdef STD_STRING_USES_COW
+template<typename Char> class trivial_string;
+typedef trivial_string<char> trivstring;
+typedef trivial_string<char_type> trivdocstring;
+#else
+typedef std::string trivstring;
+typedef docstring trivdocstring;
+#endif
+
 } // namespace lyx
 
 #endif
diff --git a/src/support/tests/CMakeLists.txt b/src/support/tests/CMakeLists.txt
index 990e538..2d19989 100644
--- a/src/support/tests/CMakeLists.txt
+++ b/src/support/tests/CMakeLists.txt
@@ -28,7 +28,7 @@ include_directories(
        ${ZLIB_INCLUDE_DIR})
 
 
-set(check_PROGRAMS check_convert check_filetools check_lstrings)
+set(check_PROGRAMS check_convert check_filetools check_lstrings 
check_trivstring)
 
 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/regfiles")
 
diff --git a/src/support/tests/check_trivstring.cpp 
b/src/support/tests/check_trivstring.cpp
index e6a23d5..f2c44e4 100644
--- a/src/support/tests/check_trivstring.cpp
+++ b/src/support/tests/check_trivstring.cpp
@@ -1,6 +1,7 @@
 #include <config.h>
 
 #include "../trivstring.h"
+#include "../docstring.h"
 
 #include <iostream>
 
@@ -27,22 +28,111 @@ void test_trivstring()
                // assignment from trivstring
                trivstring const c = a;
                // assignment from std::string
-               trivstring const d = input[i];
+               trivstring d = input[i];
                // assignment from trivstring
-               string const e = a.str();
+               string const e = a;
                // assignment from trivstring via C string
                string const f = a.c_str();
+               if (a.empty())
+                       cout << "empty ";
+               else
+                       cout << "not empty ";
                cout << a.length() << endl;
-               cout << a.str() << endl;
-               cout << b.str() << endl;
-               cout << c.str() << endl;
-               cout << d.str() << endl;
+               cout << a << endl;
+               cout << b << endl;
+               cout << c << endl;
+               cout << d << endl;
                cout << e << endl;
                cout << f << endl;
+               // swap
+               trivstring g("swap");
+               cout << g << endl;
+               d.swap(g);
+               cout << d << endl;
+               cout << g << endl;
        }
+       // comparison
+       trivstring const a;
+       trivstring const b("a");
+       trivstring const c("b");
+       trivstring const d("42");
+       cout << (a == a) << ' ' << (a < a) << endl; // equal strings
+       cout << (a == b) << ' ' << (a < b) << endl; // different strings, same 
length
+       cout << (b == a) << ' ' << (b < a) << endl; // different strings, same 
length
+       cout << (a == c) << ' ' << (a < c) << endl; // different strings, 
different length
+       cout << (c == a) << ' ' << (c < a) << endl; // different strings, 
different length
+       char const * e = "";
+       char const * f = "b";
+       char const * g = "42";
+       cout << (a == e) << ' ' << (e == a) << endl; // empty strings
+       cout << (c == a) << ' ' << (a == c) << endl; // equal strings
+       cout << (a == f) << ' ' << (f == a) << endl; // different strings, same 
length
+       cout << (a == g) << ' ' << (g == a) << endl; // different strings, 
different length
+}
+
+void test_trivdocstring()
+{
+       docstring const input[] = {
+               from_ascii(""),
+               from_ascii("a"),
+               from_ascii("42"),
+               from_ascii("max"), // max. string with sso on 64 bit
+               from_ascii("something which does not fit into sso")
+       };
+       size_t const n = sizeof(input) / sizeof(input[0]);
+       for (size_t i = 0; i < n; ++i) {
+               // construction from std::string
+               trivdocstring const a(input[i]);
+               // construction from trivstring
+               trivdocstring const b(a);
+               // assignment from trivstring
+               trivdocstring const c = a;
+               // assignment from std::string
+               trivdocstring d = input[i];
+               // assignment from trivstring
+               docstring const e = a;
+               // assignment from trivstring via C string
+               docstring const f = a.c_str();
+               if (a.empty())
+                       cout << "empty ";
+               else
+                       cout << "not empty ";
+               cout << a.length() << endl;
+               cout << to_ascii(a) << endl;
+               cout << to_ascii(b) << endl;
+               cout << to_ascii(c) << endl;
+               cout << to_ascii(d) << endl;
+               cout << to_ascii(e) << endl;
+               cout << to_ascii(f) << endl;
+               // swap
+               trivdocstring g(from_ascii("swap"));
+               cout << to_ascii(g) << endl;
+               d.swap(g);
+               cout << to_ascii(d) << endl;
+               cout << to_ascii(g) << endl;
+       }
+       // comparison
+       trivdocstring const a;
+       trivdocstring const b(from_ascii("a"));
+       trivdocstring const c(from_ascii("b"));
+       trivdocstring const d(from_ascii("42"));
+       cout << (a == a) << ' ' << (a < a) << endl; // equal strings
+       cout << (a == b) << ' ' << (a < b) << endl; // different strings, same 
length
+       cout << (b == a) << ' ' << (b < a) << endl; // different strings, same 
length
+       cout << (a == c) << ' ' << (a < c) << endl; // different strings, 
different length
+       cout << (c == a) << ' ' << (c < a) << endl; // different strings, 
different length
+       // per character initialization works also if char_type != wchar
+       char_type const e[1] = {'\0'};
+       char_type const f[2] = {'b', '\0'};
+       char_type const g[3] = {'4', '2', '\0'};
+       cout << (a == e) << ' ' << (e == a) << endl; // empty strings
+       cout << (c == a) << ' ' << (a == c) << endl; // equal strings
+       cout << (a == f) << ' ' << (f == a) << endl; // different strings, same 
length
+       cout << (a == g) << ' ' << (g == a) << endl; // different strings, 
different length
 }
 
 int main()
 {
        test_trivstring();
+       test_trivdocstring();
 }
diff --git a/src/support/tests/regfiles/trivstring 
b/src/support/tests/regfiles/trivstring
index e23bd55..28b6085 100644
--- a/src/support/tests/regfiles/trivstring
+++ b/src/support/tests/regfiles/trivstring
@@ -1,35 +1,118 @@
-0
+empty 0
 
 
 
 
 
 
-1
+swap
+swap
+
+not empty 1
+a
 a
 a
 a
 a
 a
+swap
+swap
 a
-2
+not empty 2
+42
 42
 42
 42
 42
 42
+swap
+swap
 42
-7
+not empty 7
 max sso
 max sso
 max sso
 max sso
 max sso
 max sso
-37
+swap
+swap
+max sso
+not empty 37
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
+something which does not fit into sso
+swap
+swap
+something which does not fit into sso
+1 0
+0 1
+0 0
+0 1
+0 0
+1 1
+0 0
+0 0
+0 0
+empty 0
+
+
+
+
+
+
+swap
+swap
+
+not empty 1
+a
+a
+a
+a
+a
+a
+swap
+swap
+a
+not empty 2
+42
+42
+42
+42
+42
+42
+swap
+swap
+42
+not empty 3
+max
+max
+max
+max
+max
+max
+swap
+swap
+max
+not empty 37
+something which does not fit into sso
 something which does not fit into sso
 something which does not fit into sso
 something which does not fit into sso
 something which does not fit into sso
 something which does not fit into sso
+swap
+swap
 something which does not fit into sso
+1 0
+0 1
+0 0
+0 1
+0 0
+1 1
+0 0
+0 0
+0 0
diff --git a/src/support/trivstring.cpp b/src/support/trivstring.cpp
index 71085ee..fa714e9 100644
--- a/src/support/trivstring.cpp
+++ b/src/support/trivstring.cpp
@@ -13,6 +13,7 @@
 #include "support/trivstring.h"
 #include "support/docstring.h"
 
+#ifdef STD_STRING_USES_COW
 #include <algorithm>
 
 using namespace std;
@@ -136,11 +137,10 @@ int trivial_string<Char>::compare(trivial_string const & 
other) const
 }
 
 
-template string trivial_string<char>::str() const;
-template docstring trivial_string<char_type>::str() const;
+template trivial_string<char>::operator string() const;
+template trivial_string<char_type>::operator docstring() const;
 template<typename Char>
-basic_string<Char, char_traits<Char>, allocator<Char> >
-trivial_string<Char>::str() const
+trivial_string<Char>::operator basic_string<Char, char_traits<Char>, 
allocator<Char> >() const
 {
        if (use_sso())
                return basic_string<Char, char_traits<Char>, allocator<Char> >(
@@ -172,9 +172,49 @@ template bool operator<(trivial_string<char> const &,
 template bool operator<(trivial_string<char_type> const &,
                         trivial_string<char_type> const &);
 template <typename Char>
-bool operator<(trivial_string<Char> const & lhs, trivial_string<Char> const 
&rhs)
+bool operator<(trivial_string<Char> const & lhs, trivial_string<Char> const & 
rhs)
 {
        return lhs.compare(rhs) < 0;
 }
 
+
+template bool operator==(trivial_string<char> const &,
+                         trivial_string<char> const &);
+template bool operator==(trivial_string<char_type> const &,
+                         trivial_string<char_type> const &);
+template <typename Char>
+bool operator==(trivial_string<Char> const & lhs, trivial_string<Char> const & 
rhs)
+{
+       return lhs.compare(rhs) == 0; 
+}
+
+
+template bool operator==(trivial_string<char> const &, char const *);
+template bool operator==(trivial_string<char_type> const &, char_type const *);
+template <typename Char>
+bool operator==(trivial_string<Char> const & lhs, Char const * rhs)
+{
+       return lhs.compare(trivial_string<Char>(rhs)) == 0; 
+}
+
+
+template bool operator==(char const *, trivial_string<char> const &);
+template bool operator==(char_type const *, trivial_string<char_type> const &);
+template <typename Char>
+bool operator==(Char const * lhs, trivial_string<Char> const & rhs)
+{
+       return rhs.compare(trivial_string<Char>(lhs)) == 0; 
+}
+
+
+template ostream & operator<<(ostream &, trivial_string<char> const &);
+template odocstream & operator<<(odocstream &, trivial_string<char_type> const 
&);
+template <typename Char>
+basic_ostream<Char, char_traits<Char> > &
+operator<<(basic_ostream<Char, char_traits<Char> > & os, trivial_string<Char> 
const & s)
+{
+       return os << basic_string<Char, char_traits<Char>, allocator<Char> >(s);
+}
+
 } // namespace lyx
+#endif
diff --git a/src/support/trivstring.h b/src/support/trivstring.h
index 4123d32..4915469 100644
--- a/src/support/trivstring.h
+++ b/src/support/trivstring.h
@@ -14,6 +14,7 @@
 
 #include "support/strfwd.h"
 
+#ifdef STD_STRING_USES_COW
 #include <cstdlib>
 
 namespace lyx {
@@ -31,6 +32,9 @@ namespace lyx {
  * This class should not be used for anything else than providing 
thread-safety.
  * It should be removed as soon as LyX requires C++11, and all supported STL
  * implementations provide a C++11 conformant std::basic_string.
+ *
+ * If you change anything in this class please ensure that the unit test
+ * tests/check_trivstring.cpp still tests 100% of the public interface.
  */
 template <typename Char> class trivial_string
 {
@@ -56,7 +60,7 @@ public:
        /// Is this string ordered before, at the same position or after \p 
other?
        int compare(trivial_string const & other) const;
        /// Create a copy as std::basic_string
-       std::basic_string<Char, std::char_traits<Char>, std::allocator<Char> > 
str() const;
+       operator std::basic_string<Char, std::char_traits<Char>, 
std::allocator<Char> >() const;
        /// Return a C-compatible string, terminated by a 0 character.
        /// This is never a copy and only valid for the life time of the 
trivial_string instance.
        Char const * c_str() const;
@@ -80,8 +84,25 @@ private:
        /// The character storage
        Char * data_;
 };
-template <typename Char> bool operator<(trivial_string<Char> const & lhs, 
trivial_string<Char> const &rhs);
 
 
+/// Comparison operator (needed for std::set etc)
+template <typename Char> bool operator<(trivial_string<Char> const & lhs, 
trivial_string<Char> const & rhs);
+
+
+/// Equality operator
+template <typename Char> bool operator==(trivial_string<Char> const & lhs, 
trivial_string<Char> const & rhs);
+template <typename Char> bool operator==(trivial_string<Char> const & lhs, 
Char const * rhs);
+template <typename Char> bool operator==(Char const * lhs, 
trivial_string<Char> const & rhs);
+
+
+/// Stream output operator
+template <typename Char>
+std::basic_ostream<Char, std::char_traits<Char> > &
+operator<<(std::basic_ostream<Char, std::char_traits<Char> > &, 
trivial_string<Char> const &);
+#else
+#include <string>
+#endif
+
 } // namespace lyx
 #endif

Reply via email to