Eliminate use of strstream based on internal changes
author <shinichiro.hamaji@gmail.com> <>
Wed, 9 Jan 2013 16:06:21 +0000 (16:06 +0000)
committer <shinichiro.hamaji@gmail.com> <>
Wed, 9 Jan 2013 16:06:21 +0000 (16:06 +0000)
http://code.google.com/p/google-glog/issues/detail?id=110

git-svn-id: https://google-glog.googlecode.com/svn/trunk@119 eb4d4688-79bd-11dd-afb4-1d65580434c0

Makefile.in
configure
configure.ac
src/glog/logging.h.in
src/logging.cc
src/stl_logging_unittest.cc
src/windows/glog/logging.h
src/windows/preprocess.sh

index 1dafd4b5f66aa5dcb8c30b1b6a9e8c663850bcb2..25bae24697f0b669ae86a913b64eb624e068f218 100644 (file)
@@ -415,6 +415,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv___attribute___noinline = @ac_cv___attribute___noinline@
 ac_cv___attribute___noreturn = @ac_cv___attribute___noreturn@
 ac_cv___attribute___printf_4_5 = @ac_cv___attribute___printf_4_5@
 ac_cv_cxx_using_operator = @ac_cv_cxx_using_operator@
index 272381e91d257c903f0ff001959729307ac883a0..276d96b2c60d7c21db8145d1fd042ed2276978c6 100755 (executable)
--- a/configure
+++ b/configure
@@ -632,6 +632,7 @@ ac_cv_have_systypes_h
 ac_cv_have_stdint_h
 ac_cv_have___builtin_expect
 ac_cv___attribute___printf_4_5
+ac_cv___attribute___noinline
 ac_cv___attribute___noreturn
 ac_cv_cxx_using_operator
 ac_google_namespace
@@ -15825,9 +15826,11 @@ $as_echo "$ac_cv___attribute__" >&6; }
 # We only care about these two attributes.
 if test x"$ac_cv___attribute__" = x"yes"; then
   ac_cv___attribute___noreturn="__attribute__ ((noreturn))"
+  ac_cv___attribute___noinline="__attribute__ ((noinline))"
   ac_cv___attribute___printf_4_5="__attribute__((__format__ (__printf__, 4, 5)))"
 else
   ac_cv___attribute___noreturn=
+  ac_cv___attribute___noinline=
   ac_cv___attribute___printf_4_5=
 fi
 
@@ -17174,6 +17177,7 @@ _ACEOF
 
 
 
+
 
 
 # Write generated configuration file
index d5c705397d6032bffc81d84305a531865444f4be..d58c1080aa871881280e25183497faceca7f351a 100644 (file)
@@ -69,9 +69,11 @@ AX_C___ATTRIBUTE__
 # We only care about these two attributes.
 if test x"$ac_cv___attribute__" = x"yes"; then
   ac_cv___attribute___noreturn="__attribute__ ((noreturn))"
+  ac_cv___attribute___noinline="__attribute__ ((noinline))"
   ac_cv___attribute___printf_4_5="__attribute__((__format__ (__printf__, 4, 5)))"
 else
   ac_cv___attribute___noreturn=
+  ac_cv___attribute___noinline=
   ac_cv___attribute___printf_4_5=
 fi
 
@@ -195,6 +197,7 @@ AC_SUBST(ac_google_end_namespace)
 AC_SUBST(ac_google_namespace)
 AC_SUBST(ac_cv_cxx_using_operator)
 AC_SUBST(ac_cv___attribute___noreturn)
+AC_SUBST(ac_cv___attribute___noinline)
 AC_SUBST(ac_cv___attribute___printf_4_5)
 AC_SUBST(ac_cv_have___builtin_expect)
 AC_SUBST(ac_cv_have_stdint_h)
index b0b3240e143b5302e76702a52d5e5b1e9627f491..ec47ffd08b8ab66e4bef70d3e2daf554f6f4c012 100644 (file)
 #include <errno.h>
 #include <string.h>
 #include <time.h>
+#include <iosfwd>
+#include <ostream>
+#include <sstream>
 #include <string>
 #if @ac_cv_have_unistd_h@
 # include <unistd.h>
 #endif
-#ifdef __DEPRECATED
-// Make GCC quiet.
-# undef __DEPRECATED
-# include <strstream>
-# define __DEPRECATED
-#else
-# include <strstream>
-#endif
 #include <vector>
 
 // Annoying stuff for windows -- makes sure clients can import these functions
@@ -134,8 +129,12 @@ typedef unsigned __int64 uint64;
 #ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
 #if @ac_cv_have___builtin_expect@
 #define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
+#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
 #else
 #define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
+#define GOOGLE_PREDICT_FALSE(x) x
+#define GOOGLE_PREDICT_TRUE(x) x
 #endif
 #endif
 
@@ -606,18 +605,68 @@ inline std::ostream& operator<<(
 
 @ac_google_start_namespace@
 
-// Build the error message string.
-template<class t1, class t2>
-std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
-  // It means that we cannot use stl_logging if compiler doesn't
-  // support using expression for operator.
-  // TODO(hamaji): Figure out a way to fix.
-#if @ac_cv_cxx_using_operator@
-  using ::operator<<;
-#endif
-  std::strstream ss;
-  ss << names << " (" << v1 << " vs. " << v2 << ")";
-  return new std::string(ss.str(), static_cast<unsigned int>(ss.pcount()));
+// This formats a value for a failing CHECK_XX statement.  Ordinarily,
+// it uses the definition for operator<<, with a few special cases below.
+template <typename T>
+inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
+  (*os) << v;
+}
+
+// Overrides for char types provide readable values for unprintable
+// characters.
+template <>
+void MakeCheckOpValueString(std::ostream* os, const char& v);
+template <>
+void MakeCheckOpValueString(std::ostream* os, const signed char& v);
+template <>
+void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
+
+// Build the error message string. Specify no inlining for code size.
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
+    @ac_cv___attribute___noinline@;
+
+namespace base {
+namespace internal {
+
+// If "s" is less than base_logging::INFO, returns base_logging::INFO.
+// If "s" is greater than base_logging::FATAL, returns
+// base_logging::ERROR.  Otherwise, returns "s".
+LogSeverity NormalizeSeverity(LogSeverity s);
+
+}  // namespace internal
+
+// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX
+// statement.  See MakeCheckOpString for sample usage.  Other
+// approaches were considered: use of a template method (e.g.,
+// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,
+// base::Print<T2>, &v2), however this approach has complications
+// related to volatile arguments and function-pointer arguments).
+class CheckOpMessageBuilder {
+ public:
+  // Inserts "exprtext" and " (" to the stream.
+  explicit CheckOpMessageBuilder(const char *exprtext);
+  // Deletes "stream_".
+  ~CheckOpMessageBuilder();
+  // For inserting the first variable.
+  std::ostream* ForVar1() { return stream_; }
+  // For inserting the second variable (adds an intermediate " vs. ").
+  std::ostream* ForVar2();
+  // Get the result (inserts the closing ")").
+  std::string* NewString();
+
+ private:
+  std::ostringstream *stream_;
+};
+
+}  // namespace base
+
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
+  base::CheckOpMessageBuilder comb(exprtext);
+  MakeCheckOpValueString(comb.ForVar1(), v1);
+  MakeCheckOpValueString(comb.ForVar2(), v2);
+  return comb.NewString();
 }
 
 // Helper functions for CHECK_OP macro.
@@ -625,26 +674,26 @@ std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
 // will not instantiate the template version of the function on values of
 // unnamed enum type - see comment below.
 #define DEFINE_CHECK_OP_IMPL(name, op) \
-  template <class t1, class t2> \
-  inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
-                                        const char* names) { \
-    if (v1 op v2) return NULL; \
-    else return MakeCheckOpString(v1, v2, names); \
+  template <typename T1, typename T2> \
+  inline std::string* name##Impl(const T1& v1, const T2& v2,    \
+                            const char* exprtext) { \
+    if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
+    else return MakeCheckOpString(v1, v2, exprtext); \
   } \
-  inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
-    return Check##name##Impl<int, int>(v1, v2, names); \
+  inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
+    return name##Impl<int, int>(v1, v2, exprtext); \
   }
 
-// Use _EQ, _NE, _LE, etc. in case the file including base/logging.h
-// provides its own #defines for the simpler names EQ, NE, LE, etc.
+// We use the full name Check_EQ, Check_NE, etc. in case the file including
+// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
 // This happens if, for example, those are used as token names in a
 // yacc grammar.
-DEFINE_CHECK_OP_IMPL(_EQ, ==)
-DEFINE_CHECK_OP_IMPL(_NE, !=)
-DEFINE_CHECK_OP_IMPL(_LE, <=)
-DEFINE_CHECK_OP_IMPL(_LT, < )
-DEFINE_CHECK_OP_IMPL(_GE, >=)
-DEFINE_CHECK_OP_IMPL(_GT, > )
+DEFINE_CHECK_OP_IMPL(Check_EQ, ==)  // Compilation error with CHECK_EQ(NULL, x)?
+DEFINE_CHECK_OP_IMPL(Check_NE, !=)  // Use CHECK(x == NULL) instead.
+DEFINE_CHECK_OP_IMPL(Check_LE, <=)
+DEFINE_CHECK_OP_IMPL(Check_LT, < )
+DEFINE_CHECK_OP_IMPL(Check_GE, >=)
+DEFINE_CHECK_OP_IMPL(Check_GT, > )
 #undef DEFINE_CHECK_OP_IMPL
 
 // Helper macro for binary operators.
@@ -1022,6 +1071,29 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
 #define VLOG_IF_EVERY_N(verboselevel, condition, n) \
   LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
 
+namespace base_logging {
+
+// LogMessage::LogStream is a std::ostream backed by this streambuf.
+// This class ignores overflow and leaves two bytes at the end of the
+// buffer to allow for a '\n' and '\0'.
+class LogStreamBuf : public std::streambuf {
+ public:
+  // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
+  LogStreamBuf(char *buf, int len) {
+    setp(buf, buf + len - 2);
+  }
+  // This effectively ignores overflow.
+  virtual int_type overflow(int_type ch) {
+    return ch;
+  }
+
+  // Legacy public ostrstream method.
+  size_t pcount() const { return pptr() - pbase(); }
+  char* pbase() const { return std::streambuf::pbase(); }
+};
+
+}  // namespace base_logging
+
 //
 // This class more or less represents a particular log message.  You
 // create an instance of LogMessage and then stream stuff to it.
@@ -1051,22 +1123,30 @@ public:
 #ifdef _MSC_VER
 # pragma warning(disable: 4275)
 #endif
-  class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostrstream {
+  class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
 #ifdef _MSC_VER
 # pragma warning(default: 4275)
 #endif
   public:
-    LogStream(char *buf, int len, int ctr_in)
-      : ostrstream(buf, len),
-        ctr_(ctr_in) {
-      self_ = this;
+    LogStream(char *buf, int len, int ctr)
+        : std::ostream(NULL),
+          streambuf_(buf, len),
+          ctr_(ctr),
+          self_(this) {
+      rdbuf(&streambuf_);
     }
 
     int ctr() const { return ctr_; }
-    void set_ctr(int ctr_in) { ctr_ = ctr_in; }
+    void set_ctr(int ctr) { ctr_ = ctr; }
     LogStream* self() const { return self_; }
 
+    // Legacy std::streambuf methods.
+    size_t pcount() const { return streambuf_.pcount(); }
+    char* pbase() const { return streambuf_.pbase(); }
+    char* str() const { return pbase(); }
+
   private:
+    base_logging::LogStreamBuf streambuf_;
     int ctr_;  // Counter hack (for the LOG_EVERY_X() macro)
     LogStream *self_;  // Consistency check hack
   };
index 6d009525783de22a7b16d9d98ca19c2223210fe8..54d8e345aaad66d8c6922b4f6b0d4d9bb6e4fe77 100644 (file)
@@ -68,7 +68,6 @@
 
 using std::string;
 using std::vector;
-using std::ostrstream;
 using std::setw;
 using std::setfill;
 using std::hex;
@@ -76,7 +75,6 @@ using std::dec;
 using std::min;
 using std::ostream;
 using std::ostringstream;
-using std::strstream;
 
 using std::FILE;
 using std::fwrite;
@@ -289,7 +287,7 @@ class LogFileObject : public base::Logger {
   // Actually create a logfile using the value of base_filename_ and the
   // supplied argument time_pid_string
   // REQUIRES: lock_ is held
-  bool CreateLogfile(const char* time_pid_string);
+  bool CreateLogfile(const string& time_pid_string);
 };
 
 }  // namespace
@@ -701,7 +699,7 @@ void LogFileObject::FlushUnlocked(){
   next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
 }
 
-bool LogFileObject::CreateLogfile(const char* time_pid_string) {
+bool LogFileObject::CreateLogfile(const string& time_pid_string) {
   string string_filename = base_filename_+filename_extension_+
                            time_pid_string;
   const char* filename = string_filename.c_str();
@@ -789,24 +787,24 @@ void LogFileObject::Write(bool force_flush,
     localtime_r(&timestamp, &tm_time);
 
     // The logfile's filename will have the date/time & pid in it
-    char time_pid_string[256];  // More than enough chars for time, pid, \0
-    ostrstream time_pid_stream(time_pid_string, sizeof(time_pid_string));
+    ostringstream time_pid_stream;
     time_pid_stream.fill('0');
     time_pid_stream << 1900+tm_time.tm_year
-                   << setw(2) << 1+tm_time.tm_mon
-                   << setw(2) << tm_time.tm_mday
-                   << '-'
-                   << setw(2) << tm_time.tm_hour
-                   << setw(2) << tm_time.tm_min
-                   << setw(2) << tm_time.tm_sec
-                   << '.'
-                   << GetMainThreadPid()
-                   << '\0';
+                    << setw(2) << 1+tm_time.tm_mon
+                    << setw(2) << tm_time.tm_mday
+                    << '-'
+                    << setw(2) << tm_time.tm_hour
+                    << setw(2) << tm_time.tm_min
+                    << setw(2) << tm_time.tm_sec
+                    << '.'
+                    << GetMainThreadPid();
+    const string& time_pid_string = time_pid_stream.str();
 
     if (base_filename_selected_) {
       if (!CreateLogfile(time_pid_string)) {
         perror("Could not create log file");
-        fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n", time_pid_string);
+        fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n",
+                time_pid_string.c_str());
         return;
       }
     } else {
@@ -854,15 +852,14 @@ void LogFileObject::Write(bool force_flush,
       // If we never succeeded, we have to give up
       if ( success == false ) {
         perror("Could not create logging file");
-        fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!", time_pid_string);
+        fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!",
+                time_pid_string.c_str());
         return;
       }
     }
 
     // Write a header message into the log file
-    char file_header_string[512];  // Enough chars for time and binary info
-    ostrstream file_header_stream(file_header_string,
-                                  sizeof(file_header_string));
+    ostringstream file_header_stream;
     file_header_stream.fill('0');
     file_header_stream << "Log file created at: "
                        << 1900+tm_time.tm_year << '/'
@@ -875,10 +872,11 @@ void LogFileObject::Write(bool force_flush,
                        << "Running on machine: "
                        << LogDestination::hostname() << '\n'
                        << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu "
-                       << "threadid file:line] msg" << '\n'
-                       << '\0';
-    int header_len = strlen(file_header_string);
-    fwrite(file_header_string, 1, header_len, file_);
+                       << "threadid file:line] msg" << '\n';
+    const string& file_header_string = file_header_stream.str();
+
+    const int header_len = file_header_string.size();
+    fwrite(file_header_string.data(), 1, header_len, file_);
     file_length_ += header_len;
     bytes_since_flush_ += header_len;
   }
@@ -1741,11 +1739,11 @@ void TruncateStdoutStderr() {
     bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2));               \
     if (equal == expected) return NULL;                                 \
     else {                                                              \
-      strstream ss;                                                     \
+      ostringstream ss;                                                 \
       if (!s1) s1 = "";                                                 \
       if (!s2) s2 = "";                                                 \
       ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
-      return new string(ss.str(), ss.pcount());                         \
+      return new string(ss.str());                                      \
     }                                                                   \
   }
 DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
@@ -1816,6 +1814,56 @@ LogMessageFatal::~LogMessageFatal() {
     LogMessage::Fail();
 }
 
+namespace base {
+
+CheckOpMessageBuilder::CheckOpMessageBuilder(const char *exprtext)
+    : stream_(new ostringstream) {
+  *stream_ << exprtext << " (";
+}
+
+CheckOpMessageBuilder::~CheckOpMessageBuilder() {
+  delete stream_;
+}
+
+ostream* CheckOpMessageBuilder::ForVar2() {
+  *stream_ << " vs. ";
+  return stream_;
+}
+
+string* CheckOpMessageBuilder::NewString() {
+  *stream_ << ")";
+  return new string(stream_->str());
+}
+
+}  // namespace base
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const char& v) {
+  if (v >= 32 && v <= 126) {
+    (*os) << "'" << v << "'";
+  } else {
+    (*os) << "char value " << (short)v;
+  }
+}
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const signed char& v) {
+  if (v >= 32 && v <= 126) {
+    (*os) << "'" << v << "'";
+  } else {
+    (*os) << "signed char value " << (short)v;
+  }
+}
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {
+  if (v >= 32 && v <= 126) {
+    (*os) << "'" << v << "'";
+  } else {
+    (*os) << "unsigned char value " << (unsigned short)v;
+  }
+}
+
 void InitGoogleLogging(const char* argv0) {
   glog_internal_namespace_::InitGoogleLoggingUtilities(argv0);
 }
index f932e95aa868ca8c1b3277ea1fa83d903512fb1d..5dcbc447e33772233ead3f625b6213017d2e2d10 100644 (file)
@@ -35,8 +35,8 @@
 
 #include <iostream>
 #include <map>
+#include <ostream>
 #include <string>
-#include <strstream>
 #include <vector>
 
 #ifdef __GNUC__
@@ -63,11 +63,9 @@ void TestSTLLogging() {
     v.push_back(10);
     v.push_back(20);
     v.push_back(30);
-    char ss_buf[1000];
-    ostrstream ss(ss_buf, sizeof(ss_buf));
-    // Just ostrstream s1; leaks heap.
-    ss << v << ends;
-    CHECK_STREQ(ss.str(), "10 20 30");
+    ostringstream ss;
+    ss << v;
+    EXPECT_EQ(ss.str(), "10 20 30");
     vector<int> copied_v(v);
     CHECK_EQ(v, copied_v);  // This must compile.
   }
@@ -78,10 +76,9 @@ void TestSTLLogging() {
     m[20] = "twenty";
     m[10] = "ten";
     m[30] = "thirty";
-    char ss_buf[1000];
-    ostrstream ss(ss_buf, sizeof(ss_buf));
-    ss << m << ends;
-    CHECK_STREQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
+    ostringstream ss;
+    ss << m;
+    EXPECT_EQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
     map< int, string > copied_m(m);
     CHECK_EQ(m, copied_m);  // This must compile.
   }
@@ -93,10 +90,9 @@ void TestSTLLogging() {
     hs.insert(10);
     hs.insert(20);
     hs.insert(30);
-    char ss_buf[1000];
-    ostrstream ss(ss_buf, sizeof(ss_buf));
-    ss << hs << ends;
-    CHECK_STREQ(ss.str(), "10 20 30");
+    ostringstream ss;
+    ss << hs;
+    EXPECT_EQ(ss.str(), "10 20 30");
     hash_set<int> copied_hs(hs);
     CHECK_EQ(hs, copied_hs);  // This must compile.
   }
@@ -109,10 +105,9 @@ void TestSTLLogging() {
     hm[10] = "ten";
     hm[20] = "twenty";
     hm[30] = "thirty";
-    char ss_buf[1000];
-    ostrstream ss(ss_buf, sizeof(ss_buf));
-    ss << hm << ends;
-    CHECK_STREQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
+    ostringstream ss;
+    ss << hm;
+    EXPECT_EQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
     hash_map<int, string> copied_hm(hm);
     CHECK_EQ(hm, copied_hm);  // this must compile
   }
@@ -131,10 +126,9 @@ void TestSTLLogging() {
     }
     v.push_back(100);
     expected += " ...";
-    char ss_buf[1000];
-    ostrstream ss(ss_buf, sizeof(ss_buf));
-    ss << v << ends;
-    CHECK_STREQ(ss.str(), expected.c_str());
+    ostringstream ss;
+    ss << v;
+    CHECK_EQ(ss.str(), expected.c_str());
   }
 
   {
@@ -144,10 +138,9 @@ void TestSTLLogging() {
     m[20] = "twenty";
     m[10] = "ten";
     m[30] = "thirty";
-    char ss_buf[1000];
-    ostrstream ss(ss_buf, sizeof(ss_buf));
-    ss << m << ends;
-    CHECK_STREQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
+    ostringstream ss;
+    ss << m;
+    EXPECT_EQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
     map< int, string, greater<int> > copied_m(m);
     CHECK_EQ(m, copied_m);  // This must compile.
   }
@@ -160,10 +153,9 @@ void TestSTLLogging() {
     hs.insert(10);
     hs.insert(20);
     hs.insert(30);
-    char ss_buf[1000];
-    ostrstream ss(ss_buf, sizeof(ss_buf));
-    ss << hs << ends;
-    CHECK_STREQ(ss.str(), "10 20 30");
+    ostringstream ss;
+    ss << hs;
+    EXPECT_EQ(ss.str(), "10 20 30");
     hash_set<int, user_hash> copied_hs(hs);
     CHECK_EQ(hs, copied_hs);  // This must compile.
   }
index 1e01e26bdff7d959530a89fbf90bd72358c3946a..35565ff989ef1a433949c6637098a27691c551bd 100755 (executable)
 #include <errno.h>
 #include <string.h>
 #include <time.h>
+#include <iosfwd>
+#include <ostream>
+#include <sstream>
 #include <string>
 #if 0
 # include <unistd.h>
 #endif
-#ifdef __DEPRECATED
-// Make GCC quiet.
-# undef __DEPRECATED
-# include <strstream>
-# define __DEPRECATED
-#else
-# include <strstream>
-#endif
 #include <vector>
 
 // Annoying stuff for windows -- makes sure clients can import these functions
@@ -138,8 +133,12 @@ typedef unsigned __int64 uint64;
 #ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
 #if 0
 #define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
+#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
 #else
 #define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
+#define GOOGLE_PREDICT_FALSE(x) x
+#define GOOGLE_PREDICT_TRUE(x) x
 #endif
 #endif
 
@@ -610,18 +609,68 @@ inline std::ostream& operator<<(
 
 namespace google {
 
-// Build the error message string.
-template<class t1, class t2>
-std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
-  // It means that we cannot use stl_logging if compiler doesn't
-  // support using expression for operator.
-  // TODO(hamaji): Figure out a way to fix.
-#if 1
-  using ::operator<<;
-#endif
-  std::strstream ss;
-  ss << names << " (" << v1 << " vs. " << v2 << ")";
-  return new std::string(ss.str(), static_cast<unsigned int>(ss.pcount()));
+// This formats a value for a failing CHECK_XX statement.  Ordinarily,
+// it uses the definition for operator<<, with a few special cases below.
+template <typename T>
+inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
+  (*os) << v;
+}
+
+// Overrides for char types provide readable values for unprintable
+// characters.
+template <>
+void MakeCheckOpValueString(std::ostream* os, const char& v);
+template <>
+void MakeCheckOpValueString(std::ostream* os, const signed char& v);
+template <>
+void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
+
+// Build the error message string. Specify no inlining for code size.
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
+    ;
+
+namespace base {
+namespace internal {
+
+// If "s" is less than base_logging::INFO, returns base_logging::INFO.
+// If "s" is greater than base_logging::FATAL, returns
+// base_logging::ERROR.  Otherwise, returns "s".
+LogSeverity NormalizeSeverity(LogSeverity s);
+
+}  // namespace internal
+
+// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX
+// statement.  See MakeCheckOpString for sample usage.  Other
+// approaches were considered: use of a template method (e.g.,
+// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,
+// base::Print<T2>, &v2), however this approach has complications
+// related to volatile arguments and function-pointer arguments).
+class CheckOpMessageBuilder {
+ public:
+  // Inserts "exprtext" and " (" to the stream.
+  explicit CheckOpMessageBuilder(const char *exprtext);
+  // Deletes "stream_".
+  ~CheckOpMessageBuilder();
+  // For inserting the first variable.
+  std::ostream* ForVar1() { return stream_; }
+  // For inserting the second variable (adds an intermediate " vs. ").
+  std::ostream* ForVar2();
+  // Get the result (inserts the closing ")").
+  std::string* NewString();
+
+ private:
+  std::ostringstream *stream_;
+};
+
+}  // namespace base
+
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
+  base::CheckOpMessageBuilder comb(exprtext);
+  MakeCheckOpValueString(comb.ForVar1(), v1);
+  MakeCheckOpValueString(comb.ForVar2(), v2);
+  return comb.NewString();
 }
 
 // Helper functions for CHECK_OP macro.
@@ -629,26 +678,26 @@ std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
 // will not instantiate the template version of the function on values of
 // unnamed enum type - see comment below.
 #define DEFINE_CHECK_OP_IMPL(name, op) \
-  template <class t1, class t2> \
-  inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
-                                        const char* names) { \
-    if (v1 op v2) return NULL; \
-    else return MakeCheckOpString(v1, v2, names); \
+  template <typename T1, typename T2> \
+  inline std::string* name##Impl(const T1& v1, const T2& v2,    \
+                            const char* exprtext) { \
+    if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
+    else return MakeCheckOpString(v1, v2, exprtext); \
   } \
-  inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
-    return Check##name##Impl<int, int>(v1, v2, names); \
+  inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
+    return name##Impl<int, int>(v1, v2, exprtext); \
   }
 
-// Use _EQ, _NE, _LE, etc. in case the file including base/logging.h
-// provides its own #defines for the simpler names EQ, NE, LE, etc.
+// We use the full name Check_EQ, Check_NE, etc. in case the file including
+// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
 // This happens if, for example, those are used as token names in a
 // yacc grammar.
-DEFINE_CHECK_OP_IMPL(_EQ, ==)
-DEFINE_CHECK_OP_IMPL(_NE, !=)
-DEFINE_CHECK_OP_IMPL(_LE, <=)
-DEFINE_CHECK_OP_IMPL(_LT, < )
-DEFINE_CHECK_OP_IMPL(_GE, >=)
-DEFINE_CHECK_OP_IMPL(_GT, > )
+DEFINE_CHECK_OP_IMPL(Check_EQ, ==)  // Compilation error with CHECK_EQ(NULL, x)?
+DEFINE_CHECK_OP_IMPL(Check_NE, !=)  // Use CHECK(x == NULL) instead.
+DEFINE_CHECK_OP_IMPL(Check_LE, <=)
+DEFINE_CHECK_OP_IMPL(Check_LT, < )
+DEFINE_CHECK_OP_IMPL(Check_GE, >=)
+DEFINE_CHECK_OP_IMPL(Check_GT, > )
 #undef DEFINE_CHECK_OP_IMPL
 
 // Helper macro for binary operators.
@@ -1026,6 +1075,29 @@ const LogSeverity GLOG_0 = GLOG_ERROR;
 #define VLOG_IF_EVERY_N(verboselevel, condition, n) \
   LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
 
+namespace base_logging {
+
+// LogMessage::LogStream is a std::ostream backed by this streambuf.
+// This class ignores overflow and leaves two bytes at the end of the
+// buffer to allow for a '\n' and '\0'.
+class LogStreamBuf : public std::streambuf {
+ public:
+  // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
+  LogStreamBuf(char *buf, int len) {
+    setp(buf, buf + len - 2);
+  }
+  // This effectively ignores overflow.
+  virtual int_type overflow(int_type ch) {
+    return ch;
+  }
+
+  // Legacy public ostrstream method.
+  size_t pcount() const { return pptr() - pbase(); }
+  char* pbase() const { return std::streambuf::pbase(); }
+};
+
+}  // namespace base_logging
+
 //
 // This class more or less represents a particular log message.  You
 // create an instance of LogMessage and then stream stuff to it.
@@ -1055,22 +1127,30 @@ public:
 #ifdef _MSC_VER
 # pragma warning(disable: 4275)
 #endif
-  class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostrstream {
+  class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
 #ifdef _MSC_VER
 # pragma warning(default: 4275)
 #endif
   public:
-    LogStream(char *buf, int len, int ctr_in)
-      : ostrstream(buf, len),
-        ctr_(ctr_in) {
-      self_ = this;
+    LogStream(char *buf, int len, int ctr)
+        : std::ostream(NULL),
+          streambuf_(buf, len),
+          ctr_(ctr),
+          self_(this) {
+      rdbuf(&streambuf_);
     }
 
     int ctr() const { return ctr_; }
-    void set_ctr(int ctr_in) { ctr_ = ctr_in; }
+    void set_ctr(int ctr) { ctr_ = ctr; }
     LogStream* self() const { return self_; }
 
+    // Legacy std::streambuf methods.
+    size_t pcount() const { return streambuf_.pcount(); }
+    char* pbase() const { return streambuf_.pbase(); }
+    char* str() const { return pbase(); }
+
   private:
+    base_logging::LogStreamBuf streambuf_;
     int ctr_;  // Counter hack (for the LOG_EVERY_X() macro)
     LogStream *self_;  // Consistency check hack
   };
index ea4352e8e3a836e5b26474f8fe5f6a8afc1455b7..5398988e7eaa01f33dacbc354252d27ed224dec8 100755 (executable)
@@ -96,6 +96,7 @@ DLLDEF_DEFINES="\
          -e "s!@ac_cv_have___builtin_expect@!0!g" \
          -e "s!@ac_cv_cxx_using_operator@!1!g" \
          -e "s!@ac_cv___attribute___noreturn@!!g" \
+         -e "s!@ac_cv___attribute___noinline@!!g" \
          -e "s!@ac_cv___attribute___printf_4_5@!!g" \
          -e "s!@ac_google_attribute@!${HAVE___ATTRIBUTE__:-0}!g" \
          -e "s!@ac_google_end_namespace@!$_END_GOOGLE_NAMESPACE_!g" \