Le 25/08/2016 à 20:36, Georg Baum a écrit :
Guillaume Munch wrote:

Le 22/08/2016 à 20:56, Georg Baum a écrit :

Our own facets work, and the implementation
is confined to one file which nobody needs to look at (unless he wants
to).


I made it work with libc++ too, which was not straightforward. In this
case, the template is undefined and cannot be inherited from.

Could you or somebody else please double-check the following, which I am
not sure to understand correctly:

* Why ascii_num_get_facet::do_get uses from_local8bit at some point.

* Is the numpunct<lyx::char_type> facet correctly set with the way it
occurs in the code?

Attached is the new version.



The point is to remove the need for trivdocstring entirely, so that we
can already use docstring knowing it is thread-safe. This might not
change the existing code, but could simplify the future one. (In fact I
was unaware of trivstring and these threading issues until last week --
It's good to simplify the situation.)

I would like it more simple as well, but it seems this is not easily
possible without a C++11 compliant std::string.

I agree for std::string, but for docstring I have demonstrated that it
is very simple. Moreover I find it reassuring that versa_string is the
precursor of the new basic_string.


Of course we would need some good testing, but it is good to know that there
are currently no further known problems. Regarding the documentation I am
not aware of anything else either.

There is also a built-in conversion function between utf-8 and utf-32 in
C++11 which could replace iconv. But I don't know whether there are
clear advantages in replacing iconv. Iconv might still be needed for
other encodings. But then I don't understand why for from_local8bit it
uses QString::fromLocal8Bit instead of iconv.

Then of course another thing to do is to remove all the now-superfluous
from_ascii from the code.


The only thing I would do differently is the replacement of
empty_string() and empty_docstring(): Those were introduced to avoid
including <string>. Since <string> is now required, it would be better to
initialize the default arguments with docstring() or std::string().

There is not much a difference from what I did, other than matters of
taste, is there?

There is an additional conversion from char * to std::string. I was once
told that this is less efficient (here on the LyX mailing list, but I forgot
who wrote that), but I never tested that myself.

Surely, but the combined amount of time and energy spent in this
conversion, over all user's computers present and future, is surely less
than the time and energy spent writing this reply...


And in a second step we should
get rid of strfwd.h completely, the name would be wrong for all compilers
then.

I can also try to keep docstring forward-declared.

This does not work with clang and libc++ AFAIK. I never liked the current
mixture of forward declaration or full include depending on the used
compiler (can lead to compile errors). Therefore using the full includesd
for all compilers is good IMHO.


OK.

>From 541a3c85af9ba92f73743b072d5d7bf7b2348a16 Mon Sep 17 00:00:00 2001
From: Guillaume Munch <g...@lyx.org>
Date: Sat, 20 Aug 2016 16:27:52 +0100
Subject: [PATCH] typedef char32_t char_type; typedef std::u32string docstring;
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

char_type is now defined as char32_t and docstring is now defined as
std::u32string on all platforms.

* Enable the use of Unicode literals, i.e. one can write:
    docstring s = U"Here is a Unicode literal☺";
    char_type ellipsis = U'\u2026';
    s == U"\u203D";
  etc.

* Remove empty_string() and empty_docstring() as they are now useless.

* Remove the now useless USE_WCHAR_T and all related code

* Note that gcc < 5.1 is not compliant with C++11 regarding thread-safety. It is
  still necesary to use trivstring and trivdocstring for thread-safety.

* Note that the C++11 standard does not require all facets for char32_t which
  are required for using char32_t streams (!). This patch reuses the
  ascii_*_facets from support/docstring.cpp.

* In addition, libstdc++ and libc++ have facets that cannot be derived from.
  A new configure test is introduced for these bugs.
---
 config/lyxinclude.m4                 |  24 ++++++
 configure.ac                         |  20 -----
 src/Buffer.h                         |   2 +-
 src/Encoding.cpp                     |   4 +-
 src/Format.h                         |   2 +-
 src/LaTeX.cpp                        |   2 +-
 src/LaTeX.h                          |   8 +-
 src/LayoutFile.h                     |   2 +-
 src/frontends/alert.h                |   9 +--
 src/frontends/qt4/qt_helpers.h       |   2 +-
 src/insets/InsetText.h               |   3 +-
 src/mathed/InsetMathHull.cpp         |   8 +-
 src/mathed/InsetMathUnknown.h        |   4 +-
 src/support/FileName.h               |   8 +-
 src/support/ForkedCalls.h            |   4 +-
 src/support/Makefile.am              |   3 +-
 src/support/Systemcall.h             |   6 +-
 src/support/char32_t_facets.cpp      |  20 +++++
 src/support/char32_t_facets.h        | 152 +++++++++++++++++++++++++++++++++++
 src/support/debug.h                  |  14 ----
 src/support/docstream.cpp            |  91 ---------------------
 src/support/docstream.h              |  15 ----
 src/support/docstring.cpp            |  56 ++++---------
 src/support/docstring.h              |  13 ++-
 src/support/lstrings.cpp             |  17 +---
 src/support/numpunct_lyx_char_type.h |  58 -------------
 src/support/os.h                     |   2 +-
 src/support/strfwd.h                 | 124 +++++++++-------------------
 src/tex2lyx/Preamble.cpp             |   6 +-
 29 files changed, 298 insertions(+), 381 deletions(-)
 create mode 100644 src/support/char32_t_facets.cpp
 create mode 100644 src/support/char32_t_facets.h
 delete mode 100644 src/support/numpunct_lyx_char_type.h

diff --git a/config/lyxinclude.m4 b/config/lyxinclude.m4
index 7bddfb0..4580793 100644
--- a/config/lyxinclude.m4
+++ b/config/lyxinclude.m4
@@ -301,6 +301,29 @@ AC_DEFUN([LYX_LIB_STDCXX_CXX11_ABI],
 ])
 
 
+dnl Usage: LYX_LIB_CHAR32_FACETS: define HAS_STD_CHAR32_FACETS if deriving
+dnl        from std::ctype<char32_t> and std::numpunct<char32_t> succeeds.
+AC_DEFUN([LYX_LIB_CHAR32_FACETS],
+[AC_CACHE_CHECK([whether char32_t facets can be derived from],
+               [lyx_cv_lib_char32_facets],
+[AC_TRY_LINK([
+#include <locale>
+class myctype : std::ctype<char32_t>
+{ public: myctype(int i) : std::ctype<char32_t>(i) {} };
+class mynumpunct : std::numpunct<char32_t>
+{ public: mynumpunct(int i) :  std::numpunct<char32_t>(i) {} };
+], [
+myctype(1);
+mynumpunct(1);
+],
+[lyx_cv_lib_char32_facets=yes], [lyx_cv_lib_char32_facets=no])])
+if test x"$lyx_cv_lib_char32_facets" = xyes; then
+  AC_DEFINE([HAS_STD_CHAR32_FACETS], 1,
+            [char32_t facets can be derived from])
+fi
+])
+
+
 AC_DEFUN([LYX_PROG_CXX],
 [AC_REQUIRE([AC_PROG_CXX])
 AC_REQUIRE([AC_PROG_CXXCPP])
@@ -310,6 +333,7 @@ LYX_PROG_CLANG
 LYX_CXX_CXX11_FLAGS
 LYX_LIB_STDCXX
 LYX_LIB_STDCXX_CXX11_ABI
+LYX_LIB_CHAR32_FACETS
 LYX_CXX_USE_REGEX
 LYX_CXX_USE_CALL_ONCE
 AC_LANG_POP(C++)
diff --git a/configure.ac b/configure.ac
index 75df6c7..4b609ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -133,22 +133,6 @@ LYX_CHECK_CALLSTACK_PRINTING
 # C++14 only
 LYX_CHECK_DEF(make_unique, memory, [using std::make_unique;])
 
-# Needed for our char_type
-AC_CHECK_SIZEOF(wchar_t)
-
-# Taken from gettext, needed for libiconv
-AC_CACHE_CHECK([for wchar_t], [gt_cv_c_wchar_t],
-   [AC_TRY_COMPILE([#include <stddef.h>
-      wchar_t foo = (wchar_t)'\0';], ,
-      [gt_cv_c_wchar_t=yes], [gt_cv_c_wchar_t=no])])
-if test $gt_cv_c_wchar_t = yes; then
-  AC_DEFINE([HAVE_WCHAR_T], [1], [Define if you have the 'wchar_t' type.])
-  HAVE_WCHAR_T=1
-else
-  HAVE_WCHAR_T=0
-fi
-AC_SUBST([HAVE_WCHAR_T])
-
 # Needed for Mingw-w64
 AC_TYPE_LONG_LONG_INT
 if test "$ac_cv_type_long_long_int" = yes; then
@@ -330,10 +314,6 @@ char * strerror(int n);
 #  endif
 #endif
 
-#if defined(HAVE_WCHAR_T) && SIZEOF_WCHAR_T == 4
-#  define USE_WCHAR_T
-#endif
-
 #ifdef HAVE_LONG_LONG_INT
 #if SIZEOF_LONG_LONG > SIZEOF_LONG
 #define LYX_USE_LONG_LONG
diff --git a/src/Buffer.h b/src/Buffer.h
index 477a8ac..52152cb 100644
--- a/src/Buffer.h
+++ b/src/Buffer.h
@@ -749,7 +749,7 @@ public:
 	/// where it was saved, return the correct path relative to the new
 	/// location.
 	std::string includedFilePath(std::string const & name,
-				std::string const & ext = empty_string()) const;
+	                             std::string const & ext = "") const;
 
 	/// compute statistics between \p from and \p to
 	/// \p from initial position
diff --git a/src/Encoding.cpp b/src/Encoding.cpp
index 73edc84..7c09f75 100644
--- a/src/Encoding.cpp
+++ b/src/Encoding.cpp
@@ -277,7 +277,7 @@ bool Encodings::latexMathChar(char_type c, bool mathmode,
 			Encoding const * encoding, docstring & command,
 			bool & needsTermination)
 {
-	command = empty_docstring();
+	command = U"";
 	if (encoding)
 		if (encoding->encodable(c))
 			command = docstring(1, c);
@@ -347,7 +347,7 @@ docstring Encodings::fromLaTeXCommand(docstring const & cmd, int cmdtype,
 		bool & needsTermination, docstring & rem, set<string> * req)
 {
 	needsTermination = false;
-	rem = empty_docstring();
+	rem = U"";
 	bool const mathmode = cmdtype & MATH_CMD;
 	bool const textmode = cmdtype & TEXT_CMD;
 	docstring symbols;
diff --git a/src/Format.h b/src/Format.h
index 74d2c4e..9bf58f3 100644
--- a/src/Format.h
+++ b/src/Format.h
@@ -61,7 +61,7 @@ public:
 	///
 	std::string const extension() const
 	{
-		return extension_list_.empty() ? empty_string() : extension_list_[0];
+		return extension_list_.empty() ? "" : extension_list_[0];
 	}
 	///
 	std::string const extensions() const;
diff --git a/src/LaTeX.cpp b/src/LaTeX.cpp
index cfa6e1d..5a570906 100644
--- a/src/LaTeX.cpp
+++ b/src/LaTeX.cpp
@@ -687,7 +687,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
 				--pnest;
 			}
 		}
-		child_name = child.empty() ? empty_string() : child.top().first;
+		child_name = child.empty() ? "" : child.top().first;
 
 		if (contains(token, "file:line:error style messages enabled"))
 			fle_style = true;
diff --git a/src/LaTeX.h b/src/LaTeX.h
index 2575683..6205588 100644
--- a/src/LaTeX.h
+++ b/src/LaTeX.h
@@ -62,8 +62,8 @@ public:
 	Errors::const_iterator end() const { return errors.end(); }
 	///
 	void insertError(int line, docstring const & error_desc,
-			 docstring const & error_text,
-			 std::string const & child_name = empty_string());
+	                 docstring const & error_text,
+	                 std::string const & child_name = "");
 	///
 	void clearErrors() { errors.clear(); }
 private:
@@ -161,8 +161,8 @@ public:
 	*/
 	LaTeX(std::string const & cmd, OutputParams const &,
 	      support::FileName const & file,
-	      std::string const & path = empty_string(),
-	      std::string const & lpath = empty_string(),
+	      std::string const & path = "",
+	      std::string const & lpath = "",
 	      bool const clean_start = false);
 
 	/// runs LaTeX several times
diff --git a/src/LayoutFile.h b/src/LayoutFile.h
index e911aa5..a22f7ac 100644
--- a/src/LayoutFile.h
+++ b/src/LayoutFile.h
@@ -120,7 +120,7 @@ public:
 	/// empty string if no file was loaded.
 	LayoutFileIndex addLocalLayout(std::string const & textclass,
 	                               std::string const & path,
-	                               std::string const & oldpath = empty_string());
+	                               std::string const & oldpath = "");
 	/// a list of the available classes
 	std::vector<LayoutFileIndex> classList() const;
 
diff --git a/src/frontends/alert.h b/src/frontends/alert.h
index 2be612a..2fddc4e 100644
--- a/src/frontends/alert.h
+++ b/src/frontends/alert.h
@@ -31,10 +31,9 @@ namespace Alert {
  * slap you with fish, and not in an enjoyable way either.
  */
 int prompt(docstring const & title, docstring const & question,
-	   int default_button, int cancel_button,
-	   docstring const & b1, docstring const & b2,
-	   docstring const & b3 = empty_docstring(),
-	   docstring const & b4 = empty_docstring());
+           int default_button, int cancel_button,
+           docstring const & b1, docstring const & b2,
+           docstring const & b3 = U"", docstring const & b4 = U"");
 
 /**
  * Display a warning to the user. Title should be a short (general) summary.
@@ -65,7 +64,7 @@ void information(docstring const & title, docstring const & message);
  * (even empty string). dflt stands for default message in the dialog.
  */
 bool askForText(docstring & response, docstring const & msg,
-	docstring const & dflt = empty_docstring());
+                docstring const & dflt = U"");
 
 } // namespace Alert
 } // namespace frontend
diff --git a/src/frontends/qt4/qt_helpers.h b/src/frontends/qt4/qt_helpers.h
index 5574212..61a03af 100644
--- a/src/frontends/qt4/qt_helpers.h
+++ b/src/frontends/qt4/qt_helpers.h
@@ -155,7 +155,7 @@ QString browseRelToSub(QString const & filename,
 *  \param arg: cls, sty, bst, or bib, as required by TeXFiles.py.
 *         Can be a list of these, too.
 */
-void rescanTexStyles(std::string const & arg = empty_string());
+void rescanTexStyles(std::string const & arg = "");
 
 /** Fill \c contents from one of the three texfiles.
  *  Each entry in the file list is returned as a name_with_path
diff --git a/src/insets/InsetText.h b/src/insets/InsetText.h
index 2834019..f866449 100644
--- a/src/insets/InsetText.h
+++ b/src/insets/InsetText.h
@@ -207,8 +207,7 @@ public:
 	/// of that sort. (Note: unnecessary internal copies have been removed
 	/// since the previous note. The efficiency would have to be assessed
 	/// again by profiling.)
-	docstring toolTipText(docstring prefix = empty_docstring(),
-	                      size_t len = 400) const;
+	docstring toolTipText(docstring prefix = U"", size_t len = 400) const;
 
 	///
 	std::string contextMenu(BufferView const &, int, int) const;
diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp
index 5dffc3d..3c93af1 100644
--- a/src/mathed/InsetMathHull.cpp
+++ b/src/mathed/InsetMathHull.cpp
@@ -169,7 +169,7 @@ static InsetLabel * dummy_pointer = 0;
 
 InsetMathHull::InsetMathHull(Buffer * buf)
 	: InsetMathGrid(buf, 1, 1), type_(hullNone), numbered_(1, NUMBER),
-	  numbers_(1, empty_docstring()), label_(1, dummy_pointer),
+	  numbers_(1, U""), label_(1, dummy_pointer),
 	  preview_(new RenderPreview(this))
 {
 	//lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl;
@@ -184,7 +184,7 @@ InsetMathHull::InsetMathHull(Buffer * buf)
 
 InsetMathHull::InsetMathHull(Buffer * buf, HullType type)
 	: InsetMathGrid(buf, getCols(type), 1), type_(type), numbered_(1, NUMBER),
-	  numbers_(1, empty_docstring()), label_(1, dummy_pointer),
+	  numbers_(1, U""), label_(1, dummy_pointer),
 	  preview_(new RenderPreview(this))
 {
 	buffer_ = buf;
@@ -289,7 +289,7 @@ void InsetMathHull::updateBuffer(ParIterator const & it, UpdateType utype)
 					cnts.step(eqstr, utype);
 					numbers_[i] = cnts.theCounter(eqstr, lang);
 				} else
-					numbers_[i] = empty_docstring();
+					numbers_[i] = U"";
 			}
 		}
 	}
@@ -1151,7 +1151,7 @@ void InsetMathHull::addRow(row_type row)
 	bool numbered = numberedType();
 	// Move the number and raw pointer, do not call label() (bug 7511)
 	InsetLabel * label = dummy_pointer;
-	docstring number = empty_docstring();
+	docstring number;
 	if (type_ == hullMultline) {
 		if (row + 1 == nrows())  {
 			numbered_[row] = NONUMBER;
diff --git a/src/mathed/InsetMathUnknown.h b/src/mathed/InsetMathUnknown.h
index 2effe3c..4a4eee2 100644
--- a/src/mathed/InsetMathUnknown.h
+++ b/src/mathed/InsetMathUnknown.h
@@ -22,8 +22,8 @@ class InsetMathUnknown : public InsetMath {
 public:
 	///
 	explicit InsetMathUnknown(docstring const & name,
-		docstring const & selection = empty_docstring(),
-		bool final = true, bool black = false);
+	                          docstring const & selection = U"",
+	                          bool final = true, bool black = false);
 	///
 	void metrics(MetricsInfo & mi, Dimension & dim) const;
 	///
diff --git a/src/support/FileName.h b/src/support/FileName.h
index cfa0c65..4564683 100644
--- a/src/support/FileName.h
+++ b/src/support/FileName.h
@@ -262,10 +262,10 @@ public:
 	///
 	bool saveAbsPath() const { return save_abs_path_; }
 	/// \param buffer_path if empty, uses `pwd`
-	std::string relFileName(std::string const & buffer_path = empty_string()) const;
+	std::string relFileName(std::string const & buffer_path = "") const;
 	/// \param buf_path if empty, uses `pwd`
-	std::string outputFileName(std::string const & buf_path = empty_string()) const;
-	
+	std::string outputFileName(std::string const & buf_path = "") const;
+
 	/** @returns a mangled representation of the absolute file name
 	 *  suitable for use in the temp dir when, for example, converting
 	 *  an image file to another format.
@@ -287,7 +287,7 @@ public:
 	 *  with @c dir.
 	 */
 	std::string
-	mangledFileName(std::string const & dir = empty_string()) const;
+	mangledFileName(std::string const & dir = "") const;
 
 	/// \return the absolute file name without its .gz, .z, .Z extension
 	std::string unzippedFileName() const;
diff --git a/src/support/ForkedCalls.h b/src/support/ForkedCalls.h
index 1ed2f75..8aed814 100644
--- a/src/support/ForkedCalls.h
+++ b/src/support/ForkedCalls.h
@@ -152,8 +152,8 @@ private:
 class ForkedCall : public ForkedProcess {
 public:
 	///
-	ForkedCall(std::string const & path = empty_string(),
-	           std::string const & lpath = empty_string());
+	ForkedCall(std::string const & path = "",
+	           std::string const & lpath = "");
 	///
 	virtual std::shared_ptr<ForkedProcess> clone() const {
 		return std::make_shared<ForkedCall>(*this);
diff --git a/src/support/Makefile.am b/src/support/Makefile.am
index 08f1c71..65087ab 100644
--- a/src/support/Makefile.am
+++ b/src/support/Makefile.am
@@ -35,6 +35,8 @@ liblyxsupport_a_SOURCES = \
 	FileMonitor.cpp \
 	RandomAccessList.h \
 	bind.h \
+	char32_t_facets.h \
+	char32_t_facets.cpp \
 	Changer.h \
 	ConsoleApplication.cpp \
 	ConsoleApplication.h \
@@ -78,7 +80,6 @@ liblyxsupport_a_SOURCES = \
 	mutex.cpp \
 	Messages.cpp \
 	Messages.h \
-	numpunct_lyx_char_type.h \
 	os.cpp \
 	os.h \
 	PathChanger.cpp \
diff --git a/src/support/Systemcall.h b/src/support/Systemcall.h
index 876aa35..80d1fdc 100644
--- a/src/support/Systemcall.h
+++ b/src/support/Systemcall.h
@@ -49,9 +49,9 @@ public:
 	 *  blocked while  processing the external command.
 	 */
 	int startscript(Starttype how, std::string const & what,
-			std::string const & path = empty_string(),
-			std::string const & lpath = empty_string(),
-			bool process_events = false);
+	                std::string const & path = "",
+	                std::string const & lpath = "",
+	                bool process_events = false);
 };
 
 } // namespace support
diff --git a/src/support/char32_t_facets.cpp b/src/support/char32_t_facets.cpp
new file mode 100644
index 0000000..c02993e
--- /dev/null
+++ b/src/support/char32_t_facets.cpp
@@ -0,0 +1,20 @@
+// -*- C++ -*-
+/**
+ * \file char32_t_facets.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Guillaume Munch
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+#include <config.h>
+
+#include "support/char32_t_facets.h"
+
+#ifndef HAS_STD_CHAR32_FACETS
+
+std::locale::id std::ctype<char32_t>::id;
+std::locale::id std::numpunct<char32_t>::id;
+
+#endif
diff --git a/src/support/char32_t_facets.h b/src/support/char32_t_facets.h
new file mode 100644
index 0000000..d880f64
--- /dev/null
+++ b/src/support/char32_t_facets.h
@@ -0,0 +1,152 @@
+// -*- C++ -*-
+/**
+ * \file char32_t_facets.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Guillaume Munch
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LYX_CHAR32_T_FACETS_H
+#define LYX_CHAR32_T_FACETS_H
+
+#ifndef HAS_STD_CHAR32_FACETS
+
+// C++11 does not mandate char32_t facets. They have to be defined by hand.
+//
+// However this header is not about that. Even if the standard does not require
+// the facets, it should still be possible to derive from std::ctype<char32_t>
+// and std::numpunct<char32_t>.
+//
+// * libstdc++: this causes undefined references during linking (bug still
+//   present in 6.2)
+//
+// * libc++: this causes errors about the instantiation of incomplete templates
+//
+// The definitions below repair these issues. In a second time, we define and
+// apply our custom facets in support/docstring.cpp.
+
+#include <locale>
+
+
+namespace std {
+
+
+template <>
+class ctype<char32_t> : public locale::facet, public ctype_base {
+public:
+	typedef char32_t char_type;
+	static locale::id id;
+
+	explicit ctype(size_t refs) : locale::facet(refs) {}
+
+	bool is(mask m, char_type c) const
+	{
+		return this->do_is(m, c);
+	}
+
+	char_type const * is(char_type const * low, char_type const * high,
+	                     mask * vec) const
+	{
+		return this->do_is(low, high, vec);
+	}
+
+	char_type const * scan_is(mask m, char_type const * low,
+	                          char_type const * high) const
+	{
+		return this->do_scan_is(m, low, high);
+	}
+
+	char_type const * scan_not(mask m, char_type const * low,
+	                           char_type const * high) const
+	{
+		return this->do_scan_not(m, low, high);
+	}
+
+	char_type toupper(char_type c) const { return this->do_toupper(c); }
+
+	char_type const * toupper(char_type * low, char_type const * high) const
+	{
+		return this->do_toupper(low, high);
+	}
+
+	char_type tolower(char_type c) const { return this->do_tolower(c); }
+
+	char_type const * tolower(char_type * low, char_type const * high) const
+	{
+		return this->do_tolower(low, high);
+	}
+
+	char_type widen(char c) const { return this->do_widen(c); }
+
+	char const * widen(char const * low, char const * high, char_type * to) const
+	{
+		return this->do_widen(low, high, to);
+	}
+
+	char narrow(char_type c, char dfault) const
+	{
+		return this->do_narrow(c, dfault);
+	}
+
+	char_type const * narrow(char_type const * low, char_type const * high,
+	                        char dfault, char * to) const
+	{
+		return this->do_narrow(low, high, dfault, to);
+	}
+
+protected:
+	virtual bool do_is(mask m, char_type c) const = 0;
+	virtual char_type const * do_is(char_type const * low,
+	                                char_type const * high,
+	                                mask * vec) const = 0;
+	virtual char_type const * do_scan_is(mask m, char_type const * low,
+	                                     char_type const * high) const = 0;
+	virtual char_type const * do_scan_not(mask m, char_type const * low,
+	                                      char_type const * high) const = 0;
+	virtual char_type do_toupper(char_type c) const = 0;
+	virtual char_type const * do_toupper(char_type * low,
+	                                     char_type const * high) const = 0;
+	virtual char_type do_tolower(char_type c) const = 0;
+	virtual char_type const * do_tolower(char_type * low,
+	                                     char_type const * high) const = 0;
+	virtual char_type do_widen(char c) const = 0;
+	virtual char const * do_widen(char const * low, char const * high,
+	                              char_type * to) const = 0;
+	virtual char do_narrow(char_type c, char dfault) const = 0;
+	virtual char_type const * do_narrow(char_type const * low,
+	                                    char_type const * high,
+	                                    char dfault, char * to) const = 0;
+};
+
+// adapted from [facet.numpunct.virtuals] by substituting char32_t for wchar_t
+template<>
+class numpunct<char32_t> : public locale::facet {
+public:
+	typedef char32_t char_type;
+	typedef u32string string_type;
+	static locale::id id;
+
+	explicit numpunct(size_t refs = 0) : locale::facet(refs) {}
+
+	char_type decimal_point() const { return do_decimal_point(); }
+	char_type thousands_sep() const { return do_thousands_sep(); }
+	string grouping() const { return do_grouping(); }
+	string_type truename() const { return do_truename(); }
+	string_type falsename() const { return do_falsename(); }
+
+protected:
+	virtual char_type do_decimal_point() const { return U'.'; }
+	virtual char_type do_thousands_sep() const { return U','; }
+	virtual string do_grouping() const { return ""; }
+	virtual string_type do_truename() const { return U"true"; }
+	virtual string_type do_falsename() const { return U"false"; }
+};
+
+} // namespace std
+
+#endif // HAS_STD_CHAR32_FACETS
+
+#endif // LYX_CHAR32_T_FACETS_H
diff --git a/src/support/debug.h b/src/support/debug.h
index b98dfd0..1135930 100644
--- a/src/support/debug.h
+++ b/src/support/debug.h
@@ -17,20 +17,6 @@
 
 #include "support/strfwd.h"
 
-// Forward definitions do not work with libc++
-// but ios_base has already been defined in strfwd
-// if compiling with it
-#ifndef USE_LLVM_LIBCPP
-namespace std {
-
-class ios_base;
-
-template<typename CharT, typename Traits> class basic_streambuf;
-typedef basic_streambuf<char, char_traits<char> > streambuf;
-
-}
-#endif
-
 
 namespace lyx {
 
diff --git a/src/support/docstream.cpp b/src/support/docstream.cpp
index de5a6df..6fb2e7c 100644
--- a/src/support/docstream.cpp
+++ b/src/support/docstream.cpp
@@ -26,28 +26,6 @@ using namespace std;
 using lyx::ucs4_codeset;
 
 
-#if defined(_MSC_VER) && (_MSC_VER >= 1600)
-std::locale::id numpunct<lyx::char_type>::id;
-
-namespace std {
-// Implementation of numpunct<lyx::char_type> defined in numpunct_lyx_char_type.h
-typedef basic_string<lyx::char_type> string_type;
-	
-string_type numpunct<lyx::char_type>::truename() const
-{ 
-	return lyx::from_ascii(numpunct<char>::truename()); 
-}
-	
-string_type numpunct<lyx::char_type>::falsename() const
-{ 
-	return lyx::from_ascii(numpunct<char>::falsename()); 
-}
-
-} // namespace std
-
-#endif // _MSC_VER >= 1600
-
-
 namespace {
 
 // We use C IO throughout this file, because the facets might be used with
@@ -439,74 +417,5 @@ idocstream & operator<<(idocstream & is, SetEnc e)
 }
 
 
-#if ! defined(USE_WCHAR_T)
-odocstream & operator<<(odocstream & os, char c)
-{
-	os.put(c);
-	return os;
 }
-#endif
 
-}
-
-
-#if ! defined(USE_WCHAR_T) && defined(__GNUC__)
-// We get undefined references to these virtual methods. This looks like
-// a bug in gcc. The implementation here does not do anything useful, since
-// it is overriden in iconv_codecvt_facet.
-namespace std {
-
-template<> codecvt<lyx::char_type, char, mbstate_t>::result
-codecvt<lyx::char_type, char, mbstate_t>::do_out(
-	mbstate_t &, const lyx::char_type *, const lyx::char_type *,
-	const lyx::char_type *&, char *, char *, char *&) const
-{
-	return error;
-}
-
-
-template<> codecvt<lyx::char_type, char, mbstate_t>::result
-codecvt<lyx::char_type, char, mbstate_t>::do_unshift(
-	mbstate_t &, char *, char *, char *&) const
-{
-	return error;
-}
-
-
-template<> codecvt<lyx::char_type, char, mbstate_t>::result
-codecvt<lyx::char_type, char, mbstate_t>::do_in(
-	mbstate_t &, const char *, const char *, const char *&,
-	lyx::char_type *, lyx::char_type *, lyx::char_type *&) const
-{
-	return error;
-}
-
-
-template<>
-int codecvt<lyx::char_type, char, mbstate_t>::do_encoding() const throw()
-{
-	return 0;
-}
-
-
-template<>
-bool codecvt<lyx::char_type, char, mbstate_t>::do_always_noconv() const throw()
-{
-	return true;
-}
-
-template<>
-int codecvt<lyx::char_type, char, mbstate_t>::do_length(
-	mbstate_t &, const char *, const char *, size_t) const
-{
-	return 1;
-}
-
-template<>
-int codecvt<lyx::char_type, char, mbstate_t>::do_max_length() const throw()
-{
-	return 4;
-}
-
-} // namespace std
-#endif
diff --git a/src/support/docstream.h b/src/support/docstream.h
index 460a9b7..59135bc 100644
--- a/src/support/docstream.h
+++ b/src/support/docstream.h
@@ -25,21 +25,6 @@ public:
 	virtual const char * what() const throw();
 };
 
-/// Base class for UCS4 input streams
-typedef std::basic_istream<char_type> idocstream;
-
-/** Base class for UCS4 output streams.
-    If you want to output a single UCS4 character, use \code
-    os.put(c);
-    \endcode, not \code
-    os << c;
-    \endcode . The latter will not output the character, but the code point
-    as number if USE_WCHAR_T is not defined. This is because we can't overload
-    operator<< (our character type is not always a real type but sometimes a
-    typedef). Narrow characters of type char can be output as usual.
- */
-typedef std::basic_ostream<char_type> odocstream;
-
 struct SetEnc;
 
 /// File stream for reading UTF8-encoded files with automatic conversion to
diff --git a/src/support/docstring.cpp b/src/support/docstring.cpp
index 95c86b3..39fbdb4 100644
--- a/src/support/docstring.cpp
+++ b/src/support/docstring.cpp
@@ -21,10 +21,9 @@
 
 //Needed in Ubuntu
 #include <typeinfo>
-#if ! defined(USE_WCHAR_T) && defined(__GNUC__)
+
 #include <locale>
 #include <iostream>
-#endif
 
 using namespace std;
 
@@ -241,42 +240,14 @@ lyx::docstring & operator+=(lyx::docstring & l, char r)
 	return l;
 }
 
-} // namespace lyx
 
-#if ! defined(USE_WCHAR_T) && defined(__GNUC__)
+// C++11 does not guarantee proper locale facets for char32_t, so we have to
+// implement them on our own. The standard misses implementations of:
+// * std::ctype<char32_t>
+// * std::numpunct<char32_t>
+// * std::num_put<char32_t>
+// * std::num_get<char32_t>
 
-// gcc does not have proper locale facets for lyx::char_type if
-// sizeof(wchar_t) == 2, so we have to implement them on our own.
-
-
-// We get undefined references to these virtual methods. This looks like
-// a bug in gcc. The implementation here does not do anything useful, since
-// it is overriden in ascii_ctype_facet.
-namespace std {
-template<> ctype<lyx::char_type>::~ctype() {}
-template<> bool
-ctype<lyx::char_type>::do_is(ctype<lyx::char_type>::mask, lyx::char_type) const { return false; }
-template<> lyx::char_type const *
-ctype<lyx::char_type>::do_is(const lyx::char_type *, const lyx::char_type *, ctype<lyx::char_type>::mask *) const { return 0; }
-template<> const lyx::char_type *
-ctype<lyx::char_type>::do_scan_is(ctype<lyx::char_type>::mask, const lyx::char_type *, const lyx::char_type *) const { return 0; }
-template<> const lyx::char_type *
-ctype<lyx::char_type>::do_scan_not(ctype<lyx::char_type>::mask, const lyx::char_type *, const lyx::char_type *) const { return 0; }
-template<> lyx::char_type ctype<lyx::char_type>::do_toupper(lyx::char_type) const { return 0; }
-template<> const lyx::char_type * ctype<lyx::char_type>::do_toupper(lyx::char_type *, lyx::char_type const *) const { return 0; }
-template<> lyx::char_type ctype<lyx::char_type>::do_tolower(lyx::char_type) const { return 0; }
-template<> const lyx::char_type * ctype<lyx::char_type>::do_tolower(lyx::char_type *, lyx::char_type const *) const { return 0; }
-template<> lyx::char_type ctype<lyx::char_type>::do_widen(char) const { return 0; }
-template<> const char *
-ctype<lyx::char_type>::do_widen(const char *, const char *, lyx::char_type *) const { return 0; }
-template<> char
-ctype<lyx::char_type>::do_narrow(const lyx::char_type, char) const { return 0; }
-template<> const lyx::char_type *
-ctype<lyx::char_type>::do_narrow(const lyx::char_type *, const lyx::char_type *, char, char *) const { return 0; }
-}
-
-
-namespace lyx {
 
 class ctype_failure : public bad_cast {
 public:
@@ -284,7 +255,7 @@ public:
 	virtual ~ctype_failure() throw() {}
 	virtual const char* what() const throw()
 	{
-		return "The ctype<lyx::char_type> locale facet does only support ASCII characters on this platform.";
+		return "The ctype<lyx::char_type> locale facet does only support ASCII characters.";
 	}
 };
 
@@ -295,7 +266,7 @@ public:
 	virtual ~num_put_failure() throw() {}
 	virtual const char* what() const throw()
 	{
-		return "The num_put locale facet does only support ASCII characters on this platform.";
+		return "The num_put<lyx::char_type> locale facet does only support ASCII characters.";
 	}
 };
 
@@ -308,7 +279,7 @@ class ascii_ctype_facet : public ctype<lyx::char_type>
 public:
 	typedef lyx::char_type char_type;
 	typedef wctype_t wmask_type;
-	explicit ascii_ctype_facet(size_t refs = 0) : ctype<char_type>(refs)
+	explicit ascii_ctype_facet(size_t refs = 0) : ctype<lyx::char_type>(refs)
 	{
 		M_initialize_ctype();
 	}
@@ -773,7 +744,7 @@ private:
 		}
 		for (; iit != eit && isDigitOrSep(*iit, sep); ++iit)
 			s += static_cast<char>(*iit);
-		if (iit != eit && *iit == dot) {
+		if (iit != eit && *iit == static_cast<lyx::char_type>(dot)) {
 			s += dot;
 			++iit;
 			for (; iit != eit && isDigitOrSep(*iit, 0); ++iit)
@@ -796,7 +767,8 @@ private:
 
 	bool isDigitOrSep(lyx::char_type const c, char const sep) const
 	{
-		return (c >= '0' && c <= '9') || (c != 0 && c == sep);
+		return (c >= '0' && c <= '9') ||
+			(c != 0 && sep >= 0 && c == static_cast<lyx::char_type>(sep));
 	}
 };
 
@@ -822,4 +794,4 @@ static locale_initializer initializer;
 
 }
 }
-#endif
+
diff --git a/src/support/docstring.h b/src/support/docstring.h
index 2c2901b..9f09ee3 100644
--- a/src/support/docstring.h
+++ b/src/support/docstring.h
@@ -13,13 +13,17 @@
 #ifndef LYX_DOCSTRING_H
 #define LYX_DOCSTRING_H
 
+#ifndef HAS_STD_CHAR32_T_FACETS
+#include "support/char32_t_facets.h"
+#endif
+
 #include "support/strfwd.h"
 
-#include <string>
 
 namespace lyx {
 
 /// Creates a docstring from a C string of ASCII characters
+/// This is deprecated. Use unicode literals instead, i.e. s = U"a".
 docstring const from_ascii(char const *);
 
 /// Creates a docstring from a std::string of ASCII characters
@@ -62,15 +66,19 @@ docstring const from_iconv_encoding(std::string const & s,
 docstring const normalize_c(docstring const & s);
 
 /// Compare a docstring with a C string of ASCII characters
+/// This is deprecated. Use unicode literals instead, i.e. s == U"a".
 bool operator==(docstring const &, char const *);
 
 /// Compare a C string of ASCII characters with a docstring
+/// This is deprecated. Use unicode literals instead, i.e. U"a" == s.
 inline bool operator==(char const * l, docstring const & r) { return r == l; }
 
 /// Compare a docstring with a C string of ASCII characters
+/// This is deprecated. Use unicode literals instead, i.e. s != U"a".
 inline bool operator!=(docstring const & l, char const * r) { return !(l == r); }
 
 /// Compare a C string of ASCII characters with a docstring
+/// This is deprecated. Use unicode literals instead, i.e. U"a" != s.
 inline bool operator!=(char const * l, docstring const & r) { return !(r == l); }
 
 /// Concatenate a docstring and a C string of ASCII characters
@@ -93,4 +101,5 @@ docstring & operator+=(docstring & l, char r);
 
 } // namespace lyx
 
-#endif
+
+#endif //LYX_DOCSTRING_H
diff --git a/src/support/lstrings.cpp b/src/support/lstrings.cpp
index 6d5f866..80048e5 100644
--- a/src/support/lstrings.cpp
+++ b/src/support/lstrings.cpp
@@ -34,22 +34,6 @@ using namespace std;
 
 namespace lyx {
 
-// Using this allows us to have docstring default arguments in headers
-// without #include "support/docstring" there.
-docstring const & empty_docstring()
-{
-	static const docstring s;
-	return s;
-}
-
-// Using this allows us to have string default arguments in headers
-// without #include <string>
-string const & empty_string()
-{
-	static const string s;
-	return s;
-}
-
 namespace {
 /**
  * Convert a QChar into a UCS4 character.
@@ -79,6 +63,7 @@ inline QChar const ucs4_to_qchar(char_type const ucs4)
 
 /// Maximum valid UCS4 code point
 char_type const ucs4_max = 0x10ffff;
+
 } // anon namespace
 
 
diff --git a/src/support/numpunct_lyx_char_type.h b/src/support/numpunct_lyx_char_type.h
deleted file mode 100644
index 7ec661c..0000000
--- a/src/support/numpunct_lyx_char_type.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// -*- C++ -*-
-/**
- * \file numpunct_lyx_char_type.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Peter Kümmel
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#ifndef LYX_NUMPUNCT_LYX_CHAR_TYPE_H
-#define LYX_NUMPUNCT_LYX_CHAR_TYPE_H
-
-
-#include <locale>
-
-
-namespace std
-{
-
-	template<>
-	class numpunct<lyx::char_type> : public numpunct<char>
-	{
-	public:
-
-		typedef lyx::char_type char_type;
-		typedef basic_string<lyx::char_type> string_type;
-
-		static locale::id id;
-
-		explicit numpunct(size_t __refs = 0) : numpunct<char>(__refs)
-		{}
-
-		char_type decimal_point() const
-		{ return numpunct<char>::decimal_point(); }
-
-		char_type thousands_sep() const
-		{ return numpunct<char>::thousands_sep(); }
-
-		string grouping() const
-		{ return numpunct<char>::grouping(); }
-
-		// Implementation can be found in docstream.cpp
-		string_type truename() const;
-		string_type falsename() const;
-
-
-	protected:
-		virtual ~numpunct();
-
-	};
-
-	// Fixed in VC11:
-	// http://connect.microsoft.com/VisualStudio/feedback/details/572376/msvc10-c-std-numpunct-has-a-hardcoded-dllimport-in-definition
-
-}
-#endif
diff --git a/src/support/os.h b/src/support/os.h
index 73eb86d..503aa37 100644
--- a/src/support/os.h
+++ b/src/support/os.h
@@ -153,7 +153,7 @@ bool canAutoOpenFile(std::string const & ext, auto_open_mode const mode);
  *  \returns whether or not the file is viewed (or edited) successfully.
  */
 bool autoOpenFile(std::string const & filename, auto_open_mode const mode,
-		  std::string const & path = empty_string());
+                  std::string const & path = "");
 
 /** Resolves a path such that it does not contain '.', '..', or symbolic links.
   * \p path and the return value are encoded in utf8.
diff --git a/src/support/strfwd.h b/src/support/strfwd.h
index 58b44f5..a6caaf2 100644
--- a/src/support/strfwd.h
+++ b/src/support/strfwd.h
@@ -1,114 +1,68 @@
 // -*- C++ -*-
-
-// Heavily inspired by /usr/include/c++/4.1/bits
-//
-// Copyright (C) 2001, 2002 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library.  This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2, or (at your option)
-// any later version.
+/**
+ * \file strfwd.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ * Full author contact details are available in file CREDITS.
+ */
 
 #ifndef STRFWD_H
 #define STRFWD_H
 
-#ifdef USE_WCHAR_T
 
-// Prefer this if possible because GNU libstdc++ has usable
-// std::ctype<wchar_t> locale facets but not
-// std::ctype<boost::uint32_t>. gcc older than 3.4 is also missing
-// usable std::char_traits<boost::uint32_t>.
-namespace lyx { typedef wchar_t char_type; }
-
-#else
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1600)
-#include <cstdint>
-namespace lyx { typedef uint32_t char_type; }
-#include "support/numpunct_lyx_char_type.h" // implementation for our char_type needed
-#else
-#include <boost/cstdint.hpp>
-namespace lyx { typedef boost::uint32_t char_type; }
-#endif
-
-#endif
-
-// Forward definitions do not work with libc++
-// For gcc5 with the new std::string ABI forward declarations would work in
-// principle, but I am not sure whether we want non-standard
-// "namespace __cxx11" in our sources.
-#if defined(USE_LLVM_LIBCPP) || defined(USE_GLIBCXX_CXX11_ABI)
+#include <iosfwd>
 #include <string>
-#else
-
-namespace std {
-
-template<typename Alloc> class allocator;
-
-template<typename Char> struct char_traits;
-template<> struct char_traits<char>;
-#ifdef USE_WCHAR_T
-template<> struct char_traits<wchar_t>;
-#endif
-
-template<typename Char, typename Traits, typename Alloc> class basic_string;
-typedef basic_string<char, char_traits<char>, allocator<char> > string;
-
-template<class Char, class Traits> class basic_istream;
-template<class Char, class Traits> class basic_ostream;
-template<class Char, class Traits, class Allocator> class basic_ostringstream;
-
-typedef basic_istream<char, char_traits<char> > istream;
-typedef basic_ostream<char, char_traits<char> > ostream;
-typedef basic_ostringstream<char, char_traits<char>, allocator<char> > ostringstream;
-
-} // namepace std
-
-#endif
-
-
-
 
 
 namespace lyx {
 
-/**
- * String type for storing the main text in UCS4 encoding.
- * Use std::string only in cases 7-bit ASCII is to be manipulated
- * within the variable.
- */
-typedef std::basic_string<char_type, std::char_traits<char_type>,
-	std::allocator<char_type> > docstring;
+
+typedef char32_t char_type;
+
+// String type for storing the main text in UCS4 encoding.
+// Use std::string only for 7-bit ASCII strings!
+typedef std::u32string docstring;
 
 /// Base class for UCS4 input streams
-typedef std::basic_istream<char_type, std::char_traits<char_type> > idocstream;
+typedef std::basic_istream<char_type> idocstream;
 
 /// Base class for UCS4 output streams
-typedef std::basic_ostream<char_type, std::char_traits<char_type> > odocstream;
+typedef std::basic_ostream<char_type> odocstream;
 
 /// UCS4 output stringstream
-typedef std::basic_ostringstream<char_type, std::char_traits<char_type>, std::allocator<char_type> > odocstringstream;
+typedef std::basic_ostringstream<char_type> odocstringstream;
 
-#if ! defined(USE_WCHAR_T)
-extern odocstream & operator<<(odocstream &, char);
-#endif
-
-// defined in lstrings.cpp
-docstring const & empty_docstring();
-std::string const & empty_string();
-// defined in docstring.cpp
-bool operator==(docstring const &, char const *);
 
 #ifdef STD_STRING_USES_COW
+
+// For gcc < 5.1
+//
+// The implementation of std::string and docstring is not thread-safe because it
+// uses copy-on-write. See:
+// https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
+//
+// Once we require gcc >= 5.1, std::string and docstring will be thread-safe(*),
+// and triv(doc)string can be removed.
+//
+// (*): A read-only access does not need synchronization between multiple
+// threads, i.e. is thread-safe without locking. Therefore you can safely use a
+// const triv(doc)string object in multiple threads at the same time.
+//
+// trivial_string is declared in src/support/trivstring.h
 template<typename Char> class trivial_string;
 typedef trivial_string<char> trivstring;
 typedef trivial_string<char_type> trivdocstring;
+
 #else
+
+// We assume that std::string and docstring comply with C++11 regarding
+// thread-safety.
 typedef std::string trivstring;
 typedef docstring trivdocstring;
-#endif
+
+#endif // STD_STRING_USES_COW
+
 
 } // namespace lyx
 
-#endif
+#endif // STRFWD_H
diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp
index a52927f..be69975 100644
--- a/src/tex2lyx/Preamble.cpp
+++ b/src/tex2lyx/Preamble.cpp
@@ -378,7 +378,7 @@ void Preamble::suppressDate(bool suppress)
 
 void Preamble::registerAuthor(std::string const & name)
 {
-	Author author(from_utf8(name), empty_docstring());
+	Author author(from_utf8(name), U"");
 	author.setUsed(true);
 	authors_.record(author);
 	h_tracking_changes = "true";
@@ -388,7 +388,7 @@ void Preamble::registerAuthor(std::string const & name)
 
 Author const & Preamble::getAuthor(std::string const & name) const
 {
-	Author author(from_utf8(name), empty_docstring());
+	Author author(from_utf8(name), U"");
 	for (AuthorList::Authors::const_iterator it = authors_.begin();
 	     it != authors_.end(); ++it)
 		if (*it == author)
@@ -1115,7 +1115,7 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled
 	   << "\\save_transient_properties " << h_save_transient_properties << "\n"
 	   << "\\origin " << origin << "\n"
 	   << "\\textclass " << h_textclass << "\n";
-	string const raw = subdoc ? empty_string() : h_preamble.str();
+	string const raw = subdoc ? "" : h_preamble.str();
 	if (!raw.empty()) {
 		os << "\\begin_preamble\n";
 		for (string::size_type i = 0; i < raw.size(); ++i) {
-- 
2.7.4

Reply via email to