• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 NLP_SAFT_COMPONENTS_COMMON_MOBILE_LITE_BASE_COMPACT_LOGGING_H_
18 #define NLP_SAFT_COMPONENTS_COMMON_MOBILE_LITE_BASE_COMPACT_LOGGING_H_
19 
20 #include <cassert>
21 #include <string>
22 
23 #include "lang_id/common/lite_base/attributes.h"
24 #include "lang_id/common/lite_base/compact-logging-levels.h"
25 #include "lang_id/common/lite_strings/stringpiece.h"
26 
27 namespace libtextclassifier3 {
28 namespace mobile {
29 namespace internal_logging {
30 
31 // A tiny code footprint string stream for assembling log messages.
32 struct LoggingStringStream {
LoggingStringStreamLoggingStringStream33   LoggingStringStream() {}
streamLoggingStringStream34   LoggingStringStream &stream() { return *this; }
35 
36   // Needed for invocation in SAFTM_CHECK macro.
37   explicit operator bool() const { return true; }
38 
39   std::string message;
40 };
41 
42 template <typename T>
43 inline LoggingStringStream &operator<<(LoggingStringStream &stream,
44                                        const T &entry) {
45   stream.message.append(std::to_string(entry));
46   return stream;
47 }
48 
49 inline LoggingStringStream &operator<<(LoggingStringStream &stream,
50                                        const char *message) {
51   stream.message.append(message);
52   return stream;
53 }
54 
55 inline LoggingStringStream &operator<<(LoggingStringStream &stream,
56                                        const std::string &message) {
57   stream.message.append(message);
58   return stream;
59 }
60 
61 inline LoggingStringStream &operator<<(LoggingStringStream &stream,
62                                        StringPiece sp) {
63   stream.message.append(sp.data(), sp.size());
64   return stream;
65 }
66 
67 // The class that does all the work behind our SAFTM_LOG(severity) macros.  Each
68 // SAFTM_LOG(severity) << obj1 << obj2 << ...; logging statement creates a
69 // LogMessage temporary object containing a stringstream.  Each operator<< adds
70 // info to that stringstream and the LogMessage destructor performs the actual
71 // logging.  The reason this works is that in C++, "all temporary objects are
72 // destroyed as the last step in evaluating the full-expression that (lexically)
73 // contains the point where they were created."  For more info, see
74 // http://en.cppreference.com/w/cpp/language/lifetime.  Hence, the destructor is
75 // invoked after the last << from that logging statement.
76 class LogMessage {
77  public:
78   LogMessage(LogSeverity severity, const char *file_name,
79              int line_number) SAFTM_ATTRIBUTE_NOINLINE;
80 
81   ~LogMessage() SAFTM_ATTRIBUTE_NOINLINE;
82 
83   // Returns the stream associated with the logger object.
stream()84   LoggingStringStream &stream() { return stream_; }
85 
86  private:
87   const LogSeverity severity_;
88 
89   // Stream that "prints" all info into a string (not to a file).  We construct
90   // here the entire logging message and next print it in one operation.
91   LoggingStringStream stream_;
92 };
93 
94 // Pseudo-stream that "eats" the tokens <<-pumped into it, without printing
95 // anything.
96 class NullStream {
97  public:
NullStream()98   NullStream() {}
stream()99   NullStream &stream() { return *this; }
100 };
101 template <typename T>
102 inline NullStream &operator<<(NullStream &str, const T &) {
103   return str;
104 }
105 
106 }  // namespace internal_logging
107 }  // namespace mobile
108 }  // namespace nlp_saft
109 
110 #define SAFTM_LOG(severity)                                               \
111   ::libtextclassifier3::mobile::internal_logging::LogMessage(                       \
112       ::libtextclassifier3::mobile::internal_logging::severity, __FILE__, __LINE__) \
113       .stream()
114 
115 // If condition x is true, does nothing.  Otherwise, crashes the program (liek
116 // LOG(FATAL)) with an informative message.  Can be continued with extra
117 // messages, via <<, like any logging macro, e.g.,
118 //
119 // SAFTM_CHECK(my_cond) << "I think we hit a problem";
120 #define SAFTM_CHECK(x)                                                \
121   (x) || SAFTM_LOG(FATAL) << __FILE__ << ":" << __LINE__              \
122   << ": check failed: \"" << #x
123 
124 #define SAFTM_CHECK_EQ(x, y) SAFTM_CHECK((x) == (y))
125 #define SAFTM_CHECK_LT(x, y) SAFTM_CHECK((x) < (y))
126 #define SAFTM_CHECK_GT(x, y) SAFTM_CHECK((x) > (y))
127 #define SAFTM_CHECK_LE(x, y) SAFTM_CHECK((x) <= (y))
128 #define SAFTM_CHECK_GE(x, y) SAFTM_CHECK((x) >= (y))
129 #define SAFTM_CHECK_NE(x, y) SAFTM_CHECK((x) != (y))
130 
131 #define SAFTM_NULLSTREAM \
132   ::libtextclassifier3::mobile::internal_logging::NullStream().stream()
133 
134 // Debug checks: a SAFTM_DCHECK<suffix> macro should behave like
135 // SAFTM_CHECK<suffix> in debug mode an don't check / don't print anything in
136 // non-debug mode.
137 #ifdef NDEBUG
138 
139 #define SAFTM_DCHECK(x) SAFTM_NULLSTREAM
140 #define SAFTM_DCHECK_EQ(x, y) SAFTM_NULLSTREAM
141 #define SAFTM_DCHECK_LT(x, y) SAFTM_NULLSTREAM
142 #define SAFTM_DCHECK_GT(x, y) SAFTM_NULLSTREAM
143 #define SAFTM_DCHECK_LE(x, y) SAFTM_NULLSTREAM
144 #define SAFTM_DCHECK_GE(x, y) SAFTM_NULLSTREAM
145 #define SAFTM_DCHECK_NE(x, y) SAFTM_NULLSTREAM
146 
147 // In non-debug mode, SAFT_DLOG statements do not generate any logging.
148 #define SAFTM_DLOG(severity) SAFTM_NULLSTREAM
149 
150 #else  // NDEBUG
151 
152 // In debug mode, each SAFTM_DCHECK<suffix> is equivalent to
153 // SAFTM_CHECK<suffix>, i.e., a real check that crashes when the condition is
154 // not true.
155 #define SAFTM_DCHECK(x) SAFTM_CHECK(x)
156 #define SAFTM_DCHECK_EQ(x, y) SAFTM_CHECK_EQ(x, y)
157 #define SAFTM_DCHECK_LT(x, y) SAFTM_CHECK_LT(x, y)
158 #define SAFTM_DCHECK_GT(x, y) SAFTM_CHECK_GT(x, y)
159 #define SAFTM_DCHECK_LE(x, y) SAFTM_CHECK_LE(x, y)
160 #define SAFTM_DCHECK_GE(x, y) SAFTM_CHECK_GE(x, y)
161 #define SAFTM_DCHECK_NE(x, y) SAFTM_CHECK_NE(x, y)
162 
163 // In debug mode, SAFT_DLOG statements are like SAFT_LOG.
164 #define SAFTM_DLOG SAFTM_LOG
165 
166 #endif  // NDEBUG
167 
168 #ifdef LIBTEXTCLASSIFIER_VLOG
169 #define SAFTM_VLOG(severity)                                              \
170   ::libtextclassifier3::mobile::internal_logging::LogMessage(                     \
171        ::libtextclassifier3::mobile::internal_logging::INFO, __FILE__, __LINE__)  \
172   .stream()
173 #else
174 #define SAFTM_VLOG(severity) SAFTM_NULLSTREAM
175 #endif
176 
177 #endif  // NLP_SAFT_COMPONENTS_COMMON_MOBILE_LITE_BASE_COMPACT_LOGGING_H_
178