From c09d9c12e79fde83a87b2394c88b32e568271eda Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Thu, 17 May 2018 05:45:36 -0400
Subject: [PATCH] SL-821: Add WSTRINGIZE() and DEWSTRINGIZE() macros for wide
 strings.

Streamline convenience overload stringize(std::wstring); make convenience
overload wstringize(std::string) symmetrically convert from UTF-8 string.

Also eliminate STRINGIZE() et al. dependency on Boost.Phoenix: use lambdas
instead.

Using lambdas instead of template expansion necessitates reordering some code
in wrapllerrs.h.
---
 indra/llcommon/stringize.h        | 52 +++++++++++++++++--------------
 indra/llcommon/tests/wrapllerrs.h | 14 ++++-----
 2 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h
index a5a90d72973..38dd198ad31 100644
--- a/indra/llcommon/stringize.h
+++ b/indra/llcommon/stringize.h
@@ -30,7 +30,6 @@
 #define LL_STRINGIZE_H
 
 #include <sstream>
-#include <boost/phoenix/phoenix.hpp>
 #include <llstring.h>
 
 /**
@@ -53,12 +52,7 @@ std::basic_string<CHARTYPE> gstringize(const T& item)
  */
 inline std::string stringize(const std::wstring& item)
 {
-    LL_WARNS() << "WARNING:  Possible narrowing" << LL_ENDL;
-    
-    std::string s;
-    
-    s = wstring_to_utf8str(item);
-    return gstringize<char>(s);
+    return wstring_to_utf8str(item);
 }
 
 /**
@@ -76,7 +70,10 @@ std::string stringize(const T& item)
  */
 inline std::wstring wstringize(const std::string& item)
 {
-    return gstringize<wchar_t>(item.c_str());
+    // utf8str_to_wstring() returns LLWString, which isn't necessarily the
+    // same as std::wstring
+    LLWString s(utf8str_to_wstring(item));
+    return std::wstring(s.begin(), s.end());
 }
 
 /**
@@ -91,10 +88,10 @@ std::wstring wstringize(const T& item)
 /**
  * stringize_f(functor)
  */
-template <typename Functor>
-std::string stringize_f(Functor const & f)
+template <typename CHARTYPE, typename Functor>
+std::basic_string<CHARTYPE> stringize_f(Functor const & f)
 {
-    std::ostringstream out;
+    std::basic_ostringstream<CHARTYPE> out;
     f(out);
     return out.str();
 }
@@ -108,31 +105,37 @@ std::string stringize_f(Functor const & f)
  * return out.str();
  * @endcode
  */
-#define STRINGIZE(EXPRESSION) (stringize_f(boost::phoenix::placeholders::arg1 << EXPRESSION))
+#define STRINGIZE(EXPRESSION) (stringize_f<char>([&](std::ostream& out){ out << EXPRESSION; }))
 
+/**
+ * WSTRINGIZE() is the wstring equivalent of STRINGIZE()
+ */
+#define WSTRINGIZE(EXPRESSION) (stringize_f<wchar_t>([&](std::wostream& out){ out << EXPRESSION; }))
 
 /**
  * destringize(str)
  * defined for symmetry with stringize
- * *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
+ * @NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
  * leading/trailing whitespace and handling of bad_lexical_cast exceptions
+ * @NOTE - no need for dewstringize(), since passing std::wstring will Do The
+ * Right Thing
  */
-template <typename T>
-T destringize(std::string const & str)
+template <typename T, typename CHARTYPE>
+T destringize(std::basic_string<CHARTYPE> const & str)
 {
-	T val;
-    std::istringstream in(str);
-	in >> val;
+    T val;
+    std::basic_istringstream<CHARTYPE> in(str);
+    in >> val;
     return val;
 }
 
 /**
  * destringize_f(str, functor)
  */
-template <typename Functor>
-void destringize_f(std::string const & str, Functor const & f)
+template <typename CHARTYPE, typename Functor>
+void destringize_f(std::basic_string<CHARTYPE> const & str, Functor const & f)
 {
-    std::istringstream in(str);
+    std::basic_istringstream<CHARTYPE> in(str);
     f(in);
 }
 
@@ -143,8 +146,11 @@ void destringize_f(std::string const & str, Functor const & f)
  * std::istringstream in(str);
  * in >> item1 >> item2 >> item3 ... ;
  * @endcode
+ * @NOTE - once we get generic lambdas, we shouldn't need DEWSTRINGIZE() any
+ * more since DESTRINGIZE() should do the right thing with a std::wstring. But
+ * until then, the lambda we pass must accept the right std::basic_istream.
  */
-#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::phoenix::placeholders::arg1 >> EXPRESSION)))
-
+#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::istream& in){in >> EXPRESSION;}))
+#define DEWSTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::wistream& in){in >> EXPRESSION;}))
 
 #endif /* ! defined(LL_STRINGIZE_H) */
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index 9a4bbbd630d..08fbf19b1cd 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -109,6 +109,12 @@ class CaptureLogRecorder : public LLError::Recorder, public boost::noncopyable
         mMessages.push_back(message);
     }
 
+    friend inline
+    std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log)
+    {
+        return log.streamto(out);
+    }
+
     /// Don't assume the message we want is necessarily the LAST log message
     /// emitted by the underlying code; search backwards through all messages
     /// for the sought string.
@@ -126,7 +132,7 @@ class CaptureLogRecorder : public LLError::Recorder, public boost::noncopyable
 
         throw tut::failure(STRINGIZE("failed to find '" << search
                                      << "' in captured log messages:\n"
-                                     << boost::ref(*this)));
+                                     << *this));
     }
 
     std::ostream& streamto(std::ostream& out) const
@@ -200,10 +206,4 @@ class CaptureLog : public boost::noncopyable
 	LLError::RecorderPtr mRecorder;
 };
 
-inline
-std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log)
-{
-    return log.streamto(out);
-}
-
 #endif /* ! defined(LL_WRAPLLERRS_H) */
-- 
GitLab