• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef LIBTEXTCLASSIFIER_UTIL_BASE_LOGGING_H_
18 #define LIBTEXTCLASSIFIER_UTIL_BASE_LOGGING_H_
19 
20 #include <cassert>
21 #include <sstream>
22 #include <string>
23 
24 #include "util/base/logging_levels.h"
25 #include "util/base/port.h"
26 
27 namespace libtextclassifier {
28 namespace logging {
29 
30 // The class that does all the work behind our TC_LOG(severity) macros.  Each
31 // TC_LOG(severity) << obj1 << obj2 << ...; logging statement creates a
32 // LogMessage temporary object containing a stringstream.  Each operator<< adds
33 // info to that stringstream and the LogMessage destructor performs the actual
34 // logging.  The reason this works is that in C++, "all temporary objects are
35 // destroyed as the last step in evaluating the full-expression that (lexically)
36 // contains the point where they were created."  For more info, see
37 // http://en.cppreference.com/w/cpp/language/lifetime.  Hence, the destructor is
38 // invoked after the last << from that logging statement.
39 class LogMessage {
40  public:
41   LogMessage(LogSeverity severity, const char *file_name,
42              int line_number) TC_ATTRIBUTE_NOINLINE;
43 
44   ~LogMessage() TC_ATTRIBUTE_NOINLINE;
45 
46   // Returns the stream associated with the logger object.
stream()47   std::stringstream &stream() { return stream_; }
48 
49  private:
50   const LogSeverity severity_;
51 
52   // Stream that "prints" all info into a string (not to a file).  We construct
53   // here the entire logging message and next print it in one operation.
54   std::stringstream stream_;
55 };
56 
57 #define TC_LOG(severity)                                          \
58   ::libtextclassifier::logging::LogMessage(                       \
59       ::libtextclassifier::logging::severity, __FILE__, __LINE__) \
60       .stream()
61 
62 // If condition x is true, does nothing.  Otherwise, crashes the program (liek
63 // LOG(FATAL)) with an informative message.  Can be continued with extra
64 // messages, via <<, like any logging macro, e.g.,
65 //
66 // TC_CHECK(my_cond) << "I think we hit a problem";
67 #define TC_CHECK(x)                                                           \
68   (x) || TC_LOG(FATAL) << __FILE__ << ":" << __LINE__ << ": check failed: \"" \
69                        << #x
70 
71 #define TC_CHECK_EQ(x, y) TC_CHECK((x) == (y))
72 #define TC_CHECK_LT(x, y) TC_CHECK((x) < (y))
73 #define TC_CHECK_GT(x, y) TC_CHECK((x) > (y))
74 #define TC_CHECK_LE(x, y) TC_CHECK((x) <= (y))
75 #define TC_CHECK_GE(x, y) TC_CHECK((x) >= (y))
76 #define TC_CHECK_NE(x, y) TC_CHECK((x) != (y))
77 
78 // Debug checks: a TC_DCHECK<suffix> macro should behave like TC_CHECK<suffix>
79 // in debug mode an don't check / don't print anything in non-debug mode.
80 #ifdef NDEBUG
81 
82 // Pseudo-stream that "eats" the tokens <<-pumped into it, without printing
83 // anything.
84 class NullStream {
85  public:
NullStream()86   NullStream() {}
stream()87   NullStream &stream() { return *this; }
88 };
89 template <typename T>
90 inline NullStream &operator<<(NullStream &str, const T &) {
91   return str;
92 }
93 
94 #define TC_NULLSTREAM ::libtextclassifier::logging::NullStream().stream()
95 #define TC_DCHECK(x) TC_NULLSTREAM
96 #define TC_DCHECK_EQ(x, y) TC_NULLSTREAM
97 #define TC_DCHECK_LT(x, y) TC_NULLSTREAM
98 #define TC_DCHECK_GT(x, y) TC_NULLSTREAM
99 #define TC_DCHECK_LE(x, y) TC_NULLSTREAM
100 #define TC_DCHECK_GE(x, y) TC_NULLSTREAM
101 #define TC_DCHECK_NE(x, y) TC_NULLSTREAM
102 
103 #else  // NDEBUG
104 
105 // In debug mode, each TC_DCHECK<suffix> is equivalent to TC_CHECK<suffix>,
106 // i.e., a real check that crashes when the condition is not true.
107 #define TC_DCHECK(x) TC_CHECK(x)
108 #define TC_DCHECK_EQ(x, y) TC_CHECK_EQ(x, y)
109 #define TC_DCHECK_LT(x, y) TC_CHECK_LT(x, y)
110 #define TC_DCHECK_GT(x, y) TC_CHECK_GT(x, y)
111 #define TC_DCHECK_LE(x, y) TC_CHECK_LE(x, y)
112 #define TC_DCHECK_GE(x, y) TC_CHECK_GE(x, y)
113 #define TC_DCHECK_NE(x, y) TC_CHECK_NE(x, y)
114 
115 #endif  // NDEBUG
116 }  // namespace logging
117 }  // namespace libtextclassifier
118 
119 #endif  // LIBTEXTCLASSIFIER_UTIL_BASE_LOGGING_H_
120