From 3aa45ed56e6b13f73e35e15f45826bce9d84cb57 Mon Sep 17 00:00:00 2001 From: Date: Wed, 9 Jan 2013 16:06:21 +0000 Subject: [PATCH] Eliminate use of strstream based on internal changes 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 | 1 + configure | 4 ++ configure.ac | 3 + src/glog/logging.h.in | 162 +++++++++++++++++++++++++++++++++----------- src/logging.cc | 100 ++++++++++++++++++++------- src/stl_logging_unittest.cc | 52 ++++++-------- src/windows/glog/logging.h | 162 +++++++++++++++++++++++++++++++++----------- src/windows/preprocess.sh | 1 + 8 files changed, 347 insertions(+), 138 deletions(-) diff --git a/Makefile.in b/Makefile.in index 1dafd4b..25bae24 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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@ diff --git a/configure b/configure index 272381e..276d96b 100755 --- 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 @@ -17176,6 +17179,7 @@ _ACEOF + # Write generated configuration file ac_config_files="$ac_config_files Makefile src/glog/logging.h src/glog/raw_logging.h src/glog/vlog_is_on.h src/glog/stl_logging.h" diff --git a/configure.ac b/configure.ac index d5c7053..d58c108 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/src/glog/logging.h.in b/src/glog/logging.h.in index b0b3240..ec47ffd 100644 --- a/src/glog/logging.h.in +++ b/src/glog/logging.h.in @@ -39,18 +39,13 @@ #include #include #include +#include +#include +#include #include #if @ac_cv_have_unistd_h@ # include #endif -#ifdef __DEPRECATED -// Make GCC quiet. -# undef __DEPRECATED -# include -# define __DEPRECATED -#else -# include -#endif #include // 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 -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(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 +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 +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, &v1, +// base::Print, &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 +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 \ - 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 \ + 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(v1, v2, names); \ + inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ + return name##Impl(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 }; diff --git a/src/logging.cc b/src/logging.cc index 6d00952..54d8e34 100644 --- a/src/logging.cc +++ b/src/logging.cc @@ -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(×tamp, &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); } diff --git a/src/stl_logging_unittest.cc b/src/stl_logging_unittest.cc index f932e95..5dcbc44 100644 --- a/src/stl_logging_unittest.cc +++ b/src/stl_logging_unittest.cc @@ -35,8 +35,8 @@ #include #include +#include #include -#include #include #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 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 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 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 > 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 copied_hs(hs); CHECK_EQ(hs, copied_hs); // This must compile. } diff --git a/src/windows/glog/logging.h b/src/windows/glog/logging.h index 1e01e26..35565ff 100755 --- a/src/windows/glog/logging.h +++ b/src/windows/glog/logging.h @@ -43,18 +43,13 @@ #include #include #include +#include +#include +#include #include #if 0 # include #endif -#ifdef __DEPRECATED -// Make GCC quiet. -# undef __DEPRECATED -# include -# define __DEPRECATED -#else -# include -#endif #include // 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 -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(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 +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 +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, &v1, +// base::Print, &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 +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 \ - 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 \ + 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(v1, v2, names); \ + inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \ + return name##Impl(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 }; diff --git a/src/windows/preprocess.sh b/src/windows/preprocess.sh index ea4352e..5398988 100755 --- a/src/windows/preprocess.sh +++ b/src/windows/preprocess.sh @@ -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" \ -- 2.7.4